Преглед на файлове

Convert some "daemon" static error strings to the new errocode package format

Signed-off-by: Doug Davis <dug@us.ibm.com>
Doug Davis преди 9 години
родител
ревизия
f7d4b4fe2b

+ 471 - 0
api/errors/daemon.go

@@ -18,4 +18,475 @@ var (
 		Description:    "The specified container can not be found",
 		Description:    "The specified container can not be found",
 		HTTPStatusCode: http.StatusNotFound,
 		HTTPStatusCode: http.StatusNotFound,
 	})
 	})
+
+	// ErrorCodeUnregisteredContainer is generated when we try to load
+	// a storage driver for an unregistered container
+	ErrorCodeUnregisteredContainer = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "UNREGISTEREDCONTAINER",
+		Message:        "Can't load storage driver for unregistered container %s",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeContainerBeingRemoved is generated when an attempt to start
+	// a container is made but its in the process of being removed, or is dead.
+	ErrorCodeContainerBeingRemoved = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "CONTAINERBEINGREMOVED",
+		Message:        "Container is marked for removal and cannot be started.",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeUnpauseContainer is generated when we attempt to stop a
+	// container but its paused.
+	ErrorCodeUnpauseContainer = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "UNPAUSECONTAINER",
+		Message:        "Container %s is paused. Unpause the container before stopping",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeAlreadyPaused is generated when we attempt to pause a
+	// container when its already paused.
+	ErrorCodeAlreadyPaused = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "ALREADYPAUSED",
+		Message:        "Container %s is already paused",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeNotPaused is generated when we attempt to unpause a
+	// container when its not paused.
+	ErrorCodeNotPaused = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "NOTPAUSED",
+		Message:        "Container %s is not paused",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeImageUnregContainer is generated when we attempt to get the
+	// image of an unknown/unregistered container.
+	ErrorCodeImageUnregContainer = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "IMAGEUNREGCONTAINER",
+		Message:        "Can't get image of unregistered container",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeEmptyID is generated when an ID is the emptry string.
+	ErrorCodeEmptyID = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "EMPTYID",
+		Message:        "Invalid empty id",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeLoggingFactory is generated when we could not load the
+	// log driver.
+	ErrorCodeLoggingFactory = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "LOGGINGFACTORY",
+		Message:        "Failed to get logging factory: %v",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeInitLogger is generated when we could not initialize
+	// the logging driver.
+	ErrorCodeInitLogger = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "INITLOGGER",
+		Message:        "Failed to initialize logging driver: %v",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeNotRunning is generated when we need to verify that
+	// a container is running, but its not.
+	ErrorCodeNotRunning = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "NOTRUNNING",
+		Message:        "Container %s is not running",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeLinkNotRunning is generated when we try to link to a
+	// container that is not running.
+	ErrorCodeLinkNotRunning = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "LINKNOTRUNNING",
+		Message:        "Cannot link to a non running container: %s AS %s",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeDeviceInfo is generated when there is an error while trying
+	// to get info about a custom device.
+	// container that is not running.
+	ErrorCodeDeviceInfo = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "DEVICEINFO",
+		Message:        "error gathering device information while adding custom device %q: %s",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeEmptyEndpoint is generated when the endpoint for a port
+	// map is nil.
+	ErrorCodeEmptyEndpoint = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "EMPTYENDPOINT",
+		Message:        "invalid endpoint while building port map info",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeEmptyNetwork is generated when the networkSettings for a port
+	// map is nil.
+	ErrorCodeEmptyNetwork = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "EMPTYNETWORK",
+		Message:        "invalid networksettings while building port map info",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeParsingPort is generated when there is an error parsing
+	// a "port" string.
+	ErrorCodeParsingPort = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "PARSINGPORT",
+		Message:        "Error parsing Port value(%v):%v",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeNoSandbox is generated when we can't find the specified
+	// sandbox(network) by ID.
+	ErrorCodeNoSandbox = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "NOSANDBOX",
+		Message:        "error locating sandbox id %s: %v",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeNetworkUpdate is generated when there is an error while
+	// trying update a network/sandbox config.
+	ErrorCodeNetworkUpdate = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "NETWORKUPDATE",
+		Message:        "Update network failed: %v",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeNetworkRefresh is generated when there is an error while
+	// trying refresh a network/sandbox config.
+	ErrorCodeNetworkRefresh = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "NETWORKREFRESH",
+		Message:        "Update network failed: Failure in refresh sandbox %s: %v",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeHostPort is generated when there was an error while trying
+	// to parse a "host/por" string.
+	ErrorCodeHostPort = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "HOSTPORT",
+		Message:        "Error parsing HostPort value(%s):%v",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeNetworkConflict is generated when we try to public a service
+	// in network mode.
+	ErrorCodeNetworkConflict = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "NETWORKCONFLICT",
+		Message:        "conflicting options: publishing a service and network mode",
+		HTTPStatusCode: http.StatusConflict,
+	})
+
+	// ErrorCodeJoinInfo is generated when we failed to update a container's
+	// join info.
+	ErrorCodeJoinInfo = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "JOININFO",
+		Message:        "Updating join info failed: %v",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeIPCRunning is generated when we try to join a container's
+	// IPC but its running.
+	ErrorCodeIPCRunning = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "IPCRUNNING",
+		Message:        "cannot join IPC of a non running container: %s",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeNotADir is generated when we try to create a directory
+	// but the path isn't a dir.
+	ErrorCodeNotADir = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "NOTADIR",
+		Message:        "Cannot mkdir: %s is not a directory",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeParseContainer is generated when the reference to a
+	// container doesn't include a ":" (another container).
+	ErrorCodeParseContainer = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "PARSECONTAINER",
+		Message:        "no container specified to join network",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeJoinSelf is generated when we try to network to ourselves.
+	ErrorCodeJoinSelf = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "JOINSELF",
+		Message:        "cannot join own network",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeJoinRunning is generated when we try to network to ourselves.
+	ErrorCodeJoinRunning = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "JOINRUNNING",
+		Message:        "cannot join network of a non running container: %s",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeModeNotContainer is generated when we try to network to
+	// another container but the mode isn't 'container'.
+	ErrorCodeModeNotContainer = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "MODENOTCONTAINER",
+		Message:        "network mode not set to container",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeRemovingVolume is generated when we try remove a mount
+	// point (volume) but fail.
+	ErrorCodeRemovingVolume = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "REMOVINGVOLUME",
+		Message:        "Error removing volumes:\n%v",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeInvalidNetworkMode is generated when an invalid network
+	// mode value is specified.
+	ErrorCodeInvalidNetworkMode = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "INVALIDNETWORKMODE",
+		Message:        "invalid network mode: %s",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeGetGraph is generated when there was an error while
+	// trying to find a graph/image.
+	ErrorCodeGetGraph = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "GETGRAPH",
+		Message:        "Failed to graph.Get on ImageID %s - %s",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeGetLayer is generated when there was an error while
+	// trying to retrieve a particular layer of an image.
+	ErrorCodeGetLayer = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "GETLAYER",
+		Message:        "Failed to get layer path from graphdriver %s for ImageID %s - %s",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodePutLayer is generated when there was an error while
+	// trying to 'put' a particular layer of an image.
+	ErrorCodePutLayer = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "PUTLAYER",
+		Message:        "Failed to put layer path from graphdriver %s for ImageID %s - %s",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeGetLayerMetadata is generated when there was an error while
+	// trying to retrieve the metadata of a layer of an image.
+	ErrorCodeGetLayerMetadata = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "GETLAYERMETADATA",
+		Message:        "Failed to get layer metadata - %s",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeEmptyConfig is generated when the input config data
+	// is empty.
+	ErrorCodeEmptyConfig = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "EMPTYCONFIG",
+		Message:        "Config cannot be empty in order to create a container",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeNoSuchImageHash is generated when we can't find the
+	// specified image by its hash
+	ErrorCodeNoSuchImageHash = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "NOSUCHIMAGEHASH",
+		Message:        "No such image: %s",
+		HTTPStatusCode: http.StatusNotFound,
+	})
+
+	// ErrorCodeNoSuchImageTag is generated when we can't find the
+	// specified image byt its name/tag.
+	ErrorCodeNoSuchImageTag = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "NOSUCHIMAGETAG",
+		Message:        "No such image: %s:%s",
+		HTTPStatusCode: http.StatusNotFound,
+	})
+
+	// ErrorCodeMountOverFile is generated when we try to mount a volume
+	// over an existing file (but not a dir).
+	ErrorCodeMountOverFile = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "MOUNTOVERFILE",
+		Message:        "cannot mount volume over existing file, file exists %s",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeMountSetup is generated when we can't define a mount point
+	// due to the source and destination are defined.
+	ErrorCodeMountSetup = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "MOUNTSETUP",
+		Message:        "Unable to setup mount point, neither source nor volume defined",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeVolumeInvalidMode is generated when we the mode of a volume
+	// mount is invalid.
+	ErrorCodeVolumeInvalidMode = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "VOLUMEINVALIDMODE",
+		Message:        "invalid mode for volumes-from: %s",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeVolumeInvalid is generated when the format fo the
+	// volume specification isn't valid.
+	ErrorCodeVolumeInvalid = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "VOLUMEINVALID",
+		Message:        "Invalid volume specification: %s",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeVolumeAbs is generated when path to a volume isn't absolute.
+	ErrorCodeVolumeAbs = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "VOLUMEABS",
+		Message:        "Invalid volume destination path: %s mount path must be absolute.",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeVolumeFromBlank is generated when path to a volume is blank.
+	ErrorCodeVolumeFromBlank = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "VOLUMEFROMBLANK",
+		Message:        "malformed volumes-from specification: %s",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeVolumeMode is generated when 'mode' for a volume
+	// isn't a valid.
+	ErrorCodeVolumeMode = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "VOLUMEMODE",
+		Message:        "invalid mode for volumes-from: %s",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeVolumeDup is generated when we try to mount two volumes
+	// to the same path.
+	ErrorCodeVolumeDup = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "VOLUMEDUP",
+		Message:        "Duplicate bind mount %s",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeCantUnpause is generated when there's an error while trying
+	// to unpause a container.
+	ErrorCodeCantUnpause = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "CANTUNPAUSE",
+		Message:        "Cannot unpause container %s: %s",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodePSError is generated when trying to run 'ps'.
+	ErrorCodePSError = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "PSError",
+		Message:        "Error running ps: %s",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeNoPID is generated when looking for the PID field in the
+	// ps output.
+	ErrorCodeNoPID = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "NOPID",
+		Message:        "Couldn't find PID field in ps output",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeBadPID is generated when we can't convert a PID to an int.
+	ErrorCodeBadPID = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "BADPID",
+		Message:        "Unexpected pid '%s': %s",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeNoTop is generated when we try to run 'top' but can't
+	// because we're on windows.
+	ErrorCodeNoTop = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "NOTOP",
+		Message:        "Top is not supported on Windows",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeStopped is generated when we try to stop a container
+	// that is already stopped.
+	ErrorCodeStopped = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "STOPPED",
+		Message:        "Container already stopped",
+		HTTPStatusCode: http.StatusNotModified,
+	})
+
+	// ErrorCodeCantStop is generated when we try to stop a container
+	// but failed for some reason.
+	ErrorCodeCantStop = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "CANTSTOP",
+		Message:        "Cannot stop container %s: %s\n",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeBadCPUFields is generated the number of CPU fields is
+	// less than 8.
+	ErrorCodeBadCPUFields = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "BADCPUFIELDS",
+		Message:        "invalid number of cpu fields",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeBadCPUInt is generated the CPU field can't be parsed as an int.
+	ErrorCodeBadCPUInt = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "BADCPUINT",
+		Message:        "Unable to convert value %s to int: %s",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeBadStatFormat is generated the output of the stat info
+	// isn't parseable.
+	ErrorCodeBadStatFormat = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "BADSTATFORMAT",
+		Message:        "invalid stat format",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeTimedOut is generated when a timer expires.
+	ErrorCodeTimedOut = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "TIMEDOUT",
+		Message:        "Timed out: %v",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeAlreadyRemoving is generated when we try to remove a
+	// container that is already being removed.
+	ErrorCodeAlreadyRemoving = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "ALREADYREMOVING",
+		Message:        "Status is already RemovalInProgress",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeStartPaused is generated when we start a paused container.
+	ErrorCodeStartPaused = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "STARTPAUSED",
+		Message:        "Cannot start a paused container, try unpause instead.",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeAlreadyStarted is generated when we try to start a container
+	// that is already running.
+	ErrorCodeAlreadyStarted = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "ALREADYSTARTED",
+		Message:        "Container already started",
+		HTTPStatusCode: http.StatusNotModified,
+	})
+
+	// ErrorCodeHostConfigStart is generated when a HostConfig is passed
+	// into the start command.
+	ErrorCodeHostConfigStart = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "HOSTCONFIGSTART",
+		Message:        "Supplying a hostconfig on start is not supported. It should be supplied on create",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
+
+	// ErrorCodeCantStart is generated when an error occurred while
+	// trying to start a container.
+	ErrorCodeCantStart = errcode.Register(errGroup, errcode.ErrorDescriptor{
+		Value:          "CANTSTART",
+		Message:        "Cannot start container %s: %s",
+		HTTPStatusCode: http.StatusInternalServerError,
+	})
 )
 )

+ 7 - 10
api/server/container.go

@@ -12,12 +12,15 @@ import (
 	"golang.org/x/net/websocket"
 	"golang.org/x/net/websocket"
 
 
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
+	"github.com/docker/distribution/registry/api/errcode"
+	derr "github.com/docker/docker/api/errors"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/context"
 	"github.com/docker/docker/context"
 	"github.com/docker/docker/daemon"
 	"github.com/docker/docker/daemon"
 	"github.com/docker/docker/pkg/ioutils"
 	"github.com/docker/docker/pkg/ioutils"
 	"github.com/docker/docker/pkg/signal"
 	"github.com/docker/docker/pkg/signal"
 	"github.com/docker/docker/runconfig"
 	"github.com/docker/docker/runconfig"
+	"github.com/docker/docker/utils"
 )
 )
 
 
 func (s *Server) getContainersJSON(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
 func (s *Server) getContainersJSON(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
@@ -144,7 +147,7 @@ func (s *Server) getContainersLogs(ctx context.Context, w http.ResponseWriter, r
 		// The client may be expecting all of the data we're sending to
 		// The client may be expecting all of the data we're sending to
 		// be multiplexed, so send it through OutStream, which will
 		// be multiplexed, so send it through OutStream, which will
 		// have been set up to handle that if needed.
 		// have been set up to handle that if needed.
-		fmt.Fprintf(logsConfig.OutStream, "Error running logs job: %s\n", err)
+		fmt.Fprintf(logsConfig.OutStream, "Error running logs job: %s\n", utils.GetErrorMessage(err))
 	}
 	}
 
 
 	return nil
 	return nil
@@ -184,10 +187,6 @@ func (s *Server) postContainersStart(ctx context.Context, w http.ResponseWriter,
 	}
 	}
 
 
 	if err := s.daemon.ContainerStart(vars["name"], hostConfig); err != nil {
 	if err := s.daemon.ContainerStart(vars["name"], hostConfig); err != nil {
-		if err.Error() == "Container already started" {
-			w.WriteHeader(http.StatusNotModified)
-			return nil
-		}
 		return err
 		return err
 	}
 	}
 	w.WriteHeader(http.StatusNoContent)
 	w.WriteHeader(http.StatusNoContent)
@@ -205,10 +204,6 @@ func (s *Server) postContainersStop(ctx context.Context, w http.ResponseWriter,
 	seconds, _ := strconv.Atoi(r.Form.Get("t"))
 	seconds, _ := strconv.Atoi(r.Form.Get("t"))
 
 
 	if err := s.daemon.ContainerStop(vars["name"], seconds); err != nil {
 	if err := s.daemon.ContainerStop(vars["name"], seconds); err != nil {
-		if err.Error() == "Container already stopped" {
-			w.WriteHeader(http.StatusNotModified)
-			return nil
-		}
 		return err
 		return err
 	}
 	}
 	w.WriteHeader(http.StatusNoContent)
 	w.WriteHeader(http.StatusNoContent)
@@ -236,7 +231,9 @@ func (s *Server) postContainersKill(ctx context.Context, w http.ResponseWriter,
 	}
 	}
 
 
 	if err := s.daemon.ContainerKill(name, uint64(sig)); err != nil {
 	if err := s.daemon.ContainerKill(name, uint64(sig)); err != nil {
-		_, isStopped := err.(daemon.ErrContainerNotRunning)
+		theErr, isDerr := err.(errcode.ErrorCoder)
+		isStopped := isDerr && theErr.ErrorCode() == derr.ErrorCodeNotRunning
+
 		// Return error that's not caused because the container is stopped.
 		// Return error that's not caused because the container is stopped.
 		// Return error if the container is not running and the api is >= 1.20
 		// Return error if the container is not running and the api is >= 1.20
 		// to keep backwards compatibility.
 		// to keep backwards compatibility.

+ 15 - 23
daemon/container.go

@@ -15,6 +15,7 @@ import (
 	"github.com/opencontainers/runc/libcontainer/label"
 	"github.com/opencontainers/runc/libcontainer/label"
 
 
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
+	derr "github.com/docker/docker/api/errors"
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/daemon/logger"
 	"github.com/docker/docker/daemon/logger"
 	"github.com/docker/docker/daemon/logger/jsonfilelog"
 	"github.com/docker/docker/daemon/logger/jsonfilelog"
@@ -39,15 +40,6 @@ var (
 	ErrRootFSReadOnly = errors.New("container rootfs is marked read-only")
 	ErrRootFSReadOnly = errors.New("container rootfs is marked read-only")
 )
 )
 
 
-// ErrContainerNotRunning holds the id of the container that is not running.
-type ErrContainerNotRunning struct {
-	id string
-}
-
-func (e ErrContainerNotRunning) Error() string {
-	return fmt.Sprintf("Container %s is not running", e.id)
-}
-
 type streamConfig struct {
 type streamConfig struct {
 	stdout    *broadcastwriter.BroadcastWriter
 	stdout    *broadcastwriter.BroadcastWriter
 	stderr    *broadcastwriter.BroadcastWriter
 	stderr    *broadcastwriter.BroadcastWriter
@@ -229,7 +221,7 @@ func (container *Container) getRootResourcePath(path string) (string, error) {
 
 
 func (container *Container) exportContainerRw() (archive.Archive, error) {
 func (container *Container) exportContainerRw() (archive.Archive, error) {
 	if container.daemon == nil {
 	if container.daemon == nil {
-		return nil, fmt.Errorf("Can't load storage driver for unregistered container %s", container.ID)
+		return nil, derr.ErrorCodeUnregisteredContainer.WithArgs(container.ID)
 	}
 	}
 	archive, err := container.daemon.diff(container)
 	archive, err := container.daemon.diff(container)
 	if err != nil {
 	if err != nil {
@@ -255,7 +247,7 @@ func (container *Container) Start() (err error) {
 	}
 	}
 
 
 	if container.removalInProgress || container.Dead {
 	if container.removalInProgress || container.Dead {
-		return fmt.Errorf("Container is marked for removal and cannot be started.")
+		return derr.ErrorCodeContainerBeingRemoved
 	}
 	}
 
 
 	// if we encounter an error during start we need to ensure that any other
 	// if we encounter an error during start we need to ensure that any other
@@ -381,11 +373,11 @@ func (container *Container) killSig(sig int) error {
 
 
 	// We could unpause the container for them rather than returning this error
 	// We could unpause the container for them rather than returning this error
 	if container.Paused {
 	if container.Paused {
-		return fmt.Errorf("Container %s is paused. Unpause the container before stopping", container.ID)
+		return derr.ErrorCodeUnpauseContainer.WithArgs(container.ID)
 	}
 	}
 
 
 	if !container.Running {
 	if !container.Running {
-		return ErrContainerNotRunning{container.ID}
+		return derr.ErrorCodeNotRunning.WithArgs(container.ID)
 	}
 	}
 
 
 	// signal to the monitor that it should not restart the container
 	// signal to the monitor that it should not restart the container
@@ -422,12 +414,12 @@ func (container *Container) pause() error {
 
 
 	// We cannot Pause the container which is not running
 	// We cannot Pause the container which is not running
 	if !container.Running {
 	if !container.Running {
-		return ErrContainerNotRunning{container.ID}
+		return derr.ErrorCodeNotRunning.WithArgs(container.ID)
 	}
 	}
 
 
 	// We cannot Pause the container which is already paused
 	// We cannot Pause the container which is already paused
 	if container.Paused {
 	if container.Paused {
-		return fmt.Errorf("Container %s is already paused", container.ID)
+		return derr.ErrorCodeAlreadyPaused.WithArgs(container.ID)
 	}
 	}
 
 
 	if err := container.daemon.execDriver.Pause(container.command); err != nil {
 	if err := container.daemon.execDriver.Pause(container.command); err != nil {
@@ -444,12 +436,12 @@ func (container *Container) unpause() error {
 
 
 	// We cannot unpause the container which is not running
 	// We cannot unpause the container which is not running
 	if !container.Running {
 	if !container.Running {
-		return ErrContainerNotRunning{container.ID}
+		return derr.ErrorCodeNotRunning.WithArgs(container.ID)
 	}
 	}
 
 
 	// We cannot unpause the container which is not paused
 	// We cannot unpause the container which is not paused
 	if !container.Paused {
 	if !container.Paused {
-		return fmt.Errorf("Container %s is not paused", container.ID)
+		return derr.ErrorCodeNotPaused.WithArgs(container.ID)
 	}
 	}
 
 
 	if err := container.daemon.execDriver.Unpause(container.command); err != nil {
 	if err := container.daemon.execDriver.Unpause(container.command); err != nil {
@@ -463,7 +455,7 @@ func (container *Container) unpause() error {
 // Kill forcefully terminates a container.
 // Kill forcefully terminates a container.
 func (container *Container) Kill() error {
 func (container *Container) Kill() error {
 	if !container.IsRunning() {
 	if !container.IsRunning() {
-		return ErrContainerNotRunning{container.ID}
+		return derr.ErrorCodeNotRunning.WithArgs(container.ID)
 	}
 	}
 
 
 	// 1. Send SIGKILL
 	// 1. Send SIGKILL
@@ -556,7 +548,7 @@ func (container *Container) Restart(seconds int) error {
 // to the given height and width. The container must be running.
 // to the given height and width. The container must be running.
 func (container *Container) Resize(h, w int) error {
 func (container *Container) Resize(h, w int) error {
 	if !container.IsRunning() {
 	if !container.IsRunning() {
-		return ErrContainerNotRunning{container.ID}
+		return derr.ErrorCodeNotRunning.WithArgs(container.ID)
 	}
 	}
 	if err := container.command.ProcessConfig.Terminal.Resize(h, w); err != nil {
 	if err := container.command.ProcessConfig.Terminal.Resize(h, w); err != nil {
 		return err
 		return err
@@ -597,7 +589,7 @@ func (container *Container) changes() ([]archive.Change, error) {
 
 
 func (container *Container) getImage() (*image.Image, error) {
 func (container *Container) getImage() (*image.Image, error) {
 	if container.daemon == nil {
 	if container.daemon == nil {
-		return nil, fmt.Errorf("Can't get image of unregistered container")
+		return nil, derr.ErrorCodeImageUnregContainer
 	}
 	}
 	return container.daemon.graph.Get(container.ImageID)
 	return container.daemon.graph.Get(container.ImageID)
 }
 }
@@ -624,7 +616,7 @@ func (container *Container) rootfsPath() string {
 
 
 func validateID(id string) error {
 func validateID(id string) error {
 	if id == "" {
 	if id == "" {
-		return fmt.Errorf("Invalid empty id")
+		return derr.ErrorCodeEmptyID
 	}
 	}
 	return nil
 	return nil
 }
 }
@@ -722,7 +714,7 @@ func (container *Container) getLogger() (logger.Logger, error) {
 	}
 	}
 	c, err := logger.GetLogDriver(cfg.Type)
 	c, err := logger.GetLogDriver(cfg.Type)
 	if err != nil {
 	if err != nil {
-		return nil, fmt.Errorf("Failed to get logging factory: %v", err)
+		return nil, derr.ErrorCodeLoggingFactory.WithArgs(err)
 	}
 	}
 	ctx := logger.Context{
 	ctx := logger.Context{
 		Config:              cfg.Config,
 		Config:              cfg.Config,
@@ -753,7 +745,7 @@ func (container *Container) startLogging() error {
 
 
 	l, err := container.getLogger()
 	l, err := container.getLogger()
 	if err != nil {
 	if err != nil {
-		return fmt.Errorf("Failed to initialize logging driver: %v", err)
+		return derr.ErrorCodeInitLogger.WithArgs(err)
 	}
 	}
 
 
 	copier := logger.NewCopier(container.ID, map[string]io.Reader{"stdout": container.StdoutPipe(), "stderr": container.StderrPipe()}, l)
 	copier := logger.NewCopier(container.ID, map[string]io.Reader{"stdout": container.StdoutPipe(), "stderr": container.StderrPipe()}, l)

+ 21 - 20
daemon/container_unix.go

@@ -15,6 +15,7 @@ import (
 	"time"
 	"time"
 
 
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
+	derr "github.com/docker/docker/api/errors"
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/daemon/links"
 	"github.com/docker/docker/daemon/links"
 	"github.com/docker/docker/daemon/network"
 	"github.com/docker/docker/daemon/network"
@@ -86,7 +87,7 @@ func (container *Container) setupLinkedContainers() ([]string, error) {
 	if len(children) > 0 {
 	if len(children) > 0 {
 		for linkAlias, child := range children {
 		for linkAlias, child := range children {
 			if !child.IsRunning() {
 			if !child.IsRunning() {
-				return nil, fmt.Errorf("Cannot link to a non running container: %s AS %s", child.Name, linkAlias)
+				return nil, derr.ErrorCodeLinkNotRunning.WithArgs(child.Name, linkAlias)
 			}
 			}
 
 
 			link := links.NewLink(
 			link := links.NewLink(
@@ -168,7 +169,7 @@ func getDevicesFromPath(deviceMapping runconfig.DeviceMapping) (devs []*configs.
 		return devs, nil
 		return devs, nil
 	}
 	}
 
 
-	return devs, fmt.Errorf("error gathering device information while adding custom device %q: %s", deviceMapping.PathOnHost, err)
+	return devs, derr.ErrorCodeDeviceInfo.WithArgs(deviceMapping.PathOnHost, err)
 }
 }
 
 
 func populateCommand(c *Container, env []string) error {
 func populateCommand(c *Container, env []string) error {
@@ -511,11 +512,11 @@ func (container *Container) buildSandboxOptions() ([]libnetwork.SandboxOption, e
 
 
 func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) {
 func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) {
 	if ep == nil {
 	if ep == nil {
-		return nil, fmt.Errorf("invalid endpoint while building port map info")
+		return nil, derr.ErrorCodeEmptyEndpoint
 	}
 	}
 
 
 	if networkSettings == nil {
 	if networkSettings == nil {
-		return nil, fmt.Errorf("invalid networksettings while building port map info")
+		return nil, derr.ErrorCodeEmptyNetwork
 	}
 	}
 
 
 	driverInfo, err := ep.DriverInfo()
 	driverInfo, err := ep.DriverInfo()
@@ -539,7 +540,7 @@ func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint, networkSett
 			for _, tp := range exposedPorts {
 			for _, tp := range exposedPorts {
 				natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port)))
 				natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port)))
 				if err != nil {
 				if err != nil {
-					return nil, fmt.Errorf("Error parsing Port value(%v):%v", tp.Port, err)
+					return nil, derr.ErrorCodeParsingPort.WithArgs(tp.Port, err)
 				}
 				}
 				networkSettings.Ports[natPort] = nil
 				networkSettings.Ports[natPort] = nil
 			}
 			}
@@ -567,11 +568,11 @@ func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint, networkSett
 
 
 func (container *Container) buildEndpointInfo(ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) {
 func (container *Container) buildEndpointInfo(ep libnetwork.Endpoint, networkSettings *network.Settings) (*network.Settings, error) {
 	if ep == nil {
 	if ep == nil {
-		return nil, fmt.Errorf("invalid endpoint while building port map info")
+		return nil, derr.ErrorCodeEmptyEndpoint
 	}
 	}
 
 
 	if networkSettings == nil {
 	if networkSettings == nil {
-		return nil, fmt.Errorf("invalid networksettings while building port map info")
+		return nil, derr.ErrorCodeEmptyNetwork
 	}
 	}
 
 
 	epInfo := ep.Info()
 	epInfo := ep.Info()
@@ -648,16 +649,16 @@ func (container *Container) updateNetwork() error {
 
 
 	sb, err := ctrl.SandboxByID(sid)
 	sb, err := ctrl.SandboxByID(sid)
 	if err != nil {
 	if err != nil {
-		return fmt.Errorf("error locating sandbox id %s: %v", sid, err)
+		return derr.ErrorCodeNoSandbox.WithArgs(sid, err)
 	}
 	}
 
 
 	options, err := container.buildSandboxOptions()
 	options, err := container.buildSandboxOptions()
 	if err != nil {
 	if err != nil {
-		return fmt.Errorf("Update network failed: %v", err)
+		return derr.ErrorCodeNetworkUpdate.WithArgs(err)
 	}
 	}
 
 
 	if err := sb.Refresh(options...); err != nil {
 	if err := sb.Refresh(options...); err != nil {
-		return fmt.Errorf("Update network failed: Failure in refresh sandbox %s: %v", sid, err)
+		return derr.ErrorCodeNetworkRefresh.WithArgs(sid, err)
 	}
 	}
 
 
 	return nil
 	return nil
@@ -711,7 +712,7 @@ func (container *Container) buildCreateEndpointOptions() ([]libnetwork.EndpointO
 				portStart, portEnd, err = newP.Range()
 				portStart, portEnd, err = newP.Range()
 			}
 			}
 			if err != nil {
 			if err != nil {
-				return nil, fmt.Errorf("Error parsing HostPort value(%s):%v", binding[i].HostPort, err)
+				return nil, derr.ErrorCodeHostPort.WithArgs(binding[i].HostPort, err)
 			}
 			}
 			pbCopy.HostPort = uint16(portStart)
 			pbCopy.HostPort = uint16(portStart)
 			pbCopy.HostPortEnd = uint16(portEnd)
 			pbCopy.HostPortEnd = uint16(portEnd)
@@ -812,7 +813,7 @@ func (container *Container) allocateNetwork() error {
 			networkDriver = controller.Config().Daemon.DefaultDriver
 			networkDriver = controller.Config().Daemon.DefaultDriver
 		}
 		}
 	} else if service != "" {
 	} else if service != "" {
-		return fmt.Errorf("conflicting options: publishing a service and network mode")
+		return derr.ErrorCodeNetworkConflict
 	}
 	}
 
 
 	if runconfig.NetworkMode(networkDriver).IsBridge() && container.daemon.configStore.DisableBridge {
 	if runconfig.NetworkMode(networkDriver).IsBridge() && container.daemon.configStore.DisableBridge {
@@ -903,7 +904,7 @@ func (container *Container) configureNetwork(networkName, service, networkDriver
 	}
 	}
 
 
 	if err := container.updateJoinInfo(ep); err != nil {
 	if err := container.updateJoinInfo(ep); err != nil {
-		return fmt.Errorf("Updating join info failed: %v", err)
+		return derr.ErrorCodeJoinInfo.WithArgs(err)
 	}
 	}
 
 
 	return nil
 	return nil
@@ -954,7 +955,7 @@ func (container *Container) getIpcContainer() (*Container, error) {
 		return nil, err
 		return nil, err
 	}
 	}
 	if !c.IsRunning() {
 	if !c.IsRunning() {
-		return nil, fmt.Errorf("cannot join IPC of a non running container: %s", containerID)
+		return nil, derr.ErrorCodeIPCRunning
 	}
 	}
 	return c, nil
 	return c, nil
 }
 }
@@ -979,7 +980,7 @@ func (container *Container) setupWorkingDirectory() error {
 			}
 			}
 		}
 		}
 		if pthInfo != nil && !pthInfo.IsDir() {
 		if pthInfo != nil && !pthInfo.IsDir() {
-			return fmt.Errorf("Cannot mkdir: %s is not a directory", container.Config.WorkingDir)
+			return derr.ErrorCodeNotADir.WithArgs(container.Config.WorkingDir)
 		}
 		}
 	}
 	}
 	return nil
 	return nil
@@ -990,21 +991,21 @@ func (container *Container) getNetworkedContainer() (*Container, error) {
 	switch parts[0] {
 	switch parts[0] {
 	case "container":
 	case "container":
 		if len(parts) != 2 {
 		if len(parts) != 2 {
-			return nil, fmt.Errorf("no container specified to join network")
+			return nil, derr.ErrorCodeParseContainer
 		}
 		}
 		nc, err := container.daemon.Get(parts[1])
 		nc, err := container.daemon.Get(parts[1])
 		if err != nil {
 		if err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
 		if container == nc {
 		if container == nc {
-			return nil, fmt.Errorf("cannot join own network")
+			return nil, derr.ErrorCodeJoinSelf
 		}
 		}
 		if !nc.IsRunning() {
 		if !nc.IsRunning() {
-			return nil, fmt.Errorf("cannot join network of a non running container: %s", parts[1])
+			return nil, derr.ErrorCodeJoinRunning.WithArgs(parts[1])
 		}
 		}
 		return nc, nil
 		return nc, nil
 	default:
 	default:
-		return nil, fmt.Errorf("network mode not set to container")
+		return nil, derr.ErrorCodeModeNotContainer
 	}
 	}
 }
 }
 
 
@@ -1200,7 +1201,7 @@ func (container *Container) removeMountPoints(rm bool) error {
 		}
 		}
 	}
 	}
 	if len(rmErrors) > 0 {
 	if len(rmErrors) > 0 {
-		return fmt.Errorf("Error removing volumes:\n%v", strings.Join(rmErrors, "\n"))
+		return derr.ErrorCodeRemovingVolume.WithArgs(strings.Join(rmErrors, "\n"))
 	}
 	}
 	return nil
 	return nil
 }
 }

+ 6 - 6
daemon/container_windows.go

@@ -3,9 +3,9 @@
 package daemon
 package daemon
 
 
 import (
 import (
-	"fmt"
 	"strings"
 	"strings"
 
 
+	derr "github.com/docker/docker/api/errors"
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/daemon/execdriver"
 )
 )
 
 
@@ -64,7 +64,7 @@ func populateCommand(c *Container, env []string) error {
 			}
 			}
 		}
 		}
 	default:
 	default:
-		return fmt.Errorf("invalid network mode: %s", c.hostConfig.NetworkMode)
+		return derr.ErrorCodeInvalidNetworkMode.WithArgs(c.hostConfig.NetworkMode)
 	}
 	}
 
 
 	pid := &execdriver.Pid{}
 	pid := &execdriver.Pid{}
@@ -90,22 +90,22 @@ func populateCommand(c *Container, env []string) error {
 	var layerPaths []string
 	var layerPaths []string
 	img, err := c.daemon.graph.Get(c.ImageID)
 	img, err := c.daemon.graph.Get(c.ImageID)
 	if err != nil {
 	if err != nil {
-		return fmt.Errorf("Failed to graph.Get on ImageID %s - %s", c.ImageID, err)
+		return derr.ErrorCodeGetGraph.WithArgs(c.ImageID, err)
 	}
 	}
 	for i := img; i != nil && err == nil; i, err = c.daemon.graph.GetParent(i) {
 	for i := img; i != nil && err == nil; i, err = c.daemon.graph.GetParent(i) {
 		lp, err := c.daemon.driver.Get(i.ID, "")
 		lp, err := c.daemon.driver.Get(i.ID, "")
 		if err != nil {
 		if err != nil {
-			return fmt.Errorf("Failed to get layer path from graphdriver %s for ImageID %s - %s", c.daemon.driver.String(), i.ID, err)
+			return derr.ErrorCodeGetLayer.WithArgs(c.daemon.driver.String(), i.ID, err)
 		}
 		}
 		layerPaths = append(layerPaths, lp)
 		layerPaths = append(layerPaths, lp)
 		err = c.daemon.driver.Put(i.ID)
 		err = c.daemon.driver.Put(i.ID)
 		if err != nil {
 		if err != nil {
-			return fmt.Errorf("Failed to put layer path from graphdriver %s for ImageID %s - %s", c.daemon.driver.String(), i.ID, err)
+			return derr.ErrorCodePutLayer.WithArgs(c.daemon.driver.String(), i.ID, err)
 		}
 		}
 	}
 	}
 	m, err := c.daemon.driver.GetMetadata(c.ID)
 	m, err := c.daemon.driver.GetMetadata(c.ID)
 	if err != nil {
 	if err != nil {
-		return fmt.Errorf("Failed to get layer metadata - %s", err)
+		return derr.ErrorCodeGetLayerMetadata.WithArgs(err)
 	}
 	}
 	layerFolder := m["dir"]
 	layerFolder := m["dir"]
 
 

+ 4 - 4
daemon/create.go

@@ -1,10 +1,10 @@
 package daemon
 package daemon
 
 
 import (
 import (
-	"fmt"
 	"strings"
 	"strings"
 
 
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
+	derr "github.com/docker/docker/api/errors"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/graph/tags"
 	"github.com/docker/docker/graph/tags"
 	"github.com/docker/docker/image"
 	"github.com/docker/docker/image"
@@ -17,7 +17,7 @@ import (
 // ContainerCreate takes configs and creates a container.
 // ContainerCreate takes configs and creates a container.
 func (daemon *Daemon) ContainerCreate(name string, config *runconfig.Config, hostConfig *runconfig.HostConfig, adjustCPUShares bool) (*Container, []string, error) {
 func (daemon *Daemon) ContainerCreate(name string, config *runconfig.Config, hostConfig *runconfig.HostConfig, adjustCPUShares bool) (*Container, []string, error) {
 	if config == nil {
 	if config == nil {
-		return nil, nil, fmt.Errorf("Config cannot be empty in order to create a container")
+		return nil, nil, derr.ErrorCodeEmptyConfig
 	}
 	}
 
 
 	warnings, err := daemon.verifyContainerSettings(hostConfig, config)
 	warnings, err := daemon.verifyContainerSettings(hostConfig, config)
@@ -31,13 +31,13 @@ func (daemon *Daemon) ContainerCreate(name string, config *runconfig.Config, hos
 	if err != nil {
 	if err != nil {
 		if daemon.Graph().IsNotExist(err, config.Image) {
 		if daemon.Graph().IsNotExist(err, config.Image) {
 			if strings.Contains(config.Image, "@") {
 			if strings.Contains(config.Image, "@") {
-				return nil, warnings, fmt.Errorf("No such image: %s", config.Image)
+				return nil, warnings, derr.ErrorCodeNoSuchImageHash.WithArgs(config.Image)
 			}
 			}
 			img, tag := parsers.ParseRepositoryTag(config.Image)
 			img, tag := parsers.ParseRepositoryTag(config.Image)
 			if tag == "" {
 			if tag == "" {
 				tag = tags.DefaultTag
 				tag = tags.DefaultTag
 			}
 			}
-			return nil, warnings, fmt.Errorf("No such image: %s:%s", img, tag)
+			return nil, warnings, derr.ErrorCodeNoSuchImageTag.WithArgs(img, tag)
 		}
 		}
 		return nil, warnings, err
 		return nil, warnings, err
 	}
 	}

+ 2 - 2
daemon/create_unix.go

@@ -3,11 +3,11 @@
 package daemon
 package daemon
 
 
 import (
 import (
-	"fmt"
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
 	"strings"
 	"strings"
 
 
+	derr "github.com/docker/docker/api/errors"
 	"github.com/docker/docker/image"
 	"github.com/docker/docker/image"
 	"github.com/docker/docker/pkg/stringid"
 	"github.com/docker/docker/pkg/stringid"
 	"github.com/docker/docker/runconfig"
 	"github.com/docker/docker/runconfig"
@@ -41,7 +41,7 @@ func createContainerPlatformSpecificSettings(container *Container, config *runco
 
 
 		stat, err := os.Stat(path)
 		stat, err := os.Stat(path)
 		if err == nil && !stat.IsDir() {
 		if err == nil && !stat.IsDir() {
-			return fmt.Errorf("cannot mount volume over existing file, file exists %s", path)
+			return derr.ErrorCodeMountOverFile.WithArgs(path)
 		}
 		}
 
 
 		volumeDriver := hostConfig.VolumeDriver
 		volumeDriver := hostConfig.VolumeDriver

+ 6 - 5
daemon/start.go

@@ -1,10 +1,11 @@
 package daemon
 package daemon
 
 
 import (
 import (
-	"fmt"
 	"runtime"
 	"runtime"
 
 
+	derr "github.com/docker/docker/api/errors"
 	"github.com/docker/docker/runconfig"
 	"github.com/docker/docker/runconfig"
+	"github.com/docker/docker/utils"
 )
 )
 
 
 // ContainerStart starts a container.
 // ContainerStart starts a container.
@@ -15,11 +16,11 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *runconfig.HostConf
 	}
 	}
 
 
 	if container.isPaused() {
 	if container.isPaused() {
-		return fmt.Errorf("Cannot start a paused container, try unpause instead.")
+		return derr.ErrorCodeStartPaused
 	}
 	}
 
 
 	if container.IsRunning() {
 	if container.IsRunning() {
-		return fmt.Errorf("Container already started")
+		return derr.ErrorCodeAlreadyStarted
 	}
 	}
 
 
 	// Windows does not have the backwards compatibility issue here.
 	// Windows does not have the backwards compatibility issue here.
@@ -33,7 +34,7 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *runconfig.HostConf
 		}
 		}
 	} else {
 	} else {
 		if hostConfig != nil {
 		if hostConfig != nil {
-			return fmt.Errorf("Supplying a hostconfig on start is not supported. It should be supplied on create")
+			return derr.ErrorCodeHostConfigStart
 		}
 		}
 	}
 	}
 
 
@@ -44,7 +45,7 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *runconfig.HostConf
 	}
 	}
 
 
 	if err := container.Start(); err != nil {
 	if err := container.Start(); err != nil {
-		return fmt.Errorf("Cannot start container %s: %s", name, err)
+		return derr.ErrorCodeCantStart.WithArgs(name, utils.GetErrorMessage(err))
 	}
 	}
 
 
 	return nil
 	return nil

+ 3 - 2
daemon/state.go

@@ -5,6 +5,7 @@ import (
 	"sync"
 	"sync"
 	"time"
 	"time"
 
 
+	derr "github.com/docker/docker/api/errors"
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/pkg/units"
 	"github.com/docker/docker/pkg/units"
 )
 )
@@ -111,7 +112,7 @@ func wait(waitChan <-chan struct{}, timeout time.Duration) error {
 	}
 	}
 	select {
 	select {
 	case <-time.After(timeout):
 	case <-time.After(timeout):
-		return fmt.Errorf("Timed out: %v", timeout)
+		return derr.ErrorCodeTimedOut.WithArgs(timeout)
 	case <-waitChan:
 	case <-waitChan:
 		return nil
 		return nil
 	}
 	}
@@ -251,7 +252,7 @@ func (s *State) setRemovalInProgress() error {
 	s.Lock()
 	s.Lock()
 	defer s.Unlock()
 	defer s.Unlock()
 	if s.removalInProgress {
 	if s.removalInProgress {
-		return fmt.Errorf("Status is already RemovalInProgress")
+		return derr.ErrorCodeAlreadyRemoving
 	}
 	}
 	s.removalInProgress = true
 	s.removalInProgress = true
 	return nil
 	return nil

+ 4 - 4
daemon/stats_collector_unix.go

@@ -4,7 +4,6 @@ package daemon
 
 
 import (
 import (
 	"bufio"
 	"bufio"
-	"fmt"
 	"os"
 	"os"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
@@ -12,6 +11,7 @@ import (
 	"time"
 	"time"
 
 
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
+	derr "github.com/docker/docker/api/errors"
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/pkg/pubsub"
 	"github.com/docker/docker/pkg/pubsub"
 	"github.com/opencontainers/runc/libcontainer/system"
 	"github.com/opencontainers/runc/libcontainer/system"
@@ -154,13 +154,13 @@ func (s *statsCollector) getSystemCPUUsage() (uint64, error) {
 		switch parts[0] {
 		switch parts[0] {
 		case "cpu":
 		case "cpu":
 			if len(parts) < 8 {
 			if len(parts) < 8 {
-				return 0, fmt.Errorf("invalid number of cpu fields")
+				return 0, derr.ErrorCodeBadCPUFields
 			}
 			}
 			var totalClockTicks uint64
 			var totalClockTicks uint64
 			for _, i := range parts[1:8] {
 			for _, i := range parts[1:8] {
 				v, err := strconv.ParseUint(i, 10, 64)
 				v, err := strconv.ParseUint(i, 10, 64)
 				if err != nil {
 				if err != nil {
-					return 0, fmt.Errorf("Unable to convert value %s to int: %s", i, err)
+					return 0, derr.ErrorCodeBadCPUInt.WithArgs(i, err)
 				}
 				}
 				totalClockTicks += v
 				totalClockTicks += v
 			}
 			}
@@ -168,5 +168,5 @@ func (s *statsCollector) getSystemCPUUsage() (uint64, error) {
 				s.clockTicksPerSecond, nil
 				s.clockTicksPerSecond, nil
 		}
 		}
 	}
 	}
-	return 0, fmt.Errorf("invalid stat format")
+	return 0, derr.ErrorCodeBadStatFormat
 }
 }

+ 5 - 3
daemon/stop.go

@@ -1,6 +1,8 @@
 package daemon
 package daemon
 
 
-import "fmt"
+import (
+	derr "github.com/docker/docker/api/errors"
+)
 
 
 // ContainerStop looks for the given container and terminates it,
 // ContainerStop looks for the given container and terminates it,
 // waiting the given number of seconds before forcefully killing the
 // waiting the given number of seconds before forcefully killing the
@@ -14,10 +16,10 @@ func (daemon *Daemon) ContainerStop(name string, seconds int) error {
 		return err
 		return err
 	}
 	}
 	if !container.IsRunning() {
 	if !container.IsRunning() {
-		return fmt.Errorf("Container already stopped")
+		return derr.ErrorCodeStopped
 	}
 	}
 	if err := container.Stop(seconds); err != nil {
 	if err := container.Stop(seconds); err != nil {
-		return fmt.Errorf("Cannot stop container %s: %s\n", name, err)
+		return derr.ErrorCodeCantStop.WithArgs(name, err)
 	}
 	}
 	return nil
 	return nil
 }
 }

+ 5 - 5
daemon/top_unix.go

@@ -3,11 +3,11 @@
 package daemon
 package daemon
 
 
 import (
 import (
-	"fmt"
 	"os/exec"
 	"os/exec"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 
 
+	derr "github.com/docker/docker/api/errors"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types"
 )
 )
 
 
@@ -27,7 +27,7 @@ func (daemon *Daemon) ContainerTop(name string, psArgs string) (*types.Container
 	}
 	}
 
 
 	if !container.IsRunning() {
 	if !container.IsRunning() {
-		return nil, fmt.Errorf("Container %s is not running", name)
+		return nil, derr.ErrorCodeNotRunning.WithArgs(name)
 	}
 	}
 
 
 	pids, err := daemon.ExecutionDriver().GetPidsForContainer(container.ID)
 	pids, err := daemon.ExecutionDriver().GetPidsForContainer(container.ID)
@@ -37,7 +37,7 @@ func (daemon *Daemon) ContainerTop(name string, psArgs string) (*types.Container
 
 
 	output, err := exec.Command("ps", strings.Split(psArgs, " ")...).Output()
 	output, err := exec.Command("ps", strings.Split(psArgs, " ")...).Output()
 	if err != nil {
 	if err != nil {
-		return nil, fmt.Errorf("Error running ps: %s", err)
+		return nil, derr.ErrorCodePSError.WithArgs(err)
 	}
 	}
 
 
 	procList := &types.ContainerProcessList{}
 	procList := &types.ContainerProcessList{}
@@ -52,7 +52,7 @@ func (daemon *Daemon) ContainerTop(name string, psArgs string) (*types.Container
 		}
 		}
 	}
 	}
 	if pidIndex == -1 {
 	if pidIndex == -1 {
-		return nil, fmt.Errorf("Couldn't find PID field in ps output")
+		return nil, derr.ErrorCodeNoPID
 	}
 	}
 
 
 	// loop through the output and extract the PID from each line
 	// loop through the output and extract the PID from each line
@@ -63,7 +63,7 @@ func (daemon *Daemon) ContainerTop(name string, psArgs string) (*types.Container
 		fields := strings.Fields(line)
 		fields := strings.Fields(line)
 		p, err := strconv.Atoi(fields[pidIndex])
 		p, err := strconv.Atoi(fields[pidIndex])
 		if err != nil {
 		if err != nil {
-			return nil, fmt.Errorf("Unexpected pid '%s': %s", fields[pidIndex], err)
+			return nil, derr.ErrorCodeBadPID.WithArgs(fields[pidIndex], err)
 		}
 		}
 
 
 		for _, pid := range pids {
 		for _, pid := range pids {

+ 2 - 3
daemon/top_windows.go

@@ -1,12 +1,11 @@
 package daemon
 package daemon
 
 
 import (
 import (
-	"fmt"
-
+	derr "github.com/docker/docker/api/errors"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types"
 )
 )
 
 
 // ContainerTop is not supported on Windows and returns an error.
 // ContainerTop is not supported on Windows and returns an error.
 func (daemon *Daemon) ContainerTop(name string, psArgs string) (*types.ContainerProcessList, error) {
 func (daemon *Daemon) ContainerTop(name string, psArgs string) (*types.ContainerProcessList, error) {
-	return nil, fmt.Errorf("Top is not supported on Windows")
+	return nil, derr.ErrorCodeNoTop
 }
 }

+ 4 - 2
daemon/unpause.go

@@ -1,6 +1,8 @@
 package daemon
 package daemon
 
 
-import "fmt"
+import (
+	derr "github.com/docker/docker/api/errors"
+)
 
 
 // ContainerUnpause unpauses a container
 // ContainerUnpause unpauses a container
 func (daemon *Daemon) ContainerUnpause(name string) error {
 func (daemon *Daemon) ContainerUnpause(name string) error {
@@ -10,7 +12,7 @@ func (daemon *Daemon) ContainerUnpause(name string) error {
 	}
 	}
 
 
 	if err := container.unpause(); err != nil {
 	if err := container.unpause(); err != nil {
-		return fmt.Errorf("Cannot unpause container %s: %s", name, err)
+		return derr.ErrorCodeCantUnpause.WithArgs(name, err)
 	}
 	}
 
 
 	return nil
 	return nil

+ 2 - 1
daemon/volumes.go

@@ -10,6 +10,7 @@ import (
 	"sync"
 	"sync"
 
 
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
+	derr "github.com/docker/docker/api/errors"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/api/types"
 	"github.com/docker/docker/pkg/chrootarchive"
 	"github.com/docker/docker/pkg/chrootarchive"
 	"github.com/docker/docker/pkg/system"
 	"github.com/docker/docker/pkg/system"
@@ -59,7 +60,7 @@ func (m *mountPoint) Setup() (string, error) {
 		return m.Source, nil
 		return m.Source, nil
 	}
 	}
 
 
-	return "", fmt.Errorf("Unable to setup mount point, neither source nor volume defined")
+	return "", derr.ErrorCodeMountSetup
 }
 }
 
 
 // hasResource checks whether the given absolute path for a container is in
 // hasResource checks whether the given absolute path for a container is in

+ 7 - 7
daemon/volumes_unix.go

@@ -3,7 +3,6 @@
 package daemon
 package daemon
 
 
 import (
 import (
-	"fmt"
 	"io/ioutil"
 	"io/ioutil"
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
@@ -11,6 +10,7 @@ import (
 	"strings"
 	"strings"
 
 
 	"github.com/Sirupsen/logrus"
 	"github.com/Sirupsen/logrus"
+	derr "github.com/docker/docker/api/errors"
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/daemon/execdriver"
 	"github.com/docker/docker/pkg/system"
 	"github.com/docker/docker/pkg/system"
 	"github.com/docker/docker/runconfig"
 	"github.com/docker/docker/runconfig"
@@ -72,18 +72,18 @@ func parseBindMount(spec, volumeDriver string) (*mountPoint, error) {
 		bind.Destination = arr[1]
 		bind.Destination = arr[1]
 		mode := arr[2]
 		mode := arr[2]
 		if !volume.ValidMountMode(mode) {
 		if !volume.ValidMountMode(mode) {
-			return nil, fmt.Errorf("invalid mode for volumes-from: %s", mode)
+			return nil, derr.ErrorCodeVolumeInvalidMode.WithArgs(mode)
 		}
 		}
 		bind.RW = volume.ReadWrite(mode)
 		bind.RW = volume.ReadWrite(mode)
 		// Mode field is used by SELinux to decide whether to apply label
 		// Mode field is used by SELinux to decide whether to apply label
 		bind.Mode = mode
 		bind.Mode = mode
 	default:
 	default:
-		return nil, fmt.Errorf("Invalid volume specification: %s", spec)
+		return nil, derr.ErrorCodeVolumeInvalid.WithArgs(spec)
 	}
 	}
 
 
 	//validate the volumes destination path
 	//validate the volumes destination path
 	if !filepath.IsAbs(bind.Destination) {
 	if !filepath.IsAbs(bind.Destination) {
-		return nil, fmt.Errorf("Invalid volume destination path: %s mount path must be absolute.", bind.Destination)
+		return nil, derr.ErrorCodeVolumeAbs.WithArgs(bind.Destination)
 	}
 	}
 
 
 	name, source, err := parseVolumeSource(arr[0])
 	name, source, err := parseVolumeSource(arr[0])
@@ -263,7 +263,7 @@ func (daemon *Daemon) verifyVolumesInfo(container *Container) error {
 // parseVolumesFrom ensure that the supplied volumes-from is valid.
 // parseVolumesFrom ensure that the supplied volumes-from is valid.
 func parseVolumesFrom(spec string) (string, string, error) {
 func parseVolumesFrom(spec string) (string, string, error) {
 	if len(spec) == 0 {
 	if len(spec) == 0 {
-		return "", "", fmt.Errorf("malformed volumes-from specification: %s", spec)
+		return "", "", derr.ErrorCodeVolumeFromBlank.WithArgs(spec)
 	}
 	}
 
 
 	specParts := strings.SplitN(spec, ":", 2)
 	specParts := strings.SplitN(spec, ":", 2)
@@ -273,7 +273,7 @@ func parseVolumesFrom(spec string) (string, string, error) {
 	if len(specParts) == 2 {
 	if len(specParts) == 2 {
 		mode = specParts[1]
 		mode = specParts[1]
 		if !volume.ValidMountMode(mode) {
 		if !volume.ValidMountMode(mode) {
-			return "", "", fmt.Errorf("invalid mode for volumes-from: %s", mode)
+			return "", "", derr.ErrorCodeVolumeMode.WithArgs(mode)
 		}
 		}
 	}
 	}
 	return id, mode, nil
 	return id, mode, nil
@@ -336,7 +336,7 @@ func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runc
 		}
 		}
 
 
 		if binds[bind.Destination] {
 		if binds[bind.Destination] {
-			return fmt.Errorf("Duplicate bind mount %s", bind.Destination)
+			return derr.ErrorCodeVolumeDup.WithArgs(bind.Destination)
 		}
 		}
 
 
 		if len(bind.Name) > 0 && len(bind.Driver) > 0 {
 		if len(bind.Name) > 0 && len(bind.Driver) > 0 {

+ 1 - 1
integration-cli/docker_cli_run_test.go

@@ -3000,7 +3000,7 @@ func (s *DockerSuite) TestRunContainerNetworkModeToSelf(c *check.C) {
 	testRequires(c, DaemonIsLinux)
 	testRequires(c, DaemonIsLinux)
 	out, _, err := dockerCmdWithError("run", "--name=me", "--net=container:me", "busybox", "true")
 	out, _, err := dockerCmdWithError("run", "--name=me", "--net=container:me", "busybox", "true")
 	if err == nil || !strings.Contains(out, "cannot join own network") {
 	if err == nil || !strings.Contains(out, "cannot join own network") {
-		c.Fatalf("using container net mode to self should result in an error")
+		c.Fatalf("using container net mode to self should result in an error\nerr: %q\nout: %s", err, out)
 	}
 	}
 }
 }