diff --git a/api/client/network.go b/api/client/network.go index 8ebd4b05d6..aaa4b5c25a 100644 --- a/api/client/network.go +++ b/api/client/network.go @@ -137,12 +137,13 @@ func (cli *DockerCli) CmdNetworkConnect(args ...string) error { // Usage: docker network disconnect func (cli *DockerCli) CmdNetworkDisconnect(args ...string) error { 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) if err := cmd.ParseFlags(args, true); err != nil { 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 diff --git a/api/server/router/network/backend.go b/api/server/router/network/backend.go index 0826e79576..c6ea0adcf8 100644 --- a/api/server/router/network/backend.go +++ b/api/server/router/network/backend.go @@ -16,7 +16,7 @@ type Backend interface { options map[string]string, internal bool) (libnetwork.Network, error) ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error DisconnectContainerFromNetwork(containerName string, - network libnetwork.Network) error + network libnetwork.Network, force bool) error NetworkControllerEnabled() bool DeleteNetwork(name string) error } diff --git a/api/server/router/network/network_routes.go b/api/server/router/network/network_routes.go index 864057bb81..ab7427b6e3 100644 --- a/api/server/router/network/network_routes.go +++ b/api/server/router/network/network_routes.go @@ -144,7 +144,7 @@ func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.Respon 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 { diff --git a/daemon/container_operations_unix.go b/daemon/container_operations_unix.go index 870adfe7e8..2ea5a4c648 100644 --- a/daemon/container_operations_unix.go +++ b/daemon/container_operations_unix.go @@ -833,8 +833,17 @@ func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName 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. -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() { 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()) } } else { - if err := disconnectFromNetwork(container, n); err != nil { + if err := disconnectFromNetwork(container, n, false); err != nil { return err } } @@ -864,7 +873,7 @@ func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n li return nil } -func disconnectFromNetwork(container *container.Container, n libnetwork.Network) error { +func disconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error { var ( ep libnetwork.Endpoint sbox libnetwork.Sandbox @@ -886,6 +895,15 @@ func disconnectFromNetwork(container *container.Container, n libnetwork.Network) } 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 { return fmt.Errorf("container %s is not connected to the network", container.ID) } diff --git a/daemon/container_operations_windows.go b/daemon/container_operations_windows.go index d713541b19..8c3ae27e60 100644 --- a/daemon/container_operations_windows.go +++ b/daemon/container_operations_windows.go @@ -32,8 +32,13 @@ func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName 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. -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 } diff --git a/daemon/network.go b/daemon/network.go index 450a99e572..be8bc33d76 100644 --- a/daemon/network.go +++ b/daemon/network.go @@ -163,12 +163,15 @@ func (daemon *Daemon) ConnectContainerToNetwork(containerName, networkName strin // DisconnectContainerFromNetwork disconnects the given container from // 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) if err != nil { + if force { + return daemon.ForceEndpointDelete(containerName, network) + } return err } - return daemon.DisconnectFromNetwork(container, network) + return daemon.DisconnectFromNetwork(container, network, force) } // GetNetworkDriverList returns the list of plugins drivers diff --git a/docs/reference/api/docker_remote_api.md b/docs/reference/api/docker_remote_api.md index f61347e420..705f3330ab 100644 --- a/docs/reference/api/docker_remote_api.md +++ b/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. * `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/(id)/disconnect` now includes a `Force` option to forcefully disconnect a container from network ### v1.21 API changes diff --git a/docs/reference/api/docker_remote_api_v1.22.md b/docs/reference/api/docker_remote_api_v1.22.md index 1ac810e77a..9263f86be2 100644 --- a/docs/reference/api/docker_remote_api_v1.22.md +++ b/docs/reference/api/docker_remote_api_v1.22.md @@ -3073,7 +3073,8 @@ POST /networks/22be93d5babb089c5aab8dbc369042fad48ff791584ca2da2100db837a1c7c30/ Content-Type: application/json { - "Container":"3613f73ba0e4" + "Container":"3613f73ba0e4", + "Force":false } ``` @@ -3090,6 +3091,7 @@ Status Codes: JSON Parameters: - **Container** - container-id/name to be disconnected from a network +- **Force** - Force the container to disconnect from a network ### Remove a network diff --git a/docs/reference/commandline/network_disconnect.md b/docs/reference/commandline/network_disconnect.md index 7fb7a7c42e..10c4f16ea2 100644 --- a/docs/reference/commandline/network_disconnect.md +++ b/docs/reference/commandline/network_disconnect.md @@ -12,8 +12,10 @@ parent = "smn_cli" Usage: docker network disconnect [OPTIONS] NETWORK CONTAINER + Disconnects a container from a network + -f, --force Force the container to disconnect from a network --help Print usage Disconnects a container from a network. The container must be running to disconnect it from the network. diff --git a/integration-cli/docker_cli_network_unix_test.go b/integration-cli/docker_cli_network_unix_test.go index 1732216d28..90a9946f15 100644 --- a/integration-cli/docker_cli_network_unix_test.go +++ b/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(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") assertNwNotAvailable(c, "test") } diff --git a/man/docker-network-disconnect.1.md b/man/docker-network-disconnect.1.md index bfe85ad23a..09bcac51b0 100644 --- a/man/docker-network-disconnect.1.md +++ b/man/docker-network-disconnect.1.md @@ -7,6 +7,7 @@ docker-network-disconnect - disconnect a container from a network # SYNOPSIS **docker network disconnect** [**--help**] +[**--force**] NETWORK CONTAINER # DESCRIPTION @@ -25,6 +26,9 @@ Disconnects a container from a network. **CONTAINER** Specify container name +**--force** + Force the container to disconnect from a network + **--help** Print usage statement