From eaef2961cb40b214cb744214998a02097053c00f Mon Sep 17 00:00:00 2001 From: Petr Hosek Date: Mon, 18 Dec 2017 12:51:39 -0800 Subject: [PATCH 1/4] Support specifying licenses for Google Compute images This is needed to enable features such as the nested virtualization: https://cloud.google.com/compute/docs/instances/enable-nested-virtualization-vm-instances --- builder/googlecompute/config.go | 1 + builder/googlecompute/config_test.go | 3 +++ builder/googlecompute/driver.go | 2 +- builder/googlecompute/driver_gce.go | 3 ++- builder/googlecompute/driver_mock.go | 7 ++++--- builder/googlecompute/step_create_image.go | 2 +- builder/googlecompute/step_create_image_test.go | 3 +-- 7 files changed, 13 insertions(+), 8 deletions(-) diff --git a/builder/googlecompute/config.go b/builder/googlecompute/config.go index 8ed3897d6..c8863d4d9 100644 --- a/builder/googlecompute/config.go +++ b/builder/googlecompute/config.go @@ -36,6 +36,7 @@ type Config struct { ImageDescription string `mapstructure:"image_description"` ImageFamily string `mapstructure:"image_family"` ImageLabels map[string]string `mapstructure:"image_labels"` + ImageLicenses []string `mapstructure:"image_licenses"` InstanceName string `mapstructure:"instance_name"` Labels map[string]string `mapstructure:"labels"` MachineType string `mapstructure:"machine_type"` diff --git a/builder/googlecompute/config_test.go b/builder/googlecompute/config_test.go index 551692b29..a4b862a1a 100644 --- a/builder/googlecompute/config_test.go +++ b/builder/googlecompute/config_test.go @@ -309,6 +309,9 @@ func testConfig(t *testing.T) map[string]interface{} { "label-1": "value-1", "label-2": "value-2", }, + "image_licenses": []string{ + "test-license", + }, "zone": "us-east1-a", } } diff --git a/builder/googlecompute/driver.go b/builder/googlecompute/driver.go index bd302ddc0..fdb7d9442 100644 --- a/builder/googlecompute/driver.go +++ b/builder/googlecompute/driver.go @@ -11,7 +11,7 @@ import ( type Driver interface { // CreateImage creates an image from the given disk in Google Compute // Engine. - CreateImage(name, description, family, zone, disk string, image_labels map[string]string) (<-chan *Image, <-chan error) + CreateImage(name, description, family, zone, disk string, image_labels map[string]string, image_licenses []string) (<-chan *Image, <-chan error) // DeleteImage deletes the image with the given name. DeleteImage(name string) <-chan error diff --git a/builder/googlecompute/driver_gce.go b/builder/googlecompute/driver_gce.go index 44dcb85c6..c84ab222f 100644 --- a/builder/googlecompute/driver_gce.go +++ b/builder/googlecompute/driver_gce.go @@ -97,12 +97,13 @@ func NewDriverGCE(ui packer.Ui, p string, a *AccountFile) (Driver, error) { }, nil } -func (d *driverGCE) CreateImage(name, description, family, zone, disk string, image_labels map[string]string) (<-chan *Image, <-chan error) { +func (d *driverGCE) CreateImage(name, description, family, zone, disk string, image_labels map[string]string, image_licenses []string) (<-chan *Image, <-chan error) { gce_image := &compute.Image{ Description: description, Name: name, Family: family, Labels: image_labels, + Licenses: image_licenses, SourceDisk: fmt.Sprintf("%s%s/zones/%s/disks/%s", d.service.BasePath, d.projectId, zone, disk), SourceType: "RAW", } diff --git a/builder/googlecompute/driver_mock.go b/builder/googlecompute/driver_mock.go index 895775da5..720f9d60b 100644 --- a/builder/googlecompute/driver_mock.go +++ b/builder/googlecompute/driver_mock.go @@ -9,9 +9,9 @@ type DriverMock struct { CreateImageDesc string CreateImageFamily string CreateImageLabels map[string]string + CreateImageLicenses []string CreateImageZone string CreateImageDisk string - CreateImageResultLicenses []string CreateImageResultProjectId string CreateImageResultSelfLink string CreateImageResultSizeGb int64 @@ -82,11 +82,12 @@ type DriverMock struct { WaitForInstanceErrCh <-chan error } -func (d *DriverMock) CreateImage(name, description, family, zone, disk string, image_labels map[string]string) (<-chan *Image, <-chan error) { +func (d *DriverMock) CreateImage(name, description, family, zone, disk string, image_labels map[string]string, image_licenses []string) (<-chan *Image, <-chan error) { d.CreateImageName = name d.CreateImageDesc = description d.CreateImageFamily = family d.CreateImageLabels = image_labels + d.CreateImageLicenses = image_licenses d.CreateImageZone = zone d.CreateImageDisk = disk if d.CreateImageResultProjectId == "" { @@ -106,7 +107,7 @@ func (d *DriverMock) CreateImage(name, description, family, zone, disk string, i ch := make(chan *Image, 1) ch <- &Image{ Labels: d.CreateImageLabels, - Licenses: d.CreateImageResultLicenses, + Licenses: d.CreateImageLicenses, Name: name, ProjectId: d.CreateImageResultProjectId, SelfLink: d.CreateImageResultSelfLink, diff --git a/builder/googlecompute/step_create_image.go b/builder/googlecompute/step_create_image.go index 72e6a06eb..c2bde16c8 100644 --- a/builder/googlecompute/step_create_image.go +++ b/builder/googlecompute/step_create_image.go @@ -40,7 +40,7 @@ func (s *StepCreateImage) Run(_ context.Context, state multistep.StateBag) multi imageCh, errCh := driver.CreateImage( config.ImageName, config.ImageDescription, config.ImageFamily, config.Zone, - config.DiskName, config.ImageLabels) + config.DiskName, config.ImageLabels, config.ImageLicenses) var err error select { case err = <-errCh: diff --git a/builder/googlecompute/step_create_image_test.go b/builder/googlecompute/step_create_image_test.go index 6f1121a9f..65ccca313 100644 --- a/builder/googlecompute/step_create_image_test.go +++ b/builder/googlecompute/step_create_image_test.go @@ -22,7 +22,6 @@ func TestStepCreateImage(t *testing.T) { d := state.Get("driver").(*DriverMock) // These are the values of the image the driver will return. - d.CreateImageResultLicenses = []string{"test-license"} d.CreateImageResultProjectId = "test-project" d.CreateImageResultSizeGb = 100 @@ -36,7 +35,6 @@ func TestStepCreateImage(t *testing.T) { assert.True(t, ok, "Image in state is not an Image.") // Verify created Image results. - assert.Equal(t, image.Licenses, d.CreateImageResultLicenses, "Created image licenses don't match the licenses returned by the driver.") assert.Equal(t, image.Name, c.ImageName, "Created image does not match config name.") assert.Equal(t, image.ProjectId, d.CreateImageResultProjectId, "Created image project does not match driver project.") assert.Equal(t, image.SizeGb, d.CreateImageResultSizeGb, "Created image size does not match the size returned by the driver.") @@ -48,6 +46,7 @@ func TestStepCreateImage(t *testing.T) { assert.Equal(t, d.CreateImageZone, c.Zone, "Incorrect image zone passed to driver.") assert.Equal(t, d.CreateImageDisk, c.DiskName, "Incorrect disk passed to driver.") assert.Equal(t, d.CreateImageLabels, c.ImageLabels, "Incorrect image_labels passed to driver.") + assert.Equal(t, d.CreateImageLicenses, c.ImageLicenses, "Incorrect image_licenses passed to driver.") } func TestStepCreateImage_errorOnChannel(t *testing.T) { From 1c9f18603c475ce83d8649200c0b57dd6855c771 Mon Sep 17 00:00:00 2001 From: Sean Malloy Date: Sat, 3 Feb 2018 15:32:10 -0600 Subject: [PATCH 2/4] Fix Google Compute Builder Documentation Added required configuration option ssh_username to basic config example. --- website/source/docs/builders/googlecompute.html.md | 1 + 1 file changed, 1 insertion(+) diff --git a/website/source/docs/builders/googlecompute.html.md b/website/source/docs/builders/googlecompute.html.md index 1c4717768..e8147e966 100644 --- a/website/source/docs/builders/googlecompute.html.md +++ b/website/source/docs/builders/googlecompute.html.md @@ -109,6 +109,7 @@ is assumed to be the path to the file containing the JSON. "account_file": "account.json", "project_id": "my project", "source_image": "debian-7-wheezy-v20150127", + "ssh_username": "packer", "zone": "us-central1-a" } ] From c75db88f6b8e7ff1b8a0c7cffebc77c9ae02a0f2 Mon Sep 17 00:00:00 2001 From: Sean Malloy Date: Sat, 3 Feb 2018 15:56:29 -0600 Subject: [PATCH 3/4] Add documentation for new googlecompute builder image_licenses configuration option --- .../docs/builders/googlecompute.html.md | 63 ++++++++++++++----- 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/website/source/docs/builders/googlecompute.html.md b/website/source/docs/builders/googlecompute.html.md index e8147e966..d9be8cd28 100644 --- a/website/source/docs/builders/googlecompute.html.md +++ b/website/source/docs/builders/googlecompute.html.md @@ -93,7 +93,9 @@ Packer looks for credentials in the following places, preferring the first locat 4. On Google Compute Engine and Google App Engine Managed VMs, it fetches credentials from the metadata server. (Needs a correct VM authentication scope configuration, see above) -## Basic Example +## Examples + +### Basic Example Below is a fully functioning example. It doesn't do anything useful, since no provisioners or startup-script metadata are defined, but it will effectively @@ -123,25 +125,50 @@ user used to connect in a startup-script. ``` {.json} { - "builders": [{ - "type": "googlecompute", - "account_file": "account.json", - "project_id": "my project", - "source_image": "windows-server-2016-dc-v20170227", - "disk_size": "50", - "machine_type": "n1-standard-1", - "communicator": "winrm", - "winrm_username": "packer_user", - "winrm_insecure": true, - "winrm_use_ssl": true, - "metadata": { - "windows-startup-script-cmd": "winrm quickconfig -quiet & net user /add packer_user & net localgroup administrators packer_user /add & winrm set winrm/config/service/auth @{Basic=\"true\"}" - }, - "zone": "us-central1-a" - }] + "builders": [ + { + "type": "googlecompute", + "account_file": "account.json", + "project_id": "my project", + "source_image": "windows-server-2016-dc-v20170227", + "disk_size": "50", + "machine_type": "n1-standard-1", + "communicator": "winrm", + "winrm_username": "packer_user", + "winrm_insecure": true, + "winrm_use_ssl": true, + "metadata": { + "windows-startup-script-cmd": "winrm quickconfig -quiet & net user /add packer_user & net localgroup administrators packer_user /add & winrm set winrm/config/service/auth @{Basic=\"true\"}" + }, + "zone": "us-central1-a" + } + ] } ``` +### Nested Hypervisor Example + +This is an example of using the `image_licenses` configuration option to create a GCE image that has nested virtualization enabled. See +[Enabling Nested Virtualization for VM Instances](https://cloud.google.com/compute/docs/instances/enable-nested-virtualization-vm-instances) +for details. + +``` json +{ + "builders": [ + { + "type": "googlecompute", + "account_file": "account.json", + "project_id": "my project", + "source_image_family": "centos-7", + "ssh_username": "packer", + "zone": "us-central1-a", + "image_licenses": ["projects/vm-options/global/licenses/enable-vmx"] + } + ] +} + +``` + ## Configuration Reference Configuration options are organized below into two categories: required and @@ -202,6 +229,8 @@ builder. - `image_labels` (object of key/value strings) - Key/value pair labels to apply to the created image. +- `image_licenses` (array of strings) - Licenses to apply to the created image. + - `image_name` (string) - The unique name of the resulting image. Defaults to `"packer-{{timestamp}}"`. From 22deb5045dceb96afaca506299f4bf60dd92bd52 Mon Sep 17 00:00:00 2001 From: Sean Malloy Date: Sun, 4 Feb 2018 01:16:34 -0600 Subject: [PATCH 4/4] Remove extra new line from googlecompute docs --- website/source/docs/builders/googlecompute.html.md | 1 - 1 file changed, 1 deletion(-) diff --git a/website/source/docs/builders/googlecompute.html.md b/website/source/docs/builders/googlecompute.html.md index d9be8cd28..cda97b02c 100644 --- a/website/source/docs/builders/googlecompute.html.md +++ b/website/source/docs/builders/googlecompute.html.md @@ -166,7 +166,6 @@ for details. } ] } - ``` ## Configuration Reference