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 the the process cannot be found 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 "" } 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 "" } 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 or ErrProcNotFound. 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 or ErrProcNotFound. 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 }