Support container disconnect for non-existing network
There are cases such as migrating from classic overlay network to the swarm-mode networking (without kv-store), such a mechanism to allow disconnecting a container even when a network isnt available will be useful. Signed-off-by: Madhu Venugopal <madhu@docker.com>
This commit is contained in:
parent
91ec7fa811
commit
05a3f2666e
8 changed files with 50 additions and 30 deletions
|
@ -15,6 +15,6 @@ type Backend interface {
|
||||||
GetNetworks() []libnetwork.Network
|
GetNetworks() []libnetwork.Network
|
||||||
CreateNetwork(nc types.NetworkCreateRequest) (*types.NetworkCreateResponse, error)
|
CreateNetwork(nc types.NetworkCreateRequest) (*types.NetworkCreateResponse, error)
|
||||||
ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) 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
|
DeleteNetwork(name string) error
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,17 +143,14 @@ func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.Respon
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
nw, err := n.backend.FindNetwork(vars["id"])
|
nw, _ := n.backend.FindNetwork(vars["id"])
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if nw.Info().Dynamic() {
|
if nw != nil && nw.Info().Dynamic() {
|
||||||
err := fmt.Errorf("operation not supported for swarm scoped networks")
|
err := fmt.Errorf("operation not supported for swarm scoped networks")
|
||||||
return errors.NewRequestForbiddenError(err)
|
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 {
|
func (n *networkRouter) deleteNetwork(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
|
||||||
|
|
|
@ -618,8 +618,13 @@ func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForceEndpointDelete deletes an endpoing from a network forcefully
|
// ForceEndpointDelete deletes an endpoint from a network forcefully
|
||||||
func (daemon *Daemon) ForceEndpointDelete(name string, n libnetwork.Network) error {
|
func (daemon *Daemon) ForceEndpointDelete(name string, networkName string) error {
|
||||||
|
n, err := daemon.FindNetwork(networkName)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
ep, err := n.EndpointByName(name)
|
ep, err := n.EndpointByName(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
|
|
||||||
"github.com/docker/docker/container"
|
"github.com/docker/docker/container"
|
||||||
networktypes "github.com/docker/engine-api/types/network"
|
networktypes "github.com/docker/engine-api/types/network"
|
||||||
"github.com/docker/libnetwork"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]string, error) {
|
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
|
// 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")
|
return fmt.Errorf("Solaris does not support disconnecting a running container from a network")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,6 @@ import (
|
||||||
"github.com/docker/docker/runconfig"
|
"github.com/docker/docker/runconfig"
|
||||||
containertypes "github.com/docker/engine-api/types/container"
|
containertypes "github.com/docker/engine-api/types/container"
|
||||||
networktypes "github.com/docker/engine-api/types/network"
|
networktypes "github.com/docker/engine-api/types/network"
|
||||||
"github.com/docker/libnetwork"
|
|
||||||
"github.com/opencontainers/runc/libcontainer/configs"
|
"github.com/opencontainers/runc/libcontainer/configs"
|
||||||
"github.com/opencontainers/runc/libcontainer/devices"
|
"github.com/opencontainers/runc/libcontainer/devices"
|
||||||
"github.com/opencontainers/runc/libcontainer/label"
|
"github.com/opencontainers/runc/libcontainer/label"
|
||||||
|
@ -124,33 +123,38 @@ func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName
|
||||||
}
|
}
|
||||||
|
|
||||||
// DisconnectFromNetwork disconnects container from network n.
|
// DisconnectFromNetwork disconnects container from network n.
|
||||||
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 {
|
||||||
if container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() {
|
n, err := daemon.FindNetwork(networkName)
|
||||||
return runconfig.ErrConflictHostNetwork
|
if !container.Running || (err != nil && force) {
|
||||||
}
|
|
||||||
if !container.Running {
|
|
||||||
if container.RemovalInProgress || container.Dead {
|
if container.RemovalInProgress || container.Dead {
|
||||||
return errRemovalContainer(container.ID)
|
return errRemovalContainer(container.ID)
|
||||||
}
|
}
|
||||||
if _, ok := container.NetworkSettings.Networks[n.Name()]; ok {
|
if _, ok := container.NetworkSettings.Networks[networkName]; !ok {
|
||||||
delete(container.NetworkSettings.Networks, n.Name())
|
return fmt.Errorf("container %s is not connected to the network %s", container.ID, networkName)
|
||||||
} else {
|
|
||||||
return fmt.Errorf("container %s is not connected to the network %s", container.ID, n.Name())
|
|
||||||
}
|
}
|
||||||
} 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 {
|
if err := disconnectFromNetwork(container, n, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := container.ToDiskLocking(); err != nil {
|
if err := container.ToDiskLocking(); err != nil {
|
||||||
return fmt.Errorf("Error saving container to disk: %v", err)
|
return fmt.Errorf("Error saving container to disk: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes := map[string]string{
|
if n != nil {
|
||||||
"container": container.ID,
|
attributes := map[string]string{
|
||||||
|
"container": container.ID,
|
||||||
|
}
|
||||||
|
daemon.LogNetworkEventWithAttributes(n, "disconnect", attributes)
|
||||||
}
|
}
|
||||||
daemon.LogNetworkEventWithAttributes(n, "disconnect", attributes)
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ import (
|
||||||
|
|
||||||
"github.com/docker/docker/container"
|
"github.com/docker/docker/container"
|
||||||
networktypes "github.com/docker/engine-api/types/network"
|
networktypes "github.com/docker/engine-api/types/network"
|
||||||
"github.com/docker/libnetwork"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]string, error) {
|
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.
|
// 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")
|
return fmt.Errorf("Windows does not support disconnecting a running container from a network")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -316,15 +316,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, force bool) error {
|
func (daemon *Daemon) DisconnectContainerFromNetwork(containerName string, networkName string, force bool) error {
|
||||||
container, err := daemon.GetContainer(containerName)
|
container, err := daemon.GetContainer(containerName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if force {
|
if force {
|
||||||
return daemon.ForceEndpointDelete(containerName, network)
|
return daemon.ForceEndpointDelete(containerName, networkName)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return daemon.DisconnectFromNetwork(container, network, force)
|
return daemon.DisconnectFromNetwork(container, networkName, force)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNetworkDriverList returns the list of plugins drivers
|
// GetNetworkDriverList returns the list of plugins drivers
|
||||||
|
|
|
@ -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) {
|
func (s *DockerNetworkSuite) TestDockerNetworkConnectPreferredIP(c *check.C) {
|
||||||
// create two networks
|
// create two networks
|
||||||
dockerCmd(c, "network", "create", "--ipv6", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "n0")
|
dockerCmd(c, "network", "create", "--ipv6", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "n0")
|
||||||
|
|
Loading…
Reference in a new issue