github.com/hugorut/terraform@v1.1.3/src/backend/remote-state/http/backend.go (about)

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