@ -2,46 +2,81 @@ package s3
import (
"fmt"
"sort"
"strings"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/hashicorp/terraform/backend"
"github.com/hashicorp/terraform/state"
"github.com/hashicorp/terraform/state/remote"
)
const (
// This will be used a directory name, the odd looking colon is to reduce
// the chance of name conflicts with existing deploymen ts.
// This will be used a s directory name, the odd looking colon is simply to
// reduce the chance of name conflicts with existing objec ts.
keyEnvPrefix = "env:"
)
func ( b * Backend ) States ( ) ( [ ] string , error ) {
return nil , backend . ErrNamedStatesNotSupported
params := & s3 . ListObjectsInput {
Bucket : & b . bucketName ,
Prefix : aws . String ( keyEnvPrefix + "/" ) ,
}
resp , err := b . s3Client . ListObjects ( params )
if err != nil {
return nil , err
}
var envs [ ] string
for _ , obj := range resp . Contents {
env := keyEnv ( * obj . Key )
if env != "" {
envs = append ( envs , env )
}
}
sort . Strings ( envs )
envs = append ( [ ] string { backend . DefaultStateName } , envs ... )
return envs , nil
}
// extract the env name from the S3 key
func keyEnv ( key string ) string {
parts := strings . Split ( key , "/" )
if len ( parts ) < 3 {
// no env here
return ""
}
if parts [ 0 ] != keyEnvPrefix {
// not our key, so ignore
return ""
}
return parts [ 1 ]
}
func ( b * Backend ) DeleteState ( name string ) error {
return backend . ErrNamedStatesNotSupported
if name == backend . DefaultStateName || name == "" {
return fmt . Errorf ( "can't delete default state" )
}
//params := &s3.ListObjectsInput{
// Bucket: &b.client.bucketName,
// Delimiter: aws.String("Delimiter"),
// EncodingType: aws.String("EncodingType"),
// Marker: aws.String("Marker"),
// MaxKeys: aws.Int64(1),
// Prefix: aws.String("env"),
// RequestPayer: aws.String("RequestPayer"),
//}
params := & s3 . DeleteObjectInput {
Bucket : & b . bucketName ,
Key : aws . String ( b . path ( name ) ) ,
}
_ , err := b . s3Client . DeleteObject ( params )
if err != nil {
return err
}
return nil
}
func ( b * Backend ) State ( name string ) ( state . State , error ) {
if name != backend . DefaultStateName {
return nil , backend . ErrNamedStatesNotSupported
}
client := & RemoteClient {
s3Client : b . s3Client ,
dynClient : b . dynClient ,
@ -53,7 +88,13 @@ func (b *Backend) State(name string) (state.State, error) {
lockTable : b . lockTable ,
}
// TODO: create new state if it doesn't exist
// if this isn't the default state name, we need to create the object so
// it's listed by States.
if name != backend . DefaultStateName {
if err := client . Put ( [ ] byte { } ) ; err != nil {
return nil , err
}
}
return & remote . State { Client : client } , nil
}