From bd71dbea9c6667abc55a508e30f137d0f25e336f Mon Sep 17 00:00:00 2001 From: The Magician Date: Tue, 6 Aug 2024 16:41:13 -0700 Subject: [PATCH] Add deletion_protection to v2 cloud run service resource (#11318) (#7901) [upstream:1c7aa4de79d54b48b5e81cab86661d3db582625b] Signed-off-by: Modular Magician --- .changelog/11318.txt | 3 + ...ata_source_google_cloud_run_v2_job_test.go | 2 + ...source_google_cloud_run_v2_service_test.go | 2 + .../iam_cloud_run_v2_job_generated_test.go | 5 + ...iam_cloud_run_v2_service_generated_test.go | 5 + .../cloudrunv2/resource_cloud_run_v2_job.go | 25 ++++ ...esource_cloud_run_v2_job_generated_test.go | 25 ++-- .../resource_cloud_run_v2_job_sweeper.go | 139 ------------------ .../resource_cloud_run_v2_job_test.go | 30 ++-- .../resource_cloud_run_v2_service.go | 25 ++++ ...rce_cloud_run_v2_service_generated_test.go | 30 ++-- .../resource_cloud_run_v2_service_sweeper.go | 139 ------------------ .../resource_cloud_run_v2_service_test.go | 49 ++++-- .../guides/version_6_upgrade.html.markdown | 22 +++ website/docs/r/cloud_run_v2_job.html.markdown | 16 +- .../docs/r/cloud_run_v2_service.html.markdown | 17 +++ 16 files changed, 210 insertions(+), 324 deletions(-) create mode 100644 .changelog/11318.txt delete mode 100644 google-beta/services/cloudrunv2/resource_cloud_run_v2_job_sweeper.go delete mode 100644 google-beta/services/cloudrunv2/resource_cloud_run_v2_service_sweeper.go diff --git a/.changelog/11318.txt b/.changelog/11318.txt new file mode 100644 index 0000000000..d174bd6122 --- /dev/null +++ b/.changelog/11318.txt @@ -0,0 +1,3 @@ +```release-note:breaking-change +cloudrunv2: added `deletion_protection` field to `google_cloudrunv2_service` to make deleting them require an explicit intent. `google_cloudrunv2_service` resources now cannot be destroyed unless `deletion_protection = false` is set for the resource. +``` \ No newline at end of file diff --git a/google-beta/services/cloudrunv2/data_source_google_cloud_run_v2_job_test.go b/google-beta/services/cloudrunv2/data_source_google_cloud_run_v2_job_test.go index 1c8ca3c8b0..852151816e 100644 --- a/google-beta/services/cloudrunv2/data_source_google_cloud_run_v2_job_test.go +++ b/google-beta/services/cloudrunv2/data_source_google_cloud_run_v2_job_test.go @@ -41,6 +41,7 @@ func testAccDataSourceGoogleCloudRunV2Job_basic(name, location string) string { resource "google_cloud_run_v2_job" "hello" { name = "%s" location = "%s" + deletion_protection = false template { template { @@ -102,6 +103,7 @@ func testAccDataSourceGoogleCloudRunV2Job_bindIAMPermission(name, location strin resource "google_cloud_run_v2_job" "hello" { name = "%s" location = "%s" + deletion_protection = false template { template { diff --git a/google-beta/services/cloudrunv2/data_source_google_cloud_run_v2_service_test.go b/google-beta/services/cloudrunv2/data_source_google_cloud_run_v2_service_test.go index eb3e4ccf82..9cde2e128f 100644 --- a/google-beta/services/cloudrunv2/data_source_google_cloud_run_v2_service_test.go +++ b/google-beta/services/cloudrunv2/data_source_google_cloud_run_v2_service_test.go @@ -41,6 +41,7 @@ func testAccDataSourceGoogleCloudRunV2Service_basic(name, location string) strin resource "google_cloud_run_v2_service" "hello" { name = "%s" location = "%s" + deletion_protection = false ingress = "INGRESS_TRAFFIC_ALL" template { @@ -95,6 +96,7 @@ func testAccDataSourceGoogleCloudRunV2Service_bindIAMPermission(name, location s resource "google_cloud_run_v2_service" "hello" { name = "%s" location = "%s" + deletion_protection = false ingress = "INGRESS_TRAFFIC_ALL" template { diff --git a/google-beta/services/cloudrunv2/iam_cloud_run_v2_job_generated_test.go b/google-beta/services/cloudrunv2/iam_cloud_run_v2_job_generated_test.go index 7d9a06e81c..2158aef432 100644 --- a/google-beta/services/cloudrunv2/iam_cloud_run_v2_job_generated_test.go +++ b/google-beta/services/cloudrunv2/iam_cloud_run_v2_job_generated_test.go @@ -128,6 +128,7 @@ func testAccCloudRunV2JobIamMember_basicGenerated(context map[string]interface{} resource "google_cloud_run_v2_job" "default" { name = "tf-test-cloudrun-job%{random_suffix}" location = "us-central1" + deletion_protection = false template { template { @@ -153,6 +154,7 @@ func testAccCloudRunV2JobIamPolicy_basicGenerated(context map[string]interface{} resource "google_cloud_run_v2_job" "default" { name = "tf-test-cloudrun-job%{random_suffix}" location = "us-central1" + deletion_protection = false template { template { @@ -193,6 +195,7 @@ func testAccCloudRunV2JobIamPolicy_emptyBinding(context map[string]interface{}) resource "google_cloud_run_v2_job" "default" { name = "tf-test-cloudrun-job%{random_suffix}" location = "us-central1" + deletion_protection = false template { template { @@ -220,6 +223,7 @@ func testAccCloudRunV2JobIamBinding_basicGenerated(context map[string]interface{ resource "google_cloud_run_v2_job" "default" { name = "tf-test-cloudrun-job%{random_suffix}" location = "us-central1" + deletion_protection = false template { template { @@ -245,6 +249,7 @@ func testAccCloudRunV2JobIamBinding_updateGenerated(context map[string]interface resource "google_cloud_run_v2_job" "default" { name = "tf-test-cloudrun-job%{random_suffix}" location = "us-central1" + deletion_protection = false template { template { diff --git a/google-beta/services/cloudrunv2/iam_cloud_run_v2_service_generated_test.go b/google-beta/services/cloudrunv2/iam_cloud_run_v2_service_generated_test.go index a80e8532dd..5178eee9a7 100644 --- a/google-beta/services/cloudrunv2/iam_cloud_run_v2_service_generated_test.go +++ b/google-beta/services/cloudrunv2/iam_cloud_run_v2_service_generated_test.go @@ -128,6 +128,7 @@ func testAccCloudRunV2ServiceIamMember_basicGenerated(context map[string]interfa resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" location = "us-central1" + deletion_protection = false ingress = "INGRESS_TRAFFIC_ALL" template { @@ -152,6 +153,7 @@ func testAccCloudRunV2ServiceIamPolicy_basicGenerated(context map[string]interfa resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" location = "us-central1" + deletion_protection = false ingress = "INGRESS_TRAFFIC_ALL" template { @@ -191,6 +193,7 @@ func testAccCloudRunV2ServiceIamPolicy_emptyBinding(context map[string]interface resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" location = "us-central1" + deletion_protection = false ingress = "INGRESS_TRAFFIC_ALL" template { @@ -217,6 +220,7 @@ func testAccCloudRunV2ServiceIamBinding_basicGenerated(context map[string]interf resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" location = "us-central1" + deletion_protection = false ingress = "INGRESS_TRAFFIC_ALL" template { @@ -241,6 +245,7 @@ func testAccCloudRunV2ServiceIamBinding_updateGenerated(context map[string]inter resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" location = "us-central1" + deletion_protection = false ingress = "INGRESS_TRAFFIC_ALL" template { diff --git a/google-beta/services/cloudrunv2/resource_cloud_run_v2_job.go b/google-beta/services/cloudrunv2/resource_cloud_run_v2_job.go index f4b527a31e..78cb768607 100644 --- a/google-beta/services/cloudrunv2/resource_cloud_run_v2_job.go +++ b/google-beta/services/cloudrunv2/resource_cloud_run_v2_job.go @@ -756,6 +756,17 @@ A timestamp in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to n Computed: true, Description: `The last-modified time.`, }, + "deletion_protection": { + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: `Whether Terraform will be prevented from destroying the job. Defaults to true. +When a'terraform destroy' or 'terraform apply' would delete the job, +the command will fail if this field is not set to false in Terraform state. +When the field is set to true or unset in Terraform state, a 'terraform apply' +or 'terraform destroy' that would delete the job will fail. +When the field is set to false, deleting the job is allowed.`, + }, "project": { Type: schema.TypeString, Optional: true, @@ -978,6 +989,12 @@ func resourceCloudRunV2JobRead(d *schema.ResourceData, meta interface{}) error { return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("CloudRunV2Job %q", d.Id())) } + // Explicitly set virtual fields to default values if unset + if _, ok := d.GetOkExists("deletion_protection"); !ok { + if err := d.Set("deletion_protection", true); err != nil { + return fmt.Errorf("Error setting deletion_protection: %s", err) + } + } if err := d.Set("project", project); err != nil { return fmt.Errorf("Error reading Job: %s", err) } @@ -1207,6 +1224,9 @@ func resourceCloudRunV2JobDelete(d *schema.ResourceData, meta interface{}) error } headers := make(http.Header) + if d.Get("deletion_protection").(bool) { + return fmt.Errorf("cannot destroy job without setting deletion_protection=false and running `terraform apply`") + } log.Printf("[DEBUG] Deleting Job %q", d.Id()) res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ @@ -1252,6 +1272,11 @@ func resourceCloudRunV2JobImport(d *schema.ResourceData, meta interface{}) ([]*s } d.SetId(id) + // Explicitly set virtual fields to default values on import + if err := d.Set("deletion_protection", true); err != nil { + return nil, fmt.Errorf("Error setting deletion_protection: %s", err) + } + return []*schema.ResourceData{d}, nil } diff --git a/google-beta/services/cloudrunv2/resource_cloud_run_v2_job_generated_test.go b/google-beta/services/cloudrunv2/resource_cloud_run_v2_job_generated_test.go index 03ea0de3f6..378c442db3 100644 --- a/google-beta/services/cloudrunv2/resource_cloud_run_v2_job_generated_test.go +++ b/google-beta/services/cloudrunv2/resource_cloud_run_v2_job_generated_test.go @@ -49,7 +49,7 @@ func TestAccCloudRunV2Job_cloudrunv2JobBasicExample(t *testing.T) { ResourceName: "google_cloud_run_v2_job.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"annotations", "labels", "location", "name", "terraform_labels"}, + ImportStateVerifyIgnore: []string{"annotations", "deletion_protection", "labels", "location", "name", "terraform_labels"}, }, }, }) @@ -60,6 +60,7 @@ func testAccCloudRunV2Job_cloudrunv2JobBasicExample(context map[string]interface resource "google_cloud_run_v2_job" "default" { name = "tf-test-cloudrun-job%{random_suffix}" location = "us-central1" + deletion_protection = false template { template { @@ -91,7 +92,7 @@ func TestAccCloudRunV2Job_cloudrunv2JobLimitsExample(t *testing.T) { ResourceName: "google_cloud_run_v2_job.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"annotations", "labels", "location", "name", "terraform_labels"}, + ImportStateVerifyIgnore: []string{"annotations", "deletion_protection", "labels", "location", "name", "terraform_labels"}, }, }, }) @@ -102,6 +103,7 @@ func testAccCloudRunV2Job_cloudrunv2JobLimitsExample(context map[string]interfac resource "google_cloud_run_v2_job" "default" { name = "tf-test-cloudrun-job%{random_suffix}" location = "us-central1" + deletion_protection = false template { template { @@ -146,7 +148,7 @@ func TestAccCloudRunV2Job_cloudrunv2JobSqlExample(t *testing.T) { ResourceName: "google_cloud_run_v2_job.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"annotations", "labels", "location", "name", "terraform_labels"}, + ImportStateVerifyIgnore: []string{"annotations", "deletion_protection", "labels", "location", "name", "terraform_labels"}, }, }, }) @@ -157,7 +159,7 @@ func testAccCloudRunV2Job_cloudrunv2JobSqlExample(context map[string]interface{} resource "google_cloud_run_v2_job" "default" { name = "tf-test-cloudrun-job%{random_suffix}" location = "us-central1" - + deletion_protection = false template { template{ volumes { @@ -246,7 +248,7 @@ func TestAccCloudRunV2Job_cloudrunv2JobVpcaccessExample(t *testing.T) { ResourceName: "google_cloud_run_v2_job.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"annotations", "labels", "location", "name", "terraform_labels"}, + ImportStateVerifyIgnore: []string{"annotations", "deletion_protection", "labels", "location", "name", "terraform_labels"}, }, }, }) @@ -257,6 +259,7 @@ func testAccCloudRunV2Job_cloudrunv2JobVpcaccessExample(context map[string]inter resource "google_cloud_run_v2_job" "default" { name = "tf-test-cloudrun-job%{random_suffix}" location = "us-central1" + deletion_protection = false template { template{ @@ -313,7 +316,7 @@ func TestAccCloudRunV2Job_cloudrunv2JobDirectvpcExample(t *testing.T) { ResourceName: "google_cloud_run_v2_job.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"annotations", "labels", "location", "name", "terraform_labels"}, + ImportStateVerifyIgnore: []string{"annotations", "deletion_protection", "labels", "location", "name", "terraform_labels"}, }, }, }) @@ -324,6 +327,7 @@ func testAccCloudRunV2Job_cloudrunv2JobDirectvpcExample(context map[string]inter resource "google_cloud_run_v2_job" "default" { name = "tf-test-cloudrun-job%{random_suffix}" location = "us-central1" + deletion_protection = false launch_stage = "GA" template { template{ @@ -362,7 +366,7 @@ func TestAccCloudRunV2Job_cloudrunv2JobSecretExample(t *testing.T) { ResourceName: "google_cloud_run_v2_job.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"annotations", "labels", "location", "name", "terraform_labels"}, + ImportStateVerifyIgnore: []string{"annotations", "deletion_protection", "labels", "location", "name", "terraform_labels"}, }, }, }) @@ -373,6 +377,7 @@ func testAccCloudRunV2Job_cloudrunv2JobSecretExample(context map[string]interfac resource "google_cloud_run_v2_job" "default" { name = "tf-test-cloudrun-job%{random_suffix}" location = "us-central1" + deletion_protection = false template { template { @@ -447,7 +452,7 @@ func TestAccCloudRunV2Job_cloudrunv2JobEmptydirExample(t *testing.T) { ResourceName: "google_cloud_run_v2_job.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"annotations", "labels", "location", "name", "terraform_labels"}, + ImportStateVerifyIgnore: []string{"annotations", "deletion_protection", "labels", "location", "name", "terraform_labels"}, }, }, }) @@ -459,6 +464,7 @@ resource "google_cloud_run_v2_job" "default" { provider = google-beta name = "tf-test-cloudrun-job%{random_suffix}" location = "us-central1" + deletion_protection = false launch_stage = "BETA" template { template { @@ -501,7 +507,7 @@ func TestAccCloudRunV2Job_cloudrunv2JobRunJobExample(t *testing.T) { ResourceName: "google_cloud_run_v2_job.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"annotations", "labels", "location", "name", "terraform_labels"}, + ImportStateVerifyIgnore: []string{"annotations", "deletion_protection", "labels", "location", "name", "terraform_labels"}, }, }, }) @@ -513,6 +519,7 @@ resource "google_cloud_run_v2_job" "default" { provider = google-beta name = "tf-test-cloudrun-job%{random_suffix}" location = "us-central1" + deletion_protection = false start_execution_token = "start-once-created" template { template { diff --git a/google-beta/services/cloudrunv2/resource_cloud_run_v2_job_sweeper.go b/google-beta/services/cloudrunv2/resource_cloud_run_v2_job_sweeper.go deleted file mode 100644 index 54d00b5080..0000000000 --- a/google-beta/services/cloudrunv2/resource_cloud_run_v2_job_sweeper.go +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -// ---------------------------------------------------------------------------- -// -// *** AUTO GENERATED CODE *** Type: MMv1 *** -// -// ---------------------------------------------------------------------------- -// -// This file is automatically generated by Magic Modules and manual -// changes will be clobbered when the file is regenerated. -// -// Please read more about how to change this file in -// .github/CONTRIBUTING.md. -// -// ---------------------------------------------------------------------------- - -package cloudrunv2 - -import ( - "context" - "log" - "strings" - "testing" - - "github.com/hashicorp/terraform-provider-google-beta/google-beta/envvar" - "github.com/hashicorp/terraform-provider-google-beta/google-beta/sweeper" - "github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgresource" - transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport" -) - -func init() { - sweeper.AddTestSweepers("CloudRunV2Job", testSweepCloudRunV2Job) -} - -// At the time of writing, the CI only passes us-central1 as the region -func testSweepCloudRunV2Job(region string) error { - resourceName := "CloudRunV2Job" - log.Printf("[INFO][SWEEPER_LOG] Starting sweeper for %s", resourceName) - - config, err := sweeper.SharedConfigForRegion(region) - if err != nil { - log.Printf("[INFO][SWEEPER_LOG] error getting shared config for region: %s", err) - return err - } - - err = config.LoadAndValidate(context.Background()) - if err != nil { - log.Printf("[INFO][SWEEPER_LOG] error loading: %s", err) - return err - } - - t := &testing.T{} - billingId := envvar.GetTestBillingAccountFromEnv(t) - - // Setup variables to replace in list template - d := &tpgresource.ResourceDataMock{ - FieldsInSchema: map[string]interface{}{ - "project": config.Project, - "region": region, - "location": region, - "zone": "-", - "billing_account": billingId, - }, - } - - listTemplate := strings.Split("https://run.googleapis.com/v2/projects/{{project}}/locations/{{location}}/jobs", "?")[0] - listUrl, err := tpgresource.ReplaceVars(d, config, listTemplate) - if err != nil { - log.Printf("[INFO][SWEEPER_LOG] error preparing sweeper list url: %s", err) - return nil - } - - res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ - Config: config, - Method: "GET", - Project: config.Project, - RawURL: listUrl, - UserAgent: config.UserAgent, - }) - if err != nil { - log.Printf("[INFO][SWEEPER_LOG] Error in response from request %s: %s", listUrl, err) - return nil - } - - resourceList, ok := res["jobs"] - if !ok { - log.Printf("[INFO][SWEEPER_LOG] Nothing found in response.") - return nil - } - - rl := resourceList.([]interface{}) - - log.Printf("[INFO][SWEEPER_LOG] Found %d items in %s list response.", len(rl), resourceName) - // Keep count of items that aren't sweepable for logging. - nonPrefixCount := 0 - for _, ri := range rl { - obj := ri.(map[string]interface{}) - if obj["name"] == nil { - log.Printf("[INFO][SWEEPER_LOG] %s resource name was nil", resourceName) - return nil - } - - name := tpgresource.GetResourceNameFromSelfLink(obj["name"].(string)) - // Skip resources that shouldn't be sweeped - if !sweeper.IsSweepableTestResource(name) { - nonPrefixCount++ - continue - } - - deleteTemplate := "https://run.googleapis.com/v2/projects/{{project}}/locations/{{location}}/jobs/{{name}}" - deleteUrl, err := tpgresource.ReplaceVars(d, config, deleteTemplate) - if err != nil { - log.Printf("[INFO][SWEEPER_LOG] error preparing delete url: %s", err) - return nil - } - deleteUrl = deleteUrl + name - - // Don't wait on operations as we may have a lot to delete - _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ - Config: config, - Method: "DELETE", - Project: config.Project, - RawURL: deleteUrl, - UserAgent: config.UserAgent, - }) - if err != nil { - log.Printf("[INFO][SWEEPER_LOG] Error deleting for url %s : %s", deleteUrl, err) - } else { - log.Printf("[INFO][SWEEPER_LOG] Sent delete request for %s resource: %s", resourceName, name) - } - } - - if nonPrefixCount > 0 { - log.Printf("[INFO][SWEEPER_LOG] %d items were non-sweepable and skipped.", nonPrefixCount) - } - - return nil -} diff --git a/google-beta/services/cloudrunv2/resource_cloud_run_v2_job_test.go b/google-beta/services/cloudrunv2/resource_cloud_run_v2_job_test.go index 4d36ecfdb5..57b34f25e3 100644 --- a/google-beta/services/cloudrunv2/resource_cloud_run_v2_job_test.go +++ b/google-beta/services/cloudrunv2/resource_cloud_run_v2_job_test.go @@ -38,7 +38,7 @@ func TestAccCloudRunV2Job_cloudrunv2JobFullUpdate(t *testing.T) { ResourceName: "google_cloud_run_v2_job.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"location", "launch_stage", "labels", "terraform_labels", "annotations"}, + ImportStateVerifyIgnore: []string{"location", "launch_stage", "labels", "terraform_labels", "annotations", "deletion_protection"}, }, }, }) @@ -117,6 +117,7 @@ func testAccCloudRunV2Job_cloudrunv2JobFullUpdate(context map[string]interface{} resource "google_cloud_run_v2_job" "default" { name = "tf-test-cloudrun-job%{random_suffix}" location = "us-central1" + deletion_protection = false binary_authorization { use_default = true breakglass_justification = "Some justification" @@ -228,7 +229,7 @@ func TestAccCloudRunV2Job_cloudrunv2JobWithDirectVPCUpdate(t *testing.T) { ResourceName: "google_cloud_run_v2_job.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"location", "launch_stage"}, + ImportStateVerifyIgnore: []string{"location", "launch_stage", "deletion_protection"}, }, { Config: testAccCloudRunV2Job_cloudrunv2JobWithDirectVPCUpdate(context), @@ -237,7 +238,7 @@ func TestAccCloudRunV2Job_cloudrunv2JobWithDirectVPCUpdate(t *testing.T) { ResourceName: "google_cloud_run_v2_job.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"location", "launch_stage"}, + ImportStateVerifyIgnore: []string{"location", "launch_stage", "deletion_protection"}, }, }, }) @@ -248,6 +249,7 @@ func testAccCloudRunV2Job_cloudrunv2JobWithDirectVPC(context map[string]interfac resource "google_cloud_run_v2_job" "default" { name = "%{job_name}" location = "us-central1" + deletion_protection = false launch_stage = "BETA" template { template { @@ -276,6 +278,7 @@ func testAccCloudRunV2Job_cloudrunv2JobWithDirectVPCUpdate(context map[string]in resource "google_cloud_run_v2_job" "default" { name = "%{job_name}" location = "us-central1" + deletion_protection = false launch_stage = "BETA" template { template { @@ -321,7 +324,7 @@ func TestAccCloudRunV2Job_cloudrunv2JobWithGcsUpdate(t *testing.T) { ResourceName: "google_cloud_run_v2_job.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"location", "launch_stage"}, + ImportStateVerifyIgnore: []string{"location", "launch_stage", "deletion_protection"}, }, { Config: testAccCloudRunV2Job_cloudrunv2JobWithGcsVolume(context), @@ -330,7 +333,7 @@ func TestAccCloudRunV2Job_cloudrunv2JobWithGcsUpdate(t *testing.T) { ResourceName: "google_cloud_run_v2_job.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"location", "launch_stage"}, + ImportStateVerifyIgnore: []string{"location", "launch_stage", "deletion_protection"}, }, }, }) @@ -341,6 +344,7 @@ func testAccCloudRunV2Job_cloudrunv2JobWithNoVolume(context map[string]interface resource "google_cloud_run_v2_job" "default" { name = "%{job_name}" location = "us-central1" + deletion_protection = false launch_stage = "BETA" template { template { @@ -364,6 +368,7 @@ func testAccCloudRunV2Job_cloudrunv2JobWithGcsVolume(context map[string]interfac resource "google_cloud_run_v2_job" "default" { name = "%{job_name}" location = "us-central1" + deletion_protection = false launch_stage = "BETA" template { template { @@ -407,7 +412,7 @@ func TestAccCloudRunV2Job_cloudrunv2JobWithNfsUpdate(t *testing.T) { ResourceName: "google_cloud_run_v2_job.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"location", "launch_stage"}, + ImportStateVerifyIgnore: []string{"location", "launch_stage", "deletion_protection"}, }, { Config: testAccCloudRunV2Job_cloudrunv2JobWithNfsVolume(context), @@ -416,7 +421,7 @@ func TestAccCloudRunV2Job_cloudrunv2JobWithNfsUpdate(t *testing.T) { ResourceName: "google_cloud_run_v2_job.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"location", "launch_stage"}, + ImportStateVerifyIgnore: []string{"location", "launch_stage", "deletion_protection"}, }, }, }) @@ -427,6 +432,7 @@ func testAccCloudRunV2Job_cloudrunv2JobWithNfsVolume(context map[string]interfac resource "google_cloud_run_v2_job" "default" { name = "%{job_name}" location = "us-central1" + deletion_protection = false launch_stage = "BETA" template { template { @@ -476,7 +482,7 @@ func TestAccCloudRunV2Job_cloudrunv2JobWithStartExecutionTokenUpdate(t *testing. ResourceName: "google_cloud_run_v2_job.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"location", "launch_stage"}, + ImportStateVerifyIgnore: []string{"location", "launch_stage", "deletion_protection"}, }, { Config: testAccCloudRunV2Job_cloudrunv2JobWithStartExecutionToken(context2), @@ -485,7 +491,7 @@ func TestAccCloudRunV2Job_cloudrunv2JobWithStartExecutionTokenUpdate(t *testing. ResourceName: "google_cloud_run_v2_job.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"location", "launch_stage"}, + ImportStateVerifyIgnore: []string{"location", "launch_stage", "deletion_protection"}, }, }, }) @@ -496,6 +502,7 @@ func testAccCloudRunV2Job_cloudrunv2JobWithStartExecutionToken(context map[strin resource "google_cloud_run_v2_job" "default" { name = "%{job_name}" location = "us-central1" + deletion_protection = false start_execution_token = "%{token}" template { template { @@ -533,7 +540,7 @@ func TestAccCloudRunV2Job_cloudrunv2JobWithRunExecutionTokenUpdate(t *testing.T) ResourceName: "google_cloud_run_v2_job.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"location", "launch_stage"}, + ImportStateVerifyIgnore: []string{"location", "launch_stage", "deletion_protection"}, }, { Config: testAccCloudRunV2Job_cloudrunv2JobWithRunExecutionToken(context2), @@ -542,7 +549,7 @@ func TestAccCloudRunV2Job_cloudrunv2JobWithRunExecutionTokenUpdate(t *testing.T) ResourceName: "google_cloud_run_v2_job.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"location", "launch_stage"}, + ImportStateVerifyIgnore: []string{"location", "launch_stage", "deletion_protection"}, }, }, }) @@ -553,6 +560,7 @@ func testAccCloudRunV2Job_cloudrunv2JobWithRunExecutionToken(context map[string] resource "google_cloud_run_v2_job" "default" { name = "%{job_name}" location = "us-central1" + deletion_protection = false run_execution_token = "%{token}" template { template { diff --git a/google-beta/services/cloudrunv2/resource_cloud_run_v2_service.go b/google-beta/services/cloudrunv2/resource_cloud_run_v2_service.go index a0d9d70e8b..032e75840a 100644 --- a/google-beta/services/cloudrunv2/resource_cloud_run_v2_service.go +++ b/google-beta/services/cloudrunv2/resource_cloud_run_v2_service.go @@ -1096,6 +1096,17 @@ If reconciliation failed, trafficStatuses, observedGeneration, and latestReadyRe Computed: true, Description: `The main URI in which this Service is serving traffic.`, }, + "deletion_protection": { + Type: schema.TypeBool, + Optional: true, + Default: true, + Description: `Whether Terraform will be prevented from destroying the service. Defaults to true. +When a'terraform destroy' or 'terraform apply' would delete the service, +the command will fail if this field is not set to false in Terraform state. +When the field is set to true or unset in Terraform state, a 'terraform apply' +or 'terraform destroy' that would delete the service will fail. +When the field is set to false, deleting the service is allowed.`, + }, "project": { Type: schema.TypeString, Optional: true, @@ -1342,6 +1353,12 @@ func resourceCloudRunV2ServiceRead(d *schema.ResourceData, meta interface{}) err return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("CloudRunV2Service %q", d.Id())) } + // Explicitly set virtual fields to default values if unset + if _, ok := d.GetOkExists("deletion_protection"); !ok { + if err := d.Set("deletion_protection", true); err != nil { + return fmt.Errorf("Error setting deletion_protection: %s", err) + } + } if err := d.Set("project", project); err != nil { return fmt.Errorf("Error reading Service: %s", err) } @@ -1613,6 +1630,9 @@ func resourceCloudRunV2ServiceDelete(d *schema.ResourceData, meta interface{}) e } headers := make(http.Header) + if d.Get("deletion_protection").(bool) { + return fmt.Errorf("cannot destroy service without setting deletion_protection=false and running `terraform apply`") + } log.Printf("[DEBUG] Deleting Service %q", d.Id()) res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ @@ -1658,6 +1678,11 @@ func resourceCloudRunV2ServiceImport(d *schema.ResourceData, meta interface{}) ( } d.SetId(id) + // Explicitly set virtual fields to default values on import + if err := d.Set("deletion_protection", true); err != nil { + return nil, fmt.Errorf("Error setting deletion_protection: %s", err) + } + return []*schema.ResourceData{d}, nil } diff --git a/google-beta/services/cloudrunv2/resource_cloud_run_v2_service_generated_test.go b/google-beta/services/cloudrunv2/resource_cloud_run_v2_service_generated_test.go index 5deaafb6a2..911349fd2f 100644 --- a/google-beta/services/cloudrunv2/resource_cloud_run_v2_service_generated_test.go +++ b/google-beta/services/cloudrunv2/resource_cloud_run_v2_service_generated_test.go @@ -49,7 +49,7 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceBasicExample(t *testing.T) { ResourceName: "google_cloud_run_v2_service.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"annotations", "labels", "location", "name", "terraform_labels"}, + ImportStateVerifyIgnore: []string{"annotations", "deletion_protection", "labels", "location", "name", "terraform_labels"}, }, }, }) @@ -60,6 +60,7 @@ func testAccCloudRunV2Service_cloudrunv2ServiceBasicExample(context map[string]i resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" location = "us-central1" + deletion_protection = false ingress = "INGRESS_TRAFFIC_ALL" template { @@ -90,7 +91,7 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceLimitsExample(t *testing.T) { ResourceName: "google_cloud_run_v2_service.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"annotations", "labels", "location", "name", "terraform_labels"}, + ImportStateVerifyIgnore: []string{"annotations", "deletion_protection", "labels", "location", "name", "terraform_labels"}, }, }, }) @@ -101,6 +102,7 @@ func testAccCloudRunV2Service_cloudrunv2ServiceLimitsExample(context map[string] resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" location = "us-central1" + deletion_protection = false ingress = "INGRESS_TRAFFIC_ALL" template { @@ -138,7 +140,7 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceSqlExample(t *testing.T) { ResourceName: "google_cloud_run_v2_service.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"annotations", "labels", "location", "name", "terraform_labels"}, + ImportStateVerifyIgnore: []string{"annotations", "deletion_protection", "labels", "location", "name", "terraform_labels"}, }, }, }) @@ -149,6 +151,7 @@ func testAccCloudRunV2Service_cloudrunv2ServiceSqlExample(context map[string]int resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" location = "us-central1" + deletion_protection = false ingress = "INGRESS_TRAFFIC_ALL" template { @@ -247,7 +250,7 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceVpcaccessExample(t *testing.T) { ResourceName: "google_cloud_run_v2_service.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"annotations", "labels", "location", "name", "terraform_labels"}, + ImportStateVerifyIgnore: []string{"annotations", "deletion_protection", "labels", "location", "name", "terraform_labels"}, }, }, }) @@ -258,6 +261,7 @@ func testAccCloudRunV2Service_cloudrunv2ServiceVpcaccessExample(context map[stri resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" location = "us-central1" + deletion_protection = false template { containers { @@ -312,7 +316,7 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceDirectvpcExample(t *testing.T) { ResourceName: "google_cloud_run_v2_service.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"annotations", "labels", "location", "name", "terraform_labels"}, + ImportStateVerifyIgnore: []string{"annotations", "deletion_protection", "labels", "location", "name", "terraform_labels"}, }, }, }) @@ -323,6 +327,7 @@ func testAccCloudRunV2Service_cloudrunv2ServiceDirectvpcExample(context map[stri resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" location = "us-central1" + deletion_protection = false launch_stage = "GA" template { containers { @@ -359,7 +364,7 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceProbesExample(t *testing.T) { ResourceName: "google_cloud_run_v2_service.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"annotations", "labels", "location", "name", "terraform_labels"}, + ImportStateVerifyIgnore: []string{"annotations", "deletion_protection", "labels", "location", "name", "terraform_labels"}, }, }, }) @@ -370,6 +375,7 @@ func testAccCloudRunV2Service_cloudrunv2ServiceProbesExample(context map[string] resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" location = "us-central1" + deletion_protection = false template { containers { @@ -413,7 +419,7 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceSecretExample(t *testing.T) { ResourceName: "google_cloud_run_v2_service.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"annotations", "labels", "location", "name", "terraform_labels"}, + ImportStateVerifyIgnore: []string{"annotations", "deletion_protection", "labels", "location", "name", "terraform_labels"}, }, }, }) @@ -424,6 +430,7 @@ func testAccCloudRunV2Service_cloudrunv2ServiceSecretExample(context map[string] resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" location = "us-central1" + deletion_protection = false ingress = "INGRESS_TRAFFIC_ALL" template { @@ -492,7 +499,7 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceMulticontainerExample(t *testing. ResourceName: "google_cloud_run_v2_service.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"annotations", "labels", "location", "name", "terraform_labels"}, + ImportStateVerifyIgnore: []string{"annotations", "deletion_protection", "labels", "location", "name", "terraform_labels"}, }, }, }) @@ -504,6 +511,7 @@ resource "google_cloud_run_v2_service" "default" { provider = google-beta name = "tf-test-cloudrun-service%{random_suffix}" location = "us-central1" + deletion_protection = false launch_stage = "BETA" ingress = "INGRESS_TRAFFIC_ALL" template { @@ -563,7 +571,7 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceMountGcsExample(t *testing.T) { ResourceName: "google_cloud_run_v2_service.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"annotations", "labels", "location", "name", "terraform_labels"}, + ImportStateVerifyIgnore: []string{"annotations", "deletion_protection", "labels", "location", "name", "terraform_labels"}, }, }, }) @@ -575,6 +583,7 @@ resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" location = "us-central1" + deletion_protection = false launch_stage = "BETA" template { @@ -624,7 +633,7 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceMountNfsExample(t *testing.T) { ResourceName: "google_cloud_run_v2_service.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"annotations", "labels", "location", "name", "terraform_labels"}, + ImportStateVerifyIgnore: []string{"annotations", "deletion_protection", "labels", "location", "name", "terraform_labels"}, }, }, }) @@ -636,6 +645,7 @@ resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" location = "us-central1" + deletion_protection = false ingress = "INGRESS_TRAFFIC_ALL" launch_stage = "BETA" diff --git a/google-beta/services/cloudrunv2/resource_cloud_run_v2_service_sweeper.go b/google-beta/services/cloudrunv2/resource_cloud_run_v2_service_sweeper.go deleted file mode 100644 index 60fa774576..0000000000 --- a/google-beta/services/cloudrunv2/resource_cloud_run_v2_service_sweeper.go +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -// ---------------------------------------------------------------------------- -// -// *** AUTO GENERATED CODE *** Type: MMv1 *** -// -// ---------------------------------------------------------------------------- -// -// This file is automatically generated by Magic Modules and manual -// changes will be clobbered when the file is regenerated. -// -// Please read more about how to change this file in -// .github/CONTRIBUTING.md. -// -// ---------------------------------------------------------------------------- - -package cloudrunv2 - -import ( - "context" - "log" - "strings" - "testing" - - "github.com/hashicorp/terraform-provider-google-beta/google-beta/envvar" - "github.com/hashicorp/terraform-provider-google-beta/google-beta/sweeper" - "github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgresource" - transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport" -) - -func init() { - sweeper.AddTestSweepers("CloudRunV2Service", testSweepCloudRunV2Service) -} - -// At the time of writing, the CI only passes us-central1 as the region -func testSweepCloudRunV2Service(region string) error { - resourceName := "CloudRunV2Service" - log.Printf("[INFO][SWEEPER_LOG] Starting sweeper for %s", resourceName) - - config, err := sweeper.SharedConfigForRegion(region) - if err != nil { - log.Printf("[INFO][SWEEPER_LOG] error getting shared config for region: %s", err) - return err - } - - err = config.LoadAndValidate(context.Background()) - if err != nil { - log.Printf("[INFO][SWEEPER_LOG] error loading: %s", err) - return err - } - - t := &testing.T{} - billingId := envvar.GetTestBillingAccountFromEnv(t) - - // Setup variables to replace in list template - d := &tpgresource.ResourceDataMock{ - FieldsInSchema: map[string]interface{}{ - "project": config.Project, - "region": region, - "location": region, - "zone": "-", - "billing_account": billingId, - }, - } - - listTemplate := strings.Split("https://run.googleapis.com/v2/projects/{{project}}/locations/{{location}}/services", "?")[0] - listUrl, err := tpgresource.ReplaceVars(d, config, listTemplate) - if err != nil { - log.Printf("[INFO][SWEEPER_LOG] error preparing sweeper list url: %s", err) - return nil - } - - res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ - Config: config, - Method: "GET", - Project: config.Project, - RawURL: listUrl, - UserAgent: config.UserAgent, - }) - if err != nil { - log.Printf("[INFO][SWEEPER_LOG] Error in response from request %s: %s", listUrl, err) - return nil - } - - resourceList, ok := res["services"] - if !ok { - log.Printf("[INFO][SWEEPER_LOG] Nothing found in response.") - return nil - } - - rl := resourceList.([]interface{}) - - log.Printf("[INFO][SWEEPER_LOG] Found %d items in %s list response.", len(rl), resourceName) - // Keep count of items that aren't sweepable for logging. - nonPrefixCount := 0 - for _, ri := range rl { - obj := ri.(map[string]interface{}) - if obj["name"] == nil { - log.Printf("[INFO][SWEEPER_LOG] %s resource name was nil", resourceName) - return nil - } - - name := tpgresource.GetResourceNameFromSelfLink(obj["name"].(string)) - // Skip resources that shouldn't be sweeped - if !sweeper.IsSweepableTestResource(name) { - nonPrefixCount++ - continue - } - - deleteTemplate := "https://run.googleapis.com/v2/projects/{{project}}/locations/{{location}}/services/{{name}}" - deleteUrl, err := tpgresource.ReplaceVars(d, config, deleteTemplate) - if err != nil { - log.Printf("[INFO][SWEEPER_LOG] error preparing delete url: %s", err) - return nil - } - deleteUrl = deleteUrl + name - - // Don't wait on operations as we may have a lot to delete - _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ - Config: config, - Method: "DELETE", - Project: config.Project, - RawURL: deleteUrl, - UserAgent: config.UserAgent, - }) - if err != nil { - log.Printf("[INFO][SWEEPER_LOG] Error deleting for url %s : %s", deleteUrl, err) - } else { - log.Printf("[INFO][SWEEPER_LOG] Sent delete request for %s resource: %s", resourceName, name) - } - } - - if nonPrefixCount > 0 { - log.Printf("[INFO][SWEEPER_LOG] %d items were non-sweepable and skipped.", nonPrefixCount) - } - - return nil -} diff --git a/google-beta/services/cloudrunv2/resource_cloud_run_v2_service_test.go b/google-beta/services/cloudrunv2/resource_cloud_run_v2_service_test.go index 526b58a210..1d3f5b06d9 100644 --- a/google-beta/services/cloudrunv2/resource_cloud_run_v2_service_test.go +++ b/google-beta/services/cloudrunv2/resource_cloud_run_v2_service_test.go @@ -41,7 +41,7 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceFullUpdate(t *testing.T) { ResourceName: "google_cloud_run_v2_service.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"name", "location", "annotations", "labels", "terraform_labels"}, + ImportStateVerifyIgnore: []string{"name", "location", "annotations", "labels", "terraform_labels", "deletion_protection"}, }, }, }) @@ -116,6 +116,7 @@ resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" description = "description updating" location = "us-central1" + deletion_protection = false annotations = { generated-by = "magic-modules-files" } @@ -227,7 +228,7 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceGcsVolume(t *testing.T) { ResourceName: "google_cloud_run_v2_service.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"name", "location", "annotations", "labels", "terraform_labels", "launch_stage"}, + ImportStateVerifyIgnore: []string{"name", "location", "annotations", "labels", "terraform_labels", "launch_stage", "deletion_protection"}, }, }, }) @@ -239,6 +240,7 @@ resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" description = "description creating" location = "us-central1" + deletion_protection = false launch_stage = "BETA" annotations = { generated-by = "magic-modules" @@ -327,7 +329,7 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceTCPProbesUpdate(t *testing.T) { ResourceName: "google_cloud_run_v2_service.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"name", "location", "annotations"}, + ImportStateVerifyIgnore: []string{"name", "location", "annotations", "deletion_protection"}, }, { Config: testAccCloudRunV2Service_cloudrunv2ServiceUpdateWithTCPStartupProbeAndHTTPLivenessProbe(context), @@ -336,7 +338,7 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceTCPProbesUpdate(t *testing.T) { ResourceName: "google_cloud_run_v2_service.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"name", "location", "annotations"}, + ImportStateVerifyIgnore: []string{"name", "location", "annotations", "deletion_protection"}, }, }, }) @@ -361,7 +363,7 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceHTTPProbesUpdate(t *testing.T) { ResourceName: "google_cloud_run_v2_service.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"name", "location", "annotations"}, + ImportStateVerifyIgnore: []string{"name", "location", "annotations", "deletion_protection"}, }, { Config: testAccCloudRunV2Service_cloudrunv2ServiceUpdateWithHTTPStartupProbe(context), @@ -370,7 +372,7 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceHTTPProbesUpdate(t *testing.T) { ResourceName: "google_cloud_run_v2_service.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"name", "location", "annotations"}, + ImportStateVerifyIgnore: []string{"name", "location", "annotations", "deletion_protection"}, }, }, }) @@ -396,7 +398,7 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceGRPCProbesUpdate(t *testing.T) { ResourceName: "google_cloud_run_v2_service.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"name", "location", "annotations"}, + ImportStateVerifyIgnore: []string{"name", "location", "annotations", "deletion_protection"}, }, { Config: testAccCloudRunV2Service_cloudRunServiceUpdateWithGRPCLivenessProbe(context), @@ -405,7 +407,7 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceGRPCProbesUpdate(t *testing.T) { ResourceName: "google_cloud_run_v2_service.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"name", "location", "annotations"}, + ImportStateVerifyIgnore: []string{"name", "location", "annotations", "deletion_protection"}, }, // The following test steps of gRPC startup probe are expected to fail with startup probe check failures. // This is because, due to the unavailability of ready-to-use container images of a gRPC service that @@ -458,6 +460,7 @@ func testAccCloudRunV2Service_cloudrunv2ServiceWithEmptyTCPStartupProbeAndHTTPLi resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" location = "us-central1" + deletion_protection = false template { containers { @@ -482,6 +485,7 @@ func testAccCloudRunV2Service_cloudrunv2ServiceUpdateWithTCPStartupProbeAndHTTPL resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" location = "us-central1" + deletion_protection = false template { containers { @@ -526,6 +530,7 @@ func testAccCloudRunV2Service_cloudrunv2ServiceUpdateWithEmptyHTTPStartupProbe(c resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" location = "us-central1" + deletion_protection = false template { containers { @@ -544,6 +549,7 @@ func testAccCloudRunV2Service_cloudrunv2ServiceUpdateWithHTTPStartupProbe(contex resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" location = "us-central1" + deletion_protection = false template { containers { @@ -576,6 +582,7 @@ func testAccCloudRunV2Service_cloudRunServiceUpdateWithEmptyGRPCLivenessProbe(co resource "google_cloud_run_v2_service" "default" { name ="%{service_name}" location = "us-central1" + deletion_protection = false template { containers { @@ -597,6 +604,7 @@ func testAccCloudRunV2Service_cloudRunServiceUpdateWithGRPCLivenessProbe(context resource "google_cloud_run_v2_service" "default" { name = "%{service_name}" location = "us-central1" + deletion_protection = false template { containers { @@ -621,6 +629,7 @@ func testAccCloudRunV2Service_cloudRunServiceUpdateWithEmptyGRPCStartupProbe(con resource "google_cloud_run_v2_service" "default" { name = "%{service_name}" location = "us-central1" + deletion_protection = false template { containers { @@ -642,6 +651,7 @@ func testAccCloudRunV2Service_cloudRunServiceUpdateWithGRPCStartupProbe(context resource "google_cloud_run_v2_service" "default" { name = "%{service_name}" location = "us-central1" + deletion_protection = false template { containers { @@ -666,6 +676,7 @@ func testAccCloudRunV2Service_cloudRunServiceUpdateWithGRPCLivenessAndStartupPro resource "google_cloud_run_v2_service" "default" { name = "%{service_name}" location = "us-central1" + deletion_protection = false template { containers { @@ -711,7 +722,7 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceWithDirectVPCUpdate(t *testing.T) ResourceName: "google_cloud_run_v2_service.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"name", "location"}, + ImportStateVerifyIgnore: []string{"name", "location", "deletion_protection"}, }, { Config: testAccCloudRunV2Service_cloudRunServiceWithDirectVPCUpdate(context), @@ -720,7 +731,7 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceWithDirectVPCUpdate(t *testing.T) ResourceName: "google_cloud_run_v2_service.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"name", "location"}, + ImportStateVerifyIgnore: []string{"name", "location", "deletion_protection"}, }, }, }) @@ -731,6 +742,7 @@ func testAccCloudRunV2Service_cloudRunServiceWithDirectVPC(context map[string]in resource "google_cloud_run_v2_service" "default" { name = "%{service_name}" location = "us-central1" + deletion_protection = false launch_stage = "GA" template { containers { @@ -751,6 +763,7 @@ func testAccCloudRunV2Service_cloudRunServiceWithDirectVPCUpdate(context map[str resource "google_cloud_run_v2_service" "default" { name = "%{service_name}" location = "us-central1" + deletion_protection = false launch_stage = "GA" template { containers { @@ -784,7 +797,7 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceCustomAudienceUpdate(t *testing.T ResourceName: "google_cloud_run_v2_service.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"name", "location", "annotations", "launch_stage"}, + ImportStateVerifyIgnore: []string{"name", "location", "annotations", "launch_stage", "deletion_protection"}, }, { Config: testAccCloudRunV2Service_cloudRunServiceUpdateWithCustomAudience(serviceName, "test_update"), @@ -793,7 +806,7 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceCustomAudienceUpdate(t *testing.T ResourceName: "google_cloud_run_v2_service.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"name", "location", "annotations", "launch_stage"}, + ImportStateVerifyIgnore: []string{"name", "location", "annotations", "launch_stage", "deletion_protection"}, }, { Config: testAccCloudRunV2Service_cloudRunServiceUpdateWithoutCustomAudience(serviceName), @@ -802,7 +815,7 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceCustomAudienceUpdate(t *testing.T ResourceName: "google_cloud_run_v2_service.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"name", "location", "annotations", "launch_stage"}, + ImportStateVerifyIgnore: []string{"name", "location", "annotations", "launch_stage", "deletion_protection"}, }, }, }) @@ -813,6 +826,7 @@ func testAccCloudRunV2Service_cloudRunServiceUpdateWithoutCustomAudience(service resource "google_cloud_run_v2_service" "default" { name = "%s" location = "us-central1" + deletion_protection = false template { containers { @@ -831,6 +845,7 @@ func testAccCloudRunV2Service_cloudRunServiceUpdateWithCustomAudience(serviceNam resource "google_cloud_run_v2_service" "default" { name = "%s" location = "us-central1" + deletion_protection = false custom_audiences = ["%s"] template { @@ -903,6 +918,7 @@ provider "google" { resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" location = "us-central1" + deletion_protection = false labels = { user_label = "foo" @@ -930,6 +946,7 @@ provider "google" { resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" location = "us-central1" + deletion_protection = false labels = { user_label = "bar" @@ -964,7 +981,7 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceWithServiceMinInstances(t *testin ResourceName: "google_cloud_run_v2_service.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"name", "location", "annotations", "labels", "terraform_labels", "launch_stage"}, + ImportStateVerifyIgnore: []string{"name", "location", "annotations", "labels", "terraform_labels", "launch_stage", "deletion_protection"}, }, { Config: testAccCloudRunV2Service_cloudrunv2ServiceWithNoMinInstances(context), @@ -973,7 +990,7 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceWithServiceMinInstances(t *testin ResourceName: "google_cloud_run_v2_service.default", ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"name", "location", "annotations", "labels", "terraform_labels", "launch_stage"}, + ImportStateVerifyIgnore: []string{"name", "location", "annotations", "labels", "terraform_labels", "launch_stage", "deletion_protection"}, }, }, }) @@ -985,6 +1002,7 @@ resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" description = "description creating" location = "us-central1" + deletion_protection = false launch_stage = "BETA" annotations = { generated-by = "magic-modules" @@ -1016,6 +1034,7 @@ resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" description = "description creating" location = "us-central1" + deletion_protection = false launch_stage = "BETA" annotations = { generated-by = "magic-modules" diff --git a/website/docs/guides/version_6_upgrade.html.markdown b/website/docs/guides/version_6_upgrade.html.markdown index 4e886659ef..ed8c9749cf 100644 --- a/website/docs/guides/version_6_upgrade.html.markdown +++ b/website/docs/guides/version_6_upgrade.html.markdown @@ -141,6 +141,17 @@ and then run `terraform apply` to apply the change. ## Resource: `google_cloud_run_v2_job` +### Job deletion now prevented by default with `deletion_protection` + +The field `deletion_protection` has been added with a default value of `true`. This field prevents +Terraform from destroying or recreating the Job. In 6.0.0, existing jobs will have +`deletion_protection` set to `true` during the next refresh unless otherwise set in configuration. + +**`deletion_protection` does NOT prevent deletion outside of Terraform.** + +To disable deletion protection, explicitly set this field to `false` in configuration +and then run `terraform apply` to apply the change. + ### retyped `containers.env` to SET from ARRAY Previously, `containers.env` was a list, making it order-dependent. It is now a set. @@ -149,6 +160,17 @@ If you were relying on accessing an individual environment variable by index (fo ## Resource: `google_cloud_run_v2_service` +### Service deletion now prevented by default with `deletion_protection` + +The field `deletion_protection` has been added with a default value of `true`. This field prevents +Terraform from destroying or recreating the Service. In 6.0.0, existing services will have +`deletion_protection` set to `true` during the next refresh unless otherwise set in configuration. + +**`deletion_protection` does NOT prevent deletion outside of Terraform.** + +To disable deletion protection, explicitly set this field to `false` in configuration +and then run `terraform apply` to apply the change. + ### `liveness_probe` no longer defaults from API Cloud Run does not provide a default value for liveness probe. Now removing this field diff --git a/website/docs/r/cloud_run_v2_job.html.markdown b/website/docs/r/cloud_run_v2_job.html.markdown index aa21399c11..dce1d00673 100644 --- a/website/docs/r/cloud_run_v2_job.html.markdown +++ b/website/docs/r/cloud_run_v2_job.html.markdown @@ -40,6 +40,7 @@ To get more information about Job, see: resource "google_cloud_run_v2_job" "default" { name = "cloudrun-job" location = "us-central1" + deletion_protection = false template { template { @@ -62,6 +63,7 @@ resource "google_cloud_run_v2_job" "default" { resource "google_cloud_run_v2_job" "default" { name = "cloudrun-job" location = "us-central1" + deletion_protection = false template { template { @@ -96,7 +98,7 @@ resource "google_cloud_run_v2_job" "default" { resource "google_cloud_run_v2_job" "default" { name = "cloudrun-job" location = "us-central1" - + deletion_protection = false template { template{ volumes { @@ -176,6 +178,7 @@ resource "google_sql_database_instance" "instance" { resource "google_cloud_run_v2_job" "default" { name = "cloudrun-job" location = "us-central1" + deletion_protection = false template { template{ @@ -223,6 +226,7 @@ resource "google_compute_network" "custom_test" { resource "google_cloud_run_v2_job" "default" { name = "cloudrun-job" location = "us-central1" + deletion_protection = false launch_stage = "GA" template { template{ @@ -252,6 +256,7 @@ resource "google_cloud_run_v2_job" "default" { resource "google_cloud_run_v2_job" "default" { name = "cloudrun-job" location = "us-central1" + deletion_protection = false template { template { @@ -318,6 +323,7 @@ resource "google_cloud_run_v2_job" "default" { provider = google-beta name = "cloudrun-job" location = "us-central1" + deletion_protection = false launch_stage = "BETA" template { template { @@ -352,6 +358,7 @@ resource "google_cloud_run_v2_job" "default" { provider = google-beta name = "cloudrun-job" location = "us-central1" + deletion_protection = false start_execution_token = "start-once-created" template { template { @@ -750,6 +757,13 @@ 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. +* `deletion_protection` - (Optional) Whether Terraform will be prevented from destroying the job. Defaults to true. +When a`terraform destroy` or `terraform apply` would delete the job, +the command will fail if this field is not set to false in Terraform state. +When the field is set to true or unset in Terraform state, a `terraform apply` +or `terraform destroy` that would delete the job will fail. +When the field is set to false, deleting the job is allowed. + The `binary_authorization` block supports: diff --git a/website/docs/r/cloud_run_v2_service.html.markdown b/website/docs/r/cloud_run_v2_service.html.markdown index a4adaf2b27..2a04a16bf6 100644 --- a/website/docs/r/cloud_run_v2_service.html.markdown +++ b/website/docs/r/cloud_run_v2_service.html.markdown @@ -40,6 +40,7 @@ To get more information about Service, see: resource "google_cloud_run_v2_service" "default" { name = "cloudrun-service" location = "us-central1" + deletion_protection = false ingress = "INGRESS_TRAFFIC_ALL" template { @@ -61,6 +62,7 @@ resource "google_cloud_run_v2_service" "default" { resource "google_cloud_run_v2_service" "default" { name = "cloudrun-service" location = "us-central1" + deletion_protection = false ingress = "INGRESS_TRAFFIC_ALL" template { @@ -88,6 +90,7 @@ resource "google_cloud_run_v2_service" "default" { resource "google_cloud_run_v2_service" "default" { name = "cloudrun-service" location = "us-central1" + deletion_protection = false ingress = "INGRESS_TRAFFIC_ALL" template { @@ -177,6 +180,7 @@ resource "google_sql_database_instance" "instance" { resource "google_cloud_run_v2_service" "default" { name = "cloudrun-service" location = "us-central1" + deletion_protection = false template { containers { @@ -222,6 +226,7 @@ resource "google_compute_network" "custom_test" { resource "google_cloud_run_v2_service" "default" { name = "cloudrun-service" location = "us-central1" + deletion_protection = false launch_stage = "GA" template { containers { @@ -249,6 +254,7 @@ resource "google_cloud_run_v2_service" "default" { resource "google_cloud_run_v2_service" "default" { name = "cloudrun-service" location = "us-central1" + deletion_protection = false template { containers { @@ -283,6 +289,7 @@ resource "google_cloud_run_v2_service" "default" { resource "google_cloud_run_v2_service" "default" { name = "cloudrun-service" location = "us-central1" + deletion_protection = false ingress = "INGRESS_TRAFFIC_ALL" template { @@ -343,6 +350,7 @@ resource "google_cloud_run_v2_service" "default" { provider = google-beta name = "cloudrun-service" location = "us-central1" + deletion_protection = false launch_stage = "BETA" ingress = "INGRESS_TRAFFIC_ALL" template { @@ -394,6 +402,7 @@ resource "google_cloud_run_v2_service" "default" { name = "cloudrun-service" location = "us-central1" + deletion_protection = false launch_stage = "BETA" template { @@ -435,6 +444,7 @@ resource "google_cloud_run_v2_service" "default" { name = "cloudrun-service" location = "us-central1" + deletion_protection = false ingress = "INGRESS_TRAFFIC_ALL" launch_stage = "BETA" @@ -1080,6 +1090,13 @@ 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. +* `deletion_protection` - (Optional) Whether Terraform will be prevented from destroying the service. Defaults to true. +When a`terraform destroy` or `terraform apply` would delete the service, +the command will fail if this field is not set to false in Terraform state. +When the field is set to true or unset in Terraform state, a `terraform apply` +or `terraform destroy` that would delete the service will fail. +When the field is set to false, deleting the service is allowed. + The `binary_authorization` block supports: