github.com/rentongzhang/docker@v1.8.2-rc1/daemon/execdriver/native/create.go (about)

     1  // +build linux,cgo
     2  
     3  package native
     4  
     5  import (
     6  	"errors"
     7  	"fmt"
     8  	"net"
     9  	"strings"
    10  	"syscall"
    11  
    12  	"github.com/docker/docker/daemon/execdriver"
    13  	"github.com/opencontainers/runc/libcontainer/apparmor"
    14  	"github.com/opencontainers/runc/libcontainer/configs"
    15  	"github.com/opencontainers/runc/libcontainer/devices"
    16  	"github.com/opencontainers/runc/libcontainer/utils"
    17  )
    18  
    19  // createContainer populates and configures the container type with the
    20  // data provided by the execdriver.Command
    21  func (d *driver) createContainer(c *execdriver.Command) (*configs.Config, error) {
    22  	container := execdriver.InitContainer(c)
    23  
    24  	if err := d.createIpc(container, c); err != nil {
    25  		return nil, err
    26  	}
    27  
    28  	if err := d.createPid(container, c); err != nil {
    29  		return nil, err
    30  	}
    31  
    32  	if err := d.createUTS(container, c); err != nil {
    33  		return nil, err
    34  	}
    35  
    36  	if err := d.createNetwork(container, c); err != nil {
    37  		return nil, err
    38  	}
    39  
    40  	if c.ProcessConfig.Privileged {
    41  		if !container.Readonlyfs {
    42  			// clear readonly for /sys
    43  			for i := range container.Mounts {
    44  				if container.Mounts[i].Destination == "/sys" {
    45  					container.Mounts[i].Flags &= ^syscall.MS_RDONLY
    46  				}
    47  			}
    48  			container.ReadonlyPaths = nil
    49  		}
    50  
    51  		// clear readonly for cgroup
    52  		for i := range container.Mounts {
    53  			if container.Mounts[i].Device == "cgroup" {
    54  				container.Mounts[i].Flags &= ^syscall.MS_RDONLY
    55  			}
    56  		}
    57  
    58  		container.MaskPaths = nil
    59  		if err := d.setPrivileged(container); err != nil {
    60  			return nil, err
    61  		}
    62  	} else {
    63  		if err := d.setCapabilities(container, c); err != nil {
    64  			return nil, err
    65  		}
    66  	}
    67  
    68  	container.AdditionalGroups = c.GroupAdd
    69  
    70  	if c.AppArmorProfile != "" {
    71  		container.AppArmorProfile = c.AppArmorProfile
    72  	}
    73  
    74  	if err := execdriver.SetupCgroups(container, c); err != nil {
    75  		return nil, err
    76  	}
    77  
    78  	if container.Readonlyfs {
    79  		for i := range container.Mounts {
    80  			switch container.Mounts[i].Destination {
    81  			case "/proc", "/dev", "/dev/pts":
    82  				continue
    83  			}
    84  			container.Mounts[i].Flags |= syscall.MS_RDONLY
    85  		}
    86  
    87  		/* These paths must be remounted as r/o */
    88  		container.ReadonlyPaths = append(container.ReadonlyPaths, "/dev")
    89  	}
    90  
    91  	if err := d.setupMounts(container, c); err != nil {
    92  		return nil, err
    93  	}
    94  
    95  	d.setupLabels(container, c)
    96  	d.setupRlimits(container, c)
    97  	return container, nil
    98  }
    99  
   100  func generateIfaceName() (string, error) {
   101  	for i := 0; i < 10; i++ {
   102  		name, err := utils.GenerateRandomName("veth", 7)
   103  		if err != nil {
   104  			continue
   105  		}
   106  		if _, err := net.InterfaceByName(name); err != nil {
   107  			if strings.Contains(err.Error(), "no such") {
   108  				return name, nil
   109  			}
   110  			return "", err
   111  		}
   112  	}
   113  	return "", errors.New("Failed to find name for new interface")
   114  }
   115  
   116  func (d *driver) createNetwork(container *configs.Config, c *execdriver.Command) error {
   117  	if c.Network == nil {
   118  		return nil
   119  	}
   120  	if c.Network.ContainerID != "" {
   121  		d.Lock()
   122  		active := d.activeContainers[c.Network.ContainerID]
   123  		d.Unlock()
   124  
   125  		if active == nil {
   126  			return fmt.Errorf("%s is not a valid running container to join", c.Network.ContainerID)
   127  		}
   128  
   129  		state, err := active.State()
   130  		if err != nil {
   131  			return err
   132  		}
   133  
   134  		container.Namespaces.Add(configs.NEWNET, state.NamespacePaths[configs.NEWNET])
   135  		return nil
   136  	}
   137  
   138  	if c.Network.NamespacePath == "" {
   139  		return fmt.Errorf("network namespace path is empty")
   140  	}
   141  
   142  	container.Namespaces.Add(configs.NEWNET, c.Network.NamespacePath)
   143  	return nil
   144  }
   145  
   146  func (d *driver) createIpc(container *configs.Config, c *execdriver.Command) error {
   147  	if c.Ipc.HostIpc {
   148  		container.Namespaces.Remove(configs.NEWIPC)
   149  		return nil
   150  	}
   151  
   152  	if c.Ipc.ContainerID != "" {
   153  		d.Lock()
   154  		active := d.activeContainers[c.Ipc.ContainerID]
   155  		d.Unlock()
   156  
   157  		if active == nil {
   158  			return fmt.Errorf("%s is not a valid running container to join", c.Ipc.ContainerID)
   159  		}
   160  
   161  		state, err := active.State()
   162  		if err != nil {
   163  			return err
   164  		}
   165  		container.Namespaces.Add(configs.NEWIPC, state.NamespacePaths[configs.NEWIPC])
   166  	}
   167  
   168  	return nil
   169  }
   170  
   171  func (d *driver) createPid(container *configs.Config, c *execdriver.Command) error {
   172  	if c.Pid.HostPid {
   173  		container.Namespaces.Remove(configs.NEWPID)
   174  		return nil
   175  	}
   176  
   177  	return nil
   178  }
   179  
   180  func (d *driver) createUTS(container *configs.Config, c *execdriver.Command) error {
   181  	if c.UTS.HostUTS {
   182  		container.Namespaces.Remove(configs.NEWUTS)
   183  		container.Hostname = ""
   184  		return nil
   185  	}
   186  
   187  	return nil
   188  }
   189  
   190  func (d *driver) setPrivileged(container *configs.Config) (err error) {
   191  	container.Capabilities = execdriver.GetAllCapabilities()
   192  	container.Cgroups.AllowAllDevices = true
   193  
   194  	hostDevices, err := devices.HostDevices()
   195  	if err != nil {
   196  		return err
   197  	}
   198  	container.Devices = hostDevices
   199  
   200  	if apparmor.IsEnabled() {
   201  		container.AppArmorProfile = "unconfined"
   202  	}
   203  	return nil
   204  }
   205  
   206  func (d *driver) setCapabilities(container *configs.Config, c *execdriver.Command) (err error) {
   207  	container.Capabilities, err = execdriver.TweakCapabilities(container.Capabilities, c.CapAdd, c.CapDrop)
   208  	return err
   209  }
   210  
   211  func (d *driver) setupRlimits(container *configs.Config, c *execdriver.Command) {
   212  	if c.Resources == nil {
   213  		return
   214  	}
   215  
   216  	for _, rlimit := range c.Resources.Rlimits {
   217  		container.Rlimits = append(container.Rlimits, configs.Rlimit{
   218  			Type: rlimit.Type,
   219  			Hard: rlimit.Hard,
   220  			Soft: rlimit.Soft,
   221  		})
   222  	}
   223  }
   224  
   225  func (d *driver) setupMounts(container *configs.Config, c *execdriver.Command) error {
   226  	userMounts := make(map[string]struct{})
   227  	for _, m := range c.Mounts {
   228  		userMounts[m.Destination] = struct{}{}
   229  	}
   230  
   231  	// Filter out mounts that are overriden by user supplied mounts
   232  	var defaultMounts []*configs.Mount
   233  	_, mountDev := userMounts["/dev"]
   234  	for _, m := range container.Mounts {
   235  		if _, ok := userMounts[m.Destination]; !ok {
   236  			if mountDev && strings.HasPrefix(m.Destination, "/dev/") {
   237  				continue
   238  			}
   239  			defaultMounts = append(defaultMounts, m)
   240  		}
   241  	}
   242  	container.Mounts = defaultMounts
   243  
   244  	for _, m := range c.Mounts {
   245  		flags := syscall.MS_BIND | syscall.MS_REC
   246  		if !m.Writable {
   247  			flags |= syscall.MS_RDONLY
   248  		}
   249  		if m.Slave {
   250  			flags |= syscall.MS_SLAVE
   251  		}
   252  		container.Mounts = append(container.Mounts, &configs.Mount{
   253  			Source:      m.Source,
   254  			Destination: m.Destination,
   255  			Device:      "bind",
   256  			Flags:       flags,
   257  		})
   258  	}
   259  	return nil
   260  }
   261  
   262  func (d *driver) setupLabels(container *configs.Config, c *execdriver.Command) {
   263  	container.ProcessLabel = c.ProcessLabel
   264  	container.MountLabel = c.MountLabel
   265  }