github.com/ssdev-go/moby@v17.12.1-ce-rc2+incompatible/daemon/daemon_windows.go (about)

     1  package daemon
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"path/filepath"
     7  	"strings"
     8  
     9  	"github.com/Microsoft/hcsshim"
    10  	"github.com/docker/docker/api/types"
    11  	containertypes "github.com/docker/docker/api/types/container"
    12  	"github.com/docker/docker/container"
    13  	"github.com/docker/docker/daemon/config"
    14  	"github.com/docker/docker/image"
    15  	"github.com/docker/docker/pkg/containerfs"
    16  	"github.com/docker/docker/pkg/fileutils"
    17  	"github.com/docker/docker/pkg/idtools"
    18  	"github.com/docker/docker/pkg/parsers"
    19  	"github.com/docker/docker/pkg/platform"
    20  	"github.com/docker/docker/pkg/sysinfo"
    21  	"github.com/docker/docker/pkg/system"
    22  	"github.com/docker/docker/runconfig"
    23  	"github.com/docker/libnetwork"
    24  	nwconfig "github.com/docker/libnetwork/config"
    25  	"github.com/docker/libnetwork/datastore"
    26  	winlibnetwork "github.com/docker/libnetwork/drivers/windows"
    27  	"github.com/docker/libnetwork/netlabel"
    28  	"github.com/docker/libnetwork/options"
    29  	blkiodev "github.com/opencontainers/runc/libcontainer/configs"
    30  	"github.com/pkg/errors"
    31  	"github.com/sirupsen/logrus"
    32  	"golang.org/x/sys/windows"
    33  	"golang.org/x/sys/windows/svc/mgr"
    34  )
    35  
    36  const (
    37  	defaultNetworkSpace  = "172.16.0.0/12"
    38  	platformSupported    = true
    39  	windowsMinCPUShares  = 1
    40  	windowsMaxCPUShares  = 10000
    41  	windowsMinCPUPercent = 1
    42  	windowsMaxCPUPercent = 100
    43  )
    44  
    45  // Windows has no concept of an execution state directory. So use config.Root here.
    46  func getPluginExecRoot(root string) string {
    47  	return filepath.Join(root, "plugins")
    48  }
    49  
    50  func getBlkioWeightDevices(config *containertypes.HostConfig) ([]blkiodev.WeightDevice, error) {
    51  	return nil, nil
    52  }
    53  
    54  func (daemon *Daemon) parseSecurityOpt(container *container.Container, hostConfig *containertypes.HostConfig) error {
    55  	return parseSecurityOpt(container, hostConfig)
    56  }
    57  
    58  func parseSecurityOpt(container *container.Container, config *containertypes.HostConfig) error {
    59  	return nil
    60  }
    61  
    62  func (daemon *Daemon) getLayerInit() func(containerfs.ContainerFS) error {
    63  	return nil
    64  }
    65  
    66  func checkKernel() error {
    67  	return nil
    68  }
    69  
    70  func (daemon *Daemon) getCgroupDriver() string {
    71  	return ""
    72  }
    73  
    74  // adaptContainerSettings is called during container creation to modify any
    75  // settings necessary in the HostConfig structure.
    76  func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConfig, adjustCPUShares bool) error {
    77  	if hostConfig == nil {
    78  		return nil
    79  	}
    80  
    81  	return nil
    82  }
    83  
    84  func verifyContainerResources(resources *containertypes.Resources, isHyperv bool) ([]string, error) {
    85  	warnings := []string{}
    86  	fixMemorySwappiness(resources)
    87  	if !isHyperv {
    88  		// The processor resource controls are mutually exclusive on
    89  		// Windows Server Containers, the order of precedence is
    90  		// CPUCount first, then CPUShares, and CPUPercent last.
    91  		if resources.CPUCount > 0 {
    92  			if resources.CPUShares > 0 {
    93  				warnings = append(warnings, "Conflicting options: CPU count takes priority over CPU shares on Windows Server Containers. CPU shares discarded")
    94  				logrus.Warn("Conflicting options: CPU count takes priority over CPU shares on Windows Server Containers. CPU shares discarded")
    95  				resources.CPUShares = 0
    96  			}
    97  			if resources.CPUPercent > 0 {
    98  				warnings = append(warnings, "Conflicting options: CPU count takes priority over CPU percent on Windows Server Containers. CPU percent discarded")
    99  				logrus.Warn("Conflicting options: CPU count takes priority over CPU percent on Windows Server Containers. CPU percent discarded")
   100  				resources.CPUPercent = 0
   101  			}
   102  		} else if resources.CPUShares > 0 {
   103  			if resources.CPUPercent > 0 {
   104  				warnings = append(warnings, "Conflicting options: CPU shares takes priority over CPU percent on Windows Server Containers. CPU percent discarded")
   105  				logrus.Warn("Conflicting options: CPU shares takes priority over CPU percent on Windows Server Containers. CPU percent discarded")
   106  				resources.CPUPercent = 0
   107  			}
   108  		}
   109  	}
   110  
   111  	if resources.CPUShares < 0 || resources.CPUShares > windowsMaxCPUShares {
   112  		return warnings, fmt.Errorf("range of CPUShares is from %d to %d", windowsMinCPUShares, windowsMaxCPUShares)
   113  	}
   114  	if resources.CPUPercent < 0 || resources.CPUPercent > windowsMaxCPUPercent {
   115  		return warnings, fmt.Errorf("range of CPUPercent is from %d to %d", windowsMinCPUPercent, windowsMaxCPUPercent)
   116  	}
   117  	if resources.CPUCount < 0 {
   118  		return warnings, fmt.Errorf("invalid CPUCount: CPUCount cannot be negative")
   119  	}
   120  
   121  	if resources.NanoCPUs > 0 && resources.CPUPercent > 0 {
   122  		return warnings, fmt.Errorf("conflicting options: Nano CPUs and CPU Percent cannot both be set")
   123  	}
   124  	if resources.NanoCPUs > 0 && resources.CPUShares > 0 {
   125  		return warnings, fmt.Errorf("conflicting options: Nano CPUs and CPU Shares cannot both be set")
   126  	}
   127  	// The precision we could get is 0.01, because on Windows we have to convert to CPUPercent.
   128  	// We don't set the lower limit here and it is up to the underlying platform (e.g., Windows) to return an error.
   129  	if resources.NanoCPUs < 0 || resources.NanoCPUs > int64(sysinfo.NumCPU())*1e9 {
   130  		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())
   131  	}
   132  
   133  	osv := system.GetOSVersion()
   134  	if resources.NanoCPUs > 0 && isHyperv && osv.Build < 16175 {
   135  		leftoverNanoCPUs := resources.NanoCPUs % 1e9
   136  		if leftoverNanoCPUs != 0 && resources.NanoCPUs > 1e9 {
   137  			resources.NanoCPUs = ((resources.NanoCPUs + 1e9/2) / 1e9) * 1e9
   138  			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)
   139  			warnings = append(warnings, warningString)
   140  			logrus.Warn(warningString)
   141  		}
   142  	}
   143  
   144  	if len(resources.BlkioDeviceReadBps) > 0 {
   145  		return warnings, fmt.Errorf("invalid option: Windows does not support BlkioDeviceReadBps")
   146  	}
   147  	if len(resources.BlkioDeviceReadIOps) > 0 {
   148  		return warnings, fmt.Errorf("invalid option: Windows does not support BlkioDeviceReadIOps")
   149  	}
   150  	if len(resources.BlkioDeviceWriteBps) > 0 {
   151  		return warnings, fmt.Errorf("invalid option: Windows does not support BlkioDeviceWriteBps")
   152  	}
   153  	if len(resources.BlkioDeviceWriteIOps) > 0 {
   154  		return warnings, fmt.Errorf("invalid option: Windows does not support BlkioDeviceWriteIOps")
   155  	}
   156  	if resources.BlkioWeight > 0 {
   157  		return warnings, fmt.Errorf("invalid option: Windows does not support BlkioWeight")
   158  	}
   159  	if len(resources.BlkioWeightDevice) > 0 {
   160  		return warnings, fmt.Errorf("invalid option: Windows does not support BlkioWeightDevice")
   161  	}
   162  	if resources.CgroupParent != "" {
   163  		return warnings, fmt.Errorf("invalid option: Windows does not support CgroupParent")
   164  	}
   165  	if resources.CPUPeriod != 0 {
   166  		return warnings, fmt.Errorf("invalid option: Windows does not support CPUPeriod")
   167  	}
   168  	if resources.CpusetCpus != "" {
   169  		return warnings, fmt.Errorf("invalid option: Windows does not support CpusetCpus")
   170  	}
   171  	if resources.CpusetMems != "" {
   172  		return warnings, fmt.Errorf("invalid option: Windows does not support CpusetMems")
   173  	}
   174  	if resources.KernelMemory != 0 {
   175  		return warnings, fmt.Errorf("invalid option: Windows does not support KernelMemory")
   176  	}
   177  	if resources.MemoryReservation != 0 {
   178  		return warnings, fmt.Errorf("invalid option: Windows does not support MemoryReservation")
   179  	}
   180  	if resources.MemorySwap != 0 {
   181  		return warnings, fmt.Errorf("invalid option: Windows does not support MemorySwap")
   182  	}
   183  	if resources.MemorySwappiness != nil {
   184  		return warnings, fmt.Errorf("invalid option: Windows does not support MemorySwappiness")
   185  	}
   186  	if resources.OomKillDisable != nil && *resources.OomKillDisable {
   187  		return warnings, fmt.Errorf("invalid option: Windows does not support OomKillDisable")
   188  	}
   189  	if resources.PidsLimit != 0 {
   190  		return warnings, fmt.Errorf("invalid option: Windows does not support PidsLimit")
   191  	}
   192  	if len(resources.Ulimits) != 0 {
   193  		return warnings, fmt.Errorf("invalid option: Windows does not support Ulimits")
   194  	}
   195  	return warnings, nil
   196  }
   197  
   198  // verifyPlatformContainerSettings performs platform-specific validation of the
   199  // hostconfig and config structures.
   200  func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) {
   201  	warnings := []string{}
   202  
   203  	hyperv := daemon.runAsHyperVContainer(hostConfig)
   204  	if !hyperv && system.IsWindowsClient() && !system.IsIoTCore() {
   205  		// @engine maintainers. This block should not be removed. It partially enforces licensing
   206  		// restrictions on Windows. Ping @jhowardmsft if there are concerns or PRs to change this.
   207  		return warnings, fmt.Errorf("Windows client operating systems only support Hyper-V containers")
   208  	}
   209  
   210  	w, err := verifyContainerResources(&hostConfig.Resources, hyperv)
   211  	warnings = append(warnings, w...)
   212  	return warnings, err
   213  }
   214  
   215  // reloadPlatform updates configuration with platform specific options
   216  // and updates the passed attributes
   217  func (daemon *Daemon) reloadPlatform(config *config.Config, attributes map[string]string) error {
   218  	return nil
   219  }
   220  
   221  // verifyDaemonSettings performs validation of daemon config struct
   222  func verifyDaemonSettings(config *config.Config) error {
   223  	return nil
   224  }
   225  
   226  // checkSystem validates platform-specific requirements
   227  func checkSystem() error {
   228  	// Validate the OS version. Note that docker.exe must be manifested for this
   229  	// call to return the correct version.
   230  	osv := system.GetOSVersion()
   231  	if osv.MajorVersion < 10 {
   232  		return fmt.Errorf("This version of Windows does not support the docker daemon")
   233  	}
   234  	if osv.Build < 14393 {
   235  		return fmt.Errorf("The docker daemon requires build 14393 or later of Windows Server 2016 or Windows 10")
   236  	}
   237  
   238  	vmcompute := windows.NewLazySystemDLL("vmcompute.dll")
   239  	if vmcompute.Load() != nil {
   240  		return fmt.Errorf("failed to load vmcompute.dll, ensure that the Containers feature is installed")
   241  	}
   242  
   243  	// Ensure that the required Host Network Service and vmcompute services
   244  	// are running. Docker will fail in unexpected ways if this is not present.
   245  	var requiredServices = []string{"hns", "vmcompute"}
   246  	if err := ensureServicesInstalled(requiredServices); err != nil {
   247  		return errors.Wrap(err, "a required service is not installed, ensure the Containers feature is installed")
   248  	}
   249  
   250  	return nil
   251  }
   252  
   253  func ensureServicesInstalled(services []string) error {
   254  	m, err := mgr.Connect()
   255  	if err != nil {
   256  		return err
   257  	}
   258  	defer m.Disconnect()
   259  	for _, service := range services {
   260  		s, err := m.OpenService(service)
   261  		if err != nil {
   262  			return errors.Wrapf(err, "failed to open service %s", service)
   263  		}
   264  		s.Close()
   265  	}
   266  	return nil
   267  }
   268  
   269  // configureKernelSecuritySupport configures and validate security support for the kernel
   270  func configureKernelSecuritySupport(config *config.Config, driverNames []string) error {
   271  	return nil
   272  }
   273  
   274  // configureMaxThreads sets the Go runtime max threads threshold
   275  func configureMaxThreads(config *config.Config) error {
   276  	return nil
   277  }
   278  
   279  func (daemon *Daemon) initNetworkController(config *config.Config, activeSandboxes map[string]interface{}) (libnetwork.NetworkController, error) {
   280  	netOptions, err := daemon.networkOptions(config, nil, nil)
   281  	if err != nil {
   282  		return nil, err
   283  	}
   284  	controller, err := libnetwork.New(netOptions...)
   285  	if err != nil {
   286  		return nil, fmt.Errorf("error obtaining controller instance: %v", err)
   287  	}
   288  
   289  	hnsresponse, err := hcsshim.HNSListNetworkRequest("GET", "", "")
   290  	if err != nil {
   291  		return nil, err
   292  	}
   293  
   294  	// Remove networks not present in HNS
   295  	for _, v := range controller.Networks() {
   296  		options := v.Info().DriverOptions()
   297  		hnsid := options[winlibnetwork.HNSID]
   298  		found := false
   299  
   300  		for _, v := range hnsresponse {
   301  			if v.Id == hnsid {
   302  				found = true
   303  				break
   304  			}
   305  		}
   306  
   307  		if !found {
   308  			// global networks should not be deleted by local HNS
   309  			if v.Info().Scope() != datastore.GlobalScope {
   310  				err = v.Delete()
   311  				if err != nil {
   312  					logrus.Errorf("Error occurred when removing network %v", err)
   313  				}
   314  			}
   315  		}
   316  	}
   317  
   318  	_, err = controller.NewNetwork("null", "none", "", libnetwork.NetworkOptionPersist(false))
   319  	if err != nil {
   320  		return nil, err
   321  	}
   322  
   323  	defaultNetworkExists := false
   324  
   325  	if network, err := controller.NetworkByName(runconfig.DefaultDaemonNetworkMode().NetworkName()); err == nil {
   326  		options := network.Info().DriverOptions()
   327  		for _, v := range hnsresponse {
   328  			if options[winlibnetwork.HNSID] == v.Id {
   329  				defaultNetworkExists = true
   330  				break
   331  			}
   332  		}
   333  	}
   334  
   335  	// discover and add HNS networks to windows
   336  	// network that exist are removed and added again
   337  	for _, v := range hnsresponse {
   338  		if strings.ToLower(v.Type) == "private" {
   339  			continue // workaround for HNS reporting unsupported networks
   340  		}
   341  		var n libnetwork.Network
   342  		s := func(current libnetwork.Network) bool {
   343  			options := current.Info().DriverOptions()
   344  			if options[winlibnetwork.HNSID] == v.Id {
   345  				n = current
   346  				return true
   347  			}
   348  			return false
   349  		}
   350  
   351  		controller.WalkNetworks(s)
   352  
   353  		drvOptions := make(map[string]string)
   354  
   355  		if n != nil {
   356  			// global networks should not be deleted by local HNS
   357  			if n.Info().Scope() == datastore.GlobalScope {
   358  				continue
   359  			}
   360  			v.Name = n.Name()
   361  			// This will not cause network delete from HNS as the network
   362  			// is not yet populated in the libnetwork windows driver
   363  
   364  			// restore option if it existed before
   365  			drvOptions = n.Info().DriverOptions()
   366  			n.Delete()
   367  		}
   368  		netOption := map[string]string{
   369  			winlibnetwork.NetworkName: v.Name,
   370  			winlibnetwork.HNSID:       v.Id,
   371  		}
   372  
   373  		// add persisted driver options
   374  		for k, v := range drvOptions {
   375  			if k != winlibnetwork.NetworkName && k != winlibnetwork.HNSID {
   376  				netOption[k] = v
   377  			}
   378  		}
   379  
   380  		v4Conf := []*libnetwork.IpamConf{}
   381  		for _, subnet := range v.Subnets {
   382  			ipamV4Conf := libnetwork.IpamConf{}
   383  			ipamV4Conf.PreferredPool = subnet.AddressPrefix
   384  			ipamV4Conf.Gateway = subnet.GatewayAddress
   385  			v4Conf = append(v4Conf, &ipamV4Conf)
   386  		}
   387  
   388  		name := v.Name
   389  
   390  		// If there is no nat network create one from the first NAT network
   391  		// encountered if it doesn't already exist
   392  		if !defaultNetworkExists &&
   393  			runconfig.DefaultDaemonNetworkMode() == containertypes.NetworkMode(strings.ToLower(v.Type)) &&
   394  			n == nil {
   395  			name = runconfig.DefaultDaemonNetworkMode().NetworkName()
   396  			defaultNetworkExists = true
   397  		}
   398  
   399  		v6Conf := []*libnetwork.IpamConf{}
   400  		_, err := controller.NewNetwork(strings.ToLower(v.Type), name, "",
   401  			libnetwork.NetworkOptionGeneric(options.Generic{
   402  				netlabel.GenericData: netOption,
   403  			}),
   404  			libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil),
   405  		)
   406  
   407  		if err != nil {
   408  			logrus.Errorf("Error occurred when creating network %v", err)
   409  		}
   410  	}
   411  
   412  	if !config.DisableBridge {
   413  		// Initialize default driver "bridge"
   414  		if err := initBridgeDriver(controller, config); err != nil {
   415  			return nil, err
   416  		}
   417  	}
   418  
   419  	return controller, nil
   420  }
   421  
   422  func initBridgeDriver(controller libnetwork.NetworkController, config *config.Config) error {
   423  	if _, err := controller.NetworkByName(runconfig.DefaultDaemonNetworkMode().NetworkName()); err == nil {
   424  		return nil
   425  	}
   426  
   427  	netOption := map[string]string{
   428  		winlibnetwork.NetworkName: runconfig.DefaultDaemonNetworkMode().NetworkName(),
   429  	}
   430  
   431  	var ipamOption libnetwork.NetworkOption
   432  	var subnetPrefix string
   433  
   434  	if config.BridgeConfig.FixedCIDR != "" {
   435  		subnetPrefix = config.BridgeConfig.FixedCIDR
   436  	} else {
   437  		// TP5 doesn't support properly detecting subnet
   438  		osv := system.GetOSVersion()
   439  		if osv.Build < 14360 {
   440  			subnetPrefix = defaultNetworkSpace
   441  		}
   442  	}
   443  
   444  	if subnetPrefix != "" {
   445  		ipamV4Conf := libnetwork.IpamConf{}
   446  		ipamV4Conf.PreferredPool = subnetPrefix
   447  		v4Conf := []*libnetwork.IpamConf{&ipamV4Conf}
   448  		v6Conf := []*libnetwork.IpamConf{}
   449  		ipamOption = libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil)
   450  	}
   451  
   452  	_, err := controller.NewNetwork(string(runconfig.DefaultDaemonNetworkMode()), runconfig.DefaultDaemonNetworkMode().NetworkName(), "",
   453  		libnetwork.NetworkOptionGeneric(options.Generic{
   454  			netlabel.GenericData: netOption,
   455  		}),
   456  		ipamOption,
   457  	)
   458  
   459  	if err != nil {
   460  		return fmt.Errorf("Error creating default network: %v", err)
   461  	}
   462  
   463  	return nil
   464  }
   465  
   466  // registerLinks sets up links between containers and writes the
   467  // configuration out for persistence. As of Windows TP4, links are not supported.
   468  func (daemon *Daemon) registerLinks(container *container.Container, hostConfig *containertypes.HostConfig) error {
   469  	return nil
   470  }
   471  
   472  func (daemon *Daemon) cleanupMountsByID(in string) error {
   473  	return nil
   474  }
   475  
   476  func (daemon *Daemon) cleanupMounts() error {
   477  	return nil
   478  }
   479  
   480  func setupRemappedRoot(config *config.Config) (*idtools.IDMappings, error) {
   481  	return &idtools.IDMappings{}, nil
   482  }
   483  
   484  func setupDaemonRoot(config *config.Config, rootDir string, rootIDs idtools.IDPair) error {
   485  	config.Root = rootDir
   486  	// Create the root directory if it doesn't exists
   487  	if err := system.MkdirAllWithACL(config.Root, 0, system.SddlAdministratorsLocalSystem); err != nil {
   488  		return err
   489  	}
   490  	return nil
   491  }
   492  
   493  // runasHyperVContainer returns true if we are going to run as a Hyper-V container
   494  func (daemon *Daemon) runAsHyperVContainer(hostConfig *containertypes.HostConfig) bool {
   495  	if hostConfig.Isolation.IsDefault() {
   496  		// Container is set to use the default, so take the default from the daemon configuration
   497  		return daemon.defaultIsolation.IsHyperV()
   498  	}
   499  
   500  	// Container is requesting an isolation mode. Honour it.
   501  	return hostConfig.Isolation.IsHyperV()
   502  
   503  }
   504  
   505  // conditionalMountOnStart is a platform specific helper function during the
   506  // container start to call mount.
   507  func (daemon *Daemon) conditionalMountOnStart(container *container.Container) error {
   508  	// Bail out now for Linux containers. We cannot mount the containers filesystem on the
   509  	// host as it is a non-Windows filesystem.
   510  	if system.LCOWSupported() && container.OS != "windows" {
   511  		return nil
   512  	}
   513  
   514  	// We do not mount if a Hyper-V container as it needs to be mounted inside the
   515  	// utility VM, not the host.
   516  	if !daemon.runAsHyperVContainer(container.HostConfig) {
   517  		return daemon.Mount(container)
   518  	}
   519  	return nil
   520  }
   521  
   522  // conditionalUnmountOnCleanup is a platform specific helper function called
   523  // during the cleanup of a container to unmount.
   524  func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container) error {
   525  	// Bail out now for Linux containers
   526  	if system.LCOWSupported() && container.OS != "windows" {
   527  		return nil
   528  	}
   529  
   530  	// We do not unmount if a Hyper-V container
   531  	if !daemon.runAsHyperVContainer(container.HostConfig) {
   532  		return daemon.Unmount(container)
   533  	}
   534  	return nil
   535  }
   536  
   537  func driverOptions(config *config.Config) []nwconfig.Option {
   538  	return []nwconfig.Option{}
   539  }
   540  
   541  func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) {
   542  	if !c.IsRunning() {
   543  		return nil, errNotRunning(c.ID)
   544  	}
   545  
   546  	// Obtain the stats from HCS via libcontainerd
   547  	stats, err := daemon.containerd.Stats(context.Background(), c.ID)
   548  	if err != nil {
   549  		if strings.Contains(err.Error(), "container not found") {
   550  			return nil, containerNotFound(c.ID)
   551  		}
   552  		return nil, err
   553  	}
   554  
   555  	// Start with an empty structure
   556  	s := &types.StatsJSON{}
   557  	s.Stats.Read = stats.Read
   558  	s.Stats.NumProcs = platform.NumProcs()
   559  
   560  	if stats.HCSStats != nil {
   561  		hcss := stats.HCSStats
   562  		// Populate the CPU/processor statistics
   563  		s.CPUStats = types.CPUStats{
   564  			CPUUsage: types.CPUUsage{
   565  				TotalUsage:        hcss.Processor.TotalRuntime100ns,
   566  				UsageInKernelmode: hcss.Processor.RuntimeKernel100ns,
   567  				UsageInUsermode:   hcss.Processor.RuntimeKernel100ns,
   568  			},
   569  		}
   570  
   571  		// Populate the memory statistics
   572  		s.MemoryStats = types.MemoryStats{
   573  			Commit:            hcss.Memory.UsageCommitBytes,
   574  			CommitPeak:        hcss.Memory.UsageCommitPeakBytes,
   575  			PrivateWorkingSet: hcss.Memory.UsagePrivateWorkingSetBytes,
   576  		}
   577  
   578  		// Populate the storage statistics
   579  		s.StorageStats = types.StorageStats{
   580  			ReadCountNormalized:  hcss.Storage.ReadCountNormalized,
   581  			ReadSizeBytes:        hcss.Storage.ReadSizeBytes,
   582  			WriteCountNormalized: hcss.Storage.WriteCountNormalized,
   583  			WriteSizeBytes:       hcss.Storage.WriteSizeBytes,
   584  		}
   585  
   586  		// Populate the network statistics
   587  		s.Networks = make(map[string]types.NetworkStats)
   588  		for _, nstats := range hcss.Network {
   589  			s.Networks[nstats.EndpointId] = types.NetworkStats{
   590  				RxBytes:   nstats.BytesReceived,
   591  				RxPackets: nstats.PacketsReceived,
   592  				RxDropped: nstats.DroppedPacketsIncoming,
   593  				TxBytes:   nstats.BytesSent,
   594  				TxPackets: nstats.PacketsSent,
   595  				TxDropped: nstats.DroppedPacketsOutgoing,
   596  			}
   597  		}
   598  	}
   599  	return s, nil
   600  }
   601  
   602  // setDefaultIsolation determine the default isolation mode for the
   603  // daemon to run in. This is only applicable on Windows
   604  func (daemon *Daemon) setDefaultIsolation() error {
   605  	daemon.defaultIsolation = containertypes.Isolation("process")
   606  	// On client SKUs, default to Hyper-V. Note that IoT reports as a client SKU
   607  	// but it should not be treated as such.
   608  	if system.IsWindowsClient() && !system.IsIoTCore() {
   609  		daemon.defaultIsolation = containertypes.Isolation("hyperv")
   610  	}
   611  	for _, option := range daemon.configStore.ExecOptions {
   612  		key, val, err := parsers.ParseKeyValueOpt(option)
   613  		if err != nil {
   614  			return err
   615  		}
   616  		key = strings.ToLower(key)
   617  		switch key {
   618  
   619  		case "isolation":
   620  			if !containertypes.Isolation(val).IsValid() {
   621  				return fmt.Errorf("Invalid exec-opt value for 'isolation':'%s'", val)
   622  			}
   623  			if containertypes.Isolation(val).IsHyperV() {
   624  				daemon.defaultIsolation = containertypes.Isolation("hyperv")
   625  			}
   626  			if containertypes.Isolation(val).IsProcess() {
   627  				if system.IsWindowsClient() && !system.IsIoTCore() {
   628  					// @engine maintainers. This block should not be removed. It partially enforces licensing
   629  					// restrictions on Windows. Ping @jhowardmsft if there are concerns or PRs to change this.
   630  					return fmt.Errorf("Windows client operating systems only support Hyper-V containers")
   631  				}
   632  				daemon.defaultIsolation = containertypes.Isolation("process")
   633  			}
   634  		default:
   635  			return fmt.Errorf("Unrecognised exec-opt '%s'\n", key)
   636  		}
   637  	}
   638  
   639  	logrus.Infof("Windows default isolation mode: %s", daemon.defaultIsolation)
   640  	return nil
   641  }
   642  
   643  func rootFSToAPIType(rootfs *image.RootFS) types.RootFS {
   644  	var layers []string
   645  	for _, l := range rootfs.DiffIDs {
   646  		layers = append(layers, l.String())
   647  	}
   648  	return types.RootFS{
   649  		Type:   rootfs.Type,
   650  		Layers: layers,
   651  	}
   652  }
   653  
   654  func setupDaemonProcess(config *config.Config) error {
   655  	return nil
   656  }
   657  
   658  // verifyVolumesInfo is a no-op on windows.
   659  // This is called during daemon initialization to migrate volumes from pre-1.7.
   660  // volumes were not supported on windows pre-1.7
   661  func (daemon *Daemon) verifyVolumesInfo(container *container.Container) error {
   662  	return nil
   663  }
   664  
   665  func (daemon *Daemon) setupSeccompProfile() error {
   666  	return nil
   667  }
   668  
   669  func getRealPath(path string) (string, error) {
   670  	if system.IsIoTCore() {
   671  		// Due to https://github.com/golang/go/issues/20506, path expansion
   672  		// does not work correctly on the default IoT Core configuration.
   673  		// TODO @darrenstahlmsft remove this once golang/go/20506 is fixed
   674  		return path, nil
   675  	}
   676  	return fileutils.ReadSymlinkedDirectory(path)
   677  }
   678  
   679  func (daemon *Daemon) loadRuntimes() error {
   680  	return nil
   681  }
   682  
   683  func (daemon *Daemon) initRuntimes(_ map[string]types.Runtime) error {
   684  	return nil
   685  }