libnet: Endpoint: remove isAnonymous & myAliases
| ... | ... |
@@ -2530,6 +2530,21 @@ definitions: |
| 2530 | 2530 |
example: |
| 2531 | 2531 |
com.example.some-label: "some-value" |
| 2532 | 2532 |
com.example.some-other-label: "some-other-value" |
| 2533 |
+ DNSNames: |
|
| 2534 |
+ description: | |
|
| 2535 |
+ List of all DNS names an endpoint has on a specific network. This |
|
| 2536 |
+ list is based on the container name, network aliases, container short |
|
| 2537 |
+ ID, and hostname. |
|
| 2538 |
+ |
|
| 2539 |
+ These DNS names are non-fully qualified but can contain several dots. |
|
| 2540 |
+ You can get fully qualified DNS names by appending `.<network-name>`. |
|
| 2541 |
+ For instance, if container name is `my.ctr` and the network is named |
|
| 2542 |
+ `testnet`, `DNSNames` will contain `my.ctr` and the FQDN will be |
|
| 2543 |
+ `my.ctr.testnet`. |
|
| 2544 |
+ type: array |
|
| 2545 |
+ items: |
|
| 2546 |
+ type: string |
|
| 2547 |
+ example: ["foobar", "server_x", "server_y", "my.ctr"] |
|
| 2533 | 2548 |
|
| 2534 | 2549 |
EndpointIPAMConfig: |
| 2535 | 2550 |
description: | |
| ... | ... |
@@ -13,7 +13,7 @@ type EndpointSettings struct {
|
| 13 | 13 |
// Configurations |
| 14 | 14 |
IPAMConfig *EndpointIPAMConfig |
| 15 | 15 |
Links []string |
| 16 |
- Aliases []string |
|
| 16 |
+ Aliases []string // Aliases holds the list of extra, user-specified DNS names for this endpoint. |
|
| 17 | 17 |
MacAddress string |
| 18 | 18 |
// Operational data |
| 19 | 19 |
NetworkID string |
| ... | ... |
@@ -25,6 +25,9 @@ type EndpointSettings struct {
|
| 25 | 25 |
GlobalIPv6Address string |
| 26 | 26 |
GlobalIPv6PrefixLen int |
| 27 | 27 |
DriverOpts map[string]string |
| 28 |
+ // DNSNames holds all the (non fully qualified) DNS names associated to this endpoint. First entry is used to |
|
| 29 |
+ // generate PTR records. |
|
| 30 |
+ DNSNames []string |
|
| 28 | 31 |
} |
| 29 | 32 |
|
| 30 | 33 |
// Copy makes a deep copy of `EndpointSettings` |
| ... | ... |
@@ -43,6 +46,12 @@ func (es *EndpointSettings) Copy() *EndpointSettings {
|
| 43 | 43 |
aliases := make([]string, 0, len(es.Aliases)) |
| 44 | 44 |
epCopy.Aliases = append(aliases, es.Aliases...) |
| 45 | 45 |
} |
| 46 |
+ |
|
| 47 |
+ if len(es.DNSNames) > 0 {
|
|
| 48 |
+ epCopy.DNSNames = make([]string, len(es.DNSNames)) |
|
| 49 |
+ copy(epCopy.DNSNames, es.DNSNames) |
|
| 50 |
+ } |
|
| 51 |
+ |
|
| 46 | 52 |
return &epCopy |
| 47 | 53 |
} |
| 48 | 54 |
|
| ... | ... |
@@ -122,9 +122,8 @@ func (daemon *Daemon) Register(c *container.Container) error {
|
| 122 | 122 |
|
| 123 | 123 |
func (daemon *Daemon) newContainer(name string, operatingSystem string, config *containertypes.Config, hostConfig *containertypes.HostConfig, imgID image.ID, managed bool) (*container.Container, error) {
|
| 124 | 124 |
var ( |
| 125 |
- id string |
|
| 126 |
- err error |
|
| 127 |
- noExplicitName = name == "" |
|
| 125 |
+ id string |
|
| 126 |
+ err error |
|
| 128 | 127 |
) |
| 129 | 128 |
id, name, err = daemon.generateIDAndName(name) |
| 130 | 129 |
if err != nil {
|
| ... | ... |
@@ -151,7 +150,7 @@ func (daemon *Daemon) newContainer(name string, operatingSystem string, config * |
| 151 | 151 |
base.Config = config |
| 152 | 152 |
base.HostConfig = &containertypes.HostConfig{}
|
| 153 | 153 |
base.ImageID = imgID |
| 154 |
- base.NetworkSettings = &network.Settings{IsAnonymousEndpoint: noExplicitName}
|
|
| 154 |
+ base.NetworkSettings = &network.Settings{}
|
|
| 155 | 155 |
base.Name = name |
| 156 | 156 |
base.Driver = daemon.imageService.StorageDriver() |
| 157 | 157 |
base.OS = operatingSystem |
| ... | ... |
@@ -19,6 +19,7 @@ import ( |
| 19 | 19 |
"github.com/docker/docker/daemon/network" |
| 20 | 20 |
"github.com/docker/docker/errdefs" |
| 21 | 21 |
"github.com/docker/docker/internal/multierror" |
| 22 |
+ "github.com/docker/docker/internal/sliceutil" |
|
| 22 | 23 |
"github.com/docker/docker/libnetwork" |
| 23 | 24 |
"github.com/docker/docker/libnetwork/netlabel" |
| 24 | 25 |
"github.com/docker/docker/libnetwork/options" |
| ... | ... |
@@ -650,29 +651,7 @@ func cleanOperationalData(es *network.EndpointSettings) {
|
| 650 | 650 |
|
| 651 | 651 |
func (daemon *Daemon) updateNetworkConfig(container *container.Container, n *libnetwork.Network, endpointConfig *networktypes.EndpointSettings, updateSettings bool) error {
|
| 652 | 652 |
if containertypes.NetworkMode(n.Name()).IsUserDefined() {
|
| 653 |
- addShortID := true |
|
| 654 |
- shortID := stringid.TruncateID(container.ID) |
|
| 655 |
- for _, alias := range endpointConfig.Aliases {
|
|
| 656 |
- if alias == shortID {
|
|
| 657 |
- addShortID = false |
|
| 658 |
- break |
|
| 659 |
- } |
|
| 660 |
- } |
|
| 661 |
- if addShortID {
|
|
| 662 |
- endpointConfig.Aliases = append(endpointConfig.Aliases, shortID) |
|
| 663 |
- } |
|
| 664 |
- if container.Name != container.Config.Hostname {
|
|
| 665 |
- addHostname := true |
|
| 666 |
- for _, alias := range endpointConfig.Aliases {
|
|
| 667 |
- if alias == container.Config.Hostname {
|
|
| 668 |
- addHostname = false |
|
| 669 |
- break |
|
| 670 |
- } |
|
| 671 |
- } |
|
| 672 |
- if addHostname {
|
|
| 673 |
- endpointConfig.Aliases = append(endpointConfig.Aliases, container.Config.Hostname) |
|
| 674 |
- } |
|
| 675 |
- } |
|
| 653 |
+ endpointConfig.DNSNames = buildEndpointDNSNames(container, endpointConfig.Aliases) |
|
| 676 | 654 |
} |
| 677 | 655 |
|
| 678 | 656 |
if err := validateEndpointSettings(n, n.Name(), endpointConfig); err != nil {
|
| ... | ... |
@@ -687,6 +666,29 @@ func (daemon *Daemon) updateNetworkConfig(container *container.Container, n *lib |
| 687 | 687 |
return nil |
| 688 | 688 |
} |
| 689 | 689 |
|
| 690 |
+// buildEndpointDNSNames constructs the list of DNSNames that should be assigned to a given endpoint. The order within |
|
| 691 |
+// the returned slice is important as the first entry will be used to generate the PTR records (for IPv4 and v6) |
|
| 692 |
+// associated to this endpoint. |
|
| 693 |
+func buildEndpointDNSNames(ctr *container.Container, aliases []string) []string {
|
|
| 694 |
+ var dnsNames []string |
|
| 695 |
+ |
|
| 696 |
+ if ctr.Name != "" {
|
|
| 697 |
+ dnsNames = append(dnsNames, strings.TrimPrefix(ctr.Name, "/")) |
|
| 698 |
+ } |
|
| 699 |
+ |
|
| 700 |
+ dnsNames = append(dnsNames, aliases...) |
|
| 701 |
+ |
|
| 702 |
+ if ctr.ID != "" {
|
|
| 703 |
+ dnsNames = append(dnsNames, stringid.TruncateID(ctr.ID)) |
|
| 704 |
+ } |
|
| 705 |
+ |
|
| 706 |
+ if ctr.Config.Hostname != "" {
|
|
| 707 |
+ dnsNames = append(dnsNames, ctr.Config.Hostname) |
|
| 708 |
+ } |
|
| 709 |
+ |
|
| 710 |
+ return sliceutil.Dedup(dnsNames) |
|
| 711 |
+} |
|
| 712 |
+ |
|
| 690 | 713 |
func (daemon *Daemon) connectToNetwork(cfg *config.Config, container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (err error) {
|
| 691 | 714 |
start := time.Now() |
| 692 | 715 |
if container.HostConfig.NetworkMode.IsContainer() {
|
| 693 | 716 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,55 @@ |
| 0 |
+package daemon |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "encoding/json" |
|
| 4 |
+ "testing" |
|
| 5 |
+ |
|
| 6 |
+ containertypes "github.com/docker/docker/api/types/container" |
|
| 7 |
+ networktypes "github.com/docker/docker/api/types/network" |
|
| 8 |
+ "github.com/docker/docker/container" |
|
| 9 |
+ "github.com/docker/docker/libnetwork" |
|
| 10 |
+ "gotest.tools/v3/assert" |
|
| 11 |
+ is "gotest.tools/v3/assert/cmp" |
|
| 12 |
+) |
|
| 13 |
+ |
|
| 14 |
+func TestDNSNamesOrder(t *testing.T) {
|
|
| 15 |
+ d := &Daemon{}
|
|
| 16 |
+ ctr := &container.Container{
|
|
| 17 |
+ ID: "35de8003b19e27f636fc6ecbf4d7072558b872a8544f287fd69ad8182ad59023", |
|
| 18 |
+ Name: "foobar", |
|
| 19 |
+ Config: &containertypes.Config{
|
|
| 20 |
+ Hostname: "baz", |
|
| 21 |
+ }, |
|
| 22 |
+ } |
|
| 23 |
+ nw := buildNetwork(t, map[string]any{
|
|
| 24 |
+ "id": "1234567890", |
|
| 25 |
+ "name": "testnet", |
|
| 26 |
+ "networkType": "bridge", |
|
| 27 |
+ "enableIPv6": false, |
|
| 28 |
+ }) |
|
| 29 |
+ epSettings := &networktypes.EndpointSettings{
|
|
| 30 |
+ Aliases: []string{"myctr"},
|
|
| 31 |
+ } |
|
| 32 |
+ |
|
| 33 |
+ if err := d.updateNetworkConfig(ctr, nw, epSettings, false); err != nil {
|
|
| 34 |
+ t.Fatal(err) |
|
| 35 |
+ } |
|
| 36 |
+ |
|
| 37 |
+ assert.Check(t, is.DeepEqual(epSettings.DNSNames, []string{"foobar", "myctr", "35de8003b19e", "baz"}))
|
|
| 38 |
+} |
|
| 39 |
+ |
|
| 40 |
+func buildNetwork(t *testing.T, config map[string]any) *libnetwork.Network {
|
|
| 41 |
+ t.Helper() |
|
| 42 |
+ |
|
| 43 |
+ b, err := json.Marshal(config) |
|
| 44 |
+ if err != nil {
|
|
| 45 |
+ t.Fatal(err) |
|
| 46 |
+ } |
|
| 47 |
+ |
|
| 48 |
+ nw := &libnetwork.Network{}
|
|
| 49 |
+ if err := nw.UnmarshalJSON(b); err != nil {
|
|
| 50 |
+ t.Fatal(err) |
|
| 51 |
+ } |
|
| 52 |
+ |
|
| 53 |
+ return nw |
|
| 54 |
+} |
| ... | ... |
@@ -15,6 +15,8 @@ import ( |
| 15 | 15 |
"github.com/docker/docker/daemon/config" |
| 16 | 16 |
"github.com/docker/docker/daemon/network" |
| 17 | 17 |
"github.com/docker/docker/errdefs" |
| 18 |
+ "github.com/docker/docker/internal/sliceutil" |
|
| 19 |
+ "github.com/docker/docker/pkg/stringid" |
|
| 18 | 20 |
"github.com/docker/go-connections/nat" |
| 19 | 21 |
) |
| 20 | 22 |
|
| ... | ... |
@@ -27,6 +29,18 @@ func (daemon *Daemon) ContainerInspect(ctx context.Context, name string, size bo |
| 27 | 27 |
return daemon.containerInspectPre120(ctx, name) |
| 28 | 28 |
case versions.Equal(version, "1.20"): |
| 29 | 29 |
return daemon.containerInspect120(name) |
| 30 |
+ case versions.LessThan(version, "1.45"): |
|
| 31 |
+ ctr, err := daemon.ContainerInspectCurrent(ctx, name, size) |
|
| 32 |
+ if err != nil {
|
|
| 33 |
+ return nil, err |
|
| 34 |
+ } |
|
| 35 |
+ |
|
| 36 |
+ shortCID := stringid.TruncateID(ctr.ID) |
|
| 37 |
+ for _, ep := range ctr.NetworkSettings.Networks {
|
|
| 38 |
+ ep.Aliases = sliceutil.Dedup(append(ep.Aliases, shortCID, ctr.Config.Hostname)) |
|
| 39 |
+ } |
|
| 40 |
+ |
|
| 41 |
+ return ctr, nil |
|
| 30 | 42 |
default: |
| 31 | 43 |
return daemon.ContainerInspectCurrent(ctx, name, size) |
| 32 | 44 |
} |
| ... | ... |
@@ -793,10 +793,6 @@ func buildCreateEndpointOptions(c *container.Container, n *libnetwork.Network, e |
| 793 | 793 |
var genericOptions = make(options.Generic) |
| 794 | 794 |
|
| 795 | 795 |
nwName := n.Name() |
| 796 |
- defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName() |
|
| 797 |
- if c.NetworkSettings.IsAnonymousEndpoint || (nwName == defaultNetName && !serviceDiscoveryOnDefaultNetwork()) {
|
|
| 798 |
- createOptions = append(createOptions, libnetwork.CreateOptionAnonymous()) |
|
| 799 |
- } |
|
| 800 | 796 |
|
| 801 | 797 |
if epConfig != nil {
|
| 802 | 798 |
if ipam := epConfig.IPAMConfig; ipam != nil {
|
| ... | ... |
@@ -822,9 +818,8 @@ func buildCreateEndpointOptions(c *container.Container, n *libnetwork.Network, e |
| 822 | 822 |
createOptions = append(createOptions, libnetwork.CreateOptionIpam(ip, ip6, ipList, nil)) |
| 823 | 823 |
} |
| 824 | 824 |
|
| 825 |
- for _, alias := range epConfig.Aliases {
|
|
| 826 |
- createOptions = append(createOptions, libnetwork.CreateOptionMyAlias(alias)) |
|
| 827 |
- } |
|
| 825 |
+ createOptions = append(createOptions, libnetwork.CreateOptionDNSNames(epConfig.DNSNames)) |
|
| 826 |
+ |
|
| 828 | 827 |
for k, v := range epConfig.DriverOpts {
|
| 829 | 828 |
createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(options.Generic{k: v}))
|
| 830 | 829 |
} |
| ... | ... |
@@ -7,6 +7,7 @@ import ( |
| 7 | 7 |
"github.com/containerd/log" |
| 8 | 8 |
"github.com/docker/docker/api/types/events" |
| 9 | 9 |
dockercontainer "github.com/docker/docker/container" |
| 10 |
+ "github.com/docker/docker/daemon/network" |
|
| 10 | 11 |
"github.com/docker/docker/errdefs" |
| 11 | 12 |
"github.com/docker/docker/libnetwork" |
| 12 | 13 |
"github.com/pkg/errors" |
| ... | ... |
@@ -38,7 +39,6 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) (retErr error) {
|
| 38 | 38 |
defer container.Unlock() |
| 39 | 39 |
|
| 40 | 40 |
oldName = container.Name |
| 41 |
- oldIsAnonymousEndpoint := container.NetworkSettings.IsAnonymousEndpoint |
|
| 42 | 41 |
|
| 43 | 42 |
if oldName == newName {
|
| 44 | 43 |
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) {
|
| 62 | 62 |
} |
| 63 | 63 |
|
| 64 | 64 |
container.Name = newName |
| 65 |
- container.NetworkSettings.IsAnonymousEndpoint = false |
|
| 66 | 65 |
|
| 67 | 66 |
defer func() {
|
| 68 | 67 |
if retErr != nil {
|
| 69 | 68 |
container.Name = oldName |
| 70 |
- container.NetworkSettings.IsAnonymousEndpoint = oldIsAnonymousEndpoint |
|
| 71 | 69 |
daemon.reserveName(container.ID, oldName) |
| 72 | 70 |
for k, v := range links {
|
| 73 | 71 |
daemon.containersReplica.ReserveName(oldName+k, v.ID) |
| ... | ... |
@@ -101,7 +99,6 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) (retErr error) {
|
| 101 | 101 |
defer func() {
|
| 102 | 102 |
if retErr != nil {
|
| 103 | 103 |
container.Name = oldName |
| 104 |
- container.NetworkSettings.IsAnonymousEndpoint = oldIsAnonymousEndpoint |
|
| 105 | 104 |
if err := container.CheckpointTo(daemon.containersReplica); err != nil {
|
| 106 | 105 |
log.G(context.TODO()).WithFields(log.Fields{
|
| 107 | 106 |
"containerID": container.ID, |
| ... | ... |
@@ -118,10 +115,57 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) (retErr error) {
|
| 118 | 118 |
return err |
| 119 | 119 |
} |
| 120 | 120 |
|
| 121 |
- err = sb.Rename(strings.TrimPrefix(container.Name, "/")) |
|
| 122 |
- if err != nil {
|
|
| 121 |
+ if err := sb.Rename(newName[1:]); err != nil {
|
|
| 123 | 122 |
return err |
| 124 | 123 |
} |
| 124 |
+ defer func() {
|
|
| 125 |
+ if retErr != nil {
|
|
| 126 |
+ if err := sb.Rename(oldName); err != nil {
|
|
| 127 |
+ log.G(context.TODO()).WithFields(log.Fields{
|
|
| 128 |
+ "sandboxID": sid, |
|
| 129 |
+ "oldName": oldName, |
|
| 130 |
+ "newName": newName, |
|
| 131 |
+ "error": err, |
|
| 132 |
+ }).Errorf("failed to revert sandbox rename")
|
|
| 133 |
+ } |
|
| 134 |
+ } |
|
| 135 |
+ }() |
|
| 136 |
+ |
|
| 137 |
+ for nwName, epConfig := range container.NetworkSettings.Networks {
|
|
| 138 |
+ nw, err := daemon.FindNetwork(nwName) |
|
| 139 |
+ if err != nil {
|
|
| 140 |
+ return err |
|
| 141 |
+ } |
|
| 142 |
+ |
|
| 143 |
+ ep, err := nw.EndpointByID(epConfig.EndpointID) |
|
| 144 |
+ if err != nil {
|
|
| 145 |
+ return err |
|
| 146 |
+ } |
|
| 147 |
+ |
|
| 148 |
+ oldDNSNames := make([]string, len(epConfig.DNSNames)) |
|
| 149 |
+ copy(oldDNSNames, epConfig.DNSNames) |
|
| 150 |
+ |
|
| 151 |
+ epConfig.DNSNames = buildEndpointDNSNames(container, epConfig.Aliases) |
|
| 152 |
+ if err := ep.UpdateDNSNames(epConfig.DNSNames); err != nil {
|
|
| 153 |
+ return err |
|
| 154 |
+ } |
|
| 155 |
+ |
|
| 156 |
+ defer func(ep *libnetwork.Endpoint, epConfig *network.EndpointSettings, oldDNSNames []string) {
|
|
| 157 |
+ if retErr == nil {
|
|
| 158 |
+ return |
|
| 159 |
+ } |
|
| 160 |
+ |
|
| 161 |
+ epConfig.DNSNames = oldDNSNames |
|
| 162 |
+ if err := ep.UpdateDNSNames(epConfig.DNSNames); err != nil {
|
|
| 163 |
+ log.G(context.TODO()).WithFields(log.Fields{
|
|
| 164 |
+ "sandboxID": sid, |
|
| 165 |
+ "oldName": oldName, |
|
| 166 |
+ "newName": newName, |
|
| 167 |
+ "error": err, |
|
| 168 |
+ }).Errorf("failed to revert DNSNames update")
|
|
| 169 |
+ } |
|
| 170 |
+ }(ep, epConfig, oldDNSNames) |
|
| 171 |
+ } |
|
| 125 | 172 |
} |
| 126 | 173 |
|
| 127 | 174 |
daemon.LogContainerEventWithAttributes(container, events.ActionRename, attributes) |
| ... | ... |
@@ -68,6 +68,13 @@ keywords: "API, Docker, rcli, REST, documentation" |
| 68 | 68 |
* The `Container` and `ContainerConfig` fields in the `GET /images/{name}/json`
|
| 69 | 69 |
response are deprecated and will no longer be included in API v1.45. |
| 70 | 70 |
* `GET /info` now includes `status` properties in `Runtimes`. |
| 71 |
+* A new field named `DNSNames` and containing all non-fully qualified DNS names |
|
| 72 |
+ a container takes on a specific network has been added to `GET /containers/{name:.*}/json`.
|
|
| 73 |
+* The `Aliases` field returned in calls to `GET /containers/{name:.*}/json` in v1.44 and older
|
|
| 74 |
+ versions contains the short container ID. This will change in the next API version, v1.45. |
|
| 75 |
+ Starting with that API version, this specific value will be removed from the `Aliases` field |
|
| 76 |
+ such that this field will reflect exactly the values originally submitted to the |
|
| 77 |
+ `POST /containers/create` endpoint. The newly introduced `DNSNames` should now be used instead. |
|
| 71 | 78 |
|
| 72 | 79 |
## v1.43 API changes |
| 73 | 80 |
|
| ... | ... |
@@ -13,7 +13,8 @@ source hack/make/.integration-test-helpers |
| 13 | 13 |
# --deselect=tests/integration/api_container_test.py::AttachContainerTest::test_attach_no_stream |
| 14 | 14 |
# TODO re-enable test_attach_no_stream after https://github.com/docker/docker-py/issues/2513 is resolved |
| 15 | 15 |
# 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. |
| 16 |
-: "${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}"
|
|
| 16 |
+# TODO re-enable test_run_with_networking_config once this issue is fixed: https://github.com/moby/moby/pull/46853#issuecomment-1864679942. |
|
| 17 |
+: "${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}"
|
|
| 17 | 18 |
|
| 18 | 19 |
# build --squash is not supported with containerd integration. |
| 19 | 20 |
if [ -n "$TEST_INTEGRATION_USE_SNAPSHOTTER" ]; then |
| ... | ... |
@@ -5,6 +5,7 @@ import ( |
| 5 | 5 |
|
| 6 | 6 |
containertypes "github.com/docker/docker/api/types/container" |
| 7 | 7 |
"github.com/docker/docker/api/types/network" |
| 8 |
+ "github.com/docker/docker/client" |
|
| 8 | 9 |
"github.com/docker/docker/integration/internal/container" |
| 9 | 10 |
net "github.com/docker/docker/integration/internal/network" |
| 10 | 11 |
"github.com/docker/docker/integration/internal/swarm" |
| ... | ... |
@@ -13,13 +14,13 @@ import ( |
| 13 | 13 |
"gotest.tools/v3/skip" |
| 14 | 14 |
) |
| 15 | 15 |
|
| 16 |
-func TestDockerNetworkConnectAlias(t *testing.T) {
|
|
| 16 |
+func TestDockerNetworkConnectAliasPreV144(t *testing.T) {
|
|
| 17 | 17 |
skip.If(t, testEnv.DaemonInfo.OSType == "windows") |
| 18 | 18 |
ctx := setupTest(t) |
| 19 | 19 |
|
| 20 | 20 |
d := swarm.NewSwarm(ctx, t, testEnv) |
| 21 | 21 |
defer d.Stop(t) |
| 22 |
- client := d.NewClientT(t) |
|
| 22 |
+ client := d.NewClientT(t, client.WithVersion("1.43"))
|
|
| 23 | 23 |
defer client.Close() |
| 24 | 24 |
|
| 25 | 25 |
name := t.Name() + "test-alias" |
| 26 | 26 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,13 @@ |
| 0 |
+package sliceutil |
|
| 1 |
+ |
|
| 2 |
+func Dedup[T comparable](slice []T) []T {
|
|
| 3 |
+ keys := make(map[T]struct{})
|
|
| 4 |
+ out := make([]T, 0, len(slice)) |
|
| 5 |
+ for _, s := range slice {
|
|
| 6 |
+ if _, ok := keys[s]; !ok {
|
|
| 7 |
+ out = append(out, s) |
|
| 8 |
+ keys[s] = struct{}{}
|
|
| 9 |
+ } |
|
| 10 |
+ } |
|
| 11 |
+ return out |
|
| 12 |
+} |
| ... | ... |
@@ -598,7 +598,7 @@ func (ep *Endpoint) deleteDriverInfoFromCluster() error {
|
| 598 | 598 |
} |
| 599 | 599 |
|
| 600 | 600 |
func (ep *Endpoint) addServiceInfoToCluster(sb *Sandbox) error {
|
| 601 |
- if len(ep.myAliases) == 0 && ep.isAnonymous() || ep.Iface() == nil || ep.Iface().Address() == nil {
|
|
| 601 |
+ if len(ep.dnsNames) == 0 || ep.Iface() == nil || ep.Iface().Address() == nil {
|
|
| 602 | 602 |
return nil |
| 603 | 603 |
} |
| 604 | 604 |
|
| ... | ... |
@@ -628,10 +628,8 @@ func (ep *Endpoint) addServiceInfoToCluster(sb *Sandbox) error {
|
| 628 | 628 |
return nil |
| 629 | 629 |
} |
| 630 | 630 |
|
| 631 |
- name := ep.Name() |
|
| 632 |
- if ep.isAnonymous() {
|
|
| 633 |
- name = ep.MyAliases()[0] |
|
| 634 |
- } |
|
| 631 |
+ dnsNames := ep.getDNSNames() |
|
| 632 |
+ primaryDNSName, dnsAliases := dnsNames[0], dnsNames[1:] |
|
| 635 | 633 |
|
| 636 | 634 |
var ingressPorts []*PortConfig |
| 637 | 635 |
if ep.svcID != "" {
|
| ... | ... |
@@ -640,24 +638,24 @@ func (ep *Endpoint) addServiceInfoToCluster(sb *Sandbox) error {
|
| 640 | 640 |
if n.ingress {
|
| 641 | 641 |
ingressPorts = ep.ingressPorts |
| 642 | 642 |
} |
| 643 |
- 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 {
|
|
| 643 |
+ 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 {
|
|
| 644 | 644 |
return err |
| 645 | 645 |
} |
| 646 | 646 |
} else {
|
| 647 | 647 |
// This is a container simply attached to an attachable network |
| 648 |
- if err := n.getController().addContainerNameResolution(n.ID(), ep.ID(), name, ep.myAliases, ep.Iface().Address().IP, "addServiceInfoToCluster"); err != nil {
|
|
| 648 |
+ if err := n.getController().addContainerNameResolution(n.ID(), ep.ID(), primaryDNSName, dnsAliases, ep.Iface().Address().IP, "addServiceInfoToCluster"); err != nil {
|
|
| 649 | 649 |
return err |
| 650 | 650 |
} |
| 651 | 651 |
} |
| 652 | 652 |
|
| 653 | 653 |
buf, err := proto.Marshal(&EndpointRecord{
|
| 654 |
- Name: name, |
|
| 654 |
+ Name: primaryDNSName, |
|
| 655 | 655 |
ServiceName: ep.svcName, |
| 656 | 656 |
ServiceID: ep.svcID, |
| 657 | 657 |
VirtualIP: ep.virtualIP.String(), |
| 658 | 658 |
IngressPorts: ingressPorts, |
| 659 | 659 |
Aliases: ep.svcAliases, |
| 660 |
- TaskAliases: ep.myAliases, |
|
| 660 |
+ TaskAliases: dnsAliases, |
|
| 661 | 661 |
EndpointIP: ep.Iface().Address().IP.String(), |
| 662 | 662 |
ServiceDisabled: false, |
| 663 | 663 |
}) |
| ... | ... |
@@ -676,7 +674,7 @@ func (ep *Endpoint) addServiceInfoToCluster(sb *Sandbox) error {
|
| 676 | 676 |
} |
| 677 | 677 |
|
| 678 | 678 |
func (ep *Endpoint) deleteServiceInfoFromCluster(sb *Sandbox, fullRemove bool, method string) error {
|
| 679 |
- if len(ep.myAliases) == 0 && ep.isAnonymous() {
|
|
| 679 |
+ if len(ep.dnsNames) == 0 {
|
|
| 680 | 680 |
return nil |
| 681 | 681 |
} |
| 682 | 682 |
|
| ... | ... |
@@ -699,10 +697,8 @@ func (ep *Endpoint) deleteServiceInfoFromCluster(sb *Sandbox, fullRemove bool, m |
| 699 | 699 |
return nil |
| 700 | 700 |
} |
| 701 | 701 |
|
| 702 |
- name := ep.Name() |
|
| 703 |
- if ep.isAnonymous() {
|
|
| 704 |
- name = ep.MyAliases()[0] |
|
| 705 |
- } |
|
| 702 |
+ dnsNames := ep.getDNSNames() |
|
| 703 |
+ primaryDNSName, dnsAliases := dnsNames[0], dnsNames[1:] |
|
| 706 | 704 |
|
| 707 | 705 |
// First update the networkDB then locally |
| 708 | 706 |
if fullRemove {
|
| ... | ... |
@@ -720,12 +716,12 @@ func (ep *Endpoint) deleteServiceInfoFromCluster(sb *Sandbox, fullRemove bool, m |
| 720 | 720 |
if n.ingress {
|
| 721 | 721 |
ingressPorts = ep.ingressPorts |
| 722 | 722 |
} |
| 723 |
- 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 {
|
|
| 723 |
+ 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 {
|
|
| 724 | 724 |
return err |
| 725 | 725 |
} |
| 726 | 726 |
} else {
|
| 727 | 727 |
// This is a container simply attached to an attachable network |
| 728 |
- if err := n.getController().delContainerNameResolution(n.ID(), ep.ID(), name, ep.myAliases, ep.Iface().Address().IP, "deleteServiceInfoFromCluster"); err != nil {
|
|
| 728 |
+ if err := n.getController().delContainerNameResolution(n.ID(), ep.ID(), primaryDNSName, dnsAliases, ep.Iface().Address().IP, "deleteServiceInfoFromCluster"); err != nil {
|
|
| 729 | 729 |
return err |
| 730 | 730 |
} |
| 731 | 731 |
} |
| ... | ... |
@@ -8,6 +8,7 @@ import ( |
| 8 | 8 |
"sync" |
| 9 | 9 |
|
| 10 | 10 |
"github.com/containerd/log" |
| 11 |
+ "github.com/docker/docker/internal/sliceutil" |
|
| 11 | 12 |
"github.com/docker/docker/libnetwork/datastore" |
| 12 | 13 |
"github.com/docker/docker/libnetwork/ipamapi" |
| 13 | 14 |
"github.com/docker/docker/libnetwork/netlabel" |
| ... | ... |
@@ -23,21 +24,22 @@ type EndpointOption func(ep *Endpoint) |
| 23 | 23 |
|
| 24 | 24 |
// Endpoint represents a logical connection between a network and a sandbox. |
| 25 | 25 |
type Endpoint struct {
|
| 26 |
- name string |
|
| 27 |
- id string |
|
| 28 |
- network *Network |
|
| 29 |
- iface *EndpointInterface |
|
| 30 |
- joinInfo *endpointJoinInfo |
|
| 31 |
- sandboxID string |
|
| 32 |
- exposedPorts []types.TransportPort |
|
| 33 |
- anonymous bool |
|
| 26 |
+ name string |
|
| 27 |
+ id string |
|
| 28 |
+ network *Network |
|
| 29 |
+ iface *EndpointInterface |
|
| 30 |
+ joinInfo *endpointJoinInfo |
|
| 31 |
+ sandboxID string |
|
| 32 |
+ exposedPorts []types.TransportPort |
|
| 33 |
+ // dnsNames holds all the non-fully qualified DNS names associated to this endpoint. Order matters: first entry |
|
| 34 |
+ // will be used for the PTR records associated to the endpoint's IPv4 and IPv6 addresses. |
|
| 35 |
+ dnsNames []string |
|
| 34 | 36 |
disableResolution bool |
| 35 | 37 |
generic map[string]interface{}
|
| 36 | 38 |
prefAddress net.IP |
| 37 | 39 |
prefAddressV6 net.IP |
| 38 | 40 |
ipamOptions map[string]string |
| 39 | 41 |
aliases map[string]string |
| 40 |
- myAliases []string |
|
| 41 | 42 |
svcID string |
| 42 | 43 |
svcName string |
| 43 | 44 |
virtualIP net.IP |
| ... | ... |
@@ -64,9 +66,8 @@ func (ep *Endpoint) MarshalJSON() ([]byte, error) {
|
| 64 | 64 |
epMap["generic"] = ep.generic |
| 65 | 65 |
} |
| 66 | 66 |
epMap["sandbox"] = ep.sandboxID |
| 67 |
- epMap["anonymous"] = ep.anonymous |
|
| 67 |
+ epMap["dnsNames"] = ep.dnsNames |
|
| 68 | 68 |
epMap["disableResolution"] = ep.disableResolution |
| 69 |
- epMap["myAliases"] = ep.myAliases |
|
| 70 | 69 |
epMap["svcName"] = ep.svcName |
| 71 | 70 |
epMap["svcID"] = ep.svcID |
| 72 | 71 |
epMap["virtualIP"] = ep.virtualIP.String() |
| ... | ... |
@@ -156,8 +157,9 @@ func (ep *Endpoint) UnmarshalJSON(b []byte) (err error) {
|
| 156 | 156 |
} |
| 157 | 157 |
} |
| 158 | 158 |
|
| 159 |
+ var anonymous bool |
|
| 159 | 160 |
if v, ok := epMap["anonymous"]; ok {
|
| 160 |
- ep.anonymous = v.(bool) |
|
| 161 |
+ anonymous = v.(bool) |
|
| 161 | 162 |
} |
| 162 | 163 |
if v, ok := epMap["disableResolution"]; ok {
|
| 163 | 164 |
ep.disableResolution = v.(bool) |
| ... | ... |
@@ -192,7 +194,23 @@ func (ep *Endpoint) UnmarshalJSON(b []byte) (err error) {
|
| 192 | 192 |
ma, _ := json.Marshal(epMap["myAliases"]) |
| 193 | 193 |
var myAliases []string |
| 194 | 194 |
json.Unmarshal(ma, &myAliases) //nolint:errcheck |
| 195 |
- ep.myAliases = myAliases |
|
| 195 |
+ |
|
| 196 |
+ _, hasDNSNames := epMap["dnsNames"] |
|
| 197 |
+ dn, _ := json.Marshal(epMap["dnsNames"]) |
|
| 198 |
+ var dnsNames []string |
|
| 199 |
+ json.Unmarshal(dn, &dnsNames) |
|
| 200 |
+ ep.dnsNames = dnsNames |
|
| 201 |
+ |
|
| 202 |
+ // TODO(aker): remove this migration code in v27 |
|
| 203 |
+ if !hasDNSNames {
|
|
| 204 |
+ // The field dnsNames was introduced in v25.0. If we don't have it, the on-disk state was written by an older |
|
| 205 |
+ // daemon, thus we need to populate dnsNames based off of myAliases and anonymous values. |
|
| 206 |
+ if !anonymous {
|
|
| 207 |
+ myAliases = append([]string{ep.name}, myAliases...)
|
|
| 208 |
+ } |
|
| 209 |
+ ep.dnsNames = sliceutil.Dedup(myAliases) |
|
| 210 |
+ } |
|
| 211 |
+ |
|
| 196 | 212 |
return nil |
| 197 | 213 |
} |
| 198 | 214 |
|
| ... | ... |
@@ -210,7 +228,6 @@ func (ep *Endpoint) CopyTo(o datastore.KVObject) error {
|
| 210 | 210 |
dstEp.sandboxID = ep.sandboxID |
| 211 | 211 |
dstEp.dbIndex = ep.dbIndex |
| 212 | 212 |
dstEp.dbExists = ep.dbExists |
| 213 |
- dstEp.anonymous = ep.anonymous |
|
| 214 | 213 |
dstEp.disableResolution = ep.disableResolution |
| 215 | 214 |
dstEp.svcName = ep.svcName |
| 216 | 215 |
dstEp.svcID = ep.svcID |
| ... | ... |
@@ -240,8 +257,8 @@ func (ep *Endpoint) CopyTo(o datastore.KVObject) error {
|
| 240 | 240 |
dstEp.exposedPorts = make([]types.TransportPort, len(ep.exposedPorts)) |
| 241 | 241 |
copy(dstEp.exposedPorts, ep.exposedPorts) |
| 242 | 242 |
|
| 243 |
- dstEp.myAliases = make([]string, len(ep.myAliases)) |
|
| 244 |
- copy(dstEp.myAliases, ep.myAliases) |
|
| 243 |
+ dstEp.dnsNames = make([]string, len(ep.dnsNames)) |
|
| 244 |
+ copy(dstEp.dnsNames, ep.dnsNames) |
|
| 245 | 245 |
|
| 246 | 246 |
dstEp.generic = options.Generic{}
|
| 247 | 247 |
for k, v := range ep.generic {
|
| ... | ... |
@@ -267,13 +284,6 @@ func (ep *Endpoint) Name() string {
|
| 267 | 267 |
return ep.name |
| 268 | 268 |
} |
| 269 | 269 |
|
| 270 |
-func (ep *Endpoint) MyAliases() []string {
|
|
| 271 |
- ep.mu.Lock() |
|
| 272 |
- defer ep.mu.Unlock() |
|
| 273 |
- |
|
| 274 |
- return ep.myAliases |
|
| 275 |
-} |
|
| 276 |
- |
|
| 277 | 270 |
// Network returns the name of the network to which this endpoint is attached. |
| 278 | 271 |
func (ep *Endpoint) Network() string {
|
| 279 | 272 |
if ep.network == nil {
|
| ... | ... |
@@ -283,10 +293,15 @@ func (ep *Endpoint) Network() string {
|
| 283 | 283 |
return ep.network.name |
| 284 | 284 |
} |
| 285 | 285 |
|
| 286 |
-func (ep *Endpoint) isAnonymous() bool {
|
|
| 286 |
+// getDNSNames returns a copy of the DNS names associated to this endpoint. The first entry is the one used for PTR |
|
| 287 |
+// records. |
|
| 288 |
+func (ep *Endpoint) getDNSNames() []string {
|
|
| 287 | 289 |
ep.mu.Lock() |
| 288 | 290 |
defer ep.mu.Unlock() |
| 289 |
- return ep.anonymous |
|
| 291 |
+ |
|
| 292 |
+ dnsNames := make([]string, len(ep.dnsNames)) |
|
| 293 |
+ copy(dnsNames, ep.dnsNames) |
|
| 294 |
+ return dnsNames |
|
| 290 | 295 |
} |
| 291 | 296 |
|
| 292 | 297 |
// isServiceEnabled check if service is enabled on the endpoint |
| ... | ... |
@@ -568,71 +583,52 @@ func (ep *Endpoint) sbJoin(sb *Sandbox, options ...EndpointOption) (err error) {
|
| 568 | 568 |
} |
| 569 | 569 |
|
| 570 | 570 |
func (ep *Endpoint) rename(name string) error {
|
| 571 |
- var ( |
|
| 572 |
- err error |
|
| 573 |
- ok bool |
|
| 574 |
- ) |
|
| 571 |
+ ep.mu.Lock() |
|
| 572 |
+ ep.name = name |
|
| 573 |
+ ep.mu.Unlock() |
|
| 575 | 574 |
|
| 576 |
- n := ep.getNetwork() |
|
| 577 |
- if n == nil {
|
|
| 578 |
- return fmt.Errorf("network not connected for ep %q", ep.name)
|
|
| 575 |
+ // Update the store with the updated name |
|
| 576 |
+ if err := ep.getNetwork().getController().updateToStore(ep); err != nil {
|
|
| 577 |
+ return err |
|
| 579 | 578 |
} |
| 580 | 579 |
|
| 581 |
- c := n.getController() |
|
| 580 |
+ return nil |
|
| 581 |
+} |
|
| 582 | 582 |
|
| 583 |
+func (ep *Endpoint) UpdateDNSNames(dnsNames []string) error {
|
|
| 584 |
+ nw := ep.getNetwork() |
|
| 585 |
+ c := nw.getController() |
|
| 583 | 586 |
sb, ok := ep.getSandbox() |
| 584 | 587 |
if !ok {
|
| 585 |
- log.G(context.TODO()).Warnf("rename for %s aborted, sandbox %s is not anymore present", ep.ID(), ep.sandboxID)
|
|
| 588 |
+ log.G(context.TODO()).WithFields(log.Fields{
|
|
| 589 |
+ "sandboxID": ep.sandboxID, |
|
| 590 |
+ "endpointID": ep.ID(), |
|
| 591 |
+ }).Warn("DNSNames update aborted, sandbox is not present anymore")
|
|
| 586 | 592 |
return nil |
| 587 | 593 |
} |
| 588 | 594 |
|
| 589 | 595 |
if c.isAgent() {
|
| 590 |
- if err = ep.deleteServiceInfoFromCluster(sb, true, "rename"); err != nil {
|
|
| 591 |
- return types.InternalErrorf("Could not delete service state for endpoint %s from cluster on rename: %v", ep.Name(), err)
|
|
| 596 |
+ if err := ep.deleteServiceInfoFromCluster(sb, true, "UpdateDNSNames"); err != nil {
|
|
| 597 |
+ return types.InternalErrorf("could not delete service state for endpoint %s from cluster on UpdateDNSNames: %v", ep.Name(), err)
|
|
| 592 | 598 |
} |
| 593 |
- } else {
|
|
| 594 |
- n.updateSvcRecord(ep, false) |
|
| 595 |
- } |
|
| 596 |
- |
|
| 597 |
- oldName := ep.name |
|
| 598 |
- oldAnonymous := ep.anonymous |
|
| 599 |
- ep.name = name |
|
| 600 |
- ep.anonymous = false |
|
| 601 | 599 |
|
| 602 |
- if c.isAgent() {
|
|
| 603 |
- if err = ep.addServiceInfoToCluster(sb); err != nil {
|
|
| 604 |
- return types.InternalErrorf("Could not add service state for endpoint %s to cluster on rename: %v", ep.Name(), err)
|
|
| 600 |
+ ep.dnsNames = dnsNames |
|
| 601 |
+ if err := ep.addServiceInfoToCluster(sb); err != nil {
|
|
| 602 |
+ return types.InternalErrorf("could not add service state for endpoint %s to cluster on UpdateDNSNames: %v", ep.Name(), err)
|
|
| 605 | 603 |
} |
| 606 |
- defer func() {
|
|
| 607 |
- if err != nil {
|
|
| 608 |
- if err2 := ep.deleteServiceInfoFromCluster(sb, true, "rename"); err2 != nil {
|
|
| 609 |
- 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")
|
|
| 610 |
- } |
|
| 611 |
- ep.name = oldName |
|
| 612 |
- ep.anonymous = oldAnonymous |
|
| 613 |
- if err2 := ep.addServiceInfoToCluster(sb); err2 != nil {
|
|
| 614 |
- 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")
|
|
| 615 |
- } |
|
| 616 |
- } |
|
| 617 |
- }() |
|
| 618 | 604 |
} else {
|
| 619 |
- n.updateSvcRecord(ep, true) |
|
| 620 |
- defer func() {
|
|
| 621 |
- if err != nil {
|
|
| 622 |
- n.updateSvcRecord(ep, false) |
|
| 623 |
- ep.name = oldName |
|
| 624 |
- ep.anonymous = oldAnonymous |
|
| 625 |
- n.updateSvcRecord(ep, true) |
|
| 626 |
- } |
|
| 627 |
- }() |
|
| 605 |
+ nw.updateSvcRecord(ep, false) |
|
| 606 |
+ |
|
| 607 |
+ ep.dnsNames = dnsNames |
|
| 608 |
+ nw.updateSvcRecord(ep, true) |
|
| 628 | 609 |
} |
| 629 | 610 |
|
| 630 | 611 |
// Update the store with the updated name |
| 631 |
- if err = c.updateToStore(ep); err != nil {
|
|
| 612 |
+ if err := c.updateToStore(ep); err != nil {
|
|
| 632 | 613 |
return err |
| 633 | 614 |
} |
| 634 | 615 |
|
| 635 |
- return err |
|
| 616 |
+ return nil |
|
| 636 | 617 |
} |
| 637 | 618 |
|
| 638 | 619 |
func (ep *Endpoint) hasInterface(iName string) bool {
|
| ... | ... |
@@ -951,11 +947,11 @@ func CreateOptionDNS(dns []string) EndpointOption {
|
| 951 | 951 |
} |
| 952 | 952 |
} |
| 953 | 953 |
|
| 954 |
-// CreateOptionAnonymous function returns an option setter for setting |
|
| 955 |
-// this endpoint as anonymous |
|
| 956 |
-func CreateOptionAnonymous() EndpointOption {
|
|
| 954 |
+// CreateOptionDNSNames specifies the list of (non fully qualified) DNS names associated to an endpoint. These will be |
|
| 955 |
+// used to populate the embedded DNS server. Order matters: first name will be used to generate PTR records. |
|
| 956 |
+func CreateOptionDNSNames(names []string) EndpointOption {
|
|
| 957 | 957 |
return func(ep *Endpoint) {
|
| 958 |
- ep.anonymous = true |
|
| 958 |
+ ep.dnsNames = names |
|
| 959 | 959 |
} |
| 960 | 960 |
} |
| 961 | 961 |
|
| ... | ... |
@@ -988,13 +984,6 @@ func CreateOptionService(name, id string, vip net.IP, ingressPorts []*PortConfig |
| 988 | 988 |
} |
| 989 | 989 |
} |
| 990 | 990 |
|
| 991 |
-// CreateOptionMyAlias function returns an option setter for setting endpoint's self alias |
|
| 992 |
-func CreateOptionMyAlias(alias string) EndpointOption {
|
|
| 993 |
- return func(ep *Endpoint) {
|
|
| 994 |
- ep.myAliases = append(ep.myAliases, alias) |
|
| 995 |
- } |
|
| 996 |
-} |
|
| 997 |
- |
|
| 998 | 991 |
// CreateOptionLoadBalancer function returns an option setter for denoting the endpoint is a load balancer for a network |
| 999 | 992 |
func CreateOptionLoadBalancer() EndpointOption {
|
| 1000 | 993 |
return func(ep *Endpoint) {
|
| ... | ... |
@@ -5,6 +5,7 @@ import ( |
| 5 | 5 |
"encoding/json" |
| 6 | 6 |
"fmt" |
| 7 | 7 |
"net" |
| 8 |
+ "reflect" |
|
| 8 | 9 |
"runtime" |
| 9 | 10 |
"testing" |
| 10 | 11 |
"time" |
| ... | ... |
@@ -191,7 +192,6 @@ func TestEndpointMarshalling(t *testing.T) {
|
| 191 | 191 |
name: "Bau", |
| 192 | 192 |
id: "efghijklmno", |
| 193 | 193 |
sandboxID: "ambarabaciccicocco", |
| 194 |
- anonymous: true, |
|
| 195 | 194 |
iface: &EndpointInterface{
|
| 196 | 195 |
mac: []byte{11, 12, 13, 14, 15, 16},
|
| 197 | 196 |
addr: &net.IPNet{
|
| ... | ... |
@@ -205,6 +205,7 @@ func TestEndpointMarshalling(t *testing.T) {
|
| 205 | 205 |
v6PoolID: "poolv6", |
| 206 | 206 |
llAddrs: lla, |
| 207 | 207 |
}, |
| 208 |
+ dnsNames: []string{"test", "foobar", "baz"},
|
|
| 208 | 209 |
} |
| 209 | 210 |
|
| 210 | 211 |
b, err := json.Marshal(e) |
| ... | ... |
@@ -218,7 +219,7 @@ func TestEndpointMarshalling(t *testing.T) {
|
| 218 | 218 |
t.Fatal(err) |
| 219 | 219 |
} |
| 220 | 220 |
|
| 221 |
- if e.name != ee.name || e.id != ee.id || e.sandboxID != ee.sandboxID || !compareEndpointInterface(e.iface, ee.iface) || e.anonymous != ee.anonymous {
|
|
| 221 |
+ if e.name != ee.name || e.id != ee.id || e.sandboxID != ee.sandboxID || !reflect.DeepEqual(e.dnsNames, ee.dnsNames) || !compareEndpointInterface(e.iface, ee.iface) {
|
|
| 222 | 222 |
t.Fatalf("JSON marsh/unmarsh failed.\nOriginal:\n%#v\nDecoded:\n%#v\nOriginal iface: %#v\nDecodediface:\n%#v", e, ee, e.iface, ee.iface)
|
| 223 | 223 |
} |
| 224 | 224 |
} |
| ... | ... |
@@ -175,7 +175,7 @@ func (i *IpamInfo) UnmarshalJSON(data []byte) error {
|
| 175 | 175 |
type Network struct {
|
| 176 | 176 |
ctrlr *Controller |
| 177 | 177 |
name string |
| 178 |
- networkType string |
|
| 178 |
+ networkType string // networkType is the name of the netdriver used by this network |
|
| 179 | 179 |
id string |
| 180 | 180 |
created time.Time |
| 181 | 181 |
scope string // network data scope |
| ... | ... |
@@ -1302,8 +1302,6 @@ func (n *Network) updateSvcRecord(ep *Endpoint, isAdd bool) {
|
| 1302 | 1302 |
} |
| 1303 | 1303 |
|
| 1304 | 1304 |
var ipv6 net.IP |
| 1305 |
- epName := ep.Name() |
|
| 1306 |
- myAliases := ep.MyAliases() |
|
| 1307 | 1305 |
if iface.AddressIPv6() != nil {
|
| 1308 | 1306 |
ipv6 = iface.AddressIPv6().IP |
| 1309 | 1307 |
} |
| ... | ... |
@@ -1312,30 +1310,17 @@ func (n *Network) updateSvcRecord(ep *Endpoint, isAdd bool) {
|
| 1312 | 1312 |
if serviceID == "" {
|
| 1313 | 1313 |
serviceID = ep.ID() |
| 1314 | 1314 |
} |
| 1315 |
+ |
|
| 1316 |
+ dnsNames := ep.getDNSNames() |
|
| 1315 | 1317 |
if isAdd {
|
| 1316 |
- // If anonymous endpoint has an alias use the first alias |
|
| 1317 |
- // for ip->name mapping. Not having the reverse mapping |
|
| 1318 |
- // breaks some apps |
|
| 1319 |
- if ep.isAnonymous() {
|
|
| 1320 |
- if len(myAliases) > 0 {
|
|
| 1321 |
- n.addSvcRecords(ep.ID(), myAliases[0], serviceID, iface.Address().IP, ipv6, true, "updateSvcRecord") |
|
| 1322 |
- } |
|
| 1323 |
- } else {
|
|
| 1324 |
- n.addSvcRecords(ep.ID(), epName, serviceID, iface.Address().IP, ipv6, true, "updateSvcRecord") |
|
| 1325 |
- } |
|
| 1326 |
- for _, alias := range myAliases {
|
|
| 1327 |
- n.addSvcRecords(ep.ID(), alias, serviceID, iface.Address().IP, ipv6, false, "updateSvcRecord") |
|
| 1318 |
+ for i, dnsName := range dnsNames {
|
|
| 1319 |
+ ipMapUpdate := i == 0 // ipMapUpdate indicates whether PTR records should be updated. |
|
| 1320 |
+ n.addSvcRecords(ep.ID(), dnsName, serviceID, iface.Address().IP, ipv6, ipMapUpdate, "updateSvcRecord") |
|
| 1328 | 1321 |
} |
| 1329 | 1322 |
} else {
|
| 1330 |
- if ep.isAnonymous() {
|
|
| 1331 |
- if len(myAliases) > 0 {
|
|
| 1332 |
- n.deleteSvcRecords(ep.ID(), myAliases[0], serviceID, iface.Address().IP, ipv6, true, "updateSvcRecord") |
|
| 1333 |
- } |
|
| 1334 |
- } else {
|
|
| 1335 |
- n.deleteSvcRecords(ep.ID(), epName, serviceID, iface.Address().IP, ipv6, true, "updateSvcRecord") |
|
| 1336 |
- } |
|
| 1337 |
- for _, alias := range myAliases {
|
|
| 1338 |
- n.deleteSvcRecords(ep.ID(), alias, serviceID, iface.Address().IP, ipv6, false, "updateSvcRecord") |
|
| 1323 |
+ for i, dnsName := range dnsNames {
|
|
| 1324 |
+ ipMapUpdate := i == 0 // ipMapUpdate indicates whether PTR records should be updated. |
|
| 1325 |
+ n.deleteSvcRecords(ep.ID(), dnsName, serviceID, iface.Address().IP, ipv6, ipMapUpdate, "updateSvcRecord") |
|
| 1339 | 1326 |
} |
| 1340 | 1327 |
} |
| 1341 | 1328 |
} |
| ... | ... |
@@ -1374,6 +1359,7 @@ func delNameToIP(svcMap *setmatrix.SetMatrix[svcMapEntry], name, serviceID strin |
| 1374 | 1374 |
}) |
| 1375 | 1375 |
} |
| 1376 | 1376 |
|
| 1377 |
+// TODO(aker): remove ipMapUpdate param and add a proper method dedicated to update PTR records. |
|
| 1377 | 1378 |
func (n *Network) addSvcRecords(eID, name, serviceID string, epIP, epIPv6 net.IP, ipMapUpdate bool, method string) {
|
| 1378 | 1379 |
// Do not add service names for ingress network as this is a |
| 1379 | 1380 |
// routing only network |
| ... | ... |
@@ -2176,10 +2162,6 @@ func (n *Network) createLoadBalancerSandbox() (retErr error) {
|
| 2176 | 2176 |
CreateOptionIpam(n.loadBalancerIP, nil, nil, nil), |
| 2177 | 2177 |
CreateOptionLoadBalancer(), |
| 2178 | 2178 |
} |
| 2179 |
- if n.hasLoadBalancerEndpoint() && !n.ingress {
|
|
| 2180 |
- // Mark LB endpoints as anonymous so they don't show up in DNS |
|
| 2181 |
- epOptions = append(epOptions, CreateOptionAnonymous()) |
|
| 2182 |
- } |
|
| 2183 | 2179 |
ep, err := n.createEndpoint(endpointName, epOptions...) |
| 2184 | 2180 |
if err != nil {
|
| 2185 | 2181 |
return err |