api: Add a field MacAddress to EndpointSettings
Prior to this commit, only container.Config had a MacAddress field and it's used only for the first network the container connects to. It's a relic of old times where custom networks were not supported. Signed-off-by: Albin Kerouanton <albinker@gmail.com>
This commit is contained in:
parent
98323ac114
commit
052562ffd5
8 changed files with 95 additions and 11 deletions
|
@ -1381,6 +1381,7 @@ definitions:
|
|||
LinkLocalIPs:
|
||||
- "169.254.34.68"
|
||||
- "fe80::3468"
|
||||
MacAddress: "02:42:ac:12:05:02"
|
||||
Links:
|
||||
- "container_1"
|
||||
- "container_2"
|
||||
|
@ -2455,6 +2456,11 @@ definitions:
|
|||
example:
|
||||
- "container_1"
|
||||
- "container_2"
|
||||
MacAddress:
|
||||
description: |
|
||||
MAC address for the endpoint on this network. The network driver might ignore this parameter.
|
||||
type: "string"
|
||||
example: "02:42:ac:11:00:04"
|
||||
Aliases:
|
||||
type: "array"
|
||||
items:
|
||||
|
@ -2505,11 +2511,6 @@ definitions:
|
|||
type: "integer"
|
||||
format: "int64"
|
||||
example: 64
|
||||
MacAddress:
|
||||
description: |
|
||||
MAC address for the endpoint on this network.
|
||||
type: "string"
|
||||
example: "02:42:ac:11:00:04"
|
||||
DriverOpts:
|
||||
description: |
|
||||
DriverOpts is a mapping of driver options and values. These options
|
||||
|
@ -10130,6 +10131,7 @@ paths:
|
|||
IPAMConfig:
|
||||
IPv4Address: "172.24.56.89"
|
||||
IPv6Address: "2001:db8::5689"
|
||||
MacAddress: "02:42:ac:12:05:02"
|
||||
tags: ["Network"]
|
||||
|
||||
/networks/{id}/disconnect:
|
||||
|
|
|
@ -14,6 +14,7 @@ type EndpointSettings struct {
|
|||
IPAMConfig *EndpointIPAMConfig
|
||||
Links []string
|
||||
Aliases []string
|
||||
MacAddress string
|
||||
// Operational data
|
||||
NetworkID string
|
||||
EndpointID string
|
||||
|
@ -23,7 +24,6 @@ type EndpointSettings struct {
|
|||
IPv6Gateway string
|
||||
GlobalIPv6Address string
|
||||
GlobalIPv6PrefixLen int
|
||||
MacAddress string
|
||||
DriverOpts map[string]string
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,9 @@ func (cli *Client) ContainerCreate(ctx context.Context, config *container.Config
|
|||
if err := cli.NewVersionError(ctx, "1.44", "specify health-check start interval"); config != nil && config.Healthcheck != nil && config.Healthcheck.StartInterval != 0 && err != nil {
|
||||
return response, err
|
||||
}
|
||||
if err := cli.NewVersionError("1.44", "specify mac-address per network"); hasEndpointSpecificMacAddress(networkingConfig) && err != nil {
|
||||
return response, err
|
||||
}
|
||||
|
||||
if hostConfig != nil {
|
||||
if versions.LessThan(cli.ClientVersion(), "1.25") {
|
||||
|
@ -91,3 +94,16 @@ func formatPlatform(platform *ocispec.Platform) string {
|
|||
}
|
||||
return path.Join(platform.OS, platform.Architecture, platform.Variant)
|
||||
}
|
||||
|
||||
// hasEndpointSpecificMacAddress checks whether one of the endpoint in networkingConfig has a MacAddress defined.
|
||||
func hasEndpointSpecificMacAddress(networkingConfig *network.NetworkingConfig) bool {
|
||||
if networkingConfig == nil {
|
||||
return false
|
||||
}
|
||||
for _, endpoint := range networkingConfig.EndpointsConfig {
|
||||
if endpoint.MacAddress != "" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
|
@ -628,7 +628,6 @@ func cleanOperationalData(es *network.EndpointSettings) {
|
|||
es.IPv6Gateway = ""
|
||||
es.GlobalIPv6Address = ""
|
||||
es.GlobalIPv6PrefixLen = 0
|
||||
es.MacAddress = ""
|
||||
if es.IPAMOperational {
|
||||
es.IPAMConfig = nil
|
||||
}
|
||||
|
|
|
@ -788,6 +788,7 @@ func (daemon *Daemon) clearAttachableNetworks() {
|
|||
// buildCreateEndpointOptions builds endpoint options from a given network.
|
||||
func buildCreateEndpointOptions(c *container.Container, n *libnetwork.Network, epConfig *network.EndpointSettings, sb *libnetwork.Sandbox, daemonDNS []string) ([]libnetwork.EndpointOption, error) {
|
||||
var createOptions []libnetwork.EndpointOption
|
||||
var genericOptions = make(options.Generic)
|
||||
|
||||
nwName := n.Name()
|
||||
defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
|
||||
|
@ -825,6 +826,14 @@ func buildCreateEndpointOptions(c *container.Container, n *libnetwork.Network, e
|
|||
for k, v := range epConfig.DriverOpts {
|
||||
createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(options.Generic{k: v}))
|
||||
}
|
||||
|
||||
if epConfig.MacAddress != "" {
|
||||
mac, err := net.ParseMAC(epConfig.MacAddress)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
genericOptions[netlabel.MacAddress] = mac
|
||||
}
|
||||
}
|
||||
|
||||
if svcCfg := c.NetworkSettings.Service; svcCfg != nil {
|
||||
|
@ -863,9 +872,8 @@ func buildCreateEndpointOptions(c *container.Container, n *libnetwork.Network, e
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(options.Generic{
|
||||
netlabel.MacAddress: mac,
|
||||
}))
|
||||
|
||||
genericOptions[netlabel.MacAddress] = mac
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -940,7 +948,10 @@ func buildCreateEndpointOptions(c *container.Container, n *libnetwork.Network, e
|
|||
createOptions = append(createOptions, libnetwork.CreateOptionDNS(daemonDNS))
|
||||
}
|
||||
|
||||
createOptions = append(createOptions, libnetwork.CreateOptionPortMapping(publishedPorts), libnetwork.CreateOptionExposedPorts(exposedPorts))
|
||||
createOptions = append(createOptions,
|
||||
libnetwork.CreateOptionPortMapping(publishedPorts),
|
||||
libnetwork.CreateOptionExposedPorts(exposedPorts),
|
||||
libnetwork.EndpointOptionGeneric(genericOptions))
|
||||
|
||||
return createOptions, nil
|
||||
}
|
||||
|
|
|
@ -55,6 +55,8 @@ keywords: "API, Docker, rcli, REST, documentation"
|
|||
* `POST /services/create` and `POST /services/{id}/update` now accept `Seccomp`
|
||||
and `AppArmor` fields in the `ContainerSpec.Privileges` object. This allows
|
||||
some configuration of Seccomp and AppArmor in Swarm services.
|
||||
* A new endpoint-specific `MacAddress` field has been added to `NetworkSettings.EndpointSettings`
|
||||
on `POST /containers/create`, and to `EndpointConfig` on `POST /networks/{id}/connect`.
|
||||
|
||||
## v1.43 API changes
|
||||
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
package container // import "github.com/docker/docker/integration/container"
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -14,6 +16,7 @@ import (
|
|||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/errdefs"
|
||||
ctr "github.com/docker/docker/integration/internal/container"
|
||||
net "github.com/docker/docker/integration/internal/network"
|
||||
"github.com/docker/docker/oci"
|
||||
"github.com/docker/docker/testutil"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
|
@ -631,3 +634,42 @@ func TestCreateWithMultipleEndpointSettings(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateWithCustomMACs(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType == "windows")
|
||||
skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.44"), "requires API v1.44")
|
||||
|
||||
ctx := setupTest(t)
|
||||
apiClient := testEnv.APIClient()
|
||||
|
||||
net.CreateNoError(ctx, t, apiClient, "testnet")
|
||||
|
||||
attachCtx, cancel := context.WithTimeout(ctx, 1*time.Second)
|
||||
defer cancel()
|
||||
res := ctr.RunAttach(attachCtx, t, apiClient,
|
||||
ctr.WithCmd("ip", "-o", "link", "show"),
|
||||
ctr.WithNetworkMode("bridge"),
|
||||
ctr.WithMacAddress("bridge", "02:32:1c:23:00:04"))
|
||||
|
||||
assert.Equal(t, res.ExitCode, 0)
|
||||
assert.Equal(t, res.Stderr.String(), "")
|
||||
|
||||
scanner := bufio.NewScanner(res.Stdout)
|
||||
for scanner.Scan() {
|
||||
fields := strings.Fields(scanner.Text())
|
||||
// The expected output is:
|
||||
// 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000\ link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
|
||||
// 134: eth0@if135: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1400 qdisc noqueue \ link/ether 02:42:ac:11:00:04 brd ff:ff:ff:ff:ff:ff
|
||||
if len(fields) < 11 {
|
||||
continue
|
||||
}
|
||||
|
||||
ifaceName := fields[1]
|
||||
if ifaceName[:3] != "eth" {
|
||||
continue
|
||||
}
|
||||
|
||||
mac := fields[len(fields)-3]
|
||||
assert.Equal(t, mac, "02:32:1c:23:00:04")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -114,6 +114,18 @@ func WithTmpfs(targetAndOpts string) func(config *TestContainerConfig) {
|
|||
}
|
||||
}
|
||||
|
||||
func WithMacAddress(networkName, mac string) func(config *TestContainerConfig) {
|
||||
return func(c *TestContainerConfig) {
|
||||
if c.NetworkingConfig.EndpointsConfig == nil {
|
||||
c.NetworkingConfig.EndpointsConfig = map[string]*network.EndpointSettings{}
|
||||
}
|
||||
if v, ok := c.NetworkingConfig.EndpointsConfig[networkName]; !ok || v == nil {
|
||||
c.NetworkingConfig.EndpointsConfig[networkName] = &network.EndpointSettings{}
|
||||
}
|
||||
c.NetworkingConfig.EndpointsConfig[networkName].MacAddress = mac
|
||||
}
|
||||
}
|
||||
|
||||
// WithIPv4 sets the specified ip for the specified network of the container
|
||||
func WithIPv4(networkName, ip string) func(*TestContainerConfig) {
|
||||
return func(c *TestContainerConfig) {
|
||||
|
|
Loading…
Add table
Reference in a new issue