diff --git a/api/server/router/network/backend.go b/api/server/router/network/backend.go index 6e322fa378..067b033b8f 100644 --- a/api/server/router/network/backend.go +++ b/api/server/router/network/backend.go @@ -15,6 +15,6 @@ type Backend interface { GetNetworks() []libnetwork.Network CreateNetwork(nc types.NetworkCreateRequest) (*types.NetworkCreateResponse, error) ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error - DisconnectContainerFromNetwork(containerName string, network libnetwork.Network, force bool) error + DisconnectContainerFromNetwork(containerName string, networkName string, force bool) error DeleteNetwork(name string) error } diff --git a/api/server/router/network/network_routes.go b/api/server/router/network/network_routes.go index 6e491cd97e..8a42edfb6d 100644 --- a/api/server/router/network/network_routes.go +++ b/api/server/router/network/network_routes.go @@ -143,17 +143,14 @@ func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.Respon return err } - nw, err := n.backend.FindNetwork(vars["id"]) - if err != nil { - return err - } + nw, _ := n.backend.FindNetwork(vars["id"]) - if nw.Info().Dynamic() { + if nw != nil && nw.Info().Dynamic() { err := fmt.Errorf("operation not supported for swarm scoped networks") return errors.NewRequestForbiddenError(err) } - return n.backend.DisconnectContainerFromNetwork(disconnect.Container, nw, disconnect.Force) + return n.backend.DisconnectContainerFromNetwork(disconnect.Container, vars["id"], 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.go b/daemon/container_operations.go index a845e19317..83a6001cf2 100644 --- a/daemon/container_operations.go +++ b/daemon/container_operations.go @@ -618,8 +618,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 { +// ForceEndpointDelete deletes an endpoint from a network forcefully +func (daemon *Daemon) ForceEndpointDelete(name string, networkName string) error { + n, err := daemon.FindNetwork(networkName) + if err != nil { + return err + } + ep, err := n.EndpointByName(name) if err != nil { return err diff --git a/daemon/container_operations_solaris.go b/daemon/container_operations_solaris.go index b98faaae16..511fc3a39e 100644 --- a/daemon/container_operations_solaris.go +++ b/daemon/container_operations_solaris.go @@ -7,7 +7,6 @@ import ( "github.com/docker/docker/container" networktypes "github.com/docker/engine-api/types/network" - "github.com/docker/libnetwork" ) func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]string, error) { @@ -25,7 +24,7 @@ func (daemon *Daemon) getSize(container *container.Container) (int64, int64) { } // DisconnectFromNetwork disconnects a container from the network -func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error { +func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, networkName string, force bool) error { return fmt.Errorf("Solaris does not support disconnecting a running container from a network") } diff --git a/daemon/container_operations_unix.go b/daemon/container_operations_unix.go index 02497fa2a4..f4f8907c8e 100644 --- a/daemon/container_operations_unix.go +++ b/daemon/container_operations_unix.go @@ -21,7 +21,6 @@ import ( "github.com/docker/docker/runconfig" containertypes "github.com/docker/engine-api/types/container" networktypes "github.com/docker/engine-api/types/network" - "github.com/docker/libnetwork" "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/devices" "github.com/opencontainers/runc/libcontainer/label" @@ -124,33 +123,38 @@ func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName } // DisconnectFromNetwork disconnects container from network n. -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 - } - if !container.Running { +func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, networkName string, force bool) error { + n, err := daemon.FindNetwork(networkName) + if !container.Running || (err != nil && force) { if container.RemovalInProgress || container.Dead { return errRemovalContainer(container.ID) } - if _, ok := container.NetworkSettings.Networks[n.Name()]; ok { - delete(container.NetworkSettings.Networks, n.Name()) - } else { - return fmt.Errorf("container %s is not connected to the network %s", container.ID, n.Name()) + if _, ok := container.NetworkSettings.Networks[networkName]; !ok { + return fmt.Errorf("container %s is not connected to the network %s", container.ID, networkName) } - } else { + delete(container.NetworkSettings.Networks, networkName) + } else if err == nil { + if container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() { + return runconfig.ErrConflictHostNetwork + } + if err := disconnectFromNetwork(container, n, false); err != nil { return err } + } else { + return err } if err := container.ToDiskLocking(); err != nil { return fmt.Errorf("Error saving container to disk: %v", err) } - attributes := map[string]string{ - "container": container.ID, + if n != nil { + attributes := map[string]string{ + "container": container.ID, + } + daemon.LogNetworkEventWithAttributes(n, "disconnect", attributes) } - daemon.LogNetworkEventWithAttributes(n, "disconnect", attributes) return nil } diff --git a/daemon/container_operations_windows.go b/daemon/container_operations_windows.go index 16f0c81509..f85caa8d2c 100644 --- a/daemon/container_operations_windows.go +++ b/daemon/container_operations_windows.go @@ -7,7 +7,6 @@ import ( "github.com/docker/docker/container" networktypes "github.com/docker/engine-api/types/network" - "github.com/docker/libnetwork" ) func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]string, error) { @@ -20,7 +19,7 @@ func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName } // DisconnectFromNetwork disconnects container from a network. -func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error { +func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, networkName string, force bool) error { return fmt.Errorf("Windows does not support disconnecting a running container from a network") } diff --git a/daemon/network.go b/daemon/network.go index 65c27fd1e1..08372e9465 100644 --- a/daemon/network.go +++ b/daemon/network.go @@ -316,15 +316,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, force bool) error { +func (daemon *Daemon) DisconnectContainerFromNetwork(containerName string, networkName string, force bool) error { container, err := daemon.GetContainer(containerName) if err != nil { if force { - return daemon.ForceEndpointDelete(containerName, network) + return daemon.ForceEndpointDelete(containerName, networkName) } return err } - return daemon.DisconnectFromNetwork(container, network, force) + return daemon.DisconnectFromNetwork(container, networkName, force) } // GetNetworkDriverList returns the list of plugins drivers diff --git a/integration-cli/docker_cli_network_unix_test.go b/integration-cli/docker_cli_network_unix_test.go index eb75e998f3..f14a19cbc4 100644 --- a/integration-cli/docker_cli_network_unix_test.go +++ b/integration-cli/docker_cli_network_unix_test.go @@ -1274,6 +1274,22 @@ func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnectToStoppedContaine } +func (s *DockerNetworkSuite) TestDockerNetworkDisconnectContainerNonexistingNetwork(c *check.C) { + dockerCmd(c, "network", "create", "test") + dockerCmd(c, "run", "--net=test", "-d", "--name=foo", "busybox", "top") + networks := inspectField(c, "foo", "NetworkSettings.Networks") + c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network")) + + // Stop container and remove network + dockerCmd(c, "stop", "foo") + dockerCmd(c, "network", "rm", "test") + + // Test disconnecting stopped container from nonexisting network + dockerCmd(c, "network", "disconnect", "-f", "test", "foo") + networks = inspectField(c, "foo", "NetworkSettings.Networks") + c.Assert(networks, checker.Not(checker.Contains), "test", check.Commentf("Should not contain 'test' network")) +} + func (s *DockerNetworkSuite) TestDockerNetworkConnectPreferredIP(c *check.C) { // create two networks dockerCmd(c, "network", "create", "--ipv6", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "n0")