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