From 4c25efc1f8e6b9d64bec94fe095a6f058112af2b Mon Sep 17 00:00:00 2001 From: Sahdev Zala Date: Mon, 10 Feb 2020 13:43:41 -0500 Subject: [PATCH] Discovery: do not allow passing negative cluster size (#11608) When an etcd instance attempts to perform service discovery, if a cluster size with negative value is provided, the etcd instance will panic without recovery because of --- etcdserver/api/v2discovery/discovery.go | 22 ++++++++++---------- etcdserver/api/v2discovery/discovery_test.go | 6 +++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/etcdserver/api/v2discovery/discovery.go b/etcdserver/api/v2discovery/discovery.go index cf770b378..16ccfde8e 100644 --- a/etcdserver/api/v2discovery/discovery.go +++ b/etcdserver/api/v2discovery/discovery.go @@ -218,7 +218,7 @@ func (d *discovery) createSelf(contents string) error { return err } -func (d *discovery) checkCluster() ([]*client.Node, int, uint64, error) { +func (d *discovery) checkCluster() ([]*client.Node, uint64, uint64, error) { configKey := path.Join("/", d.cluster, "_config") ctx, cancel := context.WithTimeout(context.Background(), client.DefaultRequestTimeout) // find cluster size @@ -247,7 +247,7 @@ func (d *discovery) checkCluster() ([]*client.Node, int, uint64, error) { } return nil, 0, 0, err } - size, err := strconv.Atoi(resp.Node.Value) + size, err := strconv.ParseUint(resp.Node.Value, 10, 0) if err != nil { return nil, 0, 0, ErrBadSizeKey } @@ -288,7 +288,7 @@ func (d *discovery) checkCluster() ([]*client.Node, int, uint64, error) { if path.Base(nodes[i].Key) == path.Base(d.selfKey()) { break } - if i >= size-1 { + if uint64(i) >= size-1 { return nodes[:size], size, resp.Index, ErrFullCluster } } @@ -316,7 +316,7 @@ func (d *discovery) logAndBackoffForRetry(step string) { d.clock.Sleep(retryTimeInSecond) } -func (d *discovery) checkClusterRetry() ([]*client.Node, int, uint64, error) { +func (d *discovery) checkClusterRetry() ([]*client.Node, uint64, uint64, error) { if d.retries < nRetries { d.logAndBackoffForRetry("cluster status check") return d.checkCluster() @@ -336,8 +336,8 @@ func (d *discovery) waitNodesRetry() ([]*client.Node, error) { return nil, ErrTooManyRetries } -func (d *discovery) waitNodes(nodes []*client.Node, size int, index uint64) ([]*client.Node, error) { - if len(nodes) > size { +func (d *discovery) waitNodes(nodes []*client.Node, size uint64, index uint64) ([]*client.Node, error) { + if uint64(len(nodes)) > size { nodes = nodes[:size] } // watch from the next index @@ -369,16 +369,16 @@ func (d *discovery) waitNodes(nodes []*client.Node, size int, index uint64) ([]* } // wait for others - for len(all) < size { + for uint64(len(all)) < size { if d.lg != nil { d.lg.Info( "found peers from discovery server; waiting for more", zap.String("discovery-url", d.url.String()), zap.Int("found-peers", len(all)), - zap.Int("needed-peers", size-len(all)), + zap.Int("needed-peers", int(size-uint64(len(all)))), ) } else { - plog.Noticef("found %d peer(s), waiting for %d more", len(all), size-len(all)) + plog.Noticef("found %d peer(s), waiting for %d more", len(all), size-uint64(len(all))) } resp, err := w.Next(context.Background()) if err != nil { @@ -415,7 +415,7 @@ func (d *discovery) selfKey() string { return path.Join("/", d.cluster, d.id.String()) } -func nodesToCluster(ns []*client.Node, size int) (string, error) { +func nodesToCluster(ns []*client.Node, size uint64) (string, error) { s := make([]string, len(ns)) for i, n := range ns { s[i] = n.Value @@ -425,7 +425,7 @@ func nodesToCluster(ns []*client.Node, size int) (string, error) { if err != nil { return us, ErrInvalidURL } - if m.Len() != size { + if uint64(m.Len()) != size { return us, ErrDuplicateName } return us, nil diff --git a/etcdserver/api/v2discovery/discovery_test.go b/etcdserver/api/v2discovery/discovery_test.go index c1eff8823..939a26c4b 100644 --- a/etcdserver/api/v2discovery/discovery_test.go +++ b/etcdserver/api/v2discovery/discovery_test.go @@ -217,7 +217,7 @@ func TestCheckCluster(t *testing.T) { if reflect.DeepEqual(ns, tt.nodes) { t.Errorf("#%d: nodes = %v, want %v", i, ns, tt.nodes) } - if size != tt.wsize { + if size != uint64(tt.wsize) { t.Errorf("#%d: size = %v, want %d", i, size, tt.wsize) } if index != tt.index { @@ -301,7 +301,7 @@ func TestWaitNodes(t *testing.T) { fc.Advance(time.Second * (0x1 << i)) } }() - g, err := d.waitNodes(tt.nodes, 3, 0) // we do not care about index in this test + g, err := d.waitNodes(tt.nodes, uint64(3), 0) // we do not care about index in this test if err != nil { t.Errorf("#%d: err = %v, want %v", i, err, nil) } @@ -348,7 +348,7 @@ func TestCreateSelf(t *testing.T) { func TestNodesToCluster(t *testing.T) { tests := []struct { nodes []*client.Node - size int + size uint64 wcluster string werr error }{