daemon_windows.go 22 KB

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