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