daemon_windows.go 21 KB

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