From a0836c58462578e2fb5b40fcd432f5327b50c8da Mon Sep 17 00:00:00 2001 From: Modular Magician Date: Sat, 10 Oct 2020 00:23:04 +0000 Subject: [PATCH] Add Image filters to google_compute_image. (#4026) * add image filter support * fix typos in documentation * fix client function Signed-off-by: Modular Magician --- .changelog/4026.txt | 3 + google/data_source_google_compute_image.go | 41 ++++++++++---- .../data_source_google_compute_image_test.go | 56 +++++++++++++++++++ website/docs/d/compute_image.html.markdown | 9 +-- 4 files changed, 94 insertions(+), 15 deletions(-) create mode 100644 .changelog/4026.txt diff --git a/.changelog/4026.txt b/.changelog/4026.txt new file mode 100644 index 00000000000..e9bfe355625 --- /dev/null +++ b/.changelog/4026.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +compute: added filter field to google_compute_image datasource +``` diff --git a/google/data_source_google_compute_image.go b/google/data_source_google_compute_image.go index c51e91e0832..dde16ed2636 100644 --- a/google/data_source_google_compute_image.go +++ b/google/data_source_google_compute_image.go @@ -15,18 +15,24 @@ func dataSourceGoogleComputeImage() *schema.Resource { Schema: map[string]*schema.Schema{ "name": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Computed: true, - ConflictsWith: []string{"family"}, + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + ExactlyOneOf: []string{"name", "family", "filter"}, }, "family": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Computed: true, - ConflictsWith: []string{"name"}, + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Computed: true, + ExactlyOneOf: []string{"name", "family", "filter"}, + }, + "filter": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ExactlyOneOf: []string{"name", "family", "filter"}, }, "archive_size_bytes": { Type: schema.TypeInt, @@ -125,8 +131,21 @@ func dataSourceGoogleComputeImageRead(d *schema.ResourceData, meta interface{}) log.Printf("[DEBUG] Fetching latest non-deprecated image from family %s", v.(string)) image, err = config.NewComputeClient(userAgent).Images.GetFromFamily(project, v.(string)).Do() log.Printf("[DEBUG] Fetched latest non-deprecated image from family %s", v.(string)) + } else if v, ok := d.GetOk("filter"); ok { + images, err := config.NewComputeClient(userAgent).Images.List(project).Filter(v.(string)).Do() + if err != nil { + return fmt.Errorf("error retrieving list of images: %s", err) + } + + if len(images.Items) == 1 { + for _, im := range images.Items { + image = im + } + } else { + return fmt.Errorf("your filter has returned more than one image or no image. Please refine your filter to return exactly one image") + } } else { - return fmt.Errorf("one of name or family must be set") + return fmt.Errorf("one of name, family or filters must be set") } if err != nil { diff --git a/google/data_source_google_compute_image_test.go b/google/data_source_google_compute_image_test.go index c22f249b2e0..c0e760eaa4d 100644 --- a/google/data_source_google_compute_image_test.go +++ b/google/data_source_google_compute_image_test.go @@ -40,6 +40,38 @@ func TestAccDataSourceComputeImage(t *testing.T) { }) } +func TestAccDataSourceComputeImageFilter(t *testing.T) { + t.Parallel() + + family := fmt.Sprintf("tf-test-%d", randInt(t)) + name := fmt.Sprintf("tf-test-%d", randInt(t)) + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeImageDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccDataSourcePublicImageConfig, + Check: resource.ComposeTestCheckFunc( + testAccDataSourceCheckPublicImage(), + ), + }, + { + Config: testAccDataSourceCustomImageFilter(family, name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.google_compute_image.from_filter", + "name", name), + resource.TestCheckResourceAttr("data.google_compute_image.from_filter", + "family", family), + resource.TestCheckResourceAttrSet("data.google_compute_image.from_filter", + "self_link"), + ), + }, + }, + }) +} + func testAccDataSourceCheckPublicImage() resource.TestCheckFunc { return func(s *terraform.State) error { data_source_name := "data.google_compute_image.debian" @@ -105,3 +137,27 @@ data "google_compute_image" "from_family" { } `, family, name, name) } + +func testAccDataSourceCustomImageFilter(family, name string) string { + return fmt.Sprintf(` +resource "google_compute_image" "image" { + family = "%s" + name = "%s" + source_disk = google_compute_disk.disk.self_link + labels = { + test = "%s" + } +} + +resource "google_compute_disk" "disk" { + name = "%s-disk" + zone = "us-central1-b" +} + +data "google_compute_image" "from_filter" { + project = google_compute_image.image.project + filter = "labels.test = %s" +} + +`, family, name, name, name, name) +} diff --git a/website/docs/d/compute_image.html.markdown b/website/docs/d/compute_image.html.markdown index 127cd632016..e980e537bb1 100644 --- a/website/docs/d/compute_image.html.markdown +++ b/website/docs/d/compute_image.html.markdown @@ -35,10 +35,11 @@ resource "google_compute_instance" "default" { The following arguments are supported: -* `name` or `family` - (Required) The name of a specific image or a family. -Exactly one of `name` of `family` must be specified. If `name` is specified, it will fetch -the corresponding image. If `family` is specified, it will returns the latest image -that is part of an image family and is not deprecated. +* `name`, `family` or `filter` - (Required) The name of a specific image or a family. +Exactly one of `name`, `family` or `filter` must be specified. If `name` is specified, it will fetch +the corresponding image. If `family` is specified, it will return the latest image +that is part of an image family and is not deprecated. If you specify `filter`, your +filter must return exactly one image. Filter syntax can be found [here](https://cloud.google.com/compute/docs/reference/rest/v1/images/list) in the filter section. - - -