diff --git a/etcdctl/command/util.go b/etcdctl/command/util.go index 9b3452338..a8e6fa0a4 100644 --- a/etcdctl/command/util.go +++ b/etcdctl/command/util.go @@ -208,8 +208,19 @@ func mustNewClient(c *cli.Context) client.Client { if err == client.ErrNoEndpoints { fmt.Fprintf(os.Stderr, "etcd cluster has no published client endpoints.\n") fmt.Fprintf(os.Stderr, "Try '--no-sync' if you want to access non-published client endpoints(%s).\n", strings.Join(hc.Endpoints(), ",")) + handleError(ExitServerError, err) + } + + // fail-back to try sync cluster with peer API. this is for making etcdctl work with etcd 0.4.x. + // TODO: remove this when we deprecate the support for etcd 0.4. + eps, serr := syncWithPeerAPI(c, ctx, hc.Endpoints()) + if serr != nil { + handleError(ExitServerError, serr) + } + err = hc.SetEndpoints(eps) + if err != nil { + handleError(ExitServerError, err) } - handleError(ExitServerError, err) } if debug { fmt.Fprintf(os.Stderr, "got endpoints(%s) after sync\n", strings.Join(hc.Endpoints(), ",")) @@ -271,3 +282,44 @@ func newClient(c *cli.Context) (client.Client, error) { func contextWithTotalTimeout(c *cli.Context) (context.Context, context.CancelFunc) { return context.WithTimeout(context.Background(), c.GlobalDuration("total-timeout")) } + +// syncWithPeerAPI syncs cluster with peer API defined at +// https://github.com/coreos/etcd/blob/v0.4.9/server/server.go#L311. +// This exists for backward compatibility with etcd 0.4.x. +func syncWithPeerAPI(c *cli.Context, ctx context.Context, knownPeers []string) ([]string, error) { + tr, err := getTransport(c) + if err != nil { + return nil, err + } + + var ( + body []byte + resp *http.Response + ) + for _, p := range knownPeers { + var req *http.Request + req, err = http.NewRequest("GET", p+"/v2/peers", nil) + if err != nil { + continue + } + resp, err = tr.RoundTrip(req) + if err != nil { + continue + } + if resp.StatusCode != http.StatusOK { + resp.Body.Close() + continue + } + body, err = ioutil.ReadAll(resp.Body) + resp.Body.Close() + if err != nil { + continue + } + } + if err != nil { + return nil, err + } + + // Parse the peers API format: https://github.com/coreos/etcd/blob/v0.4.9/server/server.go#L311 + return strings.Split(string(body), ", "), nil +}