Skip to content

Commit

Permalink
Merge pull request #51 from Microsoft/ContainerAlreadyStoppedError
Browse files Browse the repository at this point in the history
Added known error code when shutdown is already complete
  • Loading branch information
darstahl authored Jun 15, 2016
2 parents 3aeaadd + 5065f1a commit 5357233
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 133 deletions.
55 changes: 1 addition & 54 deletions container.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package hcsshim

import (
"encoding/json"
"errors"
"fmt"
"runtime"
"syscall"
"time"
Expand All @@ -17,14 +15,6 @@ var (

const pendingUpdatesQuery = `{ "PropertyTypes" : ["PendingUpdates"]}`

// ContainerError is an error encountered in HCS
type ContainerError struct {
Container *container
Operation string
ExtraInfo string
Err error
}

type container struct {
handle hcsSystem
id string
Expand Down Expand Up @@ -253,7 +243,7 @@ func (container *container) properties(query string) (*containerProperties, erro
}

if propertiesp == nil {
return nil, errors.New("Unexpected result from hcsGetComputeSystemProperties, properties should never be nil")
return nil, ErrUnexpectedValue
}
propertiesRaw := convertAndFreeCoTaskMemBytes(propertiesp)

Expand Down Expand Up @@ -486,46 +476,3 @@ func (container *container) unregisterCallback() error {

return nil
}

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.id

if e.Operation != "" {
s += " encountered an error during " + e.Operation
}

if e.Err != nil {
s += fmt.Sprintf(" failed in Win32: %s (0x%x)", e.Err, win32FromError(e.Err))
}

if e.ExtraInfo != "" {
s += " extra info: " + e.ExtraInfo
}

return s
}

func makeContainerError(container *container, operation string, extraInfo string, err error) error {
// Don't wrap errors created in hcsshim
if err == ErrTimeout ||
err == ErrUnexpectedProcessAbort ||
err == ErrUnexpectedContainerExit ||
err == ErrHandleClose ||
err == ErrInvalidProcessState ||
err == ErrInvalidNotificationType ||
err == ErrVmcomputeOperationPending {
return err
}

containerError := &ContainerError{Container: container, Operation: operation, ExtraInfo: extraInfo, Err: err}
logrus.Error(containerError)
return containerError
}
149 changes: 149 additions & 0 deletions errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package hcsshim

import (
"errors"
"fmt"
"syscall"

"github.com/Sirupsen/logrus"
)

var (
// ErrHandleClose is an error returned when the handle generating the notification being waited on has been closed
ErrHandleClose = errors.New("hcsshim: the handle generating this notification has been closed")

// ErrInvalidNotificationType is an error encountered when an invalid notification type is used
ErrInvalidNotificationType = errors.New("hcsshim: invalid notification type")

// ErrInvalidProcessState is an error encountered when the process is not in a valid state for the requested operation
ErrInvalidProcessState = errors.New("the process is in an invalid state for the attempted operation")

// ErrTimeout is an error encountered when waiting on a notification times out
ErrTimeout = errors.New("hcsshim: timeout waiting for notification")

// ErrUnexpectedContainerExit is the error returned when a container exits while waiting for
// a different expected notification
ErrUnexpectedContainerExit = errors.New("unexpected container exit")

// ErrUnexpectedProcessAbort is the error returned when communication with the compute service
// is lost while waiting for a notification
ErrUnexpectedProcessAbort = errors.New("lost communication with compute service")

// ErrUnexpectedValue is an error returned when hcs returns an invalid value
ErrUnexpectedValue = errors.New("unexpected value returned from hcs")

// ErrVmcomputeAlreadyStopped is an error returned when a shutdown or terminate request is made on a stopped container
ErrVmcomputeAlreadyStopped = syscall.Errno(0xc0370110)

// ErrVmcomputeOperationPending is an error returned when the operation is being completed asynchronously
ErrVmcomputeOperationPending = syscall.Errno(0xC0370103)
)

// ProcessError is an error encountered in HCS during an operation on a Process object
type ProcessError struct {
Process *process
Operation string
ExtraInfo string
Err error
}

// ContainerError is an error encountered in HCS during an operation on a Container object
type ContainerError struct {
Container *container
Operation string
ExtraInfo string
Err error
}

func isKnownError(err error) bool {
// Don't wrap errors created in hcsshim
if err == ErrHandleClose ||
err == ErrInvalidNotificationType ||
err == ErrInvalidProcessState ||
err == ErrTimeout ||
err == ErrUnexpectedContainerExit ||
err == ErrUnexpectedProcessAbort ||
err == ErrUnexpectedValue ||
err == ErrVmcomputeAlreadyStopped ||
err == ErrVmcomputeOperationPending {
return true
}

return false
}

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.id

if e.Operation != "" {
s += " encountered an error during " + e.Operation
}

if e.Err != nil {
s += fmt.Sprintf(" failed in Win32: %s (0x%x)", e.Err, win32FromError(e.Err))
}

if e.ExtraInfo != "" {
s += " extra info: " + e.ExtraInfo
}

return s
}

func makeContainerError(container *container, operation string, extraInfo string, err error) error {
// Return known errors to the client
if isKnownError(err) {
return err
}

// Log any unexpected errors
containerError := &ContainerError{Container: container, Operation: operation, ExtraInfo: extraInfo, Err: err}
logrus.Error(containerError)
return containerError
}

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", e.Process.processID)

if e.Process.container != nil {
s += " in container " + e.Process.container.id
}

if e.Operation != "" {
s += " " + e.Operation
}

if e.Err != nil {
s += fmt.Sprintf(" failed in Win32: %s (0x%x)", e.Err, win32FromError(e.Err))
}

return s
}

func makeProcessError(process *process, operation string, extraInfo string, err error) error {
// Return known errors to the client
if isKnownError(err) {
return err
}

// Log any unexpected errors
processError := &ProcessError{Process: process, Operation: operation, ExtraInfo: extraInfo, Err: err}
logrus.Error(processError)
return processError
}
2 changes: 0 additions & 2 deletions hcsshim.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,6 @@ const (
ERROR_SHUTDOWN_IN_PROGRESS = syscall.Errno(1115)
WSAEINVAL = syscall.Errno(10022)

ErrVmcomputeOperationPending = syscall.Errno(0xC0370103)

// Timeout on wait calls
TimeoutInfinite = 0xFFFFFFFF
)
Expand Down
23 changes: 0 additions & 23 deletions interface.go
Original file line number Diff line number Diff line change
@@ -1,33 +1,10 @@
package hcsshim

import (
"errors"
"io"
"time"
)

var (
// ErrInvalidNotificationType is an error encountered when an invalid notification type is used
ErrInvalidNotificationType = errors.New("hcsshim: invalid notification type")

// ErrTimeout is an error encountered when waiting on a notification times out
ErrTimeout = errors.New("hcsshim: timeout waiting for notification")

// ErrHandleClose is an error returned when the handle generating the notification being waited on has been closed
ErrHandleClose = errors.New("hcsshim: the handle generating this notification has been closed")

// ErrInvalidProcessState is an error encountered when the process is not in a valid state for the requested operation
ErrInvalidProcessState = errors.New("the process is in an invalid state for the attempted operation")

// ErrUnexpectedContainerExit is the error returned when a container exits while waiting for
// a different expected notification
ErrUnexpectedContainerExit = errors.New("unexpected container exit")

// ErrUnexpectedProcessAbort is the error returned when communication with the compute service
// is lost while waiting for a notification
ErrUnexpectedProcessAbort = errors.New("lost communication with compute service")
)

// ProcessConfig is used as both the input of Container.CreateProcess
// and to convert the parameters to JSON for passing onto the HCS
type ProcessConfig struct {
Expand Down
57 changes: 3 additions & 54 deletions process.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,14 @@ package hcsshim

import (
"encoding/json"
"errors"
"fmt"
"io"
"syscall"
"time"

"github.com/Sirupsen/logrus"
)

type ProcessError struct {
Process *process
Operation string
ExtraInfo string
Err error
}

// ContainerError is an error encountered in HCS
type process struct {
handle hcsProcess
processID int
Expand Down Expand Up @@ -48,7 +40,7 @@ type closeHandle struct {
}

type processStatus struct {
ProcessId uint32
ProcessID uint32
Exited bool
ExitCode uint32
LastWaitResult int32
Expand Down Expand Up @@ -223,7 +215,7 @@ func (process *process) properties() (*processStatus, error) {
}

if propertiesp == nil {
return nil, errors.New("Unexpected result from hcsGetProcessProperties, properties should never be nil")
return nil, ErrUnexpectedValue
}
propertiesRaw := convertAndFreeCoTaskMemBytes(propertiesp)

Expand Down Expand Up @@ -396,46 +388,3 @@ func (process *process) unregisterCallback() error {

return nil
}

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", e.Process.processID)

if e.Process.container != nil {
s += " in container " + e.Process.container.id
}

if e.Operation != "" {
s += " " + e.Operation
}

if e.Err != nil {
s += fmt.Sprintf(" failed in Win32: %s (0x%x)", e.Err, win32FromError(e.Err))
}

return s
}

func makeProcessError(process *process, operation string, extraInfo string, err error) error {
// Don't wrap errors created in hcsshim
if err == ErrTimeout ||
err == ErrUnexpectedProcessAbort ||
err == ErrUnexpectedContainerExit ||
err == ErrHandleClose ||
err == ErrInvalidProcessState ||
err == ErrInvalidNotificationType ||
err == ErrVmcomputeOperationPending {
return err
}

processError := &ProcessError{Process: process, Operation: operation, ExtraInfo: extraInfo, Err: err}
logrus.Error(processError)
return processError
}

0 comments on commit 5357233

Please sign in to comment.