1package backends 2 3import ( 4 "context" 5 "fmt" 6 "io/ioutil" 7 "os" 8 9 "github.com/araddon/gou" 10 "github.com/cloudfoundry/bbl-state-resource/storage" 11 "github.com/lytics/cloudstorage" 12 "github.com/lytics/cloudstorage/awss3" 13 "github.com/mholt/archiver" 14) 15 16type Config struct { 17 AWSAccessKeyID string 18 AWSSecretAccessKey string 19 GCPServiceAccountKey string 20 Bucket string 21 Region string 22 Dest string 23} 24 25type Provider interface { 26 Client(string) (Backend, error) 27} 28 29func NewProvider() Provider { 30 return provider{} 31} 32 33type provider struct{} 34 35func (p provider) Client(iaas string) (Backend, error) { 36 switch iaas { 37 case "aws": 38 return cloudStorageBackend{}, nil 39 case "gcp": 40 return gcsStateBackend{}, nil 41 default: 42 return nil, fmt.Errorf("remote state storage is unsupported for %s environments", iaas) 43 } 44} 45 46type Backend interface { 47 GetState(Config, string) error 48} 49 50type cloudStorageBackend struct{} 51 52func (c cloudStorageBackend) GetState(config Config, name string) error { 53 awsAuthSettings := make(gou.JsonHelper) 54 awsAuthSettings[awss3.ConfKeyAccessKey] = config.AWSAccessKeyID 55 awsAuthSettings[awss3.ConfKeyAccessSecret] = config.AWSSecretAccessKey 56 57 csConfig := cloudstorage.Config{ 58 Type: awss3.StoreType, 59 AuthMethod: awss3.AuthAccessKey, 60 Bucket: config.Bucket, 61 Settings: awsAuthSettings, 62 Region: config.Region, 63 } 64 65 store, err := cloudstorage.NewStore(&csConfig) 66 if err != nil { 67 return err 68 } 69 70 tarball, err := store.Get(context.Background(), name) 71 if err != nil { 72 return err 73 } 74 75 stateTar, err := tarball.Open(cloudstorage.ReadOnly) 76 if err != nil { 77 return err 78 } 79 80 err = archiver.TarGz.Read(stateTar, config.Dest) 81 if err != nil { 82 return fmt.Errorf("unable to untar state dir: %s", err) 83 } 84 85 return nil 86} 87 88type gcsStateBackend struct{} 89 90func (g gcsStateBackend) GetState(config Config, name string) error { 91 key, err := g.getGCPServiceAccountKey(config.GCPServiceAccountKey) 92 if err != nil { 93 return fmt.Errorf("could not read GCP service account key: %s", err) 94 } 95 96 gcsClient, err := storage.NewStorageClient(key, name, config.Bucket) 97 if err != nil { 98 return fmt.Errorf("could not create GCS client: %s", err) 99 } 100 101 _, err = gcsClient.Download(config.Dest) 102 if err != nil { 103 return fmt.Errorf("downloading remote state from GCS: %s", err) 104 } 105 106 return nil 107} 108 109func (g gcsStateBackend) getGCPServiceAccountKey(key string) (string, error) { 110 if _, err := os.Stat(key); err != nil { 111 return key, nil 112 } 113 114 keyBytes, err := ioutil.ReadFile(key) 115 if err != nil { 116 return "", fmt.Errorf("Reading key: %v", err) 117 } 118 119 return string(keyBytes), nil 120} 121