소스 검색

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 <aboch@docker.com>
Alessandro Boch 8 년 전
부모
커밋
3cedca5d53
5개의 변경된 파일75개의 추가작업 그리고 5개의 파일을 삭제
  1. 2 2
      daemon/cluster/cluster.go
  2. 2 1
      daemon/cluster/executor/backend.go
  3. 16 2
      daemon/daemon.go
  4. 28 0
      daemon/network.go
  5. 27 0
      integration-cli/docker_cli_swarm_test.go

+ 2 - 2
daemon/cluster/cluster.go

@@ -244,7 +244,7 @@ func (c *Cluster) newNodeRunner(conf nodeStartConfig) (*nodeRunner, error) {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	c.config.Backend.SetClusterProvider(c)
+	c.config.Backend.DaemonJoinsCluster(c)
 
 
 	return nr, nil
 	return nr, nil
 }
 }
@@ -562,7 +562,7 @@ func (c *Cluster) Leave(force bool) error {
 	if err := clearPersistentState(c.root); err != nil {
 	if err := clearPersistentState(c.root); err != nil {
 		return err
 		return err
 	}
 	}
-	c.config.Backend.SetClusterProvider(nil)
+	c.config.Backend.DaemonLeavesCluster()
 	return nil
 	return nil
 }
 }
 
 

+ 2 - 1
daemon/cluster/executor/backend.go

@@ -47,7 +47,8 @@ type Backend interface {
 	VolumeCreate(name, driverName string, opts, labels map[string]string) (*types.Volume, error)
 	VolumeCreate(name, driverName string, opts, labels map[string]string) (*types.Volume, error)
 	Containers(config *types.ContainerListOptions) ([]*types.Container, error)
 	Containers(config *types.ContainerListOptions) ([]*types.Container, error)
 	SetNetworkBootstrapKeys([]*networktypes.EncryptionKey) error
 	SetNetworkBootstrapKeys([]*networktypes.EncryptionKey) error
-	SetClusterProvider(provider cluster.Provider)
+	DaemonJoinsCluster(provider cluster.Provider)
+	DaemonLeavesCluster()
 	IsSwarmCompatible() error
 	IsSwarmCompatible() error
 	SubscribeToEvents(since, until time.Time, filter filters.Args) ([]events.Message, chan interface{})
 	SubscribeToEvents(since, until time.Time, filter filters.Args) ([]events.Message, chan interface{})
 	UnsubscribeFromEvents(listener chan interface{})
 	UnsubscribeFromEvents(listener chan interface{})

+ 16 - 2
daemon/daemon.go

@@ -433,8 +433,22 @@ func (daemon *Daemon) registerLink(parent, child *container.Container, alias str
 	return nil
 	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.clusterProvider = clusterProvider
 	daemon.netController.SetClusterProvider(clusterProvider)
 	daemon.netController.SetClusterProvider(clusterProvider)
 }
 }

+ 28 - 0
daemon/network.go

@@ -468,3 +468,31 @@ func (daemon *Daemon) deleteNetwork(networkID string, dynamic bool) error {
 func (daemon *Daemon) GetNetworks() []libnetwork.Network {
 func (daemon *Daemon) GetNetworks() []libnetwork.Network {
 	return daemon.getAllNetworks()
 	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)
+		}
+	}
+}

+ 27 - 0
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")
 	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, "<no value>")
+
+	// 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) {
 func (s *DockerSwarmSuite) TestSwarmRemoveInternalNetwork(c *check.C) {
 	d := s.AddDaemon(c, true, true)
 	d := s.AddDaemon(c, true, true)