From 3cedca5d532958ffc007d9b62cc871d3d113f054 Mon Sep 17 00:00:00 2001 From: Alessandro Boch Date: Fri, 13 Jan 2017 20:14:03 -0800 Subject: [PATCH] Remove attachable network on swarm leave - 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 --- daemon/cluster/cluster.go | 4 ++-- daemon/cluster/executor/backend.go | 3 ++- daemon/daemon.go | 18 +++++++++++++-- daemon/network.go | 28 ++++++++++++++++++++++++ integration-cli/docker_cli_swarm_test.go | 27 +++++++++++++++++++++++ 5 files changed, 75 insertions(+), 5 deletions(-) diff --git a/daemon/cluster/cluster.go b/daemon/cluster/cluster.go index afd5d05108..5f32ef85e2 100644 --- a/daemon/cluster/cluster.go +++ b/daemon/cluster/cluster.go @@ -244,7 +244,7 @@ func (c *Cluster) newNodeRunner(conf nodeStartConfig) (*nodeRunner, error) { return nil, err } - c.config.Backend.SetClusterProvider(c) + c.config.Backend.DaemonJoinsCluster(c) return nr, nil } @@ -562,7 +562,7 @@ func (c *Cluster) Leave(force bool) error { if err := clearPersistentState(c.root); err != nil { return err } - c.config.Backend.SetClusterProvider(nil) + c.config.Backend.DaemonLeavesCluster() return nil } diff --git a/daemon/cluster/executor/backend.go b/daemon/cluster/executor/backend.go index 7107dfed66..0f1da38558 100644 --- a/daemon/cluster/executor/backend.go +++ b/daemon/cluster/executor/backend.go @@ -47,7 +47,8 @@ type Backend interface { VolumeCreate(name, driverName string, opts, labels map[string]string) (*types.Volume, error) Containers(config *types.ContainerListOptions) ([]*types.Container, error) SetNetworkBootstrapKeys([]*networktypes.EncryptionKey) error - SetClusterProvider(provider cluster.Provider) + DaemonJoinsCluster(provider cluster.Provider) + DaemonLeavesCluster() IsSwarmCompatible() error SubscribeToEvents(since, until time.Time, filter filters.Args) ([]events.Message, chan interface{}) UnsubscribeFromEvents(listener chan interface{}) diff --git a/daemon/daemon.go b/daemon/daemon.go index 6c7b619a30..b49b3dab52 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -433,8 +433,22 @@ func (daemon *Daemon) registerLink(parent, child *container.Container, alias str return nil } -// SetClusterProvider sets a component for querying the current cluster state. -func (daemon *Daemon) SetClusterProvider(clusterProvider cluster.Provider) { +// DaemonJoinsCluster informs the daemon has joined the cluster and provides +// the handler to query the cluster component +func (daemon *Daemon) DaemonJoinsCluster(clusterProvider cluster.Provider) { + daemon.setClusterProvider(clusterProvider) +} + +// DaemonLeavesCluster informs the daemon has left the cluster +func (daemon *Daemon) DaemonLeavesCluster() { + // Daemon is in charge of removing the attachable networks with + // connected containers when the node leaves the swarm + daemon.clearAttachableNetworks() + daemon.setClusterProvider(nil) +} + +// setClusterProvider sets a component for querying the current cluster state. +func (daemon *Daemon) setClusterProvider(clusterProvider cluster.Provider) { daemon.clusterProvider = clusterProvider daemon.netController.SetClusterProvider(clusterProvider) } diff --git a/daemon/network.go b/daemon/network.go index ace8459898..d01e5e8719 100644 --- a/daemon/network.go +++ b/daemon/network.go @@ -468,3 +468,31 @@ func (daemon *Daemon) deleteNetwork(networkID string, dynamic bool) error { func (daemon *Daemon) GetNetworks() []libnetwork.Network { return daemon.getAllNetworks() } + +// clearAttachableNetworks removes the attachable networks +// after disconnecting any connected container +func (daemon *Daemon) clearAttachableNetworks() { + for _, n := range daemon.GetNetworks() { + if !n.Info().Attachable() { + continue + } + for _, ep := range n.Endpoints() { + epInfo := ep.Info() + if epInfo == nil { + continue + } + sb := epInfo.Sandbox() + if sb == nil { + continue + } + containerID := sb.ContainerID() + if err := daemon.DisconnectContainerFromNetwork(containerID, n.ID(), true); err != nil { + logrus.Warnf("Failed to disconnect container %s from swarm network %s on cluster leave: %v", + containerID, n.Name(), err) + } + } + if err := daemon.DeleteManagedNetwork(n.ID()); err != nil { + logrus.Warnf("Failed to remove swarm network %s on cluster leave: %v", n.Name(), err) + } + } +} diff --git a/integration-cli/docker_cli_swarm_test.go b/integration-cli/docker_cli_swarm_test.go index 613a2c65de..67a38c82c3 100644 --- a/integration-cli/docker_cli_swarm_test.go +++ b/integration-cli/docker_cli_swarm_test.go @@ -358,6 +358,33 @@ func (s *DockerSwarmSuite) TestOverlayAttachable(c *check.C) { c.Assert(strings.TrimSpace(out), checker.Equals, "true") } +func (s *DockerSwarmSuite) TestOverlayAttachableOnSwarmLeave(c *check.C) { + d := s.AddDaemon(c, true, true) + + // Create an attachable swarm network + nwName := "attovl" + out, err := d.Cmd("network", "create", "-d", "overlay", "--attachable", nwName) + c.Assert(err, checker.IsNil, check.Commentf(out)) + + // Connect a container to the network + out, err = d.Cmd("run", "-d", "--network", nwName, "--name", "c1", "busybox", "top") + c.Assert(err, checker.IsNil, check.Commentf(out)) + + // Leave the swarm + err = d.Leave(true) + c.Assert(err, checker.IsNil) + + // Check the container is disconnected + out, err = d.Cmd("inspect", "c1", "--format", "{{.NetworkSettings.Networks."+nwName+"}}") + c.Assert(err, checker.IsNil) + c.Assert(strings.TrimSpace(out), checker.Equals, "") + + // Check the network is gone + out, err = d.Cmd("network", "ls", "--format", "{{.Name}}") + c.Assert(err, checker.IsNil) + c.Assert(out, checker.Not(checker.Contains), nwName) +} + func (s *DockerSwarmSuite) TestSwarmRemoveInternalNetwork(c *check.C) { d := s.AddDaemon(c, true, true)