| package hcsshim | |
| import ( | |
| "fmt" | |
| "syscall" | |
| "github.com/Microsoft/hcsshim/internal/hns" | |
| "github.com/Microsoft/hcsshim/internal/hcs" | |
| "github.com/Microsoft/hcsshim/internal/hcserror" | |
| ) | |
| var ( | |
| // ErrComputeSystemDoesNotExist is an error encountered when the container being operated on no longer exists = hcs.exist | |
| ErrComputeSystemDoesNotExist = hcs.ErrComputeSystemDoesNotExist | |
| // ErrElementNotFound is an error encountered when the object being referenced does not exist | |
| ErrElementNotFound = hcs.ErrElementNotFound | |
| // ErrElementNotFound is an error encountered when the object being referenced does not exist | |
| ErrNotSupported = hcs.ErrNotSupported | |
| // ErrInvalidData is an error encountered when the request being sent to hcs is invalid/unsupported | |
| // decimal -2147024883 / hex 0x8007000d | |
| ErrInvalidData = hcs.ErrInvalidData | |
| // ErrHandleClose is an error encountered when the handle generating the notification being waited on has been closed | |
| ErrHandleClose = hcs.ErrHandleClose | |
| // ErrAlreadyClosed is an error encountered when using a handle that has been closed by the Close method | |
| ErrAlreadyClosed = hcs.ErrAlreadyClosed | |
| // ErrInvalidNotificationType is an error encountered when an invalid notification type is used | |
| ErrInvalidNotificationType = hcs.ErrInvalidNotificationType | |
| // ErrInvalidProcessState is an error encountered when the process is not in a valid state for the requested operation | |
| ErrInvalidProcessState = hcs.ErrInvalidProcessState | |
| // ErrTimeout is an error encountered when waiting on a notification times out | |
| ErrTimeout = hcs.ErrTimeout | |
| // ErrUnexpectedContainerExit is the error encountered when a container exits while waiting for | |
| // a different expected notification | |
| ErrUnexpectedContainerExit = hcs.ErrUnexpectedContainerExit | |
| // ErrUnexpectedProcessAbort is the error encountered when communication with the compute service | |
| // is lost while waiting for a notification | |
| ErrUnexpectedProcessAbort = hcs.ErrUnexpectedProcessAbort | |
| // ErrUnexpectedValue is an error encountered when hcs returns an invalid value | |
| ErrUnexpectedValue = hcs.ErrUnexpectedValue | |
| // ErrVmcomputeAlreadyStopped is an error encountered when a shutdown or terminate request is made on a stopped container | |
| ErrVmcomputeAlreadyStopped = hcs.ErrVmcomputeAlreadyStopped | |
| // ErrVmcomputeOperationPending is an error encountered when the operation is being completed asynchronously | |
| ErrVmcomputeOperationPending = hcs.ErrVmcomputeOperationPending | |
| // ErrVmcomputeOperationInvalidState is an error encountered when the compute system is not in a valid state for the requested operation | |
| ErrVmcomputeOperationInvalidState = hcs.ErrVmcomputeOperationInvalidState | |
| // ErrProcNotFound is an error encountered when a procedure look up fails. | |
| ErrProcNotFound = hcs.ErrProcNotFound | |
| // ErrVmcomputeOperationAccessIsDenied is an error which can be encountered when enumerating compute systems in RS1/RS2 | |
| // builds when the underlying silo might be in the process of terminating. HCS was fixed in RS3. | |
| ErrVmcomputeOperationAccessIsDenied = hcs.ErrVmcomputeOperationAccessIsDenied | |
| // ErrVmcomputeInvalidJSON is an error encountered when the compute system does not support/understand the messages sent by management | |
| ErrVmcomputeInvalidJSON = hcs.ErrVmcomputeInvalidJSON | |
| // ErrVmcomputeUnknownMessage is an error encountered guest compute system doesn't support the message | |
| ErrVmcomputeUnknownMessage = hcs.ErrVmcomputeUnknownMessage | |
| // ErrNotSupported is an error encountered when hcs doesn't support the request | |
| ErrPlatformNotSupported = hcs.ErrPlatformNotSupported | |
| ) | |
| type EndpointNotFoundError = hns.EndpointNotFoundError | |
| type NetworkNotFoundError = hns.NetworkNotFoundError | |
| // ProcessError is an error encountered in HCS during an operation on a Process object | |
| type ProcessError struct { | |
| Process *process | |
| Operation string | |
| Err error | |
| Events []hcs.ErrorEvent | |
| } | |
| // ContainerError is an error encountered in HCS during an operation on a Container object | |
| type ContainerError struct { | |
| Container *container | |
| Operation string | |
| Err error | |
| Events []hcs.ErrorEvent | |
| } | |
| func (e *ContainerError) Error() string { | |
| if e == nil { | |
| return "<nil>" | |
| } | |
| if e.Container == nil { | |
| return "unexpected nil container for error: " + e.Err.Error() | |
| } | |
| s := "container " + e.Container.system.ID() | |
| if e.Operation != "" { | |
| s += " encountered an error during " + e.Operation | |
| } | |
| switch e.Err.(type) { | |
| case nil: | |
| break | |
| case syscall.Errno: | |
| s += fmt.Sprintf(": failure in a Windows system call: %s (0x%x)", e.Err, hcserror.Win32FromError(e.Err)) | |
| default: | |
| s += fmt.Sprintf(": %s", e.Err.Error()) | |
| } | |
| for _, ev := range e.Events { | |
| s += "\n" + ev.String() | |
| } | |
| return s | |
| } | |
| func (e *ProcessError) Error() string { | |
| if e == nil { | |
| return "<nil>" | |
| } | |
| if e.Process == nil { | |
| return "Unexpected nil process for error: " + e.Err.Error() | |
| } | |
| s := fmt.Sprintf("process %d in container %s", e.Process.p.Pid(), e.Process.p.SystemID()) | |
| if e.Operation != "" { | |
| s += " encountered an error during " + e.Operation | |
| } | |
| switch e.Err.(type) { | |
| case nil: | |
| break | |
| case syscall.Errno: | |
| s += fmt.Sprintf(": failure in a Windows system call: %s (0x%x)", e.Err, hcserror.Win32FromError(e.Err)) | |
| default: | |
| s += fmt.Sprintf(": %s", e.Err.Error()) | |
| } | |
| for _, ev := range e.Events { | |
| s += "\n" + ev.String() | |
| } | |
| return s | |
| } | |
| // IsNotExist checks if an error is caused by the Container or Process not existing. | |
| // Note: Currently, ErrElementNotFound can mean that a Process has either | |
| // already exited, or does not exist. Both IsAlreadyStopped and IsNotExist | |
| // will currently return true when the error is ErrElementNotFound. | |
| func IsNotExist(err error) bool { | |
| if _, ok := err.(EndpointNotFoundError); ok { | |
| return true | |
| } | |
| if _, ok := err.(NetworkNotFoundError); ok { | |
| return true | |
| } | |
| return hcs.IsNotExist(getInnerError(err)) | |
| } | |
| // IsAlreadyClosed checks if an error is caused by the Container or Process having been | |
| // already closed by a call to the Close() method. | |
| func IsAlreadyClosed(err error) bool { | |
| return hcs.IsAlreadyClosed(getInnerError(err)) | |
| } | |
| // IsPending returns a boolean indicating whether the error is that | |
| // the requested operation is being completed in the background. | |
| func IsPending(err error) bool { | |
| return hcs.IsPending(getInnerError(err)) | |
| } | |
| // IsTimeout returns a boolean indicating whether the error is caused by | |
| // a timeout waiting for the operation to complete. | |
| func IsTimeout(err error) bool { | |
| return hcs.IsTimeout(getInnerError(err)) | |
| } | |
| // IsAlreadyStopped returns a boolean indicating whether the error is caused by | |
| // a Container or Process being already stopped. | |
| // Note: Currently, ErrElementNotFound can mean that a Process has either | |
| // already exited, or does not exist. Both IsAlreadyStopped and IsNotExist | |
| // will currently return true when the error is ErrElementNotFound. | |
| func IsAlreadyStopped(err error) bool { | |
| return hcs.IsAlreadyStopped(getInnerError(err)) | |
| } | |
| // IsNotSupported returns a boolean indicating whether the error is caused by | |
| // unsupported platform requests | |
| // Note: Currently Unsupported platform requests can be mean either | |
| // ErrVmcomputeInvalidJSON, ErrInvalidData, ErrNotSupported or ErrVmcomputeUnknownMessage | |
| // is thrown from the Platform | |
| func IsNotSupported(err error) bool { | |
| return hcs.IsNotSupported(getInnerError(err)) | |
| } | |
| // IsOperationInvalidState returns true when err is caused by | |
| // `ErrVmcomputeOperationInvalidState`. | |
| func IsOperationInvalidState(err error) bool { | |
| return hcs.IsOperationInvalidState(getInnerError(err)) | |
| } | |
| // IsAccessIsDenied returns true when err is caused by | |
| // `ErrVmcomputeOperationAccessIsDenied`. | |
| func IsAccessIsDenied(err error) bool { | |
| return hcs.IsAccessIsDenied(getInnerError(err)) | |
| } | |
| func getInnerError(err error) error { | |
| switch pe := err.(type) { | |
| case nil: | |
| return nil | |
| case *ContainerError: | |
| err = pe.Err | |
| case *ProcessError: | |
| err = pe.Err | |
| } | |
| return err | |
| } | |
| func convertSystemError(err error, c *container) error { | |
| if serr, ok := err.(*hcs.SystemError); ok { | |
| return &ContainerError{Container: c, Operation: serr.Op, Err: serr.Err, Events: serr.Events} | |
| } | |
| return err | |
| } | |
| func convertProcessError(err error, p *process) error { | |
| if perr, ok := err.(*hcs.ProcessError); ok { | |
| return &ProcessError{Process: p, Operation: perr.Op, Err: perr.Err, Events: perr.Events} | |
| } | |
| return err | |
| } |