Add rich errors to the API
Add a rich Error type to the libcontainer package and use it in the API so that callers can: * Check for a specific error without depending on an error string, * Obtain the stack trace of the function or method which detected the error. The Error type provides a typed error code and a stack trace. The error code identifies the error and enables the caller to test for it without being sensitive to changes in the error text. The stack trace identifies the point at which the error was detected. The combination of error code and stack trace will enable errors to be diagnosed much more easily and with less guesswork than when raw string-based errors are used. The Error type conforms to the error interface and its Error method prints a short error message. The Detail method provides a verbose error message including the stack trace. Notes: 1. There is an unfortunate precedent in the Go standard library which uses variables to define errors. Checking for a specific error involves a string comparison and assumes the corresponding variable has not been updated. It is more robust and efficient to identify errors with integer-based types and associated constants, although errors should still include a string description for ease of use by humans. 2. It is not feasible to assign distinct types to Factory and Container error codes because common errors such as SystemError cannot be declared in two places and the names of the error codes then need to be decorated. This is less readable. Signed-off-by: Steve Powell <spowell@pivotal.io>
This commit is contained in:
parent
318d845931
commit
582b25986d
51
container.go
51
container.go
|
@ -14,58 +14,65 @@ type Container interface {
|
|||
|
||||
// Returns the current run state of the container.
|
||||
//
|
||||
// Errors: container no longer exists,
|
||||
// system error.
|
||||
RunState() (*RunState, error)
|
||||
// Errors:
|
||||
// ContainerDestroyed - Container no longer exists,
|
||||
// SystemError - System error.
|
||||
RunState() (*RunState, Error)
|
||||
|
||||
// Returns the current config of the container.
|
||||
Config() *Config
|
||||
|
||||
// Start a process inside the container. Returns the PID of the new process (in the caller process's namespace) and a channel that will return the exit status of the process whenever it dies.
|
||||
//
|
||||
// Errors: container no longer exists,
|
||||
// config is invalid,
|
||||
// container is paused,
|
||||
// system error.
|
||||
Start(*ProcessConfig) (pid int, exitChan chan int, err error)
|
||||
// Errors:
|
||||
// ContainerDestroyed - Container no longer exists,
|
||||
// ProcessConfigInvalid - config is invalid,
|
||||
// ContainerPaused - Container is paused,
|
||||
// SystemError - System error.
|
||||
Start(config *ProcessConfig) (pid int, exitChan chan int, err Error)
|
||||
|
||||
// Destroys the container after killing all running processes.
|
||||
//
|
||||
// Any event registrations are removed before the container is destroyed.
|
||||
// No error is returned if the container is already destroyed.
|
||||
//
|
||||
// Errors: system error.
|
||||
Destroy() error
|
||||
// Errors:
|
||||
// SystemError - System error.
|
||||
Destroy() Error
|
||||
|
||||
// Returns the PIDs inside this container. The PIDs are in the namespace of the calling process.
|
||||
//
|
||||
// Errors: container no longer exists,
|
||||
// system error.
|
||||
// Errors:
|
||||
// ContainerDestroyed - Container no longer exists,
|
||||
// SystemError - System error.
|
||||
//
|
||||
// Some of the returned PIDs may no longer refer to processes in the Container, unless
|
||||
// the Container state is PAUSED in which case every PID in the slice is valid.
|
||||
Processes() ([]int, error)
|
||||
Processes() ([]int, Error)
|
||||
|
||||
// Returns statistics for the container.
|
||||
//
|
||||
// Errors: container no longer exists,
|
||||
// system error.
|
||||
Stats() (*ContainerStats, error)
|
||||
// Errors:
|
||||
// ContainerDestroyed - Container no longer exists,
|
||||
// SystemError - System error.
|
||||
Stats() (*ContainerStats, Error)
|
||||
|
||||
// If the Container state is RUNNING or PAUSING, sets the Container state to PAUSING and pauses
|
||||
// the execution of any user processes. Asynchronously, when the container finished being paused the
|
||||
// state is changed to PAUSED.
|
||||
// If the Container state is PAUSED, do nothing.
|
||||
//
|
||||
// Errors: container no longer exists,
|
||||
// system error.
|
||||
Pause() error
|
||||
// Errors:
|
||||
// ContainerDestroyed - Container no longer exists,
|
||||
// SystemError - System error.
|
||||
Pause() Error
|
||||
|
||||
// If the Container state is PAUSED, resumes the execution of any user processes in the
|
||||
// Container before setting the Container state to RUNNING.
|
||||
// If the Container state is RUNNING, do nothing.
|
||||
//
|
||||
// Errors: container no longer exists,
|
||||
// system error.
|
||||
Resume() error
|
||||
// Errors:
|
||||
// ContainerDestroyed - Container no longer exists,
|
||||
// SystemError - System error.
|
||||
Resume() Error
|
||||
}
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package libcontainer
|
||||
|
||||
// API error code type.
|
||||
type ErrorCode int
|
||||
|
||||
// API error codes.
|
||||
const (
|
||||
// Factory errors
|
||||
IdInUse ErrorCode = iota
|
||||
InvalidIdFormat
|
||||
ConfigInvalid
|
||||
// TODO: add Load errors
|
||||
|
||||
// Container errors
|
||||
ContainerDestroyed
|
||||
ProcessConfigInvalid
|
||||
ContainerPaused
|
||||
|
||||
// Common errors
|
||||
SystemError
|
||||
)
|
||||
|
||||
// API Error type.
|
||||
type Error interface {
|
||||
error
|
||||
|
||||
// Returns the stack trace, if any, which identifies the
|
||||
// point at which the error occurred.
|
||||
Stack() []byte
|
||||
|
||||
// Returns a verbose string including the error message
|
||||
// and a representation of the stack trace suitable for
|
||||
// printing.
|
||||
Detail() string
|
||||
|
||||
// Returns the error code for this error.
|
||||
Code() ErrorCode
|
||||
}
|
13
factory.go
13
factory.go
|
@ -12,13 +12,13 @@ type Factory interface {
|
|||
// Returns the new container with a running process.
|
||||
//
|
||||
// Errors:
|
||||
// id is already in use by a container
|
||||
// id has incorrect format
|
||||
// config is invalid
|
||||
// System error
|
||||
// IdInUse - id is already in use by a container
|
||||
// InvalidIdFormat - id has incorrect format
|
||||
// ConfigInvalid - config is invalid
|
||||
// SystemError - System error
|
||||
//
|
||||
// On error, any partially created container parts are cleaned up (the operation is atomic).
|
||||
Create(id string, config *Config) (Container, error)
|
||||
Create(id string, config *Config) (Container, Error)
|
||||
|
||||
// Load takes an ID for an existing container and reconstructs the container
|
||||
// from the state.
|
||||
|
@ -27,5 +27,6 @@ type Factory interface {
|
|||
// Path does not exist
|
||||
// Container is stopped
|
||||
// System error
|
||||
Load(id string) (Container, error)
|
||||
// TODO: fix description
|
||||
Load(id string) (Container, Error)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue