github.com/tompao/terraform@v0.6.10-0.20180215233341-e41b29d0961b/backend/remote-state/manta/backend.go (about) 1 package manta 2 3 import ( 4 "context" 5 "encoding/pem" 6 "errors" 7 "fmt" 8 "io/ioutil" 9 "os" 10 11 "github.com/hashicorp/errwrap" 12 "github.com/hashicorp/go-multierror" 13 "github.com/hashicorp/terraform/backend" 14 "github.com/hashicorp/terraform/helper/schema" 15 triton "github.com/joyent/triton-go" 16 "github.com/joyent/triton-go/authentication" 17 "github.com/joyent/triton-go/storage" 18 ) 19 20 func New() backend.Backend { 21 s := &schema.Backend{ 22 Schema: map[string]*schema.Schema{ 23 "account": { 24 Type: schema.TypeString, 25 Required: true, 26 DefaultFunc: schema.MultiEnvDefaultFunc([]string{"TRITON_ACCOUNT", "SDC_ACCOUNT"}, ""), 27 }, 28 29 "user": { 30 Type: schema.TypeString, 31 Optional: true, 32 DefaultFunc: schema.MultiEnvDefaultFunc([]string{"TRITON_USER", "SDC_USER"}, ""), 33 }, 34 35 "url": { 36 Type: schema.TypeString, 37 Optional: true, 38 DefaultFunc: schema.MultiEnvDefaultFunc([]string{"MANTA_URL"}, "https://us-east.manta.joyent.com"), 39 }, 40 41 "key_material": { 42 Type: schema.TypeString, 43 Optional: true, 44 DefaultFunc: schema.MultiEnvDefaultFunc([]string{"TRITON_KEY_MATERIAL", "SDC_KEY_MATERIAL"}, ""), 45 }, 46 47 "key_id": { 48 Type: schema.TypeString, 49 Required: true, 50 DefaultFunc: schema.MultiEnvDefaultFunc([]string{"TRITON_KEY_ID", "SDC_KEY_ID"}, ""), 51 }, 52 53 "insecure_skip_tls_verify": { 54 Type: schema.TypeBool, 55 Optional: true, 56 DefaultFunc: schema.EnvDefaultFunc("TRITON_SKIP_TLS_VERIFY", ""), 57 }, 58 59 "path": { 60 Type: schema.TypeString, 61 Required: true, 62 }, 63 64 "objectName": { 65 Type: schema.TypeString, 66 Optional: true, 67 Default: "terraform.tfstate", 68 }, 69 }, 70 } 71 72 result := &Backend{Backend: s} 73 result.Backend.ConfigureFunc = result.configure 74 return result 75 } 76 77 type Backend struct { 78 *schema.Backend 79 data *schema.ResourceData 80 81 // The fields below are set from configure 82 storageClient *storage.StorageClient 83 path string 84 objectName string 85 } 86 87 type BackendConfig struct { 88 AccountId string 89 Username string 90 KeyId string 91 AccountUrl string 92 KeyMaterial string 93 SkipTls bool 94 } 95 96 func (b *Backend) configure(ctx context.Context) error { 97 if b.path != "" { 98 return nil 99 } 100 101 data := schema.FromContextBackendConfig(ctx) 102 103 config := &BackendConfig{ 104 AccountId: data.Get("account").(string), 105 AccountUrl: data.Get("url").(string), 106 KeyId: data.Get("key_id").(string), 107 SkipTls: data.Get("insecure_skip_tls_verify").(bool), 108 } 109 110 if v, ok := data.GetOk("user"); ok { 111 config.Username = v.(string) 112 } 113 114 if v, ok := data.GetOk("key_material"); ok { 115 config.KeyMaterial = v.(string) 116 } 117 118 b.path = data.Get("path").(string) 119 b.objectName = data.Get("objectName").(string) 120 121 var validationError *multierror.Error 122 123 if data.Get("account").(string) == "" { 124 validationError = multierror.Append(validationError, errors.New("`Account` must be configured for the Triton provider")) 125 } 126 if data.Get("key_id").(string) == "" { 127 validationError = multierror.Append(validationError, errors.New("`Key ID` must be configured for the Triton provider")) 128 } 129 if b.path == "" { 130 validationError = multierror.Append(validationError, errors.New("`Path` must be configured for the Triton provider")) 131 } 132 133 if validationError != nil { 134 return validationError 135 } 136 137 var signer authentication.Signer 138 var err error 139 140 if config.KeyMaterial == "" { 141 input := authentication.SSHAgentSignerInput{ 142 KeyID: config.KeyId, 143 AccountName: config.AccountId, 144 Username: config.Username, 145 } 146 signer, err = authentication.NewSSHAgentSigner(input) 147 if err != nil { 148 return errwrap.Wrapf("Error Creating SSH Agent Signer: {{err}}", err) 149 } 150 } else { 151 var keyBytes []byte 152 if _, err = os.Stat(config.KeyMaterial); err == nil { 153 keyBytes, err = ioutil.ReadFile(config.KeyMaterial) 154 if err != nil { 155 return fmt.Errorf("Error reading key material from %s: %s", 156 config.KeyMaterial, err) 157 } 158 block, _ := pem.Decode(keyBytes) 159 if block == nil { 160 return fmt.Errorf( 161 "Failed to read key material '%s': no key found", config.KeyMaterial) 162 } 163 164 if block.Headers["Proc-Type"] == "4,ENCRYPTED" { 165 return fmt.Errorf( 166 "Failed to read key '%s': password protected keys are\n"+ 167 "not currently supported. Please decrypt the key prior to use.", config.KeyMaterial) 168 } 169 170 } else { 171 keyBytes = []byte(config.KeyMaterial) 172 } 173 174 input := authentication.PrivateKeySignerInput{ 175 KeyID: config.KeyId, 176 PrivateKeyMaterial: keyBytes, 177 AccountName: config.AccountId, 178 Username: config.Username, 179 } 180 181 signer, err = authentication.NewPrivateKeySigner(input) 182 if err != nil { 183 return errwrap.Wrapf("Error Creating SSH Private Key Signer: {{err}}", err) 184 } 185 } 186 187 clientConfig := &triton.ClientConfig{ 188 MantaURL: config.AccountUrl, 189 AccountName: config.AccountId, 190 Username: config.Username, 191 Signers: []authentication.Signer{signer}, 192 } 193 triton, err := storage.NewClient(clientConfig) 194 if err != nil { 195 return err 196 } 197 198 b.storageClient = triton 199 200 return nil 201 }