parent
9ec414016d
commit
a4ceaf0035
|
@ -3,7 +3,10 @@ package physical
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/coreos/etcd/client"
|
"github.com/coreos/etcd/client"
|
||||||
"github.com/coreos/go-semver/semver"
|
"github.com/coreos/go-semver/semver"
|
||||||
|
@ -13,6 +16,7 @@ import (
|
||||||
var (
|
var (
|
||||||
EtcdSyncConfigError = errors.New("client setup failed: unable to parse etcd sync field in config")
|
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")
|
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')")
|
EtcdAddressError = errors.New("client setup failed: address must be valid URL (ex. 'scheme://host:port')")
|
||||||
EtcdSemaphoreKeysEmptyError = errors.New("lock queue is empty")
|
EtcdSemaphoreKeysEmptyError = errors.New("lock queue is empty")
|
||||||
EtcdLockHeldError = errors.New("lock already held")
|
EtcdLockHeldError = errors.New("lock already held")
|
||||||
|
@ -95,3 +99,47 @@ func getEtcdAPIVersion(c client.Client) (string, error) {
|
||||||
|
|
||||||
return "3", nil
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
"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) {
|
func newEtcdV2Client(conf map[string]string) (client.Client, error) {
|
||||||
// Set a default machines list and check for an overriding address value.
|
endpoints, err := getEtcdEndpoints(conf)
|
||||||
machines := "http://127.0.0.1:2379"
|
if err != nil {
|
||||||
if address, ok := conf["address"]; ok {
|
return nil, err
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new client from the supplied address and attempt to sync with the
|
// 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{
|
cfg := client.Config{
|
||||||
Endpoints: machinesParsed,
|
Endpoints: endpoints,
|
||||||
Transport: cTransport,
|
Transport: cTransport,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,10 +48,9 @@ func newEtcd3Backend(conf map[string]string, logger log.Logger) (Backend, error)
|
||||||
path = "/" + path
|
path = "/" + path
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set a default machines list and check for an overriding address value.
|
endpoints, err := getEtcdEndpoints(conf)
|
||||||
endpoints := []string{"http://127.0.0.1:2379"}
|
if err != nil {
|
||||||
if address, ok := conf["address"]; ok {
|
return nil, err
|
||||||
endpoints = strings.Split(address, ",")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := clientv3.Config{
|
cfg := clientv3.Config{
|
||||||
|
|
|
@ -36,6 +36,10 @@ storage "etcd" {
|
||||||
Etcd instances as a comma-separated list. This can also be provided via the
|
Etcd instances as a comma-separated list. This can also be provided via the
|
||||||
environment variable `ETCD_ADDR`.
|
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
|
- `etcd_api` `(string: "<varies>")` – Specifies the version of the API to
|
||||||
communicate with. By default, this is derived automatically. If the cluster
|
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
|
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
|
## `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
|
### Custom Authentication
|
||||||
|
|
||||||
This example shows connecting to the Etcd cluster using a username and password.
|
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"
|
[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"
|
||||||
|
|
Loading…
Reference in a new issue