Skip to content

Commit

Permalink
Add s3 bucket data source (#1505)
Browse files Browse the repository at this point in the history
* Create s3 bucket data source

* Don't return website endpoints if it doesn't exist

* Add s3 bucket data source documentation

* d/s3_bucket: Reorder imports according to conventions

* d/s3_bucket: Rename files according to conventions
  • Loading branch information
kl4w authored and radeksimko committed Oct 11, 2017
1 parent 4ea85b2 commit 5f3605b
Show file tree
Hide file tree
Showing 4 changed files with 273 additions and 0 deletions.
115 changes: 115 additions & 0 deletions aws/data_source_aws_s3_bucket.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package aws

import (
"fmt"
"log"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/hashicorp/terraform/helper/schema"
)

func dataSourceAwsS3Bucket() *schema.Resource {
return &schema.Resource{
Read: dataSourceAwsS3BucketRead,

Schema: map[string]*schema.Schema{
"bucket": {
Type: schema.TypeString,
Required: true,
},
"arn": {
Type: schema.TypeString,
Computed: true,
},
"bucket_domain_name": {
Type: schema.TypeString,
Computed: true,
},
"hosted_zone_id": {
Type: schema.TypeString,
Computed: true,
},
"region": {
Type: schema.TypeString,
Computed: true,
},
"website_endpoint": {
Type: schema.TypeString,
Computed: true,
},
"website_domain": {
Type: schema.TypeString,
Computed: true,
},
},
}
}

func dataSourceAwsS3BucketRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).s3conn

bucket := d.Get("bucket").(string)

input := &s3.HeadBucketInput{
Bucket: aws.String(bucket),
}

log.Printf("[DEBUG] Reading S3 bucket: %s", input)
_, err := conn.HeadBucket(input)

if err != nil {
return fmt.Errorf("Failed getting S3 bucket: %s Bucket: %q", err, bucket)
}

d.SetId(bucket)
d.Set("arn", fmt.Sprintf("arn:%s:s3:::%s", meta.(*AWSClient).partition, bucket))
d.Set("bucket_domain_name", bucketDomainName(bucket))

if err := bucketLocation(d, bucket, conn); err != nil {
return err
}

return nil
}

func bucketLocation(d *schema.ResourceData, bucket string, conn *s3.S3) error {
location, err := conn.GetBucketLocation(
&s3.GetBucketLocationInput{
Bucket: aws.String(bucket),
},
)
if err != nil {
return err
}
var region string
if location.LocationConstraint != nil {
region = *location.LocationConstraint
}
region = normalizeRegion(region)
if err := d.Set("region", region); err != nil {
return err
}

hostedZoneID := HostedZoneIDForRegion(region)
if err := d.Set("hosted_zone_id", hostedZoneID); err != nil {
return err
}

_, websiteErr := conn.GetBucketWebsite(
&s3.GetBucketWebsiteInput{
Bucket: aws.String(bucket),
},
)

if websiteErr == nil {
websiteEndpoint := WebsiteEndpoint(bucket, region)
if err := d.Set("website_endpoint", websiteEndpoint.Endpoint); err != nil {
return err
}
if err := d.Set("website_domain", websiteEndpoint.Domain); err != nil {
return err
}
}
return nil
}
85 changes: 85 additions & 0 deletions aws/data_source_aws_s3_bucket_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package aws

import (
"fmt"
"regexp"
"testing"

"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
)

func TestAccDataSourceS3Bucket_basic(t *testing.T) {
rInt := acctest.RandInt()
arnRegexp := regexp.MustCompile(
"^arn:aws:s3:::")

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccAWSDataSourceS3BucketConfig_basic(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSS3BucketExists("data.aws_s3_bucket.bucket"),
resource.TestMatchResourceAttr("data.aws_s3_bucket.bucket", "arn", arnRegexp),
resource.TestCheckResourceAttr("data.aws_s3_bucket.bucket", "region", "us-west-2"),
resource.TestCheckResourceAttr(
"data.aws_s3_bucket.bucket", "bucket_domain_name", testAccBucketDomainName(rInt)),
resource.TestCheckResourceAttr(
"data.aws_s3_bucket.bucket", "hosted_zone_id", HostedZoneIDForRegion("us-west-2")),
resource.TestCheckNoResourceAttr("data.aws_s3_bucket.bucket", "website_endpoint"),
),
},
},
})
}

func TestAccDataSourceS3Bucket_website(t *testing.T) {
rInt := acctest.RandInt()

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccAWSDataSourceS3BucketWebsiteConfig(rInt),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSS3BucketExists("data.aws_s3_bucket.bucket"),
testAccCheckAWSS3BucketWebsite(
"data.aws_s3_bucket.bucket", "index.html", "error.html", "", ""),
resource.TestCheckResourceAttr(
"data.aws_s3_bucket.bucket", "website_endpoint", testAccWebsiteEndpoint(rInt)),
),
},
},
})
}

func testAccAWSDataSourceS3BucketConfig_basic(randInt int) string {
return fmt.Sprintf(`
resource "aws_s3_bucket" "bucket" {
bucket = "tf-test-bucket-%d"
}
data "aws_s3_bucket" "bucket" {
bucket = "${aws_s3_bucket.bucket.id}"
}`, randInt)
}

func testAccAWSDataSourceS3BucketWebsiteConfig(randInt int) string {
return fmt.Sprintf(`
resource "aws_s3_bucket" "bucket" {
bucket = "tf-test-bucket-%d"
acl = "public-read"
website {
index_document = "index.html"
error_document = "error.html"
}
}
data "aws_s3_bucket" "bucket" {
bucket = "${aws_s3_bucket.bucket.id}"
}`, randInt)
}
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ func Provider() terraform.ResourceProvider {
"aws_region": dataSourceAwsRegion(),
"aws_route_table": dataSourceAwsRouteTable(),
"aws_route53_zone": dataSourceAwsRoute53Zone(),
"aws_s3_bucket": dataSourceAwsS3Bucket(),
"aws_s3_bucket_object": dataSourceAwsS3BucketObject(),
"aws_sns_topic": dataSourceAwsSnsTopic(),
"aws_ssm_parameter": dataSourceAwsSsmParameter(),
Expand Down
72 changes: 72 additions & 0 deletions website/docs/d/s3_bucket.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
layout: "aws"
page_title: "AWS: aws_s3_bucket"
sidebar_current: "docs-aws-datasource-s3-bucket"
description: |-
Provides details about a specific S3 bucket
---

# aws\_s3\_bucket

Provides details about a specific S3 bucket.

This resource may prove useful when setting up a Route53 record, or an origin for a CloudFront
Distribution.

## Example Usage

### Route53 Record

```hcl
data "aws_s3_bucket" "selected" {
bucket = "bucket.test.com"
}
data "aws_route53_zone" "test_zone" {
name = "test.com."
}
resource "aws_route53_record" "example" {
zone_id = "${data.aws_route53_zone.test_zone.id}"
name = "bucket"
type = "A"
alias {
name = "${data.aws_s3_bucket.selected.website_domain}"
zone_id = "${data.aws_s3_bucket.selected.hosted_zone_id}"
}
}
```

### CloudFront Origin

```hcl
data "aws_s3_bucket" "selected" {
bucket = "a-test-bucket"
}
resource "aws_cloudfront_distribution" "test" {
origin {
domain_name = "${data.aws_s3_bucket.selected.bucket_domain_name}"
origin_id = "s3-selected-bucket"
}
}
```

## Argument Reference

The following arguments are supported:

* `bucket` - (Required) The name of the bucket

## Attribute Reference

The following attributes are exported:

* `id` - The name of the bucket.
* `arn` - The ARN of the bucket. Will be of format `arn:aws:s3:::bucketname`.
* `bucket_domain_name` - The bucket domain name. Will be of format `bucketname.s3.amazonaws.com`.
* `hosted_zone_id` - The [Route 53 Hosted Zone ID](https://docs.aws.amazon.com/general/latest/gr/rande.html#s3_website_region_endpoints) for this bucket's region.
* `region` - The AWS region this bucket resides in.
* `website_endpoint` - The website endpoint, if the bucket is configured with a website. If not, this will be an empty string.
* `website_domain` - The domain of the website endpoint, if the bucket is configured with a website. If not, this will be an empty string. This is used to create Route 53 alias records.

0 comments on commit 5f3605b

Please sign in to comment.