github.com/jandre/docker@v1.7.0/daemon/container_linux.go (about)

     1  // +build linux
     2  
     3  package daemon
     4  
     5  import (
     6  	"fmt"
     7  	"io/ioutil"
     8  	"net"
     9  	"os"
    10  	"path"
    11  	"path/filepath"
    12  	"strconv"
    13  	"strings"
    14  	"syscall"
    15  	"time"
    16  
    17  	"github.com/Sirupsen/logrus"
    18  	"github.com/docker/docker/daemon/execdriver"
    19  	"github.com/docker/docker/daemon/network"
    20  	"github.com/docker/docker/links"
    21  	"github.com/docker/docker/nat"
    22  	"github.com/docker/docker/pkg/archive"
    23  	"github.com/docker/docker/pkg/directory"
    24  	"github.com/docker/docker/pkg/ioutils"
    25  	"github.com/docker/docker/pkg/stringid"
    26  	"github.com/docker/docker/pkg/ulimit"
    27  	"github.com/docker/docker/runconfig"
    28  	"github.com/docker/docker/utils"
    29  	"github.com/docker/libcontainer/configs"
    30  	"github.com/docker/libcontainer/devices"
    31  	"github.com/docker/libnetwork"
    32  	"github.com/docker/libnetwork/netlabel"
    33  	"github.com/docker/libnetwork/options"
    34  	"github.com/docker/libnetwork/types"
    35  )
    36  
    37  const DefaultPathEnv = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
    38  
    39  type Container struct {
    40  	CommonContainer
    41  
    42  	// Fields below here are platform specific.
    43  
    44  	AppArmorProfile string
    45  	activeLinks     map[string]*links.Link
    46  }
    47  
    48  func killProcessDirectly(container *Container) error {
    49  	if _, err := container.WaitStop(10 * time.Second); err != nil {
    50  		// Ensure that we don't kill ourselves
    51  		if pid := container.GetPid(); pid != 0 {
    52  			logrus.Infof("Container %s failed to exit within 10 seconds of kill - trying direct SIGKILL", stringid.TruncateID(container.ID))
    53  			if err := syscall.Kill(pid, 9); err != nil {
    54  				if err != syscall.ESRCH {
    55  					return err
    56  				}
    57  				logrus.Debugf("Cannot kill process (pid=%d) with signal 9: no such process.", pid)
    58  			}
    59  		}
    60  	}
    61  	return nil
    62  }
    63  
    64  func (container *Container) setupLinkedContainers() ([]string, error) {
    65  	var (
    66  		env    []string
    67  		daemon = container.daemon
    68  	)
    69  	children, err := daemon.Children(container.Name)
    70  	if err != nil {
    71  		return nil, err
    72  	}
    73  
    74  	if len(children) > 0 {
    75  		container.activeLinks = make(map[string]*links.Link, len(children))
    76  
    77  		// If we encounter an error make sure that we rollback any network
    78  		// config and iptables changes
    79  		rollback := func() {
    80  			for _, link := range container.activeLinks {
    81  				link.Disable()
    82  			}
    83  			container.activeLinks = nil
    84  		}
    85  
    86  		for linkAlias, child := range children {
    87  			if !child.IsRunning() {
    88  				return nil, fmt.Errorf("Cannot link to a non running container: %s AS %s", child.Name, linkAlias)
    89  			}
    90  
    91  			link, err := links.NewLink(
    92  				container.NetworkSettings.IPAddress,
    93  				child.NetworkSettings.IPAddress,
    94  				linkAlias,
    95  				child.Config.Env,
    96  				child.Config.ExposedPorts,
    97  			)
    98  
    99  			if err != nil {
   100  				rollback()
   101  				return nil, err
   102  			}
   103  
   104  			container.activeLinks[link.Alias()] = link
   105  			if err := link.Enable(); err != nil {
   106  				rollback()
   107  				return nil, err
   108  			}
   109  
   110  			for _, envVar := range link.ToEnv() {
   111  				env = append(env, envVar)
   112  			}
   113  		}
   114  	}
   115  	return env, nil
   116  }
   117  
   118  func (container *Container) createDaemonEnvironment(linkedEnv []string) []string {
   119  	// if a domain name was specified, append it to the hostname (see #7851)
   120  	fullHostname := container.Config.Hostname
   121  	if container.Config.Domainname != "" {
   122  		fullHostname = fmt.Sprintf("%s.%s", fullHostname, container.Config.Domainname)
   123  	}
   124  	// Setup environment
   125  	env := []string{
   126  		"PATH=" + DefaultPathEnv,
   127  		"HOSTNAME=" + fullHostname,
   128  		// Note: we don't set HOME here because it'll get autoset intelligently
   129  		// based on the value of USER inside dockerinit, but only if it isn't
   130  		// set already (ie, that can be overridden by setting HOME via -e or ENV
   131  		// in a Dockerfile).
   132  	}
   133  	if container.Config.Tty {
   134  		env = append(env, "TERM=xterm")
   135  	}
   136  	env = append(env, linkedEnv...)
   137  	// because the env on the container can override certain default values
   138  	// we need to replace the 'env' keys where they match and append anything
   139  	// else.
   140  	env = utils.ReplaceOrAppendEnvValues(env, container.Config.Env)
   141  
   142  	return env
   143  }
   144  
   145  func getDevicesFromPath(deviceMapping runconfig.DeviceMapping) (devs []*configs.Device, err error) {
   146  	device, err := devices.DeviceFromPath(deviceMapping.PathOnHost, deviceMapping.CgroupPermissions)
   147  	// if there was no error, return the device
   148  	if err == nil {
   149  		device.Path = deviceMapping.PathInContainer
   150  		return append(devs, device), nil
   151  	}
   152  
   153  	// if the device is not a device node
   154  	// try to see if it's a directory holding many devices
   155  	if err == devices.ErrNotADevice {
   156  
   157  		// check if it is a directory
   158  		if src, e := os.Stat(deviceMapping.PathOnHost); e == nil && src.IsDir() {
   159  
   160  			// mount the internal devices recursively
   161  			filepath.Walk(deviceMapping.PathOnHost, func(dpath string, f os.FileInfo, e error) error {
   162  				childDevice, e := devices.DeviceFromPath(dpath, deviceMapping.CgroupPermissions)
   163  				if e != nil {
   164  					// ignore the device
   165  					return nil
   166  				}
   167  
   168  				// add the device to userSpecified devices
   169  				childDevice.Path = strings.Replace(dpath, deviceMapping.PathOnHost, deviceMapping.PathInContainer, 1)
   170  				devs = append(devs, childDevice)
   171  
   172  				return nil
   173  			})
   174  		}
   175  	}
   176  
   177  	if len(devs) > 0 {
   178  		return devs, nil
   179  	}
   180  
   181  	return devs, fmt.Errorf("error gathering device information while adding custom device %q: %s", deviceMapping.PathOnHost, err)
   182  }
   183  
   184  func populateCommand(c *Container, env []string) error {
   185  	var en *execdriver.Network
   186  	if !c.Config.NetworkDisabled {
   187  		en = &execdriver.Network{
   188  			NamespacePath: c.NetworkSettings.SandboxKey,
   189  		}
   190  
   191  		parts := strings.SplitN(string(c.hostConfig.NetworkMode), ":", 2)
   192  		if parts[0] == "container" {
   193  			nc, err := c.getNetworkedContainer()
   194  			if err != nil {
   195  				return err
   196  			}
   197  			en.ContainerID = nc.ID
   198  		}
   199  	}
   200  
   201  	ipc := &execdriver.Ipc{}
   202  
   203  	if c.hostConfig.IpcMode.IsContainer() {
   204  		ic, err := c.getIpcContainer()
   205  		if err != nil {
   206  			return err
   207  		}
   208  		ipc.ContainerID = ic.ID
   209  	} else {
   210  		ipc.HostIpc = c.hostConfig.IpcMode.IsHost()
   211  	}
   212  
   213  	pid := &execdriver.Pid{}
   214  	pid.HostPid = c.hostConfig.PidMode.IsHost()
   215  
   216  	uts := &execdriver.UTS{
   217  		HostUTS: c.hostConfig.UTSMode.IsHost(),
   218  	}
   219  
   220  	// Build lists of devices allowed and created within the container.
   221  	var userSpecifiedDevices []*configs.Device
   222  	for _, deviceMapping := range c.hostConfig.Devices {
   223  		devs, err := getDevicesFromPath(deviceMapping)
   224  		if err != nil {
   225  			return err
   226  		}
   227  
   228  		userSpecifiedDevices = append(userSpecifiedDevices, devs...)
   229  	}
   230  
   231  	allowedDevices := mergeDevices(configs.DefaultAllowedDevices, userSpecifiedDevices)
   232  
   233  	autoCreatedDevices := mergeDevices(configs.DefaultAutoCreatedDevices, userSpecifiedDevices)
   234  
   235  	// TODO: this can be removed after lxc-conf is fully deprecated
   236  	lxcConfig, err := mergeLxcConfIntoOptions(c.hostConfig)
   237  	if err != nil {
   238  		return err
   239  	}
   240  
   241  	var rlimits []*ulimit.Rlimit
   242  	ulimits := c.hostConfig.Ulimits
   243  
   244  	// Merge ulimits with daemon defaults
   245  	ulIdx := make(map[string]*ulimit.Ulimit)
   246  	for _, ul := range ulimits {
   247  		ulIdx[ul.Name] = ul
   248  	}
   249  	for name, ul := range c.daemon.config.Ulimits {
   250  		if _, exists := ulIdx[name]; !exists {
   251  			ulimits = append(ulimits, ul)
   252  		}
   253  	}
   254  
   255  	for _, limit := range ulimits {
   256  		rl, err := limit.GetRlimit()
   257  		if err != nil {
   258  			return err
   259  		}
   260  		rlimits = append(rlimits, rl)
   261  	}
   262  
   263  	resources := &execdriver.Resources{
   264  		Memory:         c.hostConfig.Memory,
   265  		MemorySwap:     c.hostConfig.MemorySwap,
   266  		CpuShares:      c.hostConfig.CpuShares,
   267  		CpusetCpus:     c.hostConfig.CpusetCpus,
   268  		CpusetMems:     c.hostConfig.CpusetMems,
   269  		CpuPeriod:      c.hostConfig.CpuPeriod,
   270  		CpuQuota:       c.hostConfig.CpuQuota,
   271  		BlkioWeight:    c.hostConfig.BlkioWeight,
   272  		Rlimits:        rlimits,
   273  		OomKillDisable: c.hostConfig.OomKillDisable,
   274  	}
   275  
   276  	processConfig := execdriver.ProcessConfig{
   277  		Privileged: c.hostConfig.Privileged,
   278  		Entrypoint: c.Path,
   279  		Arguments:  c.Args,
   280  		Tty:        c.Config.Tty,
   281  		User:       c.Config.User,
   282  	}
   283  
   284  	processConfig.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
   285  	processConfig.Env = env
   286  
   287  	c.command = &execdriver.Command{
   288  		ID:                 c.ID,
   289  		Rootfs:             c.RootfsPath(),
   290  		ReadonlyRootfs:     c.hostConfig.ReadonlyRootfs,
   291  		InitPath:           "/.dockerinit",
   292  		WorkingDir:         c.Config.WorkingDir,
   293  		Network:            en,
   294  		Ipc:                ipc,
   295  		Pid:                pid,
   296  		UTS:                uts,
   297  		Resources:          resources,
   298  		AllowedDevices:     allowedDevices,
   299  		AutoCreatedDevices: autoCreatedDevices,
   300  		CapAdd:             c.hostConfig.CapAdd,
   301  		CapDrop:            c.hostConfig.CapDrop,
   302  		ProcessConfig:      processConfig,
   303  		ProcessLabel:       c.GetProcessLabel(),
   304  		MountLabel:         c.GetMountLabel(),
   305  		LxcConfig:          lxcConfig,
   306  		AppArmorProfile:    c.AppArmorProfile,
   307  		CgroupParent:       c.hostConfig.CgroupParent,
   308  	}
   309  
   310  	return nil
   311  }
   312  
   313  func mergeDevices(defaultDevices, userDevices []*configs.Device) []*configs.Device {
   314  	if len(userDevices) == 0 {
   315  		return defaultDevices
   316  	}
   317  
   318  	paths := map[string]*configs.Device{}
   319  	for _, d := range userDevices {
   320  		paths[d.Path] = d
   321  	}
   322  
   323  	var devs []*configs.Device
   324  	for _, d := range defaultDevices {
   325  		if _, defined := paths[d.Path]; !defined {
   326  			devs = append(devs, d)
   327  		}
   328  	}
   329  	return append(devs, userDevices...)
   330  }
   331  
   332  // GetSize, return real size, virtual size
   333  func (container *Container) GetSize() (int64, int64) {
   334  	var (
   335  		sizeRw, sizeRootfs int64
   336  		err                error
   337  		driver             = container.daemon.driver
   338  	)
   339  
   340  	if err := container.Mount(); err != nil {
   341  		logrus.Errorf("Failed to compute size of container rootfs %s: %s", container.ID, err)
   342  		return sizeRw, sizeRootfs
   343  	}
   344  	defer container.Unmount()
   345  
   346  	initID := fmt.Sprintf("%s-init", container.ID)
   347  	sizeRw, err = driver.DiffSize(container.ID, initID)
   348  	if err != nil {
   349  		logrus.Errorf("Driver %s couldn't return diff size of container %s: %s", driver, container.ID, err)
   350  		// FIXME: GetSize should return an error. Not changing it now in case
   351  		// there is a side-effect.
   352  		sizeRw = -1
   353  	}
   354  
   355  	if _, err = os.Stat(container.basefs); err == nil {
   356  		if sizeRootfs, err = directory.Size(container.basefs); err != nil {
   357  			sizeRootfs = -1
   358  		}
   359  	}
   360  	return sizeRw, sizeRootfs
   361  }
   362  
   363  func (container *Container) buildHostnameFile() error {
   364  	hostnamePath, err := container.GetRootResourcePath("hostname")
   365  	if err != nil {
   366  		return err
   367  	}
   368  	container.HostnamePath = hostnamePath
   369  
   370  	if container.Config.Domainname != "" {
   371  		return ioutil.WriteFile(container.HostnamePath, []byte(fmt.Sprintf("%s.%s\n", container.Config.Hostname, container.Config.Domainname)), 0644)
   372  	}
   373  	return ioutil.WriteFile(container.HostnamePath, []byte(container.Config.Hostname+"\n"), 0644)
   374  }
   375  
   376  func (container *Container) buildJoinOptions() ([]libnetwork.EndpointOption, error) {
   377  	var (
   378  		joinOptions []libnetwork.EndpointOption
   379  		err         error
   380  		dns         []string
   381  		dnsSearch   []string
   382  	)
   383  
   384  	joinOptions = append(joinOptions, libnetwork.JoinOptionHostname(container.Config.Hostname),
   385  		libnetwork.JoinOptionDomainname(container.Config.Domainname))
   386  
   387  	if container.hostConfig.NetworkMode.IsHost() {
   388  		joinOptions = append(joinOptions, libnetwork.JoinOptionUseDefaultSandbox())
   389  	}
   390  
   391  	container.HostsPath, err = container.GetRootResourcePath("hosts")
   392  	if err != nil {
   393  		return nil, err
   394  	}
   395  	joinOptions = append(joinOptions, libnetwork.JoinOptionHostsPath(container.HostsPath))
   396  
   397  	container.ResolvConfPath, err = container.GetRootResourcePath("resolv.conf")
   398  	if err != nil {
   399  		return nil, err
   400  	}
   401  	joinOptions = append(joinOptions, libnetwork.JoinOptionResolvConfPath(container.ResolvConfPath))
   402  
   403  	if len(container.hostConfig.Dns) > 0 {
   404  		dns = container.hostConfig.Dns
   405  	} else if len(container.daemon.config.Dns) > 0 {
   406  		dns = container.daemon.config.Dns
   407  	}
   408  
   409  	for _, d := range dns {
   410  		joinOptions = append(joinOptions, libnetwork.JoinOptionDNS(d))
   411  	}
   412  
   413  	if len(container.hostConfig.DnsSearch) > 0 {
   414  		dnsSearch = container.hostConfig.DnsSearch
   415  	} else if len(container.daemon.config.DnsSearch) > 0 {
   416  		dnsSearch = container.daemon.config.DnsSearch
   417  	}
   418  
   419  	for _, ds := range dnsSearch {
   420  		joinOptions = append(joinOptions, libnetwork.JoinOptionDNSSearch(ds))
   421  	}
   422  
   423  	if container.NetworkSettings.SecondaryIPAddresses != nil {
   424  		name := container.Config.Hostname
   425  		if container.Config.Domainname != "" {
   426  			name = name + "." + container.Config.Domainname
   427  		}
   428  
   429  		for _, a := range container.NetworkSettings.SecondaryIPAddresses {
   430  			joinOptions = append(joinOptions, libnetwork.JoinOptionExtraHost(name, a.Addr))
   431  		}
   432  	}
   433  
   434  	var childEndpoints, parentEndpoints []string
   435  
   436  	children, err := container.daemon.Children(container.Name)
   437  	if err != nil {
   438  		return nil, err
   439  	}
   440  
   441  	for linkAlias, child := range children {
   442  		_, alias := path.Split(linkAlias)
   443  		// allow access to the linked container via the alias, real name, and container hostname
   444  		aliasList := alias + " " + child.Config.Hostname
   445  		// only add the name if alias isn't equal to the name
   446  		if alias != child.Name[1:] {
   447  			aliasList = aliasList + " " + child.Name[1:]
   448  		}
   449  		joinOptions = append(joinOptions, libnetwork.JoinOptionExtraHost(aliasList, child.NetworkSettings.IPAddress))
   450  		if child.NetworkSettings.EndpointID != "" {
   451  			childEndpoints = append(childEndpoints, child.NetworkSettings.EndpointID)
   452  		}
   453  	}
   454  
   455  	for _, extraHost := range container.hostConfig.ExtraHosts {
   456  		// allow IPv6 addresses in extra hosts; only split on first ":"
   457  		parts := strings.SplitN(extraHost, ":", 2)
   458  		joinOptions = append(joinOptions, libnetwork.JoinOptionExtraHost(parts[0], parts[1]))
   459  	}
   460  
   461  	refs := container.daemon.ContainerGraph().RefPaths(container.ID)
   462  	for _, ref := range refs {
   463  		if ref.ParentID == "0" {
   464  			continue
   465  		}
   466  
   467  		c, err := container.daemon.Get(ref.ParentID)
   468  		if err != nil {
   469  			logrus.Error(err)
   470  		}
   471  
   472  		if c != nil && !container.daemon.config.DisableNetwork && container.hostConfig.NetworkMode.IsPrivate() {
   473  			logrus.Debugf("Update /etc/hosts of %s for alias %s with ip %s", c.ID, ref.Name, container.NetworkSettings.IPAddress)
   474  			joinOptions = append(joinOptions, libnetwork.JoinOptionParentUpdate(c.NetworkSettings.EndpointID, ref.Name, container.NetworkSettings.IPAddress))
   475  			if c.NetworkSettings.EndpointID != "" {
   476  				parentEndpoints = append(parentEndpoints, c.NetworkSettings.EndpointID)
   477  			}
   478  		}
   479  	}
   480  
   481  	linkOptions := options.Generic{
   482  		netlabel.GenericData: options.Generic{
   483  			"ParentEndpoints": parentEndpoints,
   484  			"ChildEndpoints":  childEndpoints,
   485  		},
   486  	}
   487  
   488  	joinOptions = append(joinOptions, libnetwork.JoinOptionGeneric(linkOptions))
   489  
   490  	return joinOptions, nil
   491  }
   492  
   493  func (container *Container) buildPortMapInfo(n libnetwork.Network, ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) {
   494  	if ep == nil {
   495  		return nil, fmt.Errorf("invalid endpoint while building port map info")
   496  	}
   497  
   498  	if networkSettings == nil {
   499  		return nil, fmt.Errorf("invalid networksettings while building port map info")
   500  	}
   501  
   502  	driverInfo, err := ep.DriverInfo()
   503  	if err != nil {
   504  		return nil, err
   505  	}
   506  
   507  	if driverInfo == nil {
   508  		// It is not an error for epInfo to be nil
   509  		return networkSettings, nil
   510  	}
   511  
   512  	if mac, ok := driverInfo[netlabel.MacAddress]; ok {
   513  		networkSettings.MacAddress = mac.(net.HardwareAddr).String()
   514  	}
   515  
   516  	networkSettings.Ports = nat.PortMap{}
   517  
   518  	if expData, ok := driverInfo[netlabel.ExposedPorts]; ok {
   519  		if exposedPorts, ok := expData.([]types.TransportPort); ok {
   520  			for _, tp := range exposedPorts {
   521  				natPort := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port)))
   522  				networkSettings.Ports[natPort] = nil
   523  			}
   524  		}
   525  	}
   526  
   527  	mapData, ok := driverInfo[netlabel.PortMap]
   528  	if !ok {
   529  		return networkSettings, nil
   530  	}
   531  
   532  	if portMapping, ok := mapData.([]types.PortBinding); ok {
   533  		for _, pp := range portMapping {
   534  			natPort := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port)))
   535  			natBndg := nat.PortBinding{HostIp: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))}
   536  			networkSettings.Ports[natPort] = append(networkSettings.Ports[natPort], natBndg)
   537  		}
   538  	}
   539  
   540  	return networkSettings, nil
   541  }
   542  
   543  func (container *Container) buildEndpointInfo(n libnetwork.Network, ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) {
   544  	if ep == nil {
   545  		return nil, fmt.Errorf("invalid endpoint while building port map info")
   546  	}
   547  
   548  	if networkSettings == nil {
   549  		return nil, fmt.Errorf("invalid networksettings while building port map info")
   550  	}
   551  
   552  	epInfo := ep.Info()
   553  	if epInfo == nil {
   554  		// It is not an error to get an empty endpoint info
   555  		return networkSettings, nil
   556  	}
   557  
   558  	ifaceList := epInfo.InterfaceList()
   559  	if len(ifaceList) == 0 {
   560  		return networkSettings, nil
   561  	}
   562  
   563  	iface := ifaceList[0]
   564  
   565  	ones, _ := iface.Address().Mask.Size()
   566  	networkSettings.IPAddress = iface.Address().IP.String()
   567  	networkSettings.IPPrefixLen = ones
   568  
   569  	if iface.AddressIPv6().IP.To16() != nil {
   570  		onesv6, _ := iface.AddressIPv6().Mask.Size()
   571  		networkSettings.GlobalIPv6Address = iface.AddressIPv6().IP.String()
   572  		networkSettings.GlobalIPv6PrefixLen = onesv6
   573  	}
   574  
   575  	if len(ifaceList) == 1 {
   576  		return networkSettings, nil
   577  	}
   578  
   579  	networkSettings.SecondaryIPAddresses = make([]network.Address, 0, len(ifaceList)-1)
   580  	networkSettings.SecondaryIPv6Addresses = make([]network.Address, 0, len(ifaceList)-1)
   581  	for _, iface := range ifaceList[1:] {
   582  		ones, _ := iface.Address().Mask.Size()
   583  		addr := network.Address{Addr: iface.Address().IP.String(), PrefixLen: ones}
   584  		networkSettings.SecondaryIPAddresses = append(networkSettings.SecondaryIPAddresses, addr)
   585  
   586  		if iface.AddressIPv6().IP.To16() != nil {
   587  			onesv6, _ := iface.AddressIPv6().Mask.Size()
   588  			addrv6 := network.Address{Addr: iface.AddressIPv6().IP.String(), PrefixLen: onesv6}
   589  			networkSettings.SecondaryIPv6Addresses = append(networkSettings.SecondaryIPv6Addresses, addrv6)
   590  		}
   591  	}
   592  
   593  	return networkSettings, nil
   594  }
   595  
   596  func (container *Container) updateJoinInfo(ep libnetwork.Endpoint) error {
   597  	epInfo := ep.Info()
   598  	if epInfo == nil {
   599  		// It is not an error to get an empty endpoint info
   600  		return nil
   601  	}
   602  
   603  	container.NetworkSettings.Gateway = epInfo.Gateway().String()
   604  	if epInfo.GatewayIPv6().To16() != nil {
   605  		container.NetworkSettings.IPv6Gateway = epInfo.GatewayIPv6().String()
   606  	}
   607  
   608  	container.NetworkSettings.SandboxKey = epInfo.SandboxKey()
   609  
   610  	return nil
   611  }
   612  
   613  func (container *Container) updateNetworkSettings(n libnetwork.Network, ep libnetwork.Endpoint) error {
   614  	networkSettings := &network.Settings{NetworkID: n.ID(), EndpointID: ep.ID()}
   615  
   616  	networkSettings, err := container.buildPortMapInfo(n, ep, networkSettings)
   617  	if err != nil {
   618  		return err
   619  	}
   620  
   621  	networkSettings, err = container.buildEndpointInfo(n, ep, networkSettings)
   622  	if err != nil {
   623  		return err
   624  	}
   625  
   626  	if container.hostConfig.NetworkMode == runconfig.NetworkMode("bridge") {
   627  		networkSettings.Bridge = container.daemon.config.Bridge.Iface
   628  	}
   629  
   630  	container.NetworkSettings = networkSettings
   631  	return nil
   632  }
   633  
   634  func (container *Container) UpdateNetwork() error {
   635  	n, err := container.daemon.netController.NetworkByID(container.NetworkSettings.NetworkID)
   636  	if err != nil {
   637  		return fmt.Errorf("error locating network id %s: %v", container.NetworkSettings.NetworkID, err)
   638  	}
   639  
   640  	ep, err := n.EndpointByID(container.NetworkSettings.EndpointID)
   641  	if err != nil {
   642  		return fmt.Errorf("error locating endpoint id %s: %v", container.NetworkSettings.EndpointID, err)
   643  	}
   644  
   645  	if err := ep.Leave(container.ID); err != nil {
   646  		return fmt.Errorf("endpoint leave failed: %v", err)
   647  
   648  	}
   649  
   650  	joinOptions, err := container.buildJoinOptions()
   651  	if err != nil {
   652  		return fmt.Errorf("Update network failed: %v", err)
   653  	}
   654  
   655  	if _, err := ep.Join(container.ID, joinOptions...); err != nil {
   656  		return fmt.Errorf("endpoint join failed: %v", err)
   657  	}
   658  
   659  	if err := container.updateJoinInfo(ep); err != nil {
   660  		return fmt.Errorf("Updating join info failed: %v", err)
   661  	}
   662  
   663  	return nil
   664  }
   665  
   666  func (container *Container) buildCreateEndpointOptions() ([]libnetwork.EndpointOption, error) {
   667  	var (
   668  		portSpecs     = make(nat.PortSet)
   669  		bindings      = make(nat.PortMap)
   670  		pbList        []types.PortBinding
   671  		exposeList    []types.TransportPort
   672  		createOptions []libnetwork.EndpointOption
   673  	)
   674  
   675  	if container.Config.PortSpecs != nil {
   676  		if err := migratePortMappings(container.Config, container.hostConfig); err != nil {
   677  			return nil, err
   678  		}
   679  		container.Config.PortSpecs = nil
   680  		if err := container.WriteHostConfig(); err != nil {
   681  			return nil, err
   682  		}
   683  	}
   684  
   685  	if container.Config.ExposedPorts != nil {
   686  		portSpecs = container.Config.ExposedPorts
   687  	}
   688  
   689  	if container.hostConfig.PortBindings != nil {
   690  		for p, b := range container.hostConfig.PortBindings {
   691  			bindings[p] = []nat.PortBinding{}
   692  			for _, bb := range b {
   693  				bindings[p] = append(bindings[p], nat.PortBinding{
   694  					HostIp:   bb.HostIp,
   695  					HostPort: bb.HostPort,
   696  				})
   697  			}
   698  		}
   699  	}
   700  
   701  	container.NetworkSettings.PortMapping = nil
   702  
   703  	ports := make([]nat.Port, len(portSpecs))
   704  	var i int
   705  	for p := range portSpecs {
   706  		ports[i] = p
   707  		i++
   708  	}
   709  	nat.SortPortMap(ports, bindings)
   710  	for _, port := range ports {
   711  		expose := types.TransportPort{}
   712  		expose.Proto = types.ParseProtocol(port.Proto())
   713  		expose.Port = uint16(port.Int())
   714  		exposeList = append(exposeList, expose)
   715  
   716  		pb := types.PortBinding{Port: expose.Port, Proto: expose.Proto}
   717  		binding := bindings[port]
   718  		for i := 0; i < len(binding); i++ {
   719  			pbCopy := pb.GetCopy()
   720  			pbCopy.HostPort = uint16(nat.Port(binding[i].HostPort).Int())
   721  			pbCopy.HostIP = net.ParseIP(binding[i].HostIp)
   722  			pbList = append(pbList, pbCopy)
   723  		}
   724  
   725  		if container.hostConfig.PublishAllPorts && len(binding) == 0 {
   726  			pbList = append(pbList, pb)
   727  		}
   728  	}
   729  
   730  	createOptions = append(createOptions,
   731  		libnetwork.CreateOptionPortMapping(pbList),
   732  		libnetwork.CreateOptionExposedPorts(exposeList))
   733  
   734  	if container.Config.MacAddress != "" {
   735  		mac, err := net.ParseMAC(container.Config.MacAddress)
   736  		if err != nil {
   737  			return nil, err
   738  		}
   739  
   740  		genericOption := options.Generic{
   741  			netlabel.MacAddress: mac,
   742  		}
   743  
   744  		createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption))
   745  	}
   746  
   747  	return createOptions, nil
   748  }
   749  
   750  func (container *Container) AllocateNetwork() error {
   751  	mode := container.hostConfig.NetworkMode
   752  	if container.Config.NetworkDisabled || mode.IsContainer() {
   753  		return nil
   754  	}
   755  
   756  	var err error
   757  
   758  	n, err := container.daemon.netController.NetworkByName(string(mode))
   759  	if err != nil {
   760  		return fmt.Errorf("error locating network with name %s: %v", string(mode), err)
   761  	}
   762  
   763  	createOptions, err := container.buildCreateEndpointOptions()
   764  	if err != nil {
   765  		return err
   766  	}
   767  
   768  	ep, err := n.CreateEndpoint(container.Name, createOptions...)
   769  	if err != nil {
   770  		return err
   771  	}
   772  
   773  	if err := container.updateNetworkSettings(n, ep); err != nil {
   774  		return err
   775  	}
   776  
   777  	joinOptions, err := container.buildJoinOptions()
   778  	if err != nil {
   779  		return err
   780  	}
   781  
   782  	if _, err := ep.Join(container.ID, joinOptions...); err != nil {
   783  		return err
   784  	}
   785  
   786  	if err := container.updateJoinInfo(ep); err != nil {
   787  		return fmt.Errorf("Updating join info failed: %v", err)
   788  	}
   789  
   790  	if err := container.WriteHostConfig(); err != nil {
   791  		return err
   792  	}
   793  
   794  	return nil
   795  }
   796  
   797  func (container *Container) initializeNetworking() error {
   798  	var err error
   799  
   800  	// Make sure NetworkMode has an acceptable value before
   801  	// initializing networking.
   802  	if container.hostConfig.NetworkMode == runconfig.NetworkMode("") {
   803  		container.hostConfig.NetworkMode = runconfig.NetworkMode("bridge")
   804  	}
   805  
   806  	if container.hostConfig.NetworkMode.IsContainer() {
   807  		// we need to get the hosts files from the container to join
   808  		nc, err := container.getNetworkedContainer()
   809  		if err != nil {
   810  			return err
   811  		}
   812  		container.HostnamePath = nc.HostnamePath
   813  		container.HostsPath = nc.HostsPath
   814  		container.ResolvConfPath = nc.ResolvConfPath
   815  		container.Config.Hostname = nc.Config.Hostname
   816  		container.Config.Domainname = nc.Config.Domainname
   817  		return nil
   818  	}
   819  
   820  	if container.daemon.config.DisableNetwork {
   821  		container.Config.NetworkDisabled = true
   822  	}
   823  
   824  	if container.hostConfig.NetworkMode.IsHost() {
   825  		container.Config.Hostname, err = os.Hostname()
   826  		if err != nil {
   827  			return err
   828  		}
   829  
   830  		parts := strings.SplitN(container.Config.Hostname, ".", 2)
   831  		if len(parts) > 1 {
   832  			container.Config.Hostname = parts[0]
   833  			container.Config.Domainname = parts[1]
   834  		}
   835  
   836  	}
   837  
   838  	if err := container.AllocateNetwork(); err != nil {
   839  		return err
   840  	}
   841  
   842  	return container.buildHostnameFile()
   843  }
   844  
   845  // Make sure the config is compatible with the current kernel
   846  func (container *Container) verifyDaemonSettings() {
   847  	if container.hostConfig.Memory > 0 && !container.daemon.sysInfo.MemoryLimit {
   848  		logrus.Warnf("Your kernel does not support memory limit capabilities. Limitation discarded.")
   849  		container.hostConfig.Memory = 0
   850  	}
   851  	if container.hostConfig.Memory > 0 && container.hostConfig.MemorySwap != -1 && !container.daemon.sysInfo.SwapLimit {
   852  		logrus.Warnf("Your kernel does not support swap limit capabilities. Limitation discarded.")
   853  		container.hostConfig.MemorySwap = -1
   854  	}
   855  	if container.daemon.sysInfo.IPv4ForwardingDisabled {
   856  		logrus.Warnf("IPv4 forwarding is disabled. Networking will not work")
   857  	}
   858  }
   859  
   860  func (container *Container) ExportRw() (archive.Archive, error) {
   861  	if err := container.Mount(); err != nil {
   862  		return nil, err
   863  	}
   864  	if container.daemon == nil {
   865  		return nil, fmt.Errorf("Can't load storage driver for unregistered container %s", container.ID)
   866  	}
   867  	archive, err := container.daemon.Diff(container)
   868  	if err != nil {
   869  		container.Unmount()
   870  		return nil, err
   871  	}
   872  	return ioutils.NewReadCloserWrapper(archive, func() error {
   873  			err := archive.Close()
   874  			container.Unmount()
   875  			return err
   876  		}),
   877  		nil
   878  }
   879  
   880  func (container *Container) getIpcContainer() (*Container, error) {
   881  	containerID := container.hostConfig.IpcMode.Container()
   882  	c, err := container.daemon.Get(containerID)
   883  	if err != nil {
   884  		return nil, err
   885  	}
   886  	if !c.IsRunning() {
   887  		return nil, fmt.Errorf("cannot join IPC of a non running container: %s", containerID)
   888  	}
   889  	return c, nil
   890  }
   891  
   892  func (container *Container) setupWorkingDirectory() error {
   893  	if container.Config.WorkingDir != "" {
   894  		container.Config.WorkingDir = filepath.Clean(container.Config.WorkingDir)
   895  
   896  		pth, err := container.GetResourcePath(container.Config.WorkingDir)
   897  		if err != nil {
   898  			return err
   899  		}
   900  
   901  		pthInfo, err := os.Stat(pth)
   902  		if err != nil {
   903  			if !os.IsNotExist(err) {
   904  				return err
   905  			}
   906  
   907  			if err := os.MkdirAll(pth, 0755); err != nil {
   908  				return err
   909  			}
   910  		}
   911  		if pthInfo != nil && !pthInfo.IsDir() {
   912  			return fmt.Errorf("Cannot mkdir: %s is not a directory", container.Config.WorkingDir)
   913  		}
   914  	}
   915  	return nil
   916  }
   917  
   918  func (container *Container) getNetworkedContainer() (*Container, error) {
   919  	parts := strings.SplitN(string(container.hostConfig.NetworkMode), ":", 2)
   920  	switch parts[0] {
   921  	case "container":
   922  		if len(parts) != 2 {
   923  			return nil, fmt.Errorf("no container specified to join network")
   924  		}
   925  		nc, err := container.daemon.Get(parts[1])
   926  		if err != nil {
   927  			return nil, err
   928  		}
   929  		if container == nc {
   930  			return nil, fmt.Errorf("cannot join own network")
   931  		}
   932  		if !nc.IsRunning() {
   933  			return nil, fmt.Errorf("cannot join network of a non running container: %s", parts[1])
   934  		}
   935  		return nc, nil
   936  	default:
   937  		return nil, fmt.Errorf("network mode not set to container")
   938  	}
   939  }
   940  
   941  func (container *Container) ReleaseNetwork() {
   942  	if container.hostConfig.NetworkMode.IsContainer() || container.daemon.config.DisableNetwork {
   943  		return
   944  	}
   945  
   946  	// If the container is not attached to any network do not try
   947  	// to release network and generate spurious error messages.
   948  	if container.NetworkSettings.NetworkID == "" {
   949  		return
   950  	}
   951  
   952  	n, err := container.daemon.netController.NetworkByID(container.NetworkSettings.NetworkID)
   953  	if err != nil {
   954  		logrus.Errorf("error locating network id %s: %v", container.NetworkSettings.NetworkID, err)
   955  		return
   956  	}
   957  
   958  	ep, err := n.EndpointByID(container.NetworkSettings.EndpointID)
   959  	if err != nil {
   960  		logrus.Errorf("error locating endpoint id %s: %v", container.NetworkSettings.EndpointID, err)
   961  		return
   962  	}
   963  
   964  	if err := ep.Leave(container.ID); err != nil {
   965  		logrus.Errorf("leaving endpoint failed: %v", err)
   966  	}
   967  
   968  	if err := ep.Delete(); err != nil {
   969  		logrus.Errorf("deleting endpoint failed: %v", err)
   970  	}
   971  
   972  	container.NetworkSettings = &network.Settings{}
   973  }
   974  
   975  func disableAllActiveLinks(container *Container) {
   976  	if container.activeLinks != nil {
   977  		for _, link := range container.activeLinks {
   978  			link.Disable()
   979  		}
   980  	}
   981  }
   982  
   983  func (container *Container) DisableLink(name string) {
   984  	if container.activeLinks != nil {
   985  		if link, exists := container.activeLinks[name]; exists {
   986  			link.Disable()
   987  			delete(container.activeLinks, name)
   988  			if err := container.UpdateNetwork(); err != nil {
   989  				logrus.Debugf("Could not update network to remove link: %v", err)
   990  			}
   991  		} else {
   992  			logrus.Debugf("Could not find active link for %s", name)
   993  		}
   994  	}
   995  }
   996  
   997  func (container *Container) UnmountVolumes(forceSyscall bool) error {
   998  	var volumeMounts []mountPoint
   999  
  1000  	for _, mntPoint := range container.MountPoints {
  1001  		dest, err := container.GetResourcePath(mntPoint.Destination)
  1002  		if err != nil {
  1003  			return err
  1004  		}
  1005  
  1006  		volumeMounts = append(volumeMounts, mountPoint{Destination: dest, Volume: mntPoint.Volume})
  1007  	}
  1008  
  1009  	for _, mnt := range container.networkMounts() {
  1010  		dest, err := container.GetResourcePath(mnt.Destination)
  1011  		if err != nil {
  1012  			return err
  1013  		}
  1014  
  1015  		volumeMounts = append(volumeMounts, mountPoint{Destination: dest})
  1016  	}
  1017  
  1018  	for _, volumeMount := range volumeMounts {
  1019  		if forceSyscall {
  1020  			syscall.Unmount(volumeMount.Destination, 0)
  1021  		}
  1022  
  1023  		if volumeMount.Volume != nil {
  1024  			if err := volumeMount.Volume.Unmount(); err != nil {
  1025  				return err
  1026  			}
  1027  		}
  1028  	}
  1029  
  1030  	return nil
  1031  }