github.com/markdia/terraform@v0.5.1-0.20150508012022-f1ae920aa970/builtin/providers/aws/resource_aws_s3_bucket.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  
     7  	"github.com/hashicorp/terraform/helper/schema"
     8  
     9  	"github.com/awslabs/aws-sdk-go/aws"
    10  	"github.com/awslabs/aws-sdk-go/service/s3"
    11  )
    12  
    13  func resourceAwsS3Bucket() *schema.Resource {
    14  	return &schema.Resource{
    15  		Create: resourceAwsS3BucketCreate,
    16  		Read:   resourceAwsS3BucketRead,
    17  		Update: resourceAwsS3BucketUpdate,
    18  		Delete: resourceAwsS3BucketDelete,
    19  
    20  		Schema: map[string]*schema.Schema{
    21  			"bucket": &schema.Schema{
    22  				Type:     schema.TypeString,
    23  				Required: true,
    24  				ForceNew: true,
    25  			},
    26  
    27  			"acl": &schema.Schema{
    28  				Type:     schema.TypeString,
    29  				Default:  "private",
    30  				Optional: true,
    31  				ForceNew: true,
    32  			},
    33  
    34  			"website": &schema.Schema{
    35  				Type:     schema.TypeList,
    36  				Optional: true,
    37  				Elem: &schema.Resource{
    38  					Schema: map[string]*schema.Schema{
    39  						"index_document": &schema.Schema{
    40  							Type:     schema.TypeString,
    41  							Required: true,
    42  						},
    43  
    44  						"error_document": &schema.Schema{
    45  							Type:     schema.TypeString,
    46  							Optional: true,
    47  						},
    48  					},
    49  				},
    50  			},
    51  
    52  			"website_endpoint": &schema.Schema{
    53  				Type:     schema.TypeString,
    54  				Optional: true,
    55  				Computed: true,
    56  			},
    57  
    58  			"tags": tagsSchema(),
    59  		},
    60  	}
    61  }
    62  
    63  func resourceAwsS3BucketCreate(d *schema.ResourceData, meta interface{}) error {
    64  	s3conn := meta.(*AWSClient).s3conn
    65  	awsRegion := meta.(*AWSClient).region
    66  
    67  	// Get the bucket and acl
    68  	bucket := d.Get("bucket").(string)
    69  	acl := d.Get("acl").(string)
    70  
    71  	log.Printf("[DEBUG] S3 bucket create: %s, ACL: %s", bucket, acl)
    72  
    73  	req := &s3.CreateBucketInput{
    74  		Bucket: aws.String(bucket),
    75  		ACL:    aws.String(acl),
    76  	}
    77  
    78  	// Special case us-east-1 region and do not set the LocationConstraint.
    79  	// See "Request Elements: http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUT.html
    80  	if awsRegion != "us-east-1" {
    81  		req.CreateBucketConfiguration = &s3.CreateBucketConfiguration{
    82  			LocationConstraint: aws.String(awsRegion),
    83  		}
    84  	}
    85  
    86  	_, err := s3conn.CreateBucket(req)
    87  	if err != nil {
    88  		return fmt.Errorf("Error creating S3 bucket: %s", err)
    89  	}
    90  
    91  	// Assign the bucket name as the resource ID
    92  	d.SetId(bucket)
    93  
    94  	return resourceAwsS3BucketUpdate(d, meta)
    95  }
    96  
    97  func resourceAwsS3BucketUpdate(d *schema.ResourceData, meta interface{}) error {
    98  	s3conn := meta.(*AWSClient).s3conn
    99  	if err := setTagsS3(s3conn, d); err != nil {
   100  		return err
   101  	}
   102  
   103  	if err := resourceAwsS3BucketWebsiteUpdate(s3conn, d); err != nil {
   104  		return err
   105  	}
   106  
   107  	return resourceAwsS3BucketRead(d, meta)
   108  }
   109  
   110  func resourceAwsS3BucketRead(d *schema.ResourceData, meta interface{}) error {
   111  	s3conn := meta.(*AWSClient).s3conn
   112  
   113  	_, err := s3conn.HeadBucket(&s3.HeadBucketInput{
   114  		Bucket: aws.String(d.Id()),
   115  	})
   116  	if err != nil {
   117  		if awsError, ok := err.(aws.APIError); ok && awsError.StatusCode == 404 {
   118  			d.SetId("")
   119  		} else {
   120  			// some of the AWS SDK's errors can be empty strings, so let's add
   121  			// some additional context.
   122  			return fmt.Errorf("error reading S3 bucket \"%s\": %s", d.Id(), err)
   123  		}
   124  	}
   125  
   126  	// Read the website configuration
   127  	ws, err := s3conn.GetBucketWebsite(&s3.GetBucketWebsiteInput{
   128  		Bucket: aws.String(d.Id()),
   129  	})
   130  	var websites []map[string]interface{}
   131  	if err == nil {
   132  		w := make(map[string]interface{})
   133  
   134  		w["index_document"] = *ws.IndexDocument.Suffix
   135  
   136  		if v := ws.ErrorDocument; v != nil {
   137  			w["error_document"] = *v.Key
   138  		}
   139  
   140  		websites = append(websites, w)
   141  	}
   142  	if err := d.Set("website", websites); err != nil {
   143  		return err
   144  	}
   145  
   146  	// Add website_endpoint as an output
   147  	endpoint, err := websiteEndpoint(s3conn, d)
   148  	if err != nil {
   149  		return err
   150  	}
   151  	if err := d.Set("website_endpoint", endpoint); err != nil {
   152  		return err
   153  	}
   154  
   155  	tagSet, err := getTagSetS3(s3conn, d.Id())
   156  	if err != nil {
   157  		return err
   158  	}
   159  
   160  	if err := d.Set("tags", tagsToMapS3(tagSet)); err != nil {
   161  		return err
   162  	}
   163  
   164  	return nil
   165  }
   166  
   167  func resourceAwsS3BucketDelete(d *schema.ResourceData, meta interface{}) error {
   168  	s3conn := meta.(*AWSClient).s3conn
   169  
   170  	log.Printf("[DEBUG] S3 Delete Bucket: %s", d.Id())
   171  	_, err := s3conn.DeleteBucket(&s3.DeleteBucketInput{
   172  		Bucket: aws.String(d.Id()),
   173  	})
   174  	if err != nil {
   175  		return err
   176  	}
   177  	return nil
   178  }
   179  
   180  func resourceAwsS3BucketWebsiteUpdate(s3conn *s3.S3, d *schema.ResourceData) error {
   181  	if !d.HasChange("website") {
   182  		return nil
   183  	}
   184  
   185  	ws := d.Get("website").([]interface{})
   186  
   187  	if len(ws) == 1 {
   188  		w := ws[0].(map[string]interface{})
   189  		return resourceAwsS3BucketWebsitePut(s3conn, d, w)
   190  	} else if len(ws) == 0 {
   191  		return resourceAwsS3BucketWebsiteDelete(s3conn, d)
   192  	} else {
   193  		return fmt.Errorf("Cannot specify more than one website.")
   194  	}
   195  }
   196  
   197  func resourceAwsS3BucketWebsitePut(s3conn *s3.S3, d *schema.ResourceData, website map[string]interface{}) error {
   198  	bucket := d.Get("bucket").(string)
   199  
   200  	indexDocument := website["index_document"].(string)
   201  	errorDocument := website["error_document"].(string)
   202  
   203  	websiteConfiguration := &s3.WebsiteConfiguration{}
   204  
   205  	websiteConfiguration.IndexDocument = &s3.IndexDocument{Suffix: aws.String(indexDocument)}
   206  
   207  	if errorDocument != "" {
   208  		websiteConfiguration.ErrorDocument = &s3.ErrorDocument{Key: aws.String(errorDocument)}
   209  	}
   210  
   211  	putInput := &s3.PutBucketWebsiteInput{
   212  		Bucket:               aws.String(bucket),
   213  		WebsiteConfiguration: websiteConfiguration,
   214  	}
   215  
   216  	log.Printf("[DEBUG] S3 put bucket website: %#v", putInput)
   217  
   218  	_, err := s3conn.PutBucketWebsite(putInput)
   219  	if err != nil {
   220  		return fmt.Errorf("Error putting S3 website: %s", err)
   221  	}
   222  
   223  	return nil
   224  }
   225  
   226  func resourceAwsS3BucketWebsiteDelete(s3conn *s3.S3, d *schema.ResourceData) error {
   227  	bucket := d.Get("bucket").(string)
   228  	deleteInput := &s3.DeleteBucketWebsiteInput{Bucket: aws.String(bucket)}
   229  
   230  	log.Printf("[DEBUG] S3 delete bucket website: %#v", deleteInput)
   231  
   232  	_, err := s3conn.DeleteBucketWebsite(deleteInput)
   233  	if err != nil {
   234  		return fmt.Errorf("Error deleting S3 website: %s", err)
   235  	}
   236  
   237  	return nil
   238  }
   239  
   240  func websiteEndpoint(s3conn *s3.S3, d *schema.ResourceData) (string, error) {
   241  	// If the bucket doesn't have a website configuration, return an empty
   242  	// endpoint
   243  	if _, ok := d.GetOk("website"); !ok {
   244  		return "", nil
   245  	}
   246  
   247  	bucket := d.Get("bucket").(string)
   248  
   249  	// Lookup the region for this bucket
   250  	location, err := s3conn.GetBucketLocation(
   251  		&s3.GetBucketLocationInput{
   252  			Bucket: aws.String(bucket),
   253  		},
   254  	)
   255  	if err != nil {
   256  		return "", err
   257  	}
   258  	var region string
   259  	if location.LocationConstraint != nil {
   260  		region = *location.LocationConstraint
   261  	}
   262  
   263  	// Default to us-east-1 if the bucket doesn't have a region:
   264  	// http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketGETlocation.html
   265  	if region == "" {
   266  		region = "us-east-1"
   267  	}
   268  
   269  	endpoint := fmt.Sprintf("%s.s3-website-%s.amazonaws.com", bucket, region)
   270  
   271  	return endpoint, nil
   272  }