oci_windows.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. package daemon
  2. import (
  3. "errors"
  4. "fmt"
  5. "os"
  6. "path/filepath"
  7. "syscall"
  8. "github.com/docker/docker/container"
  9. "github.com/docker/docker/image"
  10. "github.com/docker/docker/layer"
  11. "github.com/docker/docker/libcontainerd"
  12. "github.com/docker/docker/libcontainerd/windowsoci"
  13. "github.com/docker/docker/oci"
  14. )
  15. func (daemon *Daemon) createSpec(c *container.Container) (*libcontainerd.Spec, error) {
  16. s := oci.DefaultSpec()
  17. linkedEnv, err := daemon.setupLinkedContainers(c)
  18. if err != nil {
  19. return nil, err
  20. }
  21. // TODO Windows - this can be removed. Not used (UID/GID)
  22. rootUID, rootGID := daemon.GetRemappedUIDGID()
  23. if err := c.SetupWorkingDirectory(rootUID, rootGID); err != nil {
  24. return nil, err
  25. }
  26. img, err := daemon.imageStore.Get(c.ImageID)
  27. if err != nil {
  28. return nil, fmt.Errorf("Failed to graph.Get on ImageID %s - %s", c.ImageID, err)
  29. }
  30. s.Platform.OSVersion = img.OSVersion
  31. // In base spec
  32. s.Hostname = c.FullHostname()
  33. // In s.Mounts
  34. mounts, err := daemon.setupMounts(c)
  35. if err != nil {
  36. return nil, err
  37. }
  38. for _, mount := range mounts {
  39. s.Mounts = append(s.Mounts, windowsoci.Mount{
  40. Source: mount.Source,
  41. Destination: mount.Destination,
  42. Readonly: !mount.Writable,
  43. })
  44. }
  45. // In s.Process
  46. s.Process.Args = append([]string{c.Path}, c.Args...)
  47. if !c.Config.ArgsEscaped {
  48. s.Process.Args = escapeArgs(s.Process.Args)
  49. }
  50. s.Process.Cwd = c.Config.WorkingDir
  51. if len(s.Process.Cwd) == 0 {
  52. // We default to C:\ to workaround the oddity of the case that the
  53. // default directory for cmd running as LocalSystem (or
  54. // ContainerAdministrator) is c:\windows\system32. Hence docker run
  55. // <image> cmd will by default end in c:\windows\system32, rather
  56. // than 'root' (/) on Linux. The oddity is that if you have a dockerfile
  57. // which has no WORKDIR and has a COPY file ., . will be interpreted
  58. // as c:\. Hence, setting it to default of c:\ makes for consistency.
  59. s.Process.Cwd = `C:\`
  60. }
  61. s.Process.Env = c.CreateDaemonEnvironment(linkedEnv)
  62. s.Process.InitialConsoleSize = c.HostConfig.ConsoleSize
  63. s.Process.Terminal = c.Config.Tty
  64. s.Process.User.User = c.Config.User
  65. // In spec.Root
  66. s.Root.Path = c.BaseFS
  67. s.Root.Readonly = c.HostConfig.ReadonlyRootfs
  68. // In s.Windows
  69. s.Windows.FirstStart = !c.HasBeenStartedBefore
  70. // s.Windows.LayerFolder.
  71. m, err := c.RWLayer.Metadata()
  72. if err != nil {
  73. return nil, fmt.Errorf("Failed to get layer metadata - %s", err)
  74. }
  75. s.Windows.LayerFolder = m["dir"]
  76. // s.Windows.LayerPaths
  77. var layerPaths []string
  78. if img.RootFS != nil && (img.RootFS.Type == image.TypeLayers || img.RootFS.Type == image.TypeLayersWithBase) {
  79. // Get the layer path for each layer.
  80. start := 1
  81. if img.RootFS.Type == image.TypeLayersWithBase {
  82. // Include an empty slice to get the base layer ID.
  83. start = 0
  84. }
  85. max := len(img.RootFS.DiffIDs)
  86. for i := start; i <= max; i++ {
  87. img.RootFS.DiffIDs = img.RootFS.DiffIDs[:i]
  88. path, err := layer.GetLayerPath(daemon.layerStore, img.RootFS.ChainID())
  89. if err != nil {
  90. return nil, fmt.Errorf("Failed to get layer path from graphdriver %s for ImageID %s - %s", daemon.layerStore, img.RootFS.ChainID(), err)
  91. }
  92. // Reverse order, expecting parent most first
  93. layerPaths = append([]string{path}, layerPaths...)
  94. }
  95. }
  96. s.Windows.LayerPaths = layerPaths
  97. // Are we going to run as a Hyper-V container?
  98. hv := false
  99. if c.HostConfig.Isolation.IsDefault() {
  100. // Container is set to use the default, so take the default from the daemon configuration
  101. hv = daemon.defaultIsolation.IsHyperV()
  102. } else {
  103. // Container is requesting an isolation mode. Honour it.
  104. hv = c.HostConfig.Isolation.IsHyperV()
  105. }
  106. if hv {
  107. hvr := &windowsoci.HvRuntime{}
  108. if img.RootFS != nil && img.RootFS.Type == image.TypeLayers {
  109. // For TP5, the utility VM is part of the base layer.
  110. // TODO-jstarks: Add support for separate utility VM images
  111. // once it is decided how they can be stored.
  112. uvmpath := filepath.Join(layerPaths[len(layerPaths)-1], "UtilityVM")
  113. _, err = os.Stat(uvmpath)
  114. if err != nil {
  115. if os.IsNotExist(err) {
  116. err = errors.New("container image does not contain a utility VM")
  117. }
  118. return nil, err
  119. }
  120. hvr.ImagePath = uvmpath
  121. }
  122. s.Windows.HvRuntime = hvr
  123. }
  124. // In s.Windows.Networking
  125. // Connect all the libnetwork allocated networks to the container
  126. var epList []string
  127. if c.NetworkSettings != nil {
  128. for n := range c.NetworkSettings.Networks {
  129. sn, err := daemon.FindNetwork(n)
  130. if err != nil {
  131. continue
  132. }
  133. ep, err := c.GetEndpointInNetwork(sn)
  134. if err != nil {
  135. continue
  136. }
  137. data, err := ep.DriverInfo()
  138. if err != nil {
  139. continue
  140. }
  141. if data["hnsid"] != nil {
  142. epList = append(epList, data["hnsid"].(string))
  143. }
  144. }
  145. }
  146. s.Windows.Networking = &windowsoci.Networking{
  147. EndpointList: epList,
  148. }
  149. // In s.Windows.Resources
  150. // @darrenstahlmsft implement these resources
  151. cpuShares := uint64(c.HostConfig.CPUShares)
  152. s.Windows.Resources = &windowsoci.Resources{
  153. CPU: &windowsoci.CPU{
  154. Percent: &c.HostConfig.CPUPercent,
  155. Shares: &cpuShares,
  156. },
  157. Memory: &windowsoci.Memory{
  158. Limit: &c.HostConfig.Memory,
  159. //TODO Reservation: ...,
  160. },
  161. Network: &windowsoci.Network{
  162. //TODO Bandwidth: ...,
  163. },
  164. Storage: &windowsoci.Storage{
  165. Bps: &c.HostConfig.IOMaximumBandwidth,
  166. Iops: &c.HostConfig.IOMaximumIOps,
  167. //TODO SandboxSize: ...,
  168. },
  169. }
  170. return (*libcontainerd.Spec)(&s), nil
  171. }
  172. func escapeArgs(args []string) []string {
  173. escapedArgs := make([]string, len(args))
  174. for i, a := range args {
  175. escapedArgs[i] = syscall.EscapeArg(a)
  176. }
  177. return escapedArgs
  178. }