Browse code

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 authored on 2016/01/13 13:56:36
Showing 11 changed files
... ...
@@ -137,12 +137,13 @@ func (cli *DockerCli) CmdNetworkConnect(args ...string) error {
137 137
 // Usage: docker network disconnect <NETWORK> <CONTAINER>
138 138
 func (cli *DockerCli) CmdNetworkDisconnect(args ...string) error {
139 139
 	cmd := Cli.Subcmd("network disconnect", []string{"NETWORK CONTAINER"}, "Disconnects container from a network", false)
140
+	force := cmd.Bool([]string{"f", "-force"}, false, "Force the container to disconnect from a network")
140 141
 	cmd.Require(flag.Exact, 2)
141 142
 	if err := cmd.ParseFlags(args, true); err != nil {
142 143
 		return err
143 144
 	}
144 145
 
145
-	return cli.client.NetworkDisconnect(cmd.Arg(0), cmd.Arg(1), false)
146
+	return cli.client.NetworkDisconnect(cmd.Arg(0), cmd.Arg(1), *force)
146 147
 }
147 148
 
148 149
 // CmdNetworkLs lists all the networks managed by docker daemon
... ...
@@ -16,7 +16,7 @@ type Backend interface {
16 16
 		options map[string]string, internal bool) (libnetwork.Network, error)
17 17
 	ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error
18 18
 	DisconnectContainerFromNetwork(containerName string,
19
-		network libnetwork.Network) error
19
+		network libnetwork.Network, force bool) error
20 20
 	NetworkControllerEnabled() bool
21 21
 	DeleteNetwork(name string) error
22 22
 }
... ...
@@ -144,7 +144,7 @@ func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.Respon
144 144
 		return err
145 145
 	}
146 146
 
147
-	return n.backend.DisconnectContainerFromNetwork(disconnect.Container, nw)
147
+	return n.backend.DisconnectContainerFromNetwork(disconnect.Container, nw, disconnect.Force)
148 148
 }
149 149
 
150 150
 func (n *networkRouter) deleteNetwork(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
... ...
@@ -833,8 +833,17 @@ func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName
833 833
 	return nil
834 834
 }
835 835
 
836
+// ForceEndpointDelete deletes an endpoing from a network forcefully
837
+func (daemon *Daemon) ForceEndpointDelete(name string, n libnetwork.Network) error {
838
+	ep, err := n.EndpointByName(name)
839
+	if err != nil {
840
+		return err
841
+	}
842
+	return ep.Delete(true)
843
+}
844
+
836 845
 // DisconnectFromNetwork disconnects container from network n.
837
-func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n libnetwork.Network) error {
846
+func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error {
838 847
 	if container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() {
839 848
 		return runconfig.ErrConflictHostNetwork
840 849
 	}
... ...
@@ -848,7 +857,7 @@ func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n li
848 848
 			return fmt.Errorf("container %s is not connected to the network %s", container.ID, n.Name())
849 849
 		}
850 850
 	} else {
851
-		if err := disconnectFromNetwork(container, n); err != nil {
851
+		if err := disconnectFromNetwork(container, n, false); err != nil {
852 852
 			return err
853 853
 		}
854 854
 	}
... ...
@@ -864,7 +873,7 @@ func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n li
864 864
 	return nil
865 865
 }
866 866
 
867
-func disconnectFromNetwork(container *container.Container, n libnetwork.Network) error {
867
+func disconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error {
868 868
 	var (
869 869
 		ep   libnetwork.Endpoint
870 870
 		sbox libnetwork.Sandbox
... ...
@@ -886,6 +895,15 @@ func disconnectFromNetwork(container *container.Container, n libnetwork.Network)
886 886
 	}
887 887
 	n.WalkEndpoints(s)
888 888
 
889
+	if ep == nil && force {
890
+		epName := strings.TrimPrefix(container.Name, "/")
891
+		ep, err := n.EndpointByName(epName)
892
+		if err != nil {
893
+			return err
894
+		}
895
+		return ep.Delete(force)
896
+	}
897
+
889 898
 	if ep == nil {
890 899
 		return fmt.Errorf("container %s is not connected to the network", container.ID)
891 900
 	}
... ...
@@ -32,8 +32,13 @@ func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName
32 32
 	return nil
33 33
 }
34 34
 
35
+// ForceEndpointDelete deletes an endpoing from a network forcefully
36
+func (daemon *Daemon) ForceEndpointDelete(name string, n libnetwork.Network) error {
37
+	return nil
38
+}
39
+
35 40
 // DisconnectFromNetwork disconnects a container from the network.
36
-func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n libnetwork.Network) error {
41
+func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error {
37 42
 	return nil
38 43
 }
39 44
 
... ...
@@ -163,12 +163,15 @@ func (daemon *Daemon) ConnectContainerToNetwork(containerName, networkName strin
163 163
 
164 164
 // DisconnectContainerFromNetwork disconnects the given container from
165 165
 // the given network. If either cannot be found, an err is returned.
166
-func (daemon *Daemon) DisconnectContainerFromNetwork(containerName string, network libnetwork.Network) error {
166
+func (daemon *Daemon) DisconnectContainerFromNetwork(containerName string, network libnetwork.Network, force bool) error {
167 167
 	container, err := daemon.GetContainer(containerName)
168 168
 	if err != nil {
169
+		if force {
170
+			return daemon.ForceEndpointDelete(containerName, network)
171
+		}
169 172
 		return err
170 173
 	}
171
-	return daemon.DisconnectFromNetwork(container, network)
174
+	return daemon.DisconnectFromNetwork(container, network, force)
172 175
 }
173 176
 
174 177
 // GetNetworkDriverList returns the list of plugins drivers
... ...
@@ -115,6 +115,7 @@ This section lists each version from latest to oldest.  Each listing includes a
115 115
 * `POST /networks/(id)/connect` now allows you to set the static IPv4 and/or IPv6 address for the container.
116 116
 * `GET /info` now includes the number of containers running, stopped, and paused.
117 117
 * `POST /networks/create` now supports restricting external access to the network by setting the `internal` field.
118
+* `POST /networks/(id)/disconnect` now includes a `Force` option to forcefully disconnect a container from network
118 119
 
119 120
 ### v1.21 API changes
120 121
 
... ...
@@ -3073,7 +3073,8 @@ POST /networks/22be93d5babb089c5aab8dbc369042fad48ff791584ca2da2100db837a1c7c30/
3073 3073
 Content-Type: application/json
3074 3074
 
3075 3075
 {
3076
-  "Container":"3613f73ba0e4"
3076
+  "Container":"3613f73ba0e4",
3077
+  "Force":false
3077 3078
 }
3078 3079
 ```
3079 3080
 
... ...
@@ -3090,6 +3091,7 @@ Status Codes:
3090 3090
 JSON Parameters:
3091 3091
 
3092 3092
 - **Container** - container-id/name to be disconnected from a network
3093
+- **Force** - Force the container to disconnect from a network
3093 3094
 
3094 3095
 ### Remove a network
3095 3096
 
... ...
@@ -12,8 +12,10 @@ parent = "smn_cli"
12 12
 
13 13
     Usage:  docker network disconnect [OPTIONS] NETWORK CONTAINER
14 14
 
15
+
15 16
     Disconnects a container from a network
16 17
 
18
+      -f, --force        Force the container to disconnect from a network
17 19
       --help             Print usage
18 20
 
19 21
 Disconnects a container from a network. The container must be running to disconnect it from the network.
... ...
@@ -448,6 +448,22 @@ func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnect(c *check.C) {
448 448
 	c.Assert(nr.Name, checker.Equals, "test")
449 449
 	c.Assert(len(nr.Containers), checker.Equals, 0)
450 450
 
451
+	// run another container
452
+	out, _ = dockerCmd(c, "run", "-d", "--net", "test", "--name", "test2", "busybox", "top")
453
+	c.Assert(waitRun("test2"), check.IsNil)
454
+	containerID = strings.TrimSpace(out)
455
+
456
+	nr = getNwResource(c, "test")
457
+	c.Assert(nr.Name, checker.Equals, "test")
458
+	c.Assert(len(nr.Containers), checker.Equals, 1)
459
+
460
+	// force disconnect the container to the test network
461
+	dockerCmd(c, "network", "disconnect", "-f", "test", containerID)
462
+
463
+	nr = getNwResource(c, "test")
464
+	c.Assert(nr.Name, checker.Equals, "test")
465
+	c.Assert(len(nr.Containers), checker.Equals, 0)
466
+
451 467
 	dockerCmd(c, "network", "rm", "test")
452 468
 	assertNwNotAvailable(c, "test")
453 469
 }
... ...
@@ -7,6 +7,7 @@ docker-network-disconnect - disconnect a container from a network
7 7
 # SYNOPSIS
8 8
 **docker network disconnect**
9 9
 [**--help**]
10
+[**--force**]
10 11
 NETWORK CONTAINER
11 12
 
12 13
 # DESCRIPTION
... ...
@@ -25,6 +26,9 @@ Disconnects a container from a network.
25 25
 **CONTAINER**
26 26
     Specify container name
27 27
 
28
+**--force**
29
+  Force the container to disconnect from a network
30
+
28 31
 **--help**
29 32
   Print usage statement
30 33