github.com/acm1/terraform@v0.6.2-0.20150729164239-1f314444f45c/state/remote/s3.go (about)

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