From b4f2becd0fa305ed366250c9cf59d2cc22c18c3a Mon Sep 17 00:00:00 2001 From: Tavasya Ganpati Date: Fri, 8 May 2026 14:30:10 -0500 Subject: [PATCH 01/11] Added identity and list implem --- .../list_google_storage_bucket.go.tmpl | 147 ++++++++++++++++++ .../storage/resource_storage_bucket.go.tmpl | 16 ++ 2 files changed, 163 insertions(+) create mode 100644 mmv1/third_party/terraform/services/storage/list_google_storage_bucket.go.tmpl diff --git a/mmv1/third_party/terraform/services/storage/list_google_storage_bucket.go.tmpl b/mmv1/third_party/terraform/services/storage/list_google_storage_bucket.go.tmpl new file mode 100644 index 000000000000..b09bc27fac2b --- /dev/null +++ b/mmv1/third_party/terraform/services/storage/list_google_storage_bucket.go.tmpl @@ -0,0 +1,147 @@ +// Copyright (c) IBM Corp. 2014, 2026 +// SPDX-License-Identifier: MPL-2.0 + +package storage + +import ( + "context" + "errors" + "fmt" + + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/list" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "google.golang.org/api/storage/v1" + + "github.com/hashicorp/terraform-provider-google/google/registry" + "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" +) + +func init() { + registry.FrameworkListResource{ + Name: "google_storage_bucket", + ProductName: "storage", + Func: NewGoogleStorageBucketListResource, + }.Register() +} + + +type GoogleStorageBucketListResource struct { + tpgresource.ListResourceMetadata +} + +type GoogleStorageBucketListModel struct { + Project types.String `tfsdk:"project"` +} + +func NewGoogleStorageBucketListResource() list.ListResource { + listR := &GoogleStorageBucketListResource{} + listR.TypeName = "google_storage_bucket" + listR.SDKv2Resource = ResourceStorageBucket() + listR.ListConfigFields = []tpgresource.ListConfigField{ + {Name: "project", Kind: tpgresource.ListConfigKindString, Optional: true}, + } + return listR +} + +func (listR *GoogleStorageBucketListResource) List(ctx context.Context, listReq list.ListRequest, stream *list.ListResultsStream) { + var data GoogleStorageBucketListModel + diags := listReq.Config.Get(ctx, &data) + if diags.HasError() { + stream.Results = list.ListResultsStreamDiagnostics(diags) + return + } + if listR.Client == nil { + diags = append(diags, diag.NewErrorDiagnostic( + "Provider not configured", + "The Google provider client is not available; ensure the provider is configured (e.g. credentials and default project).", + )) + stream.Results = list.ListResultsStreamDiagnostics(diags) + return + } + project := listR.GetProject(data.Project) + + stream.Results = func(push func(list.ListResult) bool) { + err := ListStorageBuckets(listR.Client, project, func(rd *schema.ResourceData) error { + result := listReq.NewListResult(ctx) + + if err := listR.SetResult(ctx, listReq.IncludeResource, &result, rd, "name"); err != nil { + return err + } + + if !push(result) { + return errors.New("stream closed") + } + return nil + }) + if err != nil { + diags.AddError("API Error", err.Error()) + result := listReq.NewListResult(ctx) + result.Diagnostics = diags + push(result) + } + } +} + +func flattenStorageBucketListItem(res map[string]interface{}, d *schema.ResourceData, config *transport_tpg.Config) error { + var bucket storage.Bucket + if err := tpgresource.Convert(res, &bucket); err != nil { + return fmt.Errorf("error converting storage bucket list response: %w", err) + } + if bucket.Name == "" { + return fmt.Errorf("missing name in storage bucket list response") + } + if err := d.Set("name", bucket.Name); err != nil { + return err + } + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + return setStorageBucket(d, config, &bucket, bucket.Name, userAgent) +} + +func ListStorageBuckets(config *transport_tpg.Config, project string, callback func(rd *schema.ResourceData) error) error { + if config == nil { + return fmt.Errorf("provider client is not configured") + } + d := ResourceStorageBucket().Data(&terraform.InstanceState{}) + + if project != "" { + if err := d.Set("project", project); err != nil { + return fmt.Errorf("error setting project on temporary resource data: %w", err) + } + } + url, err := tpgresource.ReplaceVars(d, config, "{{"{{"}}StorageBasePath{{"}}"}}b?project={{"{{"}}project{{"}}"}}") + if err != nil { + return err + } + + billingProject := "" + if bp, err := tpgresource.GetBillingProject(d, config); err == nil { + billingProject = bp + } + + userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent) + if err != nil { + return err + } + + return transport_tpg.ListPages(transport_tpg.ListPagesOptions{ + Config: config, + TempData: d, + ListURL: url, + BillingProject: billingProject, + UserAgent: userAgent, + ItemName: "items", + Flattener: flattenStorageBucketListItem, + Callback: callback, + }) +} + + + diff --git a/mmv1/third_party/terraform/services/storage/resource_storage_bucket.go.tmpl b/mmv1/third_party/terraform/services/storage/resource_storage_bucket.go.tmpl index 07df37a4688a..47b9aaf2d736 100644 --- a/mmv1/third_party/terraform/services/storage/resource_storage_bucket.go.tmpl +++ b/mmv1/third_party/terraform/services/storage/resource_storage_bucket.go.tmpl @@ -67,6 +67,22 @@ func ResourceStorageBucket() *schema.Resource { tpgresource.DefaultProviderDeletionPolicy("DELETE"), ), + Identity: &schema.ResourceIdentity{ + Version: 1, + SchemaFunc: func() map[string]*schema.Schema { + return map[string]*schema.Schema{ + "project": { + Type: schema.TypeString, + OptionalForImport: true, + }, + "name": { + Type: schema.TypeString, + RequiredForImport: true, + }, + } + }, + }, + Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(10 * time.Minute), Update: schema.DefaultTimeout(4 * time.Minute), From f1359aecad3aae72c4ff47198025af28ff1f4f6c Mon Sep 17 00:00:00 2001 From: Tavasya Ganpati Date: Fri, 8 May 2026 14:32:18 -0500 Subject: [PATCH 02/11] resource fix --- .../services/storage/resource_storage_bucket.go.tmpl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mmv1/third_party/terraform/services/storage/resource_storage_bucket.go.tmpl b/mmv1/third_party/terraform/services/storage/resource_storage_bucket.go.tmpl index 47b9aaf2d736..73c53308b01b 100644 --- a/mmv1/third_party/terraform/services/storage/resource_storage_bucket.go.tmpl +++ b/mmv1/third_party/terraform/services/storage/resource_storage_bucket.go.tmpl @@ -2545,7 +2545,11 @@ func setStorageBucket(d *schema.ResourceData, config *transport_tpg.Config, res d.SetId(res.Id) - return nil + + return tpgresource.SetResourceIdentityAttributes(d, map[string]interface{}{ + "name": res.Name, + "project": d.Get("project").(string), +}) } func hierachicalNamespaceDiffSuppress(k, old, new string, r *schema.ResourceData) bool { From 65e693ac04e6f0e6bfe012fe5a5772721c0400f9 Mon Sep 17 00:00:00 2001 From: Tavasya Ganpati Date: Sun, 10 May 2026 18:48:22 -0500 Subject: [PATCH 03/11] ListPages fix --- .../list_google_storage_bucket.go.tmpl | 77 ++++++++++++++++--- .../list_google_storage_bucket_test.go | 76 ++++++++++++++++++ 2 files changed, 142 insertions(+), 11 deletions(-) create mode 100644 mmv1/third_party/terraform/services/storage/list_google_storage_bucket_test.go diff --git a/mmv1/third_party/terraform/services/storage/list_google_storage_bucket.go.tmpl b/mmv1/third_party/terraform/services/storage/list_google_storage_bucket.go.tmpl index b09bc27fac2b..cdcbf47fedd6 100644 --- a/mmv1/third_party/terraform/services/storage/list_google_storage_bucket.go.tmpl +++ b/mmv1/third_party/terraform/services/storage/list_google_storage_bucket.go.tmpl @@ -7,6 +7,7 @@ import ( "context" "errors" "fmt" + "net/http" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/list" @@ -21,6 +22,8 @@ import ( transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" ) +var errStorageBucketListStreamClosed = errors.New("stream closed") + func init() { registry.FrameworkListResource{ Name: "google_storage_bucket", @@ -74,11 +77,14 @@ func (listR *GoogleStorageBucketListResource) List(ctx context.Context, listReq } if !push(result) { - return errors.New("stream closed") + return errStorageBucketListStreamClosed } return nil }) if err != nil { + if errors.Is(err, errStorageBucketListStreamClosed) { + return + } diags.AddError("API Error", err.Error()) result := listReq.NewListResult(ctx) result.Diagnostics = diags @@ -131,16 +137,65 @@ func ListStorageBuckets(config *transport_tpg.Config, project string, callback f return err } - return transport_tpg.ListPages(transport_tpg.ListPagesOptions{ - Config: config, - TempData: d, - ListURL: url, - BillingProject: billingProject, - UserAgent: userAgent, - ItemName: "items", - Flattener: flattenStorageBucketListItem, - Callback: callback, - }) + params := map[string]string{} + for { + listURL, err := transport_tpg.AddQueryParams(url, params) + if err != nil { + return err + } + + res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: listURL, + UserAgent: userAgent, + Headers: make(http.Header), + ErrorRetryPredicates: []transport_tpg.RetryErrorPredicateFunc{ + transport_tpg.Is429RetryableQuotaError, + }, + }) + if err != nil { + return transport_tpg.HandleListGoogleApiError(err, listURL) + } + + items, ok := res["items"].([]interface{}) + if ok { + for _, item := range items { + itemMap, ok := item.(map[string]interface{}) + if !ok { + return fmt.Errorf("expected item to be map[string]interface{}, got %T", item) + } + + itemData := ResourceStorageBucket().Data(&terraform.InstanceState{}) + if project != "" { + if err := itemData.Set("project", project); err != nil { + return fmt.Errorf("error setting project on temporary resource data: %w", err) + } + } + + if err := flattenStorageBucketListItem(itemMap, itemData, config); err != nil { + return fmt.Errorf("error flattening storage bucket: %s", err) + } + if project != "" { + if err := itemData.Set("project", project); err != nil { + return fmt.Errorf("error setting project on storage bucket list item: %w", err) + } + } + if err := callback(itemData); err != nil { + return err + } + } + } + + nextPageToken, ok := res["nextPageToken"] + if !ok { + break + } + params["pageToken"] = nextPageToken.(string) + } + + return nil } diff --git a/mmv1/third_party/terraform/services/storage/list_google_storage_bucket_test.go b/mmv1/third_party/terraform/services/storage/list_google_storage_bucket_test.go new file mode 100644 index 000000000000..a8d681dd2c21 --- /dev/null +++ b/mmv1/third_party/terraform/services/storage/list_google_storage_bucket_test.go @@ -0,0 +1,76 @@ +// Copyright (c) IBM Corp. 2014, 2026 +// SPDX-License-Identifier: MPL-2.0 + +package storage_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/knownvalue" + "github.com/hashicorp/terraform-plugin-testing/querycheck" + "github.com/hashicorp/terraform-plugin-testing/tfversion" + + "github.com/hashicorp/terraform-provider-google/google/acctest" + "github.com/hashicorp/terraform-provider-google/google/envvar" +) + +func TestAccStorageBucketListResource_queryIdentity(t *testing.T) { + t.Parallel() + + project := envvar.GetTestProjectFromEnv() + bucketName := "tf-test-" + acctest.RandString(t, 10) + + acctest.VcrTest(t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_14_0), + }, + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccStorageBucketBasic(bucketName, project), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("google_storage_bucket.test", "project", project), + resource.TestCheckResourceAttr("google_storage_bucket.test", "name", bucketName), + ), + }, + { + Query: true, + Config: testAccStorageBucketListQuery(project), + QueryResultChecks: []querycheck.QueryResultCheck{ + querycheck.ExpectIdentity("google_storage_bucket.all_in_project", map[string]knownvalue.Check{ + "name": knownvalue.StringExact(bucketName), + "project": knownvalue.StringExact(project), + }), + querycheck.ExpectLengthAtLeast("google_storage_bucket.all_in_project", 1), + }, + }, + }, + }) +} + +func testAccStorageBucketBasic(name, project string) string { + return fmt.Sprintf(` +resource "google_storage_bucket" "test" { + name = %q + location = "US" + project = %q +} +`, name, project) +} + +func testAccStorageBucketListQuery(project string) string { + return fmt.Sprintf(` +provider "google" {} + +list "google_storage_bucket" "all_in_project" { + provider = google + + config { + project = %q + } +} +`, project) +} From f7956e10840e9012ecb0a9a3edd095563c564e73 Mon Sep 17 00:00:00 2001 From: Tavasya Ganpati Date: Sun, 10 May 2026 18:55:33 -0500 Subject: [PATCH 04/11] Add docs --- .../google_storage_bucket.html.markdown | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 mmv1/third_party/terraform/website/docs/list-resources/google_storage_bucket.html.markdown diff --git a/mmv1/third_party/terraform/website/docs/list-resources/google_storage_bucket.html.markdown b/mmv1/third_party/terraform/website/docs/list-resources/google_storage_bucket.html.markdown new file mode 100644 index 000000000000..28430752433c --- /dev/null +++ b/mmv1/third_party/terraform/website/docs/list-resources/google_storage_bucket.html.markdown @@ -0,0 +1,50 @@ +--- +subcategory: "Cloud Storage" +description: |- + List Google Cloud Storage buckets in a project for use with terraform query + and .tfquery.hcl files. +--- + +# google_storage_bucket (list) + +Lists Google Cloud Storage **buckets** in a project for use with +[`terraform query`](https://developer.hashicorp.com/terraform/cli/commands/query) and +**`.tfquery.hcl`** files. Results correspond to existing +[`google_storage_bucket`](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/storage_bucket) +managed resources. + +For how list resources work in this provider, file layout, Terraform version requirements, and +shared `list` block arguments, refer to the guide +[Use list resources with terraform query (Google Cloud provider)](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/using_list_resources_with_terraform_query). + +## Example + +```hcl +list "google_storage_bucket" "all" { + provider = google + + config { + # Optional. Defaults to the provider project when omitted. + # project = "other-project" + } +} +``` + +Run `terraform query` from the directory that contains the `.tfquery.hcl` file. + +## Configuration (`config` block) + +* `project` - (Optional) Project ID to list buckets from. If unset, the provider's configured + default project is used, matching the managed resource behavior. + +## Results + +By default each result includes **resource identity** for `google_storage_bucket` (see +[Resource identity](https://developer.hashicorp.com/terraform/language/resources/identities)): + +* `name` - Bucket name. +* `project` - Project ID. + +With `include_resource = true` on the `list` block, results also include the full resource-style +attributes documented for the managed +[`google_storage_bucket` resource](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/storage_bucket#attributes-reference). From c7ea6d2ef67caf87c0d475e3c690aa2e0b30f395 Mon Sep 17 00:00:00 2001 From: Tavasya Ganpati Date: Sun, 10 May 2026 19:07:26 -0500 Subject: [PATCH 05/11] Add test for include resources=true --- .../list_google_storage_bucket_test.go | 33 ++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/mmv1/third_party/terraform/services/storage/list_google_storage_bucket_test.go b/mmv1/third_party/terraform/services/storage/list_google_storage_bucket_test.go index a8d681dd2c21..486fca58433b 100644 --- a/mmv1/third_party/terraform/services/storage/list_google_storage_bucket_test.go +++ b/mmv1/third_party/terraform/services/storage/list_google_storage_bucket_test.go @@ -10,6 +10,8 @@ import ( "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/knownvalue" "github.com/hashicorp/terraform-plugin-testing/querycheck" + "github.com/hashicorp/terraform-plugin-testing/querycheck/queryfilter" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" "github.com/hashicorp/terraform-plugin-testing/tfversion" "github.com/hashicorp/terraform-provider-google/google/acctest" @@ -38,13 +40,31 @@ func TestAccStorageBucketListResource_queryIdentity(t *testing.T) { }, { Query: true, - Config: testAccStorageBucketListQuery(project), + Config: testAccStorageBucketListQuery(project, true), QueryResultChecks: []querycheck.QueryResultCheck{ querycheck.ExpectIdentity("google_storage_bucket.all_in_project", map[string]knownvalue.Check{ "name": knownvalue.StringExact(bucketName), "project": knownvalue.StringExact(project), }), querycheck.ExpectLengthAtLeast("google_storage_bucket.all_in_project", 1), + querycheck.ExpectResourceKnownValues( + "google_storage_bucket.all_in_project", + queryfilter.ByDisplayName(knownvalue.StringExact(bucketName)), + []querycheck.KnownValueCheck{ + { + Path: tfjsonpath.New("name"), + KnownValue: knownvalue.StringExact(bucketName), + }, + { + Path: tfjsonpath.New("project"), + KnownValue: knownvalue.StringExact(project), + }, + { + Path: tfjsonpath.New("location"), + KnownValue: knownvalue.StringExact("US"), + }, + }, + ), }, }, }, @@ -61,16 +81,21 @@ resource "google_storage_bucket" "test" { `, name, project) } -func testAccStorageBucketListQuery(project string) string { +func testAccStorageBucketListQuery(project string, includeResource bool) string { + includeResourceBlock := "" + if includeResource { + includeResourceBlock = "\n include_resource = true" + } + return fmt.Sprintf(` provider "google" {} list "google_storage_bucket" "all_in_project" { - provider = google + provider = google%s config { project = %q } } -`, project) +`, includeResourceBlock, project) } From 8dca29fd49298def71dfc36c6fb35986682879fd Mon Sep 17 00:00:00 2001 From: Tavasya Ganpati Date: Mon, 11 May 2026 02:00:19 -0500 Subject: [PATCH 06/11] Add bucket limit for vcr test --- .../services/storage/list_google_storage_bucket_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/mmv1/third_party/terraform/services/storage/list_google_storage_bucket_test.go b/mmv1/third_party/terraform/services/storage/list_google_storage_bucket_test.go index 486fca58433b..5a908dcc5247 100644 --- a/mmv1/third_party/terraform/services/storage/list_google_storage_bucket_test.go +++ b/mmv1/third_party/terraform/services/storage/list_google_storage_bucket_test.go @@ -92,6 +92,7 @@ provider "google" {} list "google_storage_bucket" "all_in_project" { provider = google%s + limit = 1000 config { project = %q From 5a501aa353209bf2ea217693c5dade7c33dd097a Mon Sep 17 00:00:00 2001 From: Tavasya Ganpati Date: Tue, 12 May 2026 19:35:14 -0500 Subject: [PATCH 07/11] Add identity test and fix docs --- .../list_google_storage_bucket.go.tmpl | 4 +- .../storage/resource_storage_bucket.go.tmpl | 47 +++++++++++++++++-- .../storage/resource_storage_bucket_test.go | 33 +++++++++++++ .../google_storage_bucket.html.markdown | 4 +- .../docs/r/storage_bucket.html.markdown | 12 +++++ 5 files changed, 93 insertions(+), 7 deletions(-) diff --git a/mmv1/third_party/terraform/services/storage/list_google_storage_bucket.go.tmpl b/mmv1/third_party/terraform/services/storage/list_google_storage_bucket.go.tmpl index cdcbf47fedd6..06e89588601f 100644 --- a/mmv1/third_party/terraform/services/storage/list_google_storage_bucket.go.tmpl +++ b/mmv1/third_party/terraform/services/storage/list_google_storage_bucket.go.tmpl @@ -22,8 +22,6 @@ import ( transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" ) -var errStorageBucketListStreamClosed = errors.New("stream closed") - func init() { registry.FrameworkListResource{ Name: "google_storage_bucket", @@ -52,6 +50,8 @@ func NewGoogleStorageBucketListResource() list.ListResource { } func (listR *GoogleStorageBucketListResource) List(ctx context.Context, listReq list.ListRequest, stream *list.ListResultsStream) { + errStorageBucketListStreamClosed := errors.New("stream closed") + var data GoogleStorageBucketListModel diags := listReq.Config.Get(ctx, &data) if diags.HasError() { diff --git a/mmv1/third_party/terraform/services/storage/resource_storage_bucket.go.tmpl b/mmv1/third_party/terraform/services/storage/resource_storage_bucket.go.tmpl index 73c53308b01b..29c5e70063ec 100644 --- a/mmv1/third_party/terraform/services/storage/resource_storage_bucket.go.tmpl +++ b/mmv1/third_party/terraform/services/storage/resource_storage_bucket.go.tmpl @@ -1381,6 +1381,35 @@ func resourceStorageBucketDelete(d *schema.ResourceData, meta interface{}) error } func resourceStorageBucketStateImporter(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + if d.Id() == "" { + identity, err := d.Identity() + if err != nil { + return nil, fmt.Errorf("Error reading import identity: %s", err) + } + if identity == nil { + return nil, fmt.Errorf("import requires bucket name") + } + + nameValue, ok := identity.GetOk("name") + if !ok || nameValue.(string) == "" { + return nil, fmt.Errorf("import requires bucket name") + } + + name := nameValue.(string) + if err := d.Set("name", name); err != nil { + return nil, fmt.Errorf("Error setting name: %s", err) + } + + if projectValue, ok := identity.GetOk("project"); ok && projectValue.(string) != "" { + if err := d.Set("project", projectValue.(string)); err != nil { + return nil, fmt.Errorf("Error setting project: %s", err) + } + d.SetId(fmt.Sprintf("%s/%s", projectValue.(string), name)) + } else { + d.SetId(name) + } + } + // We need to support project/bucket_name and bucket_name formats. This will allow // importing a bucket that is in a different project than the provider default. // ParseImportID can't be used because having no project will cause an error but it @@ -2475,12 +2504,24 @@ func setStorageBucket(d *schema.ResourceData, config *transport_tpg.Config, res if err := tpgresource.SetLabels(res.Labels, d, "labels"); err != nil { return fmt.Errorf("Error setting labels: %s", err) } - if err := tpgresource.SetLabels(res.Labels, d, "terraform_labels"); err != nil { - return fmt.Errorf("Error setting terraform_labels: %s", err) - } if err := d.Set("effective_labels", res.Labels); err != nil { return fmt.Errorf("Error setting labels: %s", err) } + terraformLabels := make(map[string]string) + for key, value := range config.DefaultLabels { + terraformLabels[key] = value + } + if config.AddTerraformAttributionLabel { + if _, ok := res.Labels[transport_tpg.AttributionKey]; ok { + terraformLabels[transport_tpg.AttributionKey] = transport_tpg.AttributionValue + } + } + for key, value := range d.Get("labels").(map[string]interface{}) { + terraformLabels[key] = value.(string) + } + if err := d.Set("terraform_labels", terraformLabels); err != nil { + return fmt.Errorf("Error setting terraform_labels: %s", err) + } if err := d.Set("website", flattenBucketWebsite(res.Website)); err != nil { return fmt.Errorf("Error setting website: %s", err) } diff --git a/mmv1/third_party/terraform/services/storage/resource_storage_bucket_test.go b/mmv1/third_party/terraform/services/storage/resource_storage_bucket_test.go index dbacfc98a85d..4c10ca8cbf83 100644 --- a/mmv1/third_party/terraform/services/storage/resource_storage_bucket_test.go +++ b/mmv1/third_party/terraform/services/storage/resource_storage_bucket_test.go @@ -13,6 +13,7 @@ import ( "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-plugin-testing/tfversion" "github.com/hashicorp/terraform-provider-google/google/acctest" "github.com/hashicorp/terraform-provider-google/google/envvar" @@ -67,6 +68,38 @@ func TestAccStorageBucket_basic(t *testing.T) { }) } +func TestAccStorageBucket_importBlockWithResourceIdentity(t *testing.T) { + t.Parallel() + + bucketName := acctest.TestBucketName(t) + project := envvar.GetTestProjectFromEnv() + + acctest.VcrTest(t, resource.TestCase{ + TerraformVersionChecks: []tfversion.TerraformVersionCheck{ + tfversion.SkipBelow(tfversion.Version1_12_0), + }, + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccStorageBucketDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccStorageBucket_basic(bucketName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "google_storage_bucket.bucket", "project", project), + resource.TestCheckResourceAttr( + "google_storage_bucket.bucket", "name", bucketName), + ), + }, + { + ResourceName: "google_storage_bucket.bucket", + ImportState: true, + ImportStateKind: resource.ImportBlockWithResourceIdentity, + }, + }, + }) +} + func TestAccStorageBucket_basicWithAutoclass(t *testing.T) { t.Parallel() diff --git a/mmv1/third_party/terraform/website/docs/list-resources/google_storage_bucket.html.markdown b/mmv1/third_party/terraform/website/docs/list-resources/google_storage_bucket.html.markdown index 28430752433c..45a55906e5b2 100644 --- a/mmv1/third_party/terraform/website/docs/list-resources/google_storage_bucket.html.markdown +++ b/mmv1/third_party/terraform/website/docs/list-resources/google_storage_bucket.html.markdown @@ -40,11 +40,11 @@ Run `terraform query` from the directory that contains the `.tfquery.hcl` file. ## Results By default each result includes **resource identity** for `google_storage_bucket` (see -[Resource identity](https://developer.hashicorp.com/terraform/language/resources/identities)): +[Resource identity](https://developer.hashicorp.com/terraform/language/block/import#identity)): * `name` - Bucket name. * `project` - Project ID. With `include_resource = true` on the `list` block, results also include the full resource-style attributes documented for the managed -[`google_storage_bucket` resource](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/storage_bucket#attributes-reference). +[`google_storage_bucket` resource](https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/storage_bucket#attributes-reference). \ No newline at end of file diff --git a/mmv1/third_party/terraform/website/docs/r/storage_bucket.html.markdown b/mmv1/third_party/terraform/website/docs/r/storage_bucket.html.markdown index b1fab6bc9651..43f9fce19819 100644 --- a/mmv1/third_party/terraform/website/docs/r/storage_bucket.html.markdown +++ b/mmv1/third_party/terraform/website/docs/r/storage_bucket.html.markdown @@ -453,6 +453,18 @@ import { } ``` +In Terraform v1.12.0 and later, use an [`identity` block](https://developer.hashicorp.com/terraform/language/block/import#identity) to import Storage buckets using identity values. For example: + +```tf +import { + identity = { + project = "{{project_id}}" + name = "{{bucket}}" + } + to = google_storage_bucket.default +} +``` + When using the [`terraform import` command](https://developer.hashicorp.com/terraform/cli/commands/import), Storage buckets can be imported using one of the formats above. For example: ``` From b26270141e7b4de7a9f5df1c349853b5e9478081 Mon Sep 17 00:00:00 2001 From: Tavasya Ganpati Date: Tue, 12 May 2026 19:42:13 -0500 Subject: [PATCH 08/11] Fix list test --- .../services/storage/list_google_storage_bucket_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mmv1/third_party/terraform/services/storage/list_google_storage_bucket_test.go b/mmv1/third_party/terraform/services/storage/list_google_storage_bucket_test.go index 5a908dcc5247..dcdca0c6a387 100644 --- a/mmv1/third_party/terraform/services/storage/list_google_storage_bucket_test.go +++ b/mmv1/third_party/terraform/services/storage/list_google_storage_bucket_test.go @@ -84,14 +84,15 @@ resource "google_storage_bucket" "test" { func testAccStorageBucketListQuery(project string, includeResource bool) string { includeResourceBlock := "" if includeResource { - includeResourceBlock = "\n include_resource = true" + includeResourceBlock = " include_resource = true" } return fmt.Sprintf(` provider "google" {} list "google_storage_bucket" "all_in_project" { - provider = google%s + provider = google +%s limit = 1000 config { From 739c9bbaf03f69f2082385ae67de7db659ddf245 Mon Sep 17 00:00:00 2001 From: Tavasya Ganpati Date: Tue, 19 May 2026 14:59:31 -0500 Subject: [PATCH 09/11] Add listPages --- .../list_google_storage_bucket.go.tmpl | 74 +++---------------- 1 file changed, 12 insertions(+), 62 deletions(-) diff --git a/mmv1/third_party/terraform/services/storage/list_google_storage_bucket.go.tmpl b/mmv1/third_party/terraform/services/storage/list_google_storage_bucket.go.tmpl index 06e89588601f..138e158bad10 100644 --- a/mmv1/third_party/terraform/services/storage/list_google_storage_bucket.go.tmpl +++ b/mmv1/third_party/terraform/services/storage/list_google_storage_bucket.go.tmpl @@ -7,7 +7,6 @@ import ( "context" "errors" "fmt" - "net/http" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/list" @@ -50,8 +49,8 @@ func NewGoogleStorageBucketListResource() list.ListResource { } func (listR *GoogleStorageBucketListResource) List(ctx context.Context, listReq list.ListRequest, stream *list.ListResultsStream) { - errStorageBucketListStreamClosed := errors.New("stream closed") - + errStorageBucketListStreamClosed := errors.New("stream closed") + var data GoogleStorageBucketListModel diags := listReq.Config.Get(ctx, &data) if diags.HasError() { @@ -137,65 +136,16 @@ func ListStorageBuckets(config *transport_tpg.Config, project string, callback f return err } - params := map[string]string{} - for { - listURL, err := transport_tpg.AddQueryParams(url, params) - if err != nil { - return err - } - - res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ - Config: config, - Method: "GET", - Project: billingProject, - RawURL: listURL, - UserAgent: userAgent, - Headers: make(http.Header), - ErrorRetryPredicates: []transport_tpg.RetryErrorPredicateFunc{ - transport_tpg.Is429RetryableQuotaError, - }, - }) - if err != nil { - return transport_tpg.HandleListGoogleApiError(err, listURL) - } - - items, ok := res["items"].([]interface{}) - if ok { - for _, item := range items { - itemMap, ok := item.(map[string]interface{}) - if !ok { - return fmt.Errorf("expected item to be map[string]interface{}, got %T", item) - } - - itemData := ResourceStorageBucket().Data(&terraform.InstanceState{}) - if project != "" { - if err := itemData.Set("project", project); err != nil { - return fmt.Errorf("error setting project on temporary resource data: %w", err) - } - } - - if err := flattenStorageBucketListItem(itemMap, itemData, config); err != nil { - return fmt.Errorf("error flattening storage bucket: %s", err) - } - if project != "" { - if err := itemData.Set("project", project); err != nil { - return fmt.Errorf("error setting project on storage bucket list item: %w", err) - } - } - if err := callback(itemData); err != nil { - return err - } - } - } - - nextPageToken, ok := res["nextPageToken"] - if !ok { - break - } - params["pageToken"] = nextPageToken.(string) - } - - return nil + return transport_tpg.ListPages(transport_tpg.ListPagesOptions{ + Config: config, + TempData: d, + Resource: ResourceStorageBucket(), + ListURL: url, + BillingProject: billingProject, + UserAgent: userAgent, + Flattener: flattenStorageBucketListItem, + Callback: callback, + }) } From 12bd3eef3de00e1d7aa4c2d3623f442f75afd7d9 Mon Sep 17 00:00:00 2001 From: Tavasya Ganpati Date: Wed, 20 May 2026 12:35:00 -0500 Subject: [PATCH 10/11] Ignore labels --- .../storage/resource_storage_bucket.go.tmpl | 14 +------------- .../storage/resource_storage_bucket_test.go | 7 ++++--- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/mmv1/third_party/terraform/services/storage/resource_storage_bucket.go.tmpl b/mmv1/third_party/terraform/services/storage/resource_storage_bucket.go.tmpl index 29c5e70063ec..5834b154cc3b 100644 --- a/mmv1/third_party/terraform/services/storage/resource_storage_bucket.go.tmpl +++ b/mmv1/third_party/terraform/services/storage/resource_storage_bucket.go.tmpl @@ -2507,19 +2507,7 @@ func setStorageBucket(d *schema.ResourceData, config *transport_tpg.Config, res if err := d.Set("effective_labels", res.Labels); err != nil { return fmt.Errorf("Error setting labels: %s", err) } - terraformLabels := make(map[string]string) - for key, value := range config.DefaultLabels { - terraformLabels[key] = value - } - if config.AddTerraformAttributionLabel { - if _, ok := res.Labels[transport_tpg.AttributionKey]; ok { - terraformLabels[transport_tpg.AttributionKey] = transport_tpg.AttributionValue - } - } - for key, value := range d.Get("labels").(map[string]interface{}) { - terraformLabels[key] = value.(string) - } - if err := d.Set("terraform_labels", terraformLabels); err != nil { + if err := tpgresource.SetLabels(res.Labels, d, "terraform_labels"); err != nil { return fmt.Errorf("Error setting terraform_labels: %s", err) } if err := d.Set("website", flattenBucketWebsite(res.Website)); err != nil { diff --git a/mmv1/third_party/terraform/services/storage/resource_storage_bucket_test.go b/mmv1/third_party/terraform/services/storage/resource_storage_bucket_test.go index 4c10ca8cbf83..0406baafede3 100644 --- a/mmv1/third_party/terraform/services/storage/resource_storage_bucket_test.go +++ b/mmv1/third_party/terraform/services/storage/resource_storage_bucket_test.go @@ -92,9 +92,10 @@ func TestAccStorageBucket_importBlockWithResourceIdentity(t *testing.T) { ), }, { - ResourceName: "google_storage_bucket.bucket", - ImportState: true, - ImportStateKind: resource.ImportBlockWithResourceIdentity, + ResourceName: "google_storage_bucket.bucket", + ImportState: true, + ImportStateKind: resource.ImportBlockWithResourceIdentity, + ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, }, }, }) From fe3085b6ccb739457370c93a450ef71d3d2a12ec Mon Sep 17 00:00:00 2001 From: Tavasya Ganpati Date: Wed, 20 May 2026 14:19:19 -0500 Subject: [PATCH 11/11] Fix vcr test --- .../services/storage/resource_storage_bucket_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mmv1/third_party/terraform/services/storage/resource_storage_bucket_test.go b/mmv1/third_party/terraform/services/storage/resource_storage_bucket_test.go index 0406baafede3..77ca9a934f76 100644 --- a/mmv1/third_party/terraform/services/storage/resource_storage_bucket_test.go +++ b/mmv1/third_party/terraform/services/storage/resource_storage_bucket_test.go @@ -92,10 +92,10 @@ func TestAccStorageBucket_importBlockWithResourceIdentity(t *testing.T) { ), }, { - ResourceName: "google_storage_bucket.bucket", - ImportState: true, - ImportStateKind: resource.ImportBlockWithResourceIdentity, - ImportStateVerifyIgnore: []string{"labels", "terraform_labels"}, + ResourceName: "google_storage_bucket.bucket", + RefreshState: true, + ExpectNonEmptyPlan: true, + ImportStateKind: resource.ImportBlockWithResourceIdentity, }, }, })