func TestParseLxcConfOpt(t *testing.T) { opts := []string{"lxc.utsname=docker", "lxc.utsname = docker "} for _, o := range opts { k, v, err := parsers.ParseKeyValueOpt(o) if err != nil { t.FailNow() } if k != "lxc.utsname" { t.Fail() } if v != "docker" { t.Fail() } } // With parseRun too _, hostconfig, _, err := parseRun([]string{"lxc.utsname=docker", "lxc.utsname = docker ", "img", "cmd"}) if err != nil { t.Fatal(err) } for _, lxcConf := range hostconfig.LxcConf.Slice() { if lxcConf.Key != "lxc.utsname" || lxcConf.Value != "docker" { t.Fail() } } }
func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) { var volumeDriver string for _, option := range options { key, val, err := parsers.ParseKeyValueOpt(option) if err != nil { return nil, err } switch key { case Layer0VolumeDriver: volumeDriver = val default: return nil, fmt.Errorf("Unknown option %s\n", key) } } log.Infof("Layer0 volume driver: %v", volumeDriver) volDriver, err := volume.Get(volumeDriver) if err != nil { return nil, err } ov, err := overlay.Init(home, options, uidMaps, gidMaps) if err != nil { volDriver.Shutdown() return nil, err } d := &Layer0{ Driver: ov, home: home, volumes: make(map[string]*Layer0Vol), volDriver: volDriver, } return d, nil }
// NewDriver returns a new windows driver, called from NewDriver of execdriver. func NewDriver(root, initPath string, options []string) (*Driver, error) { for _, option := range options { key, val, err := parsers.ParseKeyValueOpt(option) if err != nil { return nil, err } key = strings.ToLower(key) switch key { case "dummy": switch val { case "1": dummyMode = true logrus.Warn("Using dummy mode in Windows exec driver. This is for development use only!") } case "forcekill": switch val { case "1": forceKill = true logrus.Warn("Using force kill mode in Windows exec driver. This is for testing purposes only.") } default: return nil, fmt.Errorf("Unrecognised exec driver option %s\n", key) } } return &Driver{ root: root, initPath: initPath, activeContainers: make(map[string]*activeContainer), }, nil }
func NewRbdSet(root string, doInit bool, options []string, uidMaps, gidMaps []idtools.IDMap) (*RbdSet, error) { conn, _ := rados.NewConn() devices := &RbdSet{ MetaData: MetaData{Devices: make(map[string]*DevInfo)}, conn: conn, dataPoolName: "rbd", imagePrefix: "docker_image", snapPrefix: "docker_snap", metaPrefix: "docker_meta", baseImageName: "base_image", baseImageSize: DefaultDockerBaseImageSize, clientId: "admin", configFile: DefaultRadosConfigFile, filesystem: "ext4", uidMaps: uidMaps, gidMaps: gidMaps, } for _, option := range options { key, val, err := parsers.ParseKeyValueOpt(option) if err != nil { return nil, err } key = strings.ToLower(key) switch key { case "rbd.basesize": size, err := units.RAMInBytes(val) if err != nil { return nil, err } devices.baseImageSize = uint64(size) case "rbd.datapool": devices.dataPoolName = val case "rbd.imageprefix": devices.imagePrefix = val case "rbd.client": devices.clientId = val case "rbd.configfile": devices.configFile = val case "rbd.fs": if val != "ext4" && val != "xfs" { return nil, fmt.Errorf("Unsupported filesystem %s\n", val) } devices.filesystem = val case "rbd.mkfsarg": devices.mkfsArgs = append(devices.mkfsArgs, val) case "rbd.mountopt": devices.mountOptions = joinMountOptions(devices.mountOptions, val) default: return nil, fmt.Errorf("Unknown option %s\n", key) } } if err := devices.initRbdSet(doInit); err != nil { return nil, err } return devices, nil }
// setDefaultIsolation determine the default isolation mode for the // daemon to run in. This is only applicable on Windows func (daemon *Daemon) setDefaultIsolation() error { daemon.defaultIsolation = containertypes.Isolation("process") for _, option := range daemon.configStore.ExecOptions { key, val, err := parsers.ParseKeyValueOpt(option) if err != nil { return err } key = strings.ToLower(key) switch key { case "isolation": if !containertypes.Isolation(val).IsValid() { return fmt.Errorf("Invalid exec-opt value for 'isolation':'%s'", val) } if containertypes.Isolation(val).IsHyperV() { daemon.defaultIsolation = containertypes.Isolation("hyperv") } default: return fmt.Errorf("Unrecognised exec-opt '%s'\n", key) } } logrus.Infof("Windows default isolation mode: %s", daemon.defaultIsolation) return nil }
func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) { logrus.Infof("Initializing Fuse Graph driver at home:%s and storage: %v...", home, virtPath) var volumeDriver string for _, option := range options { key, val, err := parsers.ParseKeyValueOpt(option) if err != nil { return nil, err } switch key { case UnionFSVolumeDriver: volumeDriver = val default: return nil, fmt.Errorf("Unknown option %s\n", key) } } if volumeDriver == "" { logrus.Warnf("Error - no volume driver specified for UnionFS") return nil, fmt.Errorf("No volume driver specified for UnionFS") } logrus.Infof("UnionFS volume driver: %v", volumeDriver) volDriver, err := volume.Get(volumeDriver) if err != nil { logrus.Warnf("Error while loading volume driver: %s", volumeDriver) return nil, err } // In case it is mounted. syscall.Unmount(virtPath, 0) err = os.MkdirAll(virtPath, 0744) if err != nil { volDriver.Shutdown() logrus.Warnf("Error while creating FUSE mount path: %v", err) return nil, err } err = os.MkdirAll(physPath, 0744) if err != nil { volDriver.Shutdown() logrus.Warnf("Error while creating FUSE mount path: %v", err) return nil, err } cVirtPath := C.CString(virtPath) cPhysPath := C.CString(physPath) go C.start_unionfs(cPhysPath, cVirtPath) d := &Driver{ volDriver: volDriver, } return d, nil }
// getCD gets the raw value of the native.cgroupdriver option, if set. func getCD(config *Config) string { for _, option := range config.ExecOptions { key, val, err := parsers.ParseKeyValueOpt(option) if err != nil || !strings.EqualFold(key, "native.cgroupdriver") { continue } return val } return "" }
func parseKeyValueOpts(opts opts.ListOpts) ([]KeyValuePair, error) { out := make([]KeyValuePair, opts.Len()) for i, o := range opts.GetAll() { k, v, err := parsers.ParseKeyValueOpt(o) if err != nil { return nil, err } out[i] = KeyValuePair{Key: k, Value: v} } return out, nil }
func usingSystemd(config *Config) bool { for _, option := range config.ExecOptions { key, val, err := parsers.ParseKeyValueOpt(option) if err != nil || !strings.EqualFold(key, "native.cgroupdriver") { continue } if val == "systemd" { return true } } return false }
// NewDriver returns a new windows driver, called from NewDriver of execdriver. func NewDriver(root string, options []string) (*Driver, error) { for _, option := range options { key, val, err := parsers.ParseKeyValueOpt(option) if err != nil { return nil, err } key = strings.ToLower(key) switch key { case "dummy": switch val { case "1": dummyMode = true logrus.Warn("Using dummy mode in Windows exec driver. This is for development use only!") } case "forcekill": switch val { case "1": forceKill = true logrus.Warn("Using force kill mode in Windows exec driver. This is for testing purposes only.") } case "isolation": if !container.Isolation(val).IsValid() { return nil, fmt.Errorf("Unrecognised exec driver option 'isolation':'%s'", val) } if container.Isolation(val).IsHyperV() { DefaultIsolation = "hyperv" } logrus.Infof("Windows default isolation: '%s'", val) default: return nil, fmt.Errorf("Unrecognised exec driver option %s\n", key) } } // TODO Windows TP5 timeframe. Remove this next block of code once TP4 // is no longer supported. Also remove the workaround in run.go. // // Hack for TP4. // This overcomes an issue on TP4 which causes CreateComputeSystem to // intermittently fail. It's predominantly here to make Windows to Windows // CI more reliable. TP4RetryHack = hcsshim.IsTP4() return &Driver{ root: root, activeContainers: make(map[string]*activeContainer), }, nil }
func TestParseLxcConfOpt(t *testing.T) { opts := []string{"lxc.utsname=docker", "lxc.utsname = docker "} for _, o := range opts { k, v, err := parsers.ParseKeyValueOpt(o) if err != nil { t.FailNow() } if k != "lxc.utsname" { t.Fail() } if v != "docker" { t.Fail() } } }
func (daemon *Daemon) getCgroupDriver() string { cgroupDriver := cgroupFsDriver // No other cgroup drivers are supported at the moment. Warn the // user if they tried to set one other than cgroupfs for _, option := range daemon.configStore.ExecOptions { key, val, err := parsers.ParseKeyValueOpt(option) if err != nil || !strings.EqualFold(key, "native.cgroupdriver") { continue } if val != cgroupFsDriver { logrus.Warnf("cgroupdriver '%s' is not supported", val) } } return cgroupDriver }
func parseOptions(opt []string) (zfsOptions, error) { var options zfsOptions options.fsName = "" for _, option := range opt { key, val, err := parsers.ParseKeyValueOpt(option) if err != nil { return options, err } key = strings.ToLower(key) switch key { case "zfs.fsname": options.fsName = val default: return options, fmt.Errorf("Unknown option %s", key) } } return options, nil }
// NewDriver returns a new windows driver, called from NewDriver of execdriver. func NewDriver(root, initPath string, options []string) (*Driver, error) { for _, option := range options { key, val, err := parsers.ParseKeyValueOpt(option) if err != nil { return nil, err } key = strings.ToLower(key) switch key { case "dummy": switch val { case "1": dummyMode = true logrus.Warn("Using dummy mode in Windows exec driver. This is for development use only!") } case "forcekill": switch val { case "1": forceKill = true logrus.Warn("Using force kill mode in Windows exec driver. This is for testing purposes only.") } case "isolation": if !runconfig.IsolationLevel(val).IsValid() { return nil, fmt.Errorf("Unrecognised exec driver option 'isolation':'%s'", val) } if runconfig.IsolationLevel(val).IsHyperV() { defaultIsolation = "hyperv" } logrus.Infof("Windows default isolation level: '%s'", val) default: return nil, fmt.Errorf("Unrecognised exec driver option %s\n", key) } } return &Driver{ root: root, initPath: initPath, activeContainers: make(map[string]*activeContainer), }, nil }
func parseOptions(options []string) (*overlayOptions, error) { o := &overlayOptions{} for _, option := range options { key, val, err := parsers.ParseKeyValueOpt(option) if err != nil { return nil, err } key = strings.ToLower(key) switch key { case "overlay2.override_kernel_check": o.overrideKernelCheck, err = strconv.ParseBool(val) if err != nil { return nil, err } default: return nil, fmt.Errorf("overlay2: Unknown option %s\n", key) } } return o, nil }
func parseOptions(opt []string) (btrfsOptions, error) { var options btrfsOptions for _, option := range opt { key, val, err := parsers.ParseKeyValueOpt(option) if err != nil { return options, err } key = strings.ToLower(key) switch key { case "btrfs.min_space": minSpace, err := units.RAMInBytes(val) if err != nil { return options, err } userDiskQuota = true options.minSpace = uint64(minSpace) default: return options, fmt.Errorf("Unknown option %s", key) } } return options, nil }
// setDefaultIsolation determine the default isolation mode for the // daemon to run in. This is only applicable on Windows func (daemon *Daemon) setDefaultIsolation() error { daemon.defaultIsolation = containertypes.Isolation("process") // On client SKUs, default to Hyper-V if system.IsWindowsClient() { daemon.defaultIsolation = containertypes.Isolation("hyperv") } for _, option := range daemon.configStore.ExecOptions { key, val, err := parsers.ParseKeyValueOpt(option) if err != nil { return err } key = strings.ToLower(key) switch key { case "isolation": if !containertypes.Isolation(val).IsValid() { return fmt.Errorf("Invalid exec-opt value for 'isolation':'%s'", val) } if containertypes.Isolation(val).IsHyperV() { daemon.defaultIsolation = containertypes.Isolation("hyperv") } if containertypes.Isolation(val).IsProcess() { if system.IsWindowsClient() { // @engine maintainers. This block should not be removed. It partially enforces licensing // restrictions on Windows. Ping @jhowardmsft if there are concerns or PRs to change this. return fmt.Errorf("Windows client operating systems only support Hyper-V containers") } daemon.defaultIsolation = containertypes.Isolation("process") } default: return fmt.Errorf("Unrecognised exec-opt '%s'\n", key) } } logrus.Infof("Windows default isolation mode: %s", daemon.defaultIsolation) return nil }
// NewDriver returns a new native driver, called from NewDriver of execdriver. func NewDriver(root, initPath string, options []string) (*Driver, error) { meminfo, err := sysinfo.ReadMemInfo() if err != nil { return nil, err } if err := sysinfo.MkdirAll(root, 0700); err != nil { return nil, err } if apparmor.IsEnabled() { if err := installAppArmorProfile(); err != nil { apparmorProfiles := []string{"docker-default"} // Allow daemon to run if loading failed, but are active // (possibly through another run, manually, or via system startup) for _, policy := range apparmorProfiles { if err := hasAppArmorProfileLoaded(policy); err != nil { return nil, fmt.Errorf("AppArmor enabled on system but the %s profile could not be loaded.", policy) } } } } // choose cgroup manager // this makes sure there are no breaking changes to people // who upgrade from versions without native.cgroupdriver opt cgm := libcontainer.Cgroupfs if systemd.UseSystemd() { cgm = libcontainer.SystemdCgroups } // parse the options for _, option := range options { key, val, err := parsers.ParseKeyValueOpt(option) if err != nil { return nil, err } key = strings.ToLower(key) switch key { case "native.cgroupdriver": // override the default if they set options switch val { case "systemd": if systemd.UseSystemd() { cgm = libcontainer.SystemdCgroups } else { // warn them that they chose the wrong driver logrus.Warn("You cannot use systemd as native.cgroupdriver, using cgroupfs instead") } case "cgroupfs": cgm = libcontainer.Cgroupfs default: return nil, fmt.Errorf("Unknown native.cgroupdriver given %q. try cgroupfs or systemd", val) } default: return nil, fmt.Errorf("Unknown option %s\n", key) } } f, err := libcontainer.New( root, cgm, libcontainer.InitPath(reexec.Self(), DriverName), ) if err != nil { return nil, err } return &Driver{ root: root, initPath: initPath, activeContainers: make(map[string]libcontainer.Container), machineMemory: meminfo.MemTotal, factory: f, }, nil }
func (daemon *Daemon) populateCommand(c *container.Container, env []string) error { var en *execdriver.Network if !c.Config.NetworkDisabled { en = &execdriver.Network{} if !daemon.execDriver.SupportsHooks() || c.HostConfig.NetworkMode.IsHost() { en.NamespacePath = c.NetworkSettings.SandboxKey } if c.HostConfig.NetworkMode.IsContainer() { nc, err := daemon.getNetworkedContainer(c.ID, c.HostConfig.NetworkMode.ConnectedContainer()) if err != nil { return err } en.ContainerID = nc.ID } } ipc := &execdriver.Ipc{} var err error c.ShmPath, err = c.ShmResourcePath() if err != nil { return err } c.MqueuePath, err = c.MqueueResourcePath() if err != nil { return err } if c.HostConfig.IpcMode.IsContainer() { ic, err := daemon.getIpcContainer(c) if err != nil { return err } ipc.ContainerID = ic.ID c.ShmPath = ic.ShmPath c.MqueuePath = ic.MqueuePath } else { ipc.HostIpc = c.HostConfig.IpcMode.IsHost() if ipc.HostIpc { if _, err := os.Stat("/dev/shm"); err != nil { return fmt.Errorf("/dev/shm is not mounted, but must be for --ipc=host") } if _, err := os.Stat("/dev/mqueue"); err != nil { return fmt.Errorf("/dev/mqueue is not mounted, but must be for --ipc=host") } c.ShmPath = "/dev/shm" c.MqueuePath = "/dev/mqueue" } } pid := &execdriver.Pid{} pid.HostPid = c.HostConfig.PidMode.IsHost() uts := &execdriver.UTS{ HostUTS: c.HostConfig.UTSMode.IsHost(), } // Build lists of devices allowed and created within the container. var userSpecifiedDevices []*configs.Device for _, deviceMapping := range c.HostConfig.Devices { devs, err := getDevicesFromPath(deviceMapping) if err != nil { return err } userSpecifiedDevices = append(userSpecifiedDevices, devs...) } allowedDevices := mergeDevices(configs.DefaultAllowedDevices, userSpecifiedDevices) autoCreatedDevices := mergeDevices(configs.DefaultAutoCreatedDevices, userSpecifiedDevices) var rlimits []*units.Rlimit ulimits := c.HostConfig.Ulimits // Merge ulimits with daemon defaults ulIdx := make(map[string]*units.Ulimit) for _, ul := range ulimits { ulIdx[ul.Name] = ul } for name, ul := range daemon.configStore.Ulimits { if _, exists := ulIdx[name]; !exists { ulimits = append(ulimits, ul) } } weightDevices, err := getBlkioWeightDevices(c.HostConfig) if err != nil { return err } readBpsDevice, err := getBlkioReadBpsDevices(c.HostConfig) if err != nil { return err } writeBpsDevice, err := getBlkioWriteBpsDevices(c.HostConfig) if err != nil { return err } readIOpsDevice, err := getBlkioReadIOpsDevices(c.HostConfig) if err != nil { return err } writeIOpsDevice, err := getBlkioWriteIOpsDevices(c.HostConfig) if err != nil { return err } for _, limit := range ulimits { rl, err := limit.GetRlimit() if err != nil { return err } rlimits = append(rlimits, rl) } resources := &execdriver.Resources{ CommonResources: execdriver.CommonResources{ Memory: c.HostConfig.Memory, MemoryReservation: c.HostConfig.MemoryReservation, CPUShares: c.HostConfig.CPUShares, BlkioWeight: c.HostConfig.BlkioWeight, }, MemorySwap: c.HostConfig.MemorySwap, KernelMemory: c.HostConfig.KernelMemory, CpusetCpus: c.HostConfig.CpusetCpus, CpusetMems: c.HostConfig.CpusetMems, CPUPeriod: c.HostConfig.CPUPeriod, CPUQuota: c.HostConfig.CPUQuota, Rlimits: rlimits, BlkioWeightDevice: weightDevices, BlkioThrottleReadBpsDevice: readBpsDevice, BlkioThrottleWriteBpsDevice: writeBpsDevice, BlkioThrottleReadIOpsDevice: readIOpsDevice, BlkioThrottleWriteIOpsDevice: writeIOpsDevice, OomKillDisable: c.HostConfig.OomKillDisable, MemorySwappiness: -1, } if c.HostConfig.MemorySwappiness != nil { resources.MemorySwappiness = *c.HostConfig.MemorySwappiness } processConfig := execdriver.ProcessConfig{ CommonProcessConfig: execdriver.CommonProcessConfig{ Entrypoint: c.Path, Arguments: c.Args, Tty: c.Config.Tty, }, Privileged: c.HostConfig.Privileged, User: c.Config.User, } processConfig.SysProcAttr = &syscall.SysProcAttr{Setsid: true} processConfig.Env = env remappedRoot := &execdriver.User{} rootUID, rootGID := daemon.GetRemappedUIDGID() if rootUID != 0 { remappedRoot.UID = rootUID remappedRoot.GID = rootGID } uidMap, gidMap := daemon.GetUIDGIDMaps() defaultCgroupParent := "/docker" if daemon.configStore.CgroupParent != "" { defaultCgroupParent = daemon.configStore.CgroupParent } else { for _, option := range daemon.configStore.ExecOptions { key, val, err := parsers.ParseKeyValueOpt(option) if err != nil || !strings.EqualFold(key, "native.cgroupdriver") { continue } if val == "systemd" { defaultCgroupParent = "system.slice" } } } c.Command = &execdriver.Command{ CommonCommand: execdriver.CommonCommand{ ID: c.ID, InitPath: "/.dockerinit", MountLabel: c.GetMountLabel(), Network: en, ProcessConfig: processConfig, ProcessLabel: c.GetProcessLabel(), Rootfs: c.BaseFS, Resources: resources, WorkingDir: c.Config.WorkingDir, }, AllowedDevices: allowedDevices, AppArmorProfile: c.AppArmorProfile, AutoCreatedDevices: autoCreatedDevices, CapAdd: c.HostConfig.CapAdd.Slice(), CapDrop: c.HostConfig.CapDrop.Slice(), CgroupParent: defaultCgroupParent, GIDMapping: gidMap, GroupAdd: c.HostConfig.GroupAdd, Ipc: ipc, OomScoreAdj: c.HostConfig.OomScoreAdj, Pid: pid, ReadonlyRootfs: c.HostConfig.ReadonlyRootfs, RemappedRoot: remappedRoot, SeccompProfile: c.SeccompProfile, UIDMapping: uidMap, UTS: uts, } if c.HostConfig.CgroupParent != "" { c.Command.CgroupParent = c.HostConfig.CgroupParent } return nil }
func NewDeviceSet(root string, doInit bool, options []string) (*DeviceSet, error) { devicemapper.SetDevDir("/dev") devices := &DeviceSet{ root: root, MetaData: MetaData{Devices: make(map[string]*DevInfo)}, dataLoopbackSize: DefaultDataLoopbackSize, metaDataLoopbackSize: DefaultMetaDataLoopbackSize, baseFsSize: DefaultBaseFsSize, filesystem: "ext4", doBlkDiscard: true, thinpBlockSize: DefaultThinpBlockSize, deviceIdMap: make([]byte, DeviceIdMapSz), } foundBlkDiscard := false for _, option := range options { key, val, err := parsers.ParseKeyValueOpt(option) if err != nil { return nil, err } key = strings.ToLower(key) switch key { case "dm.basesize": size, err := units.RAMInBytes(val) if err != nil { return nil, err } devices.baseFsSize = uint64(size) case "dm.loopdatasize": size, err := units.RAMInBytes(val) if err != nil { return nil, err } devices.dataLoopbackSize = size case "dm.loopmetadatasize": size, err := units.RAMInBytes(val) if err != nil { return nil, err } devices.metaDataLoopbackSize = size case "dm.fs": if val != "ext4" && val != "xfs" { return nil, fmt.Errorf("Unsupported filesystem %s\n", val) } devices.filesystem = val case "dm.mkfsarg": devices.mkfsArgs = append(devices.mkfsArgs, val) case "dm.mountopt": devices.mountOptions = joinMountOptions(devices.mountOptions, val) case "dm.metadatadev": devices.metadataDevice = val case "dm.datadev": devices.dataDevice = val case "dm.thinpooldev": devices.thinPoolDevice = strings.TrimPrefix(val, "/dev/mapper/") case "dm.blkdiscard": foundBlkDiscard = true devices.doBlkDiscard, err = strconv.ParseBool(val) if err != nil { return nil, err } case "dm.blocksize": size, err := units.RAMInBytes(val) if err != nil { return nil, err } // convert to 512b sectors devices.thinpBlockSize = uint32(size) >> 9 default: return nil, fmt.Errorf("Unknown option %s\n", key) } } // By default, don't do blk discard hack on raw devices, its rarely useful and is expensive if !foundBlkDiscard && (devices.dataDevice != "" || devices.thinPoolDevice != "") { devices.doBlkDiscard = false } if err := devices.initDevmapper(doInit); err != nil { return nil, err } return devices, nil }
func NewDriver(root, initPath string, options []string) (*driver, error) { meminfo, err := sysinfo.ReadMemInfo() if err != nil { return nil, err } if err := sysinfo.MkdirAll(root, 0700); err != nil { return nil, err } // native driver root is at docker_root/execdriver/native. Put apparmor at docker_root if err := apparmor.InstallDefaultProfile(); err != nil { return nil, err } // choose cgroup manager // this makes sure there are no breaking changes to people // who upgrade from versions without native.cgroupdriver opt cgm := libcontainer.Cgroupfs if systemd.UseSystemd() { cgm = libcontainer.SystemdCgroups } // parse the options for _, option := range options { key, val, err := parsers.ParseKeyValueOpt(option) if err != nil { return nil, err } key = strings.ToLower(key) switch key { case "native.cgroupdriver": // override the default if they set options switch val { case "systemd": if systemd.UseSystemd() { cgm = libcontainer.SystemdCgroups } else { // warn them that they chose the wrong driver logrus.Warn("You cannot use systemd as native.cgroupdriver, using cgroupfs instead") } case "cgroupfs": cgm = libcontainer.Cgroupfs default: return nil, fmt.Errorf("Unknown native.cgroupdriver given %q. try cgroupfs or systemd", val) } default: return nil, fmt.Errorf("Unknown option %s\n", key) } } logrus.Debugf("Using %v as native.cgroupdriver", cgm) f, err := libcontainer.New( root, cgm, libcontainer.InitPath(reexec.Self(), DriverName), ) if err != nil { return nil, err } return &driver{ root: root, initPath: initPath, activeContainers: make(map[string]libcontainer.Container), machineMemory: meminfo.MemTotal, factory: f, }, nil }
// NewDriver returns a new windows driver, called from NewDriver of execdriver. func NewDriver(root string, options []string) (*Driver, error) { for _, option := range options { key, val, err := parsers.ParseKeyValueOpt(option) if err != nil { return nil, err } key = strings.ToLower(key) switch key { case "dummy": switch val { case "1": dummyMode = true logrus.Warn("Using dummy mode in Windows exec driver. This is for development use only!") } case "forcekill": switch val { case "1": forceKill = true logrus.Warn("Using force kill mode in Windows exec driver. This is for testing purposes only.") } case "isolation": if !container.IsolationLevel(val).IsValid() { return nil, fmt.Errorf("Unrecognised exec driver option 'isolation':'%s'", val) } if container.IsolationLevel(val).IsHyperV() { DefaultIsolation = "hyperv" } logrus.Infof("Windows default isolation level: '%s'", val) default: return nil, fmt.Errorf("Unrecognised exec driver option %s\n", key) } } // TODO Windows TP5 timeframe. Remove this next block of code once TP4 // is no longer supported. Also remove the workaround in run.go. // // Hack for TP4 - determine the version of Windows from the registry. // This overcomes an issue on TP4 which causes CreateComputeSystem to // intermittently fail. It's predominantly here to make Windows to Windows // CI more reliable. TP4RetryHack = false k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE) if err != nil { return &Driver{}, err } defer k.Close() s, _, err := k.GetStringValue("BuildLab") if err != nil { return &Driver{}, err } parts := strings.Split(s, ".") if len(parts) < 1 { return &Driver{}, err } var val int if val, err = strconv.Atoi(parts[0]); err != nil { return &Driver{}, err } if val < 14250 { TP4RetryHack = true } // End of Windows TP4 hack return &Driver{ root: root, activeContainers: make(map[string]*activeContainer), }, nil }