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