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 }