Skip to content

Commit 998611c

Browse files
authored
Merge pull request #23441 from hashicorp/b-s3-bucket-lifecycle-configuration-noncurrent-versioning-transition
r/s3_bucket_lifecycle_configuration: make `new_noncurrent_versions` arguments nullable ints to prevent drift and fix other nullable int args (`filter.object_size_greater_than` and `filter.object_size_less_than`)
2 parents e8d5a71 + 57e2c5d commit 998611c

5 files changed

+307
-21
lines changed

.changelog/23441.txt

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
```release-note:bug
2+
resource/aws_s3_bucket_lifecycle_configuration: Correctly configure `rule.filter.object_size_greater_than` and `rule.filter.object_size_less_than` in API requests and terraform state
3+
```
4+
5+
```release-note:bug
6+
resource/aws_s3_bucket_lifecycle_configuration: Prevent drift when `rule.noncurrent_version_expiration.newer_noncurrent_versions` or `rule.noncurrent_version_transition.newer_noncurrent_versions` is not specified
7+
```

internal/service/s3/bucket_lifecycle_configuration.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -164,9 +164,9 @@ func ResourceBucketLifecycleConfiguration() *schema.Resource {
164164
Elem: &schema.Resource{
165165
Schema: map[string]*schema.Schema{
166166
"newer_noncurrent_versions": {
167-
Type: schema.TypeInt,
167+
Type: nullable.TypeNullableInt,
168168
Optional: true,
169-
ValidateFunc: validation.IntAtLeast(1),
169+
ValidateFunc: nullable.ValidateTypeStringNullableIntAtLeast(1),
170170
},
171171
"noncurrent_days": {
172172
Type: schema.TypeInt,
@@ -182,9 +182,9 @@ func ResourceBucketLifecycleConfiguration() *schema.Resource {
182182
Elem: &schema.Resource{
183183
Schema: map[string]*schema.Schema{
184184
"newer_noncurrent_versions": {
185-
Type: schema.TypeInt,
185+
Type: nullable.TypeNullableInt,
186186
Optional: true,
187-
ValidateFunc: validation.IntAtLeast(1),
187+
ValidateFunc: nullable.ValidateTypeStringNullableIntAtLeast(1),
188188
},
189189
"noncurrent_days": {
190190
Type: schema.TypeInt,

internal/service/s3/bucket_lifecycle_configuration_test.go

+276
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,151 @@ func TestAccS3BucketLifecycleConfiguration_filterWithPrefix(t *testing.T) {
128128
})
129129
}
130130

131+
func TestAccS3BucketLifecycleConfiguration_Filter_ObjectSizeGreaterThan(t *testing.T) {
132+
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
133+
resourceName := "aws_s3_bucket_lifecycle_configuration.test"
134+
currTime := time.Now()
135+
date := time.Date(currTime.Year(), currTime.Month()+1, currTime.Day(), 0, 0, 0, 0, time.UTC).Format(time.RFC3339)
136+
137+
resource.ParallelTest(t, resource.TestCase{
138+
PreCheck: func() { acctest.PreCheck(t) },
139+
ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID),
140+
Providers: acctest.Providers,
141+
CheckDestroy: testAccCheckBucketLifecycleConfigurationDestroy,
142+
Steps: []resource.TestStep{
143+
{
144+
Config: testAccBucketLifecycleConfiguration_filterWithObjectSizeGreaterThanConfig(rName, date, 100),
145+
Check: resource.ComposeTestCheckFunc(
146+
testAccCheckBucketLifecycleConfigurationExists(resourceName),
147+
resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{
148+
"expiration.#": "1",
149+
"expiration.0.date": date,
150+
"filter.#": "1",
151+
"filter.0.object_size_greater_than": "100",
152+
"id": rName,
153+
"status": tfs3.LifecycleRuleStatusEnabled,
154+
}),
155+
),
156+
},
157+
{
158+
ResourceName: resourceName,
159+
ImportState: true,
160+
ImportStateVerify: true,
161+
},
162+
},
163+
})
164+
}
165+
166+
func TestAccS3BucketLifecycleConfiguration_Filter_ObjectSizeLessThan(t *testing.T) {
167+
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
168+
resourceName := "aws_s3_bucket_lifecycle_configuration.test"
169+
currTime := time.Now()
170+
date := time.Date(currTime.Year(), currTime.Month()+1, currTime.Day(), 0, 0, 0, 0, time.UTC).Format(time.RFC3339)
171+
172+
resource.ParallelTest(t, resource.TestCase{
173+
PreCheck: func() { acctest.PreCheck(t) },
174+
ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID),
175+
Providers: acctest.Providers,
176+
CheckDestroy: testAccCheckBucketLifecycleConfigurationDestroy,
177+
Steps: []resource.TestStep{
178+
{
179+
Config: testAccBucketLifecycleConfiguration_filterWithObjectSizeLessThanConfig(rName, date, 500),
180+
Check: resource.ComposeTestCheckFunc(
181+
testAccCheckBucketLifecycleConfigurationExists(resourceName),
182+
resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{
183+
"expiration.#": "1",
184+
"expiration.0.date": date,
185+
"filter.#": "1",
186+
"filter.0.object_size_less_than": "500",
187+
"id": rName,
188+
"status": tfs3.LifecycleRuleStatusEnabled,
189+
}),
190+
),
191+
},
192+
{
193+
ResourceName: resourceName,
194+
ImportState: true,
195+
ImportStateVerify: true,
196+
},
197+
},
198+
})
199+
}
200+
201+
func TestAccS3BucketLifecycleConfiguration_Filter_ObjectSizeRange(t *testing.T) {
202+
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
203+
resourceName := "aws_s3_bucket_lifecycle_configuration.test"
204+
currTime := time.Now()
205+
date := time.Date(currTime.Year(), currTime.Month()+1, currTime.Day(), 0, 0, 0, 0, time.UTC).Format(time.RFC3339)
206+
207+
resource.ParallelTest(t, resource.TestCase{
208+
PreCheck: func() { acctest.PreCheck(t) },
209+
ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID),
210+
Providers: acctest.Providers,
211+
CheckDestroy: testAccCheckBucketLifecycleConfigurationDestroy,
212+
Steps: []resource.TestStep{
213+
{
214+
Config: testAccBucketLifecycleConfiguration_filterWithObjectSizeRangeConfig(rName, date, 500, 64000),
215+
Check: resource.ComposeTestCheckFunc(
216+
testAccCheckBucketLifecycleConfigurationExists(resourceName),
217+
resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{
218+
"expiration.#": "1",
219+
"expiration.0.date": date,
220+
"filter.#": "1",
221+
"filter.0.and.#": "1",
222+
"filter.0.and.0.object_size_greater_than": "500",
223+
"filter.0.and.0.object_size_less_than": "64000",
224+
"id": rName,
225+
"status": tfs3.LifecycleRuleStatusEnabled,
226+
}),
227+
),
228+
},
229+
{
230+
ResourceName: resourceName,
231+
ImportState: true,
232+
ImportStateVerify: true,
233+
},
234+
},
235+
})
236+
}
237+
238+
func TestAccS3BucketLifecycleConfiguration_Filter_ObjectSizeRangeAndPrefix(t *testing.T) {
239+
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
240+
resourceName := "aws_s3_bucket_lifecycle_configuration.test"
241+
currTime := time.Now()
242+
date := time.Date(currTime.Year(), currTime.Month()+1, currTime.Day(), 0, 0, 0, 0, time.UTC).Format(time.RFC3339)
243+
244+
resource.ParallelTest(t, resource.TestCase{
245+
PreCheck: func() { acctest.PreCheck(t) },
246+
ErrorCheck: acctest.ErrorCheck(t, s3.EndpointsID),
247+
Providers: acctest.Providers,
248+
CheckDestroy: testAccCheckBucketLifecycleConfigurationDestroy,
249+
Steps: []resource.TestStep{
250+
{
251+
Config: testAccBucketLifecycleConfiguration_filterWithObjectSizeRangeAndPrefixConfig(rName, date, 500, 64000),
252+
Check: resource.ComposeTestCheckFunc(
253+
testAccCheckBucketLifecycleConfigurationExists(resourceName),
254+
resource.TestCheckTypeSetElemNestedAttrs(resourceName, "rule.*", map[string]string{
255+
"expiration.#": "1",
256+
"expiration.0.date": date,
257+
"filter.#": "1",
258+
"filter.0.and.#": "1",
259+
"filter.0.and.0.object_size_greater_than": "500",
260+
"filter.0.and.0.object_size_less_than": "64000",
261+
"filter.0.and.0.prefix": rName,
262+
"id": rName,
263+
"status": tfs3.LifecycleRuleStatusEnabled,
264+
}),
265+
),
266+
},
267+
{
268+
ResourceName: resourceName,
269+
ImportState: true,
270+
ImportStateVerify: true,
271+
},
272+
},
273+
})
274+
}
275+
131276
func TestAccS3BucketLifecycleConfiguration_disableRule(t *testing.T) {
132277
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
133278
resourceName := "aws_s3_bucket_lifecycle_configuration.test"
@@ -1241,3 +1386,134 @@ resource "aws_s3_bucket_lifecycle_configuration" "test" {
12411386
}
12421387
`, rName)
12431388
}
1389+
1390+
func testAccBucketLifecycleConfiguration_filterWithObjectSizeGreaterThanConfig(rName, date string, sizeGreaterThan int) string {
1391+
return fmt.Sprintf(`
1392+
resource "aws_s3_bucket" "test" {
1393+
bucket = %[1]q
1394+
}
1395+
1396+
resource "aws_s3_bucket_acl" "test" {
1397+
bucket = aws_s3_bucket.test.id
1398+
acl = "private"
1399+
}
1400+
1401+
resource "aws_s3_bucket_lifecycle_configuration" "test" {
1402+
bucket = aws_s3_bucket.test.bucket
1403+
1404+
rule {
1405+
id = %[1]q
1406+
1407+
expiration {
1408+
date = %[2]q
1409+
}
1410+
1411+
filter {
1412+
object_size_greater_than = %[3]d
1413+
}
1414+
1415+
status = "Enabled"
1416+
}
1417+
}
1418+
`, rName, date, sizeGreaterThan)
1419+
}
1420+
1421+
func testAccBucketLifecycleConfiguration_filterWithObjectSizeLessThanConfig(rName, date string, sizeLessThan int) string {
1422+
return fmt.Sprintf(`
1423+
resource "aws_s3_bucket" "test" {
1424+
bucket = %[1]q
1425+
}
1426+
1427+
resource "aws_s3_bucket_acl" "test" {
1428+
bucket = aws_s3_bucket.test.id
1429+
acl = "private"
1430+
}
1431+
1432+
resource "aws_s3_bucket_lifecycle_configuration" "test" {
1433+
bucket = aws_s3_bucket.test.bucket
1434+
1435+
rule {
1436+
id = %[1]q
1437+
1438+
expiration {
1439+
date = %[2]q
1440+
}
1441+
1442+
filter {
1443+
object_size_less_than = %[3]d
1444+
}
1445+
1446+
status = "Enabled"
1447+
}
1448+
}
1449+
`, rName, date, sizeLessThan)
1450+
}
1451+
1452+
func testAccBucketLifecycleConfiguration_filterWithObjectSizeRangeConfig(rName, date string, sizeGreaterThan, sizeLessThan int) string {
1453+
return fmt.Sprintf(`
1454+
resource "aws_s3_bucket" "test" {
1455+
bucket = %[1]q
1456+
}
1457+
1458+
resource "aws_s3_bucket_acl" "test" {
1459+
bucket = aws_s3_bucket.test.id
1460+
acl = "private"
1461+
}
1462+
1463+
resource "aws_s3_bucket_lifecycle_configuration" "test" {
1464+
bucket = aws_s3_bucket.test.bucket
1465+
1466+
rule {
1467+
id = %[1]q
1468+
1469+
expiration {
1470+
date = %[2]q
1471+
}
1472+
1473+
filter {
1474+
and {
1475+
object_size_greater_than = %[3]d
1476+
object_size_less_than = %[4]d
1477+
}
1478+
}
1479+
1480+
status = "Enabled"
1481+
}
1482+
}
1483+
`, rName, date, sizeGreaterThan, sizeLessThan)
1484+
}
1485+
1486+
func testAccBucketLifecycleConfiguration_filterWithObjectSizeRangeAndPrefixConfig(rName, date string, sizeGreaterThan, sizeLessThan int) string {
1487+
return fmt.Sprintf(`
1488+
resource "aws_s3_bucket" "test" {
1489+
bucket = %[1]q
1490+
}
1491+
1492+
resource "aws_s3_bucket_acl" "test" {
1493+
bucket = aws_s3_bucket.test.id
1494+
acl = "private"
1495+
}
1496+
1497+
resource "aws_s3_bucket_lifecycle_configuration" "test" {
1498+
bucket = aws_s3_bucket.test.bucket
1499+
1500+
rule {
1501+
id = %[1]q
1502+
1503+
expiration {
1504+
date = %[2]q
1505+
}
1506+
1507+
filter {
1508+
and {
1509+
object_size_greater_than = %[3]d
1510+
object_size_less_than = %[4]d
1511+
prefix = %[1]q
1512+
}
1513+
}
1514+
1515+
status = "Enabled"
1516+
}
1517+
}
1518+
`, rName, date, sizeGreaterThan, sizeLessThan)
1519+
}

0 commit comments

Comments
 (0)