github.com/wozhu6104/docker@v20.10.10+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 recursiveUnmount(_ string) error { 471 return nil 472 } 473 474 func setupRemappedRoot(config *config.Config) (*idtools.IdentityMapping, error) { 475 return &idtools.IdentityMapping{}, nil 476 } 477 478 func setupDaemonRoot(config *config.Config, rootDir string, rootIdentity idtools.Identity) error { 479 config.Root = rootDir 480 // Create the root directory if it doesn't exists 481 if err := system.MkdirAllWithACL(config.Root, 0, system.SddlAdministratorsLocalSystem); err != nil { 482 return err 483 } 484 return nil 485 } 486 487 // runasHyperVContainer returns true if we are going to run as a Hyper-V container 488 func (daemon *Daemon) runAsHyperVContainer(hostConfig *containertypes.HostConfig) bool { 489 if hostConfig.Isolation.IsDefault() { 490 // Container is set to use the default, so take the default from the daemon configuration 491 return daemon.defaultIsolation.IsHyperV() 492 } 493 494 // Container is requesting an isolation mode. Honour it. 495 return hostConfig.Isolation.IsHyperV() 496 497 } 498 499 // conditionalMountOnStart is a platform specific helper function during the 500 // container start to call mount. 501 func (daemon *Daemon) conditionalMountOnStart(container *container.Container) error { 502 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 521 // Bail out now for Linux containers 522 if system.LCOWSupported() && container.OS != "windows" { 523 return nil 524 } 525 526 // We do not unmount if a Hyper-V container 527 if !daemon.runAsHyperVContainer(container.HostConfig) { 528 return daemon.Unmount(container) 529 } 530 return nil 531 } 532 533 func driverOptions(config *config.Config) []nwconfig.Option { 534 return []nwconfig.Option{} 535 } 536 537 func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) { 538 if !c.IsRunning() { 539 return nil, errNotRunning(c.ID) 540 } 541 542 // Obtain the stats from HCS via libcontainerd 543 stats, err := daemon.containerd.Stats(context.Background(), c.ID) 544 if err != nil { 545 if strings.Contains(err.Error(), "container not found") { 546 return nil, containerNotFound(c.ID) 547 } 548 return nil, err 549 } 550 551 // Start with an empty structure 552 s := &types.StatsJSON{} 553 s.Stats.Read = stats.Read 554 s.Stats.NumProcs = platform.NumProcs() 555 556 if stats.HCSStats != nil { 557 hcss := stats.HCSStats 558 // Populate the CPU/processor statistics 559 s.CPUStats = types.CPUStats{ 560 CPUUsage: types.CPUUsage{ 561 TotalUsage: hcss.Processor.TotalRuntime100ns, 562 UsageInKernelmode: hcss.Processor.RuntimeKernel100ns, 563 UsageInUsermode: hcss.Processor.RuntimeUser100ns, 564 }, 565 } 566 567 // Populate the memory statistics 568 s.MemoryStats = types.MemoryStats{ 569 Commit: hcss.Memory.UsageCommitBytes, 570 CommitPeak: hcss.Memory.UsageCommitPeakBytes, 571 PrivateWorkingSet: hcss.Memory.UsagePrivateWorkingSetBytes, 572 } 573 574 // Populate the storage statistics 575 s.StorageStats = types.StorageStats{ 576 ReadCountNormalized: hcss.Storage.ReadCountNormalized, 577 ReadSizeBytes: hcss.Storage.ReadSizeBytes, 578 WriteCountNormalized: hcss.Storage.WriteCountNormalized, 579 WriteSizeBytes: hcss.Storage.WriteSizeBytes, 580 } 581 582 // Populate the network statistics 583 s.Networks = make(map[string]types.NetworkStats) 584 for _, nstats := range hcss.Network { 585 s.Networks[nstats.EndpointId] = types.NetworkStats{ 586 RxBytes: nstats.BytesReceived, 587 RxPackets: nstats.PacketsReceived, 588 RxDropped: nstats.DroppedPacketsIncoming, 589 TxBytes: nstats.BytesSent, 590 TxPackets: nstats.PacketsSent, 591 TxDropped: nstats.DroppedPacketsOutgoing, 592 } 593 } 594 } 595 return s, nil 596 } 597 598 // setDefaultIsolation determine the default isolation mode for the 599 // daemon to run in. This is only applicable on Windows 600 func (daemon *Daemon) setDefaultIsolation() error { 601 daemon.defaultIsolation = containertypes.Isolation("process") 602 603 // On client SKUs, default to Hyper-V. @engine maintainers. This 604 // should not be removed. Ping Microsoft folks is there are PRs to 605 // to change this. 606 if system.IsWindowsClient() { 607 daemon.defaultIsolation = containertypes.Isolation("hyperv") 608 } 609 for _, option := range daemon.configStore.ExecOptions { 610 key, val, err := parsers.ParseKeyValueOpt(option) 611 if err != nil { 612 return err 613 } 614 key = strings.ToLower(key) 615 switch key { 616 617 case "isolation": 618 if !containertypes.Isolation(val).IsValid() { 619 return fmt.Errorf("Invalid exec-opt value for 'isolation':'%s'", val) 620 } 621 if containertypes.Isolation(val).IsHyperV() { 622 daemon.defaultIsolation = containertypes.Isolation("hyperv") 623 } 624 if containertypes.Isolation(val).IsProcess() { 625 if system.IsWindowsClient() && osversion.Build() < osversion.RS5 { 626 // On RS5, we allow (but don't strictly support) process isolation on Client SKUs. 627 // @engine maintainers. This block should not be removed. It partially enforces licensing 628 // restrictions on Windows. Ping Microsoft folks if there are concerns or PRs to change this. 629 return fmt.Errorf("Windows client operating systems earlier than version 1809 can only run Hyper-V containers") 630 } 631 daemon.defaultIsolation = containertypes.Isolation("process") 632 } 633 default: 634 return fmt.Errorf("Unrecognised exec-opt '%s'\n", key) 635 } 636 } 637 638 logrus.Infof("Windows default isolation mode: %s", daemon.defaultIsolation) 639 return nil 640 } 641 642 func setupDaemonProcess(config *config.Config) error { 643 return nil 644 } 645 646 func (daemon *Daemon) setupSeccompProfile() error { 647 return nil 648 } 649 650 func (daemon *Daemon) loadRuntimes() error { 651 return nil 652 } 653 654 func (daemon *Daemon) initRuntimes(_ map[string]types.Runtime) error { 655 return nil 656 } 657 658 func setupResolvConf(config *config.Config) { 659 } 660 661 // RawSysInfo returns *sysinfo.SysInfo . 662 func (daemon *Daemon) RawSysInfo(quiet bool) *sysinfo.SysInfo { 663 return sysinfo.New(quiet) 664 }