daemon/daemon_windows.go
8fb0ca2c
 package daemon
 
 import (
ddae20c0
 	"context"
8fb0ca2c
 	"fmt"
26517a01
 	"path/filepath"
4352da78
 	"strings"
8fb0ca2c
 
e8026d8a
 	"github.com/Microsoft/hcsshim"
91e197d6
 	"github.com/docker/docker/api/types"
 	containertypes "github.com/docker/docker/api/types/container"
6bb0d181
 	"github.com/docker/docker/container"
db63f937
 	"github.com/docker/docker/daemon/config"
4352da78
 	"github.com/docker/docker/image"
7a7357da
 	"github.com/docker/docker/pkg/containerfs"
8e71b1e2
 	"github.com/docker/docker/pkg/fileutils"
557c7cb8
 	"github.com/docker/docker/pkg/idtools"
94d70d83
 	"github.com/docker/docker/pkg/parsers"
340e5233
 	"github.com/docker/docker/pkg/platform"
8df20663
 	"github.com/docker/docker/pkg/sysinfo"
805dd0ee
 	"github.com/docker/docker/pkg/system"
8df20663
 	"github.com/docker/docker/runconfig"
8fb0ca2c
 	"github.com/docker/libnetwork"
ed364b69
 	nwconfig "github.com/docker/libnetwork/config"
ed8ccc30
 	"github.com/docker/libnetwork/datastore"
e8026d8a
 	winlibnetwork "github.com/docker/libnetwork/drivers/windows"
 	"github.com/docker/libnetwork/netlabel"
 	"github.com/docker/libnetwork/options"
1edcc635
 	"github.com/pkg/errors"
1009e6a4
 	"github.com/sirupsen/logrus"
000366f1
 	"golang.org/x/sys/windows"
1edcc635
 	"golang.org/x/sys/windows/svc/mgr"
8fb0ca2c
 )
 
10d30c64
 const (
4e15420b
 	defaultNetworkSpace  = "172.16.0.0/12"
 	platformSupported    = true
 	windowsMinCPUShares  = 1
 	windowsMaxCPUShares  = 10000
 	windowsMinCPUPercent = 1
 	windowsMaxCPUPercent = 100
10d30c64
 )
e0ec0cc1
 
26517a01
 // Windows has no concept of an execution state directory. So use config.Root here.
 func getPluginExecRoot(root string) string {
 	return filepath.Join(root, "plugins")
 }
 
d7fda019
 func (daemon *Daemon) parseSecurityOpt(container *container.Container, hostConfig *containertypes.HostConfig) error {
 	return parseSecurityOpt(container, hostConfig)
 }
 
7ac4232e
 func parseSecurityOpt(container *container.Container, config *containertypes.HostConfig) error {
8fb0ca2c
 	return nil
 }
 
7a7357da
 func (daemon *Daemon) getLayerInit() func(containerfs.ContainerFS) error {
2508ca00
 	return nil
 }
 
8fb0ca2c
 func checkKernel() error {
 	return nil
 }
 
ca89c329
 func (daemon *Daemon) getCgroupDriver() string {
 	return ""
 }
 
3fea79bf
 // adaptContainerSettings is called during container creation to modify any
 // settings necessary in the HostConfig structure.
7ac4232e
 func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConfig, adjustCPUShares bool) error {
608b3db5
 	if hostConfig == nil {
4089b4e4
 		return nil
608b3db5
 	}
 
4089b4e4
 	return nil
7e0dfbf4
 }
 
4e15420b
 func verifyContainerResources(resources *containertypes.Resources, isHyperv bool) ([]string, error) {
ea8c6908
 	warnings := []string{}
9d87e6e0
 	fixMemorySwappiness(resources)
4e15420b
 	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
 			}
 		}
ea8c6908
 	}
 
0ed00b36
 	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")
846baf1f
 	}
 
0ed00b36
 	if resources.NanoCPUs > 0 && resources.CPUPercent > 0 {
 		return warnings, fmt.Errorf("conflicting options: Nano CPUs and CPU Percent cannot both be set")
 	}
846baf1f
 	if resources.NanoCPUs > 0 && resources.CPUShares > 0 {
0ed00b36
 		return warnings, fmt.Errorf("conflicting options: Nano CPUs and CPU Shares cannot both be set")
846baf1f
 	}
d22ac2f3
 	// 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.
846baf1f
 	if resources.NanoCPUs < 0 || resources.NanoCPUs > int64(sysinfo.NumCPU())*1e9 {
d22ac2f3
 		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())
846baf1f
 	}
 
3b5af0a2
 	osv := system.GetOSVersion()
 	if resources.NanoCPUs > 0 && isHyperv && osv.Build < 16175 {
 		leftoverNanoCPUs := resources.NanoCPUs % 1e9
 		if leftoverNanoCPUs != 0 && resources.NanoCPUs > 1e9 {
 			resources.NanoCPUs = ((resources.NanoCPUs + 1e9/2) / 1e9) * 1e9
 			warningString := fmt.Sprintf("Your current OS version does not support Hyper-V containers with NanoCPUs greater than 1000000000 but not divisible by 1000000000. NanoCPUs rounded to %d", resources.NanoCPUs)
 			warnings = append(warnings, warningString)
 			logrus.Warn(warningString)
 		}
 	}
 
0ed00b36
 	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")
 	}
8df20663
 	if resources.BlkioWeight > 0 {
0ed00b36
 		return warnings, fmt.Errorf("invalid option: Windows does not support BlkioWeight")
8df20663
 	}
 	if len(resources.BlkioWeightDevice) > 0 {
0ed00b36
 		return warnings, fmt.Errorf("invalid option: Windows does not support BlkioWeightDevice")
8df20663
 	}
0ed00b36
 	if resources.CgroupParent != "" {
 		return warnings, fmt.Errorf("invalid option: Windows does not support CgroupParent")
8df20663
 	}
0ed00b36
 	if resources.CPUPeriod != 0 {
 		return warnings, fmt.Errorf("invalid option: Windows does not support CPUPeriod")
8df20663
 	}
0ed00b36
 	if resources.CpusetCpus != "" {
 		return warnings, fmt.Errorf("invalid option: Windows does not support CpusetCpus")
8df20663
 	}
0ed00b36
 	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")
 	}
9d87e6e0
 	if resources.MemorySwappiness != nil {
0ed00b36
 		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")
8df20663
 	}
ea8c6908
 	return warnings, nil
 }
 
3fea79bf
 // verifyPlatformContainerSettings performs platform-specific validation of the
 // hostconfig and config structures.
8ae6f6ac
 func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) {
ea8c6908
 	warnings := []string{}
 
6b4ad8d6
 	hyperv := daemon.runAsHyperVContainer(hostConfig)
75f7f2a8
 	if !hyperv && system.IsWindowsClient() && !system.IsIoTCore() {
6b4ad8d6
 		// @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)
ea8c6908
 	warnings = append(warnings, w...)
3a425180
 	return warnings, err
8fb0ca2c
 }
 
5ce5a8e9
 // verifyDaemonSettings performs validation of daemon config struct
db63f937
 func verifyDaemonSettings(config *config.Config) error {
8fb0ca2c
 	return nil
 }
 
62a75fca
 // checkSystem validates platform-specific requirements
8fb0ca2c
 func checkSystem() error {
 	// Validate the OS version. Note that docker.exe must be manifested for this
 	// call to return the correct version.
194eaa5c
 	osv := system.GetOSVersion()
805dd0ee
 	if osv.MajorVersion < 10 {
8fb0ca2c
 		return fmt.Errorf("This version of Windows does not support the docker daemon")
 	}
cc4e17cb
 	if osv.Build < 14393 {
 		return fmt.Errorf("The docker daemon requires build 14393 or later of Windows Server 2016 or Windows 10")
122568b3
 	}
000366f1
 
 	vmcompute := windows.NewLazySystemDLL("vmcompute.dll")
 	if vmcompute.Load() != nil {
31405b55
 		return fmt.Errorf("failed to load vmcompute.dll, ensure that the Containers feature is installed")
000366f1
 	}
e128a656
 
1edcc635
 	// Ensure that the required Host Network Service and vmcompute services
 	// are running. Docker will fail in unexpected ways if this is not present.
 	var requiredServices = []string{"hns", "vmcompute"}
 	if err := ensureServicesInstalled(requiredServices); err != nil {
 		return errors.Wrap(err, "a required service is not installed, ensure the Containers feature is installed")
 	}
 
 	return nil
 }
 
 func ensureServicesInstalled(services []string) error {
 	m, err := mgr.Connect()
 	if err != nil {
 		return err
 	}
 	defer m.Disconnect()
 	for _, service := range services {
 		s, err := m.OpenService(service)
 		if err != nil {
 			return errors.Wrapf(err, "failed to open service %s", service)
 		}
 		s.Close()
 	}
6eed7f0c
 	return nil
8fb0ca2c
 }
 
 // configureKernelSecuritySupport configures and validate security support for the kernel
ce8e529e
 func configureKernelSecuritySupport(config *config.Config, driverName string) error {
8fb0ca2c
 	return nil
 }
 
140a7434
 // configureMaxThreads sets the Go runtime max threads threshold
db63f937
 func configureMaxThreads(config *config.Config) error {
140a7434
 	return nil
 }
 
db63f937
 func (daemon *Daemon) initNetworkController(config *config.Config, activeSandboxes map[string]interface{}) (libnetwork.NetworkController, error) {
a00940f0
 	netOptions, err := daemon.networkOptions(config, nil, nil)
e8026d8a
 	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 {
ed8ccc30
 			// 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)
 				}
e8026d8a
 			}
 		}
 	}
 
6eb2b903
 	_, err = controller.NewNetwork("null", "none", "", libnetwork.NetworkOptionPersist(false))
e8026d8a
 	if err != nil {
 		return nil, err
 	}
 
aad25801
 	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
 			}
 		}
 	}
 
e8026d8a
 	// discover and add HNS networks to windows
 	// network that exist are removed and added again
 	for _, v := range hnsresponse {
b91fd26b
 		if strings.ToLower(v.Type) == "private" {
 			continue // workaround for HNS reporting unsupported networks
 		}
e8026d8a
 		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)
cef1578a
 
 		drvOptions := make(map[string]string)
 
e8026d8a
 		if n != nil {
ed8ccc30
 			// global networks should not be deleted by local HNS
 			if n.Info().Scope() == datastore.GlobalScope {
 				continue
 			}
e8026d8a
 			v.Name = n.Name()
aad25801
 			// This will not cause network delete from HNS as the network
 			// is not yet populated in the libnetwork windows driver
cef1578a
 
 			// restore option if it existed before
 			drvOptions = n.Info().DriverOptions()
e8026d8a
 			n.Delete()
 		}
 		netOption := map[string]string{
 			winlibnetwork.NetworkName: v.Name,
 			winlibnetwork.HNSID:       v.Id,
 		}
 
cef1578a
 		// add persisted driver options
 		for k, v := range drvOptions {
 			if k != winlibnetwork.NetworkName && k != winlibnetwork.HNSID {
 				netOption[k] = v
 			}
 		}
 
e8026d8a
 		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
aad25801
 
 		// If there is no nat network create one from the first NAT network
e6962481
 		// encountered if it doesn't already exist
 		if !defaultNetworkExists &&
 			runconfig.DefaultDaemonNetworkMode() == containertypes.NetworkMode(strings.ToLower(v.Type)) &&
 			n == nil {
e8026d8a
 			name = runconfig.DefaultDaemonNetworkMode().NetworkName()
aad25801
 			defaultNetworkExists = true
e8026d8a
 		}
 
 		v6Conf := []*libnetwork.IpamConf{}
6eb2b903
 		_, err := controller.NewNetwork(strings.ToLower(v.Type), name, "",
e8026d8a
 			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
8fb0ca2c
 }
 
db63f937
 func initBridgeDriver(controller libnetwork.NetworkController, config *config.Config) error {
e8026d8a
 	if _, err := controller.NetworkByName(runconfig.DefaultDaemonNetworkMode().NetworkName()); err == nil {
 		return nil
e0ec0cc1
 	}
e8026d8a
 
 	netOption := map[string]string{
 		winlibnetwork.NetworkName: runconfig.DefaultDaemonNetworkMode().NetworkName(),
 	}
 
aad25801
 	var ipamOption libnetwork.NetworkOption
 	var subnetPrefix string
 
db63f937
 	if config.BridgeConfig.FixedCIDR != "" {
 		subnetPrefix = config.BridgeConfig.FixedCIDR
e8026d8a
 	} else {
aad25801
 		// TP5 doesn't support properly detecting subnet
 		osv := system.GetOSVersion()
 		if osv.Build < 14360 {
 			subnetPrefix = defaultNetworkSpace
 		}
e8026d8a
 	}
 
aad25801
 	if subnetPrefix != "" {
 		ipamV4Conf := libnetwork.IpamConf{}
 		ipamV4Conf.PreferredPool = subnetPrefix
 		v4Conf := []*libnetwork.IpamConf{&ipamV4Conf}
 		v6Conf := []*libnetwork.IpamConf{}
 		ipamOption = libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil)
 	}
e8026d8a
 
6eb2b903
 	_, err := controller.NewNetwork(string(runconfig.DefaultDaemonNetworkMode()), runconfig.DefaultDaemonNetworkMode().NetworkName(), "",
e8026d8a
 		libnetwork.NetworkOptionGeneric(options.Generic{
 			netlabel.GenericData: netOption,
 		}),
aad25801
 		ipamOption,
e8026d8a
 	)
 
 	if err != nil {
 		return fmt.Errorf("Error creating default network: %v", err)
 	}
aad25801
 
e8026d8a
 	return nil
8fb0ca2c
 }
c5e6a4b3
 
abd72d40
 // registerLinks sets up links between containers and writes the
b2771b44
 // configuration out for persistence. As of Windows TP4, links are not supported.
7ac4232e
 func (daemon *Daemon) registerLinks(container *container.Container, hostConfig *containertypes.HostConfig) error {
c5e6a4b3
 	return nil
 }
47c56e43
 
94d70d83
 func (daemon *Daemon) cleanupMountsByID(in string) error {
 	return nil
 }
 
c8291f71
 func (daemon *Daemon) cleanupMounts() error {
 	return nil
 }
3a497650
 
09cd96c5
 func setupRemappedRoot(config *config.Config) (*idtools.IDMappings, error) {
 	return &idtools.IDMappings{}, nil
557c7cb8
 }
 
09cd96c5
 func setupDaemonRoot(config *config.Config, rootDir string, rootIDs idtools.IDPair) error {
557c7cb8
 	config.Root = rootDir
 	// Create the root directory if it doesn't exists
516010e9
 	if err := system.MkdirAllWithACL(config.Root, 0, system.SddlAdministratorsLocalSystem); err != nil {
557c7cb8
 		return err
 	}
 	return nil
 }
 
4461bc45
 // runasHyperVContainer returns true if we are going to run as a Hyper-V container
4e15420b
 func (daemon *Daemon) runAsHyperVContainer(hostConfig *containertypes.HostConfig) bool {
 	if hostConfig.Isolation.IsDefault() {
94d70d83
 		// Container is set to use the default, so take the default from the daemon configuration
4461bc45
 		return daemon.defaultIsolation.IsHyperV()
94d70d83
 	}
 
4461bc45
 	// Container is requesting an isolation mode. Honour it.
4e15420b
 	return hostConfig.Isolation.IsHyperV()
4461bc45
 
 }
 
 // conditionalMountOnStart is a platform specific helper function during the
 // container start to call mount.
 func (daemon *Daemon) conditionalMountOnStart(container *container.Container) error {
0380fbff
 	// Bail out now for Linux containers. We cannot mount the containers filesystem on the
 	// host as it is a non-Windows filesystem.
 	if system.LCOWSupported() && container.OS != "windows" {
f8aa7005
 		return nil
 	}
 
0380fbff
 	// We do not mount if a Hyper-V container as it needs to be mounted inside the
 	// utility VM, not the host.
4e15420b
 	if !daemon.runAsHyperVContainer(container.HostConfig) {
4461bc45
 		return daemon.Mount(container)
3a497650
 	}
 	return nil
 }
 
 // conditionalUnmountOnCleanup is a platform specific helper function called
 // during the cleanup of a container to unmount.
94d70d83
 func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container) error {
f8aa7005
 	// Bail out now for Linux containers
0380fbff
 	if system.LCOWSupported() && container.OS != "windows" {
f8aa7005
 		return nil
 	}
 
3a497650
 	// We do not unmount if a Hyper-V container
4e15420b
 	if !daemon.runAsHyperVContainer(container.HostConfig) {
94d70d83
 		return daemon.Unmount(container)
4352da78
 	}
94d70d83
 	return nil
4352da78
 }
 
db63f937
 func driverOptions(config *config.Config) []nwconfig.Option {
e8026d8a
 	return []nwconfig.Option{}
ed364b69
 }
94d70d83
 
 func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) {
340e5233
 	if !c.IsRunning() {
ebcb7d6b
 		return nil, errNotRunning(c.ID)
340e5233
 	}
 
 	// Obtain the stats from HCS via libcontainerd
ddae20c0
 	stats, err := daemon.containerd.Stats(context.Background(), c.ID)
340e5233
 	if err != nil {
4a6cbf9b
 		if strings.Contains(err.Error(), "container not found") {
ebcb7d6b
 			return nil, containerNotFound(c.ID)
4a6cbf9b
 		}
340e5233
 		return nil, err
 	}
 
 	// Start with an empty structure
 	s := &types.StatsJSON{}
ddae20c0
 	s.Stats.Read = stats.Read
 	s.Stats.NumProcs = platform.NumProcs()
340e5233
 
ddae20c0
 	if stats.HCSStats != nil {
 		hcss := stats.HCSStats
 		// Populate the CPU/processor statistics
 		s.CPUStats = types.CPUStats{
 			CPUUsage: types.CPUUsage{
 				TotalUsage:        hcss.Processor.TotalRuntime100ns,
 				UsageInKernelmode: hcss.Processor.RuntimeKernel100ns,
 				UsageInUsermode:   hcss.Processor.RuntimeKernel100ns,
 			},
340e5233
 		}
 
ddae20c0
 		// Populate the memory statistics
 		s.MemoryStats = types.MemoryStats{
 			Commit:            hcss.Memory.UsageCommitBytes,
 			CommitPeak:        hcss.Memory.UsageCommitPeakBytes,
 			PrivateWorkingSet: hcss.Memory.UsagePrivateWorkingSetBytes,
 		}
340e5233
 
ddae20c0
 		// Populate the storage statistics
 		s.StorageStats = types.StorageStats{
 			ReadCountNormalized:  hcss.Storage.ReadCountNormalized,
 			ReadSizeBytes:        hcss.Storage.ReadSizeBytes,
 			WriteCountNormalized: hcss.Storage.WriteCountNormalized,
 			WriteSizeBytes:       hcss.Storage.WriteSizeBytes,
 		}
 
 		// Populate the network statistics
 		s.Networks = make(map[string]types.NetworkStats)
 		for _, nstats := range hcss.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,
 			}
 		}
 	}
340e5233
 	return s, nil
94d70d83
 }
 
 // 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")
75f7f2a8
 	// On client SKUs, default to Hyper-V. Note that IoT reports as a client SKU
 	// but it should not be treated as such.
 	if system.IsWindowsClient() && !system.IsIoTCore() {
ef2db56b
 		daemon.defaultIsolation = containertypes.Isolation("hyperv")
 	}
94d70d83
 	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")
 			}
ef2db56b
 			if containertypes.Isolation(val).IsProcess() {
75f7f2a8
 				if system.IsWindowsClient() && !system.IsIoTCore() {
87ab13ad
 					// @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.
ef2db56b
 					return fmt.Errorf("Windows client operating systems only support Hyper-V containers")
 				}
 				daemon.defaultIsolation = containertypes.Isolation("process")
 			}
94d70d83
 		default:
 			return fmt.Errorf("Unrecognised exec-opt '%s'\n", key)
 		}
 	}
 
 	logrus.Infof("Windows default isolation mode: %s", daemon.defaultIsolation)
 	return nil
 }
14dc4a71
 
 func rootFSToAPIType(rootfs *image.RootFS) types.RootFS {
 	var layers []string
 	for _, l := range rootfs.DiffIDs {
 		layers = append(layers, l.String())
 	}
 	return types.RootFS{
f342b271
 		Type:   rootfs.Type,
 		Layers: layers,
14dc4a71
 	}
 }
a894aec8
 
db63f937
 func setupDaemonProcess(config *config.Config) error {
a894aec8
 	return nil
 }
dc712b92
 
 // 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
 }
b237189e
 
 func (daemon *Daemon) setupSeccompProfile() error {
 	return nil
 }
8e71b1e2
 
 func getRealPath(path string) (string, error) {
 	if system.IsIoTCore() {
 		// Due to https://github.com/golang/go/issues/20506, path expansion
 		// does not work correctly on the default IoT Core configuration.
 		// TODO @darrenstahlmsft remove this once golang/go/20506 is fixed
 		return path, nil
 	}
 	return fileutils.ReadSymlinkedDirectory(path)
 }
ddae20c0
 
 func (daemon *Daemon) loadRuntimes() error {
 	return nil
 }
 
 func (daemon *Daemon) initRuntimes(_ map[string]types.Runtime) error {
 	return nil
 }