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