gopkg.in/docker/docker.v20@v20.10.27/daemon/container_operations.go (about)

     1  package daemon // import "github.com/docker/docker/daemon"
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net"
     7  	"os"
     8  	"path"
     9  	"strings"
    10  	"time"
    11  
    12  	containertypes "github.com/docker/docker/api/types/container"
    13  	networktypes "github.com/docker/docker/api/types/network"
    14  	"github.com/docker/docker/container"
    15  	"github.com/docker/docker/daemon/network"
    16  	"github.com/docker/docker/errdefs"
    17  	"github.com/docker/docker/opts"
    18  	"github.com/docker/docker/pkg/stringid"
    19  	"github.com/docker/docker/runconfig"
    20  	"github.com/docker/go-connections/nat"
    21  	"github.com/docker/libnetwork"
    22  	netconst "github.com/docker/libnetwork/datastore"
    23  	"github.com/docker/libnetwork/netlabel"
    24  	"github.com/docker/libnetwork/options"
    25  	"github.com/docker/libnetwork/types"
    26  	"github.com/sirupsen/logrus"
    27  )
    28  
    29  var (
    30  	// ErrRootFSReadOnly is returned when a container
    31  	// rootfs is marked readonly.
    32  	ErrRootFSReadOnly = errors.New("container rootfs is marked read-only")
    33  	getPortMapInfo    = getSandboxPortMapInfo
    34  )
    35  
    36  func (daemon *Daemon) getDNSSearchSettings(container *container.Container) []string {
    37  	if len(container.HostConfig.DNSSearch) > 0 {
    38  		return container.HostConfig.DNSSearch
    39  	}
    40  
    41  	if len(daemon.configStore.DNSSearch) > 0 {
    42  		return daemon.configStore.DNSSearch
    43  	}
    44  
    45  	return nil
    46  }
    47  
    48  func (daemon *Daemon) buildSandboxOptions(container *container.Container) ([]libnetwork.SandboxOption, error) {
    49  	var (
    50  		sboxOptions []libnetwork.SandboxOption
    51  		err         error
    52  		dns         []string
    53  		dnsOptions  []string
    54  		bindings    = make(nat.PortMap)
    55  		pbList      []types.PortBinding
    56  		exposeList  []types.TransportPort
    57  	)
    58  
    59  	defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
    60  	sboxOptions = append(sboxOptions, libnetwork.OptionHostname(container.Config.Hostname),
    61  		libnetwork.OptionDomainname(container.Config.Domainname))
    62  
    63  	if container.HostConfig.NetworkMode.IsHost() {
    64  		sboxOptions = append(sboxOptions, libnetwork.OptionUseDefaultSandbox())
    65  	} else {
    66  		// OptionUseExternalKey is mandatory for userns support.
    67  		// But optional for non-userns support
    68  		sboxOptions = append(sboxOptions, libnetwork.OptionUseExternalKey())
    69  	}
    70  
    71  	if err = daemon.setupPathsAndSandboxOptions(container, &sboxOptions); err != nil {
    72  		return nil, err
    73  	}
    74  
    75  	if len(container.HostConfig.DNS) > 0 {
    76  		dns = container.HostConfig.DNS
    77  	} else if len(daemon.configStore.DNS) > 0 {
    78  		dns = daemon.configStore.DNS
    79  	}
    80  
    81  	for _, d := range dns {
    82  		sboxOptions = append(sboxOptions, libnetwork.OptionDNS(d))
    83  	}
    84  
    85  	dnsSearch := daemon.getDNSSearchSettings(container)
    86  
    87  	for _, ds := range dnsSearch {
    88  		sboxOptions = append(sboxOptions, libnetwork.OptionDNSSearch(ds))
    89  	}
    90  
    91  	if len(container.HostConfig.DNSOptions) > 0 {
    92  		dnsOptions = container.HostConfig.DNSOptions
    93  	} else if len(daemon.configStore.DNSOptions) > 0 {
    94  		dnsOptions = daemon.configStore.DNSOptions
    95  	}
    96  
    97  	for _, ds := range dnsOptions {
    98  		sboxOptions = append(sboxOptions, libnetwork.OptionDNSOptions(ds))
    99  	}
   100  
   101  	if container.NetworkSettings.SecondaryIPAddresses != nil {
   102  		name := container.Config.Hostname
   103  		if container.Config.Domainname != "" {
   104  			name = name + "." + container.Config.Domainname
   105  		}
   106  
   107  		for _, a := range container.NetworkSettings.SecondaryIPAddresses {
   108  			sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(name, a.Addr))
   109  		}
   110  	}
   111  
   112  	for _, extraHost := range container.HostConfig.ExtraHosts {
   113  		// allow IPv6 addresses in extra hosts; only split on first ":"
   114  		if _, err := opts.ValidateExtraHost(extraHost); err != nil {
   115  			return nil, err
   116  		}
   117  		parts := strings.SplitN(extraHost, ":", 2)
   118  		// If the IP Address is a string called "host-gateway", replace this
   119  		// value with the IP address stored in the daemon level HostGatewayIP
   120  		// config variable
   121  		if parts[1] == opts.HostGatewayName {
   122  			gateway := daemon.configStore.HostGatewayIP.String()
   123  			if gateway == "" {
   124  				return nil, fmt.Errorf("unable to derive the IP value for host-gateway")
   125  			}
   126  			parts[1] = gateway
   127  		}
   128  		sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(parts[0], parts[1]))
   129  	}
   130  
   131  	if container.HostConfig.PortBindings != nil {
   132  		for p, b := range container.HostConfig.PortBindings {
   133  			bindings[p] = []nat.PortBinding{}
   134  			for _, bb := range b {
   135  				bindings[p] = append(bindings[p], nat.PortBinding{
   136  					HostIP:   bb.HostIP,
   137  					HostPort: bb.HostPort,
   138  				})
   139  			}
   140  		}
   141  	}
   142  
   143  	portSpecs := container.Config.ExposedPorts
   144  	ports := make([]nat.Port, len(portSpecs))
   145  	var i int
   146  	for p := range portSpecs {
   147  		ports[i] = p
   148  		i++
   149  	}
   150  	nat.SortPortMap(ports, bindings)
   151  	for _, port := range ports {
   152  		expose := types.TransportPort{}
   153  		expose.Proto = types.ParseProtocol(port.Proto())
   154  		expose.Port = uint16(port.Int())
   155  		exposeList = append(exposeList, expose)
   156  
   157  		pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto}
   158  		binding := bindings[port]
   159  		for i := 0; i < len(binding); i++ {
   160  			pbCopy := pb.GetCopy()
   161  			newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort))
   162  			var portStart, portEnd int
   163  			if err == nil {
   164  				portStart, portEnd, err = newP.Range()
   165  			}
   166  			if err != nil {
   167  				return nil, fmt.Errorf("Error parsing HostPort value(%s):%v", binding[i].HostPort, err)
   168  			}
   169  			pbCopy.HostPort = uint16(portStart)
   170  			pbCopy.HostPortEnd = uint16(portEnd)
   171  			pbCopy.HostIP = net.ParseIP(binding[i].HostIP)
   172  			pbList = append(pbList, pbCopy)
   173  		}
   174  
   175  		if container.HostConfig.PublishAllPorts && len(binding) == 0 {
   176  			pbList = append(pbList, pb)
   177  		}
   178  	}
   179  
   180  	sboxOptions = append(sboxOptions,
   181  		libnetwork.OptionPortMapping(pbList),
   182  		libnetwork.OptionExposedPorts(exposeList))
   183  
   184  	// Legacy Link feature is supported only for the default bridge network.
   185  	// return if this call to build join options is not for default bridge network
   186  	// Legacy Link is only supported by docker run --link
   187  	bridgeSettings, ok := container.NetworkSettings.Networks[defaultNetName]
   188  	if !ok || bridgeSettings.EndpointSettings == nil {
   189  		return sboxOptions, nil
   190  	}
   191  
   192  	if bridgeSettings.EndpointID == "" {
   193  		return sboxOptions, nil
   194  	}
   195  
   196  	var (
   197  		childEndpoints, parentEndpoints []string
   198  		cEndpointID                     string
   199  	)
   200  
   201  	children := daemon.children(container)
   202  	for linkAlias, child := range children {
   203  		if !isLinkable(child) {
   204  			return nil, fmt.Errorf("Cannot link to %s, as it does not belong to the default network", child.Name)
   205  		}
   206  		_, alias := path.Split(linkAlias)
   207  		// allow access to the linked container via the alias, real name, and container hostname
   208  		aliasList := alias + " " + child.Config.Hostname
   209  		// only add the name if alias isn't equal to the name
   210  		if alias != child.Name[1:] {
   211  			aliasList = aliasList + " " + child.Name[1:]
   212  		}
   213  		ipv4 := child.NetworkSettings.Networks[defaultNetName].IPAddress
   214  		ipv6 := child.NetworkSettings.Networks[defaultNetName].GlobalIPv6Address
   215  		if ipv4 != "" {
   216  			sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, ipv4))
   217  		}
   218  		if ipv6 != "" {
   219  			sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, ipv6))
   220  		}
   221  		cEndpointID = child.NetworkSettings.Networks[defaultNetName].EndpointID
   222  		if cEndpointID != "" {
   223  			childEndpoints = append(childEndpoints, cEndpointID)
   224  		}
   225  	}
   226  
   227  	for alias, parent := range daemon.parents(container) {
   228  		if daemon.configStore.DisableBridge || !container.HostConfig.NetworkMode.IsPrivate() {
   229  			continue
   230  		}
   231  
   232  		_, alias = path.Split(alias)
   233  		logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", parent.ID, alias, bridgeSettings.IPAddress)
   234  		sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate(
   235  			parent.ID,
   236  			alias,
   237  			bridgeSettings.IPAddress,
   238  		))
   239  		if cEndpointID != "" {
   240  			parentEndpoints = append(parentEndpoints, cEndpointID)
   241  		}
   242  	}
   243  
   244  	linkOptions := options.Generic{
   245  		netlabel.GenericData: options.Generic{
   246  			"ParentEndpoints": parentEndpoints,
   247  			"ChildEndpoints":  childEndpoints,
   248  		},
   249  	}
   250  
   251  	sboxOptions = append(sboxOptions, libnetwork.OptionGeneric(linkOptions))
   252  	return sboxOptions, nil
   253  }
   254  
   255  func (daemon *Daemon) updateNetworkSettings(container *container.Container, n libnetwork.Network, endpointConfig *networktypes.EndpointSettings) error {
   256  	if container.NetworkSettings == nil {
   257  		container.NetworkSettings = &network.Settings{}
   258  	}
   259  	if container.NetworkSettings.Networks == nil {
   260  		container.NetworkSettings.Networks = make(map[string]*network.EndpointSettings)
   261  	}
   262  
   263  	if !container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() {
   264  		return runconfig.ErrConflictHostNetwork
   265  	}
   266  
   267  	for s, v := range container.NetworkSettings.Networks {
   268  		sn, err := daemon.FindNetwork(getNetworkID(s, v.EndpointSettings))
   269  		if err != nil {
   270  			continue
   271  		}
   272  
   273  		if sn.Name() == n.Name() {
   274  			// If the network scope is swarm, then this
   275  			// is an attachable network, which may not
   276  			// be locally available previously.
   277  			// So always update.
   278  			if n.Info().Scope() == netconst.SwarmScope {
   279  				continue
   280  			}
   281  			// Avoid duplicate config
   282  			return nil
   283  		}
   284  		if !containertypes.NetworkMode(sn.Type()).IsPrivate() ||
   285  			!containertypes.NetworkMode(n.Type()).IsPrivate() {
   286  			return runconfig.ErrConflictSharedNetwork
   287  		}
   288  		if containertypes.NetworkMode(sn.Name()).IsNone() ||
   289  			containertypes.NetworkMode(n.Name()).IsNone() {
   290  			return runconfig.ErrConflictNoNetwork
   291  		}
   292  	}
   293  
   294  	container.NetworkSettings.Networks[n.Name()] = &network.EndpointSettings{
   295  		EndpointSettings: endpointConfig,
   296  	}
   297  
   298  	return nil
   299  }
   300  
   301  func (daemon *Daemon) updateEndpointNetworkSettings(container *container.Container, n libnetwork.Network, ep libnetwork.Endpoint) error {
   302  	if err := buildEndpointInfo(container.NetworkSettings, n, ep); err != nil {
   303  		return err
   304  	}
   305  
   306  	if container.HostConfig.NetworkMode == runconfig.DefaultDaemonNetworkMode() {
   307  		container.NetworkSettings.Bridge = daemon.configStore.BridgeConfig.Iface
   308  	}
   309  
   310  	return nil
   311  }
   312  
   313  // UpdateNetwork is used to update the container's network (e.g. when linked containers
   314  // get removed/unlinked).
   315  func (daemon *Daemon) updateNetwork(container *container.Container) error {
   316  	var (
   317  		start = time.Now()
   318  		ctrl  = daemon.netController
   319  		sid   = container.NetworkSettings.SandboxID
   320  	)
   321  
   322  	sb, err := ctrl.SandboxByID(sid)
   323  	if err != nil {
   324  		return fmt.Errorf("error locating sandbox id %s: %v", sid, err)
   325  	}
   326  
   327  	// Find if container is connected to the default bridge network
   328  	var n libnetwork.Network
   329  	for name, v := range container.NetworkSettings.Networks {
   330  		sn, err := daemon.FindNetwork(getNetworkID(name, v.EndpointSettings))
   331  		if err != nil {
   332  			continue
   333  		}
   334  		if sn.Name() == runconfig.DefaultDaemonNetworkMode().NetworkName() {
   335  			n = sn
   336  			break
   337  		}
   338  	}
   339  
   340  	if n == nil {
   341  		// Not connected to the default bridge network; Nothing to do
   342  		return nil
   343  	}
   344  
   345  	sbOptions, err := daemon.buildSandboxOptions(container)
   346  	if err != nil {
   347  		return fmt.Errorf("Update network failed: %v", err)
   348  	}
   349  
   350  	if err := sb.Refresh(sbOptions...); err != nil {
   351  		return fmt.Errorf("Update network failed: Failure in refresh sandbox %s: %v", sid, err)
   352  	}
   353  
   354  	networkActions.WithValues("update").UpdateSince(start)
   355  
   356  	return nil
   357  }
   358  
   359  func (daemon *Daemon) findAndAttachNetwork(container *container.Container, idOrName string, epConfig *networktypes.EndpointSettings) (libnetwork.Network, *networktypes.NetworkingConfig, error) {
   360  	id := getNetworkID(idOrName, epConfig)
   361  
   362  	n, err := daemon.FindNetwork(id)
   363  	if err != nil {
   364  		// We should always be able to find the network for a
   365  		// managed container.
   366  		if container.Managed {
   367  			return nil, nil, err
   368  		}
   369  	}
   370  
   371  	// If we found a network and if it is not dynamically created
   372  	// we should never attempt to attach to that network here.
   373  	if n != nil {
   374  		if container.Managed || !n.Info().Dynamic() {
   375  			return n, nil, nil
   376  		}
   377  		// Throw an error if the container is already attached to the network
   378  		if container.NetworkSettings.Networks != nil {
   379  			networkName := n.Name()
   380  			containerName := strings.TrimPrefix(container.Name, "/")
   381  			if nw, ok := container.NetworkSettings.Networks[networkName]; ok && nw.EndpointID != "" {
   382  				err := fmt.Errorf("%s is already attached to network %s", containerName, networkName)
   383  				return n, nil, errdefs.Conflict(err)
   384  			}
   385  		}
   386  	}
   387  
   388  	var addresses []string
   389  	if epConfig != nil && epConfig.IPAMConfig != nil {
   390  		if epConfig.IPAMConfig.IPv4Address != "" {
   391  			addresses = append(addresses, epConfig.IPAMConfig.IPv4Address)
   392  		}
   393  
   394  		if epConfig.IPAMConfig.IPv6Address != "" {
   395  			addresses = append(addresses, epConfig.IPAMConfig.IPv6Address)
   396  		}
   397  	}
   398  
   399  	var (
   400  		config     *networktypes.NetworkingConfig
   401  		retryCount int
   402  	)
   403  
   404  	if n == nil && daemon.attachableNetworkLock != nil {
   405  		daemon.attachableNetworkLock.Lock(id)
   406  		defer daemon.attachableNetworkLock.Unlock(id)
   407  	}
   408  
   409  	for {
   410  		// In all other cases, attempt to attach to the network to
   411  		// trigger attachment in the swarm cluster manager.
   412  		if daemon.clusterProvider != nil {
   413  			var err error
   414  			config, err = daemon.clusterProvider.AttachNetwork(id, container.ID, addresses)
   415  			if err != nil {
   416  				return nil, nil, err
   417  			}
   418  		}
   419  
   420  		n, err = daemon.FindNetwork(id)
   421  		if err != nil {
   422  			if daemon.clusterProvider != nil {
   423  				if err := daemon.clusterProvider.DetachNetwork(id, container.ID); err != nil {
   424  					logrus.Warnf("Could not rollback attachment for container %s to network %s: %v", container.ID, idOrName, err)
   425  				}
   426  			}
   427  
   428  			// Retry network attach again if we failed to
   429  			// find the network after successful
   430  			// attachment because the only reason that
   431  			// would happen is if some other container
   432  			// attached to the swarm scope network went down
   433  			// and removed the network while we were in
   434  			// the process of attaching.
   435  			if config != nil {
   436  				if _, ok := err.(libnetwork.ErrNoSuchNetwork); ok {
   437  					if retryCount >= 5 {
   438  						return nil, nil, fmt.Errorf("could not find network %s after successful attachment", idOrName)
   439  					}
   440  					retryCount++
   441  					continue
   442  				}
   443  			}
   444  
   445  			return nil, nil, err
   446  		}
   447  
   448  		break
   449  	}
   450  
   451  	// This container has attachment to a swarm scope
   452  	// network. Update the container network settings accordingly.
   453  	container.NetworkSettings.HasSwarmEndpoint = true
   454  	return n, config, nil
   455  }
   456  
   457  // updateContainerNetworkSettings updates the network settings
   458  func (daemon *Daemon) updateContainerNetworkSettings(container *container.Container, endpointsConfig map[string]*networktypes.EndpointSettings) {
   459  	var n libnetwork.Network
   460  
   461  	mode := container.HostConfig.NetworkMode
   462  	if container.Config.NetworkDisabled || mode.IsContainer() {
   463  		return
   464  	}
   465  
   466  	networkName := mode.NetworkName()
   467  	if mode.IsDefault() {
   468  		networkName = daemon.netController.Config().Daemon.DefaultNetwork
   469  	}
   470  
   471  	if mode.IsUserDefined() {
   472  		var err error
   473  
   474  		n, err = daemon.FindNetwork(networkName)
   475  		if err == nil {
   476  			networkName = n.Name()
   477  		}
   478  	}
   479  
   480  	if container.NetworkSettings == nil {
   481  		container.NetworkSettings = &network.Settings{}
   482  	}
   483  
   484  	if len(endpointsConfig) > 0 {
   485  		if container.NetworkSettings.Networks == nil {
   486  			container.NetworkSettings.Networks = make(map[string]*network.EndpointSettings)
   487  		}
   488  
   489  		for name, epConfig := range endpointsConfig {
   490  			container.NetworkSettings.Networks[name] = &network.EndpointSettings{
   491  				EndpointSettings: epConfig,
   492  			}
   493  		}
   494  	}
   495  
   496  	if container.NetworkSettings.Networks == nil {
   497  		container.NetworkSettings.Networks = make(map[string]*network.EndpointSettings)
   498  		container.NetworkSettings.Networks[networkName] = &network.EndpointSettings{
   499  			EndpointSettings: &networktypes.EndpointSettings{},
   500  		}
   501  	}
   502  
   503  	// Convert any settings added by client in default name to
   504  	// engine's default network name key
   505  	if mode.IsDefault() {
   506  		if nConf, ok := container.NetworkSettings.Networks[mode.NetworkName()]; ok {
   507  			container.NetworkSettings.Networks[networkName] = nConf
   508  			delete(container.NetworkSettings.Networks, mode.NetworkName())
   509  		}
   510  	}
   511  
   512  	if !mode.IsUserDefined() {
   513  		return
   514  	}
   515  	// Make sure to internally store the per network endpoint config by network name
   516  	if _, ok := container.NetworkSettings.Networks[networkName]; ok {
   517  		return
   518  	}
   519  
   520  	if n != nil {
   521  		if nwConfig, ok := container.NetworkSettings.Networks[n.ID()]; ok {
   522  			container.NetworkSettings.Networks[networkName] = nwConfig
   523  			delete(container.NetworkSettings.Networks, n.ID())
   524  			return
   525  		}
   526  	}
   527  }
   528  
   529  func (daemon *Daemon) allocateNetwork(container *container.Container) (retErr error) {
   530  	if daemon.netController == nil {
   531  		return nil
   532  	}
   533  
   534  	var (
   535  		start      = time.Now()
   536  		controller = daemon.netController
   537  	)
   538  
   539  	// Cleanup any stale sandbox left over due to ungraceful daemon shutdown
   540  	if err := controller.SandboxDestroy(container.ID); err != nil {
   541  		logrus.WithError(err).Errorf("failed to cleanup up stale network sandbox for container %s", container.ID)
   542  	}
   543  
   544  	if container.Config.NetworkDisabled || container.HostConfig.NetworkMode.IsContainer() {
   545  		return nil
   546  	}
   547  
   548  	updateSettings := false
   549  
   550  	if len(container.NetworkSettings.Networks) == 0 {
   551  		daemon.updateContainerNetworkSettings(container, nil)
   552  		updateSettings = true
   553  	}
   554  
   555  	// always connect default network first since only default
   556  	// network mode support link and we need do some setting
   557  	// on sandbox initialize for link, but the sandbox only be initialized
   558  	// on first network connecting.
   559  	defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
   560  	if nConf, ok := container.NetworkSettings.Networks[defaultNetName]; ok {
   561  		cleanOperationalData(nConf)
   562  		if err := daemon.connectToNetwork(container, defaultNetName, nConf.EndpointSettings, updateSettings); err != nil {
   563  			return err
   564  		}
   565  
   566  	}
   567  
   568  	// the intermediate map is necessary because "connectToNetwork" modifies "container.NetworkSettings.Networks"
   569  	networks := make(map[string]*network.EndpointSettings)
   570  	for n, epConf := range container.NetworkSettings.Networks {
   571  		if n == defaultNetName {
   572  			continue
   573  		}
   574  
   575  		networks[n] = epConf
   576  	}
   577  
   578  	for netName, epConf := range networks {
   579  		cleanOperationalData(epConf)
   580  		if err := daemon.connectToNetwork(container, netName, epConf.EndpointSettings, updateSettings); err != nil {
   581  			return err
   582  		}
   583  	}
   584  
   585  	// If the container is not to be connected to any network,
   586  	// create its network sandbox now if not present
   587  	if len(networks) == 0 {
   588  		if nil == daemon.getNetworkSandbox(container) {
   589  			sbOptions, err := daemon.buildSandboxOptions(container)
   590  			if err != nil {
   591  				return err
   592  			}
   593  			sb, err := daemon.netController.NewSandbox(container.ID, sbOptions...)
   594  			if err != nil {
   595  				return err
   596  			}
   597  			updateSandboxNetworkSettings(container, sb)
   598  			defer func() {
   599  				if retErr != nil {
   600  					sb.Delete()
   601  				}
   602  			}()
   603  		}
   604  
   605  	}
   606  
   607  	if _, err := container.WriteHostConfig(); err != nil {
   608  		return err
   609  	}
   610  	networkActions.WithValues("allocate").UpdateSince(start)
   611  	return nil
   612  }
   613  
   614  func (daemon *Daemon) getNetworkSandbox(container *container.Container) libnetwork.Sandbox {
   615  	var sb libnetwork.Sandbox
   616  	daemon.netController.WalkSandboxes(func(s libnetwork.Sandbox) bool {
   617  		if s.ContainerID() == container.ID {
   618  			sb = s
   619  			return true
   620  		}
   621  		return false
   622  	})
   623  	return sb
   624  }
   625  
   626  // hasUserDefinedIPAddress returns whether the passed IPAM configuration contains IP address configuration
   627  func hasUserDefinedIPAddress(ipamConfig *networktypes.EndpointIPAMConfig) bool {
   628  	return ipamConfig != nil && (len(ipamConfig.IPv4Address) > 0 || len(ipamConfig.IPv6Address) > 0)
   629  }
   630  
   631  // User specified ip address is acceptable only for networks with user specified subnets.
   632  func validateNetworkingConfig(n libnetwork.Network, epConfig *networktypes.EndpointSettings) error {
   633  	if n == nil || epConfig == nil {
   634  		return nil
   635  	}
   636  	if !containertypes.NetworkMode(n.Name()).IsUserDefined() {
   637  		if hasUserDefinedIPAddress(epConfig.IPAMConfig) && !enableIPOnPredefinedNetwork() {
   638  			return runconfig.ErrUnsupportedNetworkAndIP
   639  		}
   640  		if len(epConfig.Aliases) > 0 && !serviceDiscoveryOnDefaultNetwork() {
   641  			return runconfig.ErrUnsupportedNetworkAndAlias
   642  		}
   643  	}
   644  	if !hasUserDefinedIPAddress(epConfig.IPAMConfig) {
   645  		return nil
   646  	}
   647  
   648  	_, _, nwIPv4Configs, nwIPv6Configs := n.Info().IpamConfig()
   649  	for _, s := range []struct {
   650  		ipConfigured  bool
   651  		subnetConfigs []*libnetwork.IpamConf
   652  	}{
   653  		{
   654  			ipConfigured:  len(epConfig.IPAMConfig.IPv4Address) > 0,
   655  			subnetConfigs: nwIPv4Configs,
   656  		},
   657  		{
   658  			ipConfigured:  len(epConfig.IPAMConfig.IPv6Address) > 0,
   659  			subnetConfigs: nwIPv6Configs,
   660  		},
   661  	} {
   662  		if s.ipConfigured {
   663  			foundSubnet := false
   664  			for _, cfg := range s.subnetConfigs {
   665  				if len(cfg.PreferredPool) > 0 {
   666  					foundSubnet = true
   667  					break
   668  				}
   669  			}
   670  			if !foundSubnet {
   671  				return runconfig.ErrUnsupportedNetworkNoSubnetAndIP
   672  			}
   673  		}
   674  	}
   675  
   676  	return nil
   677  }
   678  
   679  // cleanOperationalData resets the operational data from the passed endpoint settings
   680  func cleanOperationalData(es *network.EndpointSettings) {
   681  	es.EndpointID = ""
   682  	es.Gateway = ""
   683  	es.IPAddress = ""
   684  	es.IPPrefixLen = 0
   685  	es.IPv6Gateway = ""
   686  	es.GlobalIPv6Address = ""
   687  	es.GlobalIPv6PrefixLen = 0
   688  	es.MacAddress = ""
   689  	if es.IPAMOperational {
   690  		es.IPAMConfig = nil
   691  	}
   692  }
   693  
   694  func (daemon *Daemon) updateNetworkConfig(container *container.Container, n libnetwork.Network, endpointConfig *networktypes.EndpointSettings, updateSettings bool) error {
   695  
   696  	if containertypes.NetworkMode(n.Name()).IsUserDefined() {
   697  		addShortID := true
   698  		shortID := stringid.TruncateID(container.ID)
   699  		for _, alias := range endpointConfig.Aliases {
   700  			if alias == shortID {
   701  				addShortID = false
   702  				break
   703  			}
   704  		}
   705  		if addShortID {
   706  			endpointConfig.Aliases = append(endpointConfig.Aliases, shortID)
   707  		}
   708  		if container.Name != container.Config.Hostname {
   709  			addHostname := true
   710  			for _, alias := range endpointConfig.Aliases {
   711  				if alias == container.Config.Hostname {
   712  					addHostname = false
   713  					break
   714  				}
   715  			}
   716  			if addHostname {
   717  				endpointConfig.Aliases = append(endpointConfig.Aliases, container.Config.Hostname)
   718  			}
   719  		}
   720  	}
   721  
   722  	if err := validateNetworkingConfig(n, endpointConfig); err != nil {
   723  		return err
   724  	}
   725  
   726  	if updateSettings {
   727  		if err := daemon.updateNetworkSettings(container, n, endpointConfig); err != nil {
   728  			return err
   729  		}
   730  	}
   731  	return nil
   732  }
   733  
   734  func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (err error) {
   735  	start := time.Now()
   736  	if container.HostConfig.NetworkMode.IsContainer() {
   737  		return runconfig.ErrConflictSharedNetwork
   738  	}
   739  	if containertypes.NetworkMode(idOrName).IsBridge() &&
   740  		daemon.configStore.DisableBridge {
   741  		container.Config.NetworkDisabled = true
   742  		return nil
   743  	}
   744  	if endpointConfig == nil {
   745  		endpointConfig = &networktypes.EndpointSettings{}
   746  	}
   747  
   748  	n, config, err := daemon.findAndAttachNetwork(container, idOrName, endpointConfig)
   749  	if err != nil {
   750  		return err
   751  	}
   752  	if n == nil {
   753  		return nil
   754  	}
   755  
   756  	var operIPAM bool
   757  	if config != nil {
   758  		if epConfig, ok := config.EndpointsConfig[n.Name()]; ok {
   759  			if endpointConfig.IPAMConfig == nil ||
   760  				(endpointConfig.IPAMConfig.IPv4Address == "" &&
   761  					endpointConfig.IPAMConfig.IPv6Address == "" &&
   762  					len(endpointConfig.IPAMConfig.LinkLocalIPs) == 0) {
   763  				operIPAM = true
   764  			}
   765  
   766  			// copy IPAMConfig and NetworkID from epConfig via AttachNetwork
   767  			endpointConfig.IPAMConfig = epConfig.IPAMConfig
   768  			endpointConfig.NetworkID = epConfig.NetworkID
   769  		}
   770  	}
   771  
   772  	if err := daemon.updateNetworkConfig(container, n, endpointConfig, updateSettings); err != nil {
   773  		return err
   774  	}
   775  
   776  	controller := daemon.netController
   777  	sb := daemon.getNetworkSandbox(container)
   778  	createOptions, err := buildCreateEndpointOptions(container, n, endpointConfig, sb, daemon.configStore.DNS)
   779  	if err != nil {
   780  		return err
   781  	}
   782  
   783  	endpointName := strings.TrimPrefix(container.Name, "/")
   784  	ep, err := n.CreateEndpoint(endpointName, createOptions...)
   785  	if err != nil {
   786  		return err
   787  	}
   788  	defer func() {
   789  		if err != nil {
   790  			if e := ep.Delete(false); e != nil {
   791  				logrus.Warnf("Could not rollback container connection to network %s", idOrName)
   792  			}
   793  		}
   794  	}()
   795  	container.NetworkSettings.Networks[n.Name()] = &network.EndpointSettings{
   796  		EndpointSettings: endpointConfig,
   797  		IPAMOperational:  operIPAM,
   798  	}
   799  
   800  	delete(container.NetworkSettings.Networks, n.ID())
   801  
   802  	if err := daemon.updateEndpointNetworkSettings(container, n, ep); err != nil {
   803  		return err
   804  	}
   805  
   806  	if sb == nil {
   807  		sbOptions, err := daemon.buildSandboxOptions(container)
   808  		if err != nil {
   809  			return err
   810  		}
   811  		sb, err = controller.NewSandbox(container.ID, sbOptions...)
   812  		if err != nil {
   813  			return err
   814  		}
   815  
   816  		updateSandboxNetworkSettings(container, sb)
   817  	}
   818  
   819  	joinOptions, err := buildJoinOptions(container.NetworkSettings, n)
   820  	if err != nil {
   821  		return err
   822  	}
   823  
   824  	if err := ep.Join(sb, joinOptions...); err != nil {
   825  		return err
   826  	}
   827  
   828  	if !container.Managed {
   829  		// add container name/alias to DNS
   830  		if err := daemon.ActivateContainerServiceBinding(container.Name); err != nil {
   831  			return fmt.Errorf("Activate container service binding for %s failed: %v", container.Name, err)
   832  		}
   833  	}
   834  
   835  	if err := updateJoinInfo(container.NetworkSettings, n, ep); err != nil {
   836  		return fmt.Errorf("Updating join info failed: %v", err)
   837  	}
   838  
   839  	container.NetworkSettings.Ports = getPortMapInfo(sb)
   840  
   841  	daemon.LogNetworkEventWithAttributes(n, "connect", map[string]string{"container": container.ID})
   842  	networkActions.WithValues("connect").UpdateSince(start)
   843  	return nil
   844  }
   845  
   846  func updateJoinInfo(networkSettings *network.Settings, n libnetwork.Network, ep libnetwork.Endpoint) error {
   847  	if ep == nil {
   848  		return errors.New("invalid enppoint whhile building portmap info")
   849  	}
   850  
   851  	if networkSettings == nil {
   852  		return errors.New("invalid network settings while building port map info")
   853  	}
   854  
   855  	if len(networkSettings.Ports) == 0 {
   856  		pm, err := getEndpointPortMapInfo(ep)
   857  		if err != nil {
   858  			return err
   859  		}
   860  		networkSettings.Ports = pm
   861  	}
   862  
   863  	epInfo := ep.Info()
   864  	if epInfo == nil {
   865  		// It is not an error to get an empty endpoint info
   866  		return nil
   867  	}
   868  	if epInfo.Gateway() != nil {
   869  		networkSettings.Networks[n.Name()].Gateway = epInfo.Gateway().String()
   870  	}
   871  	if epInfo.GatewayIPv6().To16() != nil {
   872  		networkSettings.Networks[n.Name()].IPv6Gateway = epInfo.GatewayIPv6().String()
   873  	}
   874  	return nil
   875  }
   876  
   877  // ForceEndpointDelete deletes an endpoint from a network forcefully
   878  func (daemon *Daemon) ForceEndpointDelete(name string, networkName string) error {
   879  	n, err := daemon.FindNetwork(networkName)
   880  	if err != nil {
   881  		return err
   882  	}
   883  
   884  	ep, err := n.EndpointByName(name)
   885  	if err != nil {
   886  		return err
   887  	}
   888  	return ep.Delete(true)
   889  }
   890  
   891  func (daemon *Daemon) disconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error {
   892  	var (
   893  		ep   libnetwork.Endpoint
   894  		sbox libnetwork.Sandbox
   895  	)
   896  
   897  	s := func(current libnetwork.Endpoint) bool {
   898  		epInfo := current.Info()
   899  		if epInfo == nil {
   900  			return false
   901  		}
   902  		if sb := epInfo.Sandbox(); sb != nil {
   903  			if sb.ContainerID() == container.ID {
   904  				ep = current
   905  				sbox = sb
   906  				return true
   907  			}
   908  		}
   909  		return false
   910  	}
   911  	n.WalkEndpoints(s)
   912  
   913  	if ep == nil && force {
   914  		epName := strings.TrimPrefix(container.Name, "/")
   915  		ep, err := n.EndpointByName(epName)
   916  		if err != nil {
   917  			return err
   918  		}
   919  		return ep.Delete(force)
   920  	}
   921  
   922  	if ep == nil {
   923  		return fmt.Errorf("container %s is not connected to network %s", container.ID, n.Name())
   924  	}
   925  
   926  	if err := ep.Leave(sbox); err != nil {
   927  		return fmt.Errorf("container %s failed to leave network %s: %v", container.ID, n.Name(), err)
   928  	}
   929  
   930  	container.NetworkSettings.Ports = getPortMapInfo(sbox)
   931  
   932  	if err := ep.Delete(false); err != nil {
   933  		return fmt.Errorf("endpoint delete failed for container %s on network %s: %v", container.ID, n.Name(), err)
   934  	}
   935  
   936  	delete(container.NetworkSettings.Networks, n.Name())
   937  
   938  	daemon.tryDetachContainerFromClusterNetwork(n, container)
   939  
   940  	return nil
   941  }
   942  
   943  func (daemon *Daemon) tryDetachContainerFromClusterNetwork(network libnetwork.Network, container *container.Container) {
   944  	if daemon.clusterProvider != nil && network.Info().Dynamic() && !container.Managed {
   945  		if err := daemon.clusterProvider.DetachNetwork(network.Name(), container.ID); err != nil {
   946  			logrus.Warnf("error detaching from network %s: %v", network.Name(), err)
   947  			if err := daemon.clusterProvider.DetachNetwork(network.ID(), container.ID); err != nil {
   948  				logrus.Warnf("error detaching from network %s: %v", network.ID(), err)
   949  			}
   950  		}
   951  	}
   952  	attributes := map[string]string{
   953  		"container": container.ID,
   954  	}
   955  	daemon.LogNetworkEventWithAttributes(network, "disconnect", attributes)
   956  }
   957  
   958  func (daemon *Daemon) initializeNetworking(container *container.Container) error {
   959  	var err error
   960  
   961  	if container.HostConfig.NetworkMode.IsContainer() {
   962  		// we need to get the hosts files from the container to join
   963  		nc, err := daemon.getNetworkedContainer(container.ID, container.HostConfig.NetworkMode.ConnectedContainer())
   964  		if err != nil {
   965  			return err
   966  		}
   967  
   968  		err = daemon.initializeNetworkingPaths(container, nc)
   969  		if err != nil {
   970  			return err
   971  		}
   972  
   973  		container.Config.Hostname = nc.Config.Hostname
   974  		container.Config.Domainname = nc.Config.Domainname
   975  		return nil
   976  	}
   977  
   978  	if container.HostConfig.NetworkMode.IsHost() {
   979  		if container.Config.Hostname == "" {
   980  			container.Config.Hostname, err = os.Hostname()
   981  			if err != nil {
   982  				return err
   983  			}
   984  		}
   985  	}
   986  
   987  	if err := daemon.allocateNetwork(container); err != nil {
   988  		return err
   989  	}
   990  
   991  	return container.BuildHostnameFile()
   992  }
   993  
   994  func (daemon *Daemon) getNetworkedContainer(containerID, connectedContainerID string) (*container.Container, error) {
   995  	nc, err := daemon.GetContainer(connectedContainerID)
   996  	if err != nil {
   997  		return nil, err
   998  	}
   999  	if containerID == nc.ID {
  1000  		return nil, fmt.Errorf("cannot join own network")
  1001  	}
  1002  	if !nc.IsRunning() {
  1003  		err := fmt.Errorf("cannot join network of a non running container: %s", connectedContainerID)
  1004  		return nil, errdefs.Conflict(err)
  1005  	}
  1006  	if nc.IsRestarting() {
  1007  		return nil, errContainerIsRestarting(connectedContainerID)
  1008  	}
  1009  	return nc, nil
  1010  }
  1011  
  1012  func (daemon *Daemon) releaseNetwork(container *container.Container) {
  1013  	start := time.Now()
  1014  	if daemon.netController == nil {
  1015  		return
  1016  	}
  1017  	if container.HostConfig.NetworkMode.IsContainer() || container.Config.NetworkDisabled {
  1018  		return
  1019  	}
  1020  
  1021  	sid := container.NetworkSettings.SandboxID
  1022  	settings := container.NetworkSettings.Networks
  1023  	container.NetworkSettings.Ports = nil
  1024  
  1025  	if sid == "" {
  1026  		return
  1027  	}
  1028  
  1029  	var networks []libnetwork.Network
  1030  	for n, epSettings := range settings {
  1031  		if nw, err := daemon.FindNetwork(getNetworkID(n, epSettings.EndpointSettings)); err == nil {
  1032  			networks = append(networks, nw)
  1033  		}
  1034  
  1035  		if epSettings.EndpointSettings == nil {
  1036  			continue
  1037  		}
  1038  
  1039  		cleanOperationalData(epSettings)
  1040  	}
  1041  
  1042  	sb, err := daemon.netController.SandboxByID(sid)
  1043  	if err != nil {
  1044  		logrus.Warnf("error locating sandbox id %s: %v", sid, err)
  1045  		return
  1046  	}
  1047  
  1048  	if err := sb.Delete(); err != nil {
  1049  		logrus.Errorf("Error deleting sandbox id %s for container %s: %v", sid, container.ID, err)
  1050  	}
  1051  
  1052  	for _, nw := range networks {
  1053  		daemon.tryDetachContainerFromClusterNetwork(nw, container)
  1054  	}
  1055  	networkActions.WithValues("release").UpdateSince(start)
  1056  }
  1057  
  1058  func errRemovalContainer(containerID string) error {
  1059  	return fmt.Errorf("Container %s is marked for removal and cannot be connected or disconnected to the network", containerID)
  1060  }
  1061  
  1062  // ConnectToNetwork connects a container to a network
  1063  func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings) error {
  1064  	if endpointConfig == nil {
  1065  		endpointConfig = &networktypes.EndpointSettings{}
  1066  	}
  1067  	container.Lock()
  1068  	defer container.Unlock()
  1069  
  1070  	if !container.Running {
  1071  		if container.RemovalInProgress || container.Dead {
  1072  			return errRemovalContainer(container.ID)
  1073  		}
  1074  
  1075  		n, err := daemon.FindNetwork(idOrName)
  1076  		if err == nil && n != nil {
  1077  			if err := daemon.updateNetworkConfig(container, n, endpointConfig, true); err != nil {
  1078  				return err
  1079  			}
  1080  		} else {
  1081  			container.NetworkSettings.Networks[idOrName] = &network.EndpointSettings{
  1082  				EndpointSettings: endpointConfig,
  1083  			}
  1084  		}
  1085  	} else {
  1086  		if err := daemon.connectToNetwork(container, idOrName, endpointConfig, true); err != nil {
  1087  			return err
  1088  		}
  1089  	}
  1090  
  1091  	return container.CheckpointTo(daemon.containersReplica)
  1092  }
  1093  
  1094  // DisconnectFromNetwork disconnects container from network n.
  1095  func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, networkName string, force bool) error {
  1096  	n, err := daemon.FindNetwork(networkName)
  1097  	container.Lock()
  1098  	defer container.Unlock()
  1099  
  1100  	if !container.Running || (err != nil && force) {
  1101  		if container.RemovalInProgress || container.Dead {
  1102  			return errRemovalContainer(container.ID)
  1103  		}
  1104  		// In case networkName is resolved we will use n.Name()
  1105  		// this will cover the case where network id is passed.
  1106  		if n != nil {
  1107  			networkName = n.Name()
  1108  		}
  1109  		if _, ok := container.NetworkSettings.Networks[networkName]; !ok {
  1110  			return fmt.Errorf("container %s is not connected to the network %s", container.ID, networkName)
  1111  		}
  1112  		delete(container.NetworkSettings.Networks, networkName)
  1113  	} else if err == nil {
  1114  		if container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() {
  1115  			return runconfig.ErrConflictHostNetwork
  1116  		}
  1117  
  1118  		if err := daemon.disconnectFromNetwork(container, n, false); err != nil {
  1119  			return err
  1120  		}
  1121  	} else {
  1122  		return err
  1123  	}
  1124  
  1125  	if err := container.CheckpointTo(daemon.containersReplica); err != nil {
  1126  		return err
  1127  	}
  1128  
  1129  	if n != nil {
  1130  		daemon.LogNetworkEventWithAttributes(n, "disconnect", map[string]string{
  1131  			"container": container.ID,
  1132  		})
  1133  	}
  1134  
  1135  	return nil
  1136  }
  1137  
  1138  // ActivateContainerServiceBinding puts this container into load balancer active rotation and DNS response
  1139  func (daemon *Daemon) ActivateContainerServiceBinding(containerName string) error {
  1140  	ctr, err := daemon.GetContainer(containerName)
  1141  	if err != nil {
  1142  		return err
  1143  	}
  1144  	sb := daemon.getNetworkSandbox(ctr)
  1145  	if sb == nil {
  1146  		return fmt.Errorf("network sandbox does not exist for container %s", containerName)
  1147  	}
  1148  	return sb.EnableService()
  1149  }
  1150  
  1151  // DeactivateContainerServiceBinding removes this container from load balancer active rotation, and DNS response
  1152  func (daemon *Daemon) DeactivateContainerServiceBinding(containerName string) error {
  1153  	ctr, err := daemon.GetContainer(containerName)
  1154  	if err != nil {
  1155  		return err
  1156  	}
  1157  	sb := daemon.getNetworkSandbox(ctr)
  1158  	if sb == nil {
  1159  		// If the network sandbox is not found, then there is nothing to deactivate
  1160  		logrus.Debugf("Could not find network sandbox for container %s on service binding deactivation request", containerName)
  1161  		return nil
  1162  	}
  1163  	return sb.DisableService()
  1164  }
  1165  
  1166  func getNetworkID(name string, endpointSettings *networktypes.EndpointSettings) string {
  1167  	// We only want to prefer NetworkID for user defined networks.
  1168  	// For systems like bridge, none, etc. the name is preferred (otherwise restart may cause issues)
  1169  	if containertypes.NetworkMode(name).IsUserDefined() && endpointSettings != nil && endpointSettings.NetworkID != "" {
  1170  		return endpointSettings.NetworkID
  1171  	}
  1172  	return name
  1173  }
  1174  
  1175  // updateSandboxNetworkSettings updates the sandbox ID and Key.
  1176  func updateSandboxNetworkSettings(c *container.Container, sb libnetwork.Sandbox) error {
  1177  	c.NetworkSettings.SandboxID = sb.ID()
  1178  	c.NetworkSettings.SandboxKey = sb.Key()
  1179  	return nil
  1180  }