diff --git a/builtin/providers/aws/resource_aws_s3_bucket.go b/builtin/providers/aws/resource_aws_s3_bucket.go index d550124ef5b8..170f88970c11 100644 --- a/builtin/providers/aws/resource_aws_s3_bucket.go +++ b/builtin/providers/aws/resource_aws_s3_bucket.go @@ -38,13 +38,22 @@ func resourceAwsS3Bucket() *schema.Resource { Schema: map[string]*schema.Schema{ "index_document": &schema.Schema{ Type: schema.TypeString, - Required: true, + Optional: true, }, "error_document": &schema.Schema{ Type: schema.TypeString, Optional: true, }, + + "redirect_all_requests_to": &schema.Schema{ + Type: schema.TypeString, + ConflictsWith: []string{ + "website.0.index_document", + "website.0.error_document", + }, + Optional: true, + }, }, }, }, @@ -143,12 +152,18 @@ func resourceAwsS3BucketRead(d *schema.ResourceData, meta interface{}) error { if err == nil { w := make(map[string]interface{}) - w["index_document"] = *ws.IndexDocument.Suffix + if v := ws.IndexDocument; v != nil { + w["index_document"] = *v.Suffix + } if v := ws.ErrorDocument; v != nil { w["error_document"] = *v.Key } + if v := ws.RedirectAllRequestsTo; v != nil { + w["redirect_all_requests_to"] = *v.HostName + } + websites = append(websites, w) } if err := d.Set("website", websites); err != nil { @@ -235,15 +250,26 @@ func resourceAwsS3BucketWebsitePut(s3conn *s3.S3, d *schema.ResourceData, websit indexDocument := website["index_document"].(string) errorDocument := website["error_document"].(string) + redirectAllRequestsTo := website["redirect_all_requests_to"].(string) + + if indexDocument == "" && redirectAllRequestsTo == "" { + return fmt.Errorf("Must specify either index_document or redirect_all_requests_to.") + } websiteConfiguration := &s3.WebsiteConfiguration{} - websiteConfiguration.IndexDocument = &s3.IndexDocument{Suffix: aws.String(indexDocument)} + if indexDocument != "" { + websiteConfiguration.IndexDocument = &s3.IndexDocument{Suffix: aws.String(indexDocument)} + } if errorDocument != "" { websiteConfiguration.ErrorDocument = &s3.ErrorDocument{Key: aws.String(errorDocument)} } + if redirectAllRequestsTo != "" { + websiteConfiguration.RedirectAllRequestsTo = &s3.RedirectAllRequestsTo{HostName: aws.String(redirectAllRequestsTo)} + } + putInput := &s3.PutBucketWebsiteInput{ Bucket: aws.String(bucket), WebsiteConfiguration: websiteConfiguration, diff --git a/builtin/providers/aws/resource_aws_s3_bucket_test.go b/builtin/providers/aws/resource_aws_s3_bucket_test.go index 1b41d76eaf9f..051ab5474b51 100644 --- a/builtin/providers/aws/resource_aws_s3_bucket_test.go +++ b/builtin/providers/aws/resource_aws_s3_bucket_test.go @@ -46,7 +46,7 @@ func TestAccAWSS3Bucket_Website(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"), testAccCheckAWSS3BucketWebsite( - "aws_s3_bucket.bucket", "index.html", ""), + "aws_s3_bucket.bucket", "index.html", "", ""), resource.TestCheckResourceAttr( "aws_s3_bucket.bucket", "website_endpoint", testAccWebsiteEndpoint), ), @@ -56,7 +56,7 @@ func TestAccAWSS3Bucket_Website(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"), testAccCheckAWSS3BucketWebsite( - "aws_s3_bucket.bucket", "index.html", "error.html"), + "aws_s3_bucket.bucket", "index.html", "error.html", ""), resource.TestCheckResourceAttr( "aws_s3_bucket.bucket", "website_endpoint", testAccWebsiteEndpoint), ), @@ -66,7 +66,37 @@ func TestAccAWSS3Bucket_Website(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"), testAccCheckAWSS3BucketWebsite( - "aws_s3_bucket.bucket", "", ""), + "aws_s3_bucket.bucket", "", "", ""), + resource.TestCheckResourceAttr( + "aws_s3_bucket.bucket", "website_endpoint", ""), + ), + }, + }, + }) +} + +func TestAccAWSS3Bucket_WebsiteRedirect(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSS3BucketDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSS3BucketWebsiteConfigWithRedirect, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"), + testAccCheckAWSS3BucketWebsite( + "aws_s3_bucket.bucket", "", "", "hashicorp.com"), + resource.TestCheckResourceAttr( + "aws_s3_bucket.bucket", "website_endpoint", testAccWebsiteEndpoint), + ), + }, + resource.TestStep{ + Config: testAccAWSS3BucketConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSS3BucketExists("aws_s3_bucket.bucket"), + testAccCheckAWSS3BucketWebsite( + "aws_s3_bucket.bucket", "", "", ""), resource.TestCheckResourceAttr( "aws_s3_bucket.bucket", "website_endpoint", ""), ), @@ -115,7 +145,7 @@ func testAccCheckAWSS3BucketExists(n string) resource.TestCheckFunc { } } -func testAccCheckAWSS3BucketWebsite(n string, indexDoc string, errorDoc string) resource.TestCheckFunc { +func testAccCheckAWSS3BucketWebsite(n string, indexDoc string, errorDoc string, redirectTo string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, _ := s.RootModule().Resources[n] conn := testAccProvider.Meta().(*AWSClient).s3conn @@ -134,11 +164,14 @@ func testAccCheckAWSS3BucketWebsite(n string, indexDoc string, errorDoc string) } } - if *out.IndexDocument.Suffix != indexDoc { - if out.IndexDocument.Suffix != nil { - return fmt.Errorf("bad index document suffix: %s", *out.IndexDocument.Suffix) + if v := out.IndexDocument; v == nil { + if indexDoc != "" { + return fmt.Errorf("bad index doc, found nil, expected: %s", indexDoc) + } + } else { + if *v.Suffix != indexDoc { + return fmt.Errorf("bad index doc, expected: %s, got %#v", indexDoc, out.IndexDocument) } - return fmt.Errorf("bad index document suffix, is nil") } if v := out.ErrorDocument; v == nil { @@ -151,6 +184,16 @@ func testAccCheckAWSS3BucketWebsite(n string, indexDoc string, errorDoc string) } } + if v := out.RedirectAllRequestsTo; v == nil { + if redirectTo != "" { + return fmt.Errorf("bad redirect to, found nil, expected: %s", redirectTo) + } + } else { + if *v.HostName != redirectTo { + return fmt.Errorf("bad redirect to, expected: %s, got %#v", redirectTo, out.RedirectAllRequestsTo) + } + } + return nil } } @@ -188,3 +231,14 @@ resource "aws_s3_bucket" "bucket" { } } `, randInt) + +var testAccAWSS3BucketWebsiteConfigWithRedirect = fmt.Sprintf(` +resource "aws_s3_bucket" "bucket" { + bucket = "tf-test-bucket-%d" + acl = "public-read" + + website { + redirect_all_requests_to = "hashicorp.com" + } +} +`, randInt) diff --git a/website/source/docs/providers/aws/r/s3_bucket.html.markdown b/website/source/docs/providers/aws/r/s3_bucket.html.markdown index 204be87e003b..78e0938f828e 100644 --- a/website/source/docs/providers/aws/r/s3_bucket.html.markdown +++ b/website/source/docs/providers/aws/r/s3_bucket.html.markdown @@ -51,8 +51,9 @@ The following arguments are supported: The website object supports the following: -* `index_document` - (Required) Amazon S3 returns this index document when requests are made to the root domain or any of the subfolders. +* `index_document` - (Required, unless using `redirect_all_requests_to`) Amazon S3 returns this index document when requests are made to the root domain or any of the subfolders. * `error_document` - (Optional) An absolute path to the document to return in case of a 4XX error. +* `redirect_all_requests_to` - (Optional) A hostname to redirect all website requests for this bucket to. ## Attributes Reference