diff --git a/aws/resource_aws_s3_bucket.go b/aws/resource_aws_s3_bucket.go index 924e4d7e70b..f3ae7e586ce 100644 --- a/aws/resource_aws_s3_bucket.go +++ b/aws/resource_aws_s3_bucket.go @@ -218,8 +218,9 @@ func resourceAwsS3Bucket() *schema.Resource { }, "prefix": { Type: schema.TypeString, - Required: true, + Optional: true, }, + "tags": tagsSchema(), "enabled": { Type: schema.TypeBool, Required: true, @@ -782,9 +783,21 @@ func resourceAwsS3BucketRead(d *schema.ResourceData, meta interface{}) error { if lifecycleRule.ID != nil && *lifecycleRule.ID != "" { rule["id"] = *lifecycleRule.ID } - // Prefix - if lifecycleRule.Prefix != nil && *lifecycleRule.Prefix != "" { - rule["prefix"] = *lifecycleRule.Prefix + filter := lifecycleRule.Filter + if filter.And != nil { + // Prefix + if filter.And.Prefix != nil && *filter.And.Prefix != "" { + rule["prefix"] = *filter.And.Prefix + } + // Tag + if len(filter.And.Tags) > 0 { + rule["tags"] = tagsToMapS3(filter.And.Tags) + } + } else { + // Prefix + if filter.Prefix != nil && *filter.Prefix != "" { + rule["prefix"] = *filter.Prefix + } } // Enabled if lifecycleRule.Status != nil { @@ -1514,9 +1527,20 @@ func resourceAwsS3BucketLifecycleUpdate(s3conn *s3.S3, d *schema.ResourceData) e for i, lifecycleRule := range lifecycleRules { r := lifecycleRule.(map[string]interface{}) - rule := &s3.LifecycleRule{ - Prefix: aws.String(r["prefix"].(string)), + rule := &s3.LifecycleRule{} + + // Filter + tags := r["tags"].(map[string]interface{}) + filter := &s3.LifecycleRuleFilter{} + if len(tags) > 0 { + lifecycleRuleAndOp := &s3.LifecycleRuleAndOperator{} + lifecycleRuleAndOp.SetPrefix(r["prefix"].(string)) + lifecycleRuleAndOp.SetTags(tagsFromMapS3(tags)) + filter.SetAnd(lifecycleRuleAndOp) + } else { + filter.SetPrefix(r["prefix"].(string)) } + rule.SetFilter(filter) // ID if val, ok := r["id"].(string); ok && val != "" { diff --git a/aws/resource_aws_s3_bucket_test.go b/aws/resource_aws_s3_bucket_test.go index 9216f9f3c84..0bac600b5e8 100644 --- a/aws/resource_aws_s3_bucket_test.go +++ b/aws/resource_aws_s3_bucket_test.go @@ -600,6 +600,14 @@ func TestAccAWSS3Bucket_Lifecycle(t *testing.T) { "aws_s3_bucket.bucket", "lifecycle_rule.2.prefix", "path3/"), resource.TestCheckResourceAttr( "aws_s3_bucket.bucket", "lifecycle_rule.2.transition.460947558.days", "0"), + resource.TestCheckResourceAttr( + "aws_s3_bucket.bucket", "lifecycle_rule.3.id", "id4"), + resource.TestCheckResourceAttr( + "aws_s3_bucket.bucket", "lifecycle_rule.3.prefix", "path4/"), + resource.TestCheckResourceAttr( + "aws_s3_bucket.bucket", "lifecycle_rule.3.tags.tagKey", "tagValue"), + resource.TestCheckResourceAttr( + "aws_s3_bucket.bucket", "lifecycle_rule.3.tags.terraform", "hashicorp"), ), }, { @@ -1454,6 +1462,20 @@ resource "aws_s3_bucket" "bucket" { storage_class = "GLACIER" } } + lifecycle_rule { + id = "id4" + prefix = "path4/" + enabled = true + + tags { + "tagKey" = "tagValue" + "terraform" = "hashicorp" + } + + expiration { + date = "2016-01-12" + } + } } `, randInt) } diff --git a/website/docs/r/s3_bucket.html.markdown b/website/docs/r/s3_bucket.html.markdown index 2236b37cbc0..818ea476c09 100644 --- a/website/docs/r/s3_bucket.html.markdown +++ b/website/docs/r/s3_bucket.html.markdown @@ -110,9 +110,14 @@ resource "aws_s3_bucket" "bucket" { lifecycle_rule { id = "log" - prefix = "log/" enabled = true + prefix = "log/" + tags { + "rule" = "log" + "autoclean" = "true" + } + transition { days = 30 storage_class = "STANDARD_IA" @@ -337,7 +342,8 @@ The `logging` object supports the following: The `lifecycle_rule` object supports the following: * `id` - (Optional) Unique identifier for the rule. -* `prefix` - (Required) Object key prefix identifying one or more objects to which the rule applies. +* `prefix` - (Optional) Object key prefix identifying one or more objects to which the rule applies. +* `tags` - (Optional) Specifies object tags key and value. * `enabled` - (Required) Specifies lifecycle rule status. * `abort_incomplete_multipart_upload_days` (Optional) Specifies the number of days after initiating a multipart upload when the multipart upload must be completed. * `expiration` - (Optional) Specifies a period in the object's expire (documented below).