diff --git a/cmd/kubeadm/app/phases/etcd/local.go b/cmd/kubeadm/app/phases/etcd/local.go index d2fd1adae70..1912966c547 100644 --- a/cmd/kubeadm/app/phases/etcd/local.go +++ b/cmd/kubeadm/app/phases/etcd/local.go @@ -103,6 +103,22 @@ func RemoveStackedEtcdMemberFromCluster(client clientset.Interface, cfg *kubeadm return err } + members, err := etcdClient.ListMembers() + if err != nil { + return err + } + // If this is the only remaining stacked etcd member in the cluster, calling RemoveMember() + // is not needed. + if len(members) == 1 { + etcdClientAddress := etcdutil.GetClientURL(&cfg.LocalAPIEndpoint) + for _, endpoint := range etcdClient.Endpoints { + if endpoint == etcdClientAddress { + klog.V(1).Info("[etcd] This is the only remaining etcd member in the etcd cluster, skip removing it") + return nil + } + } + } + // notifies the other members of the etcd cluster about the removing member etcdPeerAddress := etcdutil.GetPeerURL(&cfg.LocalAPIEndpoint) @@ -113,7 +129,7 @@ func RemoveStackedEtcdMemberFromCluster(client clientset.Interface, cfg *kubeadm } klog.V(1).Infof("[etcd] removing etcd member: %s, id: %d", etcdPeerAddress, id) - members, err := etcdClient.RemoveMember(id) + members, err = etcdClient.RemoveMember(id) if err != nil { return err } diff --git a/cmd/kubeadm/app/phases/upgrade/staticpods_test.go b/cmd/kubeadm/app/phases/upgrade/staticpods_test.go index 479ac129558..e97c80e9a83 100644 --- a/cmd/kubeadm/app/phases/upgrade/staticpods_test.go +++ b/cmd/kubeadm/app/phases/upgrade/staticpods_test.go @@ -246,6 +246,10 @@ func (c fakeTLSEtcdClient) CheckClusterHealth() error { func (c fakeTLSEtcdClient) Sync() error { return nil } +func (c fakeTLSEtcdClient) ListMembers() ([]etcdutil.Member, error) { + return []etcdutil.Member{}, nil +} + func (c fakeTLSEtcdClient) AddMember(name string, peerAddrs string) ([]etcdutil.Member, error) { return []etcdutil.Member{}, nil } @@ -277,6 +281,10 @@ func (c fakePodManifestEtcdClient) CheckClusterHealth() error { func (c fakePodManifestEtcdClient) Sync() error { return nil } +func (c fakePodManifestEtcdClient) ListMembers() ([]etcdutil.Member, error) { + return []etcdutil.Member{}, nil +} + func (c fakePodManifestEtcdClient) AddMember(name string, peerAddrs string) ([]etcdutil.Member, error) { return []etcdutil.Member{}, nil } diff --git a/cmd/kubeadm/app/util/etcd/etcd.go b/cmd/kubeadm/app/util/etcd/etcd.go index b7ad9e727fd..ec0b3e08c88 100644 --- a/cmd/kubeadm/app/util/etcd/etcd.go +++ b/cmd/kubeadm/app/util/etcd/etcd.go @@ -55,6 +55,7 @@ type ClusterInterrogator interface { CheckClusterHealth() error WaitForClusterAvailable(retries int, retryInterval time.Duration) (bool, error) Sync() error + ListMembers() ([]Member, error) AddMember(name string, peerAddrs string) ([]Member, error) GetMemberID(peerURL string) (uint64, error) RemoveMember(id uint64) ([]Member, error) @@ -258,8 +259,7 @@ type Member struct { PeerURL string } -// GetMemberID returns the member ID of the given peer URL -func (c *Client) GetMemberID(peerURL string) (uint64, error) { +func (c *Client) listMembers() (*clientv3.MemberListResponse, error) { cli, err := clientv3.New(clientv3.Config{ Endpoints: c.Endpoints, DialTimeout: dialTimeout, @@ -269,7 +269,7 @@ func (c *Client) GetMemberID(peerURL string) (uint64, error) { TLS: c.TLS, }) if err != nil { - return 0, err + return nil, err } defer cli.Close() @@ -288,7 +288,16 @@ func (c *Client) GetMemberID(peerURL string) (uint64, error) { return false, nil }) if err != nil { - return 0, lastError + return nil, lastError + } + return resp, nil +} + +// GetMemberID returns the member ID of the given peer URL +func (c *Client) GetMemberID(peerURL string) (uint64, error) { + resp, err := c.listMembers() + if err != nil { + return 0, err } for _, member := range resp.Members { @@ -299,6 +308,20 @@ func (c *Client) GetMemberID(peerURL string) (uint64, error) { return 0, nil } +// ListMembers returns the member list. +func (c *Client) ListMembers() ([]Member, error) { + resp, err := c.listMembers() + if err != nil { + return nil, err + } + + ret := make([]Member, 0, len(resp.Members)) + for _, m := range resp.Members { + ret = append(ret, Member{Name: m.Name, PeerURL: m.PeerURLs[0]}) + } + return ret, nil +} + // RemoveMember notifies an etcd cluster to remove an existing member func (c *Client) RemoveMember(id uint64) ([]Member, error) { cli, err := clientv3.New(clientv3.Config{