Etcd DNS discovery (#2521)

* etcd: Add discovery_srv option
This commit is contained in:
Jonathan Sokolowski 2017-04-05 01:50:44 +10:00 committed by Jeff Mitchell
parent 9ec414016d
commit a4ceaf0035
4 changed files with 72 additions and 23 deletions

View file

@ -3,7 +3,10 @@ package physical
import (
"context"
"errors"
"fmt"
"net/url"
"os"
"strings"
"github.com/coreos/etcd/client"
"github.com/coreos/go-semver/semver"
@ -13,6 +16,7 @@ import (
var (
EtcdSyncConfigError = errors.New("client setup failed: unable to parse etcd sync field in config")
EtcdSyncClusterError = errors.New("client setup failed: unable to sync etcd cluster")
EtcdMultipleBootstrapError = errors.New("client setup failed: multiple discovery or bootstrap flags specified, use either \"address\" or \"discovery_srv\"")
EtcdAddressError = errors.New("client setup failed: address must be valid URL (ex. 'scheme://host:port')")
EtcdSemaphoreKeysEmptyError = errors.New("lock queue is empty")
EtcdLockHeldError = errors.New("lock already held")
@ -95,3 +99,47 @@ func getEtcdAPIVersion(c client.Client) (string, error) {
return "3", nil
}
// Retrieves the config option in order of priority:
// 1. The named environment variable if it exist
// 2. The key in the config map
func getEtcdOption(conf map[string]string, confKey, envVar string) (string, bool) {
confVal, inConf := conf[confKey]
envVal, inEnv := os.LookupEnv(envVar)
if inEnv {
return envVal, true
}
return confVal, inConf
}
func getEtcdEndpoints(conf map[string]string) ([]string, error) {
address, staticBootstrap := getEtcdOption(conf, "address", "ETCD_ADDR")
domain, useSrv := getEtcdOption(conf, "discovery_srv", "ETCD_DISCOVERY_SRV")
if useSrv && staticBootstrap {
return nil, EtcdMultipleBootstrapError
}
if staticBootstrap {
endpoints := strings.Split(address, Etcd2MachineDelimiter)
// Verify that the machines are valid URLs
for _, e := range endpoints {
u, urlErr := url.Parse(e)
if urlErr != nil || u.Scheme == "" {
return nil, EtcdAddressError
}
}
return endpoints, nil
}
if useSrv {
discoverer := client.NewSRVDiscover()
endpoints, err := discoverer.Discover(domain)
if err != nil {
return nil, fmt.Errorf("failed to discover etcd endpoints through SRV discovery: %v", err)
}
return endpoints, nil
}
// Set a default endpoints list if no option was set
return []string{"http://127.0.0.1:2379"}, nil
}

View file

@ -4,7 +4,6 @@ import (
"context"
"encoding/base64"
"fmt"
"net/url"
"os"
"path/filepath"
"strconv"
@ -118,23 +117,9 @@ func newEtcd2Backend(conf map[string]string, logger log.Logger) (Backend, error)
}
func newEtcdV2Client(conf map[string]string) (client.Client, error) {
// Set a default machines list and check for an overriding address value.
machines := "http://127.0.0.1:2379"
if address, ok := conf["address"]; ok {
machines = address
}
machinesEnv := os.Getenv("ETCD_ADDR")
if machinesEnv != "" {
machines = machinesEnv
}
machinesParsed := strings.Split(machines, Etcd2MachineDelimiter)
// Verify that the machines are valid URLs
for _, machine := range machinesParsed {
u, urlErr := url.Parse(machine)
if urlErr != nil || u.Scheme == "" {
return nil, EtcdAddressError
}
endpoints, err := getEtcdEndpoints(conf)
if err != nil {
return nil, err
}
// Create a new client from the supplied address and attempt to sync with the
@ -160,7 +145,7 @@ func newEtcdV2Client(conf map[string]string) (client.Client, error) {
}
cfg := client.Config{
Endpoints: machinesParsed,
Endpoints: endpoints,
Transport: cTransport,
}

View file

@ -48,10 +48,9 @@ func newEtcd3Backend(conf map[string]string, logger log.Logger) (Backend, error)
path = "/" + path
}
// Set a default machines list and check for an overriding address value.
endpoints := []string{"http://127.0.0.1:2379"}
if address, ok := conf["address"]; ok {
endpoints = strings.Split(address, ",")
endpoints, err := getEtcdEndpoints(conf)
if err != nil {
return nil, err
}
cfg := clientv3.Config{

View file

@ -36,6 +36,10 @@ storage "etcd" {
Etcd instances as a comma-separated list. This can also be provided via the
environment variable `ETCD_ADDR`.
- `discovery_srv` `(string: "example.com")` - Specifies the domain name to
query for SRV records describing cluster endpoints. This can also be provided
via the environment variable `ETCD_DISCOVERY_SRV`.
- `etcd_api` `(string: "<varies>")` Specifies the version of the API to
communicate with. By default, this is derived automatically. If the cluster
version is 3.1+ and there has been no data written using the v2 API, the
@ -89,6 +93,18 @@ discussed in more detail in the [HA concepts page](/docs/concepts/ha.html).
## `etcd` Examples
### DNS Discovery of cluster members
This example configures vault to discover the Etcd cluster members via SRV
records as outlined in the
[DNS Discovery protocol documentation][dns discovery].
```hcl
storage "etcd" {
discovery_srv = "example.com"
}
```
### Custom Authentication
This example shows connecting to the Etcd cluster using a username and password.
@ -122,3 +138,4 @@ storage "etcd" {
```
[etcd]: https://coreos.com/etcd "Etcd by CoreOS"
[dns discovery]: https://coreos.com/etcd/docs/latest/op-guide/clustering.html#dns-discovery "Etcd cluster DNS Discovery"