- When the node leaves the cluster, if any user run
container(s) is connected to the swarm network,
then daemon needs to detach the container(s) and
remove the network.
Signed-off-by: Alessandro Boch <aboch@docker.com>
(cherry picked from commit 3cedca5d532958ffc007d9b62cc871d3d113f054)
Signed-off-by: Victor Vieux <vieux@docker.com>
| ... | ... |
@@ -351,7 +351,7 @@ func (c *Cluster) startNewNode(conf nodeStartConfig) (*node, error) {
|
| 351 | 351 |
c.actualLocalAddr = actualLocalAddr // not saved |
| 352 | 352 |
c.saveState(conf) |
| 353 | 353 |
|
| 354 |
- c.config.Backend.SetClusterProvider(c) |
|
| 354 |
+ c.config.Backend.DaemonJoinsCluster(c) |
|
| 355 | 355 |
go func() {
|
| 356 | 356 |
err := detectLockedError(n.Err(ctx)) |
| 357 | 357 |
if err != nil {
|
| ... | ... |
@@ -724,6 +724,7 @@ func (c *Cluster) Leave(force bool) error {
|
| 724 | 724 |
if err := c.clearState(); err != nil {
|
| 725 | 725 |
return err |
| 726 | 726 |
} |
| 727 |
+ |
|
| 727 | 728 |
return nil |
| 728 | 729 |
} |
| 729 | 730 |
|
| ... | ... |
@@ -751,7 +752,7 @@ func (c *Cluster) clearState() error {
|
| 751 | 751 |
if err := os.MkdirAll(c.root, 0700); err != nil {
|
| 752 | 752 |
return err |
| 753 | 753 |
} |
| 754 |
- c.config.Backend.SetClusterProvider(nil) |
|
| 754 |
+ c.config.Backend.DaemonLeavesCluster() |
|
| 755 | 755 |
return nil |
| 756 | 756 |
} |
| 757 | 757 |
|
| ... | ... |
@@ -47,7 +47,8 @@ type Backend interface {
|
| 47 | 47 |
VolumeCreate(name, driverName string, opts, labels map[string]string) (*types.Volume, error) |
| 48 | 48 |
Containers(config *types.ContainerListOptions) ([]*types.Container, error) |
| 49 | 49 |
SetNetworkBootstrapKeys([]*networktypes.EncryptionKey) error |
| 50 |
- SetClusterProvider(provider cluster.Provider) |
|
| 50 |
+ DaemonJoinsCluster(provider cluster.Provider) |
|
| 51 |
+ DaemonLeavesCluster() |
|
| 51 | 52 |
IsSwarmCompatible() error |
| 52 | 53 |
SubscribeToEvents(since, until time.Time, filter filters.Args) ([]events.Message, chan interface{})
|
| 53 | 54 |
UnsubscribeFromEvents(listener chan interface{})
|
| ... | ... |
@@ -446,8 +446,22 @@ func (daemon *Daemon) registerLink(parent, child *container.Container, alias str |
| 446 | 446 |
return nil |
| 447 | 447 |
} |
| 448 | 448 |
|
| 449 |
-// SetClusterProvider sets a component for querying the current cluster state. |
|
| 450 |
-func (daemon *Daemon) SetClusterProvider(clusterProvider cluster.Provider) {
|
|
| 449 |
+// DaemonJoinsCluster informs the daemon has joined the cluster and provides |
|
| 450 |
+// the handler to query the cluster component |
|
| 451 |
+func (daemon *Daemon) DaemonJoinsCluster(clusterProvider cluster.Provider) {
|
|
| 452 |
+ daemon.setClusterProvider(clusterProvider) |
|
| 453 |
+} |
|
| 454 |
+ |
|
| 455 |
+// DaemonLeavesCluster informs the daemon has left the cluster |
|
| 456 |
+func (daemon *Daemon) DaemonLeavesCluster() {
|
|
| 457 |
+ // Daemon is in charge of removing the attachable networks with |
|
| 458 |
+ // connected containers when the node leaves the swarm |
|
| 459 |
+ daemon.clearAttachableNetworks() |
|
| 460 |
+ daemon.setClusterProvider(nil) |
|
| 461 |
+} |
|
| 462 |
+ |
|
| 463 |
+// setClusterProvider sets a component for querying the current cluster state. |
|
| 464 |
+func (daemon *Daemon) setClusterProvider(clusterProvider cluster.Provider) {
|
|
| 451 | 465 |
daemon.clusterProvider = clusterProvider |
| 452 | 466 |
daemon.netController.SetClusterProvider(clusterProvider) |
| 453 | 467 |
} |
| ... | ... |
@@ -468,3 +468,31 @@ func (daemon *Daemon) deleteNetwork(networkID string, dynamic bool) error {
|
| 468 | 468 |
func (daemon *Daemon) GetNetworks() []libnetwork.Network {
|
| 469 | 469 |
return daemon.getAllNetworks() |
| 470 | 470 |
} |
| 471 |
+ |
|
| 472 |
+// clearAttachableNetworks removes the attachable networks |
|
| 473 |
+// after disconnecting any connected container |
|
| 474 |
+func (daemon *Daemon) clearAttachableNetworks() {
|
|
| 475 |
+ for _, n := range daemon.GetNetworks() {
|
|
| 476 |
+ if !n.Info().Attachable() {
|
|
| 477 |
+ continue |
|
| 478 |
+ } |
|
| 479 |
+ for _, ep := range n.Endpoints() {
|
|
| 480 |
+ epInfo := ep.Info() |
|
| 481 |
+ if epInfo == nil {
|
|
| 482 |
+ continue |
|
| 483 |
+ } |
|
| 484 |
+ sb := epInfo.Sandbox() |
|
| 485 |
+ if sb == nil {
|
|
| 486 |
+ continue |
|
| 487 |
+ } |
|
| 488 |
+ containerID := sb.ContainerID() |
|
| 489 |
+ if err := daemon.DisconnectContainerFromNetwork(containerID, n.ID(), true); err != nil {
|
|
| 490 |
+ logrus.Warnf("Failed to disconnect container %s from swarm network %s on cluster leave: %v",
|
|
| 491 |
+ containerID, n.Name(), err) |
|
| 492 |
+ } |
|
| 493 |
+ } |
|
| 494 |
+ if err := daemon.DeleteManagedNetwork(n.ID()); err != nil {
|
|
| 495 |
+ logrus.Warnf("Failed to remove swarm network %s on cluster leave: %v", n.Name(), err)
|
|
| 496 |
+ } |
|
| 497 |
+ } |
|
| 498 |
+} |
| ... | ... |
@@ -393,6 +393,33 @@ func (s *DockerSwarmSuite) TestOverlayAttachable(c *check.C) {
|
| 393 | 393 |
c.Assert(strings.TrimSpace(out), checker.Equals, "true") |
| 394 | 394 |
} |
| 395 | 395 |
|
| 396 |
+func (s *DockerSwarmSuite) TestOverlayAttachableOnSwarmLeave(c *check.C) {
|
|
| 397 |
+ d := s.AddDaemon(c, true, true) |
|
| 398 |
+ |
|
| 399 |
+ // Create an attachable swarm network |
|
| 400 |
+ nwName := "attovl" |
|
| 401 |
+ out, err := d.Cmd("network", "create", "-d", "overlay", "--attachable", nwName)
|
|
| 402 |
+ c.Assert(err, checker.IsNil, check.Commentf(out)) |
|
| 403 |
+ |
|
| 404 |
+ // Connect a container to the network |
|
| 405 |
+ out, err = d.Cmd("run", "-d", "--network", nwName, "--name", "c1", "busybox", "top")
|
|
| 406 |
+ c.Assert(err, checker.IsNil, check.Commentf(out)) |
|
| 407 |
+ |
|
| 408 |
+ // Leave the swarm |
|
| 409 |
+ err = d.Leave(true) |
|
| 410 |
+ c.Assert(err, checker.IsNil) |
|
| 411 |
+ |
|
| 412 |
+ // Check the container is disconnected |
|
| 413 |
+ out, err = d.Cmd("inspect", "c1", "--format", "{{.NetworkSettings.Networks."+nwName+"}}")
|
|
| 414 |
+ c.Assert(err, checker.IsNil) |
|
| 415 |
+ c.Assert(strings.TrimSpace(out), checker.Equals, "<no value>") |
|
| 416 |
+ |
|
| 417 |
+ // Check the network is gone |
|
| 418 |
+ out, err = d.Cmd("network", "ls", "--format", "{{.Name}}")
|
|
| 419 |
+ c.Assert(err, checker.IsNil) |
|
| 420 |
+ c.Assert(out, checker.Not(checker.Contains), nwName) |
|
| 421 |
+} |
|
| 422 |
+ |
|
| 396 | 423 |
func (s *DockerSwarmSuite) TestSwarmRemoveInternalNetwork(c *check.C) {
|
| 397 | 424 |
d := s.AddDaemon(c, true, true) |
| 398 | 425 |
|