From 76c40ac451a4a3b2e80c49c88ed2e5ae15fcd45b Mon Sep 17 00:00:00 2001 From: Radek Simko Date: Tue, 14 Feb 2017 23:35:17 +0000 Subject: [PATCH] provider/google: Add google_compute_zones data source --- .../data_source_google_compute_zones.go | 80 +++++++++++++++++++ .../data_source_google_compute_zones_test.go | 70 ++++++++++++++++ builtin/providers/google/provider.go | 3 +- .../d/google_compute_zones.html.markdown | 40 ++++++++++ website/source/layouts/google.erb | 3 + 5 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 builtin/providers/google/data_source_google_compute_zones.go create mode 100644 builtin/providers/google/data_source_google_compute_zones_test.go create mode 100644 website/source/docs/providers/google/d/google_compute_zones.html.markdown diff --git a/builtin/providers/google/data_source_google_compute_zones.go b/builtin/providers/google/data_source_google_compute_zones.go new file mode 100644 index 000000000000..a200aba5cd3f --- /dev/null +++ b/builtin/providers/google/data_source_google_compute_zones.go @@ -0,0 +1,80 @@ +package google + +import ( + "fmt" + "log" + "sort" + "time" + + "github.com/hashicorp/terraform/helper/schema" + compute "google.golang.org/api/compute/v1" +) + +func dataSourceGoogleComputeZones() *schema.Resource { + return &schema.Resource{ + Read: dataSourceGoogleComputeZonesRead, + Schema: map[string]*schema.Schema{ + "region": { + Type: schema.TypeString, + Optional: true, + }, + "names": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "status": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: func(v interface{}, k string) (ws []string, es []error) { + value := v.(string) + if value != "UP" && value != "DOWN" { + es = append(es, fmt.Errorf("%q can only be 'UP' or 'DOWN' (%q given)", k, value)) + } + return + }, + }, + }, + } +} + +func dataSourceGoogleComputeZonesRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + region := config.Region + if r, ok := d.GetOk("region"); ok { + region = r.(string) + } + + regionUrl := fmt.Sprintf("https://www.googleapis.com/compute/v1/projects/%s/regions/%s", + config.Project, region) + filter := fmt.Sprintf("(region eq %s)", regionUrl) + + if s, ok := d.GetOk("status"); ok { + filter += fmt.Sprintf(" (status eq %s)", s) + } + + call := config.clientCompute.Zones.List(config.Project).Filter(filter) + + resp, err := call.Do() + if err != nil { + return err + } + + zones := flattenZones(resp.Items) + log.Printf("[DEBUG] Received Google Compute Zones: %q", zones) + + d.Set("names", zones) + d.SetId(time.Now().UTC().String()) + + return nil +} + +func flattenZones(zones []*compute.Zone) []string { + result := make([]string, len(zones), len(zones)) + for i, zone := range zones { + result[i] = zone.Name + } + sort.Strings(result) + return result +} diff --git a/builtin/providers/google/data_source_google_compute_zones_test.go b/builtin/providers/google/data_source_google_compute_zones_test.go new file mode 100644 index 000000000000..80dabf220dd2 --- /dev/null +++ b/builtin/providers/google/data_source_google_compute_zones_test.go @@ -0,0 +1,70 @@ +package google + +import ( + "errors" + "fmt" + "strconv" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccGoogleComputeZones_basic(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckGoogleComputeZonesConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckGoogleComputeZonesMeta("data.google_compute_zones.available"), + ), + }, + }, + }) +} + +func testAccCheckGoogleComputeZonesMeta(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Can't find zones data source: %s", n) + } + + if rs.Primary.ID == "" { + return errors.New("zones data source ID not set.") + } + + count, ok := rs.Primary.Attributes["names.#"] + if !ok { + return errors.New("can't find 'names' attribute") + } + + noOfNames, err := strconv.Atoi(count) + if err != nil { + return errors.New("failed to read number of zones") + } + if noOfNames < 2 { + return fmt.Errorf("expected at least 2 zones, received %d, this is most likely a bug", + noOfNames) + } + + for i := 0; i < noOfNames; i++ { + idx := "names." + strconv.Itoa(i) + v, ok := rs.Primary.Attributes[idx] + if !ok { + return fmt.Errorf("zone list is corrupt (%q not found), this is definitely a bug", idx) + } + if len(v) < 1 { + return fmt.Errorf("Empty zone name (%q), this is definitely a bug", idx) + } + } + + return nil + } +} + +var testAccCheckGoogleComputeZonesConfig = ` +data "google_compute_zones" "available" {} +` diff --git a/builtin/providers/google/provider.go b/builtin/providers/google/provider.go index d1263efaa107..f4d7d5f7b771 100644 --- a/builtin/providers/google/provider.go +++ b/builtin/providers/google/provider.go @@ -57,7 +57,8 @@ func Provider() terraform.ResourceProvider { }, DataSourcesMap: map[string]*schema.Resource{ - "google_iam_policy": dataSourceGoogleIamPolicy(), + "google_iam_policy": dataSourceGoogleIamPolicy(), + "google_compute_zones": dataSourceGoogleComputeZones(), }, ResourcesMap: map[string]*schema.Resource{ diff --git a/website/source/docs/providers/google/d/google_compute_zones.html.markdown b/website/source/docs/providers/google/d/google_compute_zones.html.markdown new file mode 100644 index 000000000000..ec441f09a310 --- /dev/null +++ b/website/source/docs/providers/google/d/google_compute_zones.html.markdown @@ -0,0 +1,40 @@ +--- +layout: "google" +page_title: "Google: google_compute_zones" +sidebar_current: "docs-google-datasource-compute-zones" +description: |- + Provides a list of available Google Compute zones +--- + +# google\_compute\_zones + +Provides access to available Google Compute zones in a region for a given project. +See more about [regions and zones](https://cloud.google.com/compute/docs/regions-zones/regions-zones) in the upstream docs. + +``` +data "google_compute_zones" "available" {} + +resource "google_compute_instance_group_manager" "foo" { + count = "${length(data.google_compute_zones.available.names)}" + + name = "terraform-test-${count.index}" + instance_template = "${google_compute_instance_template.foobar.self_link}" + base_instance_name = "foobar-${count.index}" + zone = "${data.google_compute_zones.available.names[count.index]}" + target_size = 1 +} +``` + +## Argument Reference + +The following arguments are supported: + +* `region` (Optional) - Region from which to list available zones. Defaults to region declared in the provider. +* `status` (Optional) - Allows to filter list of zones based on their current status. Status can be either `UP` or `DOWN`. + Defaults to no filtering (all available zones - both `UP` and `DOWN`). + +## Attributes Reference + +The following attribute is exported: + +* `names` - A list of zones available in the given region diff --git a/website/source/layouts/google.erb b/website/source/layouts/google.erb index 7b028f852f65..074543363423 100644 --- a/website/source/layouts/google.erb +++ b/website/source/layouts/google.erb @@ -13,6 +13,9 @@ > Google Cloud Platform Data Sources