github.com/portworx/docker@v1.12.1/daemon/container_operations.go (about)

     1  package daemon
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net"
     7  	"os"
     8  	"path"
     9  	"strings"
    10  
    11  	"github.com/Sirupsen/logrus"
    12  	"github.com/docker/docker/container"
    13  	"github.com/docker/docker/daemon/network"
    14  	derr "github.com/docker/docker/errors"
    15  	"github.com/docker/docker/pkg/stringid"
    16  	"github.com/docker/docker/runconfig"
    17  	containertypes "github.com/docker/engine-api/types/container"
    18  	networktypes "github.com/docker/engine-api/types/network"
    19  	"github.com/docker/go-connections/nat"
    20  	"github.com/docker/libnetwork"
    21  	"github.com/docker/libnetwork/netlabel"
    22  	"github.com/docker/libnetwork/options"
    23  	"github.com/docker/libnetwork/types"
    24  )
    25  
    26  var (
    27  	// ErrRootFSReadOnly is returned when a container
    28  	// rootfs is marked readonly.
    29  	ErrRootFSReadOnly = errors.New("container rootfs is marked read-only")
    30  	getPortMapInfo    = container.GetSandboxPortMapInfo
    31  )
    32  
    33  func (daemon *Daemon) buildSandboxOptions(container *container.Container) ([]libnetwork.SandboxOption, error) {
    34  	var (
    35  		sboxOptions []libnetwork.SandboxOption
    36  		err         error
    37  		dns         []string
    38  		dnsSearch   []string
    39  		dnsOptions  []string
    40  		bindings    = make(nat.PortMap)
    41  		pbList      []types.PortBinding
    42  		exposeList  []types.TransportPort
    43  	)
    44  
    45  	defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
    46  	sboxOptions = append(sboxOptions, libnetwork.OptionHostname(container.Config.Hostname),
    47  		libnetwork.OptionDomainname(container.Config.Domainname))
    48  
    49  	if container.HostConfig.NetworkMode.IsHost() {
    50  		sboxOptions = append(sboxOptions, libnetwork.OptionUseDefaultSandbox())
    51  		if len(container.HostConfig.ExtraHosts) == 0 {
    52  			sboxOptions = append(sboxOptions, libnetwork.OptionOriginHostsPath("/etc/hosts"))
    53  		}
    54  		if len(container.HostConfig.DNS) == 0 && len(daemon.configStore.DNS) == 0 &&
    55  			len(container.HostConfig.DNSSearch) == 0 && len(daemon.configStore.DNSSearch) == 0 &&
    56  			len(container.HostConfig.DNSOptions) == 0 && len(daemon.configStore.DNSOptions) == 0 {
    57  			sboxOptions = append(sboxOptions, libnetwork.OptionOriginResolvConfPath("/etc/resolv.conf"))
    58  		}
    59  	} else {
    60  		// OptionUseExternalKey is mandatory for userns support.
    61  		// But optional for non-userns support
    62  		sboxOptions = append(sboxOptions, libnetwork.OptionUseExternalKey())
    63  	}
    64  
    65  	container.HostsPath, err = container.GetRootResourcePath("hosts")
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  	sboxOptions = append(sboxOptions, libnetwork.OptionHostsPath(container.HostsPath))
    70  
    71  	container.ResolvConfPath, err = container.GetRootResourcePath("resolv.conf")
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  	sboxOptions = append(sboxOptions, libnetwork.OptionResolvConfPath(container.ResolvConfPath))
    76  
    77  	if len(container.HostConfig.DNS) > 0 {
    78  		dns = container.HostConfig.DNS
    79  	} else if len(daemon.configStore.DNS) > 0 {
    80  		dns = daemon.configStore.DNS
    81  	}
    82  
    83  	for _, d := range dns {
    84  		sboxOptions = append(sboxOptions, libnetwork.OptionDNS(d))
    85  	}
    86  
    87  	if len(container.HostConfig.DNSSearch) > 0 {
    88  		dnsSearch = container.HostConfig.DNSSearch
    89  	} else if len(daemon.configStore.DNSSearch) > 0 {
    90  		dnsSearch = daemon.configStore.DNSSearch
    91  	}
    92  
    93  	for _, ds := range dnsSearch {
    94  		sboxOptions = append(sboxOptions, libnetwork.OptionDNSSearch(ds))
    95  	}
    96  
    97  	if len(container.HostConfig.DNSOptions) > 0 {
    98  		dnsOptions = container.HostConfig.DNSOptions
    99  	} else if len(daemon.configStore.DNSOptions) > 0 {
   100  		dnsOptions = daemon.configStore.DNSOptions
   101  	}
   102  
   103  	for _, ds := range dnsOptions {
   104  		sboxOptions = append(sboxOptions, libnetwork.OptionDNSOptions(ds))
   105  	}
   106  
   107  	if container.NetworkSettings.SecondaryIPAddresses != nil {
   108  		name := container.Config.Hostname
   109  		if container.Config.Domainname != "" {
   110  			name = name + "." + container.Config.Domainname
   111  		}
   112  
   113  		for _, a := range container.NetworkSettings.SecondaryIPAddresses {
   114  			sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(name, a.Addr))
   115  		}
   116  	}
   117  
   118  	for _, extraHost := range container.HostConfig.ExtraHosts {
   119  		// allow IPv6 addresses in extra hosts; only split on first ":"
   120  		parts := strings.SplitN(extraHost, ":", 2)
   121  		sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(parts[0], parts[1]))
   122  	}
   123  
   124  	if container.HostConfig.PortBindings != nil {
   125  		for p, b := range container.HostConfig.PortBindings {
   126  			bindings[p] = []nat.PortBinding{}
   127  			for _, bb := range b {
   128  				bindings[p] = append(bindings[p], nat.PortBinding{
   129  					HostIP:   bb.HostIP,
   130  					HostPort: bb.HostPort,
   131  				})
   132  			}
   133  		}
   134  	}
   135  
   136  	portSpecs := container.Config.ExposedPorts
   137  	ports := make([]nat.Port, len(portSpecs))
   138  	var i int
   139  	for p := range portSpecs {
   140  		ports[i] = p
   141  		i++
   142  	}
   143  	nat.SortPortMap(ports, bindings)
   144  	for _, port := range ports {
   145  		expose := types.TransportPort{}
   146  		expose.Proto = types.ParseProtocol(port.Proto())
   147  		expose.Port = uint16(port.Int())
   148  		exposeList = append(exposeList, expose)
   149  
   150  		pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto}
   151  		binding := bindings[port]
   152  		for i := 0; i < len(binding); i++ {
   153  			pbCopy := pb.GetCopy()
   154  			newP, err := nat.NewPort(nat.SplitProtoPort(binding[i].HostPort))
   155  			var portStart, portEnd int
   156  			if err == nil {
   157  				portStart, portEnd, err = newP.Range()
   158  			}
   159  			if err != nil {
   160  				return nil, fmt.Errorf("Error parsing HostPort value(%s):%v", binding[i].HostPort, err)
   161  			}
   162  			pbCopy.HostPort = uint16(portStart)
   163  			pbCopy.HostPortEnd = uint16(portEnd)
   164  			pbCopy.HostIP = net.ParseIP(binding[i].HostIP)
   165  			pbList = append(pbList, pbCopy)
   166  		}
   167  
   168  		if container.HostConfig.PublishAllPorts && len(binding) == 0 {
   169  			pbList = append(pbList, pb)
   170  		}
   171  	}
   172  
   173  	sboxOptions = append(sboxOptions,
   174  		libnetwork.OptionPortMapping(pbList),
   175  		libnetwork.OptionExposedPorts(exposeList))
   176  
   177  	// Legacy Link feature is supported only for the default bridge network.
   178  	// return if this call to build join options is not for default bridge network
   179  	// Legacy Link is only supported by docker run --link
   180  	bridgeSettings, ok := container.NetworkSettings.Networks[defaultNetName]
   181  	if !ok {
   182  		return sboxOptions, nil
   183  	}
   184  
   185  	if bridgeSettings.EndpointID == "" {
   186  		return sboxOptions, nil
   187  	}
   188  
   189  	var (
   190  		childEndpoints, parentEndpoints []string
   191  		cEndpointID                     string
   192  	)
   193  
   194  	children := daemon.children(container)
   195  	for linkAlias, child := range children {
   196  		if !isLinkable(child) {
   197  			return nil, fmt.Errorf("Cannot link to %s, as it does not belong to the default network", child.Name)
   198  		}
   199  		_, alias := path.Split(linkAlias)
   200  		// allow access to the linked container via the alias, real name, and container hostname
   201  		aliasList := alias + " " + child.Config.Hostname
   202  		// only add the name if alias isn't equal to the name
   203  		if alias != child.Name[1:] {
   204  			aliasList = aliasList + " " + child.Name[1:]
   205  		}
   206  		sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, child.NetworkSettings.Networks[defaultNetName].IPAddress))
   207  		cEndpointID = child.NetworkSettings.Networks[defaultNetName].EndpointID
   208  		if cEndpointID != "" {
   209  			childEndpoints = append(childEndpoints, cEndpointID)
   210  		}
   211  	}
   212  
   213  	for alias, parent := range daemon.parents(container) {
   214  		if daemon.configStore.DisableBridge || !container.HostConfig.NetworkMode.IsPrivate() {
   215  			continue
   216  		}
   217  
   218  		_, alias = path.Split(alias)
   219  		logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", parent.ID, alias, bridgeSettings.IPAddress)
   220  		sboxOptions = append(sboxOptions, libnetwork.OptionParentUpdate(
   221  			parent.ID,
   222  			alias,
   223  			bridgeSettings.IPAddress,
   224  		))
   225  		if cEndpointID != "" {
   226  			parentEndpoints = append(parentEndpoints, cEndpointID)
   227  		}
   228  	}
   229  
   230  	linkOptions := options.Generic{
   231  		netlabel.GenericData: options.Generic{
   232  			"ParentEndpoints": parentEndpoints,
   233  			"ChildEndpoints":  childEndpoints,
   234  		},
   235  	}
   236  
   237  	sboxOptions = append(sboxOptions, libnetwork.OptionGeneric(linkOptions))
   238  	return sboxOptions, nil
   239  }
   240  
   241  func (daemon *Daemon) updateNetworkSettings(container *container.Container, n libnetwork.Network) error {
   242  	if container.NetworkSettings == nil {
   243  		container.NetworkSettings = &network.Settings{Networks: make(map[string]*networktypes.EndpointSettings)}
   244  	}
   245  
   246  	if !container.HostConfig.NetworkMode.IsHost() && containertypes.NetworkMode(n.Type()).IsHost() {
   247  		return runconfig.ErrConflictHostNetwork
   248  	}
   249  
   250  	for s := range container.NetworkSettings.Networks {
   251  		sn, err := daemon.FindNetwork(s)
   252  		if err != nil {
   253  			continue
   254  		}
   255  
   256  		if sn.Name() == n.Name() {
   257  			// Avoid duplicate config
   258  			return nil
   259  		}
   260  		if !containertypes.NetworkMode(sn.Type()).IsPrivate() ||
   261  			!containertypes.NetworkMode(n.Type()).IsPrivate() {
   262  			return runconfig.ErrConflictSharedNetwork
   263  		}
   264  		if containertypes.NetworkMode(sn.Name()).IsNone() ||
   265  			containertypes.NetworkMode(n.Name()).IsNone() {
   266  			return runconfig.ErrConflictNoNetwork
   267  		}
   268  	}
   269  
   270  	if _, ok := container.NetworkSettings.Networks[n.Name()]; !ok {
   271  		container.NetworkSettings.Networks[n.Name()] = new(networktypes.EndpointSettings)
   272  	}
   273  
   274  	return nil
   275  }
   276  
   277  func (daemon *Daemon) updateEndpointNetworkSettings(container *container.Container, n libnetwork.Network, ep libnetwork.Endpoint) error {
   278  	if err := container.BuildEndpointInfo(n, ep); err != nil {
   279  		return err
   280  	}
   281  
   282  	if container.HostConfig.NetworkMode == runconfig.DefaultDaemonNetworkMode() {
   283  		container.NetworkSettings.Bridge = daemon.configStore.bridgeConfig.Iface
   284  	}
   285  
   286  	return nil
   287  }
   288  
   289  // UpdateNetwork is used to update the container's network (e.g. when linked containers
   290  // get removed/unlinked).
   291  func (daemon *Daemon) updateNetwork(container *container.Container) error {
   292  	ctrl := daemon.netController
   293  	sid := container.NetworkSettings.SandboxID
   294  
   295  	sb, err := ctrl.SandboxByID(sid)
   296  	if err != nil {
   297  		return fmt.Errorf("error locating sandbox id %s: %v", sid, err)
   298  	}
   299  
   300  	// Find if container is connected to the default bridge network
   301  	var n libnetwork.Network
   302  	for name := range container.NetworkSettings.Networks {
   303  		sn, err := daemon.FindNetwork(name)
   304  		if err != nil {
   305  			continue
   306  		}
   307  		if sn.Name() == runconfig.DefaultDaemonNetworkMode().NetworkName() {
   308  			n = sn
   309  			break
   310  		}
   311  	}
   312  
   313  	if n == nil {
   314  		// Not connected to the default bridge network; Nothing to do
   315  		return nil
   316  	}
   317  
   318  	options, err := daemon.buildSandboxOptions(container)
   319  	if err != nil {
   320  		return fmt.Errorf("Update network failed: %v", err)
   321  	}
   322  
   323  	if err := sb.Refresh(options...); err != nil {
   324  		return fmt.Errorf("Update network failed: Failure in refresh sandbox %s: %v", sid, err)
   325  	}
   326  
   327  	return nil
   328  }
   329  
   330  func errClusterNetworkOnRun(n string) error {
   331  	return fmt.Errorf("swarm-scoped network (%s) is not compatible with `docker create` or `docker run`. This network can only be used by a docker service", n)
   332  }
   333  
   334  // updateContainerNetworkSettings update the network settings
   335  func (daemon *Daemon) updateContainerNetworkSettings(container *container.Container, endpointsConfig map[string]*networktypes.EndpointSettings) error {
   336  	var (
   337  		n   libnetwork.Network
   338  		err error
   339  	)
   340  
   341  	mode := container.HostConfig.NetworkMode
   342  	if container.Config.NetworkDisabled || mode.IsContainer() {
   343  		return nil
   344  	}
   345  
   346  	networkName := mode.NetworkName()
   347  	if mode.IsDefault() {
   348  		networkName = daemon.netController.Config().Daemon.DefaultNetwork
   349  	}
   350  	if mode.IsUserDefined() {
   351  		n, err = daemon.FindNetwork(networkName)
   352  		if err != nil {
   353  			return err
   354  		}
   355  		if !container.Managed && n.Info().Dynamic() {
   356  			return errClusterNetworkOnRun(networkName)
   357  		}
   358  		networkName = n.Name()
   359  	}
   360  	if container.NetworkSettings == nil {
   361  		container.NetworkSettings = &network.Settings{}
   362  	}
   363  	if len(endpointsConfig) > 0 {
   364  		container.NetworkSettings.Networks = endpointsConfig
   365  	}
   366  	if container.NetworkSettings.Networks == nil {
   367  		container.NetworkSettings.Networks = make(map[string]*networktypes.EndpointSettings)
   368  		container.NetworkSettings.Networks[networkName] = new(networktypes.EndpointSettings)
   369  	}
   370  	if !mode.IsUserDefined() {
   371  		return nil
   372  	}
   373  	// Make sure to internally store the per network endpoint config by network name
   374  	if _, ok := container.NetworkSettings.Networks[networkName]; ok {
   375  		return nil
   376  	}
   377  	if nwConfig, ok := container.NetworkSettings.Networks[n.ID()]; ok {
   378  		container.NetworkSettings.Networks[networkName] = nwConfig
   379  		delete(container.NetworkSettings.Networks, n.ID())
   380  		return nil
   381  	}
   382  
   383  	return nil
   384  }
   385  
   386  func (daemon *Daemon) allocateNetwork(container *container.Container) error {
   387  	controller := daemon.netController
   388  
   389  	if daemon.netController == nil {
   390  		return nil
   391  	}
   392  
   393  	// Cleanup any stale sandbox left over due to ungraceful daemon shutdown
   394  	if err := controller.SandboxDestroy(container.ID); err != nil {
   395  		logrus.Errorf("failed to cleanup up stale network sandbox for container %s", container.ID)
   396  	}
   397  
   398  	updateSettings := false
   399  	if len(container.NetworkSettings.Networks) == 0 {
   400  		if container.Config.NetworkDisabled || container.HostConfig.NetworkMode.IsContainer() {
   401  			return nil
   402  		}
   403  
   404  		err := daemon.updateContainerNetworkSettings(container, nil)
   405  		if err != nil {
   406  			return err
   407  		}
   408  		updateSettings = true
   409  	}
   410  
   411  	// always connect default network first since only default
   412  	// network mode support link and we need do some setting
   413  	// on sandbox initialize for link, but the sandbox only be initialized
   414  	// on first network connecting.
   415  	defaultNetName := runconfig.DefaultDaemonNetworkMode().NetworkName()
   416  	if nConf, ok := container.NetworkSettings.Networks[defaultNetName]; ok {
   417  		if err := daemon.connectToNetwork(container, defaultNetName, nConf, updateSettings); err != nil {
   418  			return err
   419  		}
   420  
   421  	}
   422  	for n, nConf := range container.NetworkSettings.Networks {
   423  		if n == defaultNetName {
   424  			continue
   425  		}
   426  		if err := daemon.connectToNetwork(container, n, nConf, updateSettings); err != nil {
   427  			return err
   428  		}
   429  	}
   430  
   431  	return container.WriteHostConfig()
   432  }
   433  
   434  func (daemon *Daemon) getNetworkSandbox(container *container.Container) libnetwork.Sandbox {
   435  	var sb libnetwork.Sandbox
   436  	daemon.netController.WalkSandboxes(func(s libnetwork.Sandbox) bool {
   437  		if s.ContainerID() == container.ID {
   438  			sb = s
   439  			return true
   440  		}
   441  		return false
   442  	})
   443  	return sb
   444  }
   445  
   446  // hasUserDefinedIPAddress returns whether the passed endpoint configuration contains IP address configuration
   447  func hasUserDefinedIPAddress(epConfig *networktypes.EndpointSettings) bool {
   448  	return epConfig != nil && epConfig.IPAMConfig != nil && (len(epConfig.IPAMConfig.IPv4Address) > 0 || len(epConfig.IPAMConfig.IPv6Address) > 0)
   449  }
   450  
   451  // User specified ip address is acceptable only for networks with user specified subnets.
   452  func validateNetworkingConfig(n libnetwork.Network, epConfig *networktypes.EndpointSettings) error {
   453  	if n == nil || epConfig == nil {
   454  		return nil
   455  	}
   456  	if !hasUserDefinedIPAddress(epConfig) {
   457  		return nil
   458  	}
   459  	_, _, nwIPv4Configs, nwIPv6Configs := n.Info().IpamConfig()
   460  	for _, s := range []struct {
   461  		ipConfigured  bool
   462  		subnetConfigs []*libnetwork.IpamConf
   463  	}{
   464  		{
   465  			ipConfigured:  len(epConfig.IPAMConfig.IPv4Address) > 0,
   466  			subnetConfigs: nwIPv4Configs,
   467  		},
   468  		{
   469  			ipConfigured:  len(epConfig.IPAMConfig.IPv6Address) > 0,
   470  			subnetConfigs: nwIPv6Configs,
   471  		},
   472  	} {
   473  		if s.ipConfigured {
   474  			foundSubnet := false
   475  			for _, cfg := range s.subnetConfigs {
   476  				if len(cfg.PreferredPool) > 0 {
   477  					foundSubnet = true
   478  					break
   479  				}
   480  			}
   481  			if !foundSubnet {
   482  				return runconfig.ErrUnsupportedNetworkNoSubnetAndIP
   483  			}
   484  		}
   485  	}
   486  
   487  	return nil
   488  }
   489  
   490  // cleanOperationalData resets the operational data from the passed endpoint settings
   491  func cleanOperationalData(es *networktypes.EndpointSettings) {
   492  	es.EndpointID = ""
   493  	es.Gateway = ""
   494  	es.IPAddress = ""
   495  	es.IPPrefixLen = 0
   496  	es.IPv6Gateway = ""
   497  	es.GlobalIPv6Address = ""
   498  	es.GlobalIPv6PrefixLen = 0
   499  	es.MacAddress = ""
   500  }
   501  
   502  func (daemon *Daemon) updateNetworkConfig(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (libnetwork.Network, error) {
   503  	if container.HostConfig.NetworkMode.IsContainer() {
   504  		return nil, runconfig.ErrConflictSharedNetwork
   505  	}
   506  
   507  	if containertypes.NetworkMode(idOrName).IsBridge() &&
   508  		daemon.configStore.DisableBridge {
   509  		container.Config.NetworkDisabled = true
   510  		return nil, nil
   511  	}
   512  
   513  	if !containertypes.NetworkMode(idOrName).IsUserDefined() {
   514  		if hasUserDefinedIPAddress(endpointConfig) {
   515  			return nil, runconfig.ErrUnsupportedNetworkAndIP
   516  		}
   517  		if endpointConfig != nil && len(endpointConfig.Aliases) > 0 {
   518  			return nil, runconfig.ErrUnsupportedNetworkAndAlias
   519  		}
   520  	} else {
   521  		addShortID := true
   522  		shortID := stringid.TruncateID(container.ID)
   523  		for _, alias := range endpointConfig.Aliases {
   524  			if alias == shortID {
   525  				addShortID = false
   526  				break
   527  			}
   528  		}
   529  		if addShortID {
   530  			endpointConfig.Aliases = append(endpointConfig.Aliases, shortID)
   531  		}
   532  	}
   533  
   534  	n, err := daemon.FindNetwork(idOrName)
   535  	if err != nil {
   536  		return nil, err
   537  	}
   538  
   539  	if err := validateNetworkingConfig(n, endpointConfig); err != nil {
   540  		return nil, err
   541  	}
   542  
   543  	if updateSettings {
   544  		if err := daemon.updateNetworkSettings(container, n); err != nil {
   545  			return nil, err
   546  		}
   547  	}
   548  	return n, nil
   549  }
   550  
   551  func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (err error) {
   552  	if endpointConfig == nil {
   553  		endpointConfig = &networktypes.EndpointSettings{}
   554  	}
   555  	n, err := daemon.updateNetworkConfig(container, idOrName, endpointConfig, updateSettings)
   556  	if err != nil {
   557  		return err
   558  	}
   559  	if n == nil {
   560  		return nil
   561  	}
   562  
   563  	controller := daemon.netController
   564  
   565  	sb := daemon.getNetworkSandbox(container)
   566  	createOptions, err := container.BuildCreateEndpointOptions(n, endpointConfig, sb)
   567  	if err != nil {
   568  		return err
   569  	}
   570  
   571  	endpointName := strings.TrimPrefix(container.Name, "/")
   572  	ep, err := n.CreateEndpoint(endpointName, createOptions...)
   573  	if err != nil {
   574  		return err
   575  	}
   576  	defer func() {
   577  		if err != nil {
   578  			if e := ep.Delete(false); e != nil {
   579  				logrus.Warnf("Could not rollback container connection to network %s", idOrName)
   580  			}
   581  		}
   582  	}()
   583  	container.NetworkSettings.Networks[n.Name()] = endpointConfig
   584  
   585  	if err := daemon.updateEndpointNetworkSettings(container, n, ep); err != nil {
   586  		return err
   587  	}
   588  
   589  	if sb == nil {
   590  		options, err := daemon.buildSandboxOptions(container)
   591  		if err != nil {
   592  			return err
   593  		}
   594  		sb, err = controller.NewSandbox(container.ID, options...)
   595  		if err != nil {
   596  			return err
   597  		}
   598  
   599  		container.UpdateSandboxNetworkSettings(sb)
   600  	}
   601  
   602  	joinOptions, err := container.BuildJoinOptions(n)
   603  	if err != nil {
   604  		return err
   605  	}
   606  
   607  	if err := ep.Join(sb, joinOptions...); err != nil {
   608  		return err
   609  	}
   610  
   611  	if err := container.UpdateJoinInfo(n, ep); err != nil {
   612  		return fmt.Errorf("Updating join info failed: %v", err)
   613  	}
   614  
   615  	container.NetworkSettings.Ports = getPortMapInfo(sb)
   616  
   617  	daemon.LogNetworkEventWithAttributes(n, "connect", map[string]string{"container": container.ID})
   618  	return nil
   619  }
   620  
   621  // ForceEndpointDelete deletes an endpoing from a network forcefully
   622  func (daemon *Daemon) ForceEndpointDelete(name string, n libnetwork.Network) error {
   623  	ep, err := n.EndpointByName(name)
   624  	if err != nil {
   625  		return err
   626  	}
   627  	return ep.Delete(true)
   628  }
   629  
   630  func disconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error {
   631  	var (
   632  		ep   libnetwork.Endpoint
   633  		sbox libnetwork.Sandbox
   634  	)
   635  
   636  	s := func(current libnetwork.Endpoint) bool {
   637  		epInfo := current.Info()
   638  		if epInfo == nil {
   639  			return false
   640  		}
   641  		if sb := epInfo.Sandbox(); sb != nil {
   642  			if sb.ContainerID() == container.ID {
   643  				ep = current
   644  				sbox = sb
   645  				return true
   646  			}
   647  		}
   648  		return false
   649  	}
   650  	n.WalkEndpoints(s)
   651  
   652  	if ep == nil && force {
   653  		epName := strings.TrimPrefix(container.Name, "/")
   654  		ep, err := n.EndpointByName(epName)
   655  		if err != nil {
   656  			return err
   657  		}
   658  		return ep.Delete(force)
   659  	}
   660  
   661  	if ep == nil {
   662  		return fmt.Errorf("container %s is not connected to the network", container.ID)
   663  	}
   664  
   665  	if err := ep.Leave(sbox); err != nil {
   666  		return fmt.Errorf("container %s failed to leave network %s: %v", container.ID, n.Name(), err)
   667  	}
   668  
   669  	container.NetworkSettings.Ports = getPortMapInfo(sbox)
   670  
   671  	if err := ep.Delete(false); err != nil {
   672  		return fmt.Errorf("endpoint delete failed for container %s on network %s: %v", container.ID, n.Name(), err)
   673  	}
   674  
   675  	delete(container.NetworkSettings.Networks, n.Name())
   676  	return nil
   677  }
   678  
   679  func (daemon *Daemon) initializeNetworking(container *container.Container) error {
   680  	var err error
   681  
   682  	if container.HostConfig.NetworkMode.IsContainer() {
   683  		// we need to get the hosts files from the container to join
   684  		nc, err := daemon.getNetworkedContainer(container.ID, container.HostConfig.NetworkMode.ConnectedContainer())
   685  		if err != nil {
   686  			return err
   687  		}
   688  		container.HostnamePath = nc.HostnamePath
   689  		container.HostsPath = nc.HostsPath
   690  		container.ResolvConfPath = nc.ResolvConfPath
   691  		container.Config.Hostname = nc.Config.Hostname
   692  		container.Config.Domainname = nc.Config.Domainname
   693  		return nil
   694  	}
   695  
   696  	if container.HostConfig.NetworkMode.IsHost() {
   697  		container.Config.Hostname, err = os.Hostname()
   698  		if err != nil {
   699  			return err
   700  		}
   701  	}
   702  
   703  	if err := daemon.allocateNetwork(container); err != nil {
   704  		return err
   705  	}
   706  
   707  	return container.BuildHostnameFile()
   708  }
   709  
   710  func (daemon *Daemon) getNetworkedContainer(containerID, connectedContainerID string) (*container.Container, error) {
   711  	nc, err := daemon.GetContainer(connectedContainerID)
   712  	if err != nil {
   713  		return nil, err
   714  	}
   715  	if containerID == nc.ID {
   716  		return nil, fmt.Errorf("cannot join own network")
   717  	}
   718  	if !nc.IsRunning() {
   719  		err := fmt.Errorf("cannot join network of a non running container: %s", connectedContainerID)
   720  		return nil, derr.NewRequestConflictError(err)
   721  	}
   722  	if nc.IsRestarting() {
   723  		return nil, errContainerIsRestarting(connectedContainerID)
   724  	}
   725  	return nc, nil
   726  }
   727  
   728  func (daemon *Daemon) releaseNetwork(container *container.Container) {
   729  	if daemon.netController == nil {
   730  		return
   731  	}
   732  	if container.HostConfig.NetworkMode.IsContainer() || container.Config.NetworkDisabled {
   733  		return
   734  	}
   735  
   736  	sid := container.NetworkSettings.SandboxID
   737  	settings := container.NetworkSettings.Networks
   738  	container.NetworkSettings.Ports = nil
   739  
   740  	if sid == "" || len(settings) == 0 {
   741  		return
   742  	}
   743  
   744  	var networks []libnetwork.Network
   745  	for n, epSettings := range settings {
   746  		if nw, err := daemon.FindNetwork(n); err == nil {
   747  			networks = append(networks, nw)
   748  		}
   749  		cleanOperationalData(epSettings)
   750  	}
   751  
   752  	sb, err := daemon.netController.SandboxByID(sid)
   753  	if err != nil {
   754  		logrus.Warnf("error locating sandbox id %s: %v", sid, err)
   755  		return
   756  	}
   757  
   758  	if err := sb.Delete(); err != nil {
   759  		logrus.Errorf("Error deleting sandbox id %s for container %s: %v", sid, container.ID, err)
   760  	}
   761  
   762  	for _, nw := range networks {
   763  		attributes := map[string]string{
   764  			"container": container.ID,
   765  		}
   766  		daemon.LogNetworkEventWithAttributes(nw, "disconnect", attributes)
   767  	}
   768  }