From cdb263734fa5acab840211d6f5bff54e752a6beb Mon Sep 17 00:00:00 2001 From: Modular Magician Date: Wed, 5 Mar 2025 20:16:26 +0000 Subject: [PATCH] compute: Add `scheduling.termination_time` field to compute_instance resources (#12791) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Norbert KamiƄski [upstream:fc3eeaab049d020371a96176262f2495ee9f7121] Signed-off-by: Modular Magician --- .changelog/12791.txt | 15 +++ .../compute/compute_instance_helpers.go | 26 +++- .../compute/compute_instance_helpers_test.go | 41 ++++++ .../compute/resource_compute_instance.go | 10 ++ ...rce_compute_instance_from_template_test.go | 82 ++++++++++++ .../resource_compute_instance_template.go | 10 ++ ...resource_compute_instance_template_test.go | 80 ++++++++++++ .../compute/resource_compute_instance_test.go | 121 ++++++++++++++++++ ...source_compute_region_instance_template.go | 9 ++ ...e_compute_region_instance_template_test.go | 80 ++++++++++++ website/docs/r/compute_instance.html.markdown | 2 + .../r/compute_instance_template.html.markdown | 2 + ...ute_region_instance_template.html.markdown | 2 + 13 files changed, 479 insertions(+), 1 deletion(-) create mode 100644 .changelog/12791.txt create mode 100644 google/services/compute/compute_instance_helpers_test.go diff --git a/.changelog/12791.txt b/.changelog/12791.txt new file mode 100644 index 00000000000..72d155338c0 --- /dev/null +++ b/.changelog/12791.txt @@ -0,0 +1,15 @@ +```release-note:enhancement +compute: added `scheduling.termination_time` field to `google_compute_instance` resource +``` +```release-note:enhancement +compute: added `scheduling.termination_time` field to `google_compute_instance_from_machine_image` resource +``` +```release-note:enhancement +compute: added `scheduling.termination_time` field to `google_compute_instance_from_template` resource +``` +```release-note:enhancement +compute: added `scheduling.termination_time` field to `google_compute_instance_template` resource +``` +```release-note:enhancement +compute: added `scheduling.termination_time` field to `google_compute_region_instance_template` resource +``` \ No newline at end of file diff --git a/google/services/compute/compute_instance_helpers.go b/google/services/compute/compute_instance_helpers.go index e3c04ea13b3..b5b672a7077 100644 --- a/google/services/compute/compute_instance_helpers.go +++ b/google/services/compute/compute_instance_helpers.go @@ -172,6 +172,9 @@ func expandScheduling(v interface{}) (*compute.Scheduling, error) { scheduling.LocalSsdRecoveryTimeout = transformedLocalSsdRecoveryTimeout scheduling.ForceSendFields = append(scheduling.ForceSendFields, "LocalSsdRecoveryTimeout") } + if v, ok := original["termination_time"]; ok { + scheduling.TerminationTime = v.(string) + } return scheduling, nil } @@ -268,6 +271,7 @@ func flattenScheduling(resp *compute.Scheduling) []map[string]interface{} { "provisioning_model": resp.ProvisioningModel, "instance_termination_action": resp.InstanceTerminationAction, "availability_domain": resp.AvailabilityDomain, + "termination_time": resp.TerminationTime, } if resp.AutomaticRestart != nil { @@ -663,7 +667,9 @@ func schedulingHasChangeRequiringReboot(d *schema.ResourceData) bool { oScheduling := o.([]interface{})[0].(map[string]interface{}) newScheduling := n.([]interface{})[0].(map[string]interface{}) - return hasNodeAffinitiesChanged(oScheduling, newScheduling) || hasMaxRunDurationChanged(oScheduling, newScheduling) + return (hasNodeAffinitiesChanged(oScheduling, newScheduling) || + hasMaxRunDurationChanged(oScheduling, newScheduling) || + hasTerminationTimeChanged(oScheduling, newScheduling)) } // Terraform doesn't correctly calculate changes on schema.Set, so we do it manually @@ -708,6 +714,24 @@ func schedulingHasChangeWithoutReboot(d *schema.ResourceData) bool { return false } +func hasTerminationTimeChanged(oScheduling, nScheduling map[string]interface{}) bool { + oTerminationTime := oScheduling["termination_time"].(string) + nTerminationTime := nScheduling["termination_time"].(string) + + if len(oTerminationTime) == 0 && len(nTerminationTime) == 0 { + return false + } + if len(oTerminationTime) == 0 || len(nTerminationTime) == 0 { + return true + } + + if oTerminationTime != nTerminationTime { + return true + } + + return false +} + func hasMaxRunDurationChanged(oScheduling, nScheduling map[string]interface{}) bool { oMrd := oScheduling["max_run_duration"].([]interface{}) nMrd := nScheduling["max_run_duration"].([]interface{}) diff --git a/google/services/compute/compute_instance_helpers_test.go b/google/services/compute/compute_instance_helpers_test.go new file mode 100644 index 00000000000..de08a8de721 --- /dev/null +++ b/google/services/compute/compute_instance_helpers_test.go @@ -0,0 +1,41 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 +package compute + +import ( + "testing" +) + +func TestHasTerminationTimeChanged(t *testing.T) { + t.Parallel() + cases := map[string]struct { + Old, New map[string]interface{} + Expect bool + }{ + "empty": { + Old: map[string]interface{}{"termination_time": ""}, + New: map[string]interface{}{"termination_time": ""}, + Expect: false, + }, + "new": { + Old: map[string]interface{}{"termination_time": ""}, + New: map[string]interface{}{"termination_time": "2025-01-31T15:04:05Z"}, + Expect: true, + }, + "changed": { + Old: map[string]interface{}{"termination_time": "2025-01-30T15:04:05Z"}, + New: map[string]interface{}{"termination_time": "2025-01-31T15:04:05Z"}, + Expect: true, + }, + "same": { + Old: map[string]interface{}{"termination_time": "2025-01-30T15:04:05Z"}, + New: map[string]interface{}{"termination_time": "2025-01-30T15:04:05Z"}, + Expect: false, + }, + } + for tn, tc := range cases { + if hasTerminationTimeChanged(tc.Old, tc.New) != tc.Expect { + t.Errorf("%s: expected %t for whether termination time matched for old = %q, new = %q", tn, tc.Expect, tc.Old, tc.New) + } + } +} diff --git a/google/services/compute/resource_compute_instance.go b/google/services/compute/resource_compute_instance.go index 1888e82a18c..d401452618a 100644 --- a/google/services/compute/resource_compute_instance.go +++ b/google/services/compute/resource_compute_instance.go @@ -92,6 +92,7 @@ var ( "scheduling.0.min_node_cpus", "scheduling.0.provisioning_model", "scheduling.0.instance_termination_action", + "scheduling.0.termination_time", "scheduling.0.availability_domain", "scheduling.0.max_run_duration", "scheduling.0.on_instance_stop_action", @@ -856,6 +857,15 @@ func ResourceComputeInstance() *schema.Resource { AtLeastOneOf: schedulingKeys, Description: `Specifies the action GCE should take when SPOT VM is preempted.`, }, + "termination_time": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + AtLeastOneOf: schedulingKeys, + Description: `Specifies the timestamp, when the instance will be terminated, +in RFC3339 text format. If specified, the instance termination action +will be performed at the termination time.`, + }, "availability_domain": { Type: schema.TypeInt, Optional: true, diff --git a/google/services/compute/resource_compute_instance_from_template_test.go b/google/services/compute/resource_compute_instance_from_template_test.go index a53688d8454..982f46217e3 100644 --- a/google/services/compute/resource_compute_instance_from_template_test.go +++ b/google/services/compute/resource_compute_instance_from_template_test.go @@ -6,6 +6,7 @@ import ( "fmt" "regexp" "testing" + "time" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" @@ -275,6 +276,32 @@ func TestAccComputeInstanceFromTemplate_overrideScheduling(t *testing.T) { }) } +func TestAccComputeInstanceFromTemplate_TerminationTime(t *testing.T) { + t.Parallel() + + var instance compute.Instance + instanceName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + templateName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + templateDisk := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + resourceName := "google_compute_instance_from_template.inst" + now := time.Now().UTC() + terminationTime := time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 9999, now.Location()).Format(time.RFC3339) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckComputeInstanceFromTemplateDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeInstanceFromTemplate_terminationTime(templateDisk, templateName, terminationTime, instanceName), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeInstanceExists(t, resourceName, &instance), + ), + }, + }, + }) +} + func TestAccComputeInstanceFromTemplate_overrideMetadataDotStartupScript(t *testing.T) { var instance compute.Instance instanceName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) @@ -978,6 +1005,61 @@ resource "google_compute_instance_from_template" "inst" { `, templateDisk, template, instance) } +func testAccComputeInstanceFromTemplate_terminationTime(templateDisk, template, termination_time, instance string) string { + return fmt.Sprintf(` +data "google_compute_image" "my_image" { + family = "debian-11" + project = "debian-cloud" +} + +resource "google_compute_disk" "foobar" { + name = "%s" + image = data.google_compute_image.my_image.self_link + size = 10 + type = "pd-ssd" + zone = "us-central1-a" +} + +resource "google_compute_instance_template" "foobar" { + name = "%s" + machine_type = "e2-medium" + + disk { + source = google_compute_disk.foobar.name + auto_delete = false + boot = true + } + + network_interface { + network = "default" + } + + metadata = { + foo = "bar" + } + + scheduling { + instance_termination_action = "STOP" + termination_time = "%s" + } + + can_ip_forward = true +} + +resource "google_compute_instance_from_template" "inst" { + name = "%s" + zone = "us-central1-a" + + source_instance_template = google_compute_instance_template.foobar.self_link + + scheduling { + instance_termination_action = "STOP" + termination_time = "%s" + } +} +`, templateDisk, template, termination_time, instance, termination_time) +} + func testAccComputeInstanceFromTemplate_overrideMetadataDotStartupScript(instance, template string) string { return fmt.Sprintf(` data "google_compute_image" "my_image" { diff --git a/google/services/compute/resource_compute_instance_template.go b/google/services/compute/resource_compute_instance_template.go index 28daeae457b..1111e724b3b 100644 --- a/google/services/compute/resource_compute_instance_template.go +++ b/google/services/compute/resource_compute_instance_template.go @@ -34,6 +34,7 @@ var ( "scheduling.0.availability_domain", "scheduling.0.max_run_duration", "scheduling.0.on_instance_stop_action", + "scheduling.0.termination_time", "scheduling.0.local_ssd_recovery_timeout", } @@ -739,6 +740,15 @@ be from 0 to 999,999,999 inclusive.`, }, }, }, + "termination_time": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + AtLeastOneOf: schedulingKeys, + Description: `Specifies the timestamp, when the instance will be terminated, +in RFC3339 text format. If specified, the instance termination action +will be performed at the termination time.`, + }, "local_ssd_recovery_timeout": { Type: schema.TypeList, Optional: true, diff --git a/google/services/compute/resource_compute_instance_template_test.go b/google/services/compute/resource_compute_instance_template_test.go index 274292618d7..ce494d2eadc 100644 --- a/google/services/compute/resource_compute_instance_template_test.go +++ b/google/services/compute/resource_compute_instance_template_test.go @@ -1319,6 +1319,37 @@ func TestAccComputeInstanceTemplate_maxRunDuration_onInstanceStopAction(t *testi }) } +func TestAccComputeInstanceTemplate_instanceTerminationAction_terminationTime(t *testing.T) { + t.Parallel() + + var instanceTemplate compute.InstanceTemplate + now := time.Now().UTC() + terminationTime := time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 9999, now.Location()).Format(time.RFC3339) + var instanceTerminationAction = "STOP" + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckComputeInstanceTemplateDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeInstanceTemplate_onInstanceStopAction_terminationTime(acctest.RandString(t, 10), terminationTime), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeInstanceTemplateExists( + t, "google_compute_instance_template.foobar", &instanceTemplate), + testAccCheckComputeInstanceTemplateInstanceTerminationAction(&instanceTemplate, instanceTerminationAction), + testAccCheckComputeInstanceTemplateInstanceTerminationTime(&instanceTemplate, terminationTime), + ), + }, + { + ResourceName: "google_compute_instance_template.foobar", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccComputeInstanceTemplate_spot_maxRunDuration(t *testing.T) { t.Parallel() @@ -1857,6 +1888,15 @@ func testAccCheckComputeInstanceTemplateInstanceTerminationAction(instanceTempla } } +func testAccCheckComputeInstanceTemplateInstanceTerminationTime(instanceTemplate *compute.InstanceTemplate, termination_time string) resource.TestCheckFunc { + return func(s *terraform.State) error { + if instanceTemplate.Properties.Scheduling.TerminationTime != termination_time { + return fmt.Errorf("Expected instance_termination_time %v, got %v", termination_time, instanceTemplate.Properties.Scheduling.TerminationTime) + } + return nil + } +} + func testAccCheckComputeInstanceTemplateMaxRunDuration(instanceTemplate *compute.InstanceTemplate, instance_max_run_duration_want compute.Duration) resource.TestCheckFunc { return func(s *terraform.State) error { if !reflect.DeepEqual(*instanceTemplate.Properties.Scheduling.MaxRunDuration, instance_max_run_duration_want) { @@ -4071,6 +4111,46 @@ resource "google_compute_instance_template" "foobar" { `, suffix) } +func testAccComputeInstanceTemplate_onInstanceStopAction_terminationTime(suffix string, terminationTime string) string { + return fmt.Sprintf(` +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-medium" + can_ip_forward = false + tags = ["foo", "bar"] + + disk { + source_image = data.google_compute_image.my_image.self_link + auto_delete = true + boot = true + } + + network_interface { + network = "default" + } + + scheduling { + automatic_restart = false + instance_termination_action = "STOP" + termination_time = "%s" + } + + metadata = { + foo = "bar" + } + + service_account { + scopes = ["userinfo-email", "compute-ro", "storage-ro"] + } +} +`, suffix, terminationTime) +} + func testAccComputeInstanceTemplate_localSsdRecoveryTimeout(suffix string) string { return fmt.Sprintf(` data "google_compute_image" "my_image" { diff --git a/google/services/compute/resource_compute_instance_test.go b/google/services/compute/resource_compute_instance_test.go index 235f49ef217..065a8b072d4 100644 --- a/google/services/compute/resource_compute_instance_test.go +++ b/google/services/compute/resource_compute_instance_test.go @@ -13,6 +13,7 @@ import ( "time" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-google/google/acctest" @@ -1456,6 +1457,59 @@ func TestAccComputeInstance_scheduling(t *testing.T) { }) } +func TestAccComputeInstance_schedulingTerminationTime(t *testing.T) { + t.Parallel() + + var instance compute.Instance + var instanceName = fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10)) + now := time.Now().UTC() + terminationTimeNonFormatted := time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 9999, now.Location()) + terminationTime := terminationTimeNonFormatted.Format(time.RFC3339) + terminationTimeUpdated := terminationTimeNonFormatted.Add(25 * time.Hour).Format(time.RFC3339) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckComputeInstanceDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeInstance_TerminationTime(instanceName, terminationTime), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeInstanceExists( + t, "google_compute_instance.foobar", &instance), + ), + }, + computeInstanceImportStep("us-central1-a", instanceName, []string{"allow_stopping_for_update"}), + { + Config: testAccComputeInstance_TerminationTime(instanceName, terminationTimeUpdated), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction("google_compute_instance.foobar", plancheck.ResourceActionReplace), + }, + }, + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeInstanceExists( + t, "google_compute_instance.foobar", &instance), + ), + }, + computeInstanceImportStep("us-central1-a", instanceName, []string{"allow_stopping_for_update"}), + { + Config: testAccComputeInstance_TerminationTimeDeleted(instanceName), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction("google_compute_instance.foobar", plancheck.ResourceActionReplace), + }, + }, + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeInstanceExists( + t, "google_compute_instance.foobar", &instance), + ), + }, + computeInstanceImportStep("us-central1-a", instanceName, []string{"allow_stopping_for_update"}), + }, + }) +} + func TestAccComputeInstance_advancedMachineFeatures(t *testing.T) { t.Parallel() @@ -6835,6 +6889,73 @@ resource "google_compute_instance" "foobar" { `, instance) } +func testAccComputeInstance_TerminationTime(instance string, terminationTime 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-medium" + zone = "us-central1-a" + + boot_disk { + initialize_params { + image = data.google_compute_image.my_image.self_link + } + } + + network_interface { + network = "default" + } + + scheduling { + automatic_restart = false + preemptible = true + provisioning_model = "SPOT" + instance_termination_action = "STOP" + termination_time = "%s" + } + allow_stopping_for_update = true +} +`, instance, terminationTime) +} + +func testAccComputeInstance_TerminationTimeDeleted(instance 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-medium" + zone = "us-central1-a" + + boot_disk { + initialize_params { + image = data.google_compute_image.my_image.self_link + } + } + + network_interface { + network = "default" + } + + scheduling { + automatic_restart = false + preemptible = true + provisioning_model = "SPOT" + instance_termination_action = "STOP" + } + allow_stopping_for_update = true +} +`, instance) +} + func testAccComputeInstance_advancedMachineFeatures(instance string) string { return fmt.Sprintf(` data "google_compute_image" "my_image" { diff --git a/google/services/compute/resource_compute_region_instance_template.go b/google/services/compute/resource_compute_region_instance_template.go index d9e98e4c40a..fb3f91403a3 100644 --- a/google/services/compute/resource_compute_region_instance_template.go +++ b/google/services/compute/resource_compute_region_instance_template.go @@ -660,6 +660,15 @@ Google Cloud KMS.`, AtLeastOneOf: schedulingInstTemplateKeys, Description: `Specifies the action GCE should take when SPOT VM is preempted.`, }, + "termination_time": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + AtLeastOneOf: schedulingKeys, + Description: `Specifies the timestamp, when the instance will be terminated, +in RFC3339 text format. If specified, the instance termination action +will be performed at the termination time.`, + }, "availability_domain": { Type: schema.TypeInt, Optional: true, diff --git a/google/services/compute/resource_compute_region_instance_template_test.go b/google/services/compute/resource_compute_region_instance_template_test.go index 301b87946b4..97b81917533 100644 --- a/google/services/compute/resource_compute_region_instance_template_test.go +++ b/google/services/compute/resource_compute_region_instance_template_test.go @@ -1191,6 +1191,37 @@ func TestAccComputeRegionInstanceTemplate_maxRunDuration_onInstanceStopAction(t }) } +func TestAccComputeRegionInstanceTemplate_instanceTerminationAction_terminationTime(t *testing.T) { + t.Parallel() + + var instanceTemplate compute.InstanceTemplate + now := time.Now().UTC() + terminationTime := time.Date(now.Year(), now.Month(), now.Day(), 23, 59, 59, 9999, now.Location()).Format(time.RFC3339) + var instanceTerminationAction = "STOP" + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckComputeRegionInstanceTemplateDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccComputeRegionInstanceTemplate_onInstanceStopAction_terminationTime(acctest.RandString(t, 10), terminationTime), + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeRegionInstanceTemplateExists( + t, "google_compute_region_instance_template.foobar", &instanceTemplate), + testAccCheckComputeRegionInstanceTemplateInstanceTerminationAction(&instanceTemplate, instanceTerminationAction), + testAccCheckComputeRegionInstanceTemplateInstanceTerminationTime(&instanceTemplate, terminationTime), + ), + }, + { + ResourceName: "google_compute_region_instance_template.foobar", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func TestAccComputeRegionInstanceTemplate_localSsdRecoveryTimeout(t *testing.T) { t.Parallel() @@ -1577,6 +1608,15 @@ func testAccCheckComputeRegionInstanceTemplateInstanceTerminationAction(instance } } +func testAccCheckComputeRegionInstanceTemplateInstanceTerminationTime(instanceTemplate *compute.InstanceTemplate, termination_time string) resource.TestCheckFunc { + return func(s *terraform.State) error { + if instanceTemplate.Properties.Scheduling.TerminationTime != termination_time { + return fmt.Errorf("Expected instance_termination_time %v, got %v", termination_time, instanceTemplate.Properties.Scheduling.TerminationTime) + } + return nil + } +} + func testAccCheckComputeRegionInstanceTemplateMaxRunDuration(instanceTemplate *compute.InstanceTemplate, instance_max_run_duration_want compute.Duration) resource.TestCheckFunc { return func(s *terraform.State) error { if !reflect.DeepEqual(*instanceTemplate.Properties.Scheduling.MaxRunDuration, instance_max_run_duration_want) { @@ -3608,6 +3648,46 @@ resource "google_compute_region_instance_template" "foobar" { `, suffix) } +func testAccComputeRegionInstanceTemplate_onInstanceStopAction_terminationTime(suffix string, terminationTime string) string { + return fmt.Sprintf(` +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-medium" + can_ip_forward = false + tags = ["foo", "bar"] + + disk { + source_image = data.google_compute_image.my_image.self_link + auto_delete = true + boot = true + } + + network_interface { + network = "default" + } + + scheduling { + automatic_restart = false + instance_termination_action = "STOP" + termination_time = "%s" + } + + metadata = { + foo = "bar" + } + + service_account { + scopes = ["userinfo-email", "compute-ro", "storage-ro"] + } +} +`, suffix, terminationTime) +} + func testAccComputeRegionInstanceTemplate_localSsdRecoveryTimeout(suffix string) string { return fmt.Sprintf(` data "google_compute_image" "my_image" { diff --git a/website/docs/r/compute_instance.html.markdown b/website/docs/r/compute_instance.html.markdown index 1a5e56b0f87..0b42206858a 100644 --- a/website/docs/r/compute_instance.html.markdown +++ b/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) +* `termination_time` - (Optional) Specifies the timestamp, when the instance will be terminated, in RFC3339 text format. If specified, the instance termination action will be performed at the termination time. + * `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/website/docs/r/compute_instance_template.html.markdown b/website/docs/r/compute_instance_template.html.markdown index 5740d8b01b4..ec227ad1560 100644 --- a/website/docs/r/compute_instance_template.html.markdown +++ b/website/docs/r/compute_instance_template.html.markdown @@ -642,6 +642,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) +* `termination_time` - (Optional) Specifies the timestamp, when the instance will be terminated, in RFC3339 text format. If specified, the instance termination action will be performed at the termination time. + * `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/website/docs/r/compute_region_instance_template.html.markdown b/website/docs/r/compute_region_instance_template.html.markdown index d73982e63ae..4b0c446ca28 100644 --- a/website/docs/r/compute_region_instance_template.html.markdown +++ b/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) +* `termination_time` - (Optional) Specifies the timestamp, when the instance will be terminated, in RFC3339 text format. If specified, the instance termination action will be performed at the termination time. + * `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.