Merge pull request #46853 from akerouanton/libnet-ep-dns-names
libnet: Endpoint: remove isAnonymous & myAliases
This commit is contained in:
commit
7bc56c5365
18 changed files with 296 additions and 174 deletions
|
@ -2530,6 +2530,21 @@ definitions:
|
|||
example:
|
||||
com.example.some-label: "some-value"
|
||||
com.example.some-other-label: "some-other-value"
|
||||
DNSNames:
|
||||
description: |
|
||||
List of all DNS names an endpoint has on a specific network. This
|
||||
list is based on the container name, network aliases, container short
|
||||
ID, and hostname.
|
||||
|
||||
These DNS names are non-fully qualified but can contain several dots.
|
||||
You can get fully qualified DNS names by appending `.<network-name>`.
|
||||
For instance, if container name is `my.ctr` and the network is named
|
||||
`testnet`, `DNSNames` will contain `my.ctr` and the FQDN will be
|
||||
`my.ctr.testnet`.
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
example: ["foobar", "server_x", "server_y", "my.ctr"]
|
||||
|
||||
EndpointIPAMConfig:
|
||||
description: |
|
||||
|
|
|
@ -13,7 +13,7 @@ type EndpointSettings struct {
|
|||
// Configurations
|
||||
IPAMConfig *EndpointIPAMConfig
|
||||
Links []string
|
||||
Aliases []string
|
||||
Aliases []string // Aliases holds the list of extra, user-specified DNS names for this endpoint.
|
||||
MacAddress string
|
||||
// Operational data
|
||||
NetworkID string
|
||||
|
@ -25,6 +25,9 @@ type EndpointSettings struct {
|
|||
GlobalIPv6Address string
|
||||
GlobalIPv6PrefixLen int
|
||||
DriverOpts map[string]string
|
||||
// DNSNames holds all the (non fully qualified) DNS names associated to this endpoint. First entry is used to
|
||||
// generate PTR records.
|
||||
DNSNames []string
|
||||
}
|
||||
|
||||
// Copy makes a deep copy of `EndpointSettings`
|
||||
|
@ -43,6 +46,12 @@ func (es *EndpointSettings) Copy() *EndpointSettings {
|
|||
aliases := make([]string, 0, len(es.Aliases))
|
||||
epCopy.Aliases = append(aliases, es.Aliases...)
|
||||
}
|
||||
|
||||
if len(es.DNSNames) > 0 {
|
||||
epCopy.DNSNames = make([]string, len(es.DNSNames))
|
||||
copy(epCopy.DNSNames, es.DNSNames)
|
||||
}
|
||||
|
||||
return &epCopy
|
||||
}
|
||||
|
||||
|
|
|
@ -122,9 +122,8 @@ func (daemon *Daemon) Register(c *container.Container) error {
|
|||
|
||||
func (daemon *Daemon) newContainer(name string, operatingSystem string, config *containertypes.Config, hostConfig *containertypes.HostConfig, imgID image.ID, managed bool) (*container.Container, error) {
|
||||
var (
|
||||
id string
|
||||
err error
|
||||
noExplicitName = name == ""
|
||||
id string
|
||||
err error
|
||||
)
|
||||
id, name, err = daemon.generateIDAndName(name)
|
||||
if err != nil {
|
||||
|
@ -151,7 +150,7 @@ func (daemon *Daemon) newContainer(name string, operatingSystem string, config *
|
|||
base.Config = config
|
||||
base.HostConfig = &containertypes.HostConfig{}
|
||||
base.ImageID = imgID
|
||||
base.NetworkSettings = &network.Settings{IsAnonymousEndpoint: noExplicitName}
|
||||
base.NetworkSettings = &network.Settings{}
|
||||
base.Name = name
|
||||
base.Driver = daemon.imageService.StorageDriver()
|
||||
base.OS = operatingSystem
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
"github.com/docker/docker/daemon/network"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/internal/multierror"
|
||||
"github.com/docker/docker/internal/sliceutil"
|
||||
"github.com/docker/docker/libnetwork"
|
||||
"github.com/docker/docker/libnetwork/netlabel"
|
||||
"github.com/docker/docker/libnetwork/options"
|
||||
|
@ -650,29 +651,7 @@ func cleanOperationalData(es *network.EndpointSettings) {
|
|||
|
||||
func (daemon *Daemon) updateNetworkConfig(container *container.Container, n *libnetwork.Network, endpointConfig *networktypes.EndpointSettings, updateSettings bool) error {
|
||||
if containertypes.NetworkMode(n.Name()).IsUserDefined() {
|
||||
addShortID := true
|
||||
shortID := stringid.TruncateID(container.ID)
|
||||
for _, alias := range endpointConfig.Aliases {
|
||||
if alias == shortID {
|
||||
addShortID = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if addShortID {
|
||||
endpointConfig.Aliases = append(endpointConfig.Aliases, shortID)
|
||||
}
|
||||
if container.Name != container.Config.Hostname {
|
||||
addHostname := true
|
||||
for _, alias := range endpointConfig.Aliases {
|
||||
if alias == container.Config.Hostname {
|
||||
addHostname = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if addHostname {
|
||||
endpointConfig.Aliases = append(endpointConfig.Aliases, container.Config.Hostname)
|
||||
}
|
||||
}
|
||||
endpointConfig.DNSNames = buildEndpointDNSNames(container, endpointConfig.Aliases)
|
||||
}
|
||||
|
||||
if err := validateEndpointSettings(n, n.Name(), endpointConfig); err != nil {
|
||||
|
@ -687,6 +666,29 @@ func (daemon *Daemon) updateNetworkConfig(container *container.Container, n *lib
|
|||
return nil
|
||||
}
|
||||
|
||||
// buildEndpointDNSNames constructs the list of DNSNames that should be assigned to a given endpoint. The order within
|
||||
// the returned slice is important as the first entry will be used to generate the PTR records (for IPv4 and v6)
|
||||
// associated to this endpoint.
|
||||
func buildEndpointDNSNames(ctr *container.Container, aliases []string) []string {
|
||||
var dnsNames []string
|
||||
|
||||
if ctr.Name != "" {
|
||||
dnsNames = append(dnsNames, strings.TrimPrefix(ctr.Name, "/"))
|
||||
}
|
||||
|
||||
dnsNames = append(dnsNames, aliases...)
|
||||
|
||||
if ctr.ID != "" {
|
||||
dnsNames = append(dnsNames, stringid.TruncateID(ctr.ID))
|
||||
}
|
||||
|
||||
if ctr.Config.Hostname != "" {
|
||||
dnsNames = append(dnsNames, ctr.Config.Hostname)
|
||||
}
|
||||
|
||||
return sliceutil.Dedup(dnsNames)
|
||||
}
|
||||
|
||||
func (daemon *Daemon) connectToNetwork(cfg *config.Config, container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (err error) {
|
||||
start := time.Now()
|
||||
if container.HostConfig.NetworkMode.IsContainer() {
|
||||
|
|
55
daemon/container_operations_test.go
Normal file
55
daemon/container_operations_test.go
Normal file
|
@ -0,0 +1,55 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
networktypes "github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/libnetwork"
|
||||
"gotest.tools/v3/assert"
|
||||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestDNSNamesOrder(t *testing.T) {
|
||||
d := &Daemon{}
|
||||
ctr := &container.Container{
|
||||
ID: "35de8003b19e27f636fc6ecbf4d7072558b872a8544f287fd69ad8182ad59023",
|
||||
Name: "foobar",
|
||||
Config: &containertypes.Config{
|
||||
Hostname: "baz",
|
||||
},
|
||||
}
|
||||
nw := buildNetwork(t, map[string]any{
|
||||
"id": "1234567890",
|
||||
"name": "testnet",
|
||||
"networkType": "bridge",
|
||||
"enableIPv6": false,
|
||||
})
|
||||
epSettings := &networktypes.EndpointSettings{
|
||||
Aliases: []string{"myctr"},
|
||||
}
|
||||
|
||||
if err := d.updateNetworkConfig(ctr, nw, epSettings, false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
assert.Check(t, is.DeepEqual(epSettings.DNSNames, []string{"foobar", "myctr", "35de8003b19e", "baz"}))
|
||||
}
|
||||
|
||||
func buildNetwork(t *testing.T, config map[string]any) *libnetwork.Network {
|
||||
t.Helper()
|
||||
|
||||
b, err := json.Marshal(config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
nw := &libnetwork.Network{}
|
||||
if err := nw.UnmarshalJSON(b); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return nw
|
||||
}
|
|
@ -15,6 +15,8 @@ import (
|
|||
"github.com/docker/docker/daemon/config"
|
||||
"github.com/docker/docker/daemon/network"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/internal/sliceutil"
|
||||
"github.com/docker/docker/pkg/stringid"
|
||||
"github.com/docker/go-connections/nat"
|
||||
)
|
||||
|
||||
|
@ -27,6 +29,18 @@ func (daemon *Daemon) ContainerInspect(ctx context.Context, name string, size bo
|
|||
return daemon.containerInspectPre120(ctx, name)
|
||||
case versions.Equal(version, "1.20"):
|
||||
return daemon.containerInspect120(name)
|
||||
case versions.LessThan(version, "1.45"):
|
||||
ctr, err := daemon.ContainerInspectCurrent(ctx, name, size)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
shortCID := stringid.TruncateID(ctr.ID)
|
||||
for _, ep := range ctr.NetworkSettings.Networks {
|
||||
ep.Aliases = sliceutil.Dedup(append(ep.Aliases, shortCID, ctr.Config.Hostname))
|
||||
}
|
||||
|
||||
return ctr, nil
|
||||
default:
|
||||
return daemon.ContainerInspectCurrent(ctx, name, size)
|
||||
}
|
||||
|
|
|
@ -793,10 +793,6 @@ func buildCreateEndpointOptions(c *container.Container, n *libnetwork.Network, e
|
|||
var genericOptions = make(options.Generic)
|
||||
|
||||
nwName := n.Name()
|
||||
defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
|
||||
if c.NetworkSettings.IsAnonymousEndpoint || (nwName == defaultNetName && !serviceDiscoveryOnDefaultNetwork()) {
|
||||
createOptions = append(createOptions, libnetwork.CreateOptionAnonymous())
|
||||
}
|
||||
|
||||
if epConfig != nil {
|
||||
if ipam := epConfig.IPAMConfig; ipam != nil {
|
||||
|
@ -822,9 +818,8 @@ func buildCreateEndpointOptions(c *container.Container, n *libnetwork.Network, e
|
|||
createOptions = append(createOptions, libnetwork.CreateOptionIpam(ip, ip6, ipList, nil))
|
||||
}
|
||||
|
||||
for _, alias := range epConfig.Aliases {
|
||||
createOptions = append(createOptions, libnetwork.CreateOptionMyAlias(alias))
|
||||
}
|
||||
createOptions = append(createOptions, libnetwork.CreateOptionDNSNames(epConfig.DNSNames))
|
||||
|
||||
for k, v := range epConfig.DriverOpts {
|
||||
createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(options.Generic{k: v}))
|
||||
}
|
||||
|
|
|
@ -24,7 +24,6 @@ type Settings struct {
|
|||
Ports nat.PortMap
|
||||
SecondaryIPAddresses []networktypes.Address
|
||||
SecondaryIPv6Addresses []networktypes.Address
|
||||
IsAnonymousEndpoint bool
|
||||
HasSwarmEndpoint bool
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/api/types/events"
|
||||
dockercontainer "github.com/docker/docker/container"
|
||||
"github.com/docker/docker/daemon/network"
|
||||
"github.com/docker/docker/errdefs"
|
||||
"github.com/docker/docker/libnetwork"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -38,7 +39,6 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) (retErr error) {
|
|||
defer container.Unlock()
|
||||
|
||||
oldName = container.Name
|
||||
oldIsAnonymousEndpoint := container.NetworkSettings.IsAnonymousEndpoint
|
||||
|
||||
if oldName == newName {
|
||||
return errdefs.InvalidParameter(errors.New("Renaming a container with the same name as its current name"))
|
||||
|
@ -62,12 +62,10 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) (retErr error) {
|
|||
}
|
||||
|
||||
container.Name = newName
|
||||
container.NetworkSettings.IsAnonymousEndpoint = false
|
||||
|
||||
defer func() {
|
||||
if retErr != nil {
|
||||
container.Name = oldName
|
||||
container.NetworkSettings.IsAnonymousEndpoint = oldIsAnonymousEndpoint
|
||||
daemon.reserveName(container.ID, oldName)
|
||||
for k, v := range links {
|
||||
daemon.containersReplica.ReserveName(oldName+k, v.ID)
|
||||
|
@ -101,7 +99,6 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) (retErr error) {
|
|||
defer func() {
|
||||
if retErr != nil {
|
||||
container.Name = oldName
|
||||
container.NetworkSettings.IsAnonymousEndpoint = oldIsAnonymousEndpoint
|
||||
if err := container.CheckpointTo(daemon.containersReplica); err != nil {
|
||||
log.G(context.TODO()).WithFields(log.Fields{
|
||||
"containerID": container.ID,
|
||||
|
@ -118,10 +115,57 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) (retErr error) {
|
|||
return err
|
||||
}
|
||||
|
||||
err = sb.Rename(strings.TrimPrefix(container.Name, "/"))
|
||||
if err != nil {
|
||||
if err := sb.Rename(newName[1:]); err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if retErr != nil {
|
||||
if err := sb.Rename(oldName); err != nil {
|
||||
log.G(context.TODO()).WithFields(log.Fields{
|
||||
"sandboxID": sid,
|
||||
"oldName": oldName,
|
||||
"newName": newName,
|
||||
"error": err,
|
||||
}).Errorf("failed to revert sandbox rename")
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
for nwName, epConfig := range container.NetworkSettings.Networks {
|
||||
nw, err := daemon.FindNetwork(nwName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ep, err := nw.EndpointByID(epConfig.EndpointID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
oldDNSNames := make([]string, len(epConfig.DNSNames))
|
||||
copy(oldDNSNames, epConfig.DNSNames)
|
||||
|
||||
epConfig.DNSNames = buildEndpointDNSNames(container, epConfig.Aliases)
|
||||
if err := ep.UpdateDNSNames(epConfig.DNSNames); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func(ep *libnetwork.Endpoint, epConfig *network.EndpointSettings, oldDNSNames []string) {
|
||||
if retErr == nil {
|
||||
return
|
||||
}
|
||||
|
||||
epConfig.DNSNames = oldDNSNames
|
||||
if err := ep.UpdateDNSNames(epConfig.DNSNames); err != nil {
|
||||
log.G(context.TODO()).WithFields(log.Fields{
|
||||
"sandboxID": sid,
|
||||
"oldName": oldName,
|
||||
"newName": newName,
|
||||
"error": err,
|
||||
}).Errorf("failed to revert DNSNames update")
|
||||
}
|
||||
}(ep, epConfig, oldDNSNames)
|
||||
}
|
||||
}
|
||||
|
||||
daemon.LogContainerEventWithAttributes(container, events.ActionRename, attributes)
|
||||
|
|
|
@ -68,6 +68,13 @@ keywords: "API, Docker, rcli, REST, documentation"
|
|||
* The `Container` and `ContainerConfig` fields in the `GET /images/{name}/json`
|
||||
response are deprecated and will no longer be included in API v1.45.
|
||||
* `GET /info` now includes `status` properties in `Runtimes`.
|
||||
* A new field named `DNSNames` and containing all non-fully qualified DNS names
|
||||
a container takes on a specific network has been added to `GET /containers/{name:.*}/json`.
|
||||
* The `Aliases` field returned in calls to `GET /containers/{name:.*}/json` in v1.44 and older
|
||||
versions contains the short container ID. This will change in the next API version, v1.45.
|
||||
Starting with that API version, this specific value will be removed from the `Aliases` field
|
||||
such that this field will reflect exactly the values originally submitted to the
|
||||
`POST /containers/create` endpoint. The newly introduced `DNSNames` should now be used instead.
|
||||
|
||||
## v1.43 API changes
|
||||
|
||||
|
|
|
@ -13,7 +13,8 @@ source hack/make/.integration-test-helpers
|
|||
# --deselect=tests/integration/api_container_test.py::AttachContainerTest::test_attach_no_stream
|
||||
# TODO re-enable test_attach_no_stream after https://github.com/docker/docker-py/issues/2513 is resolved
|
||||
# TODO re-enable test_run_container_reading_socket_ws. It's reported in https://github.com/docker/docker-py/issues/1478, and we're getting that error in our tests.
|
||||
: "${PY_TEST_OPTIONS:=--junitxml=${DEST}/junit-report.xml --deselect=tests/integration/api_container_test.py::AttachContainerTest::test_attach_no_stream --deselect=tests/integration/api_container_test.py::AttachContainerTest::test_run_container_reading_socket_ws}"
|
||||
# TODO re-enable test_run_with_networking_config once this issue is fixed: https://github.com/moby/moby/pull/46853#issuecomment-1864679942.
|
||||
: "${PY_TEST_OPTIONS:=--junitxml=${DEST}/junit-report.xml --deselect=tests/integration/api_container_test.py::AttachContainerTest::test_attach_no_stream --deselect=tests/integration/api_container_test.py::AttachContainerTest::test_run_container_reading_socket_ws --deselect=tests/integration/models_containers_test.py::ContainerCollectionTest::test_run_with_networking_config}"
|
||||
|
||||
# build --squash is not supported with containerd integration.
|
||||
if [ -n "$TEST_INTEGRATION_USE_SNAPSHOTTER" ]; then
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/docker/integration/internal/container"
|
||||
net "github.com/docker/docker/integration/internal/network"
|
||||
"github.com/docker/docker/integration/internal/swarm"
|
||||
|
@ -13,13 +14,13 @@ import (
|
|||
"gotest.tools/v3/skip"
|
||||
)
|
||||
|
||||
func TestDockerNetworkConnectAlias(t *testing.T) {
|
||||
func TestDockerNetworkConnectAliasPreV144(t *testing.T) {
|
||||
skip.If(t, testEnv.DaemonInfo.OSType == "windows")
|
||||
ctx := setupTest(t)
|
||||
|
||||
d := swarm.NewSwarm(ctx, t, testEnv)
|
||||
defer d.Stop(t)
|
||||
client := d.NewClientT(t)
|
||||
client := d.NewClientT(t, client.WithVersion("1.43"))
|
||||
defer client.Close()
|
||||
|
||||
name := t.Name() + "test-alias"
|
||||
|
|
13
internal/sliceutil/sliceutil.go
Normal file
13
internal/sliceutil/sliceutil.go
Normal file
|
@ -0,0 +1,13 @@
|
|||
package sliceutil
|
||||
|
||||
func Dedup[T comparable](slice []T) []T {
|
||||
keys := make(map[T]struct{})
|
||||
out := make([]T, 0, len(slice))
|
||||
for _, s := range slice {
|
||||
if _, ok := keys[s]; !ok {
|
||||
out = append(out, s)
|
||||
keys[s] = struct{}{}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
|
@ -598,7 +598,7 @@ func (ep *Endpoint) deleteDriverInfoFromCluster() error {
|
|||
}
|
||||
|
||||
func (ep *Endpoint) addServiceInfoToCluster(sb *Sandbox) error {
|
||||
if len(ep.myAliases) == 0 && ep.isAnonymous() || ep.Iface() == nil || ep.Iface().Address() == nil {
|
||||
if len(ep.dnsNames) == 0 || ep.Iface() == nil || ep.Iface().Address() == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -628,10 +628,8 @@ func (ep *Endpoint) addServiceInfoToCluster(sb *Sandbox) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
name := ep.Name()
|
||||
if ep.isAnonymous() {
|
||||
name = ep.MyAliases()[0]
|
||||
}
|
||||
dnsNames := ep.getDNSNames()
|
||||
primaryDNSName, dnsAliases := dnsNames[0], dnsNames[1:]
|
||||
|
||||
var ingressPorts []*PortConfig
|
||||
if ep.svcID != "" {
|
||||
|
@ -640,24 +638,24 @@ func (ep *Endpoint) addServiceInfoToCluster(sb *Sandbox) error {
|
|||
if n.ingress {
|
||||
ingressPorts = ep.ingressPorts
|
||||
}
|
||||
if err := n.getController().addServiceBinding(ep.svcName, ep.svcID, n.ID(), ep.ID(), name, ep.virtualIP, ingressPorts, ep.svcAliases, ep.myAliases, ep.Iface().Address().IP, "addServiceInfoToCluster"); err != nil {
|
||||
if err := n.getController().addServiceBinding(ep.svcName, ep.svcID, n.ID(), ep.ID(), primaryDNSName, ep.virtualIP, ingressPorts, ep.svcAliases, dnsAliases, ep.Iface().Address().IP, "addServiceInfoToCluster"); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// This is a container simply attached to an attachable network
|
||||
if err := n.getController().addContainerNameResolution(n.ID(), ep.ID(), name, ep.myAliases, ep.Iface().Address().IP, "addServiceInfoToCluster"); err != nil {
|
||||
if err := n.getController().addContainerNameResolution(n.ID(), ep.ID(), primaryDNSName, dnsAliases, ep.Iface().Address().IP, "addServiceInfoToCluster"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
buf, err := proto.Marshal(&EndpointRecord{
|
||||
Name: name,
|
||||
Name: primaryDNSName,
|
||||
ServiceName: ep.svcName,
|
||||
ServiceID: ep.svcID,
|
||||
VirtualIP: ep.virtualIP.String(),
|
||||
IngressPorts: ingressPorts,
|
||||
Aliases: ep.svcAliases,
|
||||
TaskAliases: ep.myAliases,
|
||||
TaskAliases: dnsAliases,
|
||||
EndpointIP: ep.Iface().Address().IP.String(),
|
||||
ServiceDisabled: false,
|
||||
})
|
||||
|
@ -676,7 +674,7 @@ func (ep *Endpoint) addServiceInfoToCluster(sb *Sandbox) error {
|
|||
}
|
||||
|
||||
func (ep *Endpoint) deleteServiceInfoFromCluster(sb *Sandbox, fullRemove bool, method string) error {
|
||||
if len(ep.myAliases) == 0 && ep.isAnonymous() {
|
||||
if len(ep.dnsNames) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -699,10 +697,8 @@ func (ep *Endpoint) deleteServiceInfoFromCluster(sb *Sandbox, fullRemove bool, m
|
|||
return nil
|
||||
}
|
||||
|
||||
name := ep.Name()
|
||||
if ep.isAnonymous() {
|
||||
name = ep.MyAliases()[0]
|
||||
}
|
||||
dnsNames := ep.getDNSNames()
|
||||
primaryDNSName, dnsAliases := dnsNames[0], dnsNames[1:]
|
||||
|
||||
// First update the networkDB then locally
|
||||
if fullRemove {
|
||||
|
@ -720,12 +716,12 @@ func (ep *Endpoint) deleteServiceInfoFromCluster(sb *Sandbox, fullRemove bool, m
|
|||
if n.ingress {
|
||||
ingressPorts = ep.ingressPorts
|
||||
}
|
||||
if err := n.getController().rmServiceBinding(ep.svcName, ep.svcID, n.ID(), ep.ID(), name, ep.virtualIP, ingressPorts, ep.svcAliases, ep.myAliases, ep.Iface().Address().IP, "deleteServiceInfoFromCluster", true, fullRemove); err != nil {
|
||||
if err := n.getController().rmServiceBinding(ep.svcName, ep.svcID, n.ID(), ep.ID(), primaryDNSName, ep.virtualIP, ingressPorts, ep.svcAliases, dnsAliases, ep.Iface().Address().IP, "deleteServiceInfoFromCluster", true, fullRemove); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// This is a container simply attached to an attachable network
|
||||
if err := n.getController().delContainerNameResolution(n.ID(), ep.ID(), name, ep.myAliases, ep.Iface().Address().IP, "deleteServiceInfoFromCluster"); err != nil {
|
||||
if err := n.getController().delContainerNameResolution(n.ID(), ep.ID(), primaryDNSName, dnsAliases, ep.Iface().Address().IP, "deleteServiceInfoFromCluster"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ func (sb *Sandbox) setupDefaultGW() error {
|
|||
}
|
||||
}
|
||||
|
||||
createOptions := []EndpointOption{CreateOptionAnonymous()}
|
||||
createOptions := []EndpointOption{}
|
||||
|
||||
var gwName string
|
||||
if len(sb.containerID) <= gwEPlen {
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/containerd/log"
|
||||
"github.com/docker/docker/internal/sliceutil"
|
||||
"github.com/docker/docker/libnetwork/datastore"
|
||||
"github.com/docker/docker/libnetwork/ipamapi"
|
||||
"github.com/docker/docker/libnetwork/netlabel"
|
||||
|
@ -23,21 +24,22 @@ type EndpointOption func(ep *Endpoint)
|
|||
|
||||
// Endpoint represents a logical connection between a network and a sandbox.
|
||||
type Endpoint struct {
|
||||
name string
|
||||
id string
|
||||
network *Network
|
||||
iface *EndpointInterface
|
||||
joinInfo *endpointJoinInfo
|
||||
sandboxID string
|
||||
exposedPorts []types.TransportPort
|
||||
anonymous bool
|
||||
name string
|
||||
id string
|
||||
network *Network
|
||||
iface *EndpointInterface
|
||||
joinInfo *endpointJoinInfo
|
||||
sandboxID string
|
||||
exposedPorts []types.TransportPort
|
||||
// dnsNames holds all the non-fully qualified DNS names associated to this endpoint. Order matters: first entry
|
||||
// will be used for the PTR records associated to the endpoint's IPv4 and IPv6 addresses.
|
||||
dnsNames []string
|
||||
disableResolution bool
|
||||
generic map[string]interface{}
|
||||
prefAddress net.IP
|
||||
prefAddressV6 net.IP
|
||||
ipamOptions map[string]string
|
||||
aliases map[string]string
|
||||
myAliases []string
|
||||
svcID string
|
||||
svcName string
|
||||
virtualIP net.IP
|
||||
|
@ -64,9 +66,8 @@ func (ep *Endpoint) MarshalJSON() ([]byte, error) {
|
|||
epMap["generic"] = ep.generic
|
||||
}
|
||||
epMap["sandbox"] = ep.sandboxID
|
||||
epMap["anonymous"] = ep.anonymous
|
||||
epMap["dnsNames"] = ep.dnsNames
|
||||
epMap["disableResolution"] = ep.disableResolution
|
||||
epMap["myAliases"] = ep.myAliases
|
||||
epMap["svcName"] = ep.svcName
|
||||
epMap["svcID"] = ep.svcID
|
||||
epMap["virtualIP"] = ep.virtualIP.String()
|
||||
|
@ -156,8 +157,9 @@ func (ep *Endpoint) UnmarshalJSON(b []byte) (err error) {
|
|||
}
|
||||
}
|
||||
|
||||
var anonymous bool
|
||||
if v, ok := epMap["anonymous"]; ok {
|
||||
ep.anonymous = v.(bool)
|
||||
anonymous = v.(bool)
|
||||
}
|
||||
if v, ok := epMap["disableResolution"]; ok {
|
||||
ep.disableResolution = v.(bool)
|
||||
|
@ -192,7 +194,23 @@ func (ep *Endpoint) UnmarshalJSON(b []byte) (err error) {
|
|||
ma, _ := json.Marshal(epMap["myAliases"])
|
||||
var myAliases []string
|
||||
json.Unmarshal(ma, &myAliases) //nolint:errcheck
|
||||
ep.myAliases = myAliases
|
||||
|
||||
_, hasDNSNames := epMap["dnsNames"]
|
||||
dn, _ := json.Marshal(epMap["dnsNames"])
|
||||
var dnsNames []string
|
||||
json.Unmarshal(dn, &dnsNames)
|
||||
ep.dnsNames = dnsNames
|
||||
|
||||
// TODO(aker): remove this migration code in v27
|
||||
if !hasDNSNames {
|
||||
// The field dnsNames was introduced in v25.0. If we don't have it, the on-disk state was written by an older
|
||||
// daemon, thus we need to populate dnsNames based off of myAliases and anonymous values.
|
||||
if !anonymous {
|
||||
myAliases = append([]string{ep.name}, myAliases...)
|
||||
}
|
||||
ep.dnsNames = sliceutil.Dedup(myAliases)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -210,7 +228,6 @@ func (ep *Endpoint) CopyTo(o datastore.KVObject) error {
|
|||
dstEp.sandboxID = ep.sandboxID
|
||||
dstEp.dbIndex = ep.dbIndex
|
||||
dstEp.dbExists = ep.dbExists
|
||||
dstEp.anonymous = ep.anonymous
|
||||
dstEp.disableResolution = ep.disableResolution
|
||||
dstEp.svcName = ep.svcName
|
||||
dstEp.svcID = ep.svcID
|
||||
|
@ -240,8 +257,8 @@ func (ep *Endpoint) CopyTo(o datastore.KVObject) error {
|
|||
dstEp.exposedPorts = make([]types.TransportPort, len(ep.exposedPorts))
|
||||
copy(dstEp.exposedPorts, ep.exposedPorts)
|
||||
|
||||
dstEp.myAliases = make([]string, len(ep.myAliases))
|
||||
copy(dstEp.myAliases, ep.myAliases)
|
||||
dstEp.dnsNames = make([]string, len(ep.dnsNames))
|
||||
copy(dstEp.dnsNames, ep.dnsNames)
|
||||
|
||||
dstEp.generic = options.Generic{}
|
||||
for k, v := range ep.generic {
|
||||
|
@ -267,13 +284,6 @@ func (ep *Endpoint) Name() string {
|
|||
return ep.name
|
||||
}
|
||||
|
||||
func (ep *Endpoint) MyAliases() []string {
|
||||
ep.mu.Lock()
|
||||
defer ep.mu.Unlock()
|
||||
|
||||
return ep.myAliases
|
||||
}
|
||||
|
||||
// Network returns the name of the network to which this endpoint is attached.
|
||||
func (ep *Endpoint) Network() string {
|
||||
if ep.network == nil {
|
||||
|
@ -283,10 +293,15 @@ func (ep *Endpoint) Network() string {
|
|||
return ep.network.name
|
||||
}
|
||||
|
||||
func (ep *Endpoint) isAnonymous() bool {
|
||||
// getDNSNames returns a copy of the DNS names associated to this endpoint. The first entry is the one used for PTR
|
||||
// records.
|
||||
func (ep *Endpoint) getDNSNames() []string {
|
||||
ep.mu.Lock()
|
||||
defer ep.mu.Unlock()
|
||||
return ep.anonymous
|
||||
|
||||
dnsNames := make([]string, len(ep.dnsNames))
|
||||
copy(dnsNames, ep.dnsNames)
|
||||
return dnsNames
|
||||
}
|
||||
|
||||
// isServiceEnabled check if service is enabled on the endpoint
|
||||
|
@ -568,71 +583,52 @@ func (ep *Endpoint) sbJoin(sb *Sandbox, options ...EndpointOption) (err error) {
|
|||
}
|
||||
|
||||
func (ep *Endpoint) rename(name string) error {
|
||||
var (
|
||||
err error
|
||||
ok bool
|
||||
)
|
||||
ep.mu.Lock()
|
||||
ep.name = name
|
||||
ep.mu.Unlock()
|
||||
|
||||
n := ep.getNetwork()
|
||||
if n == nil {
|
||||
return fmt.Errorf("network not connected for ep %q", ep.name)
|
||||
// Update the store with the updated name
|
||||
if err := ep.getNetwork().getController().updateToStore(ep); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c := n.getController()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ep *Endpoint) UpdateDNSNames(dnsNames []string) error {
|
||||
nw := ep.getNetwork()
|
||||
c := nw.getController()
|
||||
sb, ok := ep.getSandbox()
|
||||
if !ok {
|
||||
log.G(context.TODO()).Warnf("rename for %s aborted, sandbox %s is not anymore present", ep.ID(), ep.sandboxID)
|
||||
log.G(context.TODO()).WithFields(log.Fields{
|
||||
"sandboxID": ep.sandboxID,
|
||||
"endpointID": ep.ID(),
|
||||
}).Warn("DNSNames update aborted, sandbox is not present anymore")
|
||||
return nil
|
||||
}
|
||||
|
||||
if c.isAgent() {
|
||||
if err = ep.deleteServiceInfoFromCluster(sb, true, "rename"); err != nil {
|
||||
return types.InternalErrorf("Could not delete service state for endpoint %s from cluster on rename: %v", ep.Name(), err)
|
||||
if err := ep.deleteServiceInfoFromCluster(sb, true, "UpdateDNSNames"); err != nil {
|
||||
return types.InternalErrorf("could not delete service state for endpoint %s from cluster on UpdateDNSNames: %v", ep.Name(), err)
|
||||
}
|
||||
|
||||
ep.dnsNames = dnsNames
|
||||
if err := ep.addServiceInfoToCluster(sb); err != nil {
|
||||
return types.InternalErrorf("could not add service state for endpoint %s to cluster on UpdateDNSNames: %v", ep.Name(), err)
|
||||
}
|
||||
} else {
|
||||
n.updateSvcRecord(ep, false)
|
||||
}
|
||||
nw.updateSvcRecord(ep, false)
|
||||
|
||||
oldName := ep.name
|
||||
oldAnonymous := ep.anonymous
|
||||
ep.name = name
|
||||
ep.anonymous = false
|
||||
|
||||
if c.isAgent() {
|
||||
if err = ep.addServiceInfoToCluster(sb); err != nil {
|
||||
return types.InternalErrorf("Could not add service state for endpoint %s to cluster on rename: %v", ep.Name(), err)
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if err2 := ep.deleteServiceInfoFromCluster(sb, true, "rename"); err2 != nil {
|
||||
log.G(context.TODO()).WithField("main error", err).WithError(err2).Debug("Error during cleanup due deleting service info from cluster while cleaning up due to other error")
|
||||
}
|
||||
ep.name = oldName
|
||||
ep.anonymous = oldAnonymous
|
||||
if err2 := ep.addServiceInfoToCluster(sb); err2 != nil {
|
||||
log.G(context.TODO()).WithField("main error", err).WithError(err2).Debug("Error during cleanup due adding service to from cluster while cleaning up due to other error")
|
||||
}
|
||||
}
|
||||
}()
|
||||
} else {
|
||||
n.updateSvcRecord(ep, true)
|
||||
defer func() {
|
||||
if err != nil {
|
||||
n.updateSvcRecord(ep, false)
|
||||
ep.name = oldName
|
||||
ep.anonymous = oldAnonymous
|
||||
n.updateSvcRecord(ep, true)
|
||||
}
|
||||
}()
|
||||
ep.dnsNames = dnsNames
|
||||
nw.updateSvcRecord(ep, true)
|
||||
}
|
||||
|
||||
// Update the store with the updated name
|
||||
if err = c.updateToStore(ep); err != nil {
|
||||
if err := c.updateToStore(ep); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ep *Endpoint) hasInterface(iName string) bool {
|
||||
|
@ -951,11 +947,11 @@ func CreateOptionDNS(dns []string) EndpointOption {
|
|||
}
|
||||
}
|
||||
|
||||
// CreateOptionAnonymous function returns an option setter for setting
|
||||
// this endpoint as anonymous
|
||||
func CreateOptionAnonymous() EndpointOption {
|
||||
// CreateOptionDNSNames specifies the list of (non fully qualified) DNS names associated to an endpoint. These will be
|
||||
// used to populate the embedded DNS server. Order matters: first name will be used to generate PTR records.
|
||||
func CreateOptionDNSNames(names []string) EndpointOption {
|
||||
return func(ep *Endpoint) {
|
||||
ep.anonymous = true
|
||||
ep.dnsNames = names
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -988,13 +984,6 @@ func CreateOptionService(name, id string, vip net.IP, ingressPorts []*PortConfig
|
|||
}
|
||||
}
|
||||
|
||||
// CreateOptionMyAlias function returns an option setter for setting endpoint's self alias
|
||||
func CreateOptionMyAlias(alias string) EndpointOption {
|
||||
return func(ep *Endpoint) {
|
||||
ep.myAliases = append(ep.myAliases, alias)
|
||||
}
|
||||
}
|
||||
|
||||
// CreateOptionLoadBalancer function returns an option setter for denoting the endpoint is a load balancer for a network
|
||||
func CreateOptionLoadBalancer() EndpointOption {
|
||||
return func(ep *Endpoint) {
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -191,7 +192,6 @@ func TestEndpointMarshalling(t *testing.T) {
|
|||
name: "Bau",
|
||||
id: "efghijklmno",
|
||||
sandboxID: "ambarabaciccicocco",
|
||||
anonymous: true,
|
||||
iface: &EndpointInterface{
|
||||
mac: []byte{11, 12, 13, 14, 15, 16},
|
||||
addr: &net.IPNet{
|
||||
|
@ -205,6 +205,7 @@ func TestEndpointMarshalling(t *testing.T) {
|
|||
v6PoolID: "poolv6",
|
||||
llAddrs: lla,
|
||||
},
|
||||
dnsNames: []string{"test", "foobar", "baz"},
|
||||
}
|
||||
|
||||
b, err := json.Marshal(e)
|
||||
|
@ -218,7 +219,7 @@ func TestEndpointMarshalling(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if e.name != ee.name || e.id != ee.id || e.sandboxID != ee.sandboxID || !compareEndpointInterface(e.iface, ee.iface) || e.anonymous != ee.anonymous {
|
||||
if e.name != ee.name || e.id != ee.id || e.sandboxID != ee.sandboxID || !reflect.DeepEqual(e.dnsNames, ee.dnsNames) || !compareEndpointInterface(e.iface, ee.iface) {
|
||||
t.Fatalf("JSON marsh/unmarsh failed.\nOriginal:\n%#v\nDecoded:\n%#v\nOriginal iface: %#v\nDecodediface:\n%#v", e, ee, e.iface, ee.iface)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -175,7 +175,7 @@ func (i *IpamInfo) UnmarshalJSON(data []byte) error {
|
|||
type Network struct {
|
||||
ctrlr *Controller
|
||||
name string
|
||||
networkType string
|
||||
networkType string // networkType is the name of the netdriver used by this network
|
||||
id string
|
||||
created time.Time
|
||||
scope string // network data scope
|
||||
|
@ -1302,8 +1302,6 @@ func (n *Network) updateSvcRecord(ep *Endpoint, isAdd bool) {
|
|||
}
|
||||
|
||||
var ipv6 net.IP
|
||||
epName := ep.Name()
|
||||
myAliases := ep.MyAliases()
|
||||
if iface.AddressIPv6() != nil {
|
||||
ipv6 = iface.AddressIPv6().IP
|
||||
}
|
||||
|
@ -1312,30 +1310,17 @@ func (n *Network) updateSvcRecord(ep *Endpoint, isAdd bool) {
|
|||
if serviceID == "" {
|
||||
serviceID = ep.ID()
|
||||
}
|
||||
|
||||
dnsNames := ep.getDNSNames()
|
||||
if isAdd {
|
||||
// If anonymous endpoint has an alias use the first alias
|
||||
// for ip->name mapping. Not having the reverse mapping
|
||||
// breaks some apps
|
||||
if ep.isAnonymous() {
|
||||
if len(myAliases) > 0 {
|
||||
n.addSvcRecords(ep.ID(), myAliases[0], serviceID, iface.Address().IP, ipv6, true, "updateSvcRecord")
|
||||
}
|
||||
} else {
|
||||
n.addSvcRecords(ep.ID(), epName, serviceID, iface.Address().IP, ipv6, true, "updateSvcRecord")
|
||||
}
|
||||
for _, alias := range myAliases {
|
||||
n.addSvcRecords(ep.ID(), alias, serviceID, iface.Address().IP, ipv6, false, "updateSvcRecord")
|
||||
for i, dnsName := range dnsNames {
|
||||
ipMapUpdate := i == 0 // ipMapUpdate indicates whether PTR records should be updated.
|
||||
n.addSvcRecords(ep.ID(), dnsName, serviceID, iface.Address().IP, ipv6, ipMapUpdate, "updateSvcRecord")
|
||||
}
|
||||
} else {
|
||||
if ep.isAnonymous() {
|
||||
if len(myAliases) > 0 {
|
||||
n.deleteSvcRecords(ep.ID(), myAliases[0], serviceID, iface.Address().IP, ipv6, true, "updateSvcRecord")
|
||||
}
|
||||
} else {
|
||||
n.deleteSvcRecords(ep.ID(), epName, serviceID, iface.Address().IP, ipv6, true, "updateSvcRecord")
|
||||
}
|
||||
for _, alias := range myAliases {
|
||||
n.deleteSvcRecords(ep.ID(), alias, serviceID, iface.Address().IP, ipv6, false, "updateSvcRecord")
|
||||
for i, dnsName := range dnsNames {
|
||||
ipMapUpdate := i == 0 // ipMapUpdate indicates whether PTR records should be updated.
|
||||
n.deleteSvcRecords(ep.ID(), dnsName, serviceID, iface.Address().IP, ipv6, ipMapUpdate, "updateSvcRecord")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1374,6 +1359,7 @@ func delNameToIP(svcMap *setmatrix.SetMatrix[svcMapEntry], name, serviceID strin
|
|||
})
|
||||
}
|
||||
|
||||
// TODO(aker): remove ipMapUpdate param and add a proper method dedicated to update PTR records.
|
||||
func (n *Network) addSvcRecords(eID, name, serviceID string, epIP, epIPv6 net.IP, ipMapUpdate bool, method string) {
|
||||
// Do not add service names for ingress network as this is a
|
||||
// routing only network
|
||||
|
@ -2176,10 +2162,6 @@ func (n *Network) createLoadBalancerSandbox() (retErr error) {
|
|||
CreateOptionIpam(n.loadBalancerIP, nil, nil, nil),
|
||||
CreateOptionLoadBalancer(),
|
||||
}
|
||||
if n.hasLoadBalancerEndpoint() && !n.ingress {
|
||||
// Mark LB endpoints as anonymous so they don't show up in DNS
|
||||
epOptions = append(epOptions, CreateOptionAnonymous())
|
||||
}
|
||||
ep, err := n.createEndpoint(endpointName, epOptions...)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
Loading…
Add table
Reference in a new issue