Parcourir la source

daemon: fix under what conditions container's mac-address is applied

The daemon would pass an EndpointCreateOption to set the interface MAC
address if the network name and the provided network mode were matching.
Obviously, if the network mode is a network ID, it won't work. To make
things worse, the network mode is never normalized if it's a partial ID.

To fix that: 1. the condition under what the container's mac-address is
applied is updated to also match the full ID; 2. the network mode is
normalized to a full ID when it's only a partial one.

Signed-off-by: Albin Kerouanton <albinker@gmail.com>
Albin Kerouanton il y a 1 an
Parent
commit
6cc6682f5f

+ 25 - 0
daemon/container_operations.go

@@ -691,6 +691,12 @@ func (daemon *Daemon) connectToNetwork(cfg *config.Config, container *container.
 	}
 	}
 	nwName := n.Name()
 	nwName := n.Name()
 
 
+	if idOrName != container.HostConfig.NetworkMode.NetworkName() {
+		if err := daemon.normalizeNetMode(container); err != nil {
+			return err
+		}
+	}
+
 	var operIPAM bool
 	var operIPAM bool
 	if nwCfg != nil {
 	if nwCfg != nil {
 		if epConfig, ok := nwCfg.EndpointsConfig[nwName]; ok {
 		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 {
 func (daemon *Daemon) initializeNetworking(cfg *config.Config, container *container.Container) error {
 	if container.HostConfig.NetworkMode.IsContainer() {
 	if container.HostConfig.NetworkMode.IsContainer() {
 		// we need to get the hosts files from the container to join
 		// we need to get the hosts files from the container to join

+ 2 - 1
daemon/network.go

@@ -870,7 +870,8 @@ func buildCreateEndpointOptions(c *container.Container, n *libnetwork.Network, e
 	// to which container was connected to on docker run.
 	// to which container was connected to on docker run.
 	// Ideally all these network-specific endpoint configurations must be moved under
 	// Ideally all these network-specific endpoint configurations must be moved under
 	// container.NetworkSettings.Networks[n.Name()]
 	// 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 != "" {
 		if c.Config.MacAddress != "" {
 			mac, err := net.ParseMAC(c.Config.MacAddress)
 			mac, err := net.ParseMAC(c.Config.MacAddress)
 			if err != nil {
 			if err != nil {

+ 26 - 0
integration/container/run_linux_test.go

@@ -286,3 +286,29 @@ func TestRunWithAlternativeContainerdShim(t *testing.T) {
 
 
 	assert.Equal(t, strings.TrimSpace(b.String()), "Hello, world!")
 	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")
+}

+ 16 - 0
integration/internal/container/container.go

@@ -154,3 +154,19 @@ func demultiplexStreams(ctx context.Context, resp types.HijackedResponse) (strea
 	wg.Wait()
 	wg.Wait()
 	return s, err
 	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
+}

+ 12 - 0
integration/internal/container/ops.go

@@ -280,3 +280,15 @@ func WithPIDMode(mode container.PidMode) func(c *TestContainerConfig) {
 		c.HostConfig.PidMode = mode
 		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
+	}
+}