github.com/muratcelep/terraform@v1.1.0-beta2-not-internal-4/not-internal/backend/remote-state/http/backend.go (about) 1 package http 2 3 import ( 4 "context" 5 "crypto/tls" 6 "fmt" 7 "net/http" 8 "net/url" 9 "time" 10 11 "github.com/hashicorp/go-cleanhttp" 12 "github.com/hashicorp/go-retryablehttp" 13 "github.com/muratcelep/terraform/not-internal/backend" 14 "github.com/muratcelep/terraform/not-internal/legacy/helper/schema" 15 "github.com/muratcelep/terraform/not-internal/states/remote" 16 "github.com/muratcelep/terraform/not-internal/states/statemgr" 17 ) 18 19 func New() backend.Backend { 20 s := &schema.Backend{ 21 Schema: map[string]*schema.Schema{ 22 "address": &schema.Schema{ 23 Type: schema.TypeString, 24 Required: true, 25 DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_ADDRESS", nil), 26 Description: "The address of the REST endpoint", 27 }, 28 "update_method": &schema.Schema{ 29 Type: schema.TypeString, 30 Optional: true, 31 DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_UPDATE_METHOD", "POST"), 32 Description: "HTTP method to use when updating state", 33 }, 34 "lock_address": &schema.Schema{ 35 Type: schema.TypeString, 36 Optional: true, 37 DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_LOCK_ADDRESS", nil), 38 Description: "The address of the lock REST endpoint", 39 }, 40 "unlock_address": &schema.Schema{ 41 Type: schema.TypeString, 42 Optional: true, 43 DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_UNLOCK_ADDRESS", nil), 44 Description: "The address of the unlock REST endpoint", 45 }, 46 "lock_method": &schema.Schema{ 47 Type: schema.TypeString, 48 Optional: true, 49 DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_LOCK_METHOD", "LOCK"), 50 Description: "The HTTP method to use when locking", 51 }, 52 "unlock_method": &schema.Schema{ 53 Type: schema.TypeString, 54 Optional: true, 55 DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_UNLOCK_METHOD", "UNLOCK"), 56 Description: "The HTTP method to use when unlocking", 57 }, 58 "username": &schema.Schema{ 59 Type: schema.TypeString, 60 Optional: true, 61 DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_USERNAME", nil), 62 Description: "The username for HTTP basic authentication", 63 }, 64 "password": &schema.Schema{ 65 Type: schema.TypeString, 66 Optional: true, 67 DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_PASSWORD", nil), 68 Description: "The password for HTTP basic authentication", 69 }, 70 "skip_cert_verification": &schema.Schema{ 71 Type: schema.TypeBool, 72 Optional: true, 73 Default: false, 74 Description: "Whether to skip TLS verification.", 75 }, 76 "retry_max": &schema.Schema{ 77 Type: schema.TypeInt, 78 Optional: true, 79 DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_RETRY_MAX", 2), 80 Description: "The number of HTTP request retries.", 81 }, 82 "retry_wait_min": &schema.Schema{ 83 Type: schema.TypeInt, 84 Optional: true, 85 DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_RETRY_WAIT_MIN", 1), 86 Description: "The minimum time in seconds to wait between HTTP request attempts.", 87 }, 88 "retry_wait_max": &schema.Schema{ 89 Type: schema.TypeInt, 90 Optional: true, 91 DefaultFunc: schema.EnvDefaultFunc("TF_HTTP_RETRY_WAIT_MAX", 30), 92 Description: "The maximum time in seconds to wait between HTTP request attempts.", 93 }, 94 }, 95 } 96 97 b := &Backend{Backend: s} 98 b.Backend.ConfigureFunc = b.configure 99 return b 100 } 101 102 type Backend struct { 103 *schema.Backend 104 105 client *httpClient 106 } 107 108 func (b *Backend) configure(ctx context.Context) error { 109 data := schema.FromContextBackendConfig(ctx) 110 111 address := data.Get("address").(string) 112 updateURL, err := url.Parse(address) 113 if err != nil { 114 return fmt.Errorf("failed to parse address URL: %s", err) 115 } 116 if updateURL.Scheme != "http" && updateURL.Scheme != "https" { 117 return fmt.Errorf("address must be HTTP or HTTPS") 118 } 119 120 updateMethod := data.Get("update_method").(string) 121 122 var lockURL *url.URL 123 if v, ok := data.GetOk("lock_address"); ok && v.(string) != "" { 124 var err error 125 lockURL, err = url.Parse(v.(string)) 126 if err != nil { 127 return fmt.Errorf("failed to parse lockAddress URL: %s", err) 128 } 129 if lockURL.Scheme != "http" && lockURL.Scheme != "https" { 130 return fmt.Errorf("lockAddress must be HTTP or HTTPS") 131 } 132 } 133 134 lockMethod := data.Get("lock_method").(string) 135 136 var unlockURL *url.URL 137 if v, ok := data.GetOk("unlock_address"); ok && v.(string) != "" { 138 var err error 139 unlockURL, err = url.Parse(v.(string)) 140 if err != nil { 141 return fmt.Errorf("failed to parse unlockAddress URL: %s", err) 142 } 143 if unlockURL.Scheme != "http" && unlockURL.Scheme != "https" { 144 return fmt.Errorf("unlockAddress must be HTTP or HTTPS") 145 } 146 } 147 148 unlockMethod := data.Get("unlock_method").(string) 149 150 client := cleanhttp.DefaultPooledClient() 151 152 if data.Get("skip_cert_verification").(bool) { 153 // ignores TLS verification 154 client.Transport.(*http.Transport).TLSClientConfig = &tls.Config{ 155 InsecureSkipVerify: true, 156 } 157 } 158 159 rClient := retryablehttp.NewClient() 160 rClient.HTTPClient = client 161 rClient.RetryMax = data.Get("retry_max").(int) 162 rClient.RetryWaitMin = time.Duration(data.Get("retry_wait_min").(int)) * time.Second 163 rClient.RetryWaitMax = time.Duration(data.Get("retry_wait_max").(int)) * time.Second 164 165 b.client = &httpClient{ 166 URL: updateURL, 167 UpdateMethod: updateMethod, 168 169 LockURL: lockURL, 170 LockMethod: lockMethod, 171 UnlockURL: unlockURL, 172 UnlockMethod: unlockMethod, 173 174 Username: data.Get("username").(string), 175 Password: data.Get("password").(string), 176 177 // accessible only for testing use 178 Client: rClient, 179 } 180 return nil 181 } 182 183 func (b *Backend) StateMgr(name string) (statemgr.Full, error) { 184 if name != backend.DefaultStateName { 185 return nil, backend.ErrWorkspacesNotSupported 186 } 187 188 return &remote.State{Client: b.client}, nil 189 } 190 191 func (b *Backend) Workspaces() ([]string, error) { 192 return nil, backend.ErrWorkspacesNotSupported 193 } 194 195 func (b *Backend) DeleteWorkspace(string) error { 196 return backend.ErrWorkspacesNotSupported 197 }