Support distributionPolicy when creating regional instance group managers. (#1092)

* Support `distributionPolicy` when creating regional instance group managers.

* Better match the API structure of distributionPolicy.

* Switch to "distribution_policy_zones".

This approach lets us more simply allow a list of zones to use, while
providing a deprecation path for implementing the distribution policy
field more holistically, avoiding backwards-incompatible changes.

* fix typo

* use slice instead of Set for flattenDP
This commit is contained in:
Toby Lawrence 2018-03-09 14:04:09 -05:00 committed by Dana Hoffman
parent 1d1cfa64c4
commit 08e81f528c
3 changed files with 175 additions and 9 deletions

View File

@ -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)
}

View File

@ -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, "\",\""))
}

View File

@ -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.