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