daemon_windows.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  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/container"
  9. "github.com/docker/docker/image"
  10. "github.com/docker/docker/pkg/idtools"
  11. "github.com/docker/docker/pkg/parsers"
  12. "github.com/docker/docker/pkg/sysinfo"
  13. "github.com/docker/docker/pkg/system"
  14. "github.com/docker/docker/runconfig"
  15. "github.com/docker/engine-api/types"
  16. pblkiodev "github.com/docker/engine-api/types/blkiodev"
  17. containertypes "github.com/docker/engine-api/types/container"
  18. "github.com/docker/libnetwork"
  19. nwconfig "github.com/docker/libnetwork/config"
  20. winlibnetwork "github.com/docker/libnetwork/drivers/windows"
  21. "github.com/docker/libnetwork/netlabel"
  22. "github.com/docker/libnetwork/options"
  23. blkiodev "github.com/opencontainers/runc/libcontainer/configs"
  24. )
  25. const (
  26. defaultNetworkSpace = "172.16.0.0/12"
  27. platformSupported = true
  28. windowsMinCPUShares = 1
  29. windowsMaxCPUShares = 10000
  30. )
  31. func getBlkioWeightDevices(config *containertypes.HostConfig) ([]blkiodev.WeightDevice, error) {
  32. return nil, nil
  33. }
  34. func parseSecurityOpt(container *container.Container, config *containertypes.HostConfig) error {
  35. return nil
  36. }
  37. func getBlkioReadIOpsDevices(config *containertypes.HostConfig) ([]blkiodev.ThrottleDevice, error) {
  38. return nil, nil
  39. }
  40. func getBlkioWriteIOpsDevices(config *containertypes.HostConfig) ([]blkiodev.ThrottleDevice, error) {
  41. return nil, nil
  42. }
  43. func getBlkioReadBpsDevices(config *containertypes.HostConfig) ([]blkiodev.ThrottleDevice, error) {
  44. return nil, nil
  45. }
  46. func getBlkioWriteBpsDevices(config *containertypes.HostConfig) ([]blkiodev.ThrottleDevice, error) {
  47. return nil, nil
  48. }
  49. func setupInitLayer(initLayer string, rootUID, rootGID int) error {
  50. return nil
  51. }
  52. func checkKernel() error {
  53. return nil
  54. }
  55. func (daemon *Daemon) getCgroupDriver() string {
  56. return ""
  57. }
  58. // adaptContainerSettings is called during container creation to modify any
  59. // settings necessary in the HostConfig structure.
  60. func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConfig, adjustCPUShares bool) error {
  61. if hostConfig == nil {
  62. return nil
  63. }
  64. if hostConfig.CPUShares < 0 {
  65. logrus.Warnf("Changing requested CPUShares of %d to minimum allowed of %d", hostConfig.CPUShares, windowsMinCPUShares)
  66. hostConfig.CPUShares = windowsMinCPUShares
  67. } else if hostConfig.CPUShares > windowsMaxCPUShares {
  68. logrus.Warnf("Changing requested CPUShares of %d to maximum allowed of %d", hostConfig.CPUShares, windowsMaxCPUShares)
  69. hostConfig.CPUShares = windowsMaxCPUShares
  70. }
  71. return nil
  72. }
  73. func verifyContainerResources(resources *containertypes.Resources, sysInfo *sysinfo.SysInfo) ([]string, error) {
  74. warnings := []string{}
  75. // cpu subsystem checks and adjustments
  76. if resources.CPUPercent < 0 || resources.CPUPercent > 100 {
  77. return warnings, fmt.Errorf("Range of CPU percent is from 1 to 100")
  78. }
  79. if resources.CPUPercent > 0 && resources.CPUShares > 0 {
  80. return warnings, fmt.Errorf("Conflicting options: CPU Shares and CPU Percent cannot both be set")
  81. }
  82. // TODO Windows: Add more validation of resource settings not supported on Windows
  83. if resources.BlkioWeight > 0 {
  84. warnings = append(warnings, "Windows does not support Block I/O weight. Block I/O weight discarded.")
  85. logrus.Warn("Windows does not support Block I/O weight. Block I/O weight discarded.")
  86. resources.BlkioWeight = 0
  87. }
  88. if len(resources.BlkioWeightDevice) > 0 {
  89. warnings = append(warnings, "Windows does not support Block I/O weight-device. Weight-device discarded.")
  90. logrus.Warn("Windows does not support Block I/O weight-device. Weight-device discarded.")
  91. resources.BlkioWeightDevice = []*pblkiodev.WeightDevice{}
  92. }
  93. if len(resources.BlkioDeviceReadBps) > 0 {
  94. warnings = append(warnings, "Windows does not support Block read limit in bytes per second. Device read bps discarded.")
  95. logrus.Warn("Windows does not support Block I/O read limit in bytes per second. Device read bps discarded.")
  96. resources.BlkioDeviceReadBps = []*pblkiodev.ThrottleDevice{}
  97. }
  98. if len(resources.BlkioDeviceWriteBps) > 0 {
  99. warnings = append(warnings, "Windows does not support Block write limit in bytes per second. Device write bps discarded.")
  100. logrus.Warn("Windows does not support Block I/O write limit in bytes per second. Device write bps discarded.")
  101. resources.BlkioDeviceWriteBps = []*pblkiodev.ThrottleDevice{}
  102. }
  103. if len(resources.BlkioDeviceReadIOps) > 0 {
  104. warnings = append(warnings, "Windows does not support Block read limit in IO per second. Device read iops discarded.")
  105. logrus.Warn("Windows does not support Block I/O read limit in IO per second. Device read iops discarded.")
  106. resources.BlkioDeviceReadIOps = []*pblkiodev.ThrottleDevice{}
  107. }
  108. if len(resources.BlkioDeviceWriteIOps) > 0 {
  109. warnings = append(warnings, "Windows does not support Block write limit in IO per second. Device write iops discarded.")
  110. logrus.Warn("Windows does not support Block I/O write limit in IO per second. Device write iops discarded.")
  111. resources.BlkioDeviceWriteIOps = []*pblkiodev.ThrottleDevice{}
  112. }
  113. return warnings, nil
  114. }
  115. // verifyPlatformContainerSettings performs platform-specific validation of the
  116. // hostconfig and config structures.
  117. func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) {
  118. warnings := []string{}
  119. w, err := verifyContainerResources(&hostConfig.Resources, nil)
  120. warnings = append(warnings, w...)
  121. if err != nil {
  122. return warnings, err
  123. }
  124. return warnings, nil
  125. }
  126. // platformReload update configuration with platform specific options
  127. func (daemon *Daemon) platformReload(config *Config, attributes *map[string]string) {
  128. }
  129. // verifyDaemonSettings performs validation of daemon config struct
  130. func verifyDaemonSettings(config *Config) error {
  131. return nil
  132. }
  133. // checkSystem validates platform-specific requirements
  134. func checkSystem() error {
  135. // Validate the OS version. Note that docker.exe must be manifested for this
  136. // call to return the correct version.
  137. osv := system.GetOSVersion()
  138. if osv.MajorVersion < 10 {
  139. return fmt.Errorf("This version of Windows does not support the docker daemon")
  140. }
  141. if osv.Build < 14300 {
  142. return fmt.Errorf("The Windows daemon requires Windows Server 2016 Technical Preview 5 build 14300 or later")
  143. }
  144. return nil
  145. }
  146. // configureKernelSecuritySupport configures and validate security support for the kernel
  147. func configureKernelSecuritySupport(config *Config, driverName string) error {
  148. return nil
  149. }
  150. // configureMaxThreads sets the Go runtime max threads threshold
  151. func configureMaxThreads(config *Config) error {
  152. return nil
  153. }
  154. func (daemon *Daemon) initNetworkController(config *Config, activeSandboxes map[string]interface{}) (libnetwork.NetworkController, error) {
  155. netOptions, err := daemon.networkOptions(config, nil)
  156. if err != nil {
  157. return nil, err
  158. }
  159. controller, err := libnetwork.New(netOptions...)
  160. if err != nil {
  161. return nil, fmt.Errorf("error obtaining controller instance: %v", err)
  162. }
  163. hnsresponse, err := hcsshim.HNSListNetworkRequest("GET", "", "")
  164. if err != nil {
  165. return nil, err
  166. }
  167. // Remove networks not present in HNS
  168. for _, v := range controller.Networks() {
  169. options := v.Info().DriverOptions()
  170. hnsid := options[winlibnetwork.HNSID]
  171. found := false
  172. for _, v := range hnsresponse {
  173. if v.Id == hnsid {
  174. found = true
  175. break
  176. }
  177. }
  178. if !found {
  179. err = v.Delete()
  180. if err != nil {
  181. return nil, err
  182. }
  183. }
  184. }
  185. _, err = controller.NewNetwork("null", "none", "", libnetwork.NetworkOptionPersist(false))
  186. if err != nil {
  187. return nil, err
  188. }
  189. // discover and add HNS networks to windows
  190. // network that exist are removed and added again
  191. for _, v := range hnsresponse {
  192. var n libnetwork.Network
  193. s := func(current libnetwork.Network) bool {
  194. options := current.Info().DriverOptions()
  195. if options[winlibnetwork.HNSID] == v.Id {
  196. n = current
  197. return true
  198. }
  199. return false
  200. }
  201. controller.WalkNetworks(s)
  202. if n != nil {
  203. v.Name = n.Name()
  204. n.Delete()
  205. }
  206. netOption := map[string]string{
  207. winlibnetwork.NetworkName: v.Name,
  208. winlibnetwork.HNSID: v.Id,
  209. }
  210. v4Conf := []*libnetwork.IpamConf{}
  211. for _, subnet := range v.Subnets {
  212. ipamV4Conf := libnetwork.IpamConf{}
  213. ipamV4Conf.PreferredPool = subnet.AddressPrefix
  214. ipamV4Conf.Gateway = subnet.GatewayAddress
  215. v4Conf = append(v4Conf, &ipamV4Conf)
  216. }
  217. name := v.Name
  218. // There is only one nat network supported in windows.
  219. // If it exists with a different name add it as the default name
  220. if runconfig.DefaultDaemonNetworkMode() == containertypes.NetworkMode(strings.ToLower(v.Type)) {
  221. name = runconfig.DefaultDaemonNetworkMode().NetworkName()
  222. }
  223. v6Conf := []*libnetwork.IpamConf{}
  224. _, err := controller.NewNetwork(strings.ToLower(v.Type), name, "",
  225. libnetwork.NetworkOptionGeneric(options.Generic{
  226. netlabel.GenericData: netOption,
  227. }),
  228. libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil),
  229. )
  230. if err != nil {
  231. logrus.Errorf("Error occurred when creating network %v", err)
  232. }
  233. }
  234. if !config.DisableBridge {
  235. // Initialize default driver "bridge"
  236. if err := initBridgeDriver(controller, config); err != nil {
  237. return nil, err
  238. }
  239. }
  240. return controller, nil
  241. }
  242. func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error {
  243. if _, err := controller.NetworkByName(runconfig.DefaultDaemonNetworkMode().NetworkName()); err == nil {
  244. return nil
  245. }
  246. netOption := map[string]string{
  247. winlibnetwork.NetworkName: runconfig.DefaultDaemonNetworkMode().NetworkName(),
  248. }
  249. ipamV4Conf := libnetwork.IpamConf{}
  250. if config.bridgeConfig.FixedCIDR == "" {
  251. ipamV4Conf.PreferredPool = defaultNetworkSpace
  252. } else {
  253. ipamV4Conf.PreferredPool = config.bridgeConfig.FixedCIDR
  254. }
  255. v4Conf := []*libnetwork.IpamConf{&ipamV4Conf}
  256. v6Conf := []*libnetwork.IpamConf{}
  257. _, err := controller.NewNetwork(string(runconfig.DefaultDaemonNetworkMode()), runconfig.DefaultDaemonNetworkMode().NetworkName(), "",
  258. libnetwork.NetworkOptionGeneric(options.Generic{
  259. netlabel.GenericData: netOption,
  260. }),
  261. libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil),
  262. )
  263. if err != nil {
  264. return fmt.Errorf("Error creating default network: %v", err)
  265. }
  266. return nil
  267. }
  268. // registerLinks sets up links between containers and writes the
  269. // configuration out for persistence. As of Windows TP4, links are not supported.
  270. func (daemon *Daemon) registerLinks(container *container.Container, hostConfig *containertypes.HostConfig) error {
  271. return nil
  272. }
  273. func (daemon *Daemon) cleanupMountsByID(in string) error {
  274. return nil
  275. }
  276. func (daemon *Daemon) cleanupMounts() error {
  277. return nil
  278. }
  279. func setupRemappedRoot(config *Config) ([]idtools.IDMap, []idtools.IDMap, error) {
  280. return nil, nil, nil
  281. }
  282. func setupDaemonRoot(config *Config, rootDir string, rootUID, rootGID int) error {
  283. config.Root = rootDir
  284. // Create the root directory if it doesn't exists
  285. if err := system.MkdirAll(config.Root, 0700); err != nil && !os.IsExist(err) {
  286. return err
  287. }
  288. return nil
  289. }
  290. // runasHyperVContainer returns true if we are going to run as a Hyper-V container
  291. func (daemon *Daemon) runAsHyperVContainer(container *container.Container) bool {
  292. if container.HostConfig.Isolation.IsDefault() {
  293. // Container is set to use the default, so take the default from the daemon configuration
  294. return daemon.defaultIsolation.IsHyperV()
  295. }
  296. // Container is requesting an isolation mode. Honour it.
  297. return container.HostConfig.Isolation.IsHyperV()
  298. }
  299. // conditionalMountOnStart is a platform specific helper function during the
  300. // container start to call mount.
  301. func (daemon *Daemon) conditionalMountOnStart(container *container.Container) error {
  302. // We do not mount if a Hyper-V container
  303. if !daemon.runAsHyperVContainer(container) {
  304. return daemon.Mount(container)
  305. }
  306. return nil
  307. }
  308. // conditionalUnmountOnCleanup is a platform specific helper function called
  309. // during the cleanup of a container to unmount.
  310. func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container) error {
  311. // We do not unmount if a Hyper-V container
  312. if !daemon.runAsHyperVContainer(container) {
  313. return daemon.Unmount(container)
  314. }
  315. return nil
  316. }
  317. func driverOptions(config *Config) []nwconfig.Option {
  318. return []nwconfig.Option{}
  319. }
  320. func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) {
  321. return nil, nil
  322. }
  323. // setDefaultIsolation determine the default isolation mode for the
  324. // daemon to run in. This is only applicable on Windows
  325. func (daemon *Daemon) setDefaultIsolation() error {
  326. daemon.defaultIsolation = containertypes.Isolation("process")
  327. // On client SKUs, default to Hyper-V
  328. if system.IsWindowsClient() {
  329. daemon.defaultIsolation = containertypes.Isolation("hyperv")
  330. }
  331. for _, option := range daemon.configStore.ExecOptions {
  332. key, val, err := parsers.ParseKeyValueOpt(option)
  333. if err != nil {
  334. return err
  335. }
  336. key = strings.ToLower(key)
  337. switch key {
  338. case "isolation":
  339. if !containertypes.Isolation(val).IsValid() {
  340. return fmt.Errorf("Invalid exec-opt value for 'isolation':'%s'", val)
  341. }
  342. if containertypes.Isolation(val).IsHyperV() {
  343. daemon.defaultIsolation = containertypes.Isolation("hyperv")
  344. }
  345. if containertypes.Isolation(val).IsProcess() {
  346. if system.IsWindowsClient() {
  347. return fmt.Errorf("Windows client operating systems only support Hyper-V containers")
  348. }
  349. daemon.defaultIsolation = containertypes.Isolation("process")
  350. }
  351. default:
  352. return fmt.Errorf("Unrecognised exec-opt '%s'\n", key)
  353. }
  354. }
  355. logrus.Infof("Windows default isolation mode: %s", daemon.defaultIsolation)
  356. return nil
  357. }
  358. func rootFSToAPIType(rootfs *image.RootFS) types.RootFS {
  359. var layers []string
  360. for _, l := range rootfs.DiffIDs {
  361. layers = append(layers, l.String())
  362. }
  363. return types.RootFS{
  364. Type: rootfs.Type,
  365. Layers: layers,
  366. BaseLayer: rootfs.BaseLayer,
  367. }
  368. }
  369. func setupDaemonProcess(config *Config) error {
  370. return nil
  371. }