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:
|
LinkLocalIPs:
|
||||||
- "169.254.34.68"
|
- "169.254.34.68"
|
||||||
- "fe80::3468"
|
- "fe80::3468"
|
||||||
|
MacAddress: "02:42:ac:12:05:02"
|
||||||
Links:
|
Links:
|
||||||
- "container_1"
|
- "container_1"
|
||||||
- "container_2"
|
- "container_2"
|
||||||
|
@ -2455,6 +2456,11 @@ definitions:
|
||||||
example:
|
example:
|
||||||
- "container_1"
|
- "container_1"
|
||||||
- "container_2"
|
- "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:
|
Aliases:
|
||||||
type: "array"
|
type: "array"
|
||||||
items:
|
items:
|
||||||
|
@ -2505,11 +2511,6 @@ definitions:
|
||||||
type: "integer"
|
type: "integer"
|
||||||
format: "int64"
|
format: "int64"
|
||||||
example: 64
|
example: 64
|
||||||
MacAddress:
|
|
||||||
description: |
|
|
||||||
MAC address for the endpoint on this network.
|
|
||||||
type: "string"
|
|
||||||
example: "02:42:ac:11:00:04"
|
|
||||||
DriverOpts:
|
DriverOpts:
|
||||||
description: |
|
description: |
|
||||||
DriverOpts is a mapping of driver options and values. These options
|
DriverOpts is a mapping of driver options and values. These options
|
||||||
|
@ -10130,6 +10131,7 @@ paths:
|
||||||
IPAMConfig:
|
IPAMConfig:
|
||||||
IPv4Address: "172.24.56.89"
|
IPv4Address: "172.24.56.89"
|
||||||
IPv6Address: "2001:db8::5689"
|
IPv6Address: "2001:db8::5689"
|
||||||
|
MacAddress: "02:42:ac:12:05:02"
|
||||||
tags: ["Network"]
|
tags: ["Network"]
|
||||||
|
|
||||||
/networks/{id}/disconnect:
|
/networks/{id}/disconnect:
|
||||||
|
|
|
@ -14,6 +14,7 @@ type EndpointSettings struct {
|
||||||
IPAMConfig *EndpointIPAMConfig
|
IPAMConfig *EndpointIPAMConfig
|
||||||
Links []string
|
Links []string
|
||||||
Aliases []string
|
Aliases []string
|
||||||
|
MacAddress string
|
||||||
// Operational data
|
// Operational data
|
||||||
NetworkID string
|
NetworkID string
|
||||||
EndpointID string
|
EndpointID string
|
||||||
|
@ -23,7 +24,6 @@ type EndpointSettings struct {
|
||||||
IPv6Gateway string
|
IPv6Gateway string
|
||||||
GlobalIPv6Address string
|
GlobalIPv6Address string
|
||||||
GlobalIPv6PrefixLen int
|
GlobalIPv6PrefixLen int
|
||||||
MacAddress string
|
|
||||||
DriverOpts map[string]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 {
|
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
|
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 hostConfig != nil {
|
||||||
if versions.LessThan(cli.ClientVersion(), "1.25") {
|
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)
|
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.IPv6Gateway = ""
|
||||||
es.GlobalIPv6Address = ""
|
es.GlobalIPv6Address = ""
|
||||||
es.GlobalIPv6PrefixLen = 0
|
es.GlobalIPv6PrefixLen = 0
|
||||||
es.MacAddress = ""
|
|
||||||
if es.IPAMOperational {
|
if es.IPAMOperational {
|
||||||
es.IPAMConfig = nil
|
es.IPAMConfig = nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -788,6 +788,7 @@ func (daemon *Daemon) clearAttachableNetworks() {
|
||||||
// buildCreateEndpointOptions builds endpoint options from a given network.
|
// 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) {
|
func buildCreateEndpointOptions(c *container.Container, n *libnetwork.Network, epConfig *network.EndpointSettings, sb *libnetwork.Sandbox, daemonDNS []string) ([]libnetwork.EndpointOption, error) {
|
||||||
var createOptions []libnetwork.EndpointOption
|
var createOptions []libnetwork.EndpointOption
|
||||||
|
var genericOptions = make(options.Generic)
|
||||||
|
|
||||||
nwName := n.Name()
|
nwName := n.Name()
|
||||||
defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
|
defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
|
||||||
|
@ -825,6 +826,14 @@ func buildCreateEndpointOptions(c *container.Container, n *libnetwork.Network, e
|
||||||
for k, v := range epConfig.DriverOpts {
|
for k, v := range epConfig.DriverOpts {
|
||||||
createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(options.Generic{k: v}))
|
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 {
|
if svcCfg := c.NetworkSettings.Service; svcCfg != nil {
|
||||||
|
@ -863,9 +872,8 @@ func buildCreateEndpointOptions(c *container.Container, n *libnetwork.Network, e
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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.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
|
return createOptions, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,8 @@ keywords: "API, Docker, rcli, REST, documentation"
|
||||||
* `POST /services/create` and `POST /services/{id}/update` now accept `Seccomp`
|
* `POST /services/create` and `POST /services/{id}/update` now accept `Seccomp`
|
||||||
and `AppArmor` fields in the `ContainerSpec.Privileges` object. This allows
|
and `AppArmor` fields in the `ContainerSpec.Privileges` object. This allows
|
||||||
some configuration of Seccomp and AppArmor in Swarm services.
|
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
|
## v1.43 API changes
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
package container // import "github.com/docker/docker/integration/container"
|
package container // import "github.com/docker/docker/integration/container"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -14,6 +16,7 @@ import (
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
"github.com/docker/docker/errdefs"
|
"github.com/docker/docker/errdefs"
|
||||||
ctr "github.com/docker/docker/integration/internal/container"
|
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/oci"
|
||||||
"github.com/docker/docker/testutil"
|
"github.com/docker/docker/testutil"
|
||||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
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
|
// WithIPv4 sets the specified ip for the specified network of the container
|
||||||
func WithIPv4(networkName, ip string) func(*TestContainerConfig) {
|
func WithIPv4(networkName, ip string) func(*TestContainerConfig) {
|
||||||
return func(c *TestContainerConfig) {
|
return func(c *TestContainerConfig) {
|
||||||
|
|
Loading…
Add table
Reference in a new issue