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