daemon_windows.go 19 KB

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