container.go 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. //go:build windows
  2. package hcsshim
  3. import (
  4. "context"
  5. "fmt"
  6. "os"
  7. "sync"
  8. "time"
  9. "github.com/Microsoft/hcsshim/internal/hcs"
  10. "github.com/Microsoft/hcsshim/internal/hcs/schema1"
  11. "github.com/Microsoft/hcsshim/internal/mergemaps"
  12. )
  13. // ContainerProperties holds the properties for a container and the processes running in that container
  14. type ContainerProperties = schema1.ContainerProperties
  15. // MemoryStats holds the memory statistics for a container
  16. type MemoryStats = schema1.MemoryStats
  17. // ProcessorStats holds the processor statistics for a container
  18. type ProcessorStats = schema1.ProcessorStats
  19. // StorageStats holds the storage statistics for a container
  20. type StorageStats = schema1.StorageStats
  21. // NetworkStats holds the network statistics for a container
  22. type NetworkStats = schema1.NetworkStats
  23. // Statistics is the structure returned by a statistics call on a container
  24. type Statistics = schema1.Statistics
  25. // ProcessList is the structure of an item returned by a ProcessList call on a container
  26. type ProcessListItem = schema1.ProcessListItem
  27. // MappedVirtualDiskController is the structure of an item returned by a MappedVirtualDiskList call on a container
  28. type MappedVirtualDiskController = schema1.MappedVirtualDiskController
  29. // Type of Request Support in ModifySystem
  30. type RequestType = schema1.RequestType
  31. // Type of Resource Support in ModifySystem
  32. type ResourceType = schema1.ResourceType
  33. // RequestType const
  34. const (
  35. Add = schema1.Add
  36. Remove = schema1.Remove
  37. Network = schema1.Network
  38. )
  39. // ResourceModificationRequestResponse is the structure used to send request to the container to modify the system
  40. // Supported resource types are Network and Request Types are Add/Remove
  41. type ResourceModificationRequestResponse = schema1.ResourceModificationRequestResponse
  42. type container struct {
  43. system *hcs.System
  44. waitOnce sync.Once
  45. waitErr error
  46. waitCh chan struct{}
  47. }
  48. // createContainerAdditionalJSON is read from the environment at initialization
  49. // time. It allows an environment variable to define additional JSON which
  50. // is merged in the CreateComputeSystem call to HCS.
  51. var createContainerAdditionalJSON []byte
  52. func init() {
  53. createContainerAdditionalJSON = ([]byte)(os.Getenv("HCSSHIM_CREATECONTAINER_ADDITIONALJSON"))
  54. }
  55. // CreateContainer creates a new container with the given configuration but does not start it.
  56. func CreateContainer(id string, c *ContainerConfig) (Container, error) {
  57. fullConfig, err := mergemaps.MergeJSON(c, createContainerAdditionalJSON)
  58. if err != nil {
  59. return nil, fmt.Errorf("failed to merge additional JSON '%s': %s", createContainerAdditionalJSON, err)
  60. }
  61. system, err := hcs.CreateComputeSystem(context.Background(), id, fullConfig)
  62. if err != nil {
  63. return nil, err
  64. }
  65. return &container{system: system}, err
  66. }
  67. // OpenContainer opens an existing container by ID.
  68. func OpenContainer(id string) (Container, error) {
  69. system, err := hcs.OpenComputeSystem(context.Background(), id)
  70. if err != nil {
  71. return nil, err
  72. }
  73. return &container{system: system}, err
  74. }
  75. // GetContainers gets a list of the containers on the system that match the query
  76. func GetContainers(q ComputeSystemQuery) ([]ContainerProperties, error) {
  77. return hcs.GetComputeSystems(context.Background(), q)
  78. }
  79. // Start synchronously starts the container.
  80. func (container *container) Start() error {
  81. return convertSystemError(container.system.Start(context.Background()), container)
  82. }
  83. // Shutdown requests a container shutdown, but it may not actually be shutdown until Wait() succeeds.
  84. func (container *container) Shutdown() error {
  85. err := container.system.Shutdown(context.Background())
  86. if err != nil {
  87. return convertSystemError(err, container)
  88. }
  89. return &ContainerError{Container: container, Err: ErrVmcomputeOperationPending, Operation: "hcsshim::ComputeSystem::Shutdown"}
  90. }
  91. // Terminate requests a container terminate, but it may not actually be terminated until Wait() succeeds.
  92. func (container *container) Terminate() error {
  93. err := container.system.Terminate(context.Background())
  94. if err != nil {
  95. return convertSystemError(err, container)
  96. }
  97. return &ContainerError{Container: container, Err: ErrVmcomputeOperationPending, Operation: "hcsshim::ComputeSystem::Terminate"}
  98. }
  99. // Waits synchronously waits for the container to shutdown or terminate.
  100. func (container *container) Wait() error {
  101. err := container.system.Wait()
  102. if err == nil {
  103. err = container.system.ExitError()
  104. }
  105. return convertSystemError(err, container)
  106. }
  107. // WaitTimeout synchronously waits for the container to terminate or the duration to elapse. It
  108. // returns false if timeout occurs.
  109. func (container *container) WaitTimeout(timeout time.Duration) error {
  110. container.waitOnce.Do(func() {
  111. container.waitCh = make(chan struct{})
  112. go func() {
  113. container.waitErr = container.Wait()
  114. close(container.waitCh)
  115. }()
  116. })
  117. t := time.NewTimer(timeout)
  118. defer t.Stop()
  119. select {
  120. case <-t.C:
  121. return &ContainerError{Container: container, Err: ErrTimeout, Operation: "hcsshim::ComputeSystem::Wait"}
  122. case <-container.waitCh:
  123. return container.waitErr
  124. }
  125. }
  126. // Pause pauses the execution of a container.
  127. func (container *container) Pause() error {
  128. return convertSystemError(container.system.Pause(context.Background()), container)
  129. }
  130. // Resume resumes the execution of a container.
  131. func (container *container) Resume() error {
  132. return convertSystemError(container.system.Resume(context.Background()), container)
  133. }
  134. // HasPendingUpdates returns true if the container has updates pending to install
  135. func (container *container) HasPendingUpdates() (bool, error) {
  136. return false, nil
  137. }
  138. // Statistics returns statistics for the container. This is a legacy v1 call
  139. func (container *container) Statistics() (Statistics, error) {
  140. properties, err := container.system.Properties(context.Background(), schema1.PropertyTypeStatistics)
  141. if err != nil {
  142. return Statistics{}, convertSystemError(err, container)
  143. }
  144. return properties.Statistics, nil
  145. }
  146. // ProcessList returns an array of ProcessListItems for the container. This is a legacy v1 call
  147. func (container *container) ProcessList() ([]ProcessListItem, error) {
  148. properties, err := container.system.Properties(context.Background(), schema1.PropertyTypeProcessList)
  149. if err != nil {
  150. return nil, convertSystemError(err, container)
  151. }
  152. return properties.ProcessList, nil
  153. }
  154. // This is a legacy v1 call
  155. func (container *container) MappedVirtualDisks() (map[int]MappedVirtualDiskController, error) {
  156. properties, err := container.system.Properties(context.Background(), schema1.PropertyTypeMappedVirtualDisk)
  157. if err != nil {
  158. return nil, convertSystemError(err, container)
  159. }
  160. return properties.MappedVirtualDiskControllers, nil
  161. }
  162. // CreateProcess launches a new process within the container.
  163. func (container *container) CreateProcess(c *ProcessConfig) (Process, error) {
  164. p, err := container.system.CreateProcess(context.Background(), c)
  165. if err != nil {
  166. return nil, convertSystemError(err, container)
  167. }
  168. return &process{p: p.(*hcs.Process)}, nil
  169. }
  170. // OpenProcess gets an interface to an existing process within the container.
  171. func (container *container) OpenProcess(pid int) (Process, error) {
  172. p, err := container.system.OpenProcess(context.Background(), pid)
  173. if err != nil {
  174. return nil, convertSystemError(err, container)
  175. }
  176. return &process{p: p}, nil
  177. }
  178. // Close cleans up any state associated with the container but does not terminate or wait for it.
  179. func (container *container) Close() error {
  180. return convertSystemError(container.system.Close(), container)
  181. }
  182. // Modify the System
  183. func (container *container) Modify(config *ResourceModificationRequestResponse) error {
  184. return convertSystemError(container.system.Modify(context.Background(), config), container)
  185. }