diff --git a/daemon/container_operations.go b/daemon/container_operations.go index 5bb2ba5e1b..a87cccb355 100644 --- a/daemon/container_operations.go +++ b/daemon/container_operations.go @@ -691,6 +691,12 @@ func (daemon *Daemon) connectToNetwork(cfg *config.Config, container *container. } nwName := n.Name() + if idOrName != container.HostConfig.NetworkMode.NetworkName() { + if err := daemon.normalizeNetMode(container); err != nil { + return err + } + } + var operIPAM bool if nwCfg != nil { if epConfig, ok := nwCfg.EndpointsConfig[nwName]; ok { @@ -886,6 +892,25 @@ func (daemon *Daemon) tryDetachContainerFromClusterNetwork(network *libnetwork.N }) } +// normalizeNetMode checks whether the network mode references a network by a partial ID. In that case, it replaces the +// partial ID with the full network ID. +// TODO(aker): transform ID into name when the referenced network is one of the predefined. +func (daemon *Daemon) normalizeNetMode(container *container.Container) error { + if container.HostConfig.NetworkMode.IsUserDefined() { + netMode := container.HostConfig.NetworkMode.NetworkName() + nw, err := daemon.FindNetwork(netMode) + if err != nil { + return fmt.Errorf("could not find a network matching network mode %s: %w", netMode, err) + } + + if netMode != nw.ID() && netMode != nw.Name() { + container.HostConfig.NetworkMode = containertypes.NetworkMode(nw.ID()) + } + } + + return nil +} + func (daemon *Daemon) initializeNetworking(cfg *config.Config, container *container.Container) error { if container.HostConfig.NetworkMode.IsContainer() { // we need to get the hosts files from the container to join diff --git a/daemon/network.go b/daemon/network.go index c5dae5c20c..2ba6c495bc 100644 --- a/daemon/network.go +++ b/daemon/network.go @@ -856,7 +856,8 @@ func buildCreateEndpointOptions(c *container.Container, n *libnetwork.Network, e // to which container was connected to on docker run. // Ideally all these network-specific endpoint configurations must be moved under // container.NetworkSettings.Networks[n.Name()] - if nwName == c.HostConfig.NetworkMode.NetworkName() || (nwName == defaultNetName && c.HostConfig.NetworkMode.IsDefault()) { + netMode := c.HostConfig.NetworkMode + if nwName == netMode.NetworkName() || n.ID() == netMode.NetworkName() || (nwName == defaultNetName && netMode.IsDefault()) { if c.Config.MacAddress != "" { mac, err := net.ParseMAC(c.Config.MacAddress) if err != nil { diff --git a/integration/container/run_linux_test.go b/integration/container/run_linux_test.go index f63824ba3b..89308d816a 100644 --- a/integration/container/run_linux_test.go +++ b/integration/container/run_linux_test.go @@ -276,3 +276,29 @@ func TestRunWithAlternativeContainerdShim(t *testing.T) { assert.Equal(t, strings.TrimSpace(b.String()), "Hello, world!") } + +func TestMacAddressIsAppliedToMainNetworkWithShortID(t *testing.T) { + skip.If(t, testEnv.IsRemoteDaemon) + skip.If(t, testEnv.DaemonInfo.OSType != "linux") + + ctx := testutil.StartSpan(baseContext, t) + + d := daemon.New(t) + d.StartWithBusybox(ctx, t) + defer d.Stop(t) + + apiClient := d.NewClientT(t) + + n := net.CreateNoError(ctx, t, apiClient, "testnet", net.WithIPAM("192.168.101.0/24", "192.168.101.1")) + + cid := container.Run(ctx, t, apiClient, + container.WithImage("busybox:latest"), + container.WithCmd("/bin/sleep", "infinity"), + container.WithStopSignal("SIGKILL"), + container.WithNetworkMode(n[:10]), + container.WithMacAddress("02:42:08:26:a9:55")) + defer container.Remove(ctx, t, apiClient, cid, types.ContainerRemoveOptions{Force: true}) + + c := container.Inspect(ctx, t, apiClient, cid) + assert.Equal(t, c.NetworkSettings.Networks["testnet"].MacAddress, "02:42:08:26:a9:55") +} diff --git a/integration/internal/container/container.go b/integration/internal/container/container.go index 50ed6a3c7a..2eb04ef0ae 100644 --- a/integration/internal/container/container.go +++ b/integration/internal/container/container.go @@ -154,3 +154,19 @@ func demultiplexStreams(ctx context.Context, resp types.HijackedResponse) (strea wg.Wait() return s, err } + +func Remove(ctx context.Context, t *testing.T, apiClient client.APIClient, container string, options types.ContainerRemoveOptions) { + t.Helper() + + err := apiClient.ContainerRemove(ctx, container, options) + assert.NilError(t, err) +} + +func Inspect(ctx context.Context, t *testing.T, apiClient client.APIClient, containerRef string) types.ContainerJSON { + t.Helper() + + c, err := apiClient.ContainerInspect(ctx, containerRef) + assert.NilError(t, err) + + return c +} diff --git a/integration/internal/container/ops.go b/integration/internal/container/ops.go index 72146d0a12..8b9ad9d22e 100644 --- a/integration/internal/container/ops.go +++ b/integration/internal/container/ops.go @@ -280,3 +280,15 @@ func WithPIDMode(mode container.PidMode) func(c *TestContainerConfig) { c.HostConfig.PidMode = mode } } + +func WithStopSignal(stopSignal string) func(c *TestContainerConfig) { + return func(c *TestContainerConfig) { + c.Config.StopSignal = stopSignal + } +} + +func WithMacAddress(address string) func(c *TestContainerConfig) { + return func(c *TestContainerConfig) { + c.Config.MacAddress = address + } +}