github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/aws/resource_aws_s3_bucket_notification_test.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "reflect" 6 "sort" 7 "testing" 8 "time" 9 10 "github.com/hashicorp/terraform/helper/acctest" 11 "github.com/hashicorp/terraform/helper/resource" 12 "github.com/hashicorp/terraform/terraform" 13 14 "github.com/aws/aws-sdk-go/aws" 15 "github.com/aws/aws-sdk-go/aws/awserr" 16 "github.com/aws/aws-sdk-go/service/s3" 17 ) 18 19 func TestAccAWSS3Bucket_Notification(t *testing.T) { 20 rInt := acctest.RandInt() 21 resource.Test(t, resource.TestCase{ 22 PreCheck: func() { testAccPreCheck(t) }, 23 Providers: testAccProviders, 24 CheckDestroy: testAccCheckAWSS3BucketNotificationDestroy, 25 Steps: []resource.TestStep{ 26 resource.TestStep{ 27 Config: testAccAWSS3BucketConfigWithTopicNotification(rInt), 28 Check: resource.ComposeTestCheckFunc( 29 testAccCheckAWSS3BucketTopicNotification( 30 "aws_s3_bucket.bucket", 31 "notification-sns1", 32 "aws_sns_topic.topic", 33 []string{"s3:ObjectCreated:*", "s3:ObjectRemoved:Delete"}, 34 &s3.KeyFilter{ 35 FilterRules: []*s3.FilterRule{ 36 &s3.FilterRule{ 37 Name: aws.String("Prefix"), 38 Value: aws.String(fmt.Sprintf("%d/", rInt)), 39 }, 40 &s3.FilterRule{ 41 Name: aws.String("Suffix"), 42 Value: aws.String(".txt"), 43 }, 44 }, 45 }, 46 ), 47 testAccCheckAWSS3BucketTopicNotification( 48 "aws_s3_bucket.bucket", 49 "notification-sns2", 50 "aws_sns_topic.topic", 51 []string{"s3:ObjectCreated:*", "s3:ObjectRemoved:Delete"}, 52 &s3.KeyFilter{ 53 FilterRules: []*s3.FilterRule{ 54 &s3.FilterRule{ 55 Name: aws.String("Suffix"), 56 Value: aws.String(".log"), 57 }, 58 }, 59 }, 60 ), 61 ), 62 }, 63 resource.TestStep{ 64 Config: testAccAWSS3BucketConfigWithQueueNotification(rInt), 65 Check: resource.ComposeTestCheckFunc( 66 testAccCheckAWSS3BucketQueueNotification( 67 "aws_s3_bucket.bucket", 68 "notification-sqs", 69 "aws_sqs_queue.queue", 70 []string{"s3:ObjectCreated:*", "s3:ObjectRemoved:Delete"}, 71 &s3.KeyFilter{ 72 FilterRules: []*s3.FilterRule{ 73 &s3.FilterRule{ 74 Name: aws.String("Prefix"), 75 Value: aws.String(fmt.Sprintf("%d/", rInt)), 76 }, 77 &s3.FilterRule{ 78 Name: aws.String("Suffix"), 79 Value: aws.String(".mp4"), 80 }, 81 }, 82 }, 83 ), 84 ), 85 }, 86 resource.TestStep{ 87 Config: testAccAWSS3BucketConfigWithLambdaNotification(rInt), 88 Check: resource.ComposeTestCheckFunc( 89 testAccCheckAWSS3BucketLambdaFunctionConfiguration( 90 "aws_s3_bucket.bucket", 91 "notification-lambda", 92 "aws_lambda_function.func", 93 []string{"s3:ObjectCreated:*", "s3:ObjectRemoved:Delete"}, 94 &s3.KeyFilter{ 95 FilterRules: []*s3.FilterRule{ 96 &s3.FilterRule{ 97 Name: aws.String("Prefix"), 98 Value: aws.String(fmt.Sprintf("%d/", rInt)), 99 }, 100 &s3.FilterRule{ 101 Name: aws.String("Suffix"), 102 Value: aws.String(".png"), 103 }, 104 }, 105 }, 106 ), 107 ), 108 }, 109 }, 110 }) 111 } 112 113 func TestAccAWSS3Bucket_NotificationWithoutFilter(t *testing.T) { 114 rInt := acctest.RandInt() 115 resource.Test(t, resource.TestCase{ 116 PreCheck: func() { testAccPreCheck(t) }, 117 Providers: testAccProviders, 118 CheckDestroy: testAccCheckAWSS3BucketNotificationDestroy, 119 Steps: []resource.TestStep{ 120 resource.TestStep{ 121 Config: testAccAWSS3BucketConfigWithTopicNotificationWithoutFilter(rInt), 122 Check: resource.ComposeTestCheckFunc( 123 testAccCheckAWSS3BucketTopicNotification( 124 "aws_s3_bucket.bucket", 125 "notification-sns1", 126 "aws_sns_topic.topic", 127 []string{"s3:ObjectCreated:*", "s3:ObjectRemoved:Delete"}, 128 nil, 129 ), 130 ), 131 }, 132 }, 133 }) 134 } 135 136 func testAccCheckAWSS3BucketNotificationDestroy(s *terraform.State) error { 137 conn := testAccProvider.Meta().(*AWSClient).s3conn 138 139 for _, rs := range s.RootModule().Resources { 140 if rs.Type != "aws_s3_bucket_notification" { 141 continue 142 } 143 err := resource.Retry(1*time.Minute, func() *resource.RetryError { 144 out, err := conn.GetBucketNotificationConfiguration(&s3.GetBucketNotificationConfigurationRequest{ 145 Bucket: aws.String(rs.Primary.ID), 146 }) 147 if err != nil { 148 if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NoSuchBucket" { 149 return nil 150 } 151 return resource.NonRetryableError(err) 152 } 153 if len(out.TopicConfigurations) > 0 { 154 return resource.RetryableError(fmt.Errorf("TopicConfigurations is exists: %v", out)) 155 } 156 if len(out.LambdaFunctionConfigurations) > 0 { 157 return resource.RetryableError(fmt.Errorf("LambdaFunctionConfigurations is exists: %v", out)) 158 } 159 if len(out.QueueConfigurations) > 0 { 160 return resource.RetryableError(fmt.Errorf("QueueConfigurations is exists: %v", out)) 161 } 162 163 return nil 164 }) 165 166 if err != nil { 167 return err 168 } 169 } 170 return nil 171 } 172 173 func testAccCheckAWSS3BucketTopicNotification(n, i, t string, events []string, filters *s3.KeyFilter) resource.TestCheckFunc { 174 return func(s *terraform.State) error { 175 rs, _ := s.RootModule().Resources[n] 176 topicArn := s.RootModule().Resources[t].Primary.ID 177 conn := testAccProvider.Meta().(*AWSClient).s3conn 178 179 err := resource.Retry(1*time.Minute, func() *resource.RetryError { 180 out, err := conn.GetBucketNotificationConfiguration(&s3.GetBucketNotificationConfigurationRequest{ 181 Bucket: aws.String(rs.Primary.ID), 182 }) 183 184 if err != nil { 185 return resource.NonRetryableError(fmt.Errorf("GetBucketNotification error: %v", err)) 186 } 187 188 eventSlice := sort.StringSlice(events) 189 eventSlice.Sort() 190 191 outputTopics := out.TopicConfigurations 192 matched := false 193 for _, outputTopic := range outputTopics { 194 if *outputTopic.Id == i { 195 matched = true 196 197 if *outputTopic.TopicArn != topicArn { 198 return resource.RetryableError(fmt.Errorf("bad topic arn, expected: %s, got %#v", topicArn, *outputTopic.TopicArn)) 199 } 200 201 if filters != nil { 202 if !reflect.DeepEqual(filters, outputTopic.Filter.Key) { 203 return resource.RetryableError(fmt.Errorf("bad notification filters, expected: %#v, got %#v", filters, outputTopic.Filter.Key)) 204 } 205 } else { 206 if outputTopic.Filter != nil { 207 return resource.RetryableError(fmt.Errorf("bad notification filters, expected: nil, got %#v", outputTopic.Filter)) 208 } 209 } 210 211 outputEventSlice := sort.StringSlice(aws.StringValueSlice(outputTopic.Events)) 212 outputEventSlice.Sort() 213 if !reflect.DeepEqual(eventSlice, outputEventSlice) { 214 return resource.RetryableError(fmt.Errorf("bad notification events, expected: %#v, got %#v", events, outputEventSlice)) 215 } 216 } 217 } 218 219 if !matched { 220 return resource.RetryableError(fmt.Errorf("No match topic configurations: %#v", out)) 221 } 222 223 return nil 224 }) 225 226 return err 227 } 228 } 229 230 func testAccCheckAWSS3BucketQueueNotification(n, i, t string, events []string, filters *s3.KeyFilter) resource.TestCheckFunc { 231 return func(s *terraform.State) error { 232 rs, _ := s.RootModule().Resources[n] 233 queueArn := s.RootModule().Resources[t].Primary.Attributes["arn"] 234 conn := testAccProvider.Meta().(*AWSClient).s3conn 235 236 err := resource.Retry(1*time.Minute, func() *resource.RetryError { 237 out, err := conn.GetBucketNotificationConfiguration(&s3.GetBucketNotificationConfigurationRequest{ 238 Bucket: aws.String(rs.Primary.ID), 239 }) 240 241 if err != nil { 242 return resource.NonRetryableError(fmt.Errorf("GetBucketNotification error: %v", err)) 243 } 244 245 eventSlice := sort.StringSlice(events) 246 eventSlice.Sort() 247 248 outputQueues := out.QueueConfigurations 249 matched := false 250 for _, outputQueue := range outputQueues { 251 if *outputQueue.Id == i { 252 matched = true 253 254 if *outputQueue.QueueArn != queueArn { 255 return resource.RetryableError(fmt.Errorf("bad queue arn, expected: %s, got %#v", queueArn, *outputQueue.QueueArn)) 256 } 257 258 if filters != nil { 259 if !reflect.DeepEqual(filters, outputQueue.Filter.Key) { 260 return resource.RetryableError(fmt.Errorf("bad notification filters, expected: %#v, got %#v", filters, outputQueue.Filter.Key)) 261 } 262 } else { 263 if outputQueue.Filter != nil { 264 return resource.RetryableError(fmt.Errorf("bad notification filters, expected: nil, got %#v", outputQueue.Filter)) 265 } 266 } 267 268 outputEventSlice := sort.StringSlice(aws.StringValueSlice(outputQueue.Events)) 269 outputEventSlice.Sort() 270 if !reflect.DeepEqual(eventSlice, outputEventSlice) { 271 return resource.RetryableError(fmt.Errorf("bad notification events, expected: %#v, got %#v", events, outputEventSlice)) 272 } 273 } 274 } 275 276 if !matched { 277 return resource.RetryableError(fmt.Errorf("No match queue configurations: %#v", out)) 278 } 279 280 return nil 281 }) 282 283 return err 284 } 285 } 286 287 func testAccCheckAWSS3BucketLambdaFunctionConfiguration(n, i, t string, events []string, filters *s3.KeyFilter) resource.TestCheckFunc { 288 return func(s *terraform.State) error { 289 rs, _ := s.RootModule().Resources[n] 290 funcArn := s.RootModule().Resources[t].Primary.Attributes["arn"] 291 conn := testAccProvider.Meta().(*AWSClient).s3conn 292 293 err := resource.Retry(1*time.Minute, func() *resource.RetryError { 294 out, err := conn.GetBucketNotificationConfiguration(&s3.GetBucketNotificationConfigurationRequest{ 295 Bucket: aws.String(rs.Primary.ID), 296 }) 297 298 if err != nil { 299 return resource.NonRetryableError(fmt.Errorf("GetBucketNotification error: %v", err)) 300 } 301 302 eventSlice := sort.StringSlice(events) 303 eventSlice.Sort() 304 305 outputFunctions := out.LambdaFunctionConfigurations 306 matched := false 307 for _, outputFunc := range outputFunctions { 308 if *outputFunc.Id == i { 309 matched = true 310 311 if *outputFunc.LambdaFunctionArn != funcArn { 312 return resource.RetryableError(fmt.Errorf("bad lambda function arn, expected: %s, got %#v", funcArn, *outputFunc.LambdaFunctionArn)) 313 } 314 315 if filters != nil { 316 if !reflect.DeepEqual(filters, outputFunc.Filter.Key) { 317 return resource.RetryableError(fmt.Errorf("bad notification filters, expected: %#v, got %#v", filters, outputFunc.Filter.Key)) 318 } 319 } else { 320 if outputFunc.Filter != nil { 321 return resource.RetryableError(fmt.Errorf("bad notification filters, expected: nil, got %#v", outputFunc.Filter)) 322 } 323 } 324 325 outputEventSlice := sort.StringSlice(aws.StringValueSlice(outputFunc.Events)) 326 outputEventSlice.Sort() 327 if !reflect.DeepEqual(eventSlice, outputEventSlice) { 328 return resource.RetryableError(fmt.Errorf("bad notification events, expected: %#v, got %#v", events, outputEventSlice)) 329 } 330 } 331 } 332 333 if !matched { 334 return resource.RetryableError(fmt.Errorf("No match lambda function configurations: %#v", out)) 335 } 336 337 return nil 338 }) 339 340 return err 341 } 342 } 343 344 func testAccAWSS3BucketConfigWithTopicNotification(randInt int) string { 345 return fmt.Sprintf(` 346 resource "aws_sns_topic" "topic" { 347 name = "terraform-test-topic" 348 policy = <<POLICY 349 { 350 "Version":"2012-10-17", 351 "Statement":[{ 352 "Sid": "", 353 "Effect": "Allow", 354 "Principal": {"AWS":"*"}, 355 "Action": "SNS:Publish", 356 "Resource": "arn:aws:sns:*:*:terraform-test-topic", 357 "Condition":{ 358 "ArnLike":{"aws:SourceArn":"${aws_s3_bucket.bucket.arn}"} 359 } 360 }] 361 } 362 POLICY 363 } 364 365 resource "aws_s3_bucket" "bucket" { 366 bucket = "tf-test-bucket-%d" 367 acl = "public-read" 368 } 369 370 resource "aws_s3_bucket_notification" "notification" { 371 bucket = "${aws_s3_bucket.bucket.id}" 372 topic { 373 id = "notification-sns1" 374 topic_arn = "${aws_sns_topic.topic.arn}" 375 events = [ 376 "s3:ObjectCreated:*", 377 "s3:ObjectRemoved:Delete", 378 ] 379 filter_prefix = "%d/" 380 filter_suffix = ".txt" 381 } 382 topic { 383 id = "notification-sns2" 384 topic_arn = "${aws_sns_topic.topic.arn}" 385 events = [ 386 "s3:ObjectCreated:*", 387 "s3:ObjectRemoved:Delete", 388 ] 389 filter_suffix = ".log" 390 } 391 } 392 `, randInt, randInt) 393 } 394 395 func testAccAWSS3BucketConfigWithQueueNotification(randInt int) string { 396 return fmt.Sprintf(` 397 resource "aws_sqs_queue" "queue" { 398 name = "terraform-test-queue-%d" 399 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}\"}}}]}" 400 } 401 402 resource "aws_s3_bucket" "bucket" { 403 bucket = "tf-test-bucket-%d" 404 acl = "public-read" 405 } 406 407 resource "aws_s3_bucket_notification" "notification" { 408 bucket = "${aws_s3_bucket.bucket.id}" 409 queue { 410 id = "notification-sqs" 411 queue_arn = "${aws_sqs_queue.queue.arn}" 412 events = [ 413 "s3:ObjectCreated:*", 414 "s3:ObjectRemoved:Delete", 415 ] 416 filter_prefix = "%d/" 417 filter_suffix = ".mp4" 418 } 419 } 420 `, randInt, randInt, randInt, randInt) 421 } 422 423 func testAccAWSS3BucketConfigWithLambdaNotification(randInt int) string { 424 return fmt.Sprintf(` 425 426 resource "aws_iam_role" "iam_for_lambda" { 427 name = "iam_for_lambda" 428 assume_role_policy = <<EOF 429 { 430 "Version": "2012-10-17", 431 "Statement": [ 432 { 433 "Action": "sts:AssumeRole", 434 "Principal": { 435 "Service": "lambda.amazonaws.com" 436 }, 437 "Effect": "Allow", 438 "Sid": "" 439 } 440 ] 441 } 442 EOF 443 } 444 445 resource "aws_lambda_permission" "allow_bucket" { 446 statement_id = "AllowExecutionFromS3Bucket" 447 action = "lambda:InvokeFunction" 448 function_name = "${aws_lambda_function.func.arn}" 449 principal = "s3.amazonaws.com" 450 source_arn = "${aws_s3_bucket.bucket.arn}" 451 } 452 453 resource "aws_lambda_function" "func" { 454 filename = "test-fixtures/lambdatest.zip" 455 function_name = "example_lambda_name_%d" 456 role = "${aws_iam_role.iam_for_lambda.arn}" 457 handler = "exports.example" 458 runtime = "nodejs4.3" 459 } 460 461 resource "aws_s3_bucket" "bucket" { 462 bucket = "tf-test-bucket-%d" 463 acl = "public-read" 464 } 465 466 resource "aws_s3_bucket_notification" "notification" { 467 bucket = "${aws_s3_bucket.bucket.id}" 468 lambda_function { 469 id = "notification-lambda" 470 lambda_function_arn = "${aws_lambda_function.func.arn}" 471 events = [ 472 "s3:ObjectCreated:*", 473 "s3:ObjectRemoved:Delete", 474 ] 475 filter_prefix = "%d/" 476 filter_suffix = ".png" 477 } 478 } 479 `, randInt, randInt, randInt) 480 } 481 482 func testAccAWSS3BucketConfigWithTopicNotificationWithoutFilter(randInt int) string { 483 return fmt.Sprintf(` 484 resource "aws_sns_topic" "topic" { 485 name = "terraform-test-topic" 486 policy = <<POLICY 487 { 488 "Version":"2012-10-17", 489 "Statement":[{ 490 "Sid": "", 491 "Effect": "Allow", 492 "Principal": {"AWS":"*"}, 493 "Action": "SNS:Publish", 494 "Resource": "arn:aws:sns:*:*:terraform-test-topic", 495 "Condition":{ 496 "ArnLike":{"aws:SourceArn":"${aws_s3_bucket.bucket.arn}"} 497 } 498 }] 499 } 500 POLICY 501 } 502 503 resource "aws_s3_bucket" "bucket" { 504 bucket = "tf-test-bucket-%d" 505 acl = "public-read" 506 } 507 508 resource "aws_s3_bucket_notification" "notification" { 509 bucket = "${aws_s3_bucket.bucket.id}" 510 topic { 511 id = "notification-sns1" 512 topic_arn = "${aws_sns_topic.topic.arn}" 513 events = [ 514 "s3:ObjectCreated:*", 515 "s3:ObjectRemoved:Delete", 516 ] 517 } 518 } 519 `, randInt) 520 }