| package consul |
| |
| import ( |
| "context" |
| "net" |
| "strings" |
| "time" |
| |
| consulapi "github.com/hashicorp/consul/api" |
| "github.com/hashicorp/terraform/internal/backend" |
| "github.com/hashicorp/terraform/internal/legacy/helper/schema" |
| ) |
| |
| // New creates a new backend for Consul remote state. |
| func New() backend.Backend { |
| s := &schema.Backend{ |
| Schema: map[string]*schema.Schema{ |
| "path": &schema.Schema{ |
| Type: schema.TypeString, |
| Required: true, |
| Description: "Path to store state in Consul", |
| }, |
| |
| "access_token": &schema.Schema{ |
| Type: schema.TypeString, |
| Optional: true, |
| Description: "Access token for a Consul ACL", |
| Default: "", // To prevent input |
| }, |
| |
| "address": &schema.Schema{ |
| Type: schema.TypeString, |
| Optional: true, |
| Description: "Address to the Consul Cluster", |
| Default: "", // To prevent input |
| }, |
| |
| "scheme": &schema.Schema{ |
| Type: schema.TypeString, |
| Optional: true, |
| Description: "Scheme to communicate to Consul with", |
| Default: "", // To prevent input |
| }, |
| |
| "datacenter": &schema.Schema{ |
| Type: schema.TypeString, |
| Optional: true, |
| Description: "Datacenter to communicate with", |
| Default: "", // To prevent input |
| }, |
| |
| "http_auth": &schema.Schema{ |
| Type: schema.TypeString, |
| Optional: true, |
| Description: "HTTP Auth in the format of 'username:password'", |
| Default: "", // To prevent input |
| }, |
| |
| "gzip": &schema.Schema{ |
| Type: schema.TypeBool, |
| Optional: true, |
| Description: "Compress the state data using gzip", |
| Default: false, |
| }, |
| |
| "lock": &schema.Schema{ |
| Type: schema.TypeBool, |
| Optional: true, |
| Description: "Lock state access", |
| Default: true, |
| }, |
| |
| "ca_file": &schema.Schema{ |
| Type: schema.TypeString, |
| Optional: true, |
| Description: "A path to a PEM-encoded certificate authority used to verify the remote agent's certificate.", |
| DefaultFunc: schema.EnvDefaultFunc("CONSUL_CACERT", ""), |
| }, |
| |
| "cert_file": &schema.Schema{ |
| Type: schema.TypeString, |
| Optional: true, |
| Description: "A path to a PEM-encoded certificate provided to the remote agent; requires use of key_file.", |
| DefaultFunc: schema.EnvDefaultFunc("CONSUL_CLIENT_CERT", ""), |
| }, |
| |
| "key_file": &schema.Schema{ |
| Type: schema.TypeString, |
| Optional: true, |
| Description: "A path to a PEM-encoded private key, required if cert_file is specified.", |
| DefaultFunc: schema.EnvDefaultFunc("CONSUL_CLIENT_KEY", ""), |
| }, |
| }, |
| } |
| |
| result := &Backend{Backend: s} |
| result.Backend.ConfigureFunc = result.configure |
| return result |
| } |
| |
| type Backend struct { |
| *schema.Backend |
| |
| // The fields below are set from configure |
| client *consulapi.Client |
| configData *schema.ResourceData |
| lock bool |
| } |
| |
| func (b *Backend) configure(ctx context.Context) error { |
| // Grab the resource data |
| b.configData = schema.FromContextBackendConfig(ctx) |
| |
| // Store the lock information |
| b.lock = b.configData.Get("lock").(bool) |
| |
| data := b.configData |
| |
| // Configure the client |
| config := consulapi.DefaultConfig() |
| |
| // replace the default Transport Dialer to reduce the KeepAlive |
| config.Transport.DialContext = dialContext |
| |
| if v, ok := data.GetOk("access_token"); ok && v.(string) != "" { |
| config.Token = v.(string) |
| } |
| if v, ok := data.GetOk("address"); ok && v.(string) != "" { |
| config.Address = v.(string) |
| } |
| if v, ok := data.GetOk("scheme"); ok && v.(string) != "" { |
| config.Scheme = v.(string) |
| } |
| if v, ok := data.GetOk("datacenter"); ok && v.(string) != "" { |
| config.Datacenter = v.(string) |
| } |
| |
| if v, ok := data.GetOk("ca_file"); ok && v.(string) != "" { |
| config.TLSConfig.CAFile = v.(string) |
| } |
| if v, ok := data.GetOk("cert_file"); ok && v.(string) != "" { |
| config.TLSConfig.CertFile = v.(string) |
| } |
| if v, ok := data.GetOk("key_file"); ok && v.(string) != "" { |
| config.TLSConfig.KeyFile = v.(string) |
| } |
| |
| if v, ok := data.GetOk("http_auth"); ok && v.(string) != "" { |
| auth := v.(string) |
| |
| var username, password string |
| if strings.Contains(auth, ":") { |
| split := strings.SplitN(auth, ":", 2) |
| username = split[0] |
| password = split[1] |
| } else { |
| username = auth |
| } |
| |
| config.HttpAuth = &consulapi.HttpBasicAuth{ |
| Username: username, |
| Password: password, |
| } |
| } |
| |
| client, err := consulapi.NewClient(config) |
| if err != nil { |
| return err |
| } |
| |
| b.client = client |
| return nil |
| } |
| |
| // dialContext is the DialContext function for the consul client transport. |
| // This is stored in a package var to inject a different dialer for tests. |
| var dialContext = (&net.Dialer{ |
| Timeout: 30 * time.Second, |
| KeepAlive: 17 * time.Second, |
| }).DialContext |