github.com/uppal0016/docker_new@v0.0.0-20240123060250-1c98be13ac2c/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 {
    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  	mode := container.HostConfig.NetworkMode
   327  	if container.Config.NetworkDisabled || mode.IsContainer() {
   328  		return nil
   329  	}
   330  
   331  	networkName := mode.NetworkName()
   332  	if mode.IsDefault() {
   333  		networkName = daemon.netController.Config().Daemon.DefaultNetwork
   334  	}
   335  	if mode.IsUserDefined() {
   336  		n, err = daemon.FindNetwork(networkName)
   337  		if err != nil {
   338  			return err
   339  		}
   340  		networkName = n.Name()
   341  	}
   342  	if container.NetworkSettings == nil {
   343  		container.NetworkSettings = &network.Settings{}
   344  	}
   345  	if len(endpointsConfig) > 0 {
   346  		container.NetworkSettings.Networks = endpointsConfig
   347  	}
   348  	if container.NetworkSettings.Networks == nil {
   349  		container.NetworkSettings.Networks = make(map[string]*networktypes.EndpointSettings)
   350  		container.NetworkSettings.Networks[networkName] = new(networktypes.EndpointSettings)
   351  	}
   352  	if !mode.IsUserDefined() {
   353  		return nil
   354  	}
   355  	// Make sure to internally store the per network endpoint config by network name
   356  	if _, ok := container.NetworkSettings.Networks[networkName]; ok {
   357  		return nil
   358  	}
   359  	if nwConfig, ok := container.NetworkSettings.Networks[n.ID()]; ok {
   360  		container.NetworkSettings.Networks[networkName] = nwConfig
   361  		delete(container.NetworkSettings.Networks, n.ID())
   362  		return nil
   363  	}
   364  
   365  	return nil
   366  }
   367  
   368  func (daemon *Daemon) allocateNetwork(container *container.Container) error {
   369  	controller := daemon.netController
   370  
   371  	if daemon.netController == nil {
   372  		return nil
   373  	}
   374  
   375  	// Cleanup any stale sandbox left over due to ungraceful daemon shutdown
   376  	if err := controller.SandboxDestroy(container.ID); err != nil {
   377  		logrus.Errorf("failed to cleanup up stale network sandbox for container %s", container.ID)
   378  	}
   379  
   380  	updateSettings := false
   381  	if len(container.NetworkSettings.Networks) == 0 {
   382  		if container.Config.NetworkDisabled || container.HostConfig.NetworkMode.IsContainer() {
   383  			return nil
   384  		}
   385  
   386  		err := daemon.updateContainerNetworkSettings(container, nil)
   387  		if err != nil {
   388  			return err
   389  		}
   390  		updateSettings = true
   391  	}
   392  
   393  	for n, nConf := range container.NetworkSettings.Networks {
   394  		if err := daemon.connectToNetwork(container, n, nConf, updateSettings); err != nil {
   395  			return err
   396  		}
   397  	}
   398  
   399  	return container.WriteHostConfig()
   400  }
   401  
   402  func (daemon *Daemon) getNetworkSandbox(container *container.Container) libnetwork.Sandbox {
   403  	var sb libnetwork.Sandbox
   404  	daemon.netController.WalkSandboxes(func(s libnetwork.Sandbox) bool {
   405  		if s.ContainerID() == container.ID {
   406  			sb = s
   407  			return true
   408  		}
   409  		return false
   410  	})
   411  	return sb
   412  }
   413  
   414  // hasUserDefinedIPAddress returns whether the passed endpoint configuration contains IP address configuration
   415  func hasUserDefinedIPAddress(epConfig *networktypes.EndpointSettings) bool {
   416  	return epConfig != nil && epConfig.IPAMConfig != nil && (len(epConfig.IPAMConfig.IPv4Address) > 0 || len(epConfig.IPAMConfig.IPv6Address) > 0)
   417  }
   418  
   419  // User specified ip address is acceptable only for networks with user specified subnets.
   420  func validateNetworkingConfig(n libnetwork.Network, epConfig *networktypes.EndpointSettings) error {
   421  	if n == nil || epConfig == nil {
   422  		return nil
   423  	}
   424  	if !hasUserDefinedIPAddress(epConfig) {
   425  		return nil
   426  	}
   427  	_, _, nwIPv4Configs, nwIPv6Configs := n.Info().IpamConfig()
   428  	for _, s := range []struct {
   429  		ipConfigured  bool
   430  		subnetConfigs []*libnetwork.IpamConf
   431  	}{
   432  		{
   433  			ipConfigured:  len(epConfig.IPAMConfig.IPv4Address) > 0,
   434  			subnetConfigs: nwIPv4Configs,
   435  		},
   436  		{
   437  			ipConfigured:  len(epConfig.IPAMConfig.IPv6Address) > 0,
   438  			subnetConfigs: nwIPv6Configs,
   439  		},
   440  	} {
   441  		if s.ipConfigured {
   442  			foundSubnet := false
   443  			for _, cfg := range s.subnetConfigs {
   444  				if len(cfg.PreferredPool) > 0 {
   445  					foundSubnet = true
   446  					break
   447  				}
   448  			}
   449  			if !foundSubnet {
   450  				return runconfig.ErrUnsupportedNetworkNoSubnetAndIP
   451  			}
   452  		}
   453  	}
   454  
   455  	return nil
   456  }
   457  
   458  // cleanOperationalData resets the operational data from the passed endpoint settings
   459  func cleanOperationalData(es *networktypes.EndpointSettings) {
   460  	es.EndpointID = ""
   461  	es.Gateway = ""
   462  	es.IPAddress = ""
   463  	es.IPPrefixLen = 0
   464  	es.IPv6Gateway = ""
   465  	es.GlobalIPv6Address = ""
   466  	es.GlobalIPv6PrefixLen = 0
   467  	es.MacAddress = ""
   468  }
   469  
   470  func (daemon *Daemon) updateNetworkConfig(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (libnetwork.Network, error) {
   471  	if container.HostConfig.NetworkMode.IsContainer() {
   472  		return nil, runconfig.ErrConflictSharedNetwork
   473  	}
   474  
   475  	if containertypes.NetworkMode(idOrName).IsBridge() &&
   476  		daemon.configStore.DisableBridge {
   477  		container.Config.NetworkDisabled = true
   478  		return nil, nil
   479  	}
   480  
   481  	if !containertypes.NetworkMode(idOrName).IsUserDefined() {
   482  		if hasUserDefinedIPAddress(endpointConfig) {
   483  			return nil, runconfig.ErrUnsupportedNetworkAndIP
   484  		}
   485  		if endpointConfig != nil && len(endpointConfig.Aliases) > 0 {
   486  			return nil, runconfig.ErrUnsupportedNetworkAndAlias
   487  		}
   488  	}
   489  
   490  	n, err := daemon.FindNetwork(idOrName)
   491  	if err != nil {
   492  		return nil, err
   493  	}
   494  
   495  	if err := validateNetworkingConfig(n, endpointConfig); err != nil {
   496  		return nil, err
   497  	}
   498  
   499  	if updateSettings {
   500  		if err := daemon.updateNetworkSettings(container, n); err != nil {
   501  			return nil, err
   502  		}
   503  	}
   504  	return n, nil
   505  }
   506  
   507  func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (err error) {
   508  	n, err := daemon.updateNetworkConfig(container, idOrName, endpointConfig, updateSettings)
   509  	if err != nil {
   510  		return err
   511  	}
   512  	if n == nil {
   513  		return nil
   514  	}
   515  
   516  	controller := daemon.netController
   517  
   518  	sb := daemon.getNetworkSandbox(container)
   519  	createOptions, err := container.BuildCreateEndpointOptions(n, endpointConfig, sb)
   520  	if err != nil {
   521  		return err
   522  	}
   523  
   524  	endpointName := strings.TrimPrefix(container.Name, "/")
   525  	ep, err := n.CreateEndpoint(endpointName, createOptions...)
   526  	if err != nil {
   527  		return err
   528  	}
   529  	defer func() {
   530  		if err != nil {
   531  			if e := ep.Delete(false); e != nil {
   532  				logrus.Warnf("Could not rollback container connection to network %s", idOrName)
   533  			}
   534  		}
   535  	}()
   536  
   537  	if endpointConfig != nil {
   538  		container.NetworkSettings.Networks[n.Name()] = endpointConfig
   539  	}
   540  
   541  	if err := daemon.updateEndpointNetworkSettings(container, n, ep); err != nil {
   542  		return err
   543  	}
   544  
   545  	if sb == nil {
   546  		options, err := daemon.buildSandboxOptions(container, n)
   547  		if err != nil {
   548  			return err
   549  		}
   550  		sb, err = controller.NewSandbox(container.ID, options...)
   551  		if err != nil {
   552  			return err
   553  		}
   554  
   555  		container.UpdateSandboxNetworkSettings(sb)
   556  	}
   557  
   558  	joinOptions, err := container.BuildJoinOptions(n)
   559  	if err != nil {
   560  		return err
   561  	}
   562  
   563  	if err := ep.Join(sb, joinOptions...); err != nil {
   564  		return err
   565  	}
   566  
   567  	if err := container.UpdateJoinInfo(n, ep); err != nil {
   568  		return fmt.Errorf("Updating join info failed: %v", err)
   569  	}
   570  
   571  	daemon.LogNetworkEventWithAttributes(n, "connect", map[string]string{"container": container.ID})
   572  	return nil
   573  }
   574  
   575  // ForceEndpointDelete deletes an endpoing from a network forcefully
   576  func (daemon *Daemon) ForceEndpointDelete(name string, n libnetwork.Network) error {
   577  	ep, err := n.EndpointByName(name)
   578  	if err != nil {
   579  		return err
   580  	}
   581  	return ep.Delete(true)
   582  }
   583  
   584  func disconnectFromNetwork(container *container.Container, n libnetwork.Network, force bool) error {
   585  	var (
   586  		ep   libnetwork.Endpoint
   587  		sbox libnetwork.Sandbox
   588  	)
   589  
   590  	s := func(current libnetwork.Endpoint) bool {
   591  		epInfo := current.Info()
   592  		if epInfo == nil {
   593  			return false
   594  		}
   595  		if sb := epInfo.Sandbox(); sb != nil {
   596  			if sb.ContainerID() == container.ID {
   597  				ep = current
   598  				sbox = sb
   599  				return true
   600  			}
   601  		}
   602  		return false
   603  	}
   604  	n.WalkEndpoints(s)
   605  
   606  	if ep == nil && force {
   607  		epName := strings.TrimPrefix(container.Name, "/")
   608  		ep, err := n.EndpointByName(epName)
   609  		if err != nil {
   610  			return err
   611  		}
   612  		return ep.Delete(force)
   613  	}
   614  
   615  	if ep == nil {
   616  		return fmt.Errorf("container %s is not connected to the network", container.ID)
   617  	}
   618  
   619  	if err := ep.Leave(sbox); err != nil {
   620  		return fmt.Errorf("container %s failed to leave network %s: %v", container.ID, n.Name(), err)
   621  	}
   622  
   623  	if err := ep.Delete(false); err != nil {
   624  		return fmt.Errorf("endpoint delete failed for container %s on network %s: %v", container.ID, n.Name(), err)
   625  	}
   626  
   627  	delete(container.NetworkSettings.Networks, n.Name())
   628  	return nil
   629  }
   630  
   631  func (daemon *Daemon) initializeNetworking(container *container.Container) error {
   632  	var err error
   633  
   634  	if container.HostConfig.NetworkMode.IsContainer() {
   635  		// we need to get the hosts files from the container to join
   636  		nc, err := daemon.getNetworkedContainer(container.ID, container.HostConfig.NetworkMode.ConnectedContainer())
   637  		if err != nil {
   638  			return err
   639  		}
   640  		container.HostnamePath = nc.HostnamePath
   641  		container.HostsPath = nc.HostsPath
   642  		container.ResolvConfPath = nc.ResolvConfPath
   643  		container.Config.Hostname = nc.Config.Hostname
   644  		container.Config.Domainname = nc.Config.Domainname
   645  		return nil
   646  	}
   647  
   648  	if container.HostConfig.NetworkMode.IsHost() {
   649  		container.Config.Hostname, err = os.Hostname()
   650  		if err != nil {
   651  			return err
   652  		}
   653  	}
   654  
   655  	if err := daemon.allocateNetwork(container); err != nil {
   656  		return err
   657  	}
   658  
   659  	return container.BuildHostnameFile()
   660  }
   661  
   662  func (daemon *Daemon) getNetworkedContainer(containerID, connectedContainerID string) (*container.Container, error) {
   663  	nc, err := daemon.GetContainer(connectedContainerID)
   664  	if err != nil {
   665  		return nil, err
   666  	}
   667  	if containerID == nc.ID {
   668  		return nil, fmt.Errorf("cannot join own network")
   669  	}
   670  	if !nc.IsRunning() {
   671  		err := fmt.Errorf("cannot join network of a non running container: %s", connectedContainerID)
   672  		return nil, derr.NewRequestConflictError(err)
   673  	}
   674  	if nc.IsRestarting() {
   675  		return nil, errContainerIsRestarting(connectedContainerID)
   676  	}
   677  	return nc, nil
   678  }
   679  
   680  func (daemon *Daemon) releaseNetwork(container *container.Container) {
   681  	if container.HostConfig.NetworkMode.IsContainer() || container.Config.NetworkDisabled {
   682  		return
   683  	}
   684  
   685  	sid := container.NetworkSettings.SandboxID
   686  	settings := container.NetworkSettings.Networks
   687  	container.NetworkSettings.Ports = nil
   688  
   689  	if sid == "" || len(settings) == 0 {
   690  		return
   691  	}
   692  
   693  	var networks []libnetwork.Network
   694  	for n, epSettings := range settings {
   695  		if nw, err := daemon.FindNetwork(n); err == nil {
   696  			networks = append(networks, nw)
   697  		}
   698  		cleanOperationalData(epSettings)
   699  	}
   700  
   701  	sb, err := daemon.netController.SandboxByID(sid)
   702  	if err != nil {
   703  		logrus.Warnf("error locating sandbox id %s: %v", sid, err)
   704  		return
   705  	}
   706  
   707  	if err := sb.Delete(); err != nil {
   708  		logrus.Errorf("Error deleting sandbox id %s for container %s: %v", sid, container.ID, err)
   709  	}
   710  
   711  	attributes := map[string]string{
   712  		"container": container.ID,
   713  	}
   714  	for _, nw := range networks {
   715  		daemon.LogNetworkEventWithAttributes(nw, "disconnect", attributes)
   716  	}
   717  }