daemon_windows.go 20 KB

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