Support container disconnect for non-existing network
| ... | ... |
@@ -15,6 +15,6 @@ type Backend interface {
|
| 15 | 15 |
GetNetworks() []libnetwork.Network |
| 16 | 16 |
CreateNetwork(nc types.NetworkCreateRequest) (*types.NetworkCreateResponse, error) |
| 17 | 17 |
ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error |
| 18 |
- DisconnectContainerFromNetwork(containerName string, network libnetwork.Network, force bool) error |
|
| 18 |
+ DisconnectContainerFromNetwork(containerName string, networkName string, force bool) error |
|
| 19 | 19 |
DeleteNetwork(name string) error |
| 20 | 20 |
} |
| ... | ... |
@@ -143,17 +143,14 @@ func (n *networkRouter) postNetworkDisconnect(ctx context.Context, w http.Respon |
| 143 | 143 |
return err |
| 144 | 144 |
} |
| 145 | 145 |
|
| 146 |
- nw, err := n.backend.FindNetwork(vars["id"]) |
|
| 147 |
- if err != nil {
|
|
| 148 |
- return err |
|
| 149 |
- } |
|
| 146 |
+ nw, _ := n.backend.FindNetwork(vars["id"]) |
|
| 150 | 147 |
|
| 151 |
- if nw.Info().Dynamic() {
|
|
| 148 |
+ if nw != nil && nw.Info().Dynamic() {
|
|
| 152 | 149 |
err := fmt.Errorf("operation not supported for swarm scoped networks")
|
| 153 | 150 |
return errors.NewRequestForbiddenError(err) |
| 154 | 151 |
} |
| 155 | 152 |
|
| 156 |
- return n.backend.DisconnectContainerFromNetwork(disconnect.Container, nw, disconnect.Force) |
|
| 153 |
+ return n.backend.DisconnectContainerFromNetwork(disconnect.Container, vars["id"], disconnect.Force) |
|
| 157 | 154 |
} |
| 158 | 155 |
|
| 159 | 156 |
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 |
| 618 | 618 |
return nil |
| 619 | 619 |
} |
| 620 | 620 |
|
| 621 |
-// ForceEndpointDelete deletes an endpoing from a network forcefully |
|
| 622 |
-func (daemon *Daemon) ForceEndpointDelete(name string, n libnetwork.Network) error {
|
|
| 621 |
+// ForceEndpointDelete deletes an endpoint from a network forcefully |
|
| 622 |
+func (daemon *Daemon) ForceEndpointDelete(name string, networkName string) error {
|
|
| 623 |
+ n, err := daemon.FindNetwork(networkName) |
|
| 624 |
+ if err != nil {
|
|
| 625 |
+ return err |
|
| 626 |
+ } |
|
| 627 |
+ |
|
| 623 | 628 |
ep, err := n.EndpointByName(name) |
| 624 | 629 |
if err != nil {
|
| 625 | 630 |
return err |
| ... | ... |
@@ -7,7 +7,6 @@ import ( |
| 7 | 7 |
|
| 8 | 8 |
"github.com/docker/docker/container" |
| 9 | 9 |
networktypes "github.com/docker/engine-api/types/network" |
| 10 |
- "github.com/docker/libnetwork" |
|
| 11 | 10 |
) |
| 12 | 11 |
|
| 13 | 12 |
func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]string, error) {
|
| ... | ... |
@@ -25,7 +24,7 @@ func (daemon *Daemon) getSize(container *container.Container) (int64, int64) {
|
| 25 | 25 |
} |
| 26 | 26 |
|
| 27 | 27 |
// DisconnectFromNetwork disconnects a container from the network |
| 28 |
-func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error {
|
|
| 28 |
+func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, networkName string, force bool) error {
|
|
| 29 | 29 |
return fmt.Errorf("Solaris does not support disconnecting a running container from a network")
|
| 30 | 30 |
} |
| 31 | 31 |
|
| ... | ... |
@@ -21,7 +21,6 @@ import ( |
| 21 | 21 |
"github.com/docker/docker/runconfig" |
| 22 | 22 |
containertypes "github.com/docker/engine-api/types/container" |
| 23 | 23 |
networktypes "github.com/docker/engine-api/types/network" |
| 24 |
- "github.com/docker/libnetwork" |
|
| 25 | 24 |
"github.com/opencontainers/runc/libcontainer/configs" |
| 26 | 25 |
"github.com/opencontainers/runc/libcontainer/devices" |
| 27 | 26 |
"github.com/opencontainers/runc/libcontainer/label" |
| ... | ... |
@@ -124,33 +123,38 @@ func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName |
| 124 | 124 |
} |
| 125 | 125 |
|
| 126 | 126 |
// DisconnectFromNetwork disconnects container from network n. |
| 127 |
-func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error {
|
|
| 128 |
- if container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() {
|
|
| 129 |
- return runconfig.ErrConflictHostNetwork |
|
| 130 |
- } |
|
| 131 |
- if !container.Running {
|
|
| 127 |
+func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, networkName string, force bool) error {
|
|
| 128 |
+ n, err := daemon.FindNetwork(networkName) |
|
| 129 |
+ if !container.Running || (err != nil && force) {
|
|
| 132 | 130 |
if container.RemovalInProgress || container.Dead {
|
| 133 | 131 |
return errRemovalContainer(container.ID) |
| 134 | 132 |
} |
| 135 |
- if _, ok := container.NetworkSettings.Networks[n.Name()]; ok {
|
|
| 136 |
- delete(container.NetworkSettings.Networks, n.Name()) |
|
| 137 |
- } else {
|
|
| 138 |
- return fmt.Errorf("container %s is not connected to the network %s", container.ID, n.Name())
|
|
| 133 |
+ if _, ok := container.NetworkSettings.Networks[networkName]; !ok {
|
|
| 134 |
+ return fmt.Errorf("container %s is not connected to the network %s", container.ID, networkName)
|
|
| 139 | 135 |
} |
| 140 |
- } else {
|
|
| 136 |
+ delete(container.NetworkSettings.Networks, networkName) |
|
| 137 |
+ } else if err == nil {
|
|
| 138 |
+ if container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() {
|
|
| 139 |
+ return runconfig.ErrConflictHostNetwork |
|
| 140 |
+ } |
|
| 141 |
+ |
|
| 141 | 142 |
if err := disconnectFromNetwork(container, n, false); err != nil {
|
| 142 | 143 |
return err |
| 143 | 144 |
} |
| 145 |
+ } else {
|
|
| 146 |
+ return err |
|
| 144 | 147 |
} |
| 145 | 148 |
|
| 146 | 149 |
if err := container.ToDiskLocking(); err != nil {
|
| 147 | 150 |
return fmt.Errorf("Error saving container to disk: %v", err)
|
| 148 | 151 |
} |
| 149 | 152 |
|
| 150 |
- attributes := map[string]string{
|
|
| 151 |
- "container": container.ID, |
|
| 153 |
+ if n != nil {
|
|
| 154 |
+ attributes := map[string]string{
|
|
| 155 |
+ "container": container.ID, |
|
| 156 |
+ } |
|
| 157 |
+ daemon.LogNetworkEventWithAttributes(n, "disconnect", attributes) |
|
| 152 | 158 |
} |
| 153 |
- daemon.LogNetworkEventWithAttributes(n, "disconnect", attributes) |
|
| 154 | 159 |
return nil |
| 155 | 160 |
} |
| 156 | 161 |
|
| ... | ... |
@@ -7,7 +7,6 @@ import ( |
| 7 | 7 |
|
| 8 | 8 |
"github.com/docker/docker/container" |
| 9 | 9 |
networktypes "github.com/docker/engine-api/types/network" |
| 10 |
- "github.com/docker/libnetwork" |
|
| 11 | 10 |
) |
| 12 | 11 |
|
| 13 | 12 |
func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]string, error) {
|
| ... | ... |
@@ -20,7 +19,7 @@ func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName |
| 20 | 20 |
} |
| 21 | 21 |
|
| 22 | 22 |
// DisconnectFromNetwork disconnects container from a network. |
| 23 |
-func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error {
|
|
| 23 |
+func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, networkName string, force bool) error {
|
|
| 24 | 24 |
return fmt.Errorf("Windows does not support disconnecting a running container from a network")
|
| 25 | 25 |
} |
| 26 | 26 |
|
| ... | ... |
@@ -316,15 +316,15 @@ func (daemon *Daemon) ConnectContainerToNetwork(containerName, networkName strin |
| 316 | 316 |
|
| 317 | 317 |
// DisconnectContainerFromNetwork disconnects the given container from |
| 318 | 318 |
// the given network. If either cannot be found, an err is returned. |
| 319 |
-func (daemon *Daemon) DisconnectContainerFromNetwork(containerName string, network libnetwork.Network, force bool) error {
|
|
| 319 |
+func (daemon *Daemon) DisconnectContainerFromNetwork(containerName string, networkName string, force bool) error {
|
|
| 320 | 320 |
container, err := daemon.GetContainer(containerName) |
| 321 | 321 |
if err != nil {
|
| 322 | 322 |
if force {
|
| 323 |
- return daemon.ForceEndpointDelete(containerName, network) |
|
| 323 |
+ return daemon.ForceEndpointDelete(containerName, networkName) |
|
| 324 | 324 |
} |
| 325 | 325 |
return err |
| 326 | 326 |
} |
| 327 |
- return daemon.DisconnectFromNetwork(container, network, force) |
|
| 327 |
+ return daemon.DisconnectFromNetwork(container, networkName, force) |
|
| 328 | 328 |
} |
| 329 | 329 |
|
| 330 | 330 |
// GetNetworkDriverList returns the list of plugins drivers |
| ... | ... |
@@ -1274,6 +1274,22 @@ func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnectToStoppedContaine |
| 1274 | 1274 |
|
| 1275 | 1275 |
} |
| 1276 | 1276 |
|
| 1277 |
+func (s *DockerNetworkSuite) TestDockerNetworkDisconnectContainerNonexistingNetwork(c *check.C) {
|
|
| 1278 |
+ dockerCmd(c, "network", "create", "test") |
|
| 1279 |
+ dockerCmd(c, "run", "--net=test", "-d", "--name=foo", "busybox", "top") |
|
| 1280 |
+ networks := inspectField(c, "foo", "NetworkSettings.Networks") |
|
| 1281 |
+ c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network"))
|
|
| 1282 |
+ |
|
| 1283 |
+ // Stop container and remove network |
|
| 1284 |
+ dockerCmd(c, "stop", "foo") |
|
| 1285 |
+ dockerCmd(c, "network", "rm", "test") |
|
| 1286 |
+ |
|
| 1287 |
+ // Test disconnecting stopped container from nonexisting network |
|
| 1288 |
+ dockerCmd(c, "network", "disconnect", "-f", "test", "foo") |
|
| 1289 |
+ networks = inspectField(c, "foo", "NetworkSettings.Networks") |
|
| 1290 |
+ c.Assert(networks, checker.Not(checker.Contains), "test", check.Commentf("Should not contain 'test' network"))
|
|
| 1291 |
+} |
|
| 1292 |
+ |
|
| 1277 | 1293 |
func (s *DockerNetworkSuite) TestDockerNetworkConnectPreferredIP(c *check.C) {
|
| 1278 | 1294 |
// create two networks |
| 1279 | 1295 |
dockerCmd(c, "network", "create", "--ipv6", "--subnet=172.28.0.0/16", "--subnet=2001:db8:1234::/64", "n0") |