From cea0e6de5528fa383e51bfc855715b50dae19b63 Mon Sep 17 00:00:00 2001 From: Julio Castillo Date: Fri, 2 Aug 2024 19:19:53 +0200 Subject: [PATCH] Add `force_destroy` field to `google_storage_managed_folder` (#11303) --- mmv1/products/storage/ManagedFolder.yaml | 20 ++++- .../storage_managed_folder.go.erb | 11 +++ .../storage_managed_folder_basic.tf.erb | 5 +- .../resource_storage_managed_folder_test.go | 73 +++++++++++++++++++ 4 files changed, 104 insertions(+), 5 deletions(-) create mode 100644 mmv1/templates/terraform/custom_update/storage_managed_folder.go.erb create mode 100644 mmv1/third_party/terraform/services/storage/resource_storage_managed_folder_test.go diff --git a/mmv1/products/storage/ManagedFolder.yaml b/mmv1/products/storage/ManagedFolder.yaml index 41bde5e0855e..94f33ac04c18 100644 --- a/mmv1/products/storage/ManagedFolder.yaml +++ b/mmv1/products/storage/ManagedFolder.yaml @@ -17,10 +17,9 @@ kind: 'storage#managedFolder' base_url: 'b/{{bucket}}/managedFolders' self_link: 'b/{{bucket}}/managedFolders/{{%name}}' id_format: '{{bucket}}/{{name}}' -delete_url: 'b/{{bucket}}/managedFolders/{{%name}}' +delete_url: 'b/{{bucket}}/managedFolders/{{%name}}?allowNonEmpty={{force_destroy}}' has_self_link: true -immutable: true -skip_sweeper: true # Skipping sweeper since this is a child resource. +skip_sweeper: true # Skipping sweeper since this is a child resource. description: | A Google Cloud Storage Managed Folder. @@ -41,12 +40,16 @@ references: !ruby/object:Api::Resource::ReferenceLinks import_format: - '{{bucket}}/managedFolders/{{%name}}' - '{{bucket}}/{{%name}}' +custom_code: !ruby/object:Provider::Terraform::CustomCode + custom_update: templates/terraform/custom_update/storage_managed_folder.go.erb examples: - !ruby/object:Provider::Terraform::Examples name: 'storage_managed_folder_basic' primary_resource_id: 'folder' vars: bucket_name: 'my-bucket' + ignore_read_extra: + - 'force_destroy' parameters: - !ruby/object:Api::Type::ResourceRef name: 'bucket' @@ -54,17 +57,28 @@ parameters: imports: 'name' description: 'The name of the bucket that contains the managed folder.' required: true + immutable: true - !ruby/object:Api::Type::String name: 'name' description: | The name of the managed folder expressed as a path. Must include trailing '/'. For example, `example_dir/example_dir2/`. required: true + immutable: true # The API returns values with trailing slashes, even if not # provided. Enforcing trailing slashes prevents diffs and ensures # consistent output. validation: !ruby/object:Provider::Terraform::Validation regex: '/$' +virtual_fields: + - !ruby/object:Api::Type::Boolean + name: 'force_destroy' + default_value: false + description: | + Allows the deletion of a managed folder even if contains + objects. If a non-empty managed folder is deleted, any objects + within the folder will remain in a simulated folder with the + same name. properties: - !ruby/object:Api::Type::String name: createTime diff --git a/mmv1/templates/terraform/custom_update/storage_managed_folder.go.erb b/mmv1/templates/terraform/custom_update/storage_managed_folder.go.erb new file mode 100644 index 000000000000..417b7b924566 --- /dev/null +++ b/mmv1/templates/terraform/custom_update/storage_managed_folder.go.erb @@ -0,0 +1,11 @@ +_ = config + +// we can only get here if force_destroy was updated +if d.Get("force_destroy") != nil { + if err := d.Set("force_destroy", d.Get("force_destroy")); err != nil { + return fmt.Errorf("Error updating force_destroy: %s", err) + } +} + +// all other fields are immutable, don't do anything else +return nil diff --git a/mmv1/templates/terraform/examples/storage_managed_folder_basic.tf.erb b/mmv1/templates/terraform/examples/storage_managed_folder_basic.tf.erb index 4f349c62e0ab..e48eb4393fb2 100644 --- a/mmv1/templates/terraform/examples/storage_managed_folder_basic.tf.erb +++ b/mmv1/templates/terraform/examples/storage_managed_folder_basic.tf.erb @@ -5,6 +5,7 @@ resource "google_storage_bucket" "bucket" { } resource "google_storage_managed_folder" "<%= ctx[:primary_resource_id] %>" { - bucket = google_storage_bucket.bucket.name - name = "managed/folder/name/" + bucket = google_storage_bucket.bucket.name + name = "managed/folder/name/" + force_destroy = true } diff --git a/mmv1/third_party/terraform/services/storage/resource_storage_managed_folder_test.go b/mmv1/third_party/terraform/services/storage/resource_storage_managed_folder_test.go new file mode 100644 index 000000000000..78e492309e5a --- /dev/null +++ b/mmv1/third_party/terraform/services/storage/resource_storage_managed_folder_test.go @@ -0,0 +1,73 @@ +package storage_test + +import ( + "fmt" + "regexp" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-provider-google/google/acctest" +) + +func TestAccStorageManagedFolder_storageManagedFolderUpdate(t *testing.T) { + t.Parallel() + bucketName := fmt.Sprintf("tf-test-managed-folder-%s", acctest.RandString(t, 10)) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccStorageManagedFolder_bucket(bucketName) + testAccStorageManagedFolder_managedFolder(false), + }, + { + ResourceName: "google_storage_managed_folder.folder", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"bucket", "force_destroy"}, + }, + { + Config: testAccStorageManagedFolder_bucket(bucketName), + ExpectError: regexp.MustCompile(`Error 409: The managed folder you tried to delete is not empty.`), + }, + { + Config: testAccStorageManagedFolder_bucket(bucketName) + testAccStorageManagedFolder_managedFolder(true), + }, + { + ResourceName: "google_storage_managed_folder.folder", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"bucket", "force_destroy"}, + }, + { + Config: testAccStorageManagedFolder_bucket(bucketName), + }, + }, + }) +} + +func testAccStorageManagedFolder_bucket(bucketName string) string { + return fmt.Sprintf(` +resource "google_storage_bucket" "bucket" { + name = "%s" + location = "EU" + uniform_bucket_level_access = true +} + +resource "google_storage_bucket_object" "object" { + name = "managed/folder/name/file.txt" + content = "This file will affect the folder being deleted if allowNonEmpty=false" + bucket = google_storage_bucket.bucket.name +} +`, bucketName) +} + +func testAccStorageManagedFolder_managedFolder(forceDestroy bool) string { + return fmt.Sprintf(` +resource "google_storage_managed_folder" "folder" { + bucket = google_storage_bucket.bucket.name + name = "managed/folder/name/" + force_destroy = %t +} +`, forceDestroy) +}