github.com/ctrox/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 }