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