github.com/mheon/docker@v0.11.2-0.20150922122814-44f47903a831/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, hooks execdriver.Hooks) (*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, hooks); 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, hooks execdriver.Hooks) 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  		container.Namespaces.Add(configs.NEWNET, c.Network.NamespacePath)
   140  		return nil
   141  	}
   142  	// only set up prestart hook if the namespace path is not set (this should be
   143  	// all cases *except* for --net=host shared networking)
   144  	container.Hooks = &configs.Hooks{
   145  		Prestart: []configs.Hook{
   146  			configs.NewFunctionHook(func(s configs.HookState) error {
   147  				if len(hooks.PreStart) > 0 {
   148  					for _, fnHook := range hooks.PreStart {
   149  						if err := fnHook(&c.ProcessConfig, s.Pid); err != nil {
   150  							return err
   151  						}
   152  					}
   153  				}
   154  				return nil
   155  			}),
   156  		},
   157  	}
   158  	return nil
   159  }
   160  
   161  func (d *Driver) createIpc(container *configs.Config, c *execdriver.Command) error {
   162  	if c.Ipc.HostIpc {
   163  		container.Namespaces.Remove(configs.NEWIPC)
   164  		return nil
   165  	}
   166  
   167  	if c.Ipc.ContainerID != "" {
   168  		d.Lock()
   169  		active := d.activeContainers[c.Ipc.ContainerID]
   170  		d.Unlock()
   171  
   172  		if active == nil {
   173  			return fmt.Errorf("%s is not a valid running container to join", c.Ipc.ContainerID)
   174  		}
   175  
   176  		state, err := active.State()
   177  		if err != nil {
   178  			return err
   179  		}
   180  		container.Namespaces.Add(configs.NEWIPC, state.NamespacePaths[configs.NEWIPC])
   181  	}
   182  
   183  	return nil
   184  }
   185  
   186  func (d *Driver) createPid(container *configs.Config, c *execdriver.Command) error {
   187  	if c.Pid.HostPid {
   188  		container.Namespaces.Remove(configs.NEWPID)
   189  		return nil
   190  	}
   191  
   192  	return nil
   193  }
   194  
   195  func (d *Driver) createUTS(container *configs.Config, c *execdriver.Command) error {
   196  	if c.UTS.HostUTS {
   197  		container.Namespaces.Remove(configs.NEWUTS)
   198  		container.Hostname = ""
   199  		return nil
   200  	}
   201  
   202  	return nil
   203  }
   204  
   205  func (d *Driver) setPrivileged(container *configs.Config) (err error) {
   206  	container.Capabilities = execdriver.GetAllCapabilities()
   207  	container.Cgroups.AllowAllDevices = true
   208  
   209  	hostDevices, err := devices.HostDevices()
   210  	if err != nil {
   211  		return err
   212  	}
   213  	container.Devices = hostDevices
   214  
   215  	if apparmor.IsEnabled() {
   216  		container.AppArmorProfile = "unconfined"
   217  	}
   218  	return nil
   219  }
   220  
   221  func (d *Driver) setCapabilities(container *configs.Config, c *execdriver.Command) (err error) {
   222  	container.Capabilities, err = execdriver.TweakCapabilities(container.Capabilities, c.CapAdd, c.CapDrop)
   223  	return err
   224  }
   225  
   226  func (d *Driver) setupRlimits(container *configs.Config, c *execdriver.Command) {
   227  	if c.Resources == nil {
   228  		return
   229  	}
   230  
   231  	for _, rlimit := range c.Resources.Rlimits {
   232  		container.Rlimits = append(container.Rlimits, configs.Rlimit{
   233  			Type: rlimit.Type,
   234  			Hard: rlimit.Hard,
   235  			Soft: rlimit.Soft,
   236  		})
   237  	}
   238  }
   239  
   240  func (d *Driver) setupMounts(container *configs.Config, c *execdriver.Command) error {
   241  	userMounts := make(map[string]struct{})
   242  	for _, m := range c.Mounts {
   243  		userMounts[m.Destination] = struct{}{}
   244  	}
   245  
   246  	// Filter out mounts that are overriden by user supplied mounts
   247  	var defaultMounts []*configs.Mount
   248  	_, mountDev := userMounts["/dev"]
   249  	for _, m := range container.Mounts {
   250  		if _, ok := userMounts[m.Destination]; !ok {
   251  			if mountDev && strings.HasPrefix(m.Destination, "/dev/") {
   252  				continue
   253  			}
   254  			defaultMounts = append(defaultMounts, m)
   255  		}
   256  	}
   257  	container.Mounts = defaultMounts
   258  
   259  	for _, m := range c.Mounts {
   260  		flags := syscall.MS_BIND | syscall.MS_REC
   261  		if !m.Writable {
   262  			flags |= syscall.MS_RDONLY
   263  		}
   264  		if m.Slave {
   265  			flags |= syscall.MS_SLAVE
   266  		}
   267  		container.Mounts = append(container.Mounts, &configs.Mount{
   268  			Source:      m.Source,
   269  			Destination: m.Destination,
   270  			Device:      "bind",
   271  			Flags:       flags,
   272  		})
   273  	}
   274  	return nil
   275  }
   276  
   277  func (d *Driver) setupLabels(container *configs.Config, c *execdriver.Command) {
   278  	container.ProcessLabel = c.ProcessLabel
   279  	container.MountLabel = c.MountLabel
   280  }