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