github.com/leeprovoost/terraform@v0.6.10-0.20160119085442-96f3f76118e7/builtin/providers/aws/resource_aws_s3_bucket_test.go (about) 1 package aws 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "math/rand" 7 "reflect" 8 "regexp" 9 "strconv" 10 "testing" 11 "time" 12 13 "github.com/hashicorp/terraform/helper/resource" 14 "github.com/hashicorp/terraform/terraform" 15 16 "github.com/aws/aws-sdk-go/aws" 17 "github.com/aws/aws-sdk-go/aws/awserr" 18 "github.com/aws/aws-sdk-go/service/s3" 19 ) 20 21 func TestAccAWSS3Bucket_basic(t *testing.T) { 22 23 arnRegexp := regexp.MustCompile( 24 "^arn:aws:s3:::") 25 26 resource.Test(t, resource.TestCase{ 27 PreCheck: func() { testAccPreCheck(t) }, 28 Providers: testAccProviders, 29 CheckDestroy: testAccCheckAWSS3BucketDestroy, 30 Steps: []resource.TestStep{ 31 resource.TestStep{ 32 Config: testAccAWSS3BucketConfig, 33 Check: resource.ComposeTestCheckFunc( 34 testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"), 35 resource.TestCheckResourceAttr( 36 "aws_s3_bucket.bucket", "hosted_zone_id", HostedZoneIDForRegion("us-west-2")), 37 resource.TestCheckResourceAttr( 38 "aws_s3_bucket.bucket", "region", "us-west-2"), 39 resource.TestCheckResourceAttr( 40 "aws_s3_bucket.bucket", "website_endpoint", ""), 41 resource.TestMatchResourceAttr( 42 "aws_s3_bucket.bucket", "arn", arnRegexp), 43 ), 44 }, 45 }, 46 }) 47 } 48 49 func TestAccAWSS3Bucket_Policy(t *testing.T) { 50 resource.Test(t, resource.TestCase{ 51 PreCheck: func() { testAccPreCheck(t) }, 52 Providers: testAccProviders, 53 CheckDestroy: testAccCheckAWSS3BucketDestroy, 54 Steps: []resource.TestStep{ 55 resource.TestStep{ 56 Config: testAccAWSS3BucketConfigWithPolicy, 57 Check: resource.ComposeTestCheckFunc( 58 testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"), 59 testAccCheckAWSS3BucketPolicy( 60 "aws_s3_bucket.bucket", testAccAWSS3BucketPolicy), 61 ), 62 }, 63 resource.TestStep{ 64 Config: testAccAWSS3BucketConfig, 65 Check: resource.ComposeTestCheckFunc( 66 testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"), 67 testAccCheckAWSS3BucketPolicy( 68 "aws_s3_bucket.bucket", ""), 69 ), 70 }, 71 }, 72 }) 73 } 74 75 func TestAccAWSS3Bucket_UpdateAcl(t *testing.T) { 76 77 ri := genRandInt() 78 preConfig := fmt.Sprintf(testAccAWSS3BucketConfigWithAcl, ri) 79 postConfig := fmt.Sprintf(testAccAWSS3BucketConfigWithAclUpdate, ri) 80 81 resource.Test(t, resource.TestCase{ 82 PreCheck: func() { testAccPreCheck(t) }, 83 Providers: testAccProviders, 84 CheckDestroy: testAccCheckAWSS3BucketDestroy, 85 Steps: []resource.TestStep{ 86 resource.TestStep{ 87 Config: preConfig, 88 Check: resource.ComposeTestCheckFunc( 89 testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"), 90 resource.TestCheckResourceAttr( 91 "aws_s3_bucket.bucket", "acl", "public-read"), 92 ), 93 }, 94 resource.TestStep{ 95 Config: postConfig, 96 Check: resource.ComposeTestCheckFunc( 97 testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"), 98 resource.TestCheckResourceAttr( 99 "aws_s3_bucket.bucket", "acl", "private"), 100 ), 101 }, 102 }, 103 }) 104 } 105 106 func TestAccAWSS3Bucket_Website_Simple(t *testing.T) { 107 resource.Test(t, resource.TestCase{ 108 PreCheck: func() { testAccPreCheck(t) }, 109 Providers: testAccProviders, 110 CheckDestroy: testAccCheckAWSS3BucketDestroy, 111 Steps: []resource.TestStep{ 112 resource.TestStep{ 113 Config: testAccAWSS3BucketWebsiteConfig, 114 Check: resource.ComposeTestCheckFunc( 115 testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"), 116 testAccCheckAWSS3BucketWebsite( 117 "aws_s3_bucket.bucket", "index.html", "", ""), 118 resource.TestCheckResourceAttr( 119 "aws_s3_bucket.bucket", "website_endpoint", testAccWebsiteEndpoint), 120 ), 121 }, 122 resource.TestStep{ 123 Config: testAccAWSS3BucketWebsiteConfigWithError, 124 Check: resource.ComposeTestCheckFunc( 125 testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"), 126 testAccCheckAWSS3BucketWebsite( 127 "aws_s3_bucket.bucket", "index.html", "error.html", ""), 128 resource.TestCheckResourceAttr( 129 "aws_s3_bucket.bucket", "website_endpoint", testAccWebsiteEndpoint), 130 ), 131 }, 132 resource.TestStep{ 133 Config: testAccAWSS3BucketConfig, 134 Check: resource.ComposeTestCheckFunc( 135 testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"), 136 testAccCheckAWSS3BucketWebsite( 137 "aws_s3_bucket.bucket", "", "", ""), 138 resource.TestCheckResourceAttr( 139 "aws_s3_bucket.bucket", "website_endpoint", ""), 140 ), 141 }, 142 }, 143 }) 144 } 145 146 func TestAccAWSS3Bucket_WebsiteRedirect(t *testing.T) { 147 resource.Test(t, resource.TestCase{ 148 PreCheck: func() { testAccPreCheck(t) }, 149 Providers: testAccProviders, 150 CheckDestroy: testAccCheckAWSS3BucketDestroy, 151 Steps: []resource.TestStep{ 152 resource.TestStep{ 153 Config: testAccAWSS3BucketWebsiteConfigWithRedirect, 154 Check: resource.ComposeTestCheckFunc( 155 testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"), 156 testAccCheckAWSS3BucketWebsite( 157 "aws_s3_bucket.bucket", "", "", "hashicorp.com"), 158 resource.TestCheckResourceAttr( 159 "aws_s3_bucket.bucket", "website_endpoint", testAccWebsiteEndpoint), 160 ), 161 }, 162 resource.TestStep{ 163 Config: testAccAWSS3BucketConfig, 164 Check: resource.ComposeTestCheckFunc( 165 testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"), 166 testAccCheckAWSS3BucketWebsite( 167 "aws_s3_bucket.bucket", "", "", ""), 168 resource.TestCheckResourceAttr( 169 "aws_s3_bucket.bucket", "website_endpoint", ""), 170 ), 171 }, 172 }, 173 }) 174 } 175 176 // Test TestAccAWSS3Bucket_shouldFailNotFound is designed to fail with a "plan 177 // not empty" error in Terraform, to check against regresssions. 178 // See https://github.com/hashicorp/terraform/pull/2925 179 func TestAccAWSS3Bucket_shouldFailNotFound(t *testing.T) { 180 resource.Test(t, resource.TestCase{ 181 PreCheck: func() { testAccPreCheck(t) }, 182 Providers: testAccProviders, 183 CheckDestroy: testAccCheckAWSS3BucketDestroy, 184 Steps: []resource.TestStep{ 185 resource.TestStep{ 186 Config: testAccAWSS3BucketDestroyedConfig, 187 Check: resource.ComposeTestCheckFunc( 188 testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"), 189 testAccCheckAWSS3DestroyBucket("aws_s3_bucket.bucket"), 190 ), 191 ExpectNonEmptyPlan: true, 192 }, 193 }, 194 }) 195 } 196 197 func TestAccAWSS3Bucket_Versioning(t *testing.T) { 198 resource.Test(t, resource.TestCase{ 199 PreCheck: func() { testAccPreCheck(t) }, 200 Providers: testAccProviders, 201 CheckDestroy: testAccCheckAWSS3BucketDestroy, 202 Steps: []resource.TestStep{ 203 resource.TestStep{ 204 Config: testAccAWSS3BucketConfig, 205 Check: resource.ComposeTestCheckFunc( 206 testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"), 207 testAccCheckAWSS3BucketVersioning( 208 "aws_s3_bucket.bucket", ""), 209 ), 210 }, 211 resource.TestStep{ 212 Config: testAccAWSS3BucketConfigWithVersioning, 213 Check: resource.ComposeTestCheckFunc( 214 testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"), 215 testAccCheckAWSS3BucketVersioning( 216 "aws_s3_bucket.bucket", s3.BucketVersioningStatusEnabled), 217 ), 218 }, 219 resource.TestStep{ 220 Config: testAccAWSS3BucketConfigWithDisableVersioning, 221 Check: resource.ComposeTestCheckFunc( 222 testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"), 223 testAccCheckAWSS3BucketVersioning( 224 "aws_s3_bucket.bucket", s3.BucketVersioningStatusSuspended), 225 ), 226 }, 227 }, 228 }) 229 } 230 231 func TestAccAWSS3Bucket_Cors(t *testing.T) { 232 resource.Test(t, resource.TestCase{ 233 PreCheck: func() { testAccPreCheck(t) }, 234 Providers: testAccProviders, 235 CheckDestroy: testAccCheckAWSS3BucketDestroy, 236 Steps: []resource.TestStep{ 237 resource.TestStep{ 238 Config: testAccAWSS3BucketConfigWithCORS, 239 Check: resource.ComposeTestCheckFunc( 240 testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"), 241 testAccCheckAWSS3BucketCors( 242 "aws_s3_bucket.bucket", 243 []*s3.CORSRule{ 244 &s3.CORSRule{ 245 AllowedHeaders: []*string{aws.String("*")}, 246 AllowedMethods: []*string{aws.String("PUT"), aws.String("POST")}, 247 AllowedOrigins: []*string{aws.String("https://www.example.com")}, 248 ExposeHeaders: []*string{aws.String("x-amz-server-side-encryption"), aws.String("ETag")}, 249 MaxAgeSeconds: aws.Int64(3000), 250 }, 251 }, 252 ), 253 ), 254 }, 255 }, 256 }) 257 } 258 259 func TestAccAWSS3Bucket_Logging(t *testing.T) { 260 resource.Test(t, resource.TestCase{ 261 PreCheck: func() { testAccPreCheck(t) }, 262 Providers: testAccProviders, 263 CheckDestroy: testAccCheckAWSS3BucketDestroy, 264 Steps: []resource.TestStep{ 265 resource.TestStep{ 266 Config: testAccAWSS3BucketConfigWithLogging, 267 Check: resource.ComposeTestCheckFunc( 268 testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"), 269 testAccCheckAWSS3BucketLogging( 270 "aws_s3_bucket.bucket", "aws_s3_bucket.log_bucket", "log/"), 271 ), 272 }, 273 }, 274 }) 275 } 276 277 func testAccCheckAWSS3BucketDestroy(s *terraform.State) error { 278 conn := testAccProvider.Meta().(*AWSClient).s3conn 279 280 for _, rs := range s.RootModule().Resources { 281 if rs.Type != "aws_s3_bucket" { 282 continue 283 } 284 _, err := conn.DeleteBucket(&s3.DeleteBucketInput{ 285 Bucket: aws.String(rs.Primary.ID), 286 }) 287 if err != nil { 288 if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NoSuchBucket" { 289 return nil 290 } 291 return err 292 } 293 } 294 return nil 295 } 296 297 func testAccCheckAWSS3BucketExists(n string) resource.TestCheckFunc { 298 return func(s *terraform.State) error { 299 rs, ok := s.RootModule().Resources[n] 300 if !ok { 301 return fmt.Errorf("Not found: %s", n) 302 } 303 304 if rs.Primary.ID == "" { 305 return fmt.Errorf("No S3 Bucket ID is set") 306 } 307 308 conn := testAccProvider.Meta().(*AWSClient).s3conn 309 _, err := conn.HeadBucket(&s3.HeadBucketInput{ 310 Bucket: aws.String(rs.Primary.ID), 311 }) 312 313 if err != nil { 314 return fmt.Errorf("S3Bucket error: %v", err) 315 } 316 return nil 317 } 318 } 319 320 func testAccCheckAWSS3DestroyBucket(n string) resource.TestCheckFunc { 321 return func(s *terraform.State) error { 322 rs, ok := s.RootModule().Resources[n] 323 if !ok { 324 return fmt.Errorf("Not found: %s", n) 325 } 326 327 if rs.Primary.ID == "" { 328 return fmt.Errorf("No S3 Bucket ID is set") 329 } 330 331 conn := testAccProvider.Meta().(*AWSClient).s3conn 332 _, err := conn.DeleteBucket(&s3.DeleteBucketInput{ 333 Bucket: aws.String(rs.Primary.ID), 334 }) 335 336 if err != nil { 337 return fmt.Errorf("Error destroying Bucket (%s) in testAccCheckAWSS3DestroyBucket: %s", rs.Primary.ID, err) 338 } 339 return nil 340 } 341 } 342 343 func testAccCheckAWSS3BucketPolicy(n string, policy string) resource.TestCheckFunc { 344 return func(s *terraform.State) error { 345 rs, _ := s.RootModule().Resources[n] 346 conn := testAccProvider.Meta().(*AWSClient).s3conn 347 348 out, err := conn.GetBucketPolicy(&s3.GetBucketPolicyInput{ 349 Bucket: aws.String(rs.Primary.ID), 350 }) 351 352 if err != nil { 353 if policy == "" { 354 // expected 355 return nil 356 } else { 357 return fmt.Errorf("GetBucketPolicy error: %v, expected %s", err, policy) 358 } 359 } 360 361 if v := out.Policy; v == nil { 362 if policy != "" { 363 return fmt.Errorf("bad policy, found nil, expected: %s", policy) 364 } 365 } else { 366 expected := make(map[string]interface{}) 367 if err := json.Unmarshal([]byte(policy), &expected); err != nil { 368 return err 369 } 370 actual := make(map[string]interface{}) 371 if err := json.Unmarshal([]byte(*v), &actual); err != nil { 372 return err 373 } 374 375 if !reflect.DeepEqual(expected, actual) { 376 return fmt.Errorf("bad policy, expected: %#v, got %#v", expected, actual) 377 } 378 } 379 380 return nil 381 } 382 } 383 func testAccCheckAWSS3BucketWebsite(n string, indexDoc string, errorDoc string, redirectTo string) resource.TestCheckFunc { 384 return func(s *terraform.State) error { 385 rs, _ := s.RootModule().Resources[n] 386 conn := testAccProvider.Meta().(*AWSClient).s3conn 387 388 out, err := conn.GetBucketWebsite(&s3.GetBucketWebsiteInput{ 389 Bucket: aws.String(rs.Primary.ID), 390 }) 391 392 if err != nil { 393 if indexDoc == "" { 394 // If we want to assert that the website is not there, than 395 // this error is expected 396 return nil 397 } else { 398 return fmt.Errorf("S3BucketWebsite error: %v", err) 399 } 400 } 401 402 if v := out.IndexDocument; v == nil { 403 if indexDoc != "" { 404 return fmt.Errorf("bad index doc, found nil, expected: %s", indexDoc) 405 } 406 } else { 407 if *v.Suffix != indexDoc { 408 return fmt.Errorf("bad index doc, expected: %s, got %#v", indexDoc, out.IndexDocument) 409 } 410 } 411 412 if v := out.ErrorDocument; v == nil { 413 if errorDoc != "" { 414 return fmt.Errorf("bad error doc, found nil, expected: %s", errorDoc) 415 } 416 } else { 417 if *v.Key != errorDoc { 418 return fmt.Errorf("bad error doc, expected: %s, got %#v", errorDoc, out.ErrorDocument) 419 } 420 } 421 422 if v := out.RedirectAllRequestsTo; v == nil { 423 if redirectTo != "" { 424 return fmt.Errorf("bad redirect to, found nil, expected: %s", redirectTo) 425 } 426 } else { 427 if *v.HostName != redirectTo { 428 return fmt.Errorf("bad redirect to, expected: %s, got %#v", redirectTo, out.RedirectAllRequestsTo) 429 } 430 } 431 432 return nil 433 } 434 } 435 436 func testAccCheckAWSS3BucketVersioning(n string, versioningStatus string) resource.TestCheckFunc { 437 return func(s *terraform.State) error { 438 rs, _ := s.RootModule().Resources[n] 439 conn := testAccProvider.Meta().(*AWSClient).s3conn 440 441 out, err := conn.GetBucketVersioning(&s3.GetBucketVersioningInput{ 442 Bucket: aws.String(rs.Primary.ID), 443 }) 444 445 if err != nil { 446 return fmt.Errorf("GetBucketVersioning error: %v", err) 447 } 448 449 if v := out.Status; v == nil { 450 if versioningStatus != "" { 451 return fmt.Errorf("bad error versioning status, found nil, expected: %s", versioningStatus) 452 } 453 } else { 454 if *v != versioningStatus { 455 return fmt.Errorf("bad error versioning status, expected: %s, got %s", versioningStatus, *v) 456 } 457 } 458 459 return nil 460 } 461 } 462 func testAccCheckAWSS3BucketCors(n string, corsRules []*s3.CORSRule) resource.TestCheckFunc { 463 return func(s *terraform.State) error { 464 rs, _ := s.RootModule().Resources[n] 465 conn := testAccProvider.Meta().(*AWSClient).s3conn 466 467 out, err := conn.GetBucketCors(&s3.GetBucketCorsInput{ 468 Bucket: aws.String(rs.Primary.ID), 469 }) 470 471 if err != nil { 472 return fmt.Errorf("GetBucketCors error: %v", err) 473 } 474 475 if !reflect.DeepEqual(out.CORSRules, corsRules) { 476 return fmt.Errorf("bad error cors rule, expected: %v, got %v", corsRules, out.CORSRules) 477 } 478 479 return nil 480 } 481 } 482 483 func testAccCheckAWSS3BucketLogging(n, b, p string) resource.TestCheckFunc { 484 return func(s *terraform.State) error { 485 rs, _ := s.RootModule().Resources[n] 486 conn := testAccProvider.Meta().(*AWSClient).s3conn 487 488 out, err := conn.GetBucketLogging(&s3.GetBucketLoggingInput{ 489 Bucket: aws.String(rs.Primary.ID), 490 }) 491 492 if err != nil { 493 return fmt.Errorf("GetBucketLogging error: %v", err) 494 } 495 496 tb, _ := s.RootModule().Resources[b] 497 498 if v := out.LoggingEnabled.TargetBucket; v == nil { 499 if tb.Primary.ID != "" { 500 return fmt.Errorf("bad target bucket, found nil, expected: %s", tb.Primary.ID) 501 } 502 } else { 503 if *v != tb.Primary.ID { 504 return fmt.Errorf("bad target bucket, expected: %s, got %s", tb.Primary.ID, *v) 505 } 506 } 507 508 if v := out.LoggingEnabled.TargetPrefix; v == nil { 509 if p != "" { 510 return fmt.Errorf("bad target prefix, found nil, expected: %s", p) 511 } 512 } else { 513 if *v != p { 514 return fmt.Errorf("bad target prefix, expected: %s, got %s", p, *v) 515 } 516 } 517 518 return nil 519 } 520 } 521 522 // These need a bit of randomness as the name can only be used once globally 523 // within AWS 524 var randInt = rand.New(rand.NewSource(time.Now().UnixNano())).Int() 525 var testAccWebsiteEndpoint = fmt.Sprintf("tf-test-bucket-%d.s3-website-us-west-2.amazonaws.com", randInt) 526 var testAccAWSS3BucketPolicy = fmt.Sprintf(`{ "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": "s3:GetObject", "Resource": "arn:aws:s3:::tf-test-bucket-%d/*" } ] }`, randInt) 527 528 var testAccAWSS3BucketConfig = fmt.Sprintf(` 529 resource "aws_s3_bucket" "bucket" { 530 bucket = "tf-test-bucket-%d" 531 acl = "public-read" 532 } 533 `, randInt) 534 535 var testAccAWSS3BucketWebsiteConfig = fmt.Sprintf(` 536 resource "aws_s3_bucket" "bucket" { 537 bucket = "tf-test-bucket-%d" 538 acl = "public-read" 539 540 website { 541 index_document = "index.html" 542 } 543 } 544 `, randInt) 545 546 var testAccAWSS3BucketWebsiteConfigWithError = fmt.Sprintf(` 547 resource "aws_s3_bucket" "bucket" { 548 bucket = "tf-test-bucket-%d" 549 acl = "public-read" 550 551 website { 552 index_document = "index.html" 553 error_document = "error.html" 554 } 555 } 556 `, randInt) 557 558 var testAccAWSS3BucketWebsiteConfigWithRedirect = fmt.Sprintf(` 559 resource "aws_s3_bucket" "bucket" { 560 bucket = "tf-test-bucket-%d" 561 acl = "public-read" 562 563 website { 564 redirect_all_requests_to = "hashicorp.com" 565 } 566 } 567 `, randInt) 568 569 var testAccAWSS3BucketConfigWithPolicy = fmt.Sprintf(` 570 resource "aws_s3_bucket" "bucket" { 571 bucket = "tf-test-bucket-%d" 572 acl = "public-read" 573 policy = %s 574 } 575 `, randInt, strconv.Quote(testAccAWSS3BucketPolicy)) 576 577 var destroyedName = fmt.Sprintf("tf-test-bucket-%d", randInt) 578 var testAccAWSS3BucketDestroyedConfig = fmt.Sprintf(` 579 resource "aws_s3_bucket" "bucket" { 580 bucket = "%s" 581 acl = "public-read" 582 } 583 `, destroyedName) 584 var testAccAWSS3BucketConfigWithVersioning = fmt.Sprintf(` 585 resource "aws_s3_bucket" "bucket" { 586 bucket = "tf-test-bucket-%d" 587 acl = "public-read" 588 versioning { 589 enabled = true 590 } 591 } 592 `, randInt) 593 594 var testAccAWSS3BucketConfigWithDisableVersioning = fmt.Sprintf(` 595 resource "aws_s3_bucket" "bucket" { 596 bucket = "tf-test-bucket-%d" 597 acl = "public-read" 598 versioning { 599 enabled = false 600 } 601 } 602 `, randInt) 603 604 var testAccAWSS3BucketConfigWithCORS = fmt.Sprintf(` 605 resource "aws_s3_bucket" "bucket" { 606 bucket = "tf-test-bucket-%d" 607 acl = "public-read" 608 cors_rule { 609 allowed_headers = ["*"] 610 allowed_methods = ["PUT","POST"] 611 allowed_origins = ["https://www.example.com"] 612 expose_headers = ["x-amz-server-side-encryption","ETag"] 613 max_age_seconds = 3000 614 } 615 } 616 `, randInt) 617 618 var testAccAWSS3BucketConfigWithAcl = ` 619 resource "aws_s3_bucket" "bucket" { 620 bucket = "tf-test-bucket-%d" 621 acl = "public-read" 622 } 623 ` 624 625 var testAccAWSS3BucketConfigWithAclUpdate = ` 626 resource "aws_s3_bucket" "bucket" { 627 bucket = "tf-test-bucket-%d" 628 acl = "private" 629 } 630 ` 631 632 var testAccAWSS3BucketConfigWithLogging = fmt.Sprintf(` 633 resource "aws_s3_bucket" "log_bucket" { 634 bucket = "tf-test-log-bucket-%d" 635 acl = "log-delivery-write" 636 } 637 resource "aws_s3_bucket" "bucket" { 638 bucket = "tf-test-bucket-%d" 639 acl = "private" 640 logging { 641 target_bucket = "${aws_s3_bucket.log_bucket.id}" 642 target_prefix = "log/" 643 } 644 } 645 `, randInt, randInt)