Skip to content

Commit a95e84a

Browse files
Fix Adding Unexpected Conditions (#9547) (#16683)
* Fix Adding Unexpected Conditions * Adds no_age field * Modify no_age description and variables name. Adds relevant comments. * Fixes Build Failure * Fixes indent issues and removes unnecessary condition. * Modified condition to include case when no_age is not present in the file. [upstream:cc5606ed9072cb2cea144c1769d601d71bdc8ed1] Signed-off-by: Modular Magician <[email protected]>
1 parent 070e868 commit a95e84a

File tree

4 files changed

+162
-11
lines changed

4 files changed

+162
-11
lines changed

.changelog/9547.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:bug
2+
storage: fixed unexpected `lifecycle_rule` conditions being added for `google_storage_bucket`
3+
```

google/services/storage/resource_storage_bucket.go

+31-11
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,11 @@ func ResourceStorageBucket() *schema.Resource {
218218
Optional: true,
219219
Description: `Creation date of an object in RFC 3339 (e.g. 2017-06-13) to satisfy this condition.`,
220220
},
221+
"no_age": {
222+
Type: schema.TypeBool,
223+
Optional: true,
224+
Description: `While set true, age value will be omitted.Required to set true when age is unset in the config file.`,
225+
},
221226
"with_state": {
222227
Type: schema.TypeString,
223228
Computed: true,
@@ -1207,7 +1212,7 @@ func flattenBucketAutoclass(bucketAutoclass *storage.BucketAutoclass) []map[stri
12071212
return autoclassList
12081213
}
12091214

1210-
func flattenBucketLifecycle(lifecycle *storage.BucketLifecycle) []map[string]interface{} {
1215+
func flattenBucketLifecycle(d *schema.ResourceData, lifecycle *storage.BucketLifecycle) []map[string]interface{} {
12111216
if lifecycle == nil || lifecycle.Rule == nil {
12121217
return []map[string]interface{}{}
12131218
}
@@ -1217,7 +1222,7 @@ func flattenBucketLifecycle(lifecycle *storage.BucketLifecycle) []map[string]int
12171222
for _, rule := range lifecycle.Rule {
12181223
rules = append(rules, map[string]interface{}{
12191224
"action": schema.NewSet(resourceGCSBucketLifecycleRuleActionHash, []interface{}{flattenBucketLifecycleRuleAction(rule.Action)}),
1220-
"condition": schema.NewSet(resourceGCSBucketLifecycleRuleConditionHash, []interface{}{flattenBucketLifecycleRuleCondition(rule.Condition)}),
1225+
"condition": schema.NewSet(resourceGCSBucketLifecycleRuleConditionHash, []interface{}{flattenBucketLifecycleRuleCondition(d, rule.Condition)}),
12211226
})
12221227
}
12231228

@@ -1231,7 +1236,7 @@ func flattenBucketLifecycleRuleAction(action *storage.BucketLifecycleRuleAction)
12311236
}
12321237
}
12331238

1234-
func flattenBucketLifecycleRuleCondition(condition *storage.BucketLifecycleRuleCondition) map[string]interface{} {
1239+
func flattenBucketLifecycleRuleCondition(d *schema.ResourceData, condition *storage.BucketLifecycleRuleCondition) map[string]interface{} {
12351240
ruleCondition := map[string]interface{}{
12361241
"created_before": condition.CreatedBefore,
12371242
"matches_storage_class": tpgresource.ConvertStringArrToInterface(condition.MatchesStorageClass),
@@ -1255,6 +1260,12 @@ func flattenBucketLifecycleRuleCondition(condition *storage.BucketLifecycleRuleC
12551260
ruleCondition["with_state"] = "ARCHIVED"
12561261
}
12571262
}
1263+
// setting no_age value from state config since it is terraform only variable and not getting value from backend.
1264+
if v, ok := d.GetOk("lifecycle_rule.0.condition"); ok {
1265+
state_condition := v.(*schema.Set).List()[0].(map[string]interface{})
1266+
ruleCondition["no_age"] = state_condition["no_age"].(bool)
1267+
}
1268+
12581269
return ruleCondition
12591270
}
12601271

@@ -1402,11 +1413,14 @@ func expandStorageBucketLifecycleRuleCondition(v interface{}) (*storage.BucketLi
14021413

14031414
condition := conditions[0].(map[string]interface{})
14041415
transformed := &storage.BucketLifecycleRuleCondition{}
1405-
1406-
if v, ok := condition["age"]; ok {
1407-
age := int64(v.(int))
1408-
transformed.Age = &age
1409-
transformed.ForceSendFields = append(transformed.ForceSendFields, "Age")
1416+
// Setting high precedence of no_age over age when both used together.
1417+
// Only sets age value when no_age is not present or no_age is present and has false value
1418+
if v, ok := condition["no_age"]; !ok || !(v.(bool)) {
1419+
if v, ok := condition["age"]; ok {
1420+
age := int64(v.(int))
1421+
transformed.Age = &age
1422+
transformed.ForceSendFields = append(transformed.ForceSendFields, "Age")
1423+
}
14101424
}
14111425

14121426
if v, ok := condition["created_before"]; ok {
@@ -1507,8 +1521,12 @@ func resourceGCSBucketLifecycleRuleConditionHash(v interface{}) int {
15071521
var buf bytes.Buffer
15081522
m := v.(map[string]interface{})
15091523

1510-
if v, ok := m["age"]; ok {
1511-
buf.WriteString(fmt.Sprintf("%d-", v.(int)))
1524+
if v, ok := m["no_age"]; ok && v.(bool) {
1525+
buf.WriteString(fmt.Sprintf("%t-", v.(bool)))
1526+
} else {
1527+
if v, ok := m["age"]; ok {
1528+
buf.WriteString(fmt.Sprintf("%d-", v.(int)))
1529+
}
15121530
}
15131531

15141532
if v, ok := m["days_since_custom_time"]; ok {
@@ -1651,7 +1669,9 @@ func setStorageBucket(d *schema.ResourceData, config *transport_tpg.Config, res
16511669
if err := d.Set("autoclass", flattenBucketAutoclass(res.Autoclass)); err != nil {
16521670
return fmt.Errorf("Error setting autoclass: %s", err)
16531671
}
1654-
if err := d.Set("lifecycle_rule", flattenBucketLifecycle(res.Lifecycle)); err != nil {
1672+
// lifecycle_rule contains terraform only variable no_age.
1673+
// Passing config("d") to flattener function to set no_age separately.
1674+
if err := d.Set("lifecycle_rule", flattenBucketLifecycle(d, res.Lifecycle)); err != nil {
16551675
return fmt.Errorf("Error setting lifecycle_rule: %s", err)
16561676
}
16571677
if err := tpgresource.SetLabels(res.Labels, d, "labels"); err != nil {

google/services/storage/resource_storage_bucket_test.go

+126
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,74 @@ func TestAccStorageBucket_lifecycleRuleStateAny(t *testing.T) {
382382
})
383383
}
384384

385+
func TestAccStorageBucket_lifecycleRulesNoAge(t *testing.T) {
386+
t.Parallel()
387+
var bucket storage.Bucket
388+
bucketName := acctest.TestBucketName(t)
389+
390+
acctest.VcrTest(t, resource.TestCase{
391+
PreCheck: func() { acctest.AccTestPreCheck(t) },
392+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
393+
CheckDestroy: testAccStorageBucketDestroyProducer(t),
394+
Steps: []resource.TestStep{
395+
{
396+
Config: testAccStorageBucket_customAttributes_withLifecycle1(bucketName),
397+
Check: resource.ComposeTestCheckFunc(
398+
testAccCheckStorageBucketExists(
399+
t, "google_storage_bucket.bucket", bucketName, &bucket),
400+
),
401+
},
402+
{
403+
ResourceName: "google_storage_bucket.bucket",
404+
ImportState: true,
405+
ImportStateVerify: true,
406+
ImportStateVerifyIgnore: []string{"force_destroy"},
407+
},
408+
{
409+
Config: testAccStorageBucket_customAttributes_withLifecycleNoAge(bucketName),
410+
Check: resource.ComposeTestCheckFunc(
411+
testAccCheckStorageBucketExists(
412+
t, "google_storage_bucket.bucket", bucketName, &bucket),
413+
testAccCheckStorageBucketLifecycleConditionNoAge(nil, &bucket),
414+
),
415+
},
416+
{
417+
ResourceName: "google_storage_bucket.bucket",
418+
ImportState: true,
419+
ImportStateVerify: true,
420+
ImportStateVerifyIgnore: []string{"force_destroy", "lifecycle_rule.0.condition.0.no_age"},
421+
},
422+
{
423+
Config: testAccStorageBucket_customAttributes_withLifecycleNoAgeAndAge(bucketName),
424+
Check: resource.ComposeTestCheckFunc(
425+
testAccCheckStorageBucketExists(
426+
t, "google_storage_bucket.bucket", bucketName, &bucket),
427+
testAccCheckStorageBucketLifecycleConditionNoAge(nil, &bucket),
428+
),
429+
},
430+
{
431+
ResourceName: "google_storage_bucket.bucket",
432+
ImportState: true,
433+
ImportStateVerify: true,
434+
ImportStateVerifyIgnore: []string{"force_destroy", "lifecycle_rule.0.condition.0.no_age"},
435+
},
436+
{
437+
Config: testAccStorageBucket_customAttributes_withLifecycle1(bucketName),
438+
Check: resource.ComposeTestCheckFunc(
439+
testAccCheckStorageBucketExists(
440+
t, "google_storage_bucket.bucket", bucketName, &bucket),
441+
),
442+
},
443+
{
444+
ResourceName: "google_storage_bucket.bucket",
445+
ImportState: true,
446+
ImportStateVerify: true,
447+
ImportStateVerifyIgnore: []string{"force_destroy"},
448+
},
449+
},
450+
})
451+
}
452+
385453
func TestAccStorageBucket_storageClass(t *testing.T) {
386454
t.Parallel()
387455

@@ -1316,6 +1384,25 @@ func testAccCheckStorageBucketLifecycleConditionState(expected *bool, b *storage
13161384
}
13171385
}
13181386

1387+
func testAccCheckStorageBucketLifecycleConditionNoAge(expected *int64, b *storage.Bucket) resource.TestCheckFunc {
1388+
return func(s *terraform.State) error {
1389+
actual := b.Lifecycle.Rule[0].Condition.Age
1390+
if expected == nil && b.Lifecycle.Rule[0].Condition.Age == nil {
1391+
return nil
1392+
}
1393+
if expected == nil {
1394+
return fmt.Errorf("expected condition Age to be unset, instead got %d", *actual)
1395+
}
1396+
if actual == nil {
1397+
return fmt.Errorf("expected condition Age to be %d, instead got nil (unset)", *expected)
1398+
}
1399+
if *expected != *actual {
1400+
return fmt.Errorf("expected condition Age to be %d, instead got %d", *expected, *actual)
1401+
}
1402+
return nil
1403+
}
1404+
}
1405+
13191406
func testAccStorageBucketDestroyProducer(t *testing.T) func(s *terraform.State) error {
13201407
return func(s *terraform.State) error {
13211408
config := acctest.GoogleProviderConfig(t)
@@ -1479,6 +1566,45 @@ resource "google_storage_bucket" "bucket" {
14791566
`, bucketName)
14801567
}
14811568

1569+
func testAccStorageBucket_customAttributes_withLifecycleNoAge(bucketName string) string {
1570+
return fmt.Sprintf(`
1571+
resource "google_storage_bucket" "bucket" {
1572+
name = "%s"
1573+
location = "EU"
1574+
force_destroy = "true"
1575+
lifecycle_rule {
1576+
action {
1577+
type = "Delete"
1578+
}
1579+
condition {
1580+
num_newer_versions = 2
1581+
no_age = true
1582+
}
1583+
}
1584+
}
1585+
`, bucketName)
1586+
}
1587+
1588+
func testAccStorageBucket_customAttributes_withLifecycleNoAgeAndAge(bucketName string) string {
1589+
return fmt.Sprintf(`
1590+
resource "google_storage_bucket" "bucket" {
1591+
name = "%s"
1592+
location = "EU"
1593+
force_destroy = "true"
1594+
lifecycle_rule {
1595+
action {
1596+
type = "Delete"
1597+
}
1598+
condition {
1599+
num_newer_versions = 2
1600+
age = 10
1601+
no_age = true
1602+
}
1603+
}
1604+
}
1605+
`, bucketName)
1606+
}
1607+
14821608
func testAccStorageBucket_storageClass(bucketName, storageClass, location string) string {
14831609
return fmt.Sprintf(`
14841610
resource "google_storage_bucket" "bucket" {

website/docs/r/storage_bucket.html.markdown

+2
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ The following arguments are supported:
147147

148148
* `age` - (Optional) Minimum age of an object in days to satisfy this condition.
149149

150+
* `no_age` - (Optional) While set `true`, `age` value will be omitted. **Note** Required to set `true` when `age` is unset in the config file.
151+
150152
* `created_before` - (Optional) A date in the RFC 3339 format YYYY-MM-DD. This condition is satisfied when an object is created before midnight of the specified date in UTC.
151153

152154
* `with_state` - (Optional) Match to live and/or archived objects. Unversioned buckets have only live objects. Supported values include: `"LIVE"`, `"ARCHIVED"`, `"ANY"`.

0 commit comments

Comments
 (0)