Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

etcdbackend: support version auto discovery #2299

Merged
merged 3 commits into from
Jan 26, 2017
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 52 additions & 4 deletions physical/etcd.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package physical

import (
"context"
"errors"
"os"

"github.com/coreos/etcd/client"
"github.com/coreos/go-semver/semver"
log "github.com/mgutz/logxi/v1"
)

Expand All @@ -25,22 +28,67 @@ func newEtcdBackend(conf map[string]string, logger log.Logger) (Backend, error)
ok bool
)

// v2 client can talk to both etcd2 and etcd3 thought API v2
c, err := newEtcdV2Client(conf)
if err != nil {
return nil, errors.New("failed to create etcd client: " + err.Error())
}

remoteAPIVersion, err := getEtcdAPIVersion(c)
if err != nil {
return nil, errors.New("failed to get etcd API version: " + err.Error())
}

if apiVersion, ok = conf["etcd_api"]; !ok {
apiVersion = os.Getenv("ETCD_API")
}

if apiVersion == "" {
// TODO: auto discover latest version
apiVersion = "2"
}
path, ok := conf["path"]
if !ok {
path = "/vault"
}
kAPI := client.NewKeysAPI(c)

// TODO: check etcd server version. Fail if there is a version mismatch
// keep using v2 if vault data exists in v2 and user does not explicitly
// ask for v3.
_, err := kAPI.Get(context.Background(), path, &client.GetOptions{})
if errorIsMissingKey(err) {
apiVersion = remoteAPIVersion
} else if err == nil {
apiVersion = "2"
} else {
return nil, errors.New("failed to check etcd status: " + err.Error())
}
}

switch apiVersion {
case "2", "etcd2", "v2":
return newEtcd2Backend(conf, logger)
case "3", "etcd3", "v3":
if remoteAPIVersion == "2" {
return nil, errors.New("etcd3 is required: etcd2 is running")
}
return newEtcd3Backend(conf, logger)
default:
return nil, EtcdVersionUnknow
}
}

func getEtcdAPIVersion(c client.Client) (string, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments on this function as to how the version is computed might be helpful.

v, err := c.GetVersion(context.Background())
if err != nil {
return "", err
}

sv, err := semver.NewVersion(v.Cluster)
if err != nil {
return "", nil
}

if sv.LessThan(*semver.Must(semver.NewVersion("3.1.0"))) {
return "2", nil
}

return "3", nil
}
88 changes: 46 additions & 42 deletions physical/etcd2.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,51 @@ func newEtcd2Backend(conf map[string]string, logger log.Logger) (Backend, error)
path = "/" + path
}

c, err := newEtcdV2Client(conf)
if err != nil {
return nil, err
}

haEnabled := os.Getenv("ETCD_HA_ENABLED")
if haEnabled == "" {
haEnabled = conf["ha_enabled"]
}
haEnabledBool, _ := strconv.ParseBool(haEnabled)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we catch the error here?


// Should we sync the cluster state? There are three available options
// for our client library: don't sync (required for some proxies), sync
// once, or sync periodically with AutoSync. We currently support the
// first two.
sync, ok := conf["sync"]
if !ok {
sync = "yes"
}
switch sync {
case "yes", "true", "y", "1":
ctx, cancel := context.WithTimeout(context.Background(), client.DefaultRequestTimeout)
syncErr := c.Sync(ctx)
cancel()
if syncErr != nil {
return nil, fmt.Errorf("%s: %s", EtcdSyncClusterError, syncErr)
}
case "no", "false", "n", "0":
default:
return nil, fmt.Errorf("value of 'sync' could not be understood")
}

kAPI := client.NewKeysAPI(c)

// Setup the backend.
return &Etcd2Backend{
path: path,
kAPI: kAPI,
permitPool: NewPermitPool(DefaultParallelOperations),
logger: logger,
haEnabled: haEnabledBool,
}, nil
}

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 {
Expand All @@ -86,12 +131,6 @@ func newEtcd2Backend(conf map[string]string, logger log.Logger) (Backend, error)
}
}

haEnabled := os.Getenv("ETCD_HA_ENABLED")
if haEnabled == "" {
haEnabled = conf["ha_enabled"]
}
haEnabledBool, _ := strconv.ParseBool(haEnabled)

// Create a new client from the supplied address and attempt to sync with the
// cluster.
var cTransport client.CancelableTransport
Expand Down Expand Up @@ -135,42 +174,7 @@ func newEtcd2Backend(conf map[string]string, logger log.Logger) (Backend, error)
cfg.Password = password
}

c, err := client.New(cfg)
if err != nil {
return nil, err
}

// Should we sync the cluster state? There are three available options
// for our client library: don't sync (required for some proxies), sync
// once, or sync periodically with AutoSync. We currently support the
// first two.
sync, ok := conf["sync"]
if !ok {
sync = "yes"
}
switch sync {
case "yes", "true", "y", "1":
ctx, cancel := context.WithTimeout(context.Background(), client.DefaultRequestTimeout)
syncErr := c.Sync(ctx)
cancel()
if syncErr != nil {
return nil, fmt.Errorf("%s: %s", EtcdSyncClusterError, syncErr)
}
case "no", "false", "n", "0":
default:
return nil, fmt.Errorf("value of 'sync' could not be understood")
}

kAPI := client.NewKeysAPI(c)

// Setup the backend.
return &Etcd2Backend{
path: path,
kAPI: kAPI,
permitPool: NewPermitPool(DefaultParallelOperations),
logger: logger,
haEnabled: haEnabledBool,
}, nil
return client.New(cfg)
}

// Put is used to insert or update an entry.
Expand Down
33 changes: 33 additions & 0 deletions vendor/github.com/coreos/etcd/client/client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

56 changes: 56 additions & 0 deletions vendor/github.com/coreos/etcd/version/version.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading