diff --git a/daemon/cluster/cluster.go b/daemon/cluster/cluster.go index 7a9cbace30..8c70526c5e 100644 --- a/daemon/cluster/cluster.go +++ b/daemon/cluster/cluster.go @@ -389,10 +389,11 @@ func (c *Cluster) Leave(force bool) error { if err := node.Stop(ctx); err != nil && !strings.Contains(err.Error(), "context canceled") { return err } - nodeID := node.NodeID() - for _, id := range c.config.Backend.ListContainersForNode(nodeID) { - if err := c.config.Backend.ContainerRm(id, &apitypes.ContainerRmConfig{ForceRemove: true}); err != nil { - logrus.Errorf("error removing %v: %v", id, err) + if nodeID := node.NodeID(); nodeID != "" { + for _, id := range c.config.Backend.ListContainersForNode(nodeID) { + if err := c.config.Backend.ContainerRm(id, &apitypes.ContainerRmConfig{ForceRemove: true}); err != nil { + logrus.Errorf("error removing %v: %v", id, err) + } } } c.Lock() diff --git a/integration-cli/docker_api_swarm_test.go b/integration-cli/docker_api_swarm_test.go index ca3aed235c..9f086bd930 100644 --- a/integration-cli/docker_api_swarm_test.go +++ b/integration-cli/docker_api_swarm_test.go @@ -552,6 +552,32 @@ func (s *DockerSwarmSuite) TestApiSwarmLeaveRemovesContainer(c *check.C) { c.Assert(id, checker.HasPrefix, strings.TrimSpace(id2)) } +// #23629 +func (s *DockerSwarmSuite) TestApiSwarmLeaveOnPendingJoin(c *check.C) { + s.AddDaemon(c, true, true) + d2 := s.AddDaemon(c, false, false) + + id, err := d2.Cmd("run", "-d", "busybox", "top") + c.Assert(err, checker.IsNil) + id = strings.TrimSpace(id) + + go d2.Join("nosuchhost:1234", "", "", false) // will block on pending state + + time.Sleep(1 * time.Second) + + info, err := d2.info() + c.Assert(err, checker.IsNil) + c.Assert(info.LocalNodeState, checker.Equals, swarm.LocalNodeStatePending) + + c.Assert(d2.Leave(true), checker.IsNil) + + waitAndAssert(c, defaultReconciliationTimeout, d2.checkActiveContainerCount, checker.Equals, 1) + + id2, err := d2.Cmd("ps", "-q") + c.Assert(err, checker.IsNil) + c.Assert(id, checker.HasPrefix, strings.TrimSpace(id2)) +} + func (s *DockerSwarmSuite) TestApiSwarmManagerRestore(c *check.C) { d1 := s.AddDaemon(c, true, true)