diff --git a/google/resource_compute_region_instance_group_manager.go b/google/resource_compute_region_instance_group_manager.go index f67a918f67c..5acb90fd695 100644 --- a/google/resource_compute_region_instance_group_manager.go +++ b/google/resource_compute_region_instance_group_manager.go @@ -1,19 +1,25 @@ package google import ( + "fmt" + "log" + "strings" + "time" + + "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/validation" - "log" - "fmt" computeBeta "google.golang.org/api/compute/v0.beta" "google.golang.org/api/compute/v1" - "time" ) var RegionInstanceGroupManagerBaseApiVersion = v1 -var RegionInstanceGroupManagerVersionedFeatures = []Feature{Feature{Version: v0beta, Item: "auto_healing_policies"}} +var RegionInstanceGroupManagerVersionedFeatures = []Feature{ + Feature{Version: v0beta, Item: "auto_healing_policies"}, + Feature{Version: v0beta, Item: "distribution_policy_zones"}, +} func resourceComputeRegionInstanceGroupManager() *schema.Resource { return &schema.Resource{ @@ -109,7 +115,6 @@ func resourceComputeRegionInstanceGroupManager() *schema.Resource { }, Set: selfLinkRelativePathHash, }, - "target_size": &schema.Schema{ Type: schema.TypeInt, Computed: true, @@ -145,6 +150,18 @@ func resourceComputeRegionInstanceGroupManager() *schema.Resource { }, }, }, + + "distribution_policy_zones": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + ForceNew: true, + Computed: true, + Set: hashZoneFromSelfLinkOrResourceName, + Elem: &schema.Schema{ + Type: schema.TypeString, + DiffSuppressFunc: compareSelfLinkOrResourceName, + }, + }, }, } } @@ -167,6 +184,7 @@ func resourceComputeRegionInstanceGroupManagerCreate(d *schema.ResourceData, met NamedPorts: getNamedPortsBeta(d.Get("named_port").([]interface{})), TargetPools: convertStringSet(d.Get("target_pools").(*schema.Set)), AutoHealingPolicies: expandAutoHealingPolicies(d.Get("auto_healing_policies").([]interface{})), + DistributionPolicy: expandDistributionPolicy(d.Get("distribution_policy_zones").(*schema.Set)), // Force send TargetSize to allow size of 0. ForceSendFields: []string{"TargetSize"}, } @@ -212,6 +230,7 @@ func getManager(d *schema.ResourceData, meta interface{}) (*computeBeta.Instance region := d.Get("region").(string) manager := &computeBeta.InstanceGroupManager{} + switch computeApiVersion { case v1: v1Manager := &compute.InstanceGroupManager{} @@ -226,7 +245,7 @@ func getManager(d *schema.ResourceData, meta interface{}) (*computeBeta.Instance } if err != nil { - handleNotFoundError(err, d, fmt.Sprintf("Region Instance Manager %q", d.Get("name").(string))) + return nil, handleNotFoundError(err, d, fmt.Sprintf("Region Instance Manager %q", d.Get("name").(string))) } return manager, nil } @@ -270,6 +289,9 @@ func resourceComputeRegionInstanceGroupManagerRead(d *schema.ResourceData, meta d.Set("fingerprint", manager.Fingerprint) d.Set("instance_group", manager.InstanceGroup) d.Set("auto_healing_policies", flattenAutoHealingPolicies(manager.AutoHealingPolicies)) + if err := d.Set("distribution_policy_zones", flattenDistributionPolicy(manager.DistributionPolicy)); err != nil { + return err + } d.Set("self_link", ConvertSelfLinkToV1(manager.SelfLink)) if d.Get("wait_for_instances").(bool) { @@ -509,3 +531,39 @@ func resourceComputeRegionInstanceGroupManagerDelete(d *schema.ResourceData, met d.SetId("") return nil } + +func expandDistributionPolicy(configured *schema.Set) *computeBeta.DistributionPolicy { + if configured.Len() == 0 { + return nil + } + + distributionPolicyZoneConfigs := make([]*computeBeta.DistributionPolicyZoneConfiguration, 0, configured.Len()) + for _, raw := range configured.List() { + data := raw.(string) + distributionPolicyZoneConfig := computeBeta.DistributionPolicyZoneConfiguration{ + Zone: "zones/" + data, + } + + distributionPolicyZoneConfigs = append(distributionPolicyZoneConfigs, &distributionPolicyZoneConfig) + } + return &computeBeta.DistributionPolicy{Zones: distributionPolicyZoneConfigs} +} + +func flattenDistributionPolicy(distributionPolicy *computeBeta.DistributionPolicy) []string { + zones := make([]string, 0) + + if distributionPolicy != nil { + for _, zone := range distributionPolicy.Zones { + zones = append(zones, zone.Zone) + } + } + + return zones +} + +func hashZoneFromSelfLinkOrResourceName(value interface{}) int { + parts := strings.Split(value.(string), "/") + resource := parts[len(parts)-1] + + return hashcode.String(resource) +} diff --git a/google/resource_compute_region_instance_group_manager_test.go b/google/resource_compute_region_instance_group_manager_test.go index ab998d7867c..9bf705ca87c 100644 --- a/google/resource_compute_region_instance_group_manager_test.go +++ b/google/resource_compute_region_instance_group_manager_test.go @@ -204,6 +204,32 @@ func TestAccRegionInstanceGroupManager_autoHealingPolicies(t *testing.T) { }) } +func TestAccRegionInstanceGroupManager_distributionPolicy(t *testing.T) { + t.Parallel() + + var manager computeBeta.InstanceGroupManager + + template := fmt.Sprintf("igm-test-%s", acctest.RandString(10)) + igm := fmt.Sprintf("igm-test-%s", acctest.RandString(10)) + zones := []string{"us-central1-a", "us-central1-b"} + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckRegionInstanceGroupManagerDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccRegionInstanceGroupManager_distributionPolicy(template, igm, zones), + Check: resource.ComposeTestCheckFunc( + testAccCheckRegionInstanceGroupManagerBetaExists( + "google_compute_region_instance_group_manager.igm-basic", &manager), + testAccCheckRegionInstanceGroupManagerDistributionPolicy("google_compute_region_instance_group_manager.igm-basic", zones), + ), + }, + }, + }) +} + func testAccCheckRegionInstanceGroupManagerDestroy(s *terraform.State) error { config := testAccProvider.Meta().(*Config) @@ -401,6 +427,51 @@ func testAccCheckRegionInstanceGroupManagerAutoHealingPolicies(n, hck string, in } } +func testAccCheckRegionInstanceGroupManagerDistributionPolicy(n string, zones []string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + + config := testAccProvider.Meta().(*Config) + + manager, err := config.clientComputeBeta.RegionInstanceGroupManagers.Get( + config.Project, rs.Primary.Attributes["region"], rs.Primary.ID).Do() + if err != nil { + return err + } + + if manager.DistributionPolicy == nil { + return fmt.Errorf("Expected distribution policy to exist") + } + + zoneConfigs := manager.DistributionPolicy.Zones + if len(zoneConfigs) != len(zones) { + return fmt.Errorf("Expected number of zones in distribution policy to match; had %d, expected %d", len(zoneConfigs), len(zones)) + } + + sort.Strings(zones) + sortedExisting := make([]string, 0) + for _, zone := range zoneConfigs { + sortedExisting = append(sortedExisting, zone.Zone) + } + sort.Strings(sortedExisting) + + for i := 0; i < len(zones); i++ { + if !strings.HasSuffix(sortedExisting[i], zones[i]) { + return fmt.Errorf("found mismatched zone configuration: expected entry #%d as '%s', got %s", i, zones[i], sortedExisting[i]) + } + } + + return nil + } +} + func testAccCheckRegionInstanceGroupManagerTemplateTags(n string, tags []string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -798,3 +869,35 @@ resource "google_compute_http_health_check" "zero" { } `, template, target, igm, hck) } + +func testAccRegionInstanceGroupManager_distributionPolicy(template, igm string, zones []string) string { + return fmt.Sprintf(` +resource "google_compute_instance_template" "igm-basic" { + name = "%s" + machine_type = "n1-standard-1" + can_ip_forward = false + tags = ["foo", "bar"] + disk { + source_image = "debian-cloud/debian-8-jessie-v20160803" + auto_delete = true + boot = true + } + network_interface { + network = "default" + } + metadata { + foo = "bar" + } +} + +resource "google_compute_region_instance_group_manager" "igm-basic" { + description = "Terraform test instance group manager" + name = "%s" + instance_template = "${google_compute_instance_template.igm-basic.self_link}" + base_instance_name = "igm-basic" + region = "us-central1" + target_size = 2 + distribution_policy_zones = ["%s"] +} + `, template, igm, strings.Join(zones, "\",\"")) +} diff --git a/website/docs/r/compute_region_instance_group_manager.html.markdown b/website/docs/r/compute_region_instance_group_manager.html.markdown index b67d9fce736..561769768c0 100644 --- a/website/docs/r/compute_region_instance_group_manager.html.markdown +++ b/website/docs/r/compute_region_instance_group_manager.html.markdown @@ -34,9 +34,10 @@ resource "google_compute_health_check" "autohealing" { resource "google_compute_region_instance_group_manager" "appserver" { name = "appserver-igm" - base_instance_name = "app" - instance_template = "${google_compute_instance_template.appserver.self_link}" - region = "us-central1" + base_instance_name = "app" + instance_template = "${google_compute_instance_template.appserver.self_link}" + region = "us-central1" + distribution_policy_zones = ["us-central1-a", "us-central1-f"] target_pools = ["${google_compute_target_pool.appserver.self_link}"] target_size = 2 @@ -99,6 +100,10 @@ The following arguments are supported: * `auto_healing_policies` - (Optional, [Beta](/docs/providers/google/index.html#beta-features)) The autohealing policies for this managed instance group. You can specify only one value. Structure is documented below. For more information, see the [official documentation](https://cloud.google.com/compute/docs/instance-groups/creating-groups-of-managed-instances#monitoring_groups). +* `distribution_policy_zones` - (Optional, [Beta](/docs/providers/google/index.html#beta-features)) The distribution policy for this managed instance +group. You can specify one or more values. For more information, see the [official documentation](https://cloud.google.com/compute/docs/instance-groups/distributing-instances-with-regional-instance-groups#selectingzones). + + The `named_port` block supports: (Include a `named_port` block for each named-port required). * `name` - (Required) The name of the port.