Skip to content

Commit 0633131

Browse files
Added custom_placement_config field in google_storage_bucket resource (#6619) (#12723)
Signed-off-by: Modular Magician <[email protected]> Signed-off-by: Modular Magician <[email protected]>
1 parent b4a37c5 commit 0633131

File tree

4 files changed

+109
-0
lines changed

4 files changed

+109
-0
lines changed

.changelog/6619.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
storage: added `custom_placement_config` field to `google_storage_bucket` resource to support custom dual-region GCS buckets
3+
```

google/resource_storage_bucket.go

+64
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,27 @@ func resourceStorageBucket() *schema.Resource {
365365
Computed: true,
366366
Description: `Enables uniform bucket-level access on a bucket.`,
367367
},
368+
"custom_placement_config": {
369+
Type: schema.TypeList,
370+
Optional: true,
371+
MaxItems: 1,
372+
Elem: &schema.Resource{
373+
Schema: map[string]*schema.Schema{
374+
"data_locations": {
375+
Type: schema.TypeSet,
376+
Required: true,
377+
ForceNew: true,
378+
MaxItems: 2,
379+
MinItems: 2,
380+
Elem: &schema.Schema{
381+
Type: schema.TypeString,
382+
},
383+
Description: `The list of individual regions that comprise a dual-region bucket. See the docs for a list of acceptable regions. Note: If any of the data_locations changes, it will recreate the bucket.`,
384+
},
385+
},
386+
},
387+
Description: `The bucket's custom location configuration, which specifies the individual regions that comprise a dual-region bucket. If the bucket is designated a single or multi-region, the parameters are empty.`,
388+
},
368389
},
369390
UseJSONNumber: true,
370391
}
@@ -482,6 +503,10 @@ func resourceStorageBucketCreate(d *schema.ResourceData, meta interface{}) error
482503
}
483504
}
484505

506+
if v, ok := d.GetOk("custom_placement_config"); ok {
507+
sb.CustomPlacementConfig = expandBucketCustomPlacementConfig(v.([]interface{}))
508+
}
509+
485510
var res *storage.Bucket
486511

487512
err = retry(func() error {
@@ -894,6 +919,42 @@ func flattenBucketEncryption(enc *storage.BucketEncryption) []map[string]interfa
894919
return encryption
895920
}
896921

922+
func expandBucketCustomPlacementConfig(configured interface{}) *storage.BucketCustomPlacementConfig {
923+
cfcs := configured.([]interface{})
924+
if len(cfcs) == 0 || cfcs[0] == nil {
925+
return nil
926+
}
927+
cfc := cfcs[0].(map[string]interface{})
928+
bucketcfc := &storage.BucketCustomPlacementConfig{
929+
DataLocations: expandBucketDataLocations(cfc["data_locations"]),
930+
}
931+
return bucketcfc
932+
}
933+
934+
func flattenBucketCustomPlacementConfig(cfc *storage.BucketCustomPlacementConfig) []map[string]interface{} {
935+
customPlacementConfig := make([]map[string]interface{}, 0, 1)
936+
937+
if cfc == nil {
938+
return customPlacementConfig
939+
}
940+
941+
customPlacementConfig = append(customPlacementConfig, map[string]interface{}{
942+
"data_locations": cfc.DataLocations,
943+
})
944+
945+
return customPlacementConfig
946+
}
947+
948+
func expandBucketDataLocations(configured interface{}) []string {
949+
l := configured.(*schema.Set).List()
950+
951+
req := make([]string, 0, len(l))
952+
for _, raw := range l {
953+
req = append(req, raw.(string))
954+
}
955+
return req
956+
}
957+
897958
func expandBucketLogging(configured interface{}) *storage.BucketLogging {
898959
loggings := configured.([]interface{})
899960
if len(loggings) == 0 {
@@ -1430,6 +1491,9 @@ func setStorageBucket(d *schema.ResourceData, config *Config, res *storage.Bucke
14301491
if err := d.Set("retention_policy", flattenBucketRetentionPolicy(res.RetentionPolicy)); err != nil {
14311492
return fmt.Errorf("Error setting retention_policy: %s", err)
14321493
}
1494+
if err := d.Set("custom_placement_config", flattenBucketCustomPlacementConfig(res.CustomPlacementConfig)); err != nil {
1495+
return fmt.Errorf("Error setting custom_placement_config: %s", err)
1496+
}
14331497

14341498
if res.IamConfiguration != nil && res.IamConfiguration.UniformBucketLevelAccess != nil {
14351499
if err := d.Set("uniform_bucket_level_access", res.IamConfiguration.UniformBucketLevelAccess.Enabled); err != nil {

google/resource_storage_bucket_test.go

+36
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,29 @@ func TestAccStorageBucket_lowercaseLocation(t *testing.T) {
103103
})
104104
}
105105

106+
func TestAccStorageBucket_dualLocation(t *testing.T) {
107+
t.Parallel()
108+
109+
bucketName := testBucketName(t)
110+
111+
vcrTest(t, resource.TestCase{
112+
PreCheck: func() { testAccPreCheck(t) },
113+
Providers: testAccProviders,
114+
CheckDestroy: testAccStorageBucketDestroyProducer(t),
115+
Steps: []resource.TestStep{
116+
{
117+
Config: testAccStorageBucket_dualLocation(bucketName),
118+
},
119+
{
120+
ResourceName: "google_storage_bucket.bucket",
121+
ImportState: true,
122+
ImportStateVerify: true,
123+
ImportStateVerifyIgnore: []string{"force_destroy"},
124+
},
125+
},
126+
})
127+
}
128+
106129
func TestAccStorageBucket_customAttributes(t *testing.T) {
107130
t.Parallel()
108131

@@ -1287,6 +1310,19 @@ resource "google_storage_bucket" "bucket" {
12871310
`, bucketName)
12881311
}
12891312

1313+
func testAccStorageBucket_dualLocation(bucketName string) string {
1314+
return fmt.Sprintf(`
1315+
resource "google_storage_bucket" "bucket" {
1316+
name = "%s"
1317+
location = "ASIA"
1318+
force_destroy = true
1319+
custom_placement_config {
1320+
data_locations = ["ASIA-EAST1", "ASIA-SOUTHEAST1"]
1321+
}
1322+
}
1323+
`, bucketName)
1324+
}
1325+
12901326
func testAccStorageBucket_customAttributes(bucketName string) string {
12911327
return fmt.Sprintf(`
12921328
resource "google_storage_bucket" "bucket" {

website/docs/r/storage_bucket.html.markdown

+6
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,8 @@ The following arguments are supported:
101101

102102
* `uniform_bucket_level_access` - (Optional, Default: false) Enables [Uniform bucket-level access](https://cloud.google.com/storage/docs/uniform-bucket-level-access) access to a bucket.
103103

104+
* `custom_placement_config` - (Optional) The bucket's custom location configuration, which specifies the individual regions that comprise a dual-region bucket. If the bucket is designated a single or multi-region, the parameters are empty. Structure is [documented below](#nested_custom_placement_config).
105+
104106
<a name="nested_lifecycle_rule"></a>The `lifecycle_rule` block supports:
105107

106108
* `action` - (Required) The Lifecycle Rule's action configuration. A single block of this type is supported. Structure is [documented below](#nested_action).
@@ -189,6 +191,10 @@ The following arguments are supported:
189191
state of the project.
190192
You should take care for race conditions when the same Terraform manages IAM policy on the Cloud KMS crypto key. See the data source page for more details.
191193

194+
<a name="nested_custom_placement_config"></a>The `custom_placement_config` block supports:
195+
196+
* `data_locations` - (Required) The list of individual regions that comprise a dual-region bucket. See [Cloud Storage bucket locations](https://cloud.google.com/storage/docs/dual-regions#availability) for a list of acceptable regions. **Note**: If any of the data_locations changes, it will [recreate the bucket](https://cloud.google.com/storage/docs/locations#key-concepts).
197+
192198
## Attributes Reference
193199

194200
In addition to the arguments listed above, the following computed attributes are

0 commit comments

Comments
 (0)