Parcourir la source

Forced endpoint cleanup

docker's network disconnect api now supports `Force` option which can be
used to force cleanup an endpoint from any host in the cluster.

Signed-off-by: Madhu Venugopal <madhu@docker.com>
Madhu Venugopal il y a 9 ans
Parent
commit
b464f1d78c

+ 2 - 1
api/client/network.go

@@ -137,12 +137,13 @@ func (cli *DockerCli) CmdNetworkConnect(args ...string) error {
 // Usage: docker network disconnect <NETWORK> <CONTAINER>
 // Usage: docker network disconnect <NETWORK> <CONTAINER>
 func (cli *DockerCli) CmdNetworkDisconnect(args ...string) error {
 func (cli *DockerCli) CmdNetworkDisconnect(args ...string) error {
 	cmd := Cli.Subcmd("network disconnect", []string{"NETWORK CONTAINER"}, "Disconnects container from a network", false)
 	cmd := Cli.Subcmd("network disconnect", []string{"NETWORK CONTAINER"}, "Disconnects container from a network", false)
+	force := cmd.Bool([]string{"f", "-force"}, false, "Force the container to disconnect from a network")
 	cmd.Require(flag.Exact, 2)
 	cmd.Require(flag.Exact, 2)
 	if err := cmd.ParseFlags(args, true); err != nil {
 	if err := cmd.ParseFlags(args, true); err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	return cli.client.NetworkDisconnect(cmd.Arg(0), cmd.Arg(1), false)
+	return cli.client.NetworkDisconnect(cmd.Arg(0), cmd.Arg(1), *force)
 }
 }
 
 
 // CmdNetworkLs lists all the networks managed by docker daemon
 // CmdNetworkLs lists all the networks managed by docker daemon

+ 1 - 1
api/server/router/network/backend.go

@@ -16,7 +16,7 @@ type Backend interface {
 		options map[string]string, internal bool) (libnetwork.Network, error)
 		options map[string]string, internal bool) (libnetwork.Network, error)
 	ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error
 	ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error
 	DisconnectContainerFromNetwork(containerName string,
 	DisconnectContainerFromNetwork(containerName string,
-		network libnetwork.Network) error
+		network libnetwork.Network, force bool) error
 	NetworkControllerEnabled() bool
 	NetworkControllerEnabled() bool
 	DeleteNetwork(name string) error
 	DeleteNetwork(name string) error
 }
 }

+ 1 - 1
api/server/router/network/network_routes.go

@@ -144,7 +144,7 @@ func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.Respon
 		return err
 		return err
 	}
 	}
 
 
-	return n.backend.DisconnectContainerFromNetwork(disconnect.Container, nw)
+	return n.backend.DisconnectContainerFromNetwork(disconnect.Container, nw, disconnect.Force)
 }
 }
 
 
 func (n *networkRouter) deleteNetwork(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 func (n *networkRouter) deleteNetwork(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {

+ 21 - 3
daemon/container_operations_unix.go

@@ -833,8 +833,17 @@ func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName
 	return nil
 	return nil
 }
 }
 
 
+// ForceEndpointDelete deletes an endpoing from a network forcefully
+func (daemon *Daemon) ForceEndpointDelete(name string, n libnetwork.Network) error {
+	ep, err := n.EndpointByName(name)
+	if err != nil {
+		return err
+	}
+	return ep.Delete(true)
+}
+
 // DisconnectFromNetwork disconnects container from network n.
 // DisconnectFromNetwork disconnects container from network n.
-func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n libnetwork.Network) error {
+func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error {
 	if container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() {
 	if container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() {
 		return runconfig.ErrConflictHostNetwork
 		return runconfig.ErrConflictHostNetwork
 	}
 	}
@@ -848,7 +857,7 @@ func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n li
 			return fmt.Errorf("container %s is not connected to the network %s", container.ID, n.Name())
 			return fmt.Errorf("container %s is not connected to the network %s", container.ID, n.Name())
 		}
 		}
 	} else {
 	} else {
-		if err := disconnectFromNetwork(container, n); err != nil {
+		if err := disconnectFromNetwork(container, n, false); err != nil {
 			return err
 			return err
 		}
 		}
 	}
 	}
@@ -864,7 +873,7 @@ func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n li
 	return nil
 	return nil
 }
 }
 
 
-func disconnectFromNetwork(container *container.Container, n libnetwork.Network) error {
+func disconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error {
 	var (
 	var (
 		ep   libnetwork.Endpoint
 		ep   libnetwork.Endpoint
 		sbox libnetwork.Sandbox
 		sbox libnetwork.Sandbox
@@ -886,6 +895,15 @@ func disconnectFromNetwork(container *container.Container, n libnetwork.Network)
 	}
 	}
 	n.WalkEndpoints(s)
 	n.WalkEndpoints(s)
 
 
+	if ep == nil && force {
+		epName := strings.TrimPrefix(container.Name, "/")
+		ep, err := n.EndpointByName(epName)
+		if err != nil {
+			return err
+		}
+		return ep.Delete(force)
+	}
+
 	if ep == nil {
 	if ep == nil {
 		return fmt.Errorf("container %s is not connected to the network", container.ID)
 		return fmt.Errorf("container %s is not connected to the network", container.ID)
 	}
 	}

+ 6 - 1
daemon/container_operations_windows.go

@@ -32,8 +32,13 @@ func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName
 	return nil
 	return nil
 }
 }
 
 
+// ForceEndpointDelete deletes an endpoing from a network forcefully
+func (daemon *Daemon) ForceEndpointDelete(name string, n libnetwork.Network) error {
+	return nil
+}
+
 // DisconnectFromNetwork disconnects a container from the network.
 // DisconnectFromNetwork disconnects a container from the network.
-func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n libnetwork.Network) error {
+func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error {
 	return nil
 	return nil
 }
 }
 
 

+ 5 - 2
daemon/network.go

@@ -163,12 +163,15 @@ func (daemon *Daemon) ConnectContainerToNetwork(containerName, networkName strin
 
 
 // DisconnectContainerFromNetwork disconnects the given container from
 // DisconnectContainerFromNetwork disconnects the given container from
 // the given network. If either cannot be found, an err is returned.
 // the given network. If either cannot be found, an err is returned.
-func (daemon *Daemon) DisconnectContainerFromNetwork(containerName string, network libnetwork.Network) error {
+func (daemon *Daemon) DisconnectContainerFromNetwork(containerName string, network libnetwork.Network, force bool) error {
 	container, err := daemon.GetContainer(containerName)
 	container, err := daemon.GetContainer(containerName)
 	if err != nil {
 	if err != nil {
+		if force {
+			return daemon.ForceEndpointDelete(containerName, network)
+		}
 		return err
 		return err
 	}
 	}
-	return daemon.DisconnectFromNetwork(container, network)
+	return daemon.DisconnectFromNetwork(container, network, force)
 }
 }
 
 
 // GetNetworkDriverList returns the list of plugins drivers
 // GetNetworkDriverList returns the list of plugins drivers

+ 1 - 0
docs/reference/api/docker_remote_api.md

@@ -115,6 +115,7 @@ This section lists each version from latest to oldest.  Each listing includes a
 * `POST /networks/(id)/connect` now allows you to set the static IPv4 and/or IPv6 address for the container.
 * `POST /networks/(id)/connect` now allows you to set the static IPv4 and/or IPv6 address for the container.
 * `GET /info` now includes the number of containers running, stopped, and paused.
 * `GET /info` now includes the number of containers running, stopped, and paused.
 * `POST /networks/create` now supports restricting external access to the network by setting the `internal` field.
 * `POST /networks/create` now supports restricting external access to the network by setting the `internal` field.
+* `POST /networks/(id)/disconnect` now includes a `Force` option to forcefully disconnect a container from network
 
 
 ### v1.21 API changes
 ### v1.21 API changes
 
 

+ 3 - 1
docs/reference/api/docker_remote_api_v1.22.md

@@ -3073,7 +3073,8 @@ POST /networks/22be93d5babb089c5aab8dbc369042fad48ff791584ca2da2100db837a1c7c30/
 Content-Type: application/json
 Content-Type: application/json
 
 
 {
 {
-  "Container":"3613f73ba0e4"
+  "Container":"3613f73ba0e4",
+  "Force":false
 }
 }
 ```
 ```
 
 
@@ -3090,6 +3091,7 @@ Status Codes:
 JSON Parameters:
 JSON Parameters:
 
 
 - **Container** - container-id/name to be disconnected from a network
 - **Container** - container-id/name to be disconnected from a network
+- **Force** - Force the container to disconnect from a network
 
 
 ### Remove a network
 ### Remove a network
 
 

+ 2 - 0
docs/reference/commandline/network_disconnect.md

@@ -12,8 +12,10 @@ parent = "smn_cli"
 
 
     Usage:  docker network disconnect [OPTIONS] NETWORK CONTAINER
     Usage:  docker network disconnect [OPTIONS] NETWORK CONTAINER
 
 
+
     Disconnects a container from a network
     Disconnects a container from a network
 
 
+      -f, --force        Force the container to disconnect from a network
       --help             Print usage
       --help             Print usage
 
 
 Disconnects a container from a network. The container must be running to disconnect it from the network.
 Disconnects a container from a network. The container must be running to disconnect it from the network.

+ 16 - 0
integration-cli/docker_cli_network_unix_test.go

@@ -448,6 +448,22 @@ func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnect(c *check.C) {
 	c.Assert(nr.Name, checker.Equals, "test")
 	c.Assert(nr.Name, checker.Equals, "test")
 	c.Assert(len(nr.Containers), checker.Equals, 0)
 	c.Assert(len(nr.Containers), checker.Equals, 0)
 
 
+	// run another container
+	out, _ = dockerCmd(c, "run", "-d", "--net", "test", "--name", "test2", "busybox", "top")
+	c.Assert(waitRun("test2"), check.IsNil)
+	containerID = strings.TrimSpace(out)
+
+	nr = getNwResource(c, "test")
+	c.Assert(nr.Name, checker.Equals, "test")
+	c.Assert(len(nr.Containers), checker.Equals, 1)
+
+	// force disconnect the container to the test network
+	dockerCmd(c, "network", "disconnect", "-f", "test", containerID)
+
+	nr = getNwResource(c, "test")
+	c.Assert(nr.Name, checker.Equals, "test")
+	c.Assert(len(nr.Containers), checker.Equals, 0)
+
 	dockerCmd(c, "network", "rm", "test")
 	dockerCmd(c, "network", "rm", "test")
 	assertNwNotAvailable(c, "test")
 	assertNwNotAvailable(c, "test")
 }
 }

+ 4 - 0
man/docker-network-disconnect.1.md

@@ -7,6 +7,7 @@ docker-network-disconnect - disconnect a container from a network
 # SYNOPSIS
 # SYNOPSIS
 **docker network disconnect**
 **docker network disconnect**
 [**--help**]
 [**--help**]
+[**--force**]
 NETWORK CONTAINER
 NETWORK CONTAINER
 
 
 # DESCRIPTION
 # DESCRIPTION
@@ -25,6 +26,9 @@ Disconnects a container from a network.
 **CONTAINER**
 **CONTAINER**
     Specify container name
     Specify container name
 
 
+**--force**
+  Force the container to disconnect from a network
+
 **--help**
 **--help**
   Print usage statement
   Print usage statement