errors.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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. // ErrHandleClose is an error encountered when the handle generating the notification being waited on has been closed
  13. ErrHandleClose = errors.New("hcsshim: the handle generating this notification has been closed")
  14. // ErrAlreadyClosed is an error encountered when using a handle that has been closed by the Close method
  15. ErrAlreadyClosed = errors.New("hcsshim: the handle has already been closed")
  16. // ErrInvalidNotificationType is an error encountered when an invalid notification type is used
  17. ErrInvalidNotificationType = errors.New("hcsshim: invalid notification type")
  18. // ErrInvalidProcessState is an error encountered when the process is not in a valid state for the requested operation
  19. ErrInvalidProcessState = errors.New("the process is in an invalid state for the attempted operation")
  20. // ErrTimeout is an error encountered when waiting on a notification times out
  21. ErrTimeout = errors.New("hcsshim: timeout waiting for notification")
  22. // ErrUnexpectedContainerExit is the error encountered when a container exits while waiting for
  23. // a different expected notification
  24. ErrUnexpectedContainerExit = errors.New("unexpected container exit")
  25. // ErrUnexpectedProcessAbort is the error encountered when communication with the compute service
  26. // is lost while waiting for a notification
  27. ErrUnexpectedProcessAbort = errors.New("lost communication with compute service")
  28. // ErrUnexpectedValue is an error encountered when hcs returns an invalid value
  29. ErrUnexpectedValue = errors.New("unexpected value returned from hcs")
  30. // ErrVmcomputeAlreadyStopped is an error encountered when a shutdown or terminate request is made on a stopped container
  31. ErrVmcomputeAlreadyStopped = syscall.Errno(0xc0370110)
  32. // ErrVmcomputeOperationPending is an error encountered when the operation is being completed asynchronously
  33. ErrVmcomputeOperationPending = syscall.Errno(0xC0370103)
  34. // ErrVmcomputeOperationInvalidState is an error encountered when the compute system is not in a valid state for the requested operation
  35. ErrVmcomputeOperationInvalidState = syscall.Errno(0xc0370105)
  36. // ErrProcNotFound is an error encountered when the the process cannot be found
  37. ErrProcNotFound = syscall.Errno(0x7f)
  38. // ErrVmcomputeOperationAccessIsDenied is an error which can be encountered when enumerating compute systems in RS1/RS2
  39. // builds when the underlying silo might be in the process of terminating. HCS was fixed in RS3.
  40. ErrVmcomputeOperationAccessIsDenied = syscall.Errno(0x5)
  41. )
  42. // ProcessError is an error encountered in HCS during an operation on a Process object
  43. type ProcessError struct {
  44. Process *process
  45. Operation string
  46. ExtraInfo string
  47. Err error
  48. }
  49. // ContainerError is an error encountered in HCS during an operation on a Container object
  50. type ContainerError struct {
  51. Container *container
  52. Operation string
  53. ExtraInfo string
  54. Err error
  55. }
  56. func (e *ContainerError) Error() string {
  57. if e == nil {
  58. return "<nil>"
  59. }
  60. if e.Container == nil {
  61. return "unexpected nil container for error: " + e.Err.Error()
  62. }
  63. s := "container " + e.Container.id
  64. if e.Operation != "" {
  65. s += " encountered an error during " + e.Operation
  66. }
  67. switch e.Err.(type) {
  68. case nil:
  69. break
  70. case syscall.Errno:
  71. s += fmt.Sprintf(": failure in a Windows system call: %s (0x%x)", e.Err, win32FromError(e.Err))
  72. default:
  73. s += fmt.Sprintf(": %s", e.Err.Error())
  74. }
  75. if e.ExtraInfo != "" {
  76. s += " extra info: " + e.ExtraInfo
  77. }
  78. return s
  79. }
  80. func makeContainerError(container *container, operation string, extraInfo string, err error) error {
  81. // Don't double wrap errors
  82. if _, ok := err.(*ContainerError); ok {
  83. return err
  84. }
  85. containerError := &ContainerError{Container: container, Operation: operation, ExtraInfo: extraInfo, Err: err}
  86. return containerError
  87. }
  88. func (e *ProcessError) Error() string {
  89. if e == nil {
  90. return "<nil>"
  91. }
  92. if e.Process == nil {
  93. return "Unexpected nil process for error: " + e.Err.Error()
  94. }
  95. s := fmt.Sprintf("process %d", e.Process.processID)
  96. if e.Process.container != nil {
  97. s += " in container " + e.Process.container.id
  98. }
  99. if e.Operation != "" {
  100. s += " encountered an error during " + e.Operation
  101. }
  102. switch e.Err.(type) {
  103. case nil:
  104. break
  105. case syscall.Errno:
  106. s += fmt.Sprintf(": failure in a Windows system call: %s (0x%x)", e.Err, win32FromError(e.Err))
  107. default:
  108. s += fmt.Sprintf(": %s", e.Err.Error())
  109. }
  110. return s
  111. }
  112. func makeProcessError(process *process, operation string, extraInfo string, err error) error {
  113. // Don't double wrap errors
  114. if _, ok := err.(*ProcessError); ok {
  115. return err
  116. }
  117. processError := &ProcessError{Process: process, Operation: operation, ExtraInfo: extraInfo, Err: err}
  118. return processError
  119. }
  120. // IsNotExist checks if an error is caused by the Container or Process not existing.
  121. // Note: Currently, ErrElementNotFound can mean that a Process has either
  122. // already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
  123. // will currently return true when the error is ErrElementNotFound or ErrProcNotFound.
  124. func IsNotExist(err error) bool {
  125. err = getInnerError(err)
  126. return err == ErrComputeSystemDoesNotExist ||
  127. err == ErrElementNotFound ||
  128. err == ErrProcNotFound
  129. }
  130. // IsAlreadyClosed checks if an error is caused by the Container or Process having been
  131. // already closed by a call to the Close() method.
  132. func IsAlreadyClosed(err error) bool {
  133. err = getInnerError(err)
  134. return err == ErrAlreadyClosed
  135. }
  136. // IsPending returns a boolean indicating whether the error is that
  137. // the requested operation is being completed in the background.
  138. func IsPending(err error) bool {
  139. err = getInnerError(err)
  140. return err == ErrVmcomputeOperationPending
  141. }
  142. // IsTimeout returns a boolean indicating whether the error is caused by
  143. // a timeout waiting for the operation to complete.
  144. func IsTimeout(err error) bool {
  145. err = getInnerError(err)
  146. return err == ErrTimeout
  147. }
  148. // IsAlreadyStopped returns a boolean indicating whether the error is caused by
  149. // a Container or Process being already stopped.
  150. // Note: Currently, ErrElementNotFound can mean that a Process has either
  151. // already exited, or does not exist. Both IsAlreadyStopped and IsNotExist
  152. // will currently return true when the error is ErrElementNotFound or ErrProcNotFound.
  153. func IsAlreadyStopped(err error) bool {
  154. err = getInnerError(err)
  155. return err == ErrVmcomputeAlreadyStopped ||
  156. err == ErrElementNotFound ||
  157. err == ErrProcNotFound
  158. }
  159. func getInnerError(err error) error {
  160. switch pe := err.(type) {
  161. case nil:
  162. return nil
  163. case *ContainerError:
  164. err = pe.Err
  165. case *ProcessError:
  166. err = pe.Err
  167. }
  168. return err
  169. }