github.com/cihangir/terraform@v0.6.7-0.20151026070445-8b70867fdd95/state/remote/s3.go (about)

     1  package remote
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"log"
     8  	"os"
     9  	"strconv"
    10  
    11  	"github.com/aws/aws-sdk-go/aws"
    12  	"github.com/aws/aws-sdk-go/aws/awserr"
    13  	"github.com/aws/aws-sdk-go/aws/credentials"
    14  	"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
    15  	"github.com/aws/aws-sdk-go/service/s3"
    16  	"github.com/hashicorp/go-cleanhttp"
    17  )
    18  
    19  func s3Factory(conf map[string]string) (Client, error) {
    20  	bucketName, ok := conf["bucket"]
    21  	if !ok {
    22  		return nil, fmt.Errorf("missing 'bucket' configuration")
    23  	}
    24  
    25  	keyName, ok := conf["key"]
    26  	if !ok {
    27  		return nil, fmt.Errorf("missing 'key' configuration")
    28  	}
    29  
    30  	regionName, ok := conf["region"]
    31  	if !ok {
    32  		regionName = os.Getenv("AWS_DEFAULT_REGION")
    33  		if regionName == "" {
    34  			return nil, fmt.Errorf(
    35  				"missing 'region' configuration or AWS_DEFAULT_REGION environment variable")
    36  		}
    37  	}
    38  
    39  	serverSideEncryption := false
    40  	if raw, ok := conf["encrypt"]; ok {
    41  		v, err := strconv.ParseBool(raw)
    42  		if err != nil {
    43  			return nil, fmt.Errorf(
    44  				"'encrypt' field couldn't be parsed as bool: %s", err)
    45  		}
    46  
    47  		serverSideEncryption = v
    48  	}
    49  
    50  	acl := ""
    51  	if raw, ok := conf["acl"]; ok {
    52  		acl = raw
    53  	}
    54  
    55  	accessKeyId := conf["access_key"]
    56  	secretAccessKey := conf["secret_key"]
    57  
    58  	credentialsProvider := credentials.NewChainCredentials([]credentials.Provider{
    59  		&credentials.StaticProvider{Value: credentials.Value{
    60  			AccessKeyID:     accessKeyId,
    61  			SecretAccessKey: secretAccessKey,
    62  			SessionToken:    "",
    63  		}},
    64  		&credentials.EnvProvider{},
    65  		&credentials.SharedCredentialsProvider{Filename: "", Profile: ""},
    66  		&ec2rolecreds.EC2RoleProvider{},
    67  	})
    68  
    69  	// Make sure we got some sort of working credentials.
    70  	_, err := credentialsProvider.Get()
    71  	if err != nil {
    72  		return nil, fmt.Errorf("Unable to determine AWS credentials. Set the AWS_ACCESS_KEY_ID and "+
    73  			"AWS_SECRET_ACCESS_KEY environment variables.\n(error was: %s)", err)
    74  	}
    75  
    76  	awsConfig := &aws.Config{
    77  		Credentials: credentialsProvider,
    78  		Region:      aws.String(regionName),
    79  		HTTPClient:  cleanhttp.DefaultClient(),
    80  	}
    81  	nativeClient := s3.New(awsConfig)
    82  
    83  	return &S3Client{
    84  		nativeClient:         nativeClient,
    85  		bucketName:           bucketName,
    86  		keyName:              keyName,
    87  		serverSideEncryption: serverSideEncryption,
    88  		acl:                  acl,
    89  	}, nil
    90  }
    91  
    92  type S3Client struct {
    93  	nativeClient         *s3.S3
    94  	bucketName           string
    95  	keyName              string
    96  	serverSideEncryption bool
    97  	acl                  string
    98  }
    99  
   100  func (c *S3Client) Get() (*Payload, error) {
   101  	output, err := c.nativeClient.GetObject(&s3.GetObjectInput{
   102  		Bucket: &c.bucketName,
   103  		Key:    &c.keyName,
   104  	})
   105  
   106  	if err != nil {
   107  		if awserr := err.(awserr.Error); awserr != nil {
   108  			if awserr.Code() == "NoSuchKey" {
   109  				return nil, nil
   110  			} else {
   111  				return nil, err
   112  			}
   113  		} else {
   114  			return nil, err
   115  		}
   116  	}
   117  
   118  	defer output.Body.Close()
   119  
   120  	buf := bytes.NewBuffer(nil)
   121  	if _, err := io.Copy(buf, output.Body); err != nil {
   122  		return nil, fmt.Errorf("Failed to read remote state: %s", err)
   123  	}
   124  
   125  	payload := &Payload{
   126  		Data: buf.Bytes(),
   127  	}
   128  
   129  	// If there was no data, then return nil
   130  	if len(payload.Data) == 0 {
   131  		return nil, nil
   132  	}
   133  
   134  	return payload, nil
   135  }
   136  
   137  func (c *S3Client) Put(data []byte) error {
   138  	contentType := "application/json"
   139  	contentLength := int64(len(data))
   140  
   141  	i := &s3.PutObjectInput{
   142  		ContentType:   &contentType,
   143  		ContentLength: &contentLength,
   144  		Body:          bytes.NewReader(data),
   145  		Bucket:        &c.bucketName,
   146  		Key:           &c.keyName,
   147  	}
   148  
   149  	if c.serverSideEncryption {
   150  		i.ServerSideEncryption = aws.String("AES256")
   151  	}
   152  
   153  	if c.acl != "" {
   154  		i.ACL = aws.String(c.acl)
   155  	}
   156  
   157  	log.Printf("[DEBUG] Uploading remote state to S3: %#v", i)
   158  
   159  	if _, err := c.nativeClient.PutObject(i); err == nil {
   160  		return nil
   161  	} else {
   162  		return fmt.Errorf("Failed to upload state: %v", err)
   163  	}
   164  }
   165  
   166  func (c *S3Client) Delete() error {
   167  	_, err := c.nativeClient.DeleteObject(&s3.DeleteObjectInput{
   168  		Bucket: &c.bucketName,
   169  		Key:    &c.keyName,
   170  	})
   171  
   172  	return err
   173  }