libnet: Endpoint: remove isAnonymous & myAliases
**- What I did**

The `Endpoint` struct was containing two confusing fields:

1. `isAnonymous`: was set on endpoints which name shouldn't be taken into account when inserting DNS records into libnetwork's `Controller.svcRecords` (and into the NetworkDB). However, in that case the endpoint's aliases would still be used to create DNS records; thus, making those "anonymous endpoints" not so anonymous.
2. `myAliases`: there's also an `aliases` field in the `Endpoint` struct. `myAliases` was storing extra DNS names for the endpoint, while `aliases` stores extra DNS names for _other_ endpoints (but those extra DNS names are only accessible for the endpoint storing them -- yeah, it's confusing too).

To make it worse, the code that built the list of DNS names for a given endpoint was split in two:

1. `updateNetworkConfig` (in the `daemon` pkg) was adding the endpoint short ID and hostname to the list of aliases ;
2. In libnetwork, to handle "anonymous" endpoints as described above.

This PR replaces both fields with a new `DNSNames` containing _all_ (non-fully qualified) DNS names for a given endpoint. It's now built by the daemon during `updateNetworkConfig` and reimplements the same logic for aliases as before (a test has been added to make sure of that). An "anonymous" endpoint is now an endpoint with no `DNSNames`.

This new field is also stored in the "operational data" (ie. state) of the `EndpointSettings` struct exposed by the API via `GET /containers/{name:.*}/json`, making it easier for end-users and scripts to know every DNS names a container has on a specific network.

**- How to verify it**

`docker run --network testnet` with a variety of:

* `--name` ;
* `--hostname` ;
* `--network-alias` ;

**- A picture of a cute animal (not mandatory but encouraged)**

![](https://www.nhm.ac.uk/resources/visit/wpy/2018/large/webp/14.webp)

daemon/rename.go
package daemon // import "github.com/docker/docker/daemon"

import (
	"context"
	"strings"

	"github.com/containerd/log"
	"github.com/docker/docker/api/types/events"
	dockercontainer "github.com/docker/docker/container"
	"github.com/docker/docker/errdefs"
	"github.com/docker/docker/libnetwork"
	"github.com/pkg/errors"
)

// ContainerRename changes the name of a container, using the oldName
// to find the container. An error is returned if newName is already
// reserved.
func (daemon *Daemon) ContainerRename(oldName, newName string) (retErr error) {
	var (
		sid string
		sb  *libnetwork.Sandbox
	)

	if oldName == "" || newName == "" {
		return errdefs.InvalidParameter(errors.New("Neither old nor new names may be empty"))
	}

	if newName[0] != '/' {
		newName = "/" + newName
	}

	container, err := daemon.GetContainer(oldName)
	if err != nil {
		return err
	}

	container.Lock()
	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"))
	}

	links := map[string]*dockercontainer.Container{}
	for k, v := range daemon.linkIndex.children(container) {
		if !strings.HasPrefix(k, oldName) {
			return errdefs.InvalidParameter(errors.Errorf("Linked container %s does not match parent %s", k, oldName))
		}
		links[strings.TrimPrefix(k, oldName)] = v
	}

	if newName, err = daemon.reserveName(container.ID, newName); err != nil {
		return errors.Wrap(err, "Error when allocating new name")
	}

	for k, v := range links {
		daemon.containersReplica.ReserveName(newName+k, v.ID)
		daemon.linkIndex.link(container, v, newName+k)
	}

	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)
				daemon.linkIndex.link(container, v, oldName+k)
				daemon.linkIndex.unlink(newName+k, v, container)
				daemon.containersReplica.ReleaseName(newName + k)
			}
			daemon.releaseName(newName)
		} else {
			daemon.releaseName(oldName)
		}
	}()

	for k, v := range links {
		daemon.linkIndex.unlink(oldName+k, v, container)
		daemon.containersReplica.ReleaseName(oldName + k)
	}
	if err = container.CheckpointTo(daemon.containersReplica); err != nil {
		return err
	}

	attributes := map[string]string{
		"oldName": oldName,
	}

	if !container.Running {
		daemon.LogContainerEventWithAttributes(container, events.ActionRename, attributes)
		return nil
	}

	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,
					"error":       err,
				}).Error("failed to write container state to disk during rename")
			}
		}
	}()

	sid = container.NetworkSettings.SandboxID
	if sid != "" && daemon.netController != nil {
		sb, err = daemon.netController.SandboxByID(sid)
		if err != nil {
			return err
		}

		err = sb.Rename(strings.TrimPrefix(container.Name, "/"))
		if err != nil {
			return err
		}
	}

	daemon.LogContainerEventWithAttributes(container, events.ActionRename, attributes)
	return nil
}

package daemon // import "github.com/docker/docker/daemon"

import (
	"context"
	"strings"

	"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"
)

// ContainerRename changes the name of a container, using the oldName
// to find the container. An error is returned if newName is already
// reserved.
func (daemon *Daemon) ContainerRename(oldName, newName string) (retErr error) {
	var (
		sid string
		sb  *libnetwork.Sandbox
	)

	if oldName == "" || newName == "" {
		return errdefs.InvalidParameter(errors.New("Neither old nor new names may be empty"))
	}

	if newName[0] != '/' {
		newName = "/" + newName
	}

	container, err := daemon.GetContainer(oldName)
	if err != nil {
		return err
	}

	container.Lock()
	defer container.Unlock()

	oldName = container.Name

	if oldName == newName {
		return errdefs.InvalidParameter(errors.New("Renaming a container with the same name as its current name"))
	}

	links := map[string]*dockercontainer.Container{}
	for k, v := range daemon.linkIndex.children(container) {
		if !strings.HasPrefix(k, oldName) {
			return errdefs.InvalidParameter(errors.Errorf("Linked container %s does not match parent %s", k, oldName))
		}
		links[strings.TrimPrefix(k, oldName)] = v
	}

	if newName, err = daemon.reserveName(container.ID, newName); err != nil {
		return errors.Wrap(err, "Error when allocating new name")
	}

	for k, v := range links {
		daemon.containersReplica.ReserveName(newName+k, v.ID)
		daemon.linkIndex.link(container, v, newName+k)
	}

	container.Name = newName

	defer func() {
		if retErr != nil {
			container.Name = oldName
			daemon.reserveName(container.ID, oldName)
			for k, v := range links {
				daemon.containersReplica.ReserveName(oldName+k, v.ID)
				daemon.linkIndex.link(container, v, oldName+k)
				daemon.linkIndex.unlink(newName+k, v, container)
				daemon.containersReplica.ReleaseName(newName + k)
			}
			daemon.releaseName(newName)
		} else {
			daemon.releaseName(oldName)
		}
	}()

	for k, v := range links {
		daemon.linkIndex.unlink(oldName+k, v, container)
		daemon.containersReplica.ReleaseName(oldName + k)
	}
	if err = container.CheckpointTo(daemon.containersReplica); err != nil {
		return err
	}

	attributes := map[string]string{
		"oldName": oldName,
	}

	if !container.Running {
		daemon.LogContainerEventWithAttributes(container, events.ActionRename, attributes)
		return nil
	}

	defer func() {
		if retErr != nil {
			container.Name = oldName
			if err := container.CheckpointTo(daemon.containersReplica); err != nil {
				log.G(context.TODO()).WithFields(log.Fields{
					"containerID": container.ID,
					"error":       err,
				}).Error("failed to write container state to disk during rename")
			}
		}
	}()

	sid = container.NetworkSettings.SandboxID
	if sid != "" && daemon.netController != nil {
		sb, err = daemon.netController.SandboxByID(sid)
		if err != nil {
			return err
		}

		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)
	return nil
}

FYI: `type` statements are permitted in function scope. You don't need to write out the full struct definition multiple times or pollute the package-scope namespace.