Repository: moby/moby (language: go)

Issue:
runconfig/errors: split `ErrConflictHostNetwork`
### Description

## Description

`ErrConflictHostNetwork` was added in https://github.com/moby/moby/pull/17476.

https://github.com/moby/moby/blob/c90cbc89c098f4a41ba7cbe294df08e82597865d/runconfig/errors.go#L9

Confusingly, the same error message is used for two different errors.

1. When attempting to change the network mode of a running container from a different mode to `host`.
   https://github.com/moby/moby/blob/c90cbc89c098f4a41ba7cbe294df08e82597865d/daemon/container_operations.go#L175-L177
2. When the network mode of a running container is already `host` and attempting to disconnect from `host`.
   https://github.com/moby/moby/blob/c90cbc89c098f4a41ba7cbe294df08e82597865d/daemon/container_operations.go#L1055-L1057

Using the same error message for these two errors makes troubleshooting difficult.

## Suggestions

Split the `ErrConflictHostNetwork` error into two distinct errors:

1. `ErrConflictConnectToHostNetwork` when attempting to change the network mode of a running container from a different mode to `host`
2. `ErrConflictDisconnectFromHostNetwork` when the network mode of a running container is `host` and attempting to disconnect from `host`

## Related

- https://github.com/moby/moby/pull/17476
- [`daemon/container_operations.go`](https://github.com/moby/moby/blob/c90cbc89c098f4a41ba7cbe294df08e82597865d/daemon/container_operations.go)
- [`runconfig/errors.go`](https://github.com/moby/moby/blob/c90cbc89c098f4a41ba7cbe294df08e82597865d/runconfig/errors.go)



Discussion / hints:

Fix patch:
diff --git a/daemon/container_operations.go b/daemon/container_operations.go
index d07fe8dc45d26..b8435ee88d9f9 100644
--- a/daemon/container_operations.go
+++ b/daemon/container_operations.go
@@ -173,7 +173,7 @@ func (daemon *Daemon) updateNetworkSettings(ctr *container.Container, n *libnetw
 	}
 
 	if !ctr.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() {
-		return runconfig.ErrConflictHostNetwork
+		return runconfig.ErrConflictConnectToHostNetwork
 	}
 
 	for s, v := range ctr.NetworkSettings.Networks {
@@ -1053,7 +1053,7 @@ func (daemon *Daemon) DisconnectFromNetwork(ctx context.Context, ctr *container.
 		delete(ctr.NetworkSettings.Networks, networkName)
 	} else if err == nil {
 		if ctr.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() {
-			return runconfig.ErrConflictHostNetwork
+			return runconfig.ErrConflictDisconnectFromHostNetwork
 		}
 
 		if err := daemon.disconnectFromNetwork(ctx, ctr, n, false); err != nil {
diff --git a/runconfig/errors.go b/runconfig/errors.go
index a0ca32a7b9185..b1c2e55c01f56 100644
--- a/runconfig/errors.go
+++ b/runconfig/errors.go
@@ -5,8 +5,10 @@ const (
 	ErrConflictContainerNetworkAndLinks validationError = "conflicting options: container type network can't be used with links. This would result in undefined behavior"
 	// ErrConflictSharedNetwork conflict between private and other networks
 	ErrConflictSharedNetwork validationError = "container sharing network namespace with another container or host cannot be connected to any other network"
-	// ErrConflictHostNetwork conflict from being disconnected from host network or connected to host network.
-	ErrConflictHostNetwork validationError = "container cannot be disconnected from host network or connected to host network"
+	// ErrConflictConnectToHostNetwork error when attempting to connect a container to host network when not in host network mode
+	ErrConflictConnectToHostNetwork validationError = "cannot connect container to host network - container must be created in host network mode"
+	// ErrConflictDisconnectFromHostNetwork error when attempting to disconnect a container from host network when in host network mode
+	ErrConflictDisconnectFromHostNetwork validationError = "cannot disconnect container from host network - container was created in host network mode"
 	// ErrConflictNoNetwork conflict between private and other networks
 	ErrConflictNoNetwork validationError = "container cannot be connected to multiple networks with one of the networks in private (none) mode"
 	// ErrConflictNetworkAndDNS conflict between --dns and the network mode


Test patch:
diff --git a/integration-cli/docker_cli_network_unix_test.go b/integration-cli/docker_cli_network_unix_test.go
index a12fa0338f356..c62577e24fee7 100644
--- a/integration-cli/docker_cli_network_unix_test.go
+++ b/integration-cli/docker_cli_network_unix_test.go
@@ -1155,7 +1155,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkConnectToHostFromOtherNetwork(c *t
 	cli.DockerCmd(c, "network", "disconnect", "bridge", "container1")
 	out, _, err := dockerCmdWithError("network", "connect", "host", "container1")
 	assert.ErrorContains(c, err, "", out)
-	assert.Assert(c, is.Contains(out, runconfig.ErrConflictHostNetwork.Error()))
+	assert.Assert(c, is.Contains(out, runconfig.ErrConflictConnectToHostNetwork.Error()))
 }
 
 func (s *DockerNetworkSuite) TestDockerNetworkDisconnectFromHost(c *testing.T) {
@@ -1163,7 +1163,7 @@ func (s *DockerNetworkSuite) TestDockerNetworkDisconnectFromHost(c *testing.T) {
 	cli.WaitRun(c, "container1")
 	out, _, err := dockerCmdWithError("network", "disconnect", "host", "container1")
 	assert.Assert(c, err != nil, "Should err out disconnect from host")
-	assert.Assert(c, is.Contains(out, runconfig.ErrConflictHostNetwork.Error()))
+	assert.Assert(c, is.Contains(out, runconfig.ErrConflictDisconnectFromHostNetwork.Error()))
 }
 
 func (s *DockerNetworkSuite) TestDockerNetworkConnectWithPortMapping(c *testing.T) {