From 84162586b04908a78ee3f5cfde261fa6f8017f95 Mon Sep 17 00:00:00 2001 From: Christoph Blecker Date: Mon, 15 Aug 2016 14:29:58 -0700 Subject: [PATCH] Add support for using GCP Image Family names. (#8083) --- builtin/providers/google/image.go | 25 ++++- .../google/resource_compute_instance_test.go | 95 ++++++++++++++++++- .../google/r/compute_instance.html.markdown | 6 +- .../r/compute_instance_template.html.markdown | 4 +- 4 files changed, 120 insertions(+), 10 deletions(-) diff --git a/builtin/providers/google/image.go b/builtin/providers/google/image.go index 642b74d9b..5a006eb9a 100644 --- a/builtin/providers/google/image.go +++ b/builtin/providers/google/image.go @@ -6,8 +6,10 @@ import ( ) // If the given name is a URL, return it. -// If it is of the form project/name, use that URL. -// If it is of the form name then look in the configured project and then hosted image projects. +// If it is of the form project/name, search the specified project first, then +// search image families in the specified project. +// If it is of the form name then look in the configured project, then hosted +// image projects, and lastly at image families in hosted image projects. func resolveImage(c *Config, name string) (string, error) { if strings.HasPrefix(name, "https://www.googleapis.com/compute/v1/") { @@ -28,8 +30,8 @@ func resolveImage(c *Config, name string) (string, error) { // If we match a lookup for an alternate project, then try that next. // If not, we return the original error. - // If the image name contains the left hand side, we use the project from the right hand - // side. + // If the image name contains the left hand side, we use the project from + // the right hand side. imageMap := map[string]string{ "centos": "centos-cloud", "coreos": "coreos-cloud", @@ -57,13 +59,28 @@ func resolveImage(c *Config, name string) (string, error) { return image.SelfLink, nil } + // If it doesn't exist, try to see if it works as an image family: + image, err = c.clientCompute.Images.GetFromFamily(project, name).Do() + if err == nil { + return image.SelfLink, nil + } + return "", err } else if len(splitName) == 2 { + + // Check if image exists in the specified project: image, err := c.clientCompute.Images.Get(splitName[0], splitName[1]).Do() if err == nil { return image.SelfLink, nil } + + // If it doesn't, check if it exists as an image family: + image, err = c.clientCompute.Images.GetFromFamily(splitName[0], splitName[1]).Do() + if err == nil { + return image.SelfLink, nil + } + return "", err } else { diff --git a/builtin/providers/google/resource_compute_instance_test.go b/builtin/providers/google/resource_compute_instance_test.go index a20e127e1..bdd8c3d3e 100644 --- a/builtin/providers/google/resource_compute_instance_test.go +++ b/builtin/providers/google/resource_compute_instance_test.go @@ -104,6 +104,52 @@ func TestAccComputeInstance_basic3(t *testing.T) { }) } +func TestAccComputeInstance_basic4(t *testing.T) { + var instance compute.Instance + var instanceName = fmt.Sprintf("instance-test-%s", acctest.RandString(10)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeInstanceDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccComputeInstance_basic4(instanceName), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeInstanceExists( + "google_compute_instance.foobar", &instance), + testAccCheckComputeInstanceTag(&instance, "foo"), + testAccCheckComputeInstanceMetadata(&instance, "foo", "bar"), + testAccCheckComputeInstanceDisk(&instance, instanceName, true, true), + ), + }, + }, + }) +} + +func TestAccComputeInstance_basic5(t *testing.T) { + var instance compute.Instance + var instanceName = fmt.Sprintf("instance-test-%s", acctest.RandString(10)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeInstanceDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccComputeInstance_basic5(instanceName), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeInstanceExists( + "google_compute_instance.foobar", &instance), + testAccCheckComputeInstanceTag(&instance, "foo"), + testAccCheckComputeInstanceMetadata(&instance, "foo", "bar"), + testAccCheckComputeInstanceDisk(&instance, instanceName, true, true), + ), + }, + }, + }) +} + func TestAccComputeInstance_IP(t *testing.T) { var instance compute.Instance var ipName = fmt.Sprintf("instance-test-%s", acctest.RandString(10)) @@ -665,6 +711,29 @@ func testAccComputeInstance_basic(instance string) string { } func testAccComputeInstance_basic2(instance string) string { + return fmt.Sprintf(` + resource "google_compute_instance" "foobar" { + name = "%s" + machine_type = "n1-standard-1" + zone = "us-central1-a" + can_ip_forward = false + tags = ["foo", "bar"] + + disk { + image = "debian-8" + } + + network_interface { + network = "default" + } + + metadata { + foo = "bar" + } + }`, instance) +} + +func testAccComputeInstance_basic3(instance string) string { return fmt.Sprintf(` resource "google_compute_instance" "foobar" { name = "%s" @@ -688,7 +757,31 @@ func testAccComputeInstance_basic2(instance string) string { }`, instance) } -func testAccComputeInstance_basic3(instance string) string { +func testAccComputeInstance_basic4(instance string) string { + return fmt.Sprintf(` + resource "google_compute_instance" "foobar" { + name = "%s" + machine_type = "n1-standard-1" + zone = "us-central1-a" + can_ip_forward = false + tags = ["foo", "bar"] + + disk { + image = "debian-cloud/debian-8" + } + + network_interface { + network = "default" + } + + + metadata { + foo = "bar" + } + }`, instance) +} + +func testAccComputeInstance_basic5(instance string) string { return fmt.Sprintf(` resource "google_compute_instance" "foobar" { name = "%s" diff --git a/website/source/docs/providers/google/r/compute_instance.html.markdown b/website/source/docs/providers/google/r/compute_instance.html.markdown index 3164f1061..a9f102446 100644 --- a/website/source/docs/providers/google/r/compute_instance.html.markdown +++ b/website/source/docs/providers/google/r/compute_instance.html.markdown @@ -112,8 +112,9 @@ the type is "local-ssd", in which case scratch must be true). `google_compute_disk`) to attach. * `image` - The image from which to initialize this - disk. Either the full URL, a contraction of the form "project/name", or - just a name (in which case the current project is used). + disk. Either the full URL, a contraction of the form "project/name", an + [image family](https://cloud.google.com/compute/docs/images#image_families), + or just a name (in which case the current project is used). * `auto_delete` - (Optional) Whether or not the disk should be auto-deleted. This defaults to true. Leave true for local SSDs. @@ -195,4 +196,3 @@ exported: * `network_interface.0.address` - The internal ip address of the instance, either manually or dynamically assigned. * `network_interface.0.access_config.0.assigned_nat_ip` - If the instance has an access config, either the given external ip (in the `nat_ip` field) or the ephemeral (generated) ip (if you didn't provide one). - diff --git a/website/source/docs/providers/google/r/compute_instance_template.html.markdown b/website/source/docs/providers/google/r/compute_instance_template.html.markdown index be56da80e..52cfd1766 100644 --- a/website/source/docs/providers/google/r/compute_instance_template.html.markdown +++ b/website/source/docs/providers/google/r/compute_instance_template.html.markdown @@ -83,7 +83,7 @@ resource "google_compute_instance_template" "instance_template" { network_interface { ... } - + lifecycle { create_before_destroy = true } @@ -169,7 +169,7 @@ The `disk` block supports: to the name of the instance. * `source_image` - (Required if source not set) The name of the image to base - this disk off of. + this disk off of. Accepts same arguments as a [google_compute_instance image](https://www.terraform.io/docs/providers/google/r/compute_instance.html#image). * `interface` - (Optional) Specifies the disk interface to use for attaching this disk.