diff --git a/mmv1/third_party/cai2hcl/services/compute/compute_instance.go b/mmv1/third_party/cai2hcl/services/compute/compute_instance.go index 0b7b07065e05..69a87445d25c 100644 --- a/mmv1/third_party/cai2hcl/services/compute/compute_instance.go +++ b/mmv1/third_party/cai2hcl/services/compute/compute_instance.go @@ -211,7 +211,8 @@ func convertScheduling(sched *compute.Scheduling) []map[string]interface{} { "preemptible": sched.Preemptible, "on_host_maintenance": sched.OnHostMaintenance, // node_affinities are not converted into cai - "node_affinities": convertSchedulingNodeAffinity(sched.NodeAffinities), + "node_affinities": convertSchedulingNodeAffinity(sched.NodeAffinities), + "availability_domain": sched.AvailabilityDomain, } if sched.MinNodeCpus > 0 { data["min_node_cpus"] = sched.MinNodeCpus diff --git a/mmv1/third_party/terraform/services/compute/compute_instance_helpers.go.tmpl b/mmv1/third_party/terraform/services/compute/compute_instance_helpers.go.tmpl index 5a5267ab8eab..d5c2c4382977 100644 --- a/mmv1/third_party/terraform/services/compute/compute_instance_helpers.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/compute_instance_helpers.go.tmpl @@ -146,6 +146,9 @@ func expandScheduling(v interface{}) (*compute.Scheduling, error) { scheduling.InstanceTerminationAction = v.(string) scheduling.ForceSendFields = append(scheduling.ForceSendFields, "InstanceTerminationAction") } + if v, ok := original["availability_domain"]; ok && v != nil { + scheduling.AvailabilityDomain = int64(v.(int)) + } if v, ok := original["max_run_duration"]; ok { transformedMaxRunDuration, err := expandComputeMaxRunDuration(v) if err != nil { @@ -282,6 +285,7 @@ func flattenScheduling(resp *compute.Scheduling) []map[string]interface{} { "min_node_cpus": resp.MinNodeCpus, "provisioning_model": resp.ProvisioningModel, "instance_termination_action": resp.InstanceTerminationAction, + "availability_domain": resp.AvailabilityDomain, } if resp.AutomaticRestart != nil { @@ -757,6 +761,9 @@ func schedulingHasChangeWithoutReboot(d *schema.ResourceData) bool { if oScheduling["instance_termination_action"] != newScheduling["instance_termination_action"] { return true } + if oScheduling["availability_domain"] != newScheduling["availability_domain"] { + return true + } {{- if ne $.TargetVersionName "ga" }} if oScheduling["host_error_timeout_seconds"] != newScheduling["host_error_timeout_seconds"] { return true diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_instance.go.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_instance.go.tmpl index 57fa41af26f5..128949bd0105 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_instance.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/resource_compute_instance.go.tmpl @@ -94,6 +94,7 @@ var ( "scheduling.0.min_node_cpus", "scheduling.0.provisioning_model", "scheduling.0.instance_termination_action", + "scheduling.0.availability_domain", "scheduling.0.max_run_duration", "scheduling.0.on_instance_stop_action", {{- if ne $.TargetVersionName "ga" }} @@ -901,6 +902,12 @@ func ResourceComputeInstance() *schema.Resource { AtLeastOneOf: schedulingKeys, Description: `Specifies the action GCE should take when SPOT VM is preempted.`, }, + "availability_domain": { + Type: schema.TypeInt, + Optional: true, + AtLeastOneOf: schedulingKeys, + Description: `Specifies the availability domain, which this instance should be scheduled on.`, + }, "max_run_duration" : { Type: schema.TypeList, Optional: true, diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_instance_template.go.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_instance_template.go.tmpl index d9dcd5ad55e9..b3dad4e706ce 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_instance_template.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/resource_compute_instance_template.go.tmpl @@ -34,6 +34,7 @@ var ( "scheduling.0.min_node_cpus", "scheduling.0.provisioning_model", "scheduling.0.instance_termination_action", + "scheduling.0.availability_domain", "scheduling.0.max_run_duration", "scheduling.0.on_instance_stop_action", {{- if ne $.TargetVersionName "ga" }} @@ -728,6 +729,13 @@ Google Cloud KMS.`, AtLeastOneOf: schedulingInstTemplateKeys, Description: `Specifies the action GCE should take when SPOT VM is preempted.`, }, + "availability_domain": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + AtLeastOneOf: schedulingInstTemplateKeys, + Description: `Specifies the availability domain, which this instance should be scheduled on.`, + }, "max_run_duration" : { Type: schema.TypeList, Optional: true, diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_instance_template_test.go.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_instance_template_test.go.tmpl index 85549bc4c1a4..f1ff6bceeba2 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_instance_template_test.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/resource_compute_instance_template_test.go.tmpl @@ -738,6 +738,34 @@ func TestAccComputeInstanceTemplate_instanceResourcePolicies(t *testing.T) { }) } +func TestAccComputeInstanceTemplate_instanceResourcePoliciesSpread(t *testing.T) { + t.Parallel() + + var template compute.InstanceTemplate + var policyName = "tf-test-policy-" + acctest.RandString(t, 10) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckComputeInstanceTemplateDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeInstanceTemplate_instanceResourcePolicySpread(acctest.RandString(t, 10), policyName), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeInstanceTemplateExists(t, "google_compute_instance_template.foobar", &template), + testAccCheckComputeInstanceTemplateHasInstanceResourcePolicies(&template, policyName), + testAccCheckComputeInstanceTemplateHasAvailabilityDomain(&template, 3), + ), + }, + { + ResourceName: "google_compute_instance_template.foobar", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccComputeInstanceTemplate_reservationAffinities(t *testing.T) { t.Parallel() @@ -2235,6 +2263,15 @@ func testAccCheckComputeInstanceTemplateHasInstanceResourcePolicies(instanceTemp } +func testAccCheckComputeInstanceTemplateHasAvailabilityDomain(instanceTemplate *compute.InstanceTemplate, availabilityDomain int64) resource.TestCheckFunc { + return func (s *terraform.State) error { + if instanceTemplate.Properties.Scheduling.AvailabilityDomain != availabilityDomain { + return fmt.Errorf("Expected availability_domain %d, got %d", availabilityDomain, instanceTemplate.Properties.Scheduling.AvailabilityDomain) + } + return nil + } +} + func testAccCheckComputeInstanceTemplateHasReservationAffinity(instanceTemplate *compute.InstanceTemplate, consumeReservationType string, specificReservationNames ...string) resource.TestCheckFunc { if len(specificReservationNames) > 1 { panic("too many specificReservationNames in test") @@ -3605,6 +3642,49 @@ resource "google_compute_instance_template" "foobar" { `, policyName, suffix) } +func testAccComputeInstanceTemplate_instanceResourcePolicySpread(suffix string, policyName string) string { + return fmt.Sprintf(` +resource "google_compute_resource_policy" "foo" { + name = "%s" + region = "us-central1" + group_placement_policy { + availability_domain_count = 5 + } +} + +data "google_compute_image" "my_image" { + family = "debian-11" + project = "debian-cloud" +} + +resource "google_compute_instance_template" "foobar" { + name = "tf-test-instance-template-%s" + machine_type = "e2-standard-4" + + disk { + source_image = data.google_compute_image.my_image.self_link + auto_delete = true + boot = true + } + + network_interface { + network = "default" + } + + scheduling { + availability_domain = 3 + } + + resource_policies = [google_compute_resource_policy.foo.self_link] + + service_account { + scopes = ["userinfo-email", "compute-ro", "storage-ro"] + } +} +`, policyName, suffix) +} + + func testAccComputeInstanceTemplate_reservationAffinityInstanceTemplate_nonSpecificReservation(templateName, consumeReservationType string) string { return fmt.Sprintf(` data "google_compute_image" "my_image" { diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_instance_test.go.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_instance_test.go.tmpl index 4b6ba068521b..831721a741e2 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_instance_test.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/resource_compute_instance_test.go.tmpl @@ -2999,6 +2999,31 @@ func TestAccComputeInstance_resourcePolicyCollocate(t *testing.T) { }) } +func TestAccComputeInstance_resourcePolicySpread(t *testing.T) { + t.Parallel() + + instanceName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + var instance compute.Instance + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckComputeInstanceDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeInstance_resourcePolicySpread(instanceName, acctest.RandString(t, 10)), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeInstanceExists( + t, "google_compute_instance.foobar", &instance), + testAccCheckComputeInstanceHasStatus(&instance, "RUNNING"), + testAccCheckComputeInstanceHasAvailabilityDomain(&instance, 3), + ), + }, + computeInstanceImportStep("us-east4-b", instanceName, []string{"allow_stopping_for_update"}), + }, + }) +} + func TestAccComputeInstance_subnetworkUpdate(t *testing.T) { t.Parallel() instanceName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) @@ -4436,6 +4461,23 @@ func testAccCheckComputeInstanceMaxRunDuration(instance *compute.Instance, insta } } +func testAccCheckComputeInstanceHasAvailabilityDomain(instance *compute.Instance, availabilityDomain int64) resource.TestCheckFunc { + return func(s *terraform.State) error { + if instance == nil { + return fmt.Errorf("instance is nil") + } + if instance.Scheduling == nil { + return fmt.Errorf("no scheduling") + } + + if instance.Scheduling.AvailabilityDomain != availabilityDomain { + return fmt.Errorf("got the wrong availability domain: have %d; want %d", instance.Scheduling.AvailabilityDomain, availabilityDomain) + } + + return nil + } +} + func testAccCheckComputeInstanceLocalSsdRecoveryTimeout(instance *compute.Instance, instanceLocalSsdRecoveryTiemoutWant compute.Duration) resource.TestCheckFunc { return func(s *terraform.State) error { if instance == nil { @@ -9349,6 +9391,50 @@ resource "google_compute_resource_policy" "foo" { `, instance, instance, suffix) } +func testAccComputeInstance_resourcePolicySpread(instance, suffix string) string { + return fmt.Sprintf(` +data "google_compute_image" "my_image" { + family = "debian-11" + project = "debian-cloud" +} + +resource "google_compute_instance" "foobar" { + name = "%s" + machine_type = "e2-standard-4" + zone = "us-east4-b" + can_ip_forward = false + tags = ["foo", "bar"] + + //deletion_protection = false is implicit in this config due to default value + + boot_disk { + initialize_params { + image = data.google_compute_image.my_image.self_link + } + } + + network_interface { + network = "default" + } + + scheduling { + availability_domain = 3 + } + + resource_policies = [google_compute_resource_policy.foo.self_link] +} + +resource "google_compute_resource_policy" "foo" { + name = "tf-test-policy-%s" + region = "us-east4" + group_placement_policy { + availability_domain_count = 3 + } +} + +`, instance, suffix) +} + func testAccComputeInstance_subnetworkUpdate(suffix, instance string) string { return fmt.Sprintf(` data "google_compute_image" "my_image" { diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_template.go.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_template.go.tmpl index 41f7638e5dc0..dad4e04a7dc9 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_template.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_template.go.tmpl @@ -687,6 +687,13 @@ Google Cloud KMS.`, AtLeastOneOf: schedulingInstTemplateKeys, Description: `Specifies the action GCE should take when SPOT VM is preempted.`, }, + "availability_domain": { + Type: schema.TypeInt, + Optional: true, + ForceNew: true, + AtLeastOneOf: schedulingInstTemplateKeys, + Description: `Specifies the availability domain, which this instance should be scheduled on.`, + }, "max_run_duration" : { Type: schema.TypeList, Optional: true, diff --git a/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_template_test.go.tmpl b/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_template_test.go.tmpl index 566dc4b5d263..dadedbb8f3bd 100644 --- a/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_template_test.go.tmpl +++ b/mmv1/third_party/terraform/services/compute/resource_compute_region_instance_template_test.go.tmpl @@ -610,6 +610,34 @@ func TestAccComputeRegionInstanceTemplate_instanceResourcePolicies(t *testing.T) }) } +func TestAccComputeRegionInstanceTemplate_instanceResourcePoliciesSpread(t *testing.T) { + t.Parallel() + + var template compute.InstanceTemplate + var policyName = "tf-test-policy-" + acctest.RandString(t, 10) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckComputeRegionInstanceTemplateDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeRegionInstanceTemplate_instanceResourcePolicySpread(acctest.RandString(t, 10), policyName), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeRegionInstanceTemplateExists(t, "google_compute_region_instance_template.foobar", &template), + testAccCheckComputeRegionInstanceTemplateHasInstanceResourcePolicies(&template, policyName), + testAccCheckComputeRegionInstanceTemplateHasAvailabilityDomain(&template, 3), + ), + }, + { + ResourceName: "google_compute_region_instance_template.foobar", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccComputeRegionInstanceTemplate_reservationAffinities(t *testing.T) { t.Parallel() @@ -1858,6 +1886,15 @@ func testAccCheckComputeRegionInstanceTemplateHasInstanceResourcePolicies(instan } +func testAccCheckComputeRegionInstanceTemplateHasAvailabilityDomain(instanceTemplate *compute.InstanceTemplate, availabilityDomain int64) resource.TestCheckFunc { + return func (s *terraform.State) error { + if instanceTemplate.Properties.Scheduling.AvailabilityDomain != availabilityDomain { + return fmt.Errorf("Expected availability_domain %d, got %d", availabilityDomain, instanceTemplate.Properties.Scheduling.AvailabilityDomain) + } + return nil + } +} + func testAccCheckComputeRegionInstanceTemplateHasReservationAffinity(instanceTemplate *compute.InstanceTemplate, consumeReservationType string, specificReservationNames ...string) resource.TestCheckFunc { if len(specificReservationNames) > 1 { panic("too many specificReservationNames in test") @@ -2983,6 +3020,49 @@ resource "google_compute_region_instance_template" "foobar" { `, policyName, suffix) } +func testAccComputeRegionInstanceTemplate_instanceResourcePolicySpread(suffix string, policyName string) string { + return fmt.Sprintf(` +resource "google_compute_resource_policy" "foo" { + name = "%s" + region = "us-central1" + group_placement_policy { + availability_domain_count = 5 + } +} + +data "google_compute_image" "my_image" { + family = "debian-11" + project = "debian-cloud" +} + +resource "google_compute_region_instance_template" "foobar" { + name = "tf-test-instance-template-%s" + machine_type = "e2-standard-4" + region = "us-central1" + + disk { + source_image = data.google_compute_image.my_image.self_link + auto_delete = true + boot = true + } + + network_interface { + network = "default" + } + + scheduling { + availability_domain = 3 + } + + resource_policies = [google_compute_resource_policy.foo.self_link] + + service_account { + scopes = ["userinfo-email", "compute-ro", "storage-ro"] + } +} +`, policyName, suffix) +} + func testAccComputeRegionInstanceTemplate_reservationAffinityInstanceTemplate_nonSpecificReservation(templateName, consumeReservationType string) string { return fmt.Sprintf(` data "google_compute_image" "my_image" { diff --git a/mmv1/third_party/terraform/website/docs/r/compute_instance.html.markdown b/mmv1/third_party/terraform/website/docs/r/compute_instance.html.markdown index acd46bad2410..4b63097d8ed6 100644 --- a/mmv1/third_party/terraform/website/docs/r/compute_instance.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/compute_instance.html.markdown @@ -493,6 +493,8 @@ specified, then this instance will have no external IPv6 Internet access. Struct * `instance_termination_action` - (Optional) Describe the type of termination action for VM. Can be `STOP` or `DELETE`. Read more on [here](https://cloud.google.com/compute/docs/instances/create-use-spot) +* `availability_domain` - (Optional) Specifies the availability domain to place the instance in. The value must be a number between 1 and the number of availability domains specified in the spread placement policy attached to the instance. + * `max_run_duration` - (Optional) The duration of the instance. Instance will run and be terminated after then, the termination action could be defined in `instance_termination_action`. Structure is [documented below](#nested_max_run_duration). diff --git a/mmv1/third_party/terraform/website/docs/r/compute_instance_template.html.markdown b/mmv1/third_party/terraform/website/docs/r/compute_instance_template.html.markdown index 88a604fa44a7..b73f4c095383 100644 --- a/mmv1/third_party/terraform/website/docs/r/compute_instance_template.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/compute_instance_template.html.markdown @@ -639,6 +639,8 @@ specified, then this instance will have no external IPv6 Internet access. Struct * `instance_termination_action` - (Optional) Describe the type of termination action for `SPOT` VM. Can be `STOP` or `DELETE`. Read more on [here](https://cloud.google.com/compute/docs/instances/create-use-spot) +* `availability_domain` - (Optional) Specifies the availability domain to place the instance in. The value must be a number between 1 and the number of availability domains specified in the spread placement policy attached to the instance. + * `max_run_duration` - (Optional) The duration of the instance. Instance will run and be terminated after then, the termination action could be defined in `instance_termination_action`. Structure is [documented below](#nested_max_run_duration). * `on_instance_stop_action` - (Optional) Specifies the action to be performed when the instance is terminated using `max_run_duration` and `STOP` `instance_termination_action`. Only support `true` `discard_local_ssd` at this point. Structure is [documented below](#nested_on_instance_stop_action). diff --git a/mmv1/third_party/terraform/website/docs/r/compute_region_instance_template.html.markdown b/mmv1/third_party/terraform/website/docs/r/compute_region_instance_template.html.markdown index 9377858dd044..5626debd1c81 100644 --- a/mmv1/third_party/terraform/website/docs/r/compute_region_instance_template.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/compute_region_instance_template.html.markdown @@ -605,6 +605,8 @@ specified, then this instance will have no external IPv6 Internet access. Struct * `instance_termination_action` - (Optional) Describe the type of termination action for `SPOT` VM. Can be `STOP` or `DELETE`. Read more on [here](https://cloud.google.com/compute/docs/instances/create-use-spot) +* `availability_domain` - (Optional) Specifies the availability domain to place the instance in. The value must be a number between 1 and the number of availability domains specified in the spread placement policy attached to the instance. + * `host_error_timeout_seconds` - (Optional) [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html) Specifies the time in seconds for host error detection, the value must be within the range of [90, 330] with the increment of 30, if unset, the default behavior of host error recovery will be used. * `max_run_duration` - (Optional) The duration of the instance. Instance will run and be terminated after then, the termination action could be defined in `instance_termination_action`. Only support `DELETE` `instance_termination_action` at this point. Structure is [documented below](#nested_max_run_duration).