Merge pull request #18906 from coolljt0725/connect_to_created
Support network connect/disconnect to stopped container
This commit is contained in:
commit
301627c677
|
@ -696,13 +696,43 @@ func cleanOperationalData(es *networktypes.EndpointSettings) {
|
||||||
es.MacAddress = ""
|
es.MacAddress = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (daemon *Daemon) updateNetworkConfig(container *container.Container, idOrName string, updateSettings bool) (libnetwork.Network, error) {
|
||||||
|
if container.HostConfig.NetworkMode.IsContainer() {
|
||||||
|
return nil, runconfig.ErrConflictSharedNetwork
|
||||||
|
}
|
||||||
|
|
||||||
|
if containertypes.NetworkMode(idOrName).IsBridge() &&
|
||||||
|
daemon.configStore.DisableBridge {
|
||||||
|
container.Config.NetworkDisabled = true
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err := daemon.FindNetwork(idOrName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if updateSettings {
|
||||||
|
if err := daemon.updateNetworkSettings(container, n); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
// ConnectToNetwork connects a container to a network
|
// ConnectToNetwork connects a container to a network
|
||||||
func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings) error {
|
func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings) error {
|
||||||
if !container.Running {
|
if !container.Running {
|
||||||
return derr.ErrorCodeNotRunning.WithArgs(container.ID)
|
if container.RemovalInProgress || container.Dead {
|
||||||
}
|
return derr.ErrorCodeRemovalContainer.WithArgs(container.ID)
|
||||||
if err := daemon.connectToNetwork(container, idOrName, endpointConfig, true); err != nil {
|
}
|
||||||
return err
|
if _, err := daemon.updateNetworkConfig(container, idOrName, true); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := daemon.connectToNetwork(container, idOrName, endpointConfig, true); err != nil {
|
||||||
|
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)
|
||||||
|
@ -711,37 +741,24 @@ func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName
|
||||||
}
|
}
|
||||||
|
|
||||||
func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (err error) {
|
func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (err error) {
|
||||||
if container.HostConfig.NetworkMode.IsContainer() {
|
n, err := daemon.updateNetworkConfig(container, idOrName, updateSettings)
|
||||||
return runconfig.ErrConflictSharedNetwork
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if n == nil {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !containertypes.NetworkMode(idOrName).IsUserDefined() && hasUserDefinedIPAddress(endpointConfig) {
|
if !containertypes.NetworkMode(idOrName).IsUserDefined() && hasUserDefinedIPAddress(endpointConfig) {
|
||||||
return runconfig.ErrUnsupportedNetworkAndIP
|
return runconfig.ErrUnsupportedNetworkAndIP
|
||||||
}
|
}
|
||||||
|
|
||||||
if containertypes.NetworkMode(idOrName).IsBridge() &&
|
|
||||||
daemon.configStore.DisableBridge {
|
|
||||||
container.Config.NetworkDisabled = true
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
controller := daemon.netController
|
controller := daemon.netController
|
||||||
|
|
||||||
n, err := daemon.FindNetwork(idOrName)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := validateNetworkingConfig(n, endpointConfig); err != nil {
|
if err := validateNetworkingConfig(n, endpointConfig); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if updateSettings {
|
|
||||||
if err := daemon.updateNetworkSettings(container, n); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if endpointConfig != nil {
|
if endpointConfig != nil {
|
||||||
container.NetworkSettings.Networks[n.Name()] = endpointConfig
|
container.NetworkSettings.Networks[n.Name()] = endpointConfig
|
||||||
}
|
}
|
||||||
|
@ -805,16 +822,22 @@ 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) error {
|
func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n libnetwork.Network) error {
|
||||||
if !container.Running {
|
|
||||||
return derr.ErrorCodeNotRunning.WithArgs(container.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
if container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() {
|
if container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() {
|
||||||
return runconfig.ErrConflictHostNetwork
|
return runconfig.ErrConflictHostNetwork
|
||||||
}
|
}
|
||||||
|
if !container.Running {
|
||||||
if err := disconnectFromNetwork(container, n); err != nil {
|
if container.RemovalInProgress || container.Dead {
|
||||||
return err
|
return derr.ErrorCodeRemovalContainer.WithArgs(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())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if err := disconnectFromNetwork(container, n); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := container.ToDiskLocking(); err != nil {
|
if err := container.ToDiskLocking(); err != nil {
|
||||||
|
|
|
@ -16,7 +16,7 @@ parent = "smn_cli"
|
||||||
|
|
||||||
--help Print usage
|
--help Print usage
|
||||||
|
|
||||||
Connects a running container to a network. You can connect a container by name
|
Connects a container to a network. You can connect a container by name
|
||||||
or by ID. Once connected, the container can communicate with other containers in
|
or by ID. Once connected, the container can communicate with other containers in
|
||||||
the same network.
|
the same network.
|
||||||
|
|
||||||
|
|
|
@ -311,9 +311,8 @@ PING 172.17.0.2 (172.17.0.2): 56 data bytes
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
To connect a container to a network, the container must be running. If you stop
|
You can connect both running and non-running containers to a network. However,
|
||||||
a container and inspect a network it belongs to, you won't see that container.
|
`docker network inspect` only displays information on running containers.
|
||||||
The `docker network inspect` command only shows running containers.
|
|
||||||
|
|
||||||
## Disconnecting containers
|
## Disconnecting containers
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,15 @@ var (
|
||||||
HTTPStatusCode: http.StatusInternalServerError,
|
HTTPStatusCode: http.StatusInternalServerError,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// ErrorCodeRemovalContainer is generated when we attempt to connect or disconnect a
|
||||||
|
// container but it's marked for removal.
|
||||||
|
ErrorCodeRemovalContainer = errcode.Register(errGroup, errcode.ErrorDescriptor{
|
||||||
|
Value: "REMOVALCONTAINER",
|
||||||
|
Message: "Container %s is marked for removal and cannot be connected or disconnected to the network",
|
||||||
|
Description: "The specified container is marked for removal and cannot be connected or disconnected to the network",
|
||||||
|
HTTPStatusCode: http.StatusInternalServerError,
|
||||||
|
})
|
||||||
|
|
||||||
// ErrorCodePausedContainer is generated when we attempt to attach a
|
// ErrorCodePausedContainer is generated when we attempt to attach a
|
||||||
// container but its paused.
|
// container but its paused.
|
||||||
ErrorCodePausedContainer = errcode.Register(errGroup, errcode.ErrorDescriptor{
|
ErrorCodePausedContainer = errcode.Register(errGroup, errcode.ErrorDescriptor{
|
||||||
|
|
|
@ -448,11 +448,6 @@ func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnect(c *check.C) {
|
||||||
c.Assert(nr.Name, checker.Equals, "test")
|
c.Assert(nr.Name, checker.Equals, "test")
|
||||||
c.Assert(len(nr.Containers), checker.Equals, 0)
|
c.Assert(len(nr.Containers), checker.Equals, 0)
|
||||||
|
|
||||||
// check if network connect fails for inactive containers
|
|
||||||
dockerCmd(c, "stop", containerID)
|
|
||||||
_, _, err = dockerCmdWithError("network", "connect", "test", containerID)
|
|
||||||
c.Assert(err, check.NotNil)
|
|
||||||
|
|
||||||
dockerCmd(c, "network", "rm", "test")
|
dockerCmd(c, "network", "rm", "test")
|
||||||
assertNwNotAvailable(c, "test")
|
assertNwNotAvailable(c, "test")
|
||||||
}
|
}
|
||||||
|
@ -938,7 +933,44 @@ func (s *DockerNetworkSuite) TestDockerNetworkRestartWithMulipleNetworks(c *chec
|
||||||
networks, err := inspectField("foo", "NetworkSettings.Networks")
|
networks, err := inspectField("foo", "NetworkSettings.Networks")
|
||||||
c.Assert(err, checker.IsNil)
|
c.Assert(err, checker.IsNil)
|
||||||
c.Assert(networks, checker.Contains, "bridge", check.Commentf("Should contain 'bridge' network"))
|
c.Assert(networks, checker.Contains, "bridge", check.Commentf("Should contain 'bridge' network"))
|
||||||
c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' netwokr"))
|
c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *DockerNetworkSuite) TestDockerNetworkConnectDisconnectToStoppedContainer(c *check.C) {
|
||||||
|
dockerCmd(c, "network", "create", "test")
|
||||||
|
dockerCmd(c, "create", "--name=foo", "busybox", "top")
|
||||||
|
dockerCmd(c, "network", "connect", "test", "foo")
|
||||||
|
networks, err := inspectField("foo", "NetworkSettings.Networks")
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network"))
|
||||||
|
|
||||||
|
// Restart docker daemon to test the config has persisted to disk
|
||||||
|
s.d.Restart()
|
||||||
|
networks, err = inspectField("foo", "NetworkSettings.Networks")
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
c.Assert(networks, checker.Contains, "test", check.Commentf("Should contain 'test' network"))
|
||||||
|
|
||||||
|
// start the container and test if we can ping it from another container in the same network
|
||||||
|
dockerCmd(c, "start", "foo")
|
||||||
|
c.Assert(waitRun("foo"), checker.IsNil)
|
||||||
|
ip, err := inspectField("foo", "NetworkSettings.Networks.test.IPAddress")
|
||||||
|
ip = strings.TrimSpace(ip)
|
||||||
|
dockerCmd(c, "run", "--net=test", "busybox", "sh", "-c", fmt.Sprintf("ping -c 1 %s", ip))
|
||||||
|
|
||||||
|
dockerCmd(c, "stop", "foo")
|
||||||
|
|
||||||
|
// Test disconnect
|
||||||
|
dockerCmd(c, "network", "disconnect", "test", "foo")
|
||||||
|
networks, err = inspectField("foo", "NetworkSettings.Networks")
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
c.Assert(networks, checker.Not(checker.Contains), "test", check.Commentf("Should not contain 'test' network"))
|
||||||
|
|
||||||
|
// Restart docker daemon to test the config has persisted to disk
|
||||||
|
s.d.Restart()
|
||||||
|
networks, err = inspectField("foo", "NetworkSettings.Networks")
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
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) {
|
||||||
|
|
|
@ -11,7 +11,7 @@ NETWORK CONTAINER
|
||||||
|
|
||||||
# DESCRIPTION
|
# DESCRIPTION
|
||||||
|
|
||||||
Connects a running container to a network. You can connect a container by name
|
Connects a container to a network. You can connect a container by name
|
||||||
or by ID. Once connected, the container can communicate with other containers in
|
or by ID. Once connected, the container can communicate with other containers in
|
||||||
the same network.
|
the same network.
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ NETWORK CONTAINER
|
||||||
|
|
||||||
# DESCRIPTION
|
# DESCRIPTION
|
||||||
|
|
||||||
Disconnects a container from a network. The container must be running to disconnect it from the network.
|
Disconnects a container from a network.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ docker network disconnect multi-host-network container1
|
$ docker network disconnect multi-host-network container1
|
||||||
|
|
Loading…
Reference in New Issue