github.com/codeherentuk/terraform@v0.11.12-beta1/backend/remote-state/etcdv3/backend.go (about)

     1  package etcd
     2  
     3  import (
     4  	"context"
     5  
     6  	etcdv3 "github.com/coreos/etcd/clientv3"
     7  	"github.com/coreos/etcd/pkg/transport"
     8  	"github.com/hashicorp/terraform/backend"
     9  	"github.com/hashicorp/terraform/helper/schema"
    10  )
    11  
    12  const (
    13  	endpointsKey       = "endpoints"
    14  	usernameKey        = "username"
    15  	usernameEnvVarName = "ETCDV3_USERNAME"
    16  	passwordKey        = "password"
    17  	passwordEnvVarName = "ETCDV3_PASSWORD"
    18  	prefixKey          = "prefix"
    19  	lockKey            = "lock"
    20  	cacertPathKey      = "cacert_path"
    21  	certPathKey        = "cert_path"
    22  	keyPathKey         = "key_path"
    23  )
    24  
    25  func New() backend.Backend {
    26  	s := &schema.Backend{
    27  		Schema: map[string]*schema.Schema{
    28  			endpointsKey: &schema.Schema{
    29  				Type: schema.TypeList,
    30  				Elem: &schema.Schema{
    31  					Type: schema.TypeString,
    32  				},
    33  				MinItems:    1,
    34  				Required:    true,
    35  				Description: "Endpoints for the etcd cluster.",
    36  			},
    37  
    38  			usernameKey: &schema.Schema{
    39  				Type:        schema.TypeString,
    40  				Optional:    true,
    41  				Description: "Username used to connect to the etcd cluster.",
    42  				DefaultFunc: schema.EnvDefaultFunc(usernameEnvVarName, ""),
    43  			},
    44  
    45  			passwordKey: &schema.Schema{
    46  				Type:        schema.TypeString,
    47  				Optional:    true,
    48  				Description: "Password used to connect to the etcd cluster.",
    49  				DefaultFunc: schema.EnvDefaultFunc(passwordEnvVarName, ""),
    50  			},
    51  
    52  			prefixKey: &schema.Schema{
    53  				Type:        schema.TypeString,
    54  				Optional:    true,
    55  				Description: "An optional prefix to be added to keys when to storing state in etcd.",
    56  				Default:     "",
    57  			},
    58  
    59  			lockKey: &schema.Schema{
    60  				Type:        schema.TypeBool,
    61  				Optional:    true,
    62  				Description: "Whether to lock state access.",
    63  				Default:     true,
    64  			},
    65  
    66  			cacertPathKey: &schema.Schema{
    67  				Type:        schema.TypeString,
    68  				Optional:    true,
    69  				Description: "The path to a PEM-encoded CA bundle with which to verify certificates of TLS-enabled etcd servers.",
    70  				Default:     "",
    71  			},
    72  
    73  			certPathKey: &schema.Schema{
    74  				Type:        schema.TypeString,
    75  				Optional:    true,
    76  				Description: "The path to a PEM-encoded certificate to provide to etcd for secure client identification.",
    77  				Default:     "",
    78  			},
    79  
    80  			keyPathKey: &schema.Schema{
    81  				Type:        schema.TypeString,
    82  				Optional:    true,
    83  				Description: "The path to a PEM-encoded key to provide to etcd for secure client identification.",
    84  				Default:     "",
    85  			},
    86  		},
    87  	}
    88  
    89  	result := &Backend{Backend: s}
    90  	result.Backend.ConfigureFunc = result.configure
    91  	return result
    92  }
    93  
    94  type Backend struct {
    95  	*schema.Backend
    96  
    97  	// The fields below are set from configure.
    98  	client *etcdv3.Client
    99  	data   *schema.ResourceData
   100  	lock   bool
   101  	prefix string
   102  }
   103  
   104  func (b *Backend) configure(ctx context.Context) error {
   105  	var err error
   106  	// Grab the resource data.
   107  	b.data = schema.FromContextBackendConfig(ctx)
   108  	// Store the lock information.
   109  	b.lock = b.data.Get(lockKey).(bool)
   110  	// Store the prefix information.
   111  	b.prefix = b.data.Get(prefixKey).(string)
   112  	// Initialize a client to test config.
   113  	b.client, err = b.rawClient()
   114  	// Return err, if any.
   115  	return err
   116  }
   117  
   118  func (b *Backend) rawClient() (*etcdv3.Client, error) {
   119  	config := etcdv3.Config{}
   120  	tlsInfo := transport.TLSInfo{}
   121  
   122  	if v, ok := b.data.GetOk(endpointsKey); ok {
   123  		config.Endpoints = retrieveEndpoints(v)
   124  	}
   125  	if v, ok := b.data.GetOk(usernameKey); ok && v.(string) != "" {
   126  		config.Username = v.(string)
   127  	}
   128  	if v, ok := b.data.GetOk(passwordKey); ok && v.(string) != "" {
   129  		config.Password = v.(string)
   130  	}
   131  	if v, ok := b.data.GetOk(cacertPathKey); ok && v.(string) != "" {
   132  		tlsInfo.TrustedCAFile = v.(string)
   133  	}
   134  	if v, ok := b.data.GetOk(certPathKey); ok && v.(string) != "" {
   135  		tlsInfo.CertFile = v.(string)
   136  	}
   137  	if v, ok := b.data.GetOk(keyPathKey); ok && v.(string) != "" {
   138  		tlsInfo.KeyFile = v.(string)
   139  	}
   140  
   141  	if tlsCfg, err := tlsInfo.ClientConfig(); err != nil {
   142  		return nil, err
   143  	} else if !tlsInfo.Empty() {
   144  		config.TLS = tlsCfg // Assign TLS configuration only if it valid and non-empty.
   145  	}
   146  
   147  	return etcdv3.New(config)
   148  }
   149  
   150  func retrieveEndpoints(v interface{}) []string {
   151  	var endpoints []string
   152  	list := v.([]interface{})
   153  	for _, ep := range list {
   154  		endpoints = append(endpoints, ep.(string))
   155  	}
   156  	return endpoints
   157  }