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 }