provider/aws: Support S3 bucket notification
* Implement aws_s3_bucket_notification resource
This commit is contained in:
parent
b04b508b54
commit
d646682d7a
|
@ -228,6 +228,7 @@ func Provider() terraform.ResourceProvider {
|
||||||
"aws_route_table_association": resourceAwsRouteTableAssociation(),
|
"aws_route_table_association": resourceAwsRouteTableAssociation(),
|
||||||
"aws_s3_bucket": resourceAwsS3Bucket(),
|
"aws_s3_bucket": resourceAwsS3Bucket(),
|
||||||
"aws_s3_bucket_object": resourceAwsS3BucketObject(),
|
"aws_s3_bucket_object": resourceAwsS3BucketObject(),
|
||||||
|
"aws_s3_bucket_notification": resourceAwsS3BucketNotification(),
|
||||||
"aws_security_group": resourceAwsSecurityGroup(),
|
"aws_security_group": resourceAwsSecurityGroup(),
|
||||||
"aws_security_group_rule": resourceAwsSecurityGroupRule(),
|
"aws_security_group_rule": resourceAwsSecurityGroupRule(),
|
||||||
"aws_spot_instance_request": resourceAwsSpotInstanceRequest(),
|
"aws_spot_instance_request": resourceAwsSpotInstanceRequest(),
|
||||||
|
|
|
@ -0,0 +1,464 @@
|
||||||
|
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/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/service/s3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func resourceAwsS3BucketNotification() *schema.Resource {
|
||||||
|
return &schema.Resource{
|
||||||
|
Create: resourceAwsS3BucketNotificationPut,
|
||||||
|
Read: resourceAwsS3BucketNotificationRead,
|
||||||
|
Update: resourceAwsS3BucketNotificationPut,
|
||||||
|
Delete: resourceAwsS3BucketNotificationDelete,
|
||||||
|
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"bucket": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
"topic": &schema.Schema{
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"id": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"filter_prefix": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"filter_suffix": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"topic_arn": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"events": &schema.Schema{
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Required: true,
|
||||||
|
Elem: &schema.Schema{Type: schema.TypeString},
|
||||||
|
Set: schema.HashString,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"queue": &schema.Schema{
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"id": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"filter_prefix": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"filter_suffix": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"queue_arn": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
"events": &schema.Schema{
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Required: true,
|
||||||
|
Elem: &schema.Schema{Type: schema.TypeString},
|
||||||
|
Set: schema.HashString,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
"lambda_function": &schema.Schema{
|
||||||
|
Type: schema.TypeList,
|
||||||
|
Optional: true,
|
||||||
|
Elem: &schema.Resource{
|
||||||
|
Schema: map[string]*schema.Schema{
|
||||||
|
"id": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
|
},
|
||||||
|
"filter_prefix": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"filter_suffix": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"lambda_function_arn": &schema.Schema{
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
"events": &schema.Schema{
|
||||||
|
Type: schema.TypeSet,
|
||||||
|
Required: true,
|
||||||
|
Elem: &schema.Schema{Type: schema.TypeString},
|
||||||
|
Set: schema.HashString,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsS3BucketNotificationPut(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
s3conn := meta.(*AWSClient).s3conn
|
||||||
|
bucket := d.Get("bucket").(string)
|
||||||
|
|
||||||
|
// TopicNotifications
|
||||||
|
topicNotifications := d.Get("topic").([]interface{})
|
||||||
|
topicConfigs := make([]*s3.TopicConfiguration, 0, len(topicNotifications))
|
||||||
|
for i, c := range topicNotifications {
|
||||||
|
tc := &s3.TopicConfiguration{}
|
||||||
|
|
||||||
|
c := c.(map[string]interface{})
|
||||||
|
|
||||||
|
// Id
|
||||||
|
if val, ok := c["id"].(string); ok && val != "" {
|
||||||
|
tc.Id = aws.String(val)
|
||||||
|
} else {
|
||||||
|
tc.Id = aws.String(resource.PrefixedUniqueId("tf-s3-topic-"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TopicArn
|
||||||
|
if val, ok := c["topic_arn"].(string); ok {
|
||||||
|
tc.TopicArn = aws.String(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Events
|
||||||
|
events := d.Get(fmt.Sprintf("topic.%d.events", i)).(*schema.Set).List()
|
||||||
|
tc.Events = make([]*string, 0, len(events))
|
||||||
|
for _, e := range events {
|
||||||
|
tc.Events = append(tc.Events, aws.String(e.(string)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter
|
||||||
|
filterRules := make([]*s3.FilterRule, 0, 2)
|
||||||
|
if val, ok := c["filter_prefix"].(string); ok && val != "" {
|
||||||
|
filterRule := &s3.FilterRule{
|
||||||
|
Name: aws.String("prefix"),
|
||||||
|
Value: aws.String(val),
|
||||||
|
}
|
||||||
|
filterRules = append(filterRules, filterRule)
|
||||||
|
}
|
||||||
|
if val, ok := c["filter_suffix"].(string); ok && val != "" {
|
||||||
|
filterRule := &s3.FilterRule{
|
||||||
|
Name: aws.String("suffix"),
|
||||||
|
Value: aws.String(val),
|
||||||
|
}
|
||||||
|
filterRules = append(filterRules, filterRule)
|
||||||
|
}
|
||||||
|
if len(filterRules) > 0 {
|
||||||
|
tc.Filter = &s3.NotificationConfigurationFilter{
|
||||||
|
Key: &s3.KeyFilter{
|
||||||
|
FilterRules: filterRules,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
topicConfigs = append(topicConfigs, tc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SQS
|
||||||
|
queueNotifications := d.Get("queue").([]interface{})
|
||||||
|
queueConfigs := make([]*s3.QueueConfiguration, 0, len(queueNotifications))
|
||||||
|
for i, c := range queueNotifications {
|
||||||
|
qc := &s3.QueueConfiguration{}
|
||||||
|
|
||||||
|
c := c.(map[string]interface{})
|
||||||
|
|
||||||
|
// Id
|
||||||
|
if val, ok := c["id"].(string); ok && val != "" {
|
||||||
|
qc.Id = aws.String(val)
|
||||||
|
} else {
|
||||||
|
qc.Id = aws.String(resource.PrefixedUniqueId("tf-s3-queue-"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueueArn
|
||||||
|
if val, ok := c["queue_arn"].(string); ok {
|
||||||
|
qc.QueueArn = aws.String(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Events
|
||||||
|
events := d.Get(fmt.Sprintf("queue.%d.events", i)).(*schema.Set).List()
|
||||||
|
qc.Events = make([]*string, 0, len(events))
|
||||||
|
for _, e := range events {
|
||||||
|
qc.Events = append(qc.Events, aws.String(e.(string)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter
|
||||||
|
filterRules := make([]*s3.FilterRule, 0, 2)
|
||||||
|
if val, ok := c["filter_prefix"].(string); ok && val != "" {
|
||||||
|
filterRule := &s3.FilterRule{
|
||||||
|
Name: aws.String("prefix"),
|
||||||
|
Value: aws.String(val),
|
||||||
|
}
|
||||||
|
filterRules = append(filterRules, filterRule)
|
||||||
|
}
|
||||||
|
if val, ok := c["filter_suffix"].(string); ok && val != "" {
|
||||||
|
filterRule := &s3.FilterRule{
|
||||||
|
Name: aws.String("suffix"),
|
||||||
|
Value: aws.String(val),
|
||||||
|
}
|
||||||
|
filterRules = append(filterRules, filterRule)
|
||||||
|
}
|
||||||
|
if len(filterRules) > 0 {
|
||||||
|
qc.Filter = &s3.NotificationConfigurationFilter{
|
||||||
|
Key: &s3.KeyFilter{
|
||||||
|
FilterRules: filterRules,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
queueConfigs = append(queueConfigs, qc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lambda
|
||||||
|
lambdaFunctionNotifications := d.Get("lambda_function").([]interface{})
|
||||||
|
lambdaConfigs := make([]*s3.LambdaFunctionConfiguration, 0, len(lambdaFunctionNotifications))
|
||||||
|
for i, c := range lambdaFunctionNotifications {
|
||||||
|
lc := &s3.LambdaFunctionConfiguration{}
|
||||||
|
|
||||||
|
c := c.(map[string]interface{})
|
||||||
|
|
||||||
|
// Id
|
||||||
|
if val, ok := c["id"].(string); ok && val != "" {
|
||||||
|
lc.Id = aws.String(val)
|
||||||
|
} else {
|
||||||
|
lc.Id = aws.String(resource.PrefixedUniqueId("tf-s3-lambda-"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// LambdaFunctionArn
|
||||||
|
if val, ok := c["lambda_function_arn"].(string); ok {
|
||||||
|
lc.LambdaFunctionArn = aws.String(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Events
|
||||||
|
events := d.Get(fmt.Sprintf("lambda_function.%d.events", i)).(*schema.Set).List()
|
||||||
|
lc.Events = make([]*string, 0, len(events))
|
||||||
|
for _, e := range events {
|
||||||
|
lc.Events = append(lc.Events, aws.String(e.(string)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter
|
||||||
|
filterRules := make([]*s3.FilterRule, 0, 2)
|
||||||
|
if val, ok := c["filter_prefix"].(string); ok && val != "" {
|
||||||
|
filterRule := &s3.FilterRule{
|
||||||
|
Name: aws.String("prefix"),
|
||||||
|
Value: aws.String(val),
|
||||||
|
}
|
||||||
|
filterRules = append(filterRules, filterRule)
|
||||||
|
}
|
||||||
|
if val, ok := c["filter_suffix"].(string); ok && val != "" {
|
||||||
|
filterRule := &s3.FilterRule{
|
||||||
|
Name: aws.String("suffix"),
|
||||||
|
Value: aws.String(val),
|
||||||
|
}
|
||||||
|
filterRules = append(filterRules, filterRule)
|
||||||
|
}
|
||||||
|
if len(filterRules) > 0 {
|
||||||
|
lc.Filter = &s3.NotificationConfigurationFilter{
|
||||||
|
Key: &s3.KeyFilter{
|
||||||
|
FilterRules: filterRules,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lambdaConfigs = append(lambdaConfigs, lc)
|
||||||
|
}
|
||||||
|
|
||||||
|
notificationConfiguration := &s3.NotificationConfiguration{}
|
||||||
|
if len(lambdaConfigs) > 0 {
|
||||||
|
notificationConfiguration.LambdaFunctionConfigurations = lambdaConfigs
|
||||||
|
}
|
||||||
|
if len(queueConfigs) > 0 {
|
||||||
|
notificationConfiguration.QueueConfigurations = queueConfigs
|
||||||
|
}
|
||||||
|
if len(topicConfigs) > 0 {
|
||||||
|
notificationConfiguration.TopicConfigurations = topicConfigs
|
||||||
|
}
|
||||||
|
i := &s3.PutBucketNotificationConfigurationInput{
|
||||||
|
Bucket: aws.String(bucket),
|
||||||
|
NotificationConfiguration: notificationConfiguration,
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] S3 bucket: %s, Putting notification: %v", bucket, i)
|
||||||
|
err := resource.Retry(1*time.Minute, func() *resource.RetryError {
|
||||||
|
if _, err := s3conn.PutBucketNotificationConfiguration(i); err != nil {
|
||||||
|
if awserr, ok := err.(awserr.Error); ok {
|
||||||
|
switch awserr.Message() {
|
||||||
|
case "Unable to validate the following destination configurations":
|
||||||
|
return resource.RetryableError(awserr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Didn't recognize the error, so shouldn't retry.
|
||||||
|
return resource.NonRetryableError(err)
|
||||||
|
}
|
||||||
|
// Successful put configuration
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error putting S3 notification configuration: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId(bucket)
|
||||||
|
|
||||||
|
return resourceAwsS3BucketNotificationRead(d, meta)
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsS3BucketNotificationDelete(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
s3conn := meta.(*AWSClient).s3conn
|
||||||
|
|
||||||
|
i := &s3.PutBucketNotificationConfigurationInput{
|
||||||
|
Bucket: aws.String(d.Id()),
|
||||||
|
NotificationConfiguration: &s3.NotificationConfiguration{},
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[DEBUG] S3 bucket: %s, Deleting notification: %v", d.Id(), i)
|
||||||
|
_, err := s3conn.PutBucketNotificationConfiguration(i)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error deleting S3 notification configuration: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
d.SetId("")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resourceAwsS3BucketNotificationRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
s3conn := meta.(*AWSClient).s3conn
|
||||||
|
|
||||||
|
var err error
|
||||||
|
_, err = s3conn.HeadBucket(&s3.HeadBucketInput{
|
||||||
|
Bucket: aws.String(d.Id()),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
if awsError, ok := err.(awserr.RequestFailure); ok && awsError.StatusCode() == 404 {
|
||||||
|
log.Printf("[WARN] S3 Bucket (%s) not found, error code (404)", d.Id())
|
||||||
|
d.SetId("")
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
// some of the AWS SDK's errors can be empty strings, so let's add
|
||||||
|
// some additional context.
|
||||||
|
return fmt.Errorf("error reading S3 bucket \"%s\": %s", d.Id(), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the notification configuration
|
||||||
|
notificationConfigs, err := s3conn.GetBucketNotificationConfiguration(&s3.GetBucketNotificationConfigurationRequest{
|
||||||
|
Bucket: aws.String(d.Id()),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Printf("[DEBUG] S3 Bucket: %s, get notification: %v", d.Id(), notificationConfigs)
|
||||||
|
// Topic Notification
|
||||||
|
if err := d.Set("topic", flattenTopicConfigurations(notificationConfigs.TopicConfigurations)); err != nil {
|
||||||
|
return fmt.Errorf("error reading S3 bucket \"%s\" topic notification: %s", d.Id(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SQS Notification
|
||||||
|
if err := d.Set("queue", flattenQueueConfigurations(notificationConfigs.QueueConfigurations)); err != nil {
|
||||||
|
return fmt.Errorf("error reading S3 bucket \"%s\" queue notification: %s", d.Id(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lambda Notification
|
||||||
|
if err := d.Set("lambda_function", flattenLambdaFunctionConfigurations(notificationConfigs.LambdaFunctionConfigurations)); err != nil {
|
||||||
|
return fmt.Errorf("error reading S3 bucket \"%s\" lambda function notification: %s", d.Id(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func flattenNotificationConfigurationFilter(filter *s3.NotificationConfigurationFilter) map[string]interface{} {
|
||||||
|
filterRules := map[string]interface{}{}
|
||||||
|
for _, f := range filter.Key.FilterRules {
|
||||||
|
if strings.ToLower(*f.Name) == s3.FilterRuleNamePrefix {
|
||||||
|
filterRules["filter_prefix"] = *f.Value
|
||||||
|
}
|
||||||
|
if strings.ToLower(*f.Name) == s3.FilterRuleNameSuffix {
|
||||||
|
filterRules["filter_suffix"] = *f.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filterRules
|
||||||
|
}
|
||||||
|
|
||||||
|
func flattenTopicConfigurations(configs []*s3.TopicConfiguration) []map[string]interface{} {
|
||||||
|
topicNotifications := make([]map[string]interface{}, 0, len(configs))
|
||||||
|
for _, notification := range configs {
|
||||||
|
var conf map[string]interface{}
|
||||||
|
if filter := notification.Filter; filter != nil {
|
||||||
|
conf = flattenNotificationConfigurationFilter(filter)
|
||||||
|
} else {
|
||||||
|
conf = map[string]interface{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
conf["id"] = *notification.Id
|
||||||
|
conf["events"] = schema.NewSet(schema.HashString, flattenStringList(notification.Events))
|
||||||
|
conf["topic_arn"] = *notification.TopicArn
|
||||||
|
topicNotifications = append(topicNotifications, conf)
|
||||||
|
}
|
||||||
|
|
||||||
|
return topicNotifications
|
||||||
|
}
|
||||||
|
|
||||||
|
func flattenQueueConfigurations(configs []*s3.QueueConfiguration) []map[string]interface{} {
|
||||||
|
queueNotifications := make([]map[string]interface{}, 0, len(configs))
|
||||||
|
for _, notification := range configs {
|
||||||
|
var conf map[string]interface{}
|
||||||
|
if filter := notification.Filter; filter != nil {
|
||||||
|
conf = flattenNotificationConfigurationFilter(filter)
|
||||||
|
} else {
|
||||||
|
conf = map[string]interface{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
conf["id"] = *notification.Id
|
||||||
|
conf["events"] = schema.NewSet(schema.HashString, flattenStringList(notification.Events))
|
||||||
|
conf["queue_arn"] = *notification.QueueArn
|
||||||
|
queueNotifications = append(queueNotifications, conf)
|
||||||
|
}
|
||||||
|
|
||||||
|
return queueNotifications
|
||||||
|
}
|
||||||
|
|
||||||
|
func flattenLambdaFunctionConfigurations(configs []*s3.LambdaFunctionConfiguration) []map[string]interface{} {
|
||||||
|
lambdaFunctionNotifications := make([]map[string]interface{}, 0, len(configs))
|
||||||
|
for _, notification := range configs {
|
||||||
|
var conf map[string]interface{}
|
||||||
|
if filter := notification.Filter; filter != nil {
|
||||||
|
conf = flattenNotificationConfigurationFilter(filter)
|
||||||
|
} else {
|
||||||
|
conf = map[string]interface{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
conf["id"] = *notification.Id
|
||||||
|
conf["events"] = schema.NewSet(schema.HashString, flattenStringList(notification.Events))
|
||||||
|
conf["lambda_function_arn"] = *notification.LambdaFunctionArn
|
||||||
|
lambdaFunctionNotifications = append(lambdaFunctionNotifications, conf)
|
||||||
|
}
|
||||||
|
|
||||||
|
return lambdaFunctionNotifications
|
||||||
|
}
|
|
@ -0,0 +1,519 @@
|
||||||
|
package aws
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/acctest"
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
|
"github.com/hashicorp/terraform/terraform"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
|
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||||
|
"github.com/aws/aws-sdk-go/service/s3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAccAWSS3Bucket_Notification(t *testing.T) {
|
||||||
|
rInt := acctest.RandInt()
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckAWSS3BucketNotificationDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccAWSS3BucketConfigWithTopicNotification(rInt),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckAWSS3BucketTopicNotification(
|
||||||
|
"aws_s3_bucket.bucket",
|
||||||
|
"notification-sns1",
|
||||||
|
"aws_sns_topic.topic",
|
||||||
|
[]string{"s3:ObjectCreated:*", "s3:ObjectRemoved:Delete"},
|
||||||
|
&s3.KeyFilter{
|
||||||
|
FilterRules: []*s3.FilterRule{
|
||||||
|
&s3.FilterRule{
|
||||||
|
Name: aws.String("Prefix"),
|
||||||
|
Value: aws.String(fmt.Sprintf("%d/", rInt)),
|
||||||
|
},
|
||||||
|
&s3.FilterRule{
|
||||||
|
Name: aws.String("Suffix"),
|
||||||
|
Value: aws.String(".txt"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
testAccCheckAWSS3BucketTopicNotification(
|
||||||
|
"aws_s3_bucket.bucket",
|
||||||
|
"notification-sns2",
|
||||||
|
"aws_sns_topic.topic",
|
||||||
|
[]string{"s3:ObjectCreated:*", "s3:ObjectRemoved:Delete"},
|
||||||
|
&s3.KeyFilter{
|
||||||
|
FilterRules: []*s3.FilterRule{
|
||||||
|
&s3.FilterRule{
|
||||||
|
Name: aws.String("Suffix"),
|
||||||
|
Value: aws.String(".log"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccAWSS3BucketConfigWithQueueNotification(rInt),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckAWSS3BucketQueueNotification(
|
||||||
|
"aws_s3_bucket.bucket",
|
||||||
|
"notification-sqs",
|
||||||
|
"aws_sqs_queue.queue",
|
||||||
|
[]string{"s3:ObjectCreated:*", "s3:ObjectRemoved:Delete"},
|
||||||
|
&s3.KeyFilter{
|
||||||
|
FilterRules: []*s3.FilterRule{
|
||||||
|
&s3.FilterRule{
|
||||||
|
Name: aws.String("Prefix"),
|
||||||
|
Value: aws.String(fmt.Sprintf("%d/", rInt)),
|
||||||
|
},
|
||||||
|
&s3.FilterRule{
|
||||||
|
Name: aws.String("Suffix"),
|
||||||
|
Value: aws.String(".mp4"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccAWSS3BucketConfigWithLambdaNotification(rInt),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckAWSS3BucketLambdaFunctionConfiguration(
|
||||||
|
"aws_s3_bucket.bucket",
|
||||||
|
"notification-lambda",
|
||||||
|
"aws_lambda_function.func",
|
||||||
|
[]string{"s3:ObjectCreated:*", "s3:ObjectRemoved:Delete"},
|
||||||
|
&s3.KeyFilter{
|
||||||
|
FilterRules: []*s3.FilterRule{
|
||||||
|
&s3.FilterRule{
|
||||||
|
Name: aws.String("Prefix"),
|
||||||
|
Value: aws.String(fmt.Sprintf("%d/", rInt)),
|
||||||
|
},
|
||||||
|
&s3.FilterRule{
|
||||||
|
Name: aws.String("Suffix"),
|
||||||
|
Value: aws.String(".png"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAccAWSS3Bucket_NotificationWithoutFilter(t *testing.T) {
|
||||||
|
rInt := acctest.RandInt()
|
||||||
|
resource.Test(t, resource.TestCase{
|
||||||
|
PreCheck: func() { testAccPreCheck(t) },
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckAWSS3BucketNotificationDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: testAccAWSS3BucketConfigWithTopicNotificationWithoutFilter(rInt),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
testAccCheckAWSS3BucketTopicNotification(
|
||||||
|
"aws_s3_bucket.bucket",
|
||||||
|
"notification-sns1",
|
||||||
|
"aws_sns_topic.topic",
|
||||||
|
[]string{"s3:ObjectCreated:*", "s3:ObjectRemoved:Delete"},
|
||||||
|
nil,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckAWSS3BucketNotificationDestroy(s *terraform.State) error {
|
||||||
|
conn := testAccProvider.Meta().(*AWSClient).s3conn
|
||||||
|
|
||||||
|
for _, rs := range s.RootModule().Resources {
|
||||||
|
if rs.Type != "aws_s3_bucket_notification" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err := resource.Retry(1*time.Minute, func() *resource.RetryError {
|
||||||
|
out, err := conn.GetBucketNotificationConfiguration(&s3.GetBucketNotificationConfigurationRequest{
|
||||||
|
Bucket: aws.String(rs.Primary.ID),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NoSuchBucket" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return resource.NonRetryableError(err)
|
||||||
|
}
|
||||||
|
if len(out.TopicConfigurations) > 0 {
|
||||||
|
return resource.RetryableError(fmt.Errorf("TopicConfigurations is exists: %v", out))
|
||||||
|
}
|
||||||
|
if len(out.LambdaFunctionConfigurations) > 0 {
|
||||||
|
return resource.RetryableError(fmt.Errorf("LambdaFunctionConfigurations is exists: %v", out))
|
||||||
|
}
|
||||||
|
if len(out.QueueConfigurations) > 0 {
|
||||||
|
return resource.RetryableError(fmt.Errorf("QueueConfigurations is exists: %v", out))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckAWSS3BucketTopicNotification(n, i, t string, events []string, filters *s3.KeyFilter) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rs, _ := s.RootModule().Resources[n]
|
||||||
|
topicArn := s.RootModule().Resources[t].Primary.ID
|
||||||
|
conn := testAccProvider.Meta().(*AWSClient).s3conn
|
||||||
|
|
||||||
|
err := resource.Retry(1*time.Minute, func() *resource.RetryError {
|
||||||
|
out, err := conn.GetBucketNotificationConfiguration(&s3.GetBucketNotificationConfigurationRequest{
|
||||||
|
Bucket: aws.String(rs.Primary.ID),
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return resource.NonRetryableError(fmt.Errorf("GetBucketNotification error: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
eventSlice := sort.StringSlice(events)
|
||||||
|
eventSlice.Sort()
|
||||||
|
|
||||||
|
outputTopics := out.TopicConfigurations
|
||||||
|
matched := false
|
||||||
|
for _, outputTopic := range outputTopics {
|
||||||
|
if *outputTopic.Id == i {
|
||||||
|
matched = true
|
||||||
|
|
||||||
|
if *outputTopic.TopicArn != topicArn {
|
||||||
|
return resource.RetryableError(fmt.Errorf("bad topic arn, expected: %s, got %#v", topicArn, *outputTopic.TopicArn))
|
||||||
|
}
|
||||||
|
|
||||||
|
if filters != nil {
|
||||||
|
if !reflect.DeepEqual(filters, outputTopic.Filter.Key) {
|
||||||
|
return resource.RetryableError(fmt.Errorf("bad notification filters, expected: %#v, got %#v", filters, outputTopic.Filter.Key))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if outputTopic.Filter != nil {
|
||||||
|
return resource.RetryableError(fmt.Errorf("bad notification filters, expected: nil, got %#v", outputTopic.Filter))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outputEventSlice := sort.StringSlice(aws.StringValueSlice(outputTopic.Events))
|
||||||
|
outputEventSlice.Sort()
|
||||||
|
if !reflect.DeepEqual(eventSlice, outputEventSlice) {
|
||||||
|
return resource.RetryableError(fmt.Errorf("bad notification events, expected: %#v, got %#v", events, outputEventSlice))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !matched {
|
||||||
|
return resource.RetryableError(fmt.Errorf("No match topic configurations: %#v", out))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckAWSS3BucketQueueNotification(n, i, t string, events []string, filters *s3.KeyFilter) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rs, _ := s.RootModule().Resources[n]
|
||||||
|
queueArn := s.RootModule().Resources[t].Primary.Attributes["arn"]
|
||||||
|
conn := testAccProvider.Meta().(*AWSClient).s3conn
|
||||||
|
|
||||||
|
err := resource.Retry(1*time.Minute, func() *resource.RetryError {
|
||||||
|
out, err := conn.GetBucketNotificationConfiguration(&s3.GetBucketNotificationConfigurationRequest{
|
||||||
|
Bucket: aws.String(rs.Primary.ID),
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return resource.NonRetryableError(fmt.Errorf("GetBucketNotification error: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
eventSlice := sort.StringSlice(events)
|
||||||
|
eventSlice.Sort()
|
||||||
|
|
||||||
|
outputQueues := out.QueueConfigurations
|
||||||
|
matched := false
|
||||||
|
for _, outputQueue := range outputQueues {
|
||||||
|
if *outputQueue.Id == i {
|
||||||
|
matched = true
|
||||||
|
|
||||||
|
if *outputQueue.QueueArn != queueArn {
|
||||||
|
return resource.RetryableError(fmt.Errorf("bad queue arn, expected: %s, got %#v", queueArn, *outputQueue.QueueArn))
|
||||||
|
}
|
||||||
|
|
||||||
|
if filters != nil {
|
||||||
|
if !reflect.DeepEqual(filters, outputQueue.Filter.Key) {
|
||||||
|
return resource.RetryableError(fmt.Errorf("bad notification filters, expected: %#v, got %#v", filters, outputQueue.Filter.Key))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if outputQueue.Filter != nil {
|
||||||
|
return resource.RetryableError(fmt.Errorf("bad notification filters, expected: nil, got %#v", outputQueue.Filter))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outputEventSlice := sort.StringSlice(aws.StringValueSlice(outputQueue.Events))
|
||||||
|
outputEventSlice.Sort()
|
||||||
|
if !reflect.DeepEqual(eventSlice, outputEventSlice) {
|
||||||
|
return resource.RetryableError(fmt.Errorf("bad notification events, expected: %#v, got %#v", events, outputEventSlice))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !matched {
|
||||||
|
return resource.RetryableError(fmt.Errorf("No match queue configurations: %#v", out))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccCheckAWSS3BucketLambdaFunctionConfiguration(n, i, t string, events []string, filters *s3.KeyFilter) resource.TestCheckFunc {
|
||||||
|
return func(s *terraform.State) error {
|
||||||
|
rs, _ := s.RootModule().Resources[n]
|
||||||
|
funcArn := s.RootModule().Resources[t].Primary.Attributes["arn"]
|
||||||
|
conn := testAccProvider.Meta().(*AWSClient).s3conn
|
||||||
|
|
||||||
|
err := resource.Retry(1*time.Minute, func() *resource.RetryError {
|
||||||
|
out, err := conn.GetBucketNotificationConfiguration(&s3.GetBucketNotificationConfigurationRequest{
|
||||||
|
Bucket: aws.String(rs.Primary.ID),
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return resource.NonRetryableError(fmt.Errorf("GetBucketNotification error: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
eventSlice := sort.StringSlice(events)
|
||||||
|
eventSlice.Sort()
|
||||||
|
|
||||||
|
outputFunctions := out.LambdaFunctionConfigurations
|
||||||
|
matched := false
|
||||||
|
for _, outputFunc := range outputFunctions {
|
||||||
|
if *outputFunc.Id == i {
|
||||||
|
matched = true
|
||||||
|
|
||||||
|
if *outputFunc.LambdaFunctionArn != funcArn {
|
||||||
|
return resource.RetryableError(fmt.Errorf("bad lambda function arn, expected: %s, got %#v", funcArn, *outputFunc.LambdaFunctionArn))
|
||||||
|
}
|
||||||
|
|
||||||
|
if filters != nil {
|
||||||
|
if !reflect.DeepEqual(filters, outputFunc.Filter.Key) {
|
||||||
|
return resource.RetryableError(fmt.Errorf("bad notification filters, expected: %#v, got %#v", filters, outputFunc.Filter.Key))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if outputFunc.Filter != nil {
|
||||||
|
return resource.RetryableError(fmt.Errorf("bad notification filters, expected: nil, got %#v", outputFunc.Filter))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
outputEventSlice := sort.StringSlice(aws.StringValueSlice(outputFunc.Events))
|
||||||
|
outputEventSlice.Sort()
|
||||||
|
if !reflect.DeepEqual(eventSlice, outputEventSlice) {
|
||||||
|
return resource.RetryableError(fmt.Errorf("bad notification events, expected: %#v, got %#v", events, outputEventSlice))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !matched {
|
||||||
|
return resource.RetryableError(fmt.Errorf("No match lambda function configurations: %#v", out))
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccAWSS3BucketConfigWithTopicNotification(randInt int) string {
|
||||||
|
return fmt.Sprintf(`
|
||||||
|
resource "aws_sns_topic" "topic" {
|
||||||
|
name = "terraform-test-topic"
|
||||||
|
policy = <<POLICY
|
||||||
|
{
|
||||||
|
"Version":"2012-10-17",
|
||||||
|
"Statement":[{
|
||||||
|
"Sid": "",
|
||||||
|
"Effect": "Allow",
|
||||||
|
"Principal": {"AWS":"*"},
|
||||||
|
"Action": "SNS:Publish",
|
||||||
|
"Resource": "arn:aws:sns:*:*:terraform-test-topic",
|
||||||
|
"Condition":{
|
||||||
|
"ArnLike":{"aws:SourceArn":"${aws_s3_bucket.bucket.arn}"}
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
POLICY
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_s3_bucket" "bucket" {
|
||||||
|
bucket = "tf-test-bucket-%d"
|
||||||
|
acl = "public-read"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_s3_bucket_notification" "notification" {
|
||||||
|
bucket = "${aws_s3_bucket.bucket.id}"
|
||||||
|
topic {
|
||||||
|
id = "notification-sns1"
|
||||||
|
topic_arn = "${aws_sns_topic.topic.arn}"
|
||||||
|
events = [
|
||||||
|
"s3:ObjectCreated:*",
|
||||||
|
"s3:ObjectRemoved:Delete",
|
||||||
|
]
|
||||||
|
filter_prefix = "%d/"
|
||||||
|
filter_suffix = ".txt"
|
||||||
|
}
|
||||||
|
topic {
|
||||||
|
id = "notification-sns2"
|
||||||
|
topic_arn = "${aws_sns_topic.topic.arn}"
|
||||||
|
events = [
|
||||||
|
"s3:ObjectCreated:*",
|
||||||
|
"s3:ObjectRemoved:Delete",
|
||||||
|
]
|
||||||
|
filter_suffix = ".log"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`, randInt, randInt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccAWSS3BucketConfigWithQueueNotification(randInt int) string {
|
||||||
|
return fmt.Sprintf(`
|
||||||
|
resource "aws_sqs_queue" "queue" {
|
||||||
|
name = "terraform-test-queue-%d"
|
||||||
|
policy = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":\"*\",\"Action\":\"sqs:SendMessage\",\"Resource\":\"arn:aws:sqs:*:*:terraform-test-queue-%d\",\"Condition\":{\"ArnEquals\":{\"aws:SourceArn\":\"${aws_s3_bucket.bucket.arn}\"}}}]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_s3_bucket" "bucket" {
|
||||||
|
bucket = "tf-test-bucket-%d"
|
||||||
|
acl = "public-read"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_s3_bucket_notification" "notification" {
|
||||||
|
bucket = "${aws_s3_bucket.bucket.id}"
|
||||||
|
queue {
|
||||||
|
id = "notification-sqs"
|
||||||
|
queue_arn = "${aws_sqs_queue.queue.arn}"
|
||||||
|
events = [
|
||||||
|
"s3:ObjectCreated:*",
|
||||||
|
"s3:ObjectRemoved:Delete",
|
||||||
|
]
|
||||||
|
filter_prefix = "%d/"
|
||||||
|
filter_suffix = ".mp4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`, randInt, randInt, randInt, randInt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccAWSS3BucketConfigWithLambdaNotification(randInt int) string {
|
||||||
|
return fmt.Sprintf(`
|
||||||
|
|
||||||
|
resource "aws_iam_role" "iam_for_lambda" {
|
||||||
|
name = "iam_for_lambda"
|
||||||
|
assume_role_policy = <<EOF
|
||||||
|
{
|
||||||
|
"Version": "2012-10-17",
|
||||||
|
"Statement": [
|
||||||
|
{
|
||||||
|
"Action": "sts:AssumeRole",
|
||||||
|
"Principal": {
|
||||||
|
"Service": "lambda.amazonaws.com"
|
||||||
|
},
|
||||||
|
"Effect": "Allow",
|
||||||
|
"Sid": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_lambda_permission" "allow_bucket" {
|
||||||
|
statement_id = "AllowExecutionFromS3Bucket"
|
||||||
|
action = "lambda:InvokeFunction"
|
||||||
|
function_name = "${aws_lambda_function.func.arn}"
|
||||||
|
principal = "s3.amazonaws.com"
|
||||||
|
source_arn = "${aws_s3_bucket.bucket.arn}"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_lambda_function" "func" {
|
||||||
|
filename = "test-fixtures/lambdatest.zip"
|
||||||
|
function_name = "example_lambda_name"
|
||||||
|
role = "${aws_iam_role.iam_for_lambda.arn}"
|
||||||
|
handler = "exports.example"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_s3_bucket" "bucket" {
|
||||||
|
bucket = "tf-test-bucket-%d"
|
||||||
|
acl = "public-read"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_s3_bucket_notification" "notification" {
|
||||||
|
bucket = "${aws_s3_bucket.bucket.id}"
|
||||||
|
lambda_function {
|
||||||
|
id = "notification-lambda"
|
||||||
|
lambda_function_arn = "${aws_lambda_function.func.arn}"
|
||||||
|
events = [
|
||||||
|
"s3:ObjectCreated:*",
|
||||||
|
"s3:ObjectRemoved:Delete",
|
||||||
|
]
|
||||||
|
filter_prefix = "%d/"
|
||||||
|
filter_suffix = ".png"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`, randInt, randInt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAccAWSS3BucketConfigWithTopicNotificationWithoutFilter(randInt int) string {
|
||||||
|
return fmt.Sprintf(`
|
||||||
|
resource "aws_sns_topic" "topic" {
|
||||||
|
name = "terraform-test-topic"
|
||||||
|
policy = <<POLICY
|
||||||
|
{
|
||||||
|
"Version":"2012-10-17",
|
||||||
|
"Statement":[{
|
||||||
|
"Sid": "",
|
||||||
|
"Effect": "Allow",
|
||||||
|
"Principal": {"AWS":"*"},
|
||||||
|
"Action": "SNS:Publish",
|
||||||
|
"Resource": "arn:aws:sns:*:*:terraform-test-topic",
|
||||||
|
"Condition":{
|
||||||
|
"ArnLike":{"aws:SourceArn":"${aws_s3_bucket.bucket.arn}"}
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
POLICY
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_s3_bucket" "bucket" {
|
||||||
|
bucket = "tf-test-bucket-%d"
|
||||||
|
acl = "public-read"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_s3_bucket_notification" "notification" {
|
||||||
|
bucket = "${aws_s3_bucket.bucket.id}"
|
||||||
|
topic {
|
||||||
|
id = "notification-sns1"
|
||||||
|
topic_arn = "${aws_sns_topic.topic.arn}"
|
||||||
|
events = [
|
||||||
|
"s3:ObjectCreated:*",
|
||||||
|
"s3:ObjectRemoved:Delete",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`, randInt)
|
||||||
|
}
|
|
@ -0,0 +1,170 @@
|
||||||
|
---
|
||||||
|
layout: "aws"
|
||||||
|
page_title: "AWS: aws_s3_bucket_notification"
|
||||||
|
side_bar_current: "docs-aws-resource-s3-bucket-notification"
|
||||||
|
description: |-
|
||||||
|
Provides a S3 bucket notification resource.
|
||||||
|
---
|
||||||
|
|
||||||
|
# aws\_s3\_bucket\_notification
|
||||||
|
|
||||||
|
Provides a S3 bucket notification resource.
|
||||||
|
|
||||||
|
## Example Usage
|
||||||
|
|
||||||
|
### Add notification configuration to SNS Topic
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "aws_sns_topic" "topic" {
|
||||||
|
name = "s3-event-notification-topic"
|
||||||
|
policy = <<POLICY
|
||||||
|
{
|
||||||
|
"Version":"2012-10-17",
|
||||||
|
"Statement":[{
|
||||||
|
"Effect": "Allow",
|
||||||
|
"Principal": {"AWS":"*"},
|
||||||
|
"Action": "SNS:Publish",
|
||||||
|
"Resource": "arn:aws:sns:*:*:s3-event-notification-topic",
|
||||||
|
"Condition":{
|
||||||
|
"ArnLike":{"aws:SourceArn":"${aws_s3_bucket.bucket.arn}"}
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
POLICY
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_s3_bucket" "bucket" {
|
||||||
|
bucket = "your_bucket_name"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_s3_bucket_notification" "bucket_notification" {
|
||||||
|
bucket = "${aws_s3_bucket.bucket.id}"
|
||||||
|
topic {
|
||||||
|
topic_arn = "${aws_sns_topic.topic.arn}"
|
||||||
|
events = ["s3:ObjectCreated:*"]
|
||||||
|
filter_suffix = ".log"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add notification configuration to SQS Queue
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "aws_sqs_queue" "queue" {
|
||||||
|
name = "s3-event-notification-queue"
|
||||||
|
policy = <<POLICY
|
||||||
|
{
|
||||||
|
"Version": "2012-10-17",
|
||||||
|
"Statement": [
|
||||||
|
{
|
||||||
|
"Effect": "Allow",
|
||||||
|
"Principal": "*",
|
||||||
|
"Action": "sqs:SendMessage",
|
||||||
|
"Resource": "arn:aws:sqs:*:*:s3-event-notification-queue",
|
||||||
|
"Condition": {
|
||||||
|
"ArnEquals": { "aws:SourceArn": "${aws_s3_bucket.bucket.arn}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
POLICY
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_s3_bucket" "bucket" {
|
||||||
|
bucket = "your_bucket_name"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_s3_bucket_notification" "bucket_notification" {
|
||||||
|
bucket = "${aws_s3_bucket.bucket.id}"
|
||||||
|
queue {
|
||||||
|
queue_arn = "${aws_sqs_queue.queue.arn}"
|
||||||
|
events = ["s3:ObjectCreated:*"]
|
||||||
|
filter_suffix = ".log"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Add notification configuration to Lambda Function
|
||||||
|
|
||||||
|
```
|
||||||
|
resource "aws_iam_role" "iam_for_lambda" {
|
||||||
|
name = "iam_for_lambda"
|
||||||
|
assume_role_policy = <<EOF
|
||||||
|
{
|
||||||
|
"Version": "2012-10-17",
|
||||||
|
"Statement": [
|
||||||
|
{
|
||||||
|
"Action": "sts:AssumeRole",
|
||||||
|
"Principal": {
|
||||||
|
"Service": "lambda.amazonaws.com"
|
||||||
|
},
|
||||||
|
"Effect": "Allow"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_lambda_permission" "allow_bucket" {
|
||||||
|
statement_id = "AllowExecutionFromS3Bucket"
|
||||||
|
action = "lambda:InvokeFunction"
|
||||||
|
function_name = "${aws_lambda_function.func.arn}"
|
||||||
|
principal = "s3.amazonaws.com"
|
||||||
|
source_arn = "${aws_s3_bucket.bucket.arn}"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_lambda_function" "func" {
|
||||||
|
filename = "your-function.zip"
|
||||||
|
function_name = "example_lambda_name"
|
||||||
|
role = "${aws_iam_role.iam_for_lambda.arn}"
|
||||||
|
handler = "exports.example"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_s3_bucket" "bucket" {
|
||||||
|
bucket = "your_bucket_name"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_s3_bucket_notification" "bucket_notification" {
|
||||||
|
bucket = "${aws_s3_bucket.bucket.id}"
|
||||||
|
lambda_function {
|
||||||
|
lambda_function_arn = "${aws_lambda_function.func.arn}"
|
||||||
|
events = ["s3:ObjectCreated:*"]
|
||||||
|
filter_prefix = "AWSLogs/"
|
||||||
|
filter_suffix = ".log"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Argument Reference
|
||||||
|
|
||||||
|
The following arguments are supported:
|
||||||
|
|
||||||
|
* `bucket` - (Required) The name of the bucket to put notification configuration.
|
||||||
|
* `topic` - (Optional) The notification configuration to SNS Topic (documented below).
|
||||||
|
* `queue` - (Optional) The notification configuration to SQS Queue (documented below).
|
||||||
|
* `lambda_function` - (Optional) The notification configuration to Lambda Function (documented below).
|
||||||
|
|
||||||
|
The `topic` notification configuration supports the following:
|
||||||
|
|
||||||
|
* `id` - (Optional) Specifies unique identifier for each of the notification configurations.
|
||||||
|
* `topic_arn` - (Required) Specifies Amazon SNS topic ARN.
|
||||||
|
* `events` - (Required) Specifies [event](http://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html#notification-how-to-event-types-and-destinations) for which to send notifications.
|
||||||
|
* `filter_prefix` - (Optional) Specifies object key name prefix.
|
||||||
|
* `filter_suffix` - (Optional) Specifies object key name suffix.
|
||||||
|
|
||||||
|
The `queue` notification configuration supports the following:
|
||||||
|
|
||||||
|
* `id` - (Optional) Specifies unique identifier for each of the notification configurations.
|
||||||
|
* `queue_arn` - (Required) Specifies Amazon SQS queue ARN.
|
||||||
|
* `events` - (Required) Specifies [event](http://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html#notification-how-to-event-types-and-destinations) for which to send notifications.
|
||||||
|
* `filter_prefix` - (Optional) Specifies object key name prefix.
|
||||||
|
* `filter_suffix` - (Optional) Specifies object key name suffix.
|
||||||
|
|
||||||
|
The `lambda_function` notification configuration supports the following:
|
||||||
|
|
||||||
|
* `id` - (Optional) Specifies unique identifier for each of the notification configurations.
|
||||||
|
* `lambda_function_arn` - (Required) Specifies Amazon Lambda function ARN.
|
||||||
|
* `events` - (Required) Specifies [event](http://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html#notification-how-to-event-types-and-destinations) for which to send notifications.
|
||||||
|
* `filter_prefix` - (Optional) Specifies object key name prefix.
|
||||||
|
* `filter_suffix` - (Optional) Specifies object key name suffix.
|
||||||
|
|
|
@ -596,6 +596,10 @@
|
||||||
<a href="/docs/providers/aws/r/s3_bucket_object.html">aws_s3_bucket_object</a>
|
<a href="/docs/providers/aws/r/s3_bucket_object.html">aws_s3_bucket_object</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li<%= sidebar_current("docs-aws-resource-s3-bucket-notification") %>>
|
||||||
|
<a href="/docs/providers/aws/r/s3_bucket_notification.html">aws_s3_bucket_notification</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue