Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

providers/aws: Add support for S3 website redirect #1909

Merged
merged 1 commit into from
May 15, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 29 additions & 3 deletions builtin/providers/aws/resource_aws_s3_bucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
},
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The build is failing because InternalValidate in helper/schema/schema.go doesn't support this nested notation for ConflictsWith, even though in usage it seems to work correctly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Being the original author of ConflictsWith, I know about this limitation, but I was finding it hard to create any nested schema (can't remember what was the problem exactly though), putting aside ConflictsWith.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the website actually be TypeSet?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@radeksimko we settled on list vs set for this, but I forget why

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed with #1926!

Optional: true,
},
},
},
},
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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.")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to enforce this in the schema?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not at the moment

}

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,
Expand Down
70 changes: 62 additions & 8 deletions builtin/providers/aws/resource_aws_s3_bucket_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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),
),
Expand All @@ -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),
),
Expand All @@ -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", ""),
),
Expand Down Expand Up @@ -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
Expand All @@ -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 {
Expand All @@ -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
}
}
Expand Down Expand Up @@ -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)
3 changes: 2 additions & 1 deletion website/source/docs/providers/aws/r/s3_bucket.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't sure of the best way to word this. We could just say this is optional, and put a note at the end of the line saying it's required if not specifying redirect_all_requests_to.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems fine

* `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

Expand Down