daemon_windows.go 20 KB

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