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