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 }