github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/daemon/daemon_windows.go (about)

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