From 541f2e5200bd8c3c15c512edbb147866f8f0ba1d Mon Sep 17 00:00:00 2001 From: Xiang Li Date: Thu, 17 Dec 2015 18:56:30 -0800 Subject: [PATCH] etcdctl: support basic operations with etcd 0.4. For CoreOS users, they will get a updated version of etcdctl without updating the etcd server version. And the users cannot really control this behavior. We do not want to suddenly break them without enough communication. So we still want the most basic opeartions like get, set, watch of etcdctl2 work with etcd 0.4. This patches solve the incompability issue. --- etcdctl/command/util.go | 54 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) 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 +}