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  }