errors.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. package hcsshim
  2. import (
  3. "fmt"
  4. "syscall"
  5. "github.com/Microsoft/hcsshim/internal/hns"
  6. "github.com/Microsoft/hcsshim/internal/hcs"
  7. "github.com/Microsoft/hcsshim/internal/hcserror"
  8. )
  9. var (
  10. // ErrComputeSystemDoesNotExist is an error encountered when the container being operated on no longer exists = hcs.exist
  11. ErrComputeSystemDoesNotExist = hcs.ErrComputeSystemDoesNotExist
  12. // ErrElementNotFound is an error encountered when the object being referenced does not exist
  13. ErrElementNotFound = hcs.ErrElementNotFound
  14. // ErrElementNotFound is an error encountered when the object being referenced does not exist
  15. ErrNotSupported = hcs.ErrNotSupported
  16. // ErrInvalidData is an error encountered when the request being sent to hcs is invalid/unsupported
  17. // decimal -2147024883 / hex 0x8007000d
  18. ErrInvalidData = hcs.ErrInvalidData
  19. // ErrHandleClose is an error encountered when the handle generating the notification being waited on has been closed
  20. ErrHandleClose = hcs.ErrHandleClose
  21. // ErrAlreadyClosed is an error encountered when using a handle that has been closed by the Close method
  22. ErrAlreadyClosed = hcs.ErrAlreadyClosed
  23. // ErrInvalidNotificationType is an error encountered when an invalid notification type is used
  24. ErrInvalidNotificationType = hcs.ErrInvalidNotificationType
  25. // ErrInvalidProcessState is an error encountered when the process is not in a valid state for the requested operation
  26. ErrInvalidProcessState = hcs.ErrInvalidProcessState
  27. // ErrTimeout is an error encountered when waiting on a notification times out
  28. ErrTimeout = hcs.ErrTimeout
  29. // ErrUnexpectedContainerExit is the error encountered when a container exits while waiting for
  30. // a different expected notification
  31. ErrUnexpectedContainerExit = hcs.ErrUnexpectedContainerExit
  32. // ErrUnexpectedProcessAbort is the error encountered when communication with the compute service
  33. // is lost while waiting for a notification
  34. ErrUnexpectedProcessAbort = hcs.ErrUnexpectedProcessAbort
  35. // ErrUnexpectedValue is an error encountered when hcs returns an invalid value
  36. ErrUnexpectedValue = hcs.ErrUnexpectedValue
  37. // ErrVmcomputeAlreadyStopped is an error encountered when a shutdown or terminate request is made on a stopped container
  38. ErrVmcomputeAlreadyStopped = hcs.ErrVmcomputeAlreadyStopped
  39. // ErrVmcomputeOperationPending is an error encountered when the operation is being completed asynchronously
  40. ErrVmcomputeOperationPending = hcs.ErrVmcomputeOperationPending
  41. // ErrVmcomputeOperationInvalidState is an error encountered when the compute system is not in a valid state for the requested operation
  42. ErrVmcomputeOperationInvalidState = hcs.ErrVmcomputeOperationInvalidState
  43. // ErrProcNotFound is an error encountered when the the process cannot be found
  44. ErrProcNotFound = hcs.ErrProcNotFound
  45. // ErrVmcomputeOperationAccessIsDenied is an error which can be encountered when enumerating compute systems in RS1/RS2
  46. // builds when the underlying silo might be in the process of terminating. HCS was fixed in RS3.
  47. ErrVmcomputeOperationAccessIsDenied = hcs.ErrVmcomputeOperationAccessIsDenied
  48. // ErrVmcomputeInvalidJSON is an error encountered when the compute system does not support/understand the messages sent by management
  49. ErrVmcomputeInvalidJSON = hcs.ErrVmcomputeInvalidJSON
  50. // ErrVmcomputeUnknownMessage is an error encountered guest compute system doesn't support the message
  51. ErrVmcomputeUnknownMessage = hcs.ErrVmcomputeUnknownMessage
  52. // ErrNotSupported is an error encountered when hcs doesn't support the request
  53. ErrPlatformNotSupported = hcs.ErrPlatformNotSupported
  54. )
  55. type EndpointNotFoundError = hns.EndpointNotFoundError
  56. type NetworkNotFoundError = hns.NetworkNotFoundError
  57. // ProcessError is an error encountered in HCS during an operation on a Process object
  58. type ProcessError struct {
  59. Process *process
  60. Operation string
  61. ExtraInfo string
  62. Err error
  63. Events []hcs.ErrorEvent
  64. }
  65. // ContainerError is an error encountered in HCS during an operation on a Container object
  66. type ContainerError struct {
  67. Container *container
  68. Operation string
  69. ExtraInfo string
  70. Err error
  71. Events []hcs.ErrorEvent
  72. }
  73. func (e *ContainerError) Error() string {
  74. if e == nil {
  75. return "<nil>"
  76. }
  77. if e.Container == nil {
  78. return "unexpected nil container for error: " + e.Err.Error()
  79. }
  80. s := "container " + e.Container.system.ID()
  81. if e.Operation != "" {
  82. s += " encountered an error during " + e.Operation
  83. }
  84. switch e.Err.(type) {
  85. case nil:
  86. break
  87. case syscall.Errno:
  88. s += fmt.Sprintf(": failure in a Windows system call: %s (0x%x)", e.Err, hcserror.Win32FromError(e.Err))
  89. default:
  90. s += fmt.Sprintf(": %s", e.Err.Error())
  91. }
  92. for _, ev := range e.Events {
  93. s += "\n" + ev.String()
  94. }
  95. if e.ExtraInfo != "" {
  96. s += " extra info: " + e.ExtraInfo
  97. }
  98. return s
  99. }
  100. func makeContainerError(container *container, operation string, extraInfo string, err error) error {
  101. // Don't double wrap errors
  102. if _, ok := err.(*ContainerError); ok {
  103. return err
  104. }
  105. containerError := &ContainerError{Container: container, Operation: operation, ExtraInfo: extraInfo, Err: err}
  106. return containerError
  107. }
  108. func (e *ProcessError) Error() string {
  109. if e == nil {
  110. return "<nil>"
  111. }
  112. if e.Process == nil {
  113. return "Unexpected nil process for error: " + e.Err.Error()
  114. }
  115. s := fmt.Sprintf("process %d in container %s", e.Process.p.Pid(), e.Process.p.SystemID())
  116. if e.Operation != "" {
  117. s += " encountered an error during " + e.Operation
  118. }
  119. switch e.Err.(type) {
  120. case nil:
  121. break
  122. case syscall.Errno:
  123. s += fmt.Sprintf(": failure in a Windows system call: %s (0x%x)", e.Err, hcserror.Win32FromError(e.Err))
  124. default:
  125. s += fmt.Sprintf(": %s", e.Err.Error())
  126. }
  127. for _, ev := range e.Events {
  128. s += "\n" + ev.String()
  129. }
  130. return s
  131. }
  132. func makeProcessError(process *process, operation string, extraInfo string, err error) error {
  133. // Don't double wrap errors
  134. if _, ok := err.(*ProcessError); ok {
  135. return err
  136. }
  137. processError := &ProcessError{Process: process, Operation: operation, ExtraInfo: extraInfo, Err: err}
  138. return processError
  139. }
  140. // IsNotExist checks if an error is caused by the Container or Process not existing.
  141. // Note: Currently, ErrElementNotFound can mean that a Process has either
  142. // already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
  143. // will currently return true when the error is ErrElementNotFound or ErrProcNotFound.
  144. func IsNotExist(err error) bool {
  145. if _, ok := err.(EndpointNotFoundError); ok {
  146. return true
  147. }
  148. if _, ok := err.(NetworkNotFoundError); ok {
  149. return true
  150. }
  151. return hcs.IsNotExist(getInnerError(err))
  152. }
  153. // IsAlreadyClosed checks if an error is caused by the Container or Process having been
  154. // already closed by a call to the Close() method.
  155. func IsAlreadyClosed(err error) bool {
  156. return hcs.IsAlreadyClosed(getInnerError(err))
  157. }
  158. // IsPending returns a boolean indicating whether the error is that
  159. // the requested operation is being completed in the background.
  160. func IsPending(err error) bool {
  161. return hcs.IsPending(getInnerError(err))
  162. }
  163. // IsTimeout returns a boolean indicating whether the error is caused by
  164. // a timeout waiting for the operation to complete.
  165. func IsTimeout(err error) bool {
  166. return hcs.IsTimeout(getInnerError(err))
  167. }
  168. // IsAlreadyStopped returns a boolean indicating whether the error is caused by
  169. // a Container or Process being already stopped.
  170. // Note: Currently, ErrElementNotFound can mean that a Process has either
  171. // already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
  172. // will currently return true when the error is ErrElementNotFound or ErrProcNotFound.
  173. func IsAlreadyStopped(err error) bool {
  174. return hcs.IsAlreadyStopped(getInnerError(err))
  175. }
  176. // IsNotSupported returns a boolean indicating whether the error is caused by
  177. // unsupported platform requests
  178. // Note: Currently Unsupported platform requests can be mean either
  179. // ErrVmcomputeInvalidJSON, ErrInvalidData, ErrNotSupported or ErrVmcomputeUnknownMessage
  180. // is thrown from the Platform
  181. func IsNotSupported(err error) bool {
  182. return hcs.IsNotSupported(getInnerError(err))
  183. }
  184. func getInnerError(err error) error {
  185. switch pe := err.(type) {
  186. case nil:
  187. return nil
  188. case *ContainerError:
  189. err = pe.Err
  190. case *ProcessError:
  191. err = pe.Err
  192. }
  193. return err
  194. }
  195. func convertSystemError(err error, c *container) error {
  196. if serr, ok := err.(*hcs.SystemError); ok {
  197. return &ContainerError{Container: c, Operation: serr.Op, ExtraInfo: serr.Extra, Err: serr.Err, Events: serr.Events}
  198. }
  199. return err
  200. }
  201. func convertProcessError(err error, p *process) error {
  202. if perr, ok := err.(*hcs.ProcessError); ok {
  203. return &ProcessError{Process: p, Operation: perr.Op, Err: perr.Err, Events: perr.Events}
  204. }
  205. return err
  206. }