github.com/kobeld/docker@v1.12.0-rc1/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  	if _, ok := container.NetworkSettings.Networks[defaultNetName]; !container.HostConfig.NetworkMode.IsDefault() || !ok {
   181  		return sboxOptions, nil
   182  	}
   183  
   184  	if container.NetworkSettings.Networks[defaultNetName].EndpointID == "" {
   185  		return sboxOptions, nil
   186  	}
   187  
   188  	var (
   189  		childEndpoints, parentEndpoints []string
   190  		cEndpointID                     string
   191  	)
   192  
   193  	children := daemon.children(container)
   194  	for linkAlias, child := range children {
   195  		if !isLinkable(child) {
   196  			return nil, fmt.Errorf("Cannot link to %s, as it does not belong to the default network", child.Name)
   197  		}
   198  		_, alias := path.Split(linkAlias)
   199  		// allow access to the linked container via the alias, real name, and container hostname
   200  		aliasList := alias + " " + child.Config.Hostname
   201  		// only add the name if alias isn't equal to the name
   202  		if alias != child.Name[1:] {
   203  			aliasList = aliasList + " " + child.Name[1:]
   204  		}
   205  		sboxOptions = append(sboxOptions, libnetwork.OptionExtraHost(aliasList, child.NetworkSettings.Networks[defaultNetName].IPAddress))
   206  		cEndpointID = child.NetworkSettings.Networks[defaultNetName].EndpointID
   207  		if cEndpointID != "" {
   208  			childEndpoints = append(childEndpoints, cEndpointID)
   209  		}
   210  	}
   211  
   212  	bridgeSettings := container.NetworkSettings.Networks[defaultNetName]
   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 be only used 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  	for n, nConf := range container.NetworkSettings.Networks {
   412  		if err := daemon.connectToNetwork(container, n, nConf, updateSettings); err != nil {
   413  			return err
   414  		}
   415  	}
   416  
   417  	return container.WriteHostConfig()
   418  }
   419  
   420  func (daemon *Daemon) getNetworkSandbox(container *container.Container) libnetwork.Sandbox {
   421  	var sb libnetwork.Sandbox
   422  	daemon.netController.WalkSandboxes(func(s libnetwork.Sandbox) bool {
   423  		if s.ContainerID() == container.ID {
   424  			sb = s
   425  			return true
   426  		}
   427  		return false
   428  	})
   429  	return sb
   430  }
   431  
   432  // hasUserDefinedIPAddress returns whether the passed endpoint configuration contains IP address configuration
   433  func hasUserDefinedIPAddress(epConfig *networktypes.EndpointSettings) bool {
   434  	return epConfig != nil && epConfig.IPAMConfig != nil && (len(epConfig.IPAMConfig.IPv4Address) > 0 || len(epConfig.IPAMConfig.IPv6Address) > 0)
   435  }
   436  
   437  // User specified ip address is acceptable only for networks with user specified subnets.
   438  func validateNetworkingConfig(n libnetwork.Network, epConfig *networktypes.EndpointSettings) error {
   439  	if n == nil || epConfig == nil {
   440  		return nil
   441  	}
   442  	if !hasUserDefinedIPAddress(epConfig) {
   443  		return nil
   444  	}
   445  	_, _, nwIPv4Configs, nwIPv6Configs := n.Info().IpamConfig()
   446  	for _, s := range []struct {
   447  		ipConfigured  bool
   448  		subnetConfigs []*libnetwork.IpamConf
   449  	}{
   450  		{
   451  			ipConfigured:  len(epConfig.IPAMConfig.IPv4Address) > 0,
   452  			subnetConfigs: nwIPv4Configs,
   453  		},
   454  		{
   455  			ipConfigured:  len(epConfig.IPAMConfig.IPv6Address) > 0,
   456  			subnetConfigs: nwIPv6Configs,
   457  		},
   458  	} {
   459  		if s.ipConfigured {
   460  			foundSubnet := false
   461  			for _, cfg := range s.subnetConfigs {
   462  				if len(cfg.PreferredPool) > 0 {
   463  					foundSubnet = true
   464  					break
   465  				}
   466  			}
   467  			if !foundSubnet {
   468  				return runconfig.ErrUnsupportedNetworkNoSubnetAndIP
   469  			}
   470  		}
   471  	}
   472  
   473  	return nil
   474  }
   475  
   476  // cleanOperationalData resets the operational data from the passed endpoint settings
   477  func cleanOperationalData(es *networktypes.EndpointSettings) {
   478  	es.EndpointID = ""
   479  	es.Gateway = ""
   480  	es.IPAddress = ""
   481  	es.IPPrefixLen = 0
   482  	es.IPv6Gateway = ""
   483  	es.GlobalIPv6Address = ""
   484  	es.GlobalIPv6PrefixLen = 0
   485  	es.MacAddress = ""
   486  }
   487  
   488  func (daemon *Daemon) updateNetworkConfig(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (libnetwork.Network, error) {
   489  	if container.HostConfig.NetworkMode.IsContainer() {
   490  		return nil, runconfig.ErrConflictSharedNetwork
   491  	}
   492  
   493  	if containertypes.NetworkMode(idOrName).IsBridge() &&
   494  		daemon.configStore.DisableBridge {
   495  		container.Config.NetworkDisabled = true
   496  		return nil, nil
   497  	}
   498  
   499  	if !containertypes.NetworkMode(idOrName).IsUserDefined() {
   500  		if hasUserDefinedIPAddress(endpointConfig) {
   501  			return nil, runconfig.ErrUnsupportedNetworkAndIP
   502  		}
   503  		if endpointConfig != nil && len(endpointConfig.Aliases) > 0 {
   504  			return nil, runconfig.ErrUnsupportedNetworkAndAlias
   505  		}
   506  	} else {
   507  		addShortID := true
   508  		shortID := stringid.TruncateID(container.ID)
   509  		for _, alias := range endpointConfig.Aliases {
   510  			if alias == shortID {
   511  				addShortID = false
   512  				break
   513  			}
   514  		}
   515  		if addShortID {
   516  			endpointConfig.Aliases = append(endpointConfig.Aliases, shortID)
   517  		}
   518  	}
   519  
   520  	n, err := daemon.FindNetwork(idOrName)
   521  	if err != nil {
   522  		return nil, err
   523  	}
   524  
   525  	if err := validateNetworkingConfig(n, endpointConfig); err != nil {
   526  		return nil, err
   527  	}
   528  
   529  	if updateSettings {
   530  		if err := daemon.updateNetworkSettings(container, n); err != nil {
   531  			return nil, err
   532  		}
   533  	}
   534  	return n, nil
   535  }
   536  
   537  func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (err error) {
   538  	if endpointConfig == nil {
   539  		endpointConfig = &networktypes.EndpointSettings{}
   540  	}
   541  	n, err := daemon.updateNetworkConfig(container, idOrName, endpointConfig, updateSettings)
   542  	if err != nil {
   543  		return err
   544  	}
   545  	if n == nil {
   546  		return nil
   547  	}
   548  
   549  	controller := daemon.netController
   550  
   551  	sb := daemon.getNetworkSandbox(container)
   552  	createOptions, err := container.BuildCreateEndpointOptions(n, endpointConfig, sb)
   553  	if err != nil {
   554  		return err
   555  	}
   556  
   557  	endpointName := strings.TrimPrefix(container.Name, "/")
   558  	ep, err := n.CreateEndpoint(endpointName, createOptions...)
   559  	if err != nil {
   560  		return err
   561  	}
   562  	defer func() {
   563  		if err != nil {
   564  			if e := ep.Delete(false); e != nil {
   565  				logrus.Warnf("Could not rollback container connection to network %s", idOrName)
   566  			}
   567  		}
   568  	}()
   569  	container.NetworkSettings.Networks[n.Name()] = endpointConfig
   570  
   571  	if err := daemon.updateEndpointNetworkSettings(container, n, ep); err != nil {
   572  		return err
   573  	}
   574  
   575  	if sb == nil {
   576  		options, err := daemon.buildSandboxOptions(container)
   577  		if err != nil {
   578  			return err
   579  		}
   580  		sb, err = controller.NewSandbox(container.ID, options...)
   581  		if err != nil {
   582  			return err
   583  		}
   584  
   585  		container.UpdateSandboxNetworkSettings(sb)
   586  	}
   587  
   588  	joinOptions, err := container.BuildJoinOptions(n)
   589  	if err != nil {
   590  		return err
   591  	}
   592  
   593  	if err := ep.Join(sb, joinOptions...); err != nil {
   594  		return err
   595  	}
   596  
   597  	if err := container.UpdateJoinInfo(n, ep); err != nil {
   598  		return fmt.Errorf("Updating join info failed: %v", err)
   599  	}
   600  
   601  	container.NetworkSettings.Ports = getPortMapInfo(sb)
   602  
   603  	daemon.LogNetworkEventWithAttributes(n, "connect", map[string]string{"container": container.ID})
   604  	return nil
   605  }
   606  
   607  // ForceEndpointDelete deletes an endpoing from a network forcefully
   608  func (daemon *Daemon) ForceEndpointDelete(name string, n libnetwork.Network) error {
   609  	ep, err := n.EndpointByName(name)
   610  	if err != nil {
   611  		return err
   612  	}
   613  	return ep.Delete(true)
   614  }
   615  
   616  func disconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error {
   617  	var (
   618  		ep   libnetwork.Endpoint
   619  		sbox libnetwork.Sandbox
   620  	)
   621  
   622  	s := func(current libnetwork.Endpoint) bool {
   623  		epInfo := current.Info()
   624  		if epInfo == nil {
   625  			return false
   626  		}
   627  		if sb := epInfo.Sandbox(); sb != nil {
   628  			if sb.ContainerID() == container.ID {
   629  				ep = current
   630  				sbox = sb
   631  				return true
   632  			}
   633  		}
   634  		return false
   635  	}
   636  	n.WalkEndpoints(s)
   637  
   638  	if ep == nil && force {
   639  		epName := strings.TrimPrefix(container.Name, "/")
   640  		ep, err := n.EndpointByName(epName)
   641  		if err != nil {
   642  			return err
   643  		}
   644  		return ep.Delete(force)
   645  	}
   646  
   647  	if ep == nil {
   648  		return fmt.Errorf("container %s is not connected to the network", container.ID)
   649  	}
   650  
   651  	if err := ep.Leave(sbox); err != nil {
   652  		return fmt.Errorf("container %s failed to leave network %s: %v", container.ID, n.Name(), err)
   653  	}
   654  
   655  	container.NetworkSettings.Ports = getPortMapInfo(sbox)
   656  
   657  	if err := ep.Delete(false); err != nil {
   658  		return fmt.Errorf("endpoint delete failed for container %s on network %s: %v", container.ID, n.Name(), err)
   659  	}
   660  
   661  	delete(container.NetworkSettings.Networks, n.Name())
   662  	return nil
   663  }
   664  
   665  func (daemon *Daemon) initializeNetworking(container *container.Container) error {
   666  	var err error
   667  
   668  	if container.HostConfig.NetworkMode.IsContainer() {
   669  		// we need to get the hosts files from the container to join
   670  		nc, err := daemon.getNetworkedContainer(container.ID, container.HostConfig.NetworkMode.ConnectedContainer())
   671  		if err != nil {
   672  			return err
   673  		}
   674  		container.HostnamePath = nc.HostnamePath
   675  		container.HostsPath = nc.HostsPath
   676  		container.ResolvConfPath = nc.ResolvConfPath
   677  		container.Config.Hostname = nc.Config.Hostname
   678  		container.Config.Domainname = nc.Config.Domainname
   679  		return nil
   680  	}
   681  
   682  	if container.HostConfig.NetworkMode.IsHost() {
   683  		container.Config.Hostname, err = os.Hostname()
   684  		if err != nil {
   685  			return err
   686  		}
   687  	}
   688  
   689  	if err := daemon.allocateNetwork(container); err != nil {
   690  		return err
   691  	}
   692  
   693  	return container.BuildHostnameFile()
   694  }
   695  
   696  func (daemon *Daemon) getNetworkedContainer(containerID, connectedContainerID string) (*container.Container, error) {
   697  	nc, err := daemon.GetContainer(connectedContainerID)
   698  	if err != nil {
   699  		return nil, err
   700  	}
   701  	if containerID == nc.ID {
   702  		return nil, fmt.Errorf("cannot join own network")
   703  	}
   704  	if !nc.IsRunning() {
   705  		err := fmt.Errorf("cannot join network of a non running container: %s", connectedContainerID)
   706  		return nil, derr.NewRequestConflictError(err)
   707  	}
   708  	if nc.IsRestarting() {
   709  		return nil, errContainerIsRestarting(connectedContainerID)
   710  	}
   711  	return nc, nil
   712  }
   713  
   714  func (daemon *Daemon) releaseNetwork(container *container.Container) {
   715  	if daemon.netController == nil {
   716  		return
   717  	}
   718  	if container.HostConfig.NetworkMode.IsContainer() || container.Config.NetworkDisabled {
   719  		return
   720  	}
   721  
   722  	sid := container.NetworkSettings.SandboxID
   723  	settings := container.NetworkSettings.Networks
   724  	container.NetworkSettings.Ports = nil
   725  
   726  	if sid == "" || len(settings) == 0 {
   727  		return
   728  	}
   729  
   730  	var networks []libnetwork.Network
   731  	for n, epSettings := range settings {
   732  		if nw, err := daemon.FindNetwork(n); err == nil {
   733  			networks = append(networks, nw)
   734  		}
   735  		cleanOperationalData(epSettings)
   736  	}
   737  
   738  	sb, err := daemon.netController.SandboxByID(sid)
   739  	if err != nil {
   740  		logrus.Warnf("error locating sandbox id %s: %v", sid, err)
   741  		return
   742  	}
   743  
   744  	if err := sb.Delete(); err != nil {
   745  		logrus.Errorf("Error deleting sandbox id %s for container %s: %v", sid, container.ID, err)
   746  	}
   747  
   748  	for _, nw := range networks {
   749  		attributes := map[string]string{
   750  			"container": container.ID,
   751  		}
   752  		daemon.LogNetworkEventWithAttributes(nw, "disconnect", attributes)
   753  	}
   754  }