errors.go 8.6 KB

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