github.com/sathish1597/hashicorp-terraform@v0.11.12-beta1/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 Deprecated: "please use the object_name attribute", 69 }, 70 71 "object_name": { 72 Type: schema.TypeString, 73 Optional: true, 74 // Set this default once the objectName attribute is removed! 75 // Default: "terraform.tfstate", 76 }, 77 }, 78 } 79 80 result := &Backend{Backend: s} 81 result.Backend.ConfigureFunc = result.configure 82 return result 83 } 84 85 type Backend struct { 86 *schema.Backend 87 data *schema.ResourceData 88 89 // The fields below are set from configure 90 storageClient *storage.StorageClient 91 path string 92 objectName string 93 } 94 95 type BackendConfig struct { 96 AccountId string 97 Username string 98 KeyId string 99 AccountUrl string 100 KeyMaterial string 101 SkipTls bool 102 } 103 104 func (b *Backend) configure(ctx context.Context) error { 105 if b.path != "" { 106 return nil 107 } 108 109 data := schema.FromContextBackendConfig(ctx) 110 111 config := &BackendConfig{ 112 AccountId: data.Get("account").(string), 113 AccountUrl: data.Get("url").(string), 114 KeyId: data.Get("key_id").(string), 115 SkipTls: data.Get("insecure_skip_tls_verify").(bool), 116 } 117 118 if v, ok := data.GetOk("user"); ok { 119 config.Username = v.(string) 120 } 121 122 if v, ok := data.GetOk("key_material"); ok { 123 config.KeyMaterial = v.(string) 124 } 125 126 b.path = data.Get("path").(string) 127 b.objectName = data.Get("object_name").(string) 128 129 // If object_name is not set, try the deprecated objectName. 130 if b.objectName == "" { 131 b.objectName = data.Get("objectName").(string) 132 } 133 134 var validationError *multierror.Error 135 136 if data.Get("account").(string) == "" { 137 validationError = multierror.Append(validationError, errors.New("`Account` must be configured for the Triton provider")) 138 } 139 if data.Get("key_id").(string) == "" { 140 validationError = multierror.Append(validationError, errors.New("`Key ID` must be configured for the Triton provider")) 141 } 142 if b.path == "" { 143 validationError = multierror.Append(validationError, errors.New("`Path` must be configured for the Triton provider")) 144 } 145 146 if validationError != nil { 147 return validationError 148 } 149 150 var signer authentication.Signer 151 var err error 152 153 if config.KeyMaterial == "" { 154 input := authentication.SSHAgentSignerInput{ 155 KeyID: config.KeyId, 156 AccountName: config.AccountId, 157 Username: config.Username, 158 } 159 signer, err = authentication.NewSSHAgentSigner(input) 160 if err != nil { 161 return errwrap.Wrapf("Error Creating SSH Agent Signer: {{err}}", err) 162 } 163 } else { 164 var keyBytes []byte 165 if _, err = os.Stat(config.KeyMaterial); err == nil { 166 keyBytes, err = ioutil.ReadFile(config.KeyMaterial) 167 if err != nil { 168 return fmt.Errorf("Error reading key material from %s: %s", 169 config.KeyMaterial, err) 170 } 171 block, _ := pem.Decode(keyBytes) 172 if block == nil { 173 return fmt.Errorf( 174 "Failed to read key material '%s': no key found", config.KeyMaterial) 175 } 176 177 if block.Headers["Proc-Type"] == "4,ENCRYPTED" { 178 return fmt.Errorf( 179 "Failed to read key '%s': password protected keys are\n"+ 180 "not currently supported. Please decrypt the key prior to use.", config.KeyMaterial) 181 } 182 183 } else { 184 keyBytes = []byte(config.KeyMaterial) 185 } 186 187 input := authentication.PrivateKeySignerInput{ 188 KeyID: config.KeyId, 189 PrivateKeyMaterial: keyBytes, 190 AccountName: config.AccountId, 191 Username: config.Username, 192 } 193 194 signer, err = authentication.NewPrivateKeySigner(input) 195 if err != nil { 196 return errwrap.Wrapf("Error Creating SSH Private Key Signer: {{err}}", err) 197 } 198 } 199 200 clientConfig := &triton.ClientConfig{ 201 MantaURL: config.AccountUrl, 202 AccountName: config.AccountId, 203 Username: config.Username, 204 Signers: []authentication.Signer{signer}, 205 } 206 triton, err := storage.NewClient(clientConfig) 207 if err != nil { 208 return err 209 } 210 211 b.storageClient = triton 212 213 return nil 214 }