90 lines
2.5 KiB
Go
90 lines
2.5 KiB
Go
package etcd
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/url"
|
|
"os"
|
|
"strings"
|
|
|
|
log "github.com/hashicorp/go-hclog"
|
|
"github.com/hashicorp/vault/sdk/physical"
|
|
"go.etcd.io/etcd/client/v2"
|
|
)
|
|
|
|
var (
|
|
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')")
|
|
EtcdLockHeldError = errors.New("lock already held")
|
|
EtcdLockNotHeldError = errors.New("lock not held")
|
|
EtcdVersionUnknown = errors.New("etcd: unknown API version")
|
|
)
|
|
|
|
// NewEtcdBackend constructs a etcd backend using a given machine address.
|
|
func NewEtcdBackend(conf map[string]string, logger log.Logger) (physical.Backend, error) {
|
|
var (
|
|
apiVersion string
|
|
ok bool
|
|
)
|
|
|
|
if apiVersion, ok = conf["etcd_api"]; !ok {
|
|
apiVersion = os.Getenv("ETCD_API")
|
|
}
|
|
|
|
if apiVersion == "" {
|
|
apiVersion = "v3"
|
|
}
|
|
|
|
switch apiVersion {
|
|
case "3", "etcd3", "v3":
|
|
return newEtcd3Backend(conf, logger)
|
|
default:
|
|
return nil, EtcdVersionUnknown
|
|
}
|
|
}
|
|
|
|
// 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, ",")
|
|
// 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 {
|
|
srvName, _ := getEtcdOption(conf, "discovery_srv_name", "ETCD_DISCOVERY_SRV_NAME")
|
|
discoverer := client.NewSRVDiscover()
|
|
endpoints, err := discoverer.Discover(domain, srvName)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to discover etcd endpoints through SRV discovery: %w", err)
|
|
}
|
|
return endpoints, nil
|
|
}
|
|
|
|
// Set a default endpoints list if no option was set
|
|
return []string{"http://127.0.0.1:2379"}, nil
|
|
}
|