func (d *driver) setupMounts(container *configs.Config, c *execdriver.Command) error { userMounts := make(map[string]struct{}) for _, m := range c.Mounts { userMounts[m.Destination] = struct{}{} } // Filter out mounts that are overriden by user supplied mounts var defaultMounts []*configs.Mount for _, m := range container.Mounts { if _, ok := userMounts[m.Destination]; !ok { defaultMounts = append(defaultMounts, m) } } container.Mounts = defaultMounts for _, m := range c.Mounts { flags := syscall.MS_BIND | syscall.MS_REC if !m.Writable { flags |= syscall.MS_RDONLY } if m.Slave { flags |= syscall.MS_SLAVE } container.Mounts = append(container.Mounts, &configs.Mount{ Source: m.Source, Destination: m.Destination, Device: "bind", Flags: flags, }) } return nil }
func (d *driver) createNetwork(container *configs.Config, c *execdriver.Command) error { if c.Network.HostNetworking { container.Namespaces.Remove(configs.NEWNET) return nil } container.Networks = []*configs.Network{ { Type: "loopback", }, } iName, err := generateIfaceName() if err != nil { return err } if c.Network.Interface != nil { vethNetwork := configs.Network{ Name: "eth0", HostInterfaceName: iName, Mtu: c.Network.Mtu, Address: fmt.Sprintf("%s/%d", c.Network.Interface.IPAddress, c.Network.Interface.IPPrefixLen), MacAddress: c.Network.Interface.MacAddress, Gateway: c.Network.Interface.Gateway, Type: "veth", Bridge: c.Network.Interface.Bridge, HairpinMode: c.Network.Interface.HairpinMode, } if c.Network.Interface.GlobalIPv6Address != "" { vethNetwork.IPv6Address = fmt.Sprintf("%s/%d", c.Network.Interface.GlobalIPv6Address, c.Network.Interface.GlobalIPv6PrefixLen) vethNetwork.IPv6Gateway = c.Network.Interface.IPv6Gateway } container.Networks = append(container.Networks, &vethNetwork) } if c.Network.ContainerID != "" { d.Lock() active := d.activeContainers[c.Network.ContainerID] d.Unlock() if active == nil { return fmt.Errorf("%s is not a valid running container to join", c.Network.ContainerID) } state, err := active.State() if err != nil { return err } container.Namespaces.Add(configs.NEWNET, state.NamespacePaths[configs.NEWNET]) } return nil }
func (d *driver) setPrivileged(container *configs.Config) (err error) { container.Capabilities = execdriver.GetAllCapabilities() container.Cgroups.AllowAllDevices = true hostDevices, err := devices.HostDevices() if err != nil { return err } container.Devices = hostDevices if apparmor.IsEnabled() { container.AppArmorProfile = "unconfined" } return nil }
func (d *driver) createUTS(container *configs.Config, c *execdriver.Command) error { if c.UTS.HostUTS { container.Namespaces.Remove(configs.NEWUTS) container.Hostname = "" return nil } return nil }
func (d *driver) setupMounts(container *configs.Config, c *execdriver.Command) error { userMounts := make(map[string]struct{}) for _, m := range c.Mounts { userMounts[m.Destination] = struct{}{} } // Filter out mounts that are overriden by user supplied mounts var defaultMounts []*configs.Mount _, mountDev := userMounts["/dev"] for _, m := range container.Mounts { if _, ok := userMounts[m.Destination]; !ok { if mountDev && strings.HasPrefix(m.Destination, "/dev/") { continue } defaultMounts = append(defaultMounts, m) } } container.Mounts = defaultMounts for _, m := range c.Mounts { dest, err := symlink.FollowSymlinkInScope(filepath.Join(c.Rootfs, m.Destination), c.Rootfs) if err != nil { return err } flags := syscall.MS_BIND | syscall.MS_REC if !m.Writable { flags |= syscall.MS_RDONLY } if m.Slave { flags |= syscall.MS_SLAVE } container.Mounts = append(container.Mounts, &configs.Mount{ Source: m.Source, Destination: dest, Device: "bind", Flags: flags, }) } return nil }
func (d *driver) setupRlimits(container *configs.Config, c *execdriver.Command) { if c.Resources == nil { return } for _, rlimit := range c.Resources.Rlimits { container.Rlimits = append(container.Rlimits, configs.Rlimit{ Type: rlimit.Type, Hard: rlimit.Hard, Soft: rlimit.Soft, }) } }
func setupPipes(container *configs.Config, processConfig *execdriver.ProcessConfig, p *libcontainer.Process, pipes *execdriver.Pipes) error { var term execdriver.Terminal var err error if processConfig.Tty { rootuid, err := container.HostUID() if err != nil { return err } cons, err := p.NewConsole(rootuid) if err != nil { return err } term, err = NewTtyConsole(cons, pipes, rootuid) } else { p.Stdout = pipes.Stdout p.Stderr = pipes.Stderr r, w, err := os.Pipe() if err != nil { return err } if pipes.Stdin != nil { go func() { io.Copy(w, pipes.Stdin) w.Close() }() p.Stdin = r } term = &execdriver.StdConsole{} } if err != nil { return err } processConfig.Terminal = term return nil }
func modifySecurityProfile(context *cli.Context, config *configs.Config) { profileName := context.String("security") if profileName == "" { return } profile := profiles[profileName] if profile == nil { logrus.Fatalf("invalid profile name %q", profileName) } config.Rlimits = profile.Rlimits config.Capabilities = profile.Capabilities config.Seccomp = profile.Seccomp config.AppArmorProfile = profile.ApparmorProfile config.MountLabel = profile.MountLabel config.ProcessLabel = profile.ProcessLabel }
func (d *driver) setupLabels(container *configs.Config, c *execdriver.Command) { container.ProcessLabel = c.ProcessLabel container.MountLabel = c.MountLabel }
func modify(config *configs.Config, context *cli.Context) { config.ParentDeathSignal = context.Int("parent-death-signal") config.Readonlyfs = context.Bool("read-only") config.Cgroups.CpusetCpus = context.String("cpuset-cpus") config.Cgroups.CpusetMems = context.String("cpuset-mems") config.Cgroups.CpuShares = int64(context.Int("cpushares")) config.Cgroups.Memory = int64(context.Int("memory-limit")) config.Cgroups.MemorySwap = int64(context.Int("memory-swap")) config.AppArmorProfile = context.String("apparmor-profile") config.ProcessLabel = context.String("process-label") config.MountLabel = context.String("mount-label") rootfs := context.String("rootfs") if rootfs != "" { config.Rootfs = rootfs } userns_uid := context.Int("userns-root-uid") if userns_uid != 0 { config.Namespaces.Add(configs.NEWUSER, "") config.UidMappings = []configs.IDMap{ {ContainerID: 0, HostID: userns_uid, Size: 1}, {ContainerID: 1, HostID: 1, Size: userns_uid - 1}, {ContainerID: userns_uid + 1, HostID: userns_uid + 1, Size: math.MaxInt32 - userns_uid}, } config.GidMappings = []configs.IDMap{ {ContainerID: 0, HostID: userns_uid, Size: 1}, {ContainerID: 1, HostID: 1, Size: userns_uid - 1}, {ContainerID: userns_uid + 1, HostID: userns_uid + 1, Size: math.MaxInt32 - userns_uid}, } for _, node := range config.Devices { node.Uid = uint32(userns_uid) node.Gid = uint32(userns_uid) } } for _, rawBind := range context.StringSlice("bind") { mount := &configs.Mount{ Device: "bind", Flags: syscall.MS_BIND | syscall.MS_REC, } parts := strings.SplitN(rawBind, ":", 3) switch len(parts) { default: logrus.Fatalf("invalid bind mount %s", rawBind) case 2: mount.Source, mount.Destination = parts[0], parts[1] case 3: mount.Source, mount.Destination = parts[0], parts[1] switch parts[2] { case "ro": mount.Flags |= syscall.MS_RDONLY case "rw": default: logrus.Fatalf("invalid bind mount mode %s", parts[2]) } } config.Mounts = append(config.Mounts, mount) } for _, tmpfs := range context.StringSlice("tmpfs") { config.Mounts = append(config.Mounts, &configs.Mount{ Device: "tmpfs", Destination: tmpfs, Flags: syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV, }) } for flag, value := range map[string]configs.NamespaceType{ "net": configs.NEWNET, "mnt": configs.NEWNS, "pid": configs.NEWPID, "ipc": configs.NEWIPC, "uts": configs.NEWUTS, } { switch v := context.String(flag); v { case "host": config.Namespaces.Remove(value) case "", "private": if !config.Namespaces.Contains(value) { config.Namespaces.Add(value, "") } if flag == "net" { config.Networks = []*configs.Network{ { Type: "loopback", Address: "127.0.0.1/0", Gateway: "localhost", }, } } if flag == "uts" { config.Hostname = context.String("hostname") } default: config.Namespaces.Remove(value) config.Namespaces.Add(value, v) } } if bridge := context.String("veth-bridge"); bridge != "" { hostName, err := utils.GenerateRandomName("veth", 7) if err != nil { logrus.Fatal(err) } network := &configs.Network{ Type: "veth", Name: "eth0", Bridge: bridge, Address: context.String("veth-address"), Gateway: context.String("veth-gateway"), Mtu: context.Int("veth-mtu"), HostInterfaceName: hostName, } config.Networks = append(config.Networks, network) } }
// TODO(vmarmol): Deprecate over time as old Dockers are phased out. func ReadConfig(dockerRoot, dockerRun, containerID string) (*configs.Config, error) { // Try using the new config if it is available. configPath := configPath(dockerRun, containerID) if utils.FileExists(configPath) { out, err := ioutil.ReadFile(configPath) if err != nil { return nil, err } var state libcontainer.State err = json.Unmarshal(out, &state) if err != nil { glog.Errorf("Unmarshal failure for: \n\n%v\n", string(out)) return nil, err } return &state.Config, nil } // Fallback to reading the old config which is comprised of the state and config files. oldConfigPath := oldConfigPath(dockerRoot, containerID) out, err := ioutil.ReadFile(oldConfigPath) if err != nil { glog.Errorf("Unmarshal failure for: \n\n%v\n", string(out)) return nil, err } // Try reading the preAPIConfig. var config preAPIConfig err = json.Unmarshal(out, &config) if err != nil { // Try to parse the old pre-API config. The main difference is that namespaces used to be a map, now it is a slice of structs. // The JSON marshaler will use the non-nested field before the nested one. type oldLibcontainerConfig struct { preAPIConfig OldNamespaces map[string]bool `json:"namespaces,omitempty"` } var oldConfig oldLibcontainerConfig err2 := json.Unmarshal(out, &oldConfig) if err2 != nil { // Use original error. return nil, err } // Translate the old pre-API config into the new config. config = oldConfig.preAPIConfig for ns := range oldConfig.OldNamespaces { config.Namespaces = append(config.Namespaces, configs.Namespace{ Type: configs.NamespaceType(ns), }) } } // Read the old state file as well. state, err := readState(dockerRoot, containerID) if err != nil { return nil, err } // Convert preAPIConfig + old state file to Config. // This only converts some of the fields, the ones we use. // You may need to add fields if the one you're interested in is not available. var result configs.Config result.Cgroups = new(configs.Cgroup) result.Rootfs = config.RootFs result.Hostname = config.Hostname result.Namespaces = config.Namespaces result.Capabilities = config.Capabilities for _, net := range config.Networks { n := &configs.Network{ Name: state.NetworkState.VethChild, Bridge: net.Bridge, MacAddress: net.MacAddress, Address: net.Address, Gateway: net.Gateway, IPv6Address: net.IPv6Address, IPv6Gateway: net.IPv6Gateway, HostInterfaceName: state.NetworkState.VethHost, } result.Networks = append(result.Networks, n) } result.Routes = config.Routes if config.Cgroups != nil { result.Cgroups = config.Cgroups } return &result, nil }