github.com/Kevinklinger/open_terraform@v0.11.12-beta1/backend/remote-state/consul/backend.go (about)

     1  package consul
     2  
     3  import (
     4  	"context"
     5  	"net"
     6  	"strings"
     7  	"time"
     8  
     9  	consulapi "github.com/hashicorp/consul/api"
    10  	"github.com/hashicorp/terraform/backend"
    11  	"github.com/hashicorp/terraform/helper/schema"
    12  )
    13  
    14  // New creates a new backend for Consul remote state.
    15  func New() backend.Backend {
    16  	s := &schema.Backend{
    17  		Schema: map[string]*schema.Schema{
    18  			"path": &schema.Schema{
    19  				Type:        schema.TypeString,
    20  				Required:    true,
    21  				Description: "Path to store state in Consul",
    22  			},
    23  
    24  			"access_token": &schema.Schema{
    25  				Type:        schema.TypeString,
    26  				Optional:    true,
    27  				Description: "Access token for a Consul ACL",
    28  				Default:     "", // To prevent input
    29  			},
    30  
    31  			"address": &schema.Schema{
    32  				Type:        schema.TypeString,
    33  				Optional:    true,
    34  				Description: "Address to the Consul Cluster",
    35  				Default:     "", // To prevent input
    36  			},
    37  
    38  			"scheme": &schema.Schema{
    39  				Type:        schema.TypeString,
    40  				Optional:    true,
    41  				Description: "Scheme to communicate to Consul with",
    42  				Default:     "", // To prevent input
    43  			},
    44  
    45  			"datacenter": &schema.Schema{
    46  				Type:        schema.TypeString,
    47  				Optional:    true,
    48  				Description: "Datacenter to communicate with",
    49  				Default:     "", // To prevent input
    50  			},
    51  
    52  			"http_auth": &schema.Schema{
    53  				Type:        schema.TypeString,
    54  				Optional:    true,
    55  				Description: "HTTP Auth in the format of 'username:password'",
    56  				Default:     "", // To prevent input
    57  			},
    58  
    59  			"gzip": &schema.Schema{
    60  				Type:        schema.TypeBool,
    61  				Optional:    true,
    62  				Description: "Compress the state data using gzip",
    63  				Default:     false,
    64  			},
    65  
    66  			"lock": &schema.Schema{
    67  				Type:        schema.TypeBool,
    68  				Optional:    true,
    69  				Description: "Lock state access",
    70  				Default:     true,
    71  			},
    72  
    73  			"ca_file": &schema.Schema{
    74  				Type:        schema.TypeString,
    75  				Optional:    true,
    76  				Description: "A path to a PEM-encoded certificate authority used to verify the remote agent's certificate.",
    77  				DefaultFunc: schema.EnvDefaultFunc("CONSUL_CACERT", ""),
    78  			},
    79  
    80  			"cert_file": &schema.Schema{
    81  				Type:        schema.TypeString,
    82  				Optional:    true,
    83  				Description: "A path to a PEM-encoded certificate provided to the remote agent; requires use of key_file.",
    84  				DefaultFunc: schema.EnvDefaultFunc("CONSUL_CLIENT_CERT", ""),
    85  			},
    86  
    87  			"key_file": &schema.Schema{
    88  				Type:        schema.TypeString,
    89  				Optional:    true,
    90  				Description: "A path to a PEM-encoded private key, required if cert_file is specified.",
    91  				DefaultFunc: schema.EnvDefaultFunc("CONSUL_CLIENT_KEY", ""),
    92  			},
    93  		},
    94  	}
    95  
    96  	result := &Backend{Backend: s}
    97  	result.Backend.ConfigureFunc = result.configure
    98  	return result
    99  }
   100  
   101  type Backend struct {
   102  	*schema.Backend
   103  
   104  	// The fields below are set from configure
   105  	client     *consulapi.Client
   106  	configData *schema.ResourceData
   107  	lock       bool
   108  }
   109  
   110  func (b *Backend) configure(ctx context.Context) error {
   111  	// Grab the resource data
   112  	b.configData = schema.FromContextBackendConfig(ctx)
   113  
   114  	// Store the lock information
   115  	b.lock = b.configData.Get("lock").(bool)
   116  
   117  	data := b.configData
   118  
   119  	// Configure the client
   120  	config := consulapi.DefaultConfig()
   121  
   122  	// replace the default Transport Dialer to reduce the KeepAlive
   123  	config.Transport.DialContext = dialContext
   124  
   125  	if v, ok := data.GetOk("access_token"); ok && v.(string) != "" {
   126  		config.Token = v.(string)
   127  	}
   128  	if v, ok := data.GetOk("address"); ok && v.(string) != "" {
   129  		config.Address = v.(string)
   130  	}
   131  	if v, ok := data.GetOk("scheme"); ok && v.(string) != "" {
   132  		config.Scheme = v.(string)
   133  	}
   134  	if v, ok := data.GetOk("datacenter"); ok && v.(string) != "" {
   135  		config.Datacenter = v.(string)
   136  	}
   137  
   138  	if v, ok := data.GetOk("ca_file"); ok && v.(string) != "" {
   139  		config.TLSConfig.CAFile = v.(string)
   140  	}
   141  	if v, ok := data.GetOk("cert_file"); ok && v.(string) != "" {
   142  		config.TLSConfig.CertFile = v.(string)
   143  	}
   144  	if v, ok := data.GetOk("key_file"); ok && v.(string) != "" {
   145  		config.TLSConfig.KeyFile = v.(string)
   146  	}
   147  
   148  	if v, ok := data.GetOk("http_auth"); ok && v.(string) != "" {
   149  		auth := v.(string)
   150  
   151  		var username, password string
   152  		if strings.Contains(auth, ":") {
   153  			split := strings.SplitN(auth, ":", 2)
   154  			username = split[0]
   155  			password = split[1]
   156  		} else {
   157  			username = auth
   158  		}
   159  
   160  		config.HttpAuth = &consulapi.HttpBasicAuth{
   161  			Username: username,
   162  			Password: password,
   163  		}
   164  	}
   165  
   166  	client, err := consulapi.NewClient(config)
   167  	if err != nil {
   168  		return err
   169  	}
   170  
   171  	b.client = client
   172  	return nil
   173  }
   174  
   175  // dialContext is the DialContext function for the consul client transport.
   176  // This is stored in a package var to inject a different dialer for tests.
   177  var dialContext = (&net.Dialer{
   178  	Timeout:   30 * time.Second,
   179  	KeepAlive: 17 * time.Second,
   180  }).DialContext