github.com/rhatdan/docker@v0.7.7-0.20180119204836-47a0dcbcd20a/daemon/container_operations.go (about)

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