Skip to content

Commit

Permalink
New Resource: aws_s3_bucket_metric
Browse files Browse the repository at this point in the history
  • Loading branch information
bflad committed Jan 27, 2018
1 parent 5f4d72e commit 1d9468a
Show file tree
Hide file tree
Showing 5 changed files with 996 additions and 0 deletions.
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ func Provider() terraform.ResourceProvider {
"aws_s3_bucket_policy": resourceAwsS3BucketPolicy(),
"aws_s3_bucket_object": resourceAwsS3BucketObject(),
"aws_s3_bucket_notification": resourceAwsS3BucketNotification(),
"aws_s3_bucket_metric": resourceAwsS3BucketMetric(),
"aws_security_group": resourceAwsSecurityGroup(),
"aws_default_security_group": resourceAwsDefaultSecurityGroup(),
"aws_security_group_rule": resourceAwsSecurityGroupRule(),
Expand Down
217 changes: 217 additions & 0 deletions aws/resource_aws_s3_bucket_metric.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
package aws

import (
"fmt"
"log"
"strings"
"time"

"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/helper/schema"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/s3"
)

func resourceAwsS3BucketMetric() *schema.Resource {
return &schema.Resource{
Create: resourceAwsS3BucketMetricPut,
Read: resourceAwsS3BucketMetricRead,
Update: resourceAwsS3BucketMetricPut,
Delete: resourceAwsS3BucketMetricDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"bucket": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"filter": {
Type: schema.TypeList,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"prefix": {
Type: schema.TypeString,
Optional: true,
},
"tags": tagsSchema(),
},
},
},
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
},
}
}

func resourceAwsS3BucketMetricPut(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).s3conn
bucket := d.Get("bucket").(string)
name := d.Get("name").(string)

metricsConfiguration := &s3.MetricsConfiguration{
Id: aws.String(name),
}

if v, ok := d.GetOk("filter"); ok {
metricsConfiguration.Filter = expandS3MetricsFilter(v.([]interface{})[0].(map[string]interface{}))
}

input := &s3.PutBucketMetricsConfigurationInput{
Bucket: aws.String(bucket),
Id: aws.String(name),
MetricsConfiguration: metricsConfiguration,
}

log.Printf("[DEBUG] Putting metric configuration: %s", input)
err := resource.Retry(1*time.Minute, func() *resource.RetryError {
_, err := conn.PutBucketMetricsConfiguration(input)
if err != nil {
if isAWSErr(err, s3.ErrCodeNoSuchBucket, "") {
return resource.RetryableError(err)
}
return resource.NonRetryableError(err)
}
return nil
})
if err != nil {
return fmt.Errorf("Error putting S3 metric configuration: %s", err)
}

d.SetId(fmt.Sprintf("%s:%s", bucket, name))

return resourceAwsS3BucketMetricRead(d, meta)
}

func resourceAwsS3BucketMetricDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).s3conn

bucket, name, err := resourceAwsS3BucketMetricParseID(d.Id())
if err != nil {
return err
}

input := &s3.DeleteBucketMetricsConfigurationInput{
Bucket: aws.String(bucket),
Id: aws.String(name),
}

log.Printf("[DEBUG] Deleting S3 bucket metric configuration: %s", input)
_, err = conn.DeleteBucketMetricsConfiguration(input)
if err != nil {
if isAWSErr(err, s3.ErrCodeNoSuchBucket, "") || isAWSErr(err, "NoSuchConfiguration", "The specified configuration does not exist.") {
log.Printf("[WARN] %s S3 bucket metrics configuration not found, removing from state.", d.Id())
d.SetId("")
return nil
}
return fmt.Errorf("Error deleting S3 metric configuration: %s", err)
}

d.SetId("")
return nil
}

func resourceAwsS3BucketMetricRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).s3conn

bucket, name, err := resourceAwsS3BucketMetricParseID(d.Id())
if err != nil {
return err
}

d.Set("bucket", bucket)
d.Set("name", name)

input := &s3.GetBucketMetricsConfigurationInput{
Bucket: aws.String(bucket),
Id: aws.String(name),
}

log.Printf("[DEBUG] Reading S3 bucket metrics configuration: %s", input)
output, err := conn.GetBucketMetricsConfiguration(input)
if err != nil {
if isAWSErr(err, s3.ErrCodeNoSuchBucket, "") || isAWSErr(err, "NoSuchConfiguration", "The specified configuration does not exist.") {
log.Printf("[WARN] %s S3 bucket metrics configuration not found, removing from state.", d.Id())
d.SetId("")
return nil
}
return err
}

if output.MetricsConfiguration.Filter != nil {
if err := d.Set("filter", []interface{}{flattenS3MetricsFilter(output.MetricsConfiguration.Filter)}); err != nil {
return err
}
}

return nil
}

func expandS3MetricsFilter(m map[string]interface{}) *s3.MetricsFilter {
var prefix string
if v, ok := m["prefix"]; ok {
prefix = v.(string)
}

var tags []*s3.Tag
if v, ok := m["tags"]; ok {
tags = tagsFromMapS3(v.(map[string]interface{}))
}

metricsFilter := &s3.MetricsFilter{}
if prefix != "" && len(tags) > 0 {
metricsFilter.And = &s3.MetricsAndOperator{
Prefix: aws.String(prefix),
Tags: tags,
}
} else if len(tags) > 1 {
metricsFilter.And = &s3.MetricsAndOperator{
Tags: tags,
}
} else if len(tags) == 1 {
metricsFilter.Tag = tags[0]
} else {
metricsFilter.Prefix = aws.String(prefix)
}
return metricsFilter
}

func flattenS3MetricsFilter(metricsFilter *s3.MetricsFilter) map[string]interface{} {
m := make(map[string]interface{})

if metricsFilter.And != nil {
and := *metricsFilter.And
if and.Prefix != nil {
m["prefix"] = *and.Prefix
}
if and.Tags != nil {
m["tags"] = tagsToMapS3(and.Tags)
}
} else if metricsFilter.Prefix != nil {
m["prefix"] = *metricsFilter.Prefix
} else if metricsFilter.Tag != nil {
tags := []*s3.Tag{
metricsFilter.Tag,
}
m["tags"] = tagsToMapS3(tags)
}
return m
}

func resourceAwsS3BucketMetricParseID(id string) (string, string, error) {
idParts := strings.Split(id, ":")
if len(idParts) != 2 {
return "", "", fmt.Errorf("please make sure the ID is in the form BUCKET:NAME (i.e. my-bucket:EntireBucket")
}
bucket := idParts[0]
name := idParts[1]
return bucket, name, nil
}
Loading

0 comments on commit 1d9468a

Please sign in to comment.