2015-04-30 18:21:49 +02:00
|
|
|
package remote
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
|
|
|
|
"github.com/awslabs/aws-sdk-go/aws"
|
2015-05-20 13:21:23 +02:00
|
|
|
"github.com/awslabs/aws-sdk-go/aws/awserr"
|
2015-05-05 12:26:26 +02:00
|
|
|
"github.com/awslabs/aws-sdk-go/aws/credentials"
|
2015-04-30 18:21:49 +02:00
|
|
|
"github.com/awslabs/aws-sdk-go/service/s3"
|
|
|
|
)
|
|
|
|
|
|
|
|
func s3Factory(conf map[string]string) (Client, error) {
|
|
|
|
bucketName, ok := conf["bucket"]
|
|
|
|
if !ok {
|
|
|
|
return nil, fmt.Errorf("missing 'bucket' configuration")
|
|
|
|
}
|
|
|
|
|
|
|
|
keyName, ok := conf["key"]
|
|
|
|
if !ok {
|
|
|
|
return nil, fmt.Errorf("missing 'key' configuration")
|
|
|
|
}
|
|
|
|
|
|
|
|
regionName, ok := conf["region"]
|
|
|
|
if !ok {
|
|
|
|
regionName = os.Getenv("AWS_DEFAULT_REGION")
|
|
|
|
if regionName == "" {
|
2015-05-05 20:30:35 +02:00
|
|
|
return nil, fmt.Errorf(
|
|
|
|
"missing 'region' configuration or AWS_DEFAULT_REGION environment variable")
|
2015-04-30 18:21:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
accessKeyId := conf["access_key"]
|
|
|
|
secretAccessKey := conf["secret_key"]
|
|
|
|
|
2015-05-05 20:30:35 +02:00
|
|
|
credentialsProvider := credentials.NewChainCredentials([]credentials.Provider{
|
|
|
|
&credentials.StaticProvider{Value: credentials.Value{
|
|
|
|
AccessKeyID: accessKeyId,
|
|
|
|
SecretAccessKey: secretAccessKey,
|
|
|
|
SessionToken: "",
|
|
|
|
}},
|
|
|
|
&credentials.EnvProvider{},
|
2015-05-05 20:38:35 +02:00
|
|
|
&credentials.SharedCredentialsProvider{Filename: "", Profile: ""},
|
|
|
|
&credentials.EC2RoleProvider{},
|
2015-05-05 20:30:35 +02:00
|
|
|
})
|
2015-04-30 18:21:49 +02:00
|
|
|
|
|
|
|
// Make sure we got some sort of working credentials.
|
2015-05-05 12:26:26 +02:00
|
|
|
_, err := credentialsProvider.Get()
|
2015-04-30 18:21:49 +02:00
|
|
|
if err != nil {
|
2015-05-05 20:30:35 +02:00
|
|
|
return nil, fmt.Errorf("Unable to determine AWS credentials. Set the AWS_ACCESS_KEY_ID and "+
|
|
|
|
"AWS_SECRET_ACCESS_KEY environment variables.\n(error was: %s)", err)
|
2015-04-30 18:21:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
awsConfig := &aws.Config{
|
|
|
|
Credentials: credentialsProvider,
|
|
|
|
Region: regionName,
|
|
|
|
}
|
|
|
|
nativeClient := s3.New(awsConfig)
|
|
|
|
|
|
|
|
return &S3Client{
|
|
|
|
nativeClient: nativeClient,
|
|
|
|
bucketName: bucketName,
|
|
|
|
keyName: keyName,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type S3Client struct {
|
|
|
|
nativeClient *s3.S3
|
|
|
|
bucketName string
|
|
|
|
keyName string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *S3Client) Get() (*Payload, error) {
|
|
|
|
output, err := c.nativeClient.GetObject(&s3.GetObjectInput{
|
|
|
|
Bucket: &c.bucketName,
|
|
|
|
Key: &c.keyName,
|
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil {
|
2015-05-20 22:20:30 +02:00
|
|
|
if awserr := err.(awserr.Error); awserr != nil {
|
2015-05-20 13:21:23 +02:00
|
|
|
if awserr.Code() == "NoSuchKey" {
|
2015-04-30 18:21:49 +02:00
|
|
|
return nil, nil
|
|
|
|
} else {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
defer output.Body.Close()
|
|
|
|
|
|
|
|
buf := bytes.NewBuffer(nil)
|
|
|
|
if _, err := io.Copy(buf, output.Body); err != nil {
|
|
|
|
return nil, fmt.Errorf("Failed to read remote state: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
payload := &Payload{
|
|
|
|
Data: buf.Bytes(),
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there was no data, then return nil
|
|
|
|
if len(payload.Data) == 0 {
|
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return payload, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *S3Client) Put(data []byte) error {
|
|
|
|
contentType := "application/octet-stream"
|
|
|
|
contentLength := int64(len(data))
|
|
|
|
|
|
|
|
_, err := c.nativeClient.PutObject(&s3.PutObjectInput{
|
|
|
|
ContentType: &contentType,
|
|
|
|
ContentLength: &contentLength,
|
|
|
|
Body: bytes.NewReader(data),
|
|
|
|
Bucket: &c.bucketName,
|
|
|
|
Key: &c.keyName,
|
|
|
|
})
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
return nil
|
|
|
|
} else {
|
|
|
|
return fmt.Errorf("Failed to upload state: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *S3Client) Delete() error {
|
|
|
|
_, err := c.nativeClient.DeleteObject(&s3.DeleteObjectInput{
|
|
|
|
Bucket: &c.bucketName,
|
|
|
|
Key: &c.keyName,
|
|
|
|
})
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|