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