github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/daemon/daemon_windows.go (about)

     1  package daemon
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"strings"
     7  
     8  	"github.com/Microsoft/hcsshim"
     9  	"github.com/Sirupsen/logrus"
    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/image"
    14  	"github.com/docker/docker/pkg/idtools"
    15  	"github.com/docker/docker/pkg/parsers"
    16  	"github.com/docker/docker/pkg/platform"
    17  	"github.com/docker/docker/pkg/sysinfo"
    18  	"github.com/docker/docker/pkg/system"
    19  	"github.com/docker/docker/runconfig"
    20  	"github.com/docker/libnetwork"
    21  	nwconfig "github.com/docker/libnetwork/config"
    22  	"github.com/docker/libnetwork/datastore"
    23  	winlibnetwork "github.com/docker/libnetwork/drivers/windows"
    24  	"github.com/docker/libnetwork/netlabel"
    25  	"github.com/docker/libnetwork/options"
    26  	blkiodev "github.com/opencontainers/runc/libcontainer/configs"
    27  	"golang.org/x/sys/windows"
    28  )
    29  
    30  const (
    31  	defaultNetworkSpace  = "172.16.0.0/12"
    32  	platformSupported    = true
    33  	windowsMinCPUShares  = 1
    34  	windowsMaxCPUShares  = 10000
    35  	windowsMinCPUPercent = 1
    36  	windowsMaxCPUPercent = 100
    37  	windowsMinCPUCount   = 1
    38  )
    39  
    40  func getBlkioWeightDevices(config *containertypes.HostConfig) ([]blkiodev.WeightDevice, error) {
    41  	return nil, nil
    42  }
    43  
    44  func parseSecurityOpt(container *container.Container, config *containertypes.HostConfig) error {
    45  	return nil
    46  }
    47  
    48  func getBlkioReadIOpsDevices(config *containertypes.HostConfig) ([]blkiodev.ThrottleDevice, error) {
    49  	return nil, nil
    50  }
    51  
    52  func getBlkioWriteIOpsDevices(config *containertypes.HostConfig) ([]blkiodev.ThrottleDevice, error) {
    53  	return nil, nil
    54  }
    55  
    56  func getBlkioReadBpsDevices(config *containertypes.HostConfig) ([]blkiodev.ThrottleDevice, error) {
    57  	return nil, nil
    58  }
    59  
    60  func getBlkioWriteBpsDevices(config *containertypes.HostConfig) ([]blkiodev.ThrottleDevice, error) {
    61  	return nil, nil
    62  }
    63  
    64  func setupInitLayer(initLayer string, rootUID, rootGID int) error {
    65  	return nil
    66  }
    67  
    68  func (daemon *Daemon) getLayerInit() func(string) error {
    69  	return nil
    70  }
    71  
    72  func checkKernel() error {
    73  	return nil
    74  }
    75  
    76  func (daemon *Daemon) getCgroupDriver() string {
    77  	return ""
    78  }
    79  
    80  // adaptContainerSettings is called during container creation to modify any
    81  // settings necessary in the HostConfig structure.
    82  func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConfig, adjustCPUShares bool) error {
    83  	if hostConfig == nil {
    84  		return nil
    85  	}
    86  
    87  	return nil
    88  }
    89  
    90  func verifyContainerResources(resources *containertypes.Resources, isHyperv bool) ([]string, error) {
    91  	warnings := []string{}
    92  
    93  	if !isHyperv {
    94  		// The processor resource controls are mutually exclusive on
    95  		// Windows Server Containers, the order of precedence is
    96  		// CPUCount first, then CPUShares, and CPUPercent last.
    97  		if resources.CPUCount > 0 {
    98  			if resources.CPUShares > 0 {
    99  				warnings = append(warnings, "Conflicting options: CPU count takes priority over CPU shares on Windows Server Containers. CPU shares discarded")
   100  				logrus.Warn("Conflicting options: CPU count takes priority over CPU shares on Windows Server Containers. CPU shares discarded")
   101  				resources.CPUShares = 0
   102  			}
   103  			if resources.CPUPercent > 0 {
   104  				warnings = append(warnings, "Conflicting options: CPU count takes priority over CPU percent on Windows Server Containers. CPU percent discarded")
   105  				logrus.Warn("Conflicting options: CPU count takes priority over CPU percent on Windows Server Containers. CPU percent discarded")
   106  				resources.CPUPercent = 0
   107  			}
   108  		} else if resources.CPUShares > 0 {
   109  			if resources.CPUPercent > 0 {
   110  				warnings = append(warnings, "Conflicting options: CPU shares takes priority over CPU percent on Windows Server Containers. CPU percent discarded")
   111  				logrus.Warn("Conflicting options: CPU shares takes priority over CPU percent on Windows Server Containers. CPU percent discarded")
   112  				resources.CPUPercent = 0
   113  			}
   114  		}
   115  	}
   116  
   117  	if resources.CPUShares < 0 || resources.CPUShares > windowsMaxCPUShares {
   118  		return warnings, fmt.Errorf("range of CPUShares is from %d to %d", windowsMinCPUShares, windowsMaxCPUShares)
   119  	}
   120  	if resources.CPUPercent < 0 || resources.CPUPercent > windowsMaxCPUPercent {
   121  		return warnings, fmt.Errorf("range of CPUPercent is from %d to %d", windowsMinCPUPercent, windowsMaxCPUPercent)
   122  	}
   123  	if resources.CPUCount < 0 {
   124  		return warnings, fmt.Errorf("invalid CPUCount: CPUCount cannot be negative")
   125  	}
   126  
   127  	if resources.NanoCPUs > 0 && resources.CPUPercent > 0 {
   128  		return warnings, fmt.Errorf("conflicting options: Nano CPUs and CPU Percent cannot both be set")
   129  	}
   130  	if resources.NanoCPUs > 0 && resources.CPUShares > 0 {
   131  		return warnings, fmt.Errorf("conflicting options: Nano CPUs and CPU Shares cannot both be set")
   132  	}
   133  	// The precision we could get is 0.01, because on Windows we have to convert to CPUPercent.
   134  	// We don't set the lower limit here and it is up to the underlying platform (e.g., Windows) to return an error.
   135  	if resources.NanoCPUs < 0 || resources.NanoCPUs > int64(sysinfo.NumCPU())*1e9 {
   136  		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())
   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 && *resources.MemorySwappiness != -1 {
   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() {
   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  	if err != nil {
   208  		return warnings, err
   209  	}
   210  	return warnings, nil
   211  }
   212  
   213  // platformReload update configuration with platform specific options
   214  func (daemon *Daemon) platformReload(config *Config) map[string]string {
   215  	return map[string]string{}
   216  }
   217  
   218  // verifyDaemonSettings performs validation of daemon config struct
   219  func verifyDaemonSettings(config *Config) error {
   220  	return nil
   221  }
   222  
   223  // checkSystem validates platform-specific requirements
   224  func checkSystem() error {
   225  	// Validate the OS version. Note that docker.exe must be manifested for this
   226  	// call to return the correct version.
   227  	osv := system.GetOSVersion()
   228  	if osv.MajorVersion < 10 {
   229  		return fmt.Errorf("This version of Windows does not support the docker daemon")
   230  	}
   231  	if osv.Build < 14393 {
   232  		return fmt.Errorf("The docker daemon requires build 14393 or later of Windows Server 2016 or Windows 10")
   233  	}
   234  
   235  	vmcompute := windows.NewLazySystemDLL("vmcompute.dll")
   236  	if vmcompute.Load() != nil {
   237  		return fmt.Errorf("Failed to load vmcompute.dll. Ensure that the Containers role is installed.")
   238  	}
   239  	return nil
   240  }
   241  
   242  // configureKernelSecuritySupport configures and validate security support for the kernel
   243  func configureKernelSecuritySupport(config *Config, driverName string) error {
   244  	return nil
   245  }
   246  
   247  // configureMaxThreads sets the Go runtime max threads threshold
   248  func configureMaxThreads(config *Config) error {
   249  	return nil
   250  }
   251  
   252  func (daemon *Daemon) initNetworkController(config *Config, activeSandboxes map[string]interface{}) (libnetwork.NetworkController, error) {
   253  	netOptions, err := daemon.networkOptions(config, nil, nil)
   254  	if err != nil {
   255  		return nil, err
   256  	}
   257  	controller, err := libnetwork.New(netOptions...)
   258  	if err != nil {
   259  		return nil, fmt.Errorf("error obtaining controller instance: %v", err)
   260  	}
   261  
   262  	hnsresponse, err := hcsshim.HNSListNetworkRequest("GET", "", "")
   263  	if err != nil {
   264  		return nil, err
   265  	}
   266  
   267  	// Remove networks not present in HNS
   268  	for _, v := range controller.Networks() {
   269  		options := v.Info().DriverOptions()
   270  		hnsid := options[winlibnetwork.HNSID]
   271  		found := false
   272  
   273  		for _, v := range hnsresponse {
   274  			if v.Id == hnsid {
   275  				found = true
   276  				break
   277  			}
   278  		}
   279  
   280  		if !found {
   281  			// global networks should not be deleted by local HNS
   282  			if v.Info().Scope() != datastore.GlobalScope {
   283  				err = v.Delete()
   284  				if err != nil {
   285  					logrus.Errorf("Error occurred when removing network %v", err)
   286  				}
   287  			}
   288  		}
   289  	}
   290  
   291  	_, err = controller.NewNetwork("null", "none", "", libnetwork.NetworkOptionPersist(false))
   292  	if err != nil {
   293  		return nil, err
   294  	}
   295  
   296  	defaultNetworkExists := false
   297  
   298  	if network, err := controller.NetworkByName(runconfig.DefaultDaemonNetworkMode().NetworkName()); err == nil {
   299  		options := network.Info().DriverOptions()
   300  		for _, v := range hnsresponse {
   301  			if options[winlibnetwork.HNSID] == v.Id {
   302  				defaultNetworkExists = true
   303  				break
   304  			}
   305  		}
   306  	}
   307  
   308  	// discover and add HNS networks to windows
   309  	// network that exist are removed and added again
   310  	for _, v := range hnsresponse {
   311  		var n libnetwork.Network
   312  		s := func(current libnetwork.Network) bool {
   313  			options := current.Info().DriverOptions()
   314  			if options[winlibnetwork.HNSID] == v.Id {
   315  				n = current
   316  				return true
   317  			}
   318  			return false
   319  		}
   320  
   321  		controller.WalkNetworks(s)
   322  		if n != nil {
   323  			// global networks should not be deleted by local HNS
   324  			if n.Info().Scope() == datastore.GlobalScope {
   325  				continue
   326  			}
   327  			v.Name = n.Name()
   328  			// This will not cause network delete from HNS as the network
   329  			// is not yet populated in the libnetwork windows driver
   330  			n.Delete()
   331  		}
   332  
   333  		netOption := map[string]string{
   334  			winlibnetwork.NetworkName: v.Name,
   335  			winlibnetwork.HNSID:       v.Id,
   336  		}
   337  
   338  		v4Conf := []*libnetwork.IpamConf{}
   339  		for _, subnet := range v.Subnets {
   340  			ipamV4Conf := libnetwork.IpamConf{}
   341  			ipamV4Conf.PreferredPool = subnet.AddressPrefix
   342  			ipamV4Conf.Gateway = subnet.GatewayAddress
   343  			v4Conf = append(v4Conf, &ipamV4Conf)
   344  		}
   345  
   346  		name := v.Name
   347  
   348  		// If there is no nat network create one from the first NAT network
   349  		// encountered
   350  		if !defaultNetworkExists && runconfig.DefaultDaemonNetworkMode() == containertypes.NetworkMode(strings.ToLower(v.Type)) {
   351  			name = runconfig.DefaultDaemonNetworkMode().NetworkName()
   352  			defaultNetworkExists = true
   353  		}
   354  
   355  		v6Conf := []*libnetwork.IpamConf{}
   356  		_, err := controller.NewNetwork(strings.ToLower(v.Type), name, "",
   357  			libnetwork.NetworkOptionGeneric(options.Generic{
   358  				netlabel.GenericData: netOption,
   359  			}),
   360  			libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil),
   361  		)
   362  
   363  		if err != nil {
   364  			logrus.Errorf("Error occurred when creating network %v", err)
   365  		}
   366  	}
   367  
   368  	if !config.DisableBridge {
   369  		// Initialize default driver "bridge"
   370  		if err := initBridgeDriver(controller, config); err != nil {
   371  			return nil, err
   372  		}
   373  	}
   374  
   375  	return controller, nil
   376  }
   377  
   378  func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error {
   379  	if _, err := controller.NetworkByName(runconfig.DefaultDaemonNetworkMode().NetworkName()); err == nil {
   380  		return nil
   381  	}
   382  
   383  	netOption := map[string]string{
   384  		winlibnetwork.NetworkName: runconfig.DefaultDaemonNetworkMode().NetworkName(),
   385  	}
   386  
   387  	var ipamOption libnetwork.NetworkOption
   388  	var subnetPrefix string
   389  
   390  	if config.bridgeConfig.FixedCIDR != "" {
   391  		subnetPrefix = config.bridgeConfig.FixedCIDR
   392  	} else {
   393  		// TP5 doesn't support properly detecting subnet
   394  		osv := system.GetOSVersion()
   395  		if osv.Build < 14360 {
   396  			subnetPrefix = defaultNetworkSpace
   397  		}
   398  	}
   399  
   400  	if subnetPrefix != "" {
   401  		ipamV4Conf := libnetwork.IpamConf{}
   402  		ipamV4Conf.PreferredPool = subnetPrefix
   403  		v4Conf := []*libnetwork.IpamConf{&ipamV4Conf}
   404  		v6Conf := []*libnetwork.IpamConf{}
   405  		ipamOption = libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil)
   406  	}
   407  
   408  	_, err := controller.NewNetwork(string(runconfig.DefaultDaemonNetworkMode()), runconfig.DefaultDaemonNetworkMode().NetworkName(), "",
   409  		libnetwork.NetworkOptionGeneric(options.Generic{
   410  			netlabel.GenericData: netOption,
   411  		}),
   412  		ipamOption,
   413  	)
   414  
   415  	if err != nil {
   416  		return fmt.Errorf("Error creating default network: %v", err)
   417  	}
   418  
   419  	return nil
   420  }
   421  
   422  // registerLinks sets up links between containers and writes the
   423  // configuration out for persistence. As of Windows TP4, links are not supported.
   424  func (daemon *Daemon) registerLinks(container *container.Container, hostConfig *containertypes.HostConfig) error {
   425  	return nil
   426  }
   427  
   428  func (daemon *Daemon) cleanupMountsByID(in string) error {
   429  	return nil
   430  }
   431  
   432  func (daemon *Daemon) cleanupMounts() error {
   433  	return nil
   434  }
   435  
   436  func setupRemappedRoot(config *Config) ([]idtools.IDMap, []idtools.IDMap, error) {
   437  	return nil, nil, nil
   438  }
   439  
   440  func setupDaemonRoot(config *Config, rootDir string, rootUID, rootGID int) error {
   441  	config.Root = rootDir
   442  	// Create the root directory if it doesn't exists
   443  	if err := system.MkdirAllWithACL(config.Root, 0); err != nil && !os.IsExist(err) {
   444  		return err
   445  	}
   446  	return nil
   447  }
   448  
   449  // runasHyperVContainer returns true if we are going to run as a Hyper-V container
   450  func (daemon *Daemon) runAsHyperVContainer(hostConfig *containertypes.HostConfig) bool {
   451  	if hostConfig.Isolation.IsDefault() {
   452  		// Container is set to use the default, so take the default from the daemon configuration
   453  		return daemon.defaultIsolation.IsHyperV()
   454  	}
   455  
   456  	// Container is requesting an isolation mode. Honour it.
   457  	return hostConfig.Isolation.IsHyperV()
   458  
   459  }
   460  
   461  // conditionalMountOnStart is a platform specific helper function during the
   462  // container start to call mount.
   463  func (daemon *Daemon) conditionalMountOnStart(container *container.Container) error {
   464  	// We do not mount if a Hyper-V container
   465  	if !daemon.runAsHyperVContainer(container.HostConfig) {
   466  		return daemon.Mount(container)
   467  	}
   468  	return nil
   469  }
   470  
   471  // conditionalUnmountOnCleanup is a platform specific helper function called
   472  // during the cleanup of a container to unmount.
   473  func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container) error {
   474  	// We do not unmount if a Hyper-V container
   475  	if !daemon.runAsHyperVContainer(container.HostConfig) {
   476  		return daemon.Unmount(container)
   477  	}
   478  	return nil
   479  }
   480  
   481  func driverOptions(config *Config) []nwconfig.Option {
   482  	return []nwconfig.Option{}
   483  }
   484  
   485  func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) {
   486  	if !c.IsRunning() {
   487  		return nil, errNotRunning{c.ID}
   488  	}
   489  
   490  	// Obtain the stats from HCS via libcontainerd
   491  	stats, err := daemon.containerd.Stats(c.ID)
   492  	if err != nil {
   493  		return nil, err
   494  	}
   495  
   496  	// Start with an empty structure
   497  	s := &types.StatsJSON{}
   498  
   499  	// Populate the CPU/processor statistics
   500  	s.CPUStats = types.CPUStats{
   501  		CPUUsage: types.CPUUsage{
   502  			TotalUsage:        stats.Processor.TotalRuntime100ns,
   503  			UsageInKernelmode: stats.Processor.RuntimeKernel100ns,
   504  			UsageInUsermode:   stats.Processor.RuntimeKernel100ns,
   505  		},
   506  	}
   507  
   508  	// Populate the memory statistics
   509  	s.MemoryStats = types.MemoryStats{
   510  		Commit:            stats.Memory.UsageCommitBytes,
   511  		CommitPeak:        stats.Memory.UsageCommitPeakBytes,
   512  		PrivateWorkingSet: stats.Memory.UsagePrivateWorkingSetBytes,
   513  	}
   514  
   515  	// Populate the storage statistics
   516  	s.StorageStats = types.StorageStats{
   517  		ReadCountNormalized:  stats.Storage.ReadCountNormalized,
   518  		ReadSizeBytes:        stats.Storage.ReadSizeBytes,
   519  		WriteCountNormalized: stats.Storage.WriteCountNormalized,
   520  		WriteSizeBytes:       stats.Storage.WriteSizeBytes,
   521  	}
   522  
   523  	// Populate the network statistics
   524  	s.Networks = make(map[string]types.NetworkStats)
   525  
   526  	for _, nstats := range stats.Network {
   527  		s.Networks[nstats.EndpointId] = types.NetworkStats{
   528  			RxBytes:   nstats.BytesReceived,
   529  			RxPackets: nstats.PacketsReceived,
   530  			RxDropped: nstats.DroppedPacketsIncoming,
   531  			TxBytes:   nstats.BytesSent,
   532  			TxPackets: nstats.PacketsSent,
   533  			TxDropped: nstats.DroppedPacketsOutgoing,
   534  		}
   535  	}
   536  
   537  	// Set the timestamp
   538  	s.Stats.Read = stats.Timestamp
   539  	s.Stats.NumProcs = platform.NumProcs()
   540  
   541  	return s, nil
   542  }
   543  
   544  // setDefaultIsolation determine the default isolation mode for the
   545  // daemon to run in. This is only applicable on Windows
   546  func (daemon *Daemon) setDefaultIsolation() error {
   547  	daemon.defaultIsolation = containertypes.Isolation("process")
   548  	// On client SKUs, default to Hyper-V
   549  	if system.IsWindowsClient() {
   550  		daemon.defaultIsolation = containertypes.Isolation("hyperv")
   551  	}
   552  	for _, option := range daemon.configStore.ExecOptions {
   553  		key, val, err := parsers.ParseKeyValueOpt(option)
   554  		if err != nil {
   555  			return err
   556  		}
   557  		key = strings.ToLower(key)
   558  		switch key {
   559  
   560  		case "isolation":
   561  			if !containertypes.Isolation(val).IsValid() {
   562  				return fmt.Errorf("Invalid exec-opt value for 'isolation':'%s'", val)
   563  			}
   564  			if containertypes.Isolation(val).IsHyperV() {
   565  				daemon.defaultIsolation = containertypes.Isolation("hyperv")
   566  			}
   567  			if containertypes.Isolation(val).IsProcess() {
   568  				if system.IsWindowsClient() {
   569  					// @engine maintainers. This block should not be removed. It partially enforces licensing
   570  					// restrictions on Windows. Ping @jhowardmsft if there are concerns or PRs to change this.
   571  					return fmt.Errorf("Windows client operating systems only support Hyper-V containers")
   572  				}
   573  				daemon.defaultIsolation = containertypes.Isolation("process")
   574  			}
   575  		default:
   576  			return fmt.Errorf("Unrecognised exec-opt '%s'\n", key)
   577  		}
   578  	}
   579  
   580  	logrus.Infof("Windows default isolation mode: %s", daemon.defaultIsolation)
   581  	return nil
   582  }
   583  
   584  func rootFSToAPIType(rootfs *image.RootFS) types.RootFS {
   585  	var layers []string
   586  	for _, l := range rootfs.DiffIDs {
   587  		layers = append(layers, l.String())
   588  	}
   589  	return types.RootFS{
   590  		Type:   rootfs.Type,
   591  		Layers: layers,
   592  	}
   593  }
   594  
   595  func setupDaemonProcess(config *Config) error {
   596  	return nil
   597  }
   598  
   599  // verifyVolumesInfo is a no-op on windows.
   600  // This is called during daemon initialization to migrate volumes from pre-1.7.
   601  // volumes were not supported on windows pre-1.7
   602  func (daemon *Daemon) verifyVolumesInfo(container *container.Container) error {
   603  	return nil
   604  }
   605  
   606  func (daemon *Daemon) setupSeccompProfile() error {
   607  	return nil
   608  }