d22ac2f3a0
This fix fixes error messages for `--cpus` from daemon. When `docker run` takes `--cpus`, it will translate into NanoCPUs and pass the value to daemon. The `NanoCPU` is not visible to the user. The error message generated from daemon used 'NanoCPU' which may cause some confusion to the user. This fix fixes this issue by returning the error in CPUs instead. This fix fixes 28456. Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
602 lines
19 KiB
Go
602 lines
19 KiB
Go
package daemon
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/Microsoft/hcsshim"
|
|
"github.com/Sirupsen/logrus"
|
|
"github.com/docker/docker/api/types"
|
|
containertypes "github.com/docker/docker/api/types/container"
|
|
"github.com/docker/docker/container"
|
|
"github.com/docker/docker/image"
|
|
"github.com/docker/docker/pkg/idtools"
|
|
"github.com/docker/docker/pkg/parsers"
|
|
"github.com/docker/docker/pkg/platform"
|
|
"github.com/docker/docker/pkg/sysinfo"
|
|
"github.com/docker/docker/pkg/system"
|
|
"github.com/docker/docker/runconfig"
|
|
"github.com/docker/libnetwork"
|
|
nwconfig "github.com/docker/libnetwork/config"
|
|
"github.com/docker/libnetwork/datastore"
|
|
winlibnetwork "github.com/docker/libnetwork/drivers/windows"
|
|
"github.com/docker/libnetwork/netlabel"
|
|
"github.com/docker/libnetwork/options"
|
|
blkiodev "github.com/opencontainers/runc/libcontainer/configs"
|
|
)
|
|
|
|
const (
|
|
defaultNetworkSpace = "172.16.0.0/12"
|
|
platformSupported = true
|
|
windowsMinCPUShares = 1
|
|
windowsMaxCPUShares = 10000
|
|
windowsMinCPUPercent = 1
|
|
windowsMaxCPUPercent = 100
|
|
windowsMinCPUCount = 1
|
|
)
|
|
|
|
func getBlkioWeightDevices(config *containertypes.HostConfig) ([]blkiodev.WeightDevice, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func parseSecurityOpt(container *container.Container, config *containertypes.HostConfig) error {
|
|
return nil
|
|
}
|
|
|
|
func getBlkioReadIOpsDevices(config *containertypes.HostConfig) ([]blkiodev.ThrottleDevice, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func getBlkioWriteIOpsDevices(config *containertypes.HostConfig) ([]blkiodev.ThrottleDevice, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func getBlkioReadBpsDevices(config *containertypes.HostConfig) ([]blkiodev.ThrottleDevice, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func getBlkioWriteBpsDevices(config *containertypes.HostConfig) ([]blkiodev.ThrottleDevice, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func setupInitLayer(initLayer string, rootUID, rootGID int) error {
|
|
return nil
|
|
}
|
|
|
|
func (daemon *Daemon) getLayerInit() func(string) error {
|
|
return nil
|
|
}
|
|
|
|
func checkKernel() error {
|
|
return nil
|
|
}
|
|
|
|
func (daemon *Daemon) getCgroupDriver() string {
|
|
return ""
|
|
}
|
|
|
|
// adaptContainerSettings is called during container creation to modify any
|
|
// settings necessary in the HostConfig structure.
|
|
func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConfig, adjustCPUShares bool) error {
|
|
if hostConfig == nil {
|
|
return nil
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func verifyContainerResources(resources *containertypes.Resources, isHyperv bool) ([]string, error) {
|
|
warnings := []string{}
|
|
|
|
if !isHyperv {
|
|
// The processor resource controls are mutually exclusive on
|
|
// Windows Server Containers, the order of precedence is
|
|
// CPUCount first, then CPUShares, and CPUPercent last.
|
|
if resources.CPUCount > 0 {
|
|
if resources.CPUShares > 0 {
|
|
warnings = append(warnings, "Conflicting options: CPU count takes priority over CPU shares on Windows Server Containers. CPU shares discarded")
|
|
logrus.Warn("Conflicting options: CPU count takes priority over CPU shares on Windows Server Containers. CPU shares discarded")
|
|
resources.CPUShares = 0
|
|
}
|
|
if resources.CPUPercent > 0 {
|
|
warnings = append(warnings, "Conflicting options: CPU count takes priority over CPU percent on Windows Server Containers. CPU percent discarded")
|
|
logrus.Warn("Conflicting options: CPU count takes priority over CPU percent on Windows Server Containers. CPU percent discarded")
|
|
resources.CPUPercent = 0
|
|
}
|
|
} else if resources.CPUShares > 0 {
|
|
if resources.CPUPercent > 0 {
|
|
warnings = append(warnings, "Conflicting options: CPU shares takes priority over CPU percent on Windows Server Containers. CPU percent discarded")
|
|
logrus.Warn("Conflicting options: CPU shares takes priority over CPU percent on Windows Server Containers. CPU percent discarded")
|
|
resources.CPUPercent = 0
|
|
}
|
|
}
|
|
}
|
|
|
|
if resources.CPUShares < 0 || resources.CPUShares > windowsMaxCPUShares {
|
|
return warnings, fmt.Errorf("range of CPUShares is from %d to %d", windowsMinCPUShares, windowsMaxCPUShares)
|
|
}
|
|
if resources.CPUPercent < 0 || resources.CPUPercent > windowsMaxCPUPercent {
|
|
return warnings, fmt.Errorf("range of CPUPercent is from %d to %d", windowsMinCPUPercent, windowsMaxCPUPercent)
|
|
}
|
|
if resources.CPUCount < 0 {
|
|
return warnings, fmt.Errorf("invalid CPUCount: CPUCount cannot be negative")
|
|
}
|
|
|
|
if resources.NanoCPUs > 0 && resources.CPUPercent > 0 {
|
|
return warnings, fmt.Errorf("conflicting options: Nano CPUs and CPU Percent cannot both be set")
|
|
}
|
|
if resources.NanoCPUs > 0 && resources.CPUShares > 0 {
|
|
return warnings, fmt.Errorf("conflicting options: Nano CPUs and CPU Shares cannot both be set")
|
|
}
|
|
// The precision we could get is 0.01, because on Windows we have to convert to CPUPercent.
|
|
// We don't set the lower limit here and it is up to the underlying platform (e.g., Windows) to return an error.
|
|
if resources.NanoCPUs < 0 || resources.NanoCPUs > int64(sysinfo.NumCPU())*1e9 {
|
|
return warnings, fmt.Errorf("range of CPUs is from 0.01 to %d.00, as there are only %d CPUs available", sysinfo.NumCPU(), sysinfo.NumCPU())
|
|
}
|
|
|
|
if len(resources.BlkioDeviceReadBps) > 0 {
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support BlkioDeviceReadBps")
|
|
}
|
|
if len(resources.BlkioDeviceReadIOps) > 0 {
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support BlkioDeviceReadIOps")
|
|
}
|
|
if len(resources.BlkioDeviceWriteBps) > 0 {
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support BlkioDeviceWriteBps")
|
|
}
|
|
if len(resources.BlkioDeviceWriteIOps) > 0 {
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support BlkioDeviceWriteIOps")
|
|
}
|
|
if resources.BlkioWeight > 0 {
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support BlkioWeight")
|
|
}
|
|
if len(resources.BlkioWeightDevice) > 0 {
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support BlkioWeightDevice")
|
|
}
|
|
if resources.CgroupParent != "" {
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support CgroupParent")
|
|
}
|
|
if resources.CPUPeriod != 0 {
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support CPUPeriod")
|
|
}
|
|
if resources.CpusetCpus != "" {
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support CpusetCpus")
|
|
}
|
|
if resources.CpusetMems != "" {
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support CpusetMems")
|
|
}
|
|
if resources.KernelMemory != 0 {
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support KernelMemory")
|
|
}
|
|
if resources.MemoryReservation != 0 {
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support MemoryReservation")
|
|
}
|
|
if resources.MemorySwap != 0 {
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support MemorySwap")
|
|
}
|
|
if resources.MemorySwappiness != nil && *resources.MemorySwappiness != -1 {
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support MemorySwappiness")
|
|
}
|
|
if resources.OomKillDisable != nil && *resources.OomKillDisable {
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support OomKillDisable")
|
|
}
|
|
if resources.PidsLimit != 0 {
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support PidsLimit")
|
|
}
|
|
if len(resources.Ulimits) != 0 {
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support Ulimits")
|
|
}
|
|
return warnings, nil
|
|
}
|
|
|
|
// verifyPlatformContainerSettings performs platform-specific validation of the
|
|
// hostconfig and config structures.
|
|
func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) {
|
|
warnings := []string{}
|
|
|
|
hyperv := daemon.runAsHyperVContainer(hostConfig)
|
|
if !hyperv && 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 warnings, fmt.Errorf("Windows client operating systems only support Hyper-V containers")
|
|
}
|
|
|
|
w, err := verifyContainerResources(&hostConfig.Resources, hyperv)
|
|
warnings = append(warnings, w...)
|
|
if err != nil {
|
|
return warnings, err
|
|
}
|
|
return warnings, nil
|
|
}
|
|
|
|
// platformReload update configuration with platform specific options
|
|
func (daemon *Daemon) platformReload(config *Config) map[string]string {
|
|
return map[string]string{}
|
|
}
|
|
|
|
// verifyDaemonSettings performs validation of daemon config struct
|
|
func verifyDaemonSettings(config *Config) error {
|
|
return nil
|
|
}
|
|
|
|
// checkSystem validates platform-specific requirements
|
|
func checkSystem() error {
|
|
// Validate the OS version. Note that docker.exe must be manifested for this
|
|
// call to return the correct version.
|
|
osv := system.GetOSVersion()
|
|
if osv.MajorVersion < 10 {
|
|
return fmt.Errorf("This version of Windows does not support the docker daemon")
|
|
}
|
|
if osv.Build < 14393 {
|
|
return fmt.Errorf("The docker daemon requires build 14393 or later of Windows Server 2016 or Windows 10")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// configureKernelSecuritySupport configures and validate security support for the kernel
|
|
func configureKernelSecuritySupport(config *Config, driverName string) error {
|
|
return nil
|
|
}
|
|
|
|
// configureMaxThreads sets the Go runtime max threads threshold
|
|
func configureMaxThreads(config *Config) error {
|
|
return nil
|
|
}
|
|
|
|
func (daemon *Daemon) initNetworkController(config *Config, activeSandboxes map[string]interface{}) (libnetwork.NetworkController, error) {
|
|
netOptions, err := daemon.networkOptions(config, nil, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
controller, err := libnetwork.New(netOptions...)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error obtaining controller instance: %v", err)
|
|
}
|
|
|
|
hnsresponse, err := hcsshim.HNSListNetworkRequest("GET", "", "")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Remove networks not present in HNS
|
|
for _, v := range controller.Networks() {
|
|
options := v.Info().DriverOptions()
|
|
hnsid := options[winlibnetwork.HNSID]
|
|
found := false
|
|
|
|
for _, v := range hnsresponse {
|
|
if v.Id == hnsid {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !found {
|
|
// global networks should not be deleted by local HNS
|
|
if v.Info().Scope() != datastore.GlobalScope {
|
|
err = v.Delete()
|
|
if err != nil {
|
|
logrus.Errorf("Error occurred when removing network %v", err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
_, err = controller.NewNetwork("null", "none", "", libnetwork.NetworkOptionPersist(false))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
defaultNetworkExists := false
|
|
|
|
if network, err := controller.NetworkByName(runconfig.DefaultDaemonNetworkMode().NetworkName()); err == nil {
|
|
options := network.Info().DriverOptions()
|
|
for _, v := range hnsresponse {
|
|
if options[winlibnetwork.HNSID] == v.Id {
|
|
defaultNetworkExists = true
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// discover and add HNS networks to windows
|
|
// network that exist are removed and added again
|
|
for _, v := range hnsresponse {
|
|
var n libnetwork.Network
|
|
s := func(current libnetwork.Network) bool {
|
|
options := current.Info().DriverOptions()
|
|
if options[winlibnetwork.HNSID] == v.Id {
|
|
n = current
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
controller.WalkNetworks(s)
|
|
if n != nil {
|
|
// global networks should not be deleted by local HNS
|
|
if n.Info().Scope() == datastore.GlobalScope {
|
|
continue
|
|
}
|
|
v.Name = n.Name()
|
|
// This will not cause network delete from HNS as the network
|
|
// is not yet populated in the libnetwork windows driver
|
|
n.Delete()
|
|
}
|
|
|
|
netOption := map[string]string{
|
|
winlibnetwork.NetworkName: v.Name,
|
|
winlibnetwork.HNSID: v.Id,
|
|
}
|
|
|
|
v4Conf := []*libnetwork.IpamConf{}
|
|
for _, subnet := range v.Subnets {
|
|
ipamV4Conf := libnetwork.IpamConf{}
|
|
ipamV4Conf.PreferredPool = subnet.AddressPrefix
|
|
ipamV4Conf.Gateway = subnet.GatewayAddress
|
|
v4Conf = append(v4Conf, &ipamV4Conf)
|
|
}
|
|
|
|
name := v.Name
|
|
|
|
// If there is no nat network create one from the first NAT network
|
|
// encountered
|
|
if !defaultNetworkExists && runconfig.DefaultDaemonNetworkMode() == containertypes.NetworkMode(strings.ToLower(v.Type)) {
|
|
name = runconfig.DefaultDaemonNetworkMode().NetworkName()
|
|
defaultNetworkExists = true
|
|
}
|
|
|
|
v6Conf := []*libnetwork.IpamConf{}
|
|
_, err := controller.NewNetwork(strings.ToLower(v.Type), name, "",
|
|
libnetwork.NetworkOptionGeneric(options.Generic{
|
|
netlabel.GenericData: netOption,
|
|
}),
|
|
libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil),
|
|
)
|
|
|
|
if err != nil {
|
|
logrus.Errorf("Error occurred when creating network %v", err)
|
|
}
|
|
}
|
|
|
|
if !config.DisableBridge {
|
|
// Initialize default driver "bridge"
|
|
if err := initBridgeDriver(controller, config); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return controller, nil
|
|
}
|
|
|
|
func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error {
|
|
if _, err := controller.NetworkByName(runconfig.DefaultDaemonNetworkMode().NetworkName()); err == nil {
|
|
return nil
|
|
}
|
|
|
|
netOption := map[string]string{
|
|
winlibnetwork.NetworkName: runconfig.DefaultDaemonNetworkMode().NetworkName(),
|
|
}
|
|
|
|
var ipamOption libnetwork.NetworkOption
|
|
var subnetPrefix string
|
|
|
|
if config.bridgeConfig.FixedCIDR != "" {
|
|
subnetPrefix = config.bridgeConfig.FixedCIDR
|
|
} else {
|
|
// TP5 doesn't support properly detecting subnet
|
|
osv := system.GetOSVersion()
|
|
if osv.Build < 14360 {
|
|
subnetPrefix = defaultNetworkSpace
|
|
}
|
|
}
|
|
|
|
if subnetPrefix != "" {
|
|
ipamV4Conf := libnetwork.IpamConf{}
|
|
ipamV4Conf.PreferredPool = subnetPrefix
|
|
v4Conf := []*libnetwork.IpamConf{&ipamV4Conf}
|
|
v6Conf := []*libnetwork.IpamConf{}
|
|
ipamOption = libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil)
|
|
}
|
|
|
|
_, err := controller.NewNetwork(string(runconfig.DefaultDaemonNetworkMode()), runconfig.DefaultDaemonNetworkMode().NetworkName(), "",
|
|
libnetwork.NetworkOptionGeneric(options.Generic{
|
|
netlabel.GenericData: netOption,
|
|
}),
|
|
ipamOption,
|
|
)
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("Error creating default network: %v", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// registerLinks sets up links between containers and writes the
|
|
// configuration out for persistence. As of Windows TP4, links are not supported.
|
|
func (daemon *Daemon) registerLinks(container *container.Container, hostConfig *containertypes.HostConfig) error {
|
|
return nil
|
|
}
|
|
|
|
func (daemon *Daemon) cleanupMountsByID(in string) error {
|
|
return nil
|
|
}
|
|
|
|
func (daemon *Daemon) cleanupMounts() error {
|
|
return nil
|
|
}
|
|
|
|
func setupRemappedRoot(config *Config) ([]idtools.IDMap, []idtools.IDMap, error) {
|
|
return nil, nil, nil
|
|
}
|
|
|
|
func setupDaemonRoot(config *Config, rootDir string, rootUID, rootGID int) error {
|
|
config.Root = rootDir
|
|
// Create the root directory if it doesn't exists
|
|
if err := system.MkdirAllWithACL(config.Root, 0); err != nil && !os.IsExist(err) {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// runasHyperVContainer returns true if we are going to run as a Hyper-V container
|
|
func (daemon *Daemon) runAsHyperVContainer(hostConfig *containertypes.HostConfig) bool {
|
|
if hostConfig.Isolation.IsDefault() {
|
|
// Container is set to use the default, so take the default from the daemon configuration
|
|
return daemon.defaultIsolation.IsHyperV()
|
|
}
|
|
|
|
// Container is requesting an isolation mode. Honour it.
|
|
return hostConfig.Isolation.IsHyperV()
|
|
|
|
}
|
|
|
|
// conditionalMountOnStart is a platform specific helper function during the
|
|
// container start to call mount.
|
|
func (daemon *Daemon) conditionalMountOnStart(container *container.Container) error {
|
|
// We do not mount if a Hyper-V container
|
|
if !daemon.runAsHyperVContainer(container.HostConfig) {
|
|
return daemon.Mount(container)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// conditionalUnmountOnCleanup is a platform specific helper function called
|
|
// during the cleanup of a container to unmount.
|
|
func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container) error {
|
|
// We do not unmount if a Hyper-V container
|
|
if !daemon.runAsHyperVContainer(container.HostConfig) {
|
|
return daemon.Unmount(container)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func driverOptions(config *Config) []nwconfig.Option {
|
|
return []nwconfig.Option{}
|
|
}
|
|
|
|
func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) {
|
|
if !c.IsRunning() {
|
|
return nil, errNotRunning{c.ID}
|
|
}
|
|
|
|
// Obtain the stats from HCS via libcontainerd
|
|
stats, err := daemon.containerd.Stats(c.ID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Start with an empty structure
|
|
s := &types.StatsJSON{}
|
|
|
|
// Populate the CPU/processor statistics
|
|
s.CPUStats = types.CPUStats{
|
|
CPUUsage: types.CPUUsage{
|
|
TotalUsage: stats.Processor.TotalRuntime100ns,
|
|
UsageInKernelmode: stats.Processor.RuntimeKernel100ns,
|
|
UsageInUsermode: stats.Processor.RuntimeKernel100ns,
|
|
},
|
|
}
|
|
|
|
// Populate the memory statistics
|
|
s.MemoryStats = types.MemoryStats{
|
|
Commit: stats.Memory.UsageCommitBytes,
|
|
CommitPeak: stats.Memory.UsageCommitPeakBytes,
|
|
PrivateWorkingSet: stats.Memory.UsagePrivateWorkingSetBytes,
|
|
}
|
|
|
|
// Populate the storage statistics
|
|
s.StorageStats = types.StorageStats{
|
|
ReadCountNormalized: stats.Storage.ReadCountNormalized,
|
|
ReadSizeBytes: stats.Storage.ReadSizeBytes,
|
|
WriteCountNormalized: stats.Storage.WriteCountNormalized,
|
|
WriteSizeBytes: stats.Storage.WriteSizeBytes,
|
|
}
|
|
|
|
// Populate the network statistics
|
|
s.Networks = make(map[string]types.NetworkStats)
|
|
|
|
for _, nstats := range stats.Network {
|
|
s.Networks[nstats.EndpointId] = types.NetworkStats{
|
|
RxBytes: nstats.BytesReceived,
|
|
RxPackets: nstats.PacketsReceived,
|
|
RxDropped: nstats.DroppedPacketsIncoming,
|
|
TxBytes: nstats.BytesSent,
|
|
TxPackets: nstats.PacketsSent,
|
|
TxDropped: nstats.DroppedPacketsOutgoing,
|
|
}
|
|
}
|
|
|
|
// Set the timestamp
|
|
s.Stats.Read = stats.Timestamp
|
|
s.Stats.NumProcs = platform.NumProcs()
|
|
|
|
return s, 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
|
|
}
|
|
|
|
func rootFSToAPIType(rootfs *image.RootFS) types.RootFS {
|
|
var layers []string
|
|
for _, l := range rootfs.DiffIDs {
|
|
layers = append(layers, l.String())
|
|
}
|
|
return types.RootFS{
|
|
Type: rootfs.Type,
|
|
Layers: layers,
|
|
}
|
|
}
|
|
|
|
func setupDaemonProcess(config *Config) error {
|
|
return nil
|
|
}
|
|
|
|
// verifyVolumesInfo is a no-op on windows.
|
|
// This is called during daemon initialization to migrate volumes from pre-1.7.
|
|
// volumes were not supported on windows pre-1.7
|
|
func (daemon *Daemon) verifyVolumesInfo(container *container.Container) error {
|
|
return nil
|
|
}
|
|
|
|
func (daemon *Daemon) setupSeccompProfile() error {
|
|
return nil
|
|
}
|