Skip to content

Commit

Permalink
Support distributionPolicy when creating regional instance group ma…
Browse files Browse the repository at this point in the history
…nagers. (#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
  • Loading branch information
tobz authored and danawillow committed Mar 9, 2018
1 parent 1d1cfa6 commit 08e81f5
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 9 deletions.
70 changes: 64 additions & 6 deletions google/resource_compute_region_instance_group_manager.go
Original file line number Diff line number Diff line change
@@ -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{
Expand Down Expand Up @@ -109,7 +115,6 @@ func resourceComputeRegionInstanceGroupManager() *schema.Resource {
},
Set: selfLinkRelativePathHash,
},

"target_size": &schema.Schema{
Type: schema.TypeInt,
Computed: true,
Expand Down Expand Up @@ -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,
},
},
},
}
}
Expand All @@ -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"},
}
Expand Down Expand Up @@ -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{}
Expand All @@ -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
}
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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)
}
103 changes: 103 additions & 0 deletions google/resource_compute_region_instance_group_manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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, "\",\""))
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit 08e81f5

Please sign in to comment.