github.com/hobbeswalsh/terraform@v0.3.7-0.20150619183303-ad17cf55a0fa/state/remote/s3.go (about)

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