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