Merge pull request #1260 from wayfair/ishashchuk_rigm_rolling

rIGM rolling update support
This commit is contained in:
Paddy 2018-03-29 14:30:17 -07:00 committed by GitHub
commit ea3d1034d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 351 additions and 2 deletions

View File

@ -870,6 +870,8 @@ func expandUpdatePolicy(configured []interface{}) *computeBeta.InstanceGroupMana
} else {
updatePolicy.MaxSurge = &computeBeta.FixedOrPercent{
Fixed: int64(data["max_surge_fixed"].(int)),
// allow setting this value to 0
ForceSendFields: []string{"Fixed"},
}
}
@ -880,6 +882,8 @@ func expandUpdatePolicy(configured []interface{}) *computeBeta.InstanceGroupMana
} else {
updatePolicy.MaxUnavailable = &computeBeta.FixedOrPercent{
Fixed: int64(data["max_unavailable_fixed"].(int)),
// allow setting this value to 0
ForceSendFields: []string{"Fixed"},
}
}

View File

@ -19,6 +19,7 @@ var RegionInstanceGroupManagerBaseApiVersion = v1
var RegionInstanceGroupManagerVersionedFeatures = []Feature{
Feature{Version: v0beta, Item: "auto_healing_policies"},
Feature{Version: v0beta, Item: "distribution_policy_zones"},
Feature{Version: v0beta, Item: "rolling_update_policy"},
}
func resourceComputeRegionInstanceGroupManager() *schema.Resource {
@ -107,6 +108,13 @@ func resourceComputeRegionInstanceGroupManager() *schema.Resource {
Computed: true,
},
"update_strategy": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Default: "NONE",
ValidateFunc: validation.StringInSlice([]string{"NONE", "ROLLING_UPDATE"}, false),
},
"target_pools": &schema.Schema{
Type: schema.TypeSet,
Optional: true,
@ -162,6 +170,61 @@ func resourceComputeRegionInstanceGroupManager() *schema.Resource {
DiffSuppressFunc: compareSelfLinkOrResourceName,
},
},
"rolling_update_policy": &schema.Schema{
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"minimal_action": &schema.Schema{
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{"RESTART", "REPLACE"}, false),
},
"type": &schema.Schema{
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringInSlice([]string{"OPPORTUNISTIC", "PROACTIVE"}, false),
},
"max_surge_fixed": &schema.Schema{
Type: schema.TypeInt,
Optional: true,
Default: 0,
ConflictsWith: []string{"rolling_update_policy.0.max_surge_percent"},
},
"max_surge_percent": &schema.Schema{
Type: schema.TypeInt,
Optional: true,
ConflictsWith: []string{"rolling_update_policy.0.max_surge_fixed"},
ValidateFunc: validation.IntBetween(0, 100),
},
"max_unavailable_fixed": &schema.Schema{
Type: schema.TypeInt,
Optional: true,
Default: 0,
ConflictsWith: []string{"rolling_update_policy.0.max_unavailable_percent"},
},
"max_unavailable_percent": &schema.Schema{
Type: schema.TypeInt,
Optional: true,
ConflictsWith: []string{"rolling_update_policy.0.max_unavailable_fixed"},
ValidateFunc: validation.IntBetween(0, 100),
},
"min_ready_sec": &schema.Schema{
Type: schema.TypeInt,
Optional: true,
ValidateFunc: validation.IntBetween(0, 3600),
},
},
},
},
},
}
}
@ -175,6 +238,10 @@ func resourceComputeRegionInstanceGroupManagerCreate(d *schema.ResourceData, met
return err
}
if _, ok := d.GetOk("rolling_update_policy"); d.Get("update_strategy") == "ROLLING_UPDATE" && !ok {
return fmt.Errorf("[rolling_update_policy] must be set when 'update_strategy' is set to 'ROLLING_UPDATE'")
}
manager := &computeBeta.InstanceGroupManager{
Name: d.Get("name").(string),
Description: d.Get("description").(string),
@ -323,6 +390,10 @@ func resourceComputeRegionInstanceGroupManagerUpdate(d *schema.ResourceData, met
d.Partial(true)
if _, ok := d.GetOk("rolling_update_policy"); d.Get("update_strategy") == "ROLLING_UPDATE" && !ok {
return fmt.Errorf("[rolling_update_policy] must be set when 'update_strategy' is set to 'ROLLING_UPDATE'")
}
if d.HasChange("target_pools") {
targetPools := convertStringSet(d.Get("target_pools").(*schema.Set))
@ -405,6 +476,28 @@ func resourceComputeRegionInstanceGroupManagerUpdate(d *schema.ResourceData, met
return err
}
if d.Get("update_strategy").(string) == "ROLLING_UPDATE" {
// UpdatePolicy is set for InstanceGroupManager on update only, because it is only relevant for `Patch` calls.
// Other tools(gcloud and UI) capable of executing the same `ROLLING UPDATE` call
// expect those values to be provided by user as part of the call
// or provide their own defaults without respecting what was previously set on UpdateManager.
// To follow the same logic, we provide policy values on relevant update change only.
manager := &computeBeta.InstanceGroupManager{
UpdatePolicy: expandUpdatePolicy(d.Get("rolling_update_policy").([]interface{})),
}
op, err = config.clientComputeBeta.RegionInstanceGroupManagers.Patch(
project, region, d.Id(), manager).Do()
if err != nil {
return fmt.Errorf("Error updating managed group instances: %s", err)
}
err = computeSharedOperationWait(config.clientCompute, op, project, "Updating managed group instances")
if err != nil {
return err
}
}
d.SetPartial("instance_template")
}

View File

@ -151,6 +151,85 @@ func TestAccRegionInstanceGroupManager_updateLifecycle(t *testing.T) {
})
}
func TestAccRegionInstanceGroupManager_updateStrategy(t *testing.T) {
t.Parallel()
var manager compute.InstanceGroupManager
igm := fmt.Sprintf("igm-test-%s", acctest.RandString(10))
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckInstanceGroupManagerDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccRegionInstanceGroupManager_updateStrategy(igm),
Check: resource.ComposeTestCheckFunc(
testAccCheckRegionInstanceGroupManagerExists(
"google_compute_region_instance_group_manager.igm-update-strategy", &manager),
resource.TestCheckResourceAttr(
"google_compute_region_instance_group_manager.igm-update-strategy", "update_strategy", "NONE"),
),
},
},
})
}
func TestAccRegionInstanceGroupManager_rollingUpdatePolicy(t *testing.T) {
t.Parallel()
var manager computeBeta.InstanceGroupManager
igm := fmt.Sprintf("igm-test-%s", acctest.RandString(10))
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckInstanceGroupManagerDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccRegionInstanceGroupManager_rollingUpdatePolicy(igm),
Check: resource.ComposeTestCheckFunc(
testAccCheckRegionInstanceGroupManagerBetaExists(
"google_compute_region_instance_group_manager.igm-rolling-update-policy", &manager),
resource.TestCheckResourceAttr(
"google_compute_region_instance_group_manager.igm-rolling-update-policy", "update_strategy", "ROLLING_UPDATE"),
resource.TestCheckResourceAttr(
"google_compute_region_instance_group_manager.igm-rolling-update-policy", "rolling_update_policy.0.type", "PROACTIVE"),
resource.TestCheckResourceAttr(
"google_compute_region_instance_group_manager.igm-rolling-update-policy", "rolling_update_policy.0.minimal_action", "REPLACE"),
resource.TestCheckResourceAttr(
"google_compute_region_instance_group_manager.igm-rolling-update-policy", "rolling_update_policy.0.max_surge_fixed", "2"),
resource.TestCheckResourceAttr(
"google_compute_region_instance_group_manager.igm-rolling-update-policy", "rolling_update_policy.0.max_unavailable_fixed", "2"),
resource.TestCheckResourceAttr(
"google_compute_region_instance_group_manager.igm-rolling-update-policy", "rolling_update_policy.0.min_ready_sec", "20"),
),
},
resource.TestStep{
Config: testAccRegionInstanceGroupManager_rollingUpdatePolicy2(igm),
Check: resource.ComposeTestCheckFunc(
testAccCheckRegionInstanceGroupManagerBetaExists(
"google_compute_region_instance_group_manager.igm-rolling-update-policy", &manager),
resource.TestCheckResourceAttr(
"google_compute_region_instance_group_manager.igm-rolling-update-policy", "update_strategy", "ROLLING_UPDATE"),
resource.TestCheckResourceAttr(
"google_compute_region_instance_group_manager.igm-rolling-update-policy", "rolling_update_policy.0.type", "PROACTIVE"),
resource.TestCheckResourceAttr(
"google_compute_region_instance_group_manager.igm-rolling-update-policy", "rolling_update_policy.0.minimal_action", "REPLACE"),
resource.TestCheckResourceAttr(
"google_compute_region_instance_group_manager.igm-rolling-update-policy", "rolling_update_policy.0.max_surge_fixed", "2"),
resource.TestCheckResourceAttr(
"google_compute_region_instance_group_manager.igm-rolling-update-policy", "rolling_update_policy.0.max_unavailable_fixed", "0"),
resource.TestCheckResourceAttr(
"google_compute_region_instance_group_manager.igm-rolling-update-policy", "rolling_update_policy.0.min_ready_sec", "10"),
testAccCheckInstanceGroupManagerRollingUpdatePolicy(
&manager, "google_compute_region_instance_group_manager.igm-rolling-update-policy"),
),
},
},
})
}
func TestAccRegionInstanceGroupManager_separateRegions(t *testing.T) {
t.Parallel()
@ -901,3 +980,141 @@ resource "google_compute_region_instance_group_manager" "igm-basic" {
}
`, template, igm, strings.Join(zones, "\",\""))
}
func testAccRegionInstanceGroupManager_updateStrategy(igm string) string {
return fmt.Sprintf(`
resource "google_compute_instance_template" "igm-update-strategy" {
machine_type = "n1-standard-1"
can_ip_forward = false
tags = ["terraform-testing"]
disk {
source_image = "debian-cloud/debian-8-jessie-v20160803"
auto_delete = true
boot = true
}
network_interface {
network = "default"
}
service_account {
scopes = ["userinfo-email", "compute-ro", "storage-ro"]
}
lifecycle {
create_before_destroy = true
}
}
resource "google_compute_region_instance_group_manager" "igm-update-strategy" {
description = "Terraform test instance group manager"
name = "%s"
instance_template = "${google_compute_instance_template.igm-update-strategy.self_link}"
base_instance_name = "rigm-update-strategy"
region = "us-central1"
target_size = 2
update_strategy = "NONE"
named_port {
name = "customhttp"
port = 8080
}
}`, igm)
}
func testAccRegionInstanceGroupManager_rollingUpdatePolicy(igm string) string {
return fmt.Sprintf(`
resource "google_compute_instance_template" "igm-rolling-update-policy" {
machine_type = "n1-standard-1"
can_ip_forward = false
tags = ["terraform-testing"]
disk {
source_image = "debian-cloud/debian-8-jessie-v20160803"
auto_delete = true
boot = true
}
network_interface {
network = "default"
}
service_account {
scopes = ["userinfo-email", "compute-ro", "storage-ro"]
}
lifecycle {
create_before_destroy = true
}
}
resource "google_compute_region_instance_group_manager" "igm-rolling-update-policy" {
description = "Terraform test instance group manager"
name = "%s"
instance_template = "${google_compute_instance_template.igm-rolling-update-policy.self_link}"
base_instance_name = "igm-rolling-update-policy"
region = "us-central1"
target_size = 4
distribution_policy_zones = ["us-central1-a", "us-central1-f"]
update_strategy = "ROLLING_UPDATE"
rolling_update_policy {
type = "PROACTIVE"
minimal_action = "REPLACE"
max_surge_fixed = 2
max_unavailable_fixed = 2
min_ready_sec = 20
}
named_port {
name = "customhttp"
port = 8080
}
}`, igm)
}
func testAccRegionInstanceGroupManager_rollingUpdatePolicy2(igm string) string {
return fmt.Sprintf(`
resource "google_compute_instance_template" "igm-rolling-update-policy" {
machine_type = "n1-standard-1"
can_ip_forward = false
tags = ["terraform-testing"]
disk {
source_image = "debian-cloud/debian-8-jessie-v20160803"
auto_delete = true
boot = true
}
network_interface {
network = "default"
}
lifecycle {
create_before_destroy = true
}
}
resource "google_compute_region_instance_group_manager" "igm-rolling-update-policy" {
description = "Terraform test instance group manager"
name = "%s"
instance_template = "${google_compute_instance_template.igm-rolling-update-policy.self_link}"
base_instance_name = "igm-rolling-update-policy"
region = "us-central1"
distribution_policy_zones = ["us-central1-a", "us-central1-f"]
target_size = 3
update_strategy = "ROLLING_UPDATE"
rolling_update_policy {
type = "PROACTIVE"
minimal_action = "REPLACE"
max_surge_fixed = 2
max_unavailable_fixed = 0
min_ready_sec = 10
}
named_port {
name = "customhttp"
port = 8080
}
}`, igm)
}

View File

@ -87,6 +87,12 @@ The following arguments are supported:
* `project` - (Optional) The ID of the project in which the resource belongs. If it
is not provided, the provider project is used.
* `update_strategy` - (Optional, Default `"NONE"`) If the `instance_template`
resource is modified, a value of `"NONE"` will prevent any of the managed
instances from being restarted by Terraform. A value of `"ROLLING_UPDATE"`
is supported as [Beta feature]. A value of `"ROLLING_UPDATE"` requires
`rolling_update_policy` block to be set
* `target_size` - (Optional) The target number of running instances for this managed
instance group. This value should always be explicitly set unless this resource is attached to
an autoscaler, in which case it should never be set. Defaults to `0`.
@ -104,17 +110,46 @@ 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).
* `rolling_update_policy` - (Optional, [Beta](/docs/providers/google/index.html#beta-features)) The update policy for this managed instance group. Structure is documented below. For more information, see the [official documentation](https://cloud.google.com/compute/docs/instance-groups/updating-managed-instance-groups) and [API](https://cloud.google.com/compute/docs/reference/rest/beta/regionInstanceGroupManagers/patch)
* `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 **rolling_update_policy** block supports:
The `named_port` block supports: (Include a `named_port` block for each named-port required).
```hcl
rolling_update_policy{
type = "PROACTIVE"
minimal_action = "REPLACE"
max_surge_percent = 20
max_unavailable_fixed = 2
min_ready_sec = 50
}
```
* `minimal_action` - (Required) - Minimal action to be taken on an instance. Valid values are `"RESTART"`, `"REPLACE"`
* `type` - (Required) - The type of update. Valid values are `"OPPORTUNISTIC"`, `"PROACTIVE"`
* `max_surge_fixed` - (Optional), The maximum number of instances that can be created above the specified targetSize during the update process. Conflicts with `max_surge_percent`. It has to be either 0 or at least equal to the number of zones. If fixed values are used, at least one of `max_unavailable_fixed` or `max_surge_fixed` must be greater than 0.
* `max_surge_percent` - (Optional), The maximum number of instances(calculated as percentage) that can be created above the specified targetSize during the update process. Conflicts with `max_surge_fixed`. Percent value is only allowed for regional managed instance groups with size at least 10.
* `max_unavailable_fixed` - (Optional), The maximum number of instances that can be unavailable during the update process. Conflicts with `max_unavailable_percent`. It has to be either 0 or at least equal to the number of zones. If fixed values are used, at least one of `max_unavailable_fixed` or `max_surge_fixed` must be greater than 0.
* `max_unavailable_percent` - (Optional), The maximum number of instances(calculated as percentage) that can be unavailable during the update process. Conflicts with `max_unavailable_fixed`. Percent value is only allowed for regional managed instance groups with size at least 10.
* `min_ready_sec` - (Optional), Minimum number of seconds to wait for after a newly created instance becomes available. This value must be from range [0, 3600]
- - -
The **named_port** block supports: (Include a `named_port` block for each named-port required).
* `name` - (Required) The name of the port.
* `port` - (Required) The port number.
- - -
The `auto_healing_policies` block supports:
The **auto_healing_policies** block supports:
* `health_check` - (Required) The health check resource that signals autohealing.