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