diff --git a/api/client/run.go b/api/client/run.go index 223964d595ca6..b65a0a1bbe008 100644 --- a/api/client/run.go +++ b/api/client/run.go @@ -11,7 +11,6 @@ import ( "github.com/Sirupsen/logrus" Cli "github.com/docker/docker/cli" - derr "github.com/docker/docker/errors" "github.com/docker/docker/opts" "github.com/docker/docker/pkg/promise" "github.com/docker/docker/pkg/signal" @@ -21,6 +20,11 @@ import ( "github.com/docker/libnetwork/resolvconf/dns" ) +const ( + errCmdNotFound = "Container command not found or does not exist." + errCmdCouldNotBeInvoked = "Container command could not be invoked." +) + func (cid *cidFile) Close() error { cid.file.Close() @@ -46,20 +50,13 @@ func (cid *cidFile) Write(id string) error { // return 125 for generic docker daemon failures func runStartContainerErr(err error) error { trimmedErr := strings.Trim(err.Error(), "Error response from daemon: ") - statusError := Cli.StatusError{} - derrCmdNotFound := derr.ErrorCodeCmdNotFound.Message() - derrCouldNotInvoke := derr.ErrorCodeCmdCouldNotBeInvoked.Message() - derrNoSuchImage := derr.ErrorCodeNoSuchImageHash.Message() - derrNoSuchImageTag := derr.ErrorCodeNoSuchImageTag.Message() + statusError := Cli.StatusError{StatusCode: 125} + switch trimmedErr { - case derrCmdNotFound: + case errCmdNotFound: statusError = Cli.StatusError{StatusCode: 127} - case derrCouldNotInvoke: + case errCmdCouldNotBeInvoked: statusError = Cli.StatusError{StatusCode: 126} - case derrNoSuchImage, derrNoSuchImageTag: - statusError = Cli.StatusError{StatusCode: 125} - default: - statusError = Cli.StatusError{StatusCode: 125} } return statusError } diff --git a/api/server/httputils/errors.go b/api/server/httputils/errors.go new file mode 100644 index 0000000000000..c6b0a6b2d8c98 --- /dev/null +++ b/api/server/httputils/errors.go @@ -0,0 +1,69 @@ +package httputils + +import ( + "net/http" + "strings" + + "github.com/Sirupsen/logrus" +) + +// httpStatusError is an interface +// that errors with custom status codes +// implement to tell the api layer +// which response status to set. +type httpStatusError interface { + HTTPErrorStatusCode() int +} + +// inputValidationError is an interface +// that errors generated by invalid +// inputs can implement to tell the +// api layer to set a 400 status code +// in the response. +type inputValidationError interface { + IsValidationError() bool +} + +// WriteError decodes a specific docker error and sends it in the response. +func WriteError(w http.ResponseWriter, err error) { + if err == nil || w == nil { + logrus.WithFields(logrus.Fields{"error": err, "writer": w}).Error("unexpected HTTP error handling") + return + } + + var statusCode int + errMsg := err.Error() + + switch e := err.(type) { + case httpStatusError: + statusCode = e.HTTPErrorStatusCode() + case inputValidationError: + statusCode = http.StatusBadRequest + default: + // FIXME: this is brittle and should not be necessary, but we still need to identify if + // there are errors falling back into this logic. + // If we need to differentiate between different possible error types, + // we should create appropriate error types that implement the httpStatusError interface. + errStr := strings.ToLower(errMsg) + for keyword, status := range map[string]int{ + "not found": http.StatusNotFound, + "no such": http.StatusNotFound, + "bad parameter": http.StatusBadRequest, + "conflict": http.StatusConflict, + "impossible": http.StatusNotAcceptable, + "wrong login/password": http.StatusUnauthorized, + "hasn't been activated": http.StatusForbidden, + } { + if strings.Contains(errStr, keyword) { + statusCode = status + break + } + } + } + + if statusCode == 0 { + statusCode = http.StatusInternalServerError + } + + http.Error(w, errMsg, statusCode) +} diff --git a/api/server/httputils/httputils.go b/api/server/httputils/httputils.go index ecf26e2a14c21..787a4d3181c65 100644 --- a/api/server/httputils/httputils.go +++ b/api/server/httputils/httputils.go @@ -9,8 +9,6 @@ import ( "golang.org/x/net/context" - "github.com/Sirupsen/logrus" - "github.com/docker/distribution/registry/api/errcode" "github.com/docker/docker/api" "github.com/docker/docker/pkg/version" ) @@ -85,78 +83,6 @@ func ParseMultipartForm(r *http.Request) error { return nil } -// WriteError decodes a specific docker error and sends it in the response. -func WriteError(w http.ResponseWriter, err error) { - if err == nil || w == nil { - logrus.WithFields(logrus.Fields{"error": err, "writer": w}).Error("unexpected HTTP error handling") - return - } - - statusCode := http.StatusInternalServerError - errMsg := err.Error() - - // Based on the type of error we get we need to process things - // slightly differently to extract the error message. - // In the 'errcode.*' cases there are two different type of - // error that could be returned. errocode.ErrorCode is the base - // type of error object - it is just an 'int' that can then be - // used as the look-up key to find the message. errorcode.Error - // extends errorcode.Error by adding error-instance specific - // data, like 'details' or variable strings to be inserted into - // the message. - // - // Ideally, we should just be able to call err.Error() for all - // cases but the errcode package doesn't support that yet. - // - // Additionally, in both errcode cases, there might be an http - // status code associated with it, and if so use it. - switch err.(type) { - case errcode.ErrorCode: - daError, _ := err.(errcode.ErrorCode) - statusCode = daError.Descriptor().HTTPStatusCode - errMsg = daError.Message() - - case errcode.Error: - // For reference, if you're looking for a particular error - // then you can do something like : - // import ( derr "github.com/docker/docker/errors" ) - // if daError.ErrorCode() == derr.ErrorCodeNoSuchContainer { ... } - - daError, _ := err.(errcode.Error) - statusCode = daError.ErrorCode().Descriptor().HTTPStatusCode - errMsg = daError.Message - - default: - // This part of will be removed once we've - // converted everything over to use the errcode package - - // FIXME: this is brittle and should not be necessary. - // If we need to differentiate between different possible error types, - // we should create appropriate error types with clearly defined meaning - errStr := strings.ToLower(err.Error()) - for keyword, status := range map[string]int{ - "not found": http.StatusNotFound, - "no such": http.StatusNotFound, - "bad parameter": http.StatusBadRequest, - "conflict": http.StatusConflict, - "impossible": http.StatusNotAcceptable, - "wrong login/password": http.StatusUnauthorized, - "hasn't been activated": http.StatusForbidden, - } { - if strings.Contains(errStr, keyword) { - statusCode = status - break - } - } - } - - if statusCode == 0 { - statusCode = http.StatusInternalServerError - } - - http.Error(w, errMsg, statusCode) -} - // WriteJSON writes the value v to the http response stream as json with standard json encoding. func WriteJSON(w http.ResponseWriter, code int, v interface{}) error { w.Header().Set("Content-Type", "application/json") diff --git a/api/server/middleware/version.go b/api/server/middleware/version.go index 72784a5677e41..41d518bcbcd9f 100644 --- a/api/server/middleware/version.go +++ b/api/server/middleware/version.go @@ -6,11 +6,18 @@ import ( "runtime" "github.com/docker/docker/api/server/httputils" - "github.com/docker/docker/errors" "github.com/docker/docker/pkg/version" "golang.org/x/net/context" ) +type badRequestError struct { + error +} + +func (badRequestError) HTTPErrorStatusCode() int { + return http.StatusBadRequest +} + // NewVersionMiddleware creates a new Version middleware. func NewVersionMiddleware(versionCheck string, defaultVersion, minVersion version.Version) Middleware { serverVersion := version.Version(versionCheck) @@ -23,10 +30,10 @@ func NewVersionMiddleware(versionCheck string, defaultVersion, minVersion versio } if apiVersion.GreaterThan(defaultVersion) { - return errors.ErrorCodeNewerClientVersion.WithArgs(apiVersion, defaultVersion) + return badRequestError{fmt.Errorf("client is newer than server (client API version: %s, server API version: %s)", apiVersion, defaultVersion)} } if apiVersion.LessThan(minVersion) { - return errors.ErrorCodeOldClientVersion.WithArgs(apiVersion, minVersion) + return badRequestError{fmt.Errorf("client version %s is too old. Minimum supported API version is %s, please upgrade your client to a newer version", apiVersion, minVersion)} } header := fmt.Sprintf("Docker/%s (%s)", serverVersion, runtime.GOOS) diff --git a/api/server/middleware/version_test.go b/api/server/middleware/version_test.go index 4e3d92141b1e6..f60a98e5184f5 100644 --- a/api/server/middleware/version_test.go +++ b/api/server/middleware/version_test.go @@ -53,12 +53,12 @@ func TestVersionMiddlewareWithErrors(t *testing.T) { err := h(ctx, resp, req, vars) if !strings.Contains(err.Error(), "client version 0.1 is too old. Minimum supported API version is 1.2.0") { - t.Fatalf("Expected ErrorCodeOldClientVersion, got %v", err) + t.Fatalf("Expected too old client error, got %v", err) } vars["version"] = "100000" err = h(ctx, resp, req, vars) if !strings.Contains(err.Error(), "client is newer than server") { - t.Fatalf("Expected ErrorCodeNewerClientVersion, got %v", err) + t.Fatalf("Expected client newer than server error, got %v", err) } } diff --git a/api/server/router/build/build_routes.go b/api/server/router/build/build_routes.go index acc116b9946ad..0025c85a93430 100644 --- a/api/server/router/build/build_routes.go +++ b/api/server/router/build/build_routes.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/base64" "encoding/json" - "errors" "fmt" "io" "net/http" @@ -17,7 +16,6 @@ import ( "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/progress" "github.com/docker/docker/pkg/streamformatter" - "github.com/docker/docker/utils" "github.com/docker/engine-api/types" "github.com/docker/engine-api/types/container" "github.com/docker/go-units" @@ -117,7 +115,7 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r * if !output.Flushed() { return err } - _, err = w.Write(sf.FormatError(errors.New(utils.GetErrorMessage(err)))) + _, err = w.Write(sf.FormatError(err)) if err != nil { logrus.Warnf("could not write error response: %v", err) } diff --git a/api/server/router/container/container_routes.go b/api/server/router/container/container_routes.go index 34ad48f0c433e..016e00f05b7b3 100644 --- a/api/server/router/container/container_routes.go +++ b/api/server/router/container/container_routes.go @@ -11,15 +11,12 @@ import ( "time" "github.com/Sirupsen/logrus" - "github.com/docker/distribution/registry/api/errcode" "github.com/docker/docker/api/server/httputils" "github.com/docker/docker/api/types/backend" - derr "github.com/docker/docker/errors" "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/signal" "github.com/docker/docker/pkg/term" "github.com/docker/docker/runconfig" - "github.com/docker/docker/utils" "github.com/docker/engine-api/types" "github.com/docker/engine-api/types/container" "github.com/docker/engine-api/types/filters" @@ -126,7 +123,7 @@ func (s *containerRouter) getContainersLogs(ctx context.Context, w http.Response // The client may be expecting all of the data we're sending to // be multiplexed, so send it through OutStream, which will // have been set up to handle that if needed. - fmt.Fprintf(logsConfig.OutStream, "Error running logs job: %s\n", utils.GetErrorMessage(err)) + fmt.Fprintf(logsConfig.OutStream, "Error running logs job: %v\n", err) default: return err } @@ -182,6 +179,10 @@ func (s *containerRouter) postContainersStop(ctx context.Context, w http.Respons return nil } +type errContainerIsRunning interface { + ContainerIsRunning() bool +} + func (s *containerRouter) postContainersKill(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { if err := httputils.ParseForm(r); err != nil { return err @@ -199,15 +200,17 @@ func (s *containerRouter) postContainersKill(ctx context.Context, w http.Respons } if err := s.backend.ContainerKill(name, uint64(sig)); err != nil { - theErr, isDerr := err.(errcode.ErrorCoder) - isStopped := isDerr && theErr.ErrorCode() == derr.ErrorCodeNotRunning + var isStopped bool + if e, ok := err.(errContainerIsRunning); ok { + isStopped = !e.ContainerIsRunning() + } // 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 // to keep backwards compatibility. version := httputils.VersionFromContext(ctx) if version.GreaterThanOrEqualTo("1.20") || !isStopped { - return fmt.Errorf("Cannot kill container %s: %v", name, utils.GetErrorMessage(err)) + return fmt.Errorf("Cannot kill container %s: %v", name, err) } } @@ -430,7 +433,7 @@ func (s *containerRouter) postContainersAttach(ctx context.Context, w http.Respo hijacker, ok := w.(http.Hijacker) if !ok { - return derr.ErrorCodeNoHijackConnection.WithArgs(containerName) + return fmt.Errorf("error attaching to container %s, hijack connection missing", containerName) } setupStreams := func() (io.ReadCloser, io.Writer, io.Writer, error) { diff --git a/api/server/router/container/exec.go b/api/server/router/container/exec.go index caa5da061d1c2..bc336f60390ee 100644 --- a/api/server/router/container/exec.go +++ b/api/server/router/container/exec.go @@ -10,7 +10,6 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/docker/api/server/httputils" "github.com/docker/docker/pkg/stdcopy" - "github.com/docker/docker/utils" "github.com/docker/engine-api/types" "golang.org/x/net/context" ) @@ -46,7 +45,7 @@ func (s *containerRouter) postContainerExecCreate(ctx context.Context, w http.Re // Register an instance of Exec in container. id, err := s.backend.ContainerExecCreate(execConfig) if err != nil { - logrus.Errorf("Error setting up exec command in container %s: %s", name, utils.GetErrorMessage(err)) + logrus.Errorf("Error setting up exec command in container %s: %v", name, err) return err } @@ -113,7 +112,7 @@ func (s *containerRouter) postContainerExecStart(ctx context.Context, w http.Res if execStartCheck.Detach { return err } - logrus.Errorf("Error running exec in container: %v\n", utils.GetErrorMessage(err)) + logrus.Errorf("Error running exec in container: %v\n", err) } return nil } diff --git a/api/server/router/image/backend.go b/api/server/router/image/backend.go index 73e8216025a05..8c76ef9260b30 100644 --- a/api/server/router/image/backend.go +++ b/api/server/router/image/backend.go @@ -20,7 +20,6 @@ type Backend interface { type containerBackend interface { Commit(name string, config *types.ContainerCommitConfig) (imageID string, err error) - Exists(containerName string) bool } type imageBackend interface { diff --git a/api/server/router/image/image_routes.go b/api/server/router/image/image_routes.go index e55c0bb7844d5..dade346925f96 100644 --- a/api/server/router/image/image_routes.go +++ b/api/server/router/image/image_routes.go @@ -14,7 +14,6 @@ import ( "github.com/docker/distribution/registry/api/errcode" "github.com/docker/docker/api/server/httputils" "github.com/docker/docker/builder/dockerfile" - derr "github.com/docker/docker/errors" "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/streamformatter" "github.com/docker/docker/reference" @@ -49,10 +48,6 @@ func (s *imageRouter) postCommit(ctx context.Context, w http.ResponseWriter, r * c = &container.Config{} } - if !s.backend.Exists(cname) { - return derr.ErrorCodeNoSuchContainer.WithArgs(cname) - } - newConfig, err := dockerfile.BuildFromConfig(c, r.Form["changes"]) if err != nil { return err diff --git a/api/server/router/network/backend.go b/api/server/router/network/backend.go index eb8ce4f138466..731f92e7de6c2 100644 --- a/api/server/router/network/backend.go +++ b/api/server/router/network/backend.go @@ -8,8 +8,6 @@ import ( // Backend is all the methods that need to be implemented // to provide network specific functionality. type Backend interface { - NetworkControllerEnabled() bool - FindNetwork(idName string) (libnetwork.Network, error) GetNetworkByName(idName string) (libnetwork.Network, error) GetNetworksByID(partialID string) []libnetwork.Network diff --git a/api/server/router/network/network.go b/api/server/router/network/network.go index 59641bc03bba5..7c88089623d07 100644 --- a/api/server/router/network/network.go +++ b/api/server/router/network/network.go @@ -1,13 +1,6 @@ package network -import ( - "net/http" - - "github.com/docker/docker/api/server/httputils" - "github.com/docker/docker/api/server/router" - "github.com/docker/docker/errors" - "golang.org/x/net/context" -) +import "github.com/docker/docker/api/server/router" // networkRouter is a router to talk with the network controller type networkRouter struct { @@ -32,24 +25,13 @@ func (r *networkRouter) Routes() []router.Route { func (r *networkRouter) initRoutes() { r.routes = []router.Route{ // GET - router.NewGetRoute("/networks", r.controllerEnabledMiddleware(r.getNetworksList)), - router.NewGetRoute("/networks/{id:.*}", r.controllerEnabledMiddleware(r.getNetwork)), + router.NewGetRoute("/networks", r.getNetworksList), + router.NewGetRoute("/networks/{id:.*}", r.getNetwork), // POST - router.NewPostRoute("/networks/create", r.controllerEnabledMiddleware(r.postNetworkCreate)), - router.NewPostRoute("/networks/{id:.*}/connect", r.controllerEnabledMiddleware(r.postNetworkConnect)), - router.NewPostRoute("/networks/{id:.*}/disconnect", r.controllerEnabledMiddleware(r.postNetworkDisconnect)), + router.NewPostRoute("/networks/create", r.postNetworkCreate), + router.NewPostRoute("/networks/{id:.*}/connect", r.postNetworkConnect), + router.NewPostRoute("/networks/{id:.*}/disconnect", r.postNetworkDisconnect), // DELETE - router.NewDeleteRoute("/networks/{id:.*}", r.controllerEnabledMiddleware(r.deleteNetwork)), - } -} - -func (r *networkRouter) controllerEnabledMiddleware(handler httputils.APIFunc) httputils.APIFunc { - if r.backend.NetworkControllerEnabled() { - return handler + router.NewDeleteRoute("/networks/{id:.*}", r.deleteNetwork), } - return networkControllerDisabled -} - -func networkControllerDisabled(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { - return errors.ErrorNetworkControllerNotEnabled.WithArgs() } diff --git a/api/server/server.go b/api/server/server.go index f65dfccfaa8a7..6dea4d3a5ca1a 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -10,7 +10,6 @@ import ( "github.com/docker/docker/api/server/httputils" "github.com/docker/docker/api/server/router" "github.com/docker/docker/pkg/authorization" - "github.com/docker/docker/utils" "github.com/gorilla/mux" "golang.org/x/net/context" ) @@ -134,7 +133,7 @@ func (s *Server) makeHTTPHandler(handler httputils.APIFunc) http.HandlerFunc { } if err := handlerFunc(ctx, w, r, vars); err != nil { - logrus.Errorf("Handler for %s %s returned error: %s", r.Method, r.URL.Path, utils.GetErrorMessage(err)) + logrus.Errorf("Handler for %s %s returned error: %v", r.Method, r.URL.Path, err) httputils.WriteError(w, err) } } diff --git a/builder/dockerfile/dispatchers.go b/builder/dockerfile/dispatchers.go index f800acbe8ecb4..a5e8c154f5e07 100644 --- a/builder/dockerfile/dispatchers.go +++ b/builder/dockerfile/dispatchers.go @@ -19,7 +19,6 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/docker/api" "github.com/docker/docker/builder" - derr "github.com/docker/docker/errors" "github.com/docker/docker/pkg/signal" "github.com/docker/docker/pkg/system" runconfigopts "github.com/docker/docker/runconfig/opts" @@ -40,12 +39,12 @@ func nullDispatch(b *Builder, args []string, attributes map[string]bool, origina // func env(b *Builder, args []string, attributes map[string]bool, original string) error { if len(args) == 0 { - return derr.ErrorCodeAtLeastOneArg.WithArgs("ENV") + return errAtLeastOneArgument("ENV") } if len(args)%2 != 0 { // should never get here, but just in case - return derr.ErrorCodeTooManyArgs.WithArgs("ENV") + return errTooManyArguments("ENV") } if err := b.flags.Parse(); err != nil { @@ -99,7 +98,7 @@ func env(b *Builder, args []string, attributes map[string]bool, original string) // Sets the maintainer metadata. func maintainer(b *Builder, args []string, attributes map[string]bool, original string) error { if len(args) != 1 { - return derr.ErrorCodeExactlyOneArg.WithArgs("MAINTAINER") + return errExactlyOneArgument("MAINTAINER") } if err := b.flags.Parse(); err != nil { @@ -116,11 +115,11 @@ func maintainer(b *Builder, args []string, attributes map[string]bool, original // func label(b *Builder, args []string, attributes map[string]bool, original string) error { if len(args) == 0 { - return derr.ErrorCodeAtLeastOneArg.WithArgs("LABEL") + return errAtLeastOneArgument("LABEL") } if len(args)%2 != 0 { // should never get here, but just in case - return derr.ErrorCodeTooManyArgs.WithArgs("LABEL") + return errTooManyArguments("LABEL") } if err := b.flags.Parse(); err != nil { @@ -152,7 +151,7 @@ func label(b *Builder, args []string, attributes map[string]bool, original strin // func add(b *Builder, args []string, attributes map[string]bool, original string) error { if len(args) < 2 { - return derr.ErrorCodeAtLeastTwoArgs.WithArgs("ADD") + return errAtLeastOneArgument("ADD") } if err := b.flags.Parse(); err != nil { @@ -168,7 +167,7 @@ func add(b *Builder, args []string, attributes map[string]bool, original string) // func dispatchCopy(b *Builder, args []string, attributes map[string]bool, original string) error { if len(args) < 2 { - return derr.ErrorCodeAtLeastTwoArgs.WithArgs("COPY") + return errAtLeastOneArgument("COPY") } if err := b.flags.Parse(); err != nil { @@ -184,7 +183,7 @@ func dispatchCopy(b *Builder, args []string, attributes map[string]bool, origina // func from(b *Builder, args []string, attributes map[string]bool, original string) error { if len(args) != 1 { - return derr.ErrorCodeExactlyOneArg.WithArgs("FROM") + return errExactlyOneArgument("FROM") } if err := b.flags.Parse(); err != nil { @@ -233,7 +232,7 @@ func from(b *Builder, args []string, attributes map[string]bool, original string // func onbuild(b *Builder, args []string, attributes map[string]bool, original string) error { if len(args) == 0 { - return derr.ErrorCodeAtLeastOneArg.WithArgs("ONBUILD") + return errAtLeastOneArgument("ONBUILD") } if err := b.flags.Parse(); err != nil { @@ -243,9 +242,9 @@ func onbuild(b *Builder, args []string, attributes map[string]bool, original str triggerInstruction := strings.ToUpper(strings.TrimSpace(args[0])) switch triggerInstruction { case "ONBUILD": - return derr.ErrorCodeChainOnBuild + return fmt.Errorf("Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed") case "MAINTAINER", "FROM": - return derr.ErrorCodeBadOnBuildCmd.WithArgs(triggerInstruction) + return fmt.Errorf("%s isn't allowed as an ONBUILD trigger", triggerInstruction) } original = regexp.MustCompile(`(?i)^\s*ONBUILD\s*`).ReplaceAllString(original, "") @@ -260,7 +259,7 @@ func onbuild(b *Builder, args []string, attributes map[string]bool, original str // func workdir(b *Builder, args []string, attributes map[string]bool, original string) error { if len(args) != 1 { - return derr.ErrorCodeExactlyOneArg.WithArgs("WORKDIR") + return errExactlyOneArgument("WORKDIR") } if err := b.flags.Parse(); err != nil { @@ -293,7 +292,7 @@ func workdir(b *Builder, args []string, attributes map[string]bool, original str // func run(b *Builder, args []string, attributes map[string]bool, original string) error { if b.image == "" && !b.noBaseImage { - return derr.ErrorCodeMissingFrom + return fmt.Errorf("Please provide a source image with `from` prior to run") } if err := b.flags.Parse(); err != nil { @@ -491,7 +490,7 @@ func expose(b *Builder, args []string, attributes map[string]bool, original stri portsTab := args if len(args) == 0 { - return derr.ErrorCodeAtLeastOneArg.WithArgs("EXPOSE") + return errAtLeastOneArgument("EXPOSE") } if err := b.flags.Parse(); err != nil { @@ -530,7 +529,7 @@ func expose(b *Builder, args []string, attributes map[string]bool, original stri // func user(b *Builder, args []string, attributes map[string]bool, original string) error { if len(args) != 1 { - return derr.ErrorCodeExactlyOneArg.WithArgs("USER") + return errExactlyOneArgument("USER") } if err := b.flags.Parse(); err != nil { @@ -547,7 +546,7 @@ func user(b *Builder, args []string, attributes map[string]bool, original string // func volume(b *Builder, args []string, attributes map[string]bool, original string) error { if len(args) == 0 { - return derr.ErrorCodeAtLeastOneArg.WithArgs("VOLUME") + return errAtLeastOneArgument("VOLUME") } if err := b.flags.Parse(); err != nil { @@ -560,7 +559,7 @@ func volume(b *Builder, args []string, attributes map[string]bool, original stri for _, v := range args { v = strings.TrimSpace(v) if v == "" { - return derr.ErrorCodeVolumeEmpty + return fmt.Errorf("Volume specified can not be an empty string") } b.runConfig.Volumes[v] = struct{}{} } @@ -631,3 +630,15 @@ func arg(b *Builder, args []string, attributes map[string]bool, original string) return b.commit("", b.runConfig.Cmd, fmt.Sprintf("ARG %s", arg)) } + +func errAtLeastOneArgument(command string) error { + return fmt.Errorf("%s requires at least one argument", command) +} + +func errExactlyOneArgument(command string) error { + return fmt.Errorf("%s requires exactly one argument", command) +} + +func errTooManyArguments(command string) error { + return fmt.Errorf("Bad input to %s, too many arguments", command) +} diff --git a/container/container.go b/container/container.go index 526810e5cb2fe..ad4e728663afc 100644 --- a/container/container.go +++ b/container/container.go @@ -16,7 +16,6 @@ import ( "github.com/docker/docker/daemon/logger" "github.com/docker/docker/daemon/logger/jsonfilelog" "github.com/docker/docker/daemon/network" - derr "github.com/docker/docker/errors" "github.com/docker/docker/image" "github.com/docker/docker/layer" "github.com/docker/docker/pkg/promise" @@ -199,7 +198,7 @@ func (container *Container) SetupWorkingDirectory() error { if err := system.MkdirAll(pth, 0755); err != nil { pthInfo, err2 := os.Stat(pth) if err2 == nil && pthInfo != nil && !pthInfo.IsDir() { - return derr.ErrorCodeNotADir.WithArgs(container.Config.WorkingDir) + return fmt.Errorf("Cannot mkdir: %s is not a directory", container.Config.WorkingDir) } return err @@ -277,13 +276,6 @@ func (container *Container) ConfigPath() (string, error) { return container.GetRootResourcePath(configFileName) } -func validateID(id string) error { - if id == "" { - return derr.ErrorCodeEmptyID - } - return nil -} - // Returns true if the container exposes a certain port func (container *Container) exposes(p nat.Port) bool { _, exists := container.Config.ExposedPorts[p] @@ -307,7 +299,7 @@ func (container *Container) GetLogConfig(defaultConfig containertypes.LogConfig) func (container *Container) StartLogger(cfg containertypes.LogConfig) (logger.Logger, error) { c, err := logger.GetLogDriver(cfg.Type) if err != nil { - return nil, derr.ErrorCodeLoggingFactory.WithArgs(err) + return nil, fmt.Errorf("Failed to get logging factory: %v", err) } ctx := logger.Context{ Config: cfg.Config, diff --git a/container/container_unix.go b/container/container_unix.go index 02408d25fc4dd..7cad214574c6b 100644 --- a/container/container_unix.go +++ b/container/container_unix.go @@ -14,7 +14,6 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/docker/daemon/execdriver" - derr "github.com/docker/docker/errors" "github.com/docker/docker/pkg/chrootarchive" "github.com/docker/docker/pkg/symlink" "github.com/docker/docker/pkg/system" @@ -34,6 +33,11 @@ import ( // DefaultSHMSize is the default size (64MB) of the SHM which will be mounted in the container const DefaultSHMSize int64 = 67108864 +var ( + errInvalidEndpoint = fmt.Errorf("invalid endpoint while building port map info") + errInvalidNetwork = fmt.Errorf("invalid network settings while building port map info") +) + // Container holds the fields specific to unixen implementations. // See CommonContainer for standard fields common to all containers. type Container struct { @@ -116,12 +120,12 @@ func (container *Container) GetEndpointInNetwork(n libnetwork.Network) (libnetwo func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint) error { if ep == nil { - return derr.ErrorCodeEmptyEndpoint + return errInvalidEndpoint } networkSettings := container.NetworkSettings if networkSettings == nil { - return derr.ErrorCodeEmptyNetwork + return errInvalidNetwork } if len(networkSettings.Ports) == 0 { @@ -151,7 +155,7 @@ func getEndpointPortMapInfo(ep libnetwork.Endpoint) (nat.PortMap, error) { for _, tp := range exposedPorts { natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port))) if err != nil { - return pm, derr.ErrorCodeParsingPort.WithArgs(tp.Port, err) + return pm, fmt.Errorf("Error parsing Port value(%v):%v", tp.Port, err) } pm[natPort] = nil } @@ -195,12 +199,12 @@ func getSandboxPortMapInfo(sb libnetwork.Sandbox) nat.PortMap { // BuildEndpointInfo sets endpoint-related fields on container.NetworkSettings based on the provided network and endpoint. func (container *Container) BuildEndpointInfo(n libnetwork.Network, ep libnetwork.Endpoint) error { if ep == nil { - return derr.ErrorCodeEmptyEndpoint + return errInvalidEndpoint } networkSettings := container.NetworkSettings if networkSettings == nil { - return derr.ErrorCodeEmptyNetwork + return errInvalidNetwork } epInfo := ep.Info() @@ -377,7 +381,7 @@ func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epC portStart, portEnd, err = newP.Range() } if err != nil { - return nil, derr.ErrorCodeHostPort.WithArgs(binding[i].HostPort, err) + return nil, fmt.Errorf("Error parsing HostPort value(%s):%v", binding[i].HostPort, err) } pbCopy.HostPort = uint16(portStart) pbCopy.HostPortEnd = uint16(portEnd) diff --git a/container/monitor.go b/container/monitor.go index 043ee2fe8071f..914cc1a9e0a5f 100644 --- a/container/monitor.go +++ b/container/monitor.go @@ -1,6 +1,7 @@ package container import ( + "fmt" "io" "os/exec" "strings" @@ -10,10 +11,8 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/docker/daemon/execdriver" - derr "github.com/docker/docker/errors" "github.com/docker/docker/pkg/promise" "github.com/docker/docker/pkg/stringid" - "github.com/docker/docker/utils" "github.com/docker/engine-api/types/container" ) @@ -190,7 +189,7 @@ func (m *containerMonitor) start() error { if m.container.RestartCount == 0 { m.container.ExitCode = 127 m.resetContainer(false) - return derr.ErrorCodeCmdNotFound + return fmt.Errorf("Container command not found or does not exist.") } } // set to 126 for container cmd can't be invoked errors @@ -198,7 +197,7 @@ func (m *containerMonitor) start() error { if m.container.RestartCount == 0 { m.container.ExitCode = 126 m.resetContainer(false) - return derr.ErrorCodeCmdCouldNotBeInvoked + return fmt.Errorf("Container command could not be invoked.") } } @@ -206,7 +205,7 @@ func (m *containerMonitor) start() error { m.container.ExitCode = -1 m.resetContainer(false) - return derr.ErrorCodeCantStart.WithArgs(m.container.ID, utils.GetErrorMessage(err)) + return fmt.Errorf("Cannot start container %s: %v", m.container.ID, err) } logrus.Errorf("Error running container: %s", err) diff --git a/container/state.go b/container/state.go index aa2b26722bc1c..7173c7632f37a 100644 --- a/container/state.go +++ b/container/state.go @@ -6,7 +6,6 @@ import ( "time" "github.com/docker/docker/daemon/execdriver" - derr "github.com/docker/docker/errors" "github.com/docker/go-units" ) @@ -113,7 +112,7 @@ func wait(waitChan <-chan struct{}, timeout time.Duration) error { } select { case <-time.After(timeout): - return derr.ErrorCodeTimedOut.WithArgs(timeout) + return fmt.Errorf("Timed out: %v", timeout) case <-waitChan: return nil } @@ -256,14 +255,15 @@ func (s *State) IsRestarting() bool { } // SetRemovalInProgress sets the container state as being removed. -func (s *State) SetRemovalInProgress() error { +// It returns true if the container was already in that state. +func (s *State) SetRemovalInProgress() bool { s.Lock() defer s.Unlock() if s.RemovalInProgress { - return derr.ErrorCodeAlreadyRemoving + return true } s.RemovalInProgress = true - return nil + return false } // ResetRemovalInProgress make the RemovalInProgress state to false. diff --git a/daemon/attach.go b/daemon/attach.go index 1beedbf138237..79e9cd51dacc5 100644 --- a/daemon/attach.go +++ b/daemon/attach.go @@ -9,7 +9,7 @@ import ( "github.com/docker/docker/api/types/backend" "github.com/docker/docker/container" "github.com/docker/docker/daemon/logger" - derr "github.com/docker/docker/errors" + "github.com/docker/docker/errors" "github.com/docker/docker/pkg/stdcopy" ) @@ -17,10 +17,11 @@ import ( func (daemon *Daemon) ContainerAttach(prefixOrName string, c *backend.ContainerAttachConfig) error { container, err := daemon.GetContainer(prefixOrName) if err != nil { - return derr.ErrorCodeNoSuchContainer.WithArgs(prefixOrName) + return err } if container.IsPaused() { - return derr.ErrorCodePausedContainer.WithArgs(prefixOrName) + err := fmt.Errorf("Container %s is paused. Unpause the container before attach", prefixOrName) + return errors.NewRequestConflictError(err) } inStream, outStream, errStream, err := c.GetStreams() diff --git a/daemon/container_operations_unix.go b/daemon/container_operations_unix.go index 4db5b4d62f8d8..4d658d679dc62 100644 --- a/daemon/container_operations_unix.go +++ b/daemon/container_operations_unix.go @@ -17,7 +17,7 @@ import ( "github.com/docker/docker/daemon/execdriver" "github.com/docker/docker/daemon/links" "github.com/docker/docker/daemon/network" - derr "github.com/docker/docker/errors" + "github.com/docker/docker/errors" "github.com/docker/docker/pkg/fileutils" "github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/mount" @@ -45,7 +45,7 @@ func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]s for linkAlias, child := range children { if !child.IsRunning() { - return nil, derr.ErrorCodeLinkNotRunning.WithArgs(child.Name, linkAlias) + return nil, fmt.Errorf("Cannot link to a non running container: %s AS %s", child.Name, linkAlias) } childBridgeSettings := child.NetworkSettings.Networks["bridge"] @@ -509,7 +509,7 @@ func (daemon *Daemon) updateNetwork(container *container.Container) error { sb, err := ctrl.SandboxByID(sid) if err != nil { - return derr.ErrorCodeNoSandbox.WithArgs(sid, err) + return fmt.Errorf("error locating sandbox id %s: %v", sid, err) } // Find if container is connected to the default bridge network @@ -532,11 +532,11 @@ func (daemon *Daemon) updateNetwork(container *container.Container) error { options, err := daemon.buildSandboxOptions(container, n) if err != nil { - return derr.ErrorCodeNetworkUpdate.WithArgs(err) + return fmt.Errorf("Update network failed: %v", err) } if err := sb.Refresh(options...); err != nil { - return derr.ErrorCodeNetworkRefresh.WithArgs(sid, err) + return fmt.Errorf("Update network failed: Failure in refresh sandbox %s: %v", sid, err) } return nil @@ -730,7 +730,7 @@ func (daemon *Daemon) updateNetworkConfig(container *container.Container, idOrNa func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings) error { if !container.Running { if container.RemovalInProgress || container.Dead { - return derr.ErrorCodeRemovalContainer.WithArgs(container.ID) + return errRemovalContainer(container.ID) } if _, err := daemon.updateNetworkConfig(container, idOrName, endpointConfig, true); err != nil { return err @@ -810,7 +810,7 @@ func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName } if err := container.UpdateJoinInfo(n, ep); err != nil { - return derr.ErrorCodeJoinInfo.WithArgs(err) + return fmt.Errorf("Updating join info failed: %v", err) } daemon.LogNetworkEventWithAttributes(n, "connect", map[string]string{"container": container.ID}) @@ -833,7 +833,7 @@ func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n li } if !container.Running { if container.RemovalInProgress || container.Dead { - return derr.ErrorCodeRemovalContainer.WithArgs(container.ID) + return errRemovalContainer(container.ID) } if _, ok := container.NetworkSettings.Networks[n.Name()]; ok { delete(container.NetworkSettings.Networks, n.Name()) @@ -950,7 +950,7 @@ func (daemon *Daemon) setNetworkNamespaceKey(containerID string, pid int) error search := libnetwork.SandboxContainerWalker(&sandbox, containerID) daemon.netController.WalkSandboxes(search) if sandbox == nil { - return derr.ErrorCodeNoSandbox.WithArgs(containerID, "no sandbox found") + return fmt.Errorf("error locating sandbox id %s: no sandbox found", containerID) } return sandbox.SetKey(path) @@ -963,10 +963,10 @@ func (daemon *Daemon) getIpcContainer(container *container.Container) (*containe return nil, err } if !c.IsRunning() { - return nil, derr.ErrorCodeIPCRunning.WithArgs(containerID) + return nil, fmt.Errorf("cannot join IPC of a non running container: %s", containerID) } if c.IsRestarting() { - return nil, derr.ErrorCodeContainerRestarting.WithArgs(containerID) + return nil, errContainerIsRestarting(container.ID) } return c, nil } @@ -977,13 +977,14 @@ func (daemon *Daemon) getNetworkedContainer(containerID, connectedContainerID st return nil, err } if containerID == nc.ID { - return nil, derr.ErrorCodeJoinSelf + return nil, fmt.Errorf("cannot join own network") } if !nc.IsRunning() { - return nil, derr.ErrorCodeJoinRunning.WithArgs(connectedContainerID) + err := fmt.Errorf("cannot join network of a non running container: %s", connectedContainerID) + return nil, errors.NewRequestConflictError(err) } if nc.IsRestarting() { - return nil, derr.ErrorCodeContainerRestarting.WithArgs(connectedContainerID) + return nil, errContainerIsRestarting(connectedContainerID) } return nc, nil } @@ -1141,7 +1142,7 @@ func getDevicesFromPath(deviceMapping containertypes.DeviceMapping) (devs []*con return devs, nil } - return devs, derr.ErrorCodeDeviceInfo.WithArgs(deviceMapping.PathOnHost, err) + return devs, fmt.Errorf("error gathering device information while adding custom device %q: %s", deviceMapping.PathOnHost, err) } func mergeDevices(defaultDevices, userDevices []*configs.Device) []*configs.Device { @@ -1172,3 +1173,7 @@ func isLinkable(child *container.Container) bool { _, ok := child.NetworkSettings.Networks["bridge"] return ok } + +func errRemovalContainer(containerID string) error { + return fmt.Errorf("Container %s is marked for removal and cannot be connected or disconnected to the network", containerID) +} diff --git a/daemon/container_operations_windows.go b/daemon/container_operations_windows.go index b812bfc5f419a..02173d09f1ef9 100644 --- a/daemon/container_operations_windows.go +++ b/daemon/container_operations_windows.go @@ -3,12 +3,12 @@ package daemon import ( + "fmt" "strings" "github.com/docker/docker/container" "github.com/docker/docker/daemon/execdriver" "github.com/docker/docker/daemon/execdriver/windows" - derr "github.com/docker/docker/errors" "github.com/docker/docker/layer" networktypes "github.com/docker/engine-api/types/network" "github.com/docker/libnetwork" @@ -64,7 +64,7 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro } } default: - return derr.ErrorCodeInvalidNetworkMode.WithArgs(c.HostConfig.NetworkMode) + return fmt.Errorf("invalid network mode: %s", c.HostConfig.NetworkMode) } // TODO Windows. More resource controls to be implemented later. @@ -88,7 +88,7 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro var layerPaths []string img, err := daemon.imageStore.Get(c.ImageID) if err != nil { - return derr.ErrorCodeGetGraph.WithArgs(c.ImageID, err) + return fmt.Errorf("Failed to graph.Get on ImageID %s - %s", c.ImageID, err) } if img.RootFS != nil && img.RootFS.Type == "layers+base" { @@ -97,7 +97,7 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro img.RootFS.DiffIDs = img.RootFS.DiffIDs[:i] path, err := layer.GetLayerPath(daemon.layerStore, img.RootFS.ChainID()) if err != nil { - return derr.ErrorCodeGetLayer.WithArgs(err) + return fmt.Errorf("Failed to get layer path from graphdriver %s for ImageID %s - %s", daemon.layerStore, img.RootFS.ChainID(), err) } // Reverse order, expecting parent most first layerPaths = append([]string{path}, layerPaths...) @@ -106,7 +106,7 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro m, err := c.RWLayer.Metadata() if err != nil { - return derr.ErrorCodeGetLayerMetadata.WithArgs(err) + return fmt.Errorf("Failed to get layer metadata - %s", err) } layerFolder := m["dir"] diff --git a/daemon/create.go b/daemon/create.go index ca9e2c760c626..425c4344bb84a 100644 --- a/daemon/create.go +++ b/daemon/create.go @@ -1,9 +1,10 @@ package daemon import ( + "fmt" + "github.com/Sirupsen/logrus" "github.com/docker/docker/container" - derr "github.com/docker/docker/errors" "github.com/docker/docker/image" "github.com/docker/docker/layer" "github.com/docker/docker/pkg/idtools" @@ -18,7 +19,7 @@ import ( // ContainerCreate creates a container. func (daemon *Daemon) ContainerCreate(params types.ContainerCreateConfig) (types.ContainerCreateResponse, error) { if params.Config == nil { - return types.ContainerCreateResponse{}, derr.ErrorCodeEmptyConfig + return types.ContainerCreateResponse{}, fmt.Errorf("Config cannot be empty in order to create a container") } warnings, err := daemon.verifyContainerSettings(params.HostConfig, params.Config, false) @@ -174,7 +175,7 @@ func (daemon *Daemon) VolumeCreate(name, driverName string, opts map[string]stri v, err := daemon.volumes.Create(name, driverName, opts) if err != nil { if volumestore.IsNameConflict(err) { - return nil, derr.ErrorVolumeNameTaken.WithArgs(name) + return nil, fmt.Errorf("A volume named %s already exists. Choose a different volume name.", name) } return nil, err } diff --git a/daemon/create_unix.go b/daemon/create_unix.go index 8eca648deb002..ae369f13b9fd5 100644 --- a/daemon/create_unix.go +++ b/daemon/create_unix.go @@ -3,12 +3,12 @@ package daemon import ( + "fmt" "os" "path/filepath" "github.com/Sirupsen/logrus" "github.com/docker/docker/container" - derr "github.com/docker/docker/errors" "github.com/docker/docker/pkg/stringid" containertypes "github.com/docker/engine-api/types/container" "github.com/opencontainers/runc/libcontainer/label" @@ -41,7 +41,7 @@ func (daemon *Daemon) createContainerPlatformSpecificSettings(container *contain stat, err := os.Stat(path) if err == nil && !stat.IsDir() { - return derr.ErrorCodeMountOverFile.WithArgs(path) + return fmt.Errorf("cannot mount volume over existing file, file exists %s", path) } v, err := daemon.volumes.CreateWithRef(name, hostConfig.VolumeDriver, container.ID, nil) diff --git a/daemon/daemon.go b/daemon/daemon.go index c2b2d884b90d4..6199ddc653dce 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -6,7 +6,6 @@ package daemon import ( - "errors" "fmt" "io" "io/ioutil" @@ -15,6 +14,7 @@ import ( "path" "path/filepath" "runtime" + "strings" "sync" "syscall" "time" @@ -28,6 +28,7 @@ import ( "github.com/docker/docker/daemon/exec" "github.com/docker/docker/daemon/execdriver" "github.com/docker/docker/daemon/execdriver/execdrivers" + "github.com/docker/docker/errors" "github.com/docker/engine-api/types" containertypes "github.com/docker/engine-api/types/container" eventtypes "github.com/docker/engine-api/types/events" @@ -43,7 +44,6 @@ import ( dmetadata "github.com/docker/docker/distribution/metadata" "github.com/docker/docker/distribution/xfer" "github.com/docker/docker/dockerversion" - derr "github.com/docker/docker/errors" "github.com/docker/docker/image" "github.com/docker/docker/image/tarexport" "github.com/docker/docker/layer" @@ -90,7 +90,7 @@ var ( validContainerNameChars = utils.RestrictedNameChars validContainerNamePattern = utils.RestrictedNamePattern - errSystemNotSupported = errors.New("The Docker daemon is not supported on this platform.") + errSystemNotSupported = fmt.Errorf("The Docker daemon is not supported on this platform.") ) // ErrImageDoesNotExist is error returned when no image can be found for a reference. @@ -157,7 +157,8 @@ func (daemon *Daemon) GetContainer(prefixOrName string) (*container.Container, e if indexError != nil { // When truncindex defines an error type, use that instead if indexError == truncindex.ErrNotExist { - return nil, derr.ErrorCodeNoSuchContainer.WithArgs(prefixOrName) + err := fmt.Errorf("No such container: %s", prefixOrName) + return nil, errors.NewRequestNotFoundError(err) } return nil, indexError } @@ -1211,7 +1212,7 @@ func (daemon *Daemon) ImageHistory(name string) ([]*types.ImageHistory, error) { if !h.EmptyLayer { if len(img.RootFS.DiffIDs) <= layerCounter { - return nil, errors.New("too many non-empty layers in History section") + return nil, fmt.Errorf("too many non-empty layers in History section") } rootFS.Append(img.RootFS.DiffIDs[layerCounter]) @@ -1499,7 +1500,8 @@ func (daemon *Daemon) verifyNetworkingConfig(nwConfig *networktypes.NetworkingCo for k := range nwConfig.EndpointsConfig { l = append(l, k) } - return derr.ErrorCodeMultipleNetworkConnect.WithArgs(fmt.Sprintf("%v", l)) + err := fmt.Errorf("Container cannot be connected to network endpoints: %s", strings.Join(l, ", ")) + return errors.NewBadRequestError(err) } func configureVolumes(config *Config, rootUID, rootGID int) (*store.VolumeStore, error) { @@ -1671,7 +1673,7 @@ func convertLnNetworkStats(name string, stats *lntypes.InterfaceStatistics) *lib func validateID(id string) error { if id == "" { - return derr.ErrorCodeEmptyID + return fmt.Errorf("Invalid empty id") } return nil } diff --git a/daemon/daemon_unix.go b/daemon/daemon_unix.go index ca0d50f67f333..f47e42085236e 100644 --- a/daemon/daemon_unix.go +++ b/daemon/daemon_unix.go @@ -16,7 +16,6 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/docker/container" - derr "github.com/docker/docker/errors" "github.com/docker/docker/image" "github.com/docker/docker/layer" "github.com/docker/docker/pkg/idtools" @@ -312,17 +311,17 @@ func verifyContainerResources(resources *containertypes.Resources, sysInfo *sysi } cpusAvailable, err := sysInfo.IsCpusetCpusAvailable(resources.CpusetCpus) if err != nil { - return warnings, derr.ErrorCodeInvalidCpusetCpus.WithArgs(resources.CpusetCpus) + return warnings, fmt.Errorf("Invalid value %s for cpuset cpus.", resources.CpusetCpus) } if !cpusAvailable { - return warnings, derr.ErrorCodeNotAvailableCpusetCpus.WithArgs(resources.CpusetCpus, sysInfo.Cpus) + return warnings, fmt.Errorf("Requested CPUs are not available - requested %s, available: %s.", resources.CpusetCpus, sysInfo.Cpus) } memsAvailable, err := sysInfo.IsCpusetMemsAvailable(resources.CpusetMems) if err != nil { - return warnings, derr.ErrorCodeInvalidCpusetMems.WithArgs(resources.CpusetMems) + return warnings, fmt.Errorf("Invalid value %s for cpuset mems.", resources.CpusetMems) } if !memsAvailable { - return warnings, derr.ErrorCodeNotAvailableCpusetMems.WithArgs(resources.CpusetMems, sysInfo.Mems) + return warnings, fmt.Errorf("Requested memory nodes are not available - requested %s, available: %s.", resources.CpusetMems, sysInfo.Mems) } // blkio subsystem checks and adjustments diff --git a/daemon/delete.go b/daemon/delete.go index 6c56fd7ba14bc..75af4c01a1db2 100644 --- a/daemon/delete.go +++ b/daemon/delete.go @@ -8,7 +8,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/docker/container" - derr "github.com/docker/docker/errors" + "github.com/docker/docker/errors" "github.com/docker/docker/layer" volumestore "github.com/docker/docker/volume/store" "github.com/docker/engine-api/types" @@ -25,12 +25,8 @@ func (daemon *Daemon) ContainerRm(name string, config *types.ContainerRmConfig) } // Container state RemovalInProgress should be used to avoid races. - if err = container.SetRemovalInProgress(); err != nil { - if err == derr.ErrorCodeAlreadyRemoving { - // do not fail when the removal is in progress started by other request. - return nil - } - return derr.ErrorCodeRmState.WithArgs(container.ID, err) + if inProgress := container.SetRemovalInProgress(); inProgress { + return nil } defer container.ResetRemovalInProgress() @@ -84,10 +80,11 @@ func (daemon *Daemon) rmLink(container *container.Container, name string) error func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemove bool) (err error) { if container.IsRunning() { if !forceRemove { - return derr.ErrorCodeRmRunning.WithArgs(container.ID) + err := fmt.Errorf("You cannot remove a running container %s. Stop the container before attempting removal or use -f", container.ID) + return errors.NewRequestConflictError(err) } if err := daemon.Kill(container); err != nil { - return derr.ErrorCodeRmFailed.WithArgs(container.ID, err) + return fmt.Errorf("Could not kill running container %s, cannot remove - %v", container.ID, err) } } @@ -123,17 +120,17 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemo }() if err = os.RemoveAll(container.Root); err != nil { - return derr.ErrorCodeRmFS.WithArgs(container.ID, err) + return fmt.Errorf("Unable to remove filesystem for %v: %v", container.ID, err) } metadata, err := daemon.layerStore.ReleaseRWLayer(container.RWLayer) layer.LogReleaseMetadata(metadata) if err != nil && err != layer.ErrMountDoesNotExist { - return derr.ErrorCodeRmDriverFS.WithArgs(daemon.GraphDriverName(), container.ID, err) + return fmt.Errorf("Driver %s failed to remove root filesystem %s: %s", daemon.GraphDriverName(), container.ID, err) } if err = daemon.execDriver.Clean(container.ID); err != nil { - return derr.ErrorCodeRmExecDriver.WithArgs(container.ID, err) + return fmt.Errorf("Unable to remove execdriver data for %s: %s", container.ID, err) } return nil } @@ -149,9 +146,10 @@ func (daemon *Daemon) VolumeRm(name string) error { if err := daemon.volumes.Remove(v); err != nil { if volumestore.IsInUse(err) { - return derr.ErrorCodeRmVolumeInUse.WithArgs(err) + err := fmt.Errorf("Unable to remove volume, volume still in use: %v", err) + return errors.NewRequestConflictError(err) } - return derr.ErrorCodeRmVolume.WithArgs(name, err) + return fmt.Errorf("Error while removing volume %s: %v", name, err) } daemon.LogVolumeEvent(v.Name(), "destroy", map[string]string{"driver": v.DriverName()}) return nil diff --git a/daemon/delete_test.go b/daemon/delete_test.go index 0d39b4d68faf0..adce2eb8c5102 100644 --- a/daemon/delete_test.go +++ b/daemon/delete_test.go @@ -32,9 +32,7 @@ func TestContainerDoubleDelete(t *testing.T) { daemon.containers.Add(container.ID, container) // Mark the container as having a delete in progress - if err := container.SetRemovalInProgress(); err != nil { - t.Fatal(err) - } + container.SetRemovalInProgress() // Try to remove the container when it's start is removalInProgress. // It should ignore the container and not return an error. diff --git a/daemon/errors.go b/daemon/errors.go index 8fff66b9ff831..131c9a1e22a07 100644 --- a/daemon/errors.go +++ b/daemon/errors.go @@ -1,26 +1,57 @@ package daemon import ( + "fmt" "strings" - derr "github.com/docker/docker/errors" + "github.com/docker/docker/errors" "github.com/docker/docker/reference" ) func (d *Daemon) imageNotExistToErrcode(err error) error { if dne, isDNE := err.(ErrImageDoesNotExist); isDNE { if strings.Contains(dne.RefOrID, "@") { - return derr.ErrorCodeNoSuchImageHash.WithArgs(dne.RefOrID) + e := fmt.Errorf("No such image: %s", dne.RefOrID) + return errors.NewRequestNotFoundError(e) } tag := reference.DefaultTag ref, err := reference.ParseNamed(dne.RefOrID) if err != nil { - return derr.ErrorCodeNoSuchImageTag.WithArgs(dne.RefOrID, tag) + e := fmt.Errorf("No such image: %s:%s", dne.RefOrID, tag) + return errors.NewRequestNotFoundError(e) } if tagged, isTagged := ref.(reference.NamedTagged); isTagged { tag = tagged.Tag() } - return derr.ErrorCodeNoSuchImageTag.WithArgs(ref.Name(), tag) + e := fmt.Errorf("No such image: %s:%s", ref.Name(), tag) + return errors.NewRequestNotFoundError(e) } return err } + +type errNotRunning struct { + containerID string +} + +func (e errNotRunning) Error() string { + return fmt.Sprintf("Container %s is not running", e.containerID) +} + +func (e errNotRunning) ContainerIsRunning() bool { + return false +} + +func errContainerIsRestarting(containerID string) error { + err := fmt.Errorf("Container %s is restarting, wait until the container is running", containerID) + return errors.NewRequestConflictError(err) +} + +func errExecNotFound(id string) error { + err := fmt.Errorf("No such exec instance '%s' found in daemon", id) + return errors.NewRequestNotFoundError(err) +} + +func errExecPaused(id string) error { + err := fmt.Errorf("Container %s is paused, unpause the container before exec", id) + return errors.NewRequestConflictError(err) +} diff --git a/daemon/exec.go b/daemon/exec.go index 08b6ac46ffcd3..138e437061624 100644 --- a/daemon/exec.go +++ b/daemon/exec.go @@ -1,6 +1,7 @@ package daemon import ( + "fmt" "io" "strings" "time" @@ -9,7 +10,7 @@ import ( "github.com/docker/docker/container" "github.com/docker/docker/daemon/exec" "github.com/docker/docker/daemon/execdriver" - derr "github.com/docker/docker/errors" + "github.com/docker/docker/errors" "github.com/docker/docker/pkg/pools" "github.com/docker/docker/pkg/promise" "github.com/docker/docker/pkg/term" @@ -47,19 +48,19 @@ func (d *Daemon) getExecConfig(name string) (*exec.Config, error) { if ec != nil { if container := d.containers.Get(ec.ContainerID); container != nil { if !container.IsRunning() { - return nil, derr.ErrorCodeContainerNotRunning.WithArgs(container.ID, container.State.String()) + return nil, fmt.Errorf("Container %s is not running: %s", container.ID, container.State.String()) } if container.IsPaused() { - return nil, derr.ErrorCodeExecPaused.WithArgs(container.ID) + return nil, errExecPaused(container.ID) } if container.IsRestarting() { - return nil, derr.ErrorCodeContainerRestarting.WithArgs(container.ID) + return nil, errContainerIsRestarting(container.ID) } return ec, nil } } - return nil, derr.ErrorCodeNoExecID.WithArgs(name) + return nil, errExecNotFound(name) } func (d *Daemon) unregisterExecCommand(container *container.Container, execConfig *exec.Config) { @@ -74,13 +75,13 @@ func (d *Daemon) getActiveContainer(name string) (*container.Container, error) { } if !container.IsRunning() { - return nil, derr.ErrorCodeNotRunning.WithArgs(name) + return nil, errNotRunning{container.ID} } if container.IsPaused() { - return nil, derr.ErrorCodeExecPaused.WithArgs(name) + return nil, errExecPaused(name) } if container.IsRestarting() { - return nil, derr.ErrorCodeContainerRestarting.WithArgs(name) + return nil, errContainerIsRestarting(container.ID) } return container, nil } @@ -137,18 +138,19 @@ func (d *Daemon) ContainerExecStart(name string, stdin io.ReadCloser, stdout io. ec, err := d.getExecConfig(name) if err != nil { - return derr.ErrorCodeNoExecID.WithArgs(name) + return errExecNotFound(name) } ec.Lock() if ec.ExitCode != nil { ec.Unlock() - return derr.ErrorCodeExecExited.WithArgs(ec.ID) + err := fmt.Errorf("Error: Exec command %s has already run", ec.ID) + return errors.NewRequestConflictError(err) } if ec.Running { ec.Unlock() - return derr.ErrorCodeExecRunning.WithArgs(ec.ID) + return fmt.Errorf("Error: Exec command %s is already running", ec.ID) } ec.Running = true ec.Unlock() @@ -194,12 +196,12 @@ func (d *Daemon) ContainerExecStart(name string, stdin io.ReadCloser, stdout io. select { case err := <-attachErr: if err != nil { - return derr.ErrorCodeExecAttach.WithArgs(err) + return fmt.Errorf("attach failed with error: %v", err) } return nil case err := <-execErr: if aErr := <-attachErr; aErr != nil && err == nil { - return derr.ErrorCodeExecAttach.WithArgs(aErr) + return fmt.Errorf("attach failed with error: %v", aErr) } if err == nil { return nil @@ -207,9 +209,9 @@ func (d *Daemon) ContainerExecStart(name string, stdin io.ReadCloser, stdout io. // Maybe the container stopped while we were trying to exec if !c.IsRunning() { - return derr.ErrorCodeExecContainerStopped + return fmt.Errorf("container stopped while running exec: %s", c.ID) } - return derr.ErrorCodeExecCantRun.WithArgs(ec.ID, c.ID, err) + return fmt.Errorf("Cannot run exec command %s in container %s: %s", ec.ID, c.ID, err) } } diff --git a/daemon/exec/exec.go b/daemon/exec/exec.go index 6941cde689ea0..2efb20ee9a8fa 100644 --- a/daemon/exec/exec.go +++ b/daemon/exec/exec.go @@ -1,11 +1,11 @@ package exec import ( + "fmt" "sync" "time" "github.com/docker/docker/daemon/execdriver" - derr "github.com/docker/docker/errors" "github.com/docker/docker/pkg/stringid" "github.com/docker/docker/runconfig" ) @@ -116,7 +116,7 @@ func (c *Config) Resize(h, w int) error { select { case <-c.waitStart: case <-time.After(time.Second): - return derr.ErrorCodeExecResize.WithArgs(c.ID) + return fmt.Errorf("Exec %s is not running, so it can not be resized.", c.ID) } return c.ProcessConfig.Terminal.Resize(h, w) } diff --git a/daemon/execdriver/native/create.go b/daemon/execdriver/native/create.go index ba14693abf9dc..103791d7c9885 100644 --- a/daemon/execdriver/native/create.go +++ b/daemon/execdriver/native/create.go @@ -9,7 +9,6 @@ import ( "syscall" "github.com/docker/docker/daemon/execdriver" - derr "github.com/docker/docker/errors" "github.com/docker/docker/pkg/mount" "github.com/docker/docker/profiles/seccomp" @@ -430,7 +429,7 @@ func (d *Driver) setupMounts(container *configs.Config, c *execdriver.Command) e for _, m := range c.Mounts { for _, cm := range container.Mounts { if cm.Destination == m.Destination { - return derr.ErrorCodeMountDup.WithArgs(m.Destination) + return fmt.Errorf("Duplicate mount point '%s'", m.Destination) } } diff --git a/daemon/export.go b/daemon/export.go index 9e3d8da340a32..80d7dbb2e17d0 100644 --- a/daemon/export.go +++ b/daemon/export.go @@ -1,10 +1,10 @@ package daemon import ( + "fmt" "io" "github.com/docker/docker/container" - derr "github.com/docker/docker/errors" "github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/ioutils" ) @@ -19,13 +19,13 @@ func (daemon *Daemon) ContainerExport(name string, out io.Writer) error { data, err := daemon.containerExport(container) if err != nil { - return derr.ErrorCodeExportFailed.WithArgs(name, err) + return fmt.Errorf("Error exporting container %s: %v", name, err) } defer data.Close() // Stream the entire contents of the container (basically a volatile snapshot) if _, err := io.Copy(out, data); err != nil { - return derr.ErrorCodeExportFailed.WithArgs(name, err) + return fmt.Errorf("Error exporting container %s: %v", name, err) } return nil } diff --git a/daemon/image_delete.go b/daemon/image_delete.go index 497927b643d7b..7c6329a669b28 100644 --- a/daemon/image_delete.go +++ b/daemon/image_delete.go @@ -5,7 +5,7 @@ import ( "strings" "github.com/docker/docker/container" - derr "github.com/docker/docker/errors" + "github.com/docker/docker/errors" "github.com/docker/docker/image" "github.com/docker/docker/pkg/stringid" "github.com/docker/docker/reference" @@ -82,7 +82,8 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I // this image would remain "dangling" and since // we really want to avoid that the client must // explicitly force its removal. - return nil, derr.ErrorCodeImgDelUsed.WithArgs(imageRef, stringid.TruncateID(container.ID), stringid.TruncateID(imgID.String())) + err := fmt.Errorf("conflict: unable to remove repository reference %q (must force) - container %s is using its referenced image %s", imageRef, stringid.TruncateID(container.ID), stringid.TruncateID(imgID.String())) + return nil, errors.NewRequestConflictError(err) } } diff --git a/daemon/kill.go b/daemon/kill.go index 2bb695699c034..2115c7791f0f9 100644 --- a/daemon/kill.go +++ b/daemon/kill.go @@ -8,7 +8,6 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/docker/container" - derr "github.com/docker/docker/errors" "github.com/docker/docker/pkg/signal" ) @@ -45,11 +44,11 @@ func (daemon *Daemon) killWithSignal(container *container.Container, sig int) er // We could unpause the container for them rather than returning this error if container.Paused { - return derr.ErrorCodeUnpauseContainer.WithArgs(container.ID) + return fmt.Errorf("Container %s is paused. Unpause the container before stopping", container.ID) } if !container.Running { - return derr.ErrorCodeNotRunning.WithArgs(container.ID) + return errNotRunning{container.ID} } container.ExitOnNext() @@ -62,7 +61,7 @@ func (daemon *Daemon) killWithSignal(container *container.Container, sig int) er } if err := daemon.kill(container, sig); err != nil { - return derr.ErrorCodeCantKill.WithArgs(container.ID, err) + return fmt.Errorf("Cannot kill container %s: %s", container.ID, err) } attributes := map[string]string{ @@ -75,7 +74,7 @@ func (daemon *Daemon) killWithSignal(container *container.Container, sig int) er // Kill forcefully terminates a container. func (daemon *Daemon) Kill(container *container.Container) error { if !container.IsRunning() { - return derr.ErrorCodeNotRunning.WithArgs(container.ID) + return errNotRunning{container.ID} } // 1. Send SIGKILL diff --git a/daemon/logs.go b/daemon/logs.go index eb6fa54ae68c9..1e94802399387 100644 --- a/daemon/logs.go +++ b/daemon/logs.go @@ -1,6 +1,7 @@ package daemon import ( + "fmt" "io" "strconv" "time" @@ -10,7 +11,6 @@ import ( "github.com/docker/docker/container" "github.com/docker/docker/daemon/logger" "github.com/docker/docker/daemon/logger/jsonfilelog" - derr "github.com/docker/docker/errors" "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/stdcopy" timetypes "github.com/docker/engine-api/types/time" @@ -21,11 +21,11 @@ import ( func (daemon *Daemon) ContainerLogs(containerName string, config *backend.ContainerLogsConfig, started chan struct{}) error { container, err := daemon.GetContainer(containerName) if err != nil { - return derr.ErrorCodeNoSuchContainer.WithArgs(containerName) + return err } if !(config.ShowStdout || config.ShowStderr) { - return derr.ErrorCodeNeedStream + return fmt.Errorf("You must choose at least one stream") } cLog, err := daemon.getLogger(container) @@ -122,7 +122,7 @@ func (daemon *Daemon) StartLogging(container *container.Container) error { } l, err := container.StartLogger(cfg) if err != nil { - return derr.ErrorCodeInitLogger.WithArgs(err) + return fmt.Errorf("Failed to initialize logging driver: %v", err) } copier := logger.NewCopier(container.ID, map[string]io.Reader{"stdout": container.StdoutPipe(), "stderr": container.StderrPipe()}, l) diff --git a/daemon/mounts.go b/daemon/mounts.go index 276301d130a52..d4f24b28121d3 100644 --- a/daemon/mounts.go +++ b/daemon/mounts.go @@ -1,10 +1,10 @@ package daemon import ( + "fmt" "strings" "github.com/docker/docker/container" - derr "github.com/docker/docker/errors" volumestore "github.com/docker/docker/volume/store" ) @@ -42,7 +42,7 @@ func (daemon *Daemon) removeMountPoints(container *container.Container, rm bool) } } if len(rmErrors) > 0 { - return derr.ErrorCodeRemovingVolume.WithArgs(strings.Join(rmErrors, "\n")) + return fmt.Errorf("Error removing volumes:\n%v", strings.Join(rmErrors, "\n")) } return nil } diff --git a/daemon/network.go b/daemon/network.go index 5a36b5c1b4267..e937391b831fa 100644 --- a/daemon/network.go +++ b/daemon/network.go @@ -3,9 +3,10 @@ package daemon import ( "fmt" "net" + "net/http" "strings" - derr "github.com/docker/docker/errors" + "github.com/docker/docker/errors" "github.com/docker/docker/runconfig" "github.com/docker/engine-api/types/network" "github.com/docker/libnetwork" @@ -191,7 +192,8 @@ func (daemon *Daemon) DeleteNetwork(networkID string) error { } if runconfig.IsPreDefinedNetwork(nw.Name()) { - return derr.ErrorCodeCantDeletePredefinedNetwork.WithArgs(nw.Name()) + err := fmt.Errorf("%s is a pre-defined network and cannot be removed", nw.Name()) + return errors.NewErrorWithStatusCode(err, http.StatusForbidden) } if err := nw.Delete(); err != nil { diff --git a/daemon/pause.go b/daemon/pause.go index a8ce013d4f301..2ec0df7030c65 100644 --- a/daemon/pause.go +++ b/daemon/pause.go @@ -1,8 +1,9 @@ package daemon import ( + "fmt" + "github.com/docker/docker/container" - derr "github.com/docker/docker/errors" ) // ContainerPause pauses a container @@ -27,21 +28,21 @@ func (daemon *Daemon) containerPause(container *container.Container) error { // We cannot Pause the container which is not running if !container.Running { - return derr.ErrorCodeNotRunning.WithArgs(container.ID) + return errNotRunning{container.ID} } // We cannot Pause the container which is already paused if container.Paused { - return derr.ErrorCodeAlreadyPaused.WithArgs(container.ID) + return fmt.Errorf("Container %s is already paused", container.ID) } // We cannot Pause the container which is restarting if container.Restarting { - return derr.ErrorCodeContainerRestarting.WithArgs(container.ID) + return errContainerIsRestarting(container.ID) } if err := daemon.execDriver.Pause(container.Command); err != nil { - return derr.ErrorCodeCantPause.WithArgs(container.ID, err) + return fmt.Errorf("Cannot pause container %s: %s", container.ID, err) } container.Paused = true daemon.LogContainerEvent(container, "pause") diff --git a/daemon/rename.go b/daemon/rename.go index 2f903d9324275..363a7f8bf43f8 100644 --- a/daemon/rename.go +++ b/daemon/rename.go @@ -1,10 +1,10 @@ package daemon import ( + "fmt" "strings" "github.com/Sirupsen/logrus" - derr "github.com/docker/docker/errors" "github.com/docker/libnetwork" ) @@ -18,7 +18,7 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) error { ) if oldName == "" || newName == "" { - return derr.ErrorCodeEmptyRename + return fmt.Errorf("Neither old nor new names may be empty") } container, err := daemon.GetContainer(oldName) @@ -31,7 +31,7 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) error { container.Lock() defer container.Unlock() if newName, err = daemon.reserveName(container.ID, newName); err != nil { - return derr.ErrorCodeRenameTaken.WithArgs(err) + return fmt.Errorf("Error when allocating new name: %v", err) } container.Name = newName diff --git a/daemon/resize.go b/daemon/resize.go index c326248c924fd..d7bb105b368a4 100644 --- a/daemon/resize.go +++ b/daemon/resize.go @@ -1,10 +1,6 @@ package daemon -import ( - "fmt" - - derr "github.com/docker/docker/errors" -) +import "fmt" // ContainerResize changes the size of the TTY of the process running // in the container with the given name to the given height and width. @@ -15,7 +11,7 @@ func (daemon *Daemon) ContainerResize(name string, height, width int) error { } if !container.IsRunning() { - return derr.ErrorCodeNotRunning.WithArgs(container.ID) + return errNotRunning{container.ID} } if err = container.Resize(height, width); err == nil { diff --git a/daemon/restart.go b/daemon/restart.go index 8ee16918cb687..3779116cfaabe 100644 --- a/daemon/restart.go +++ b/daemon/restart.go @@ -1,8 +1,9 @@ package daemon import ( + "fmt" + "github.com/docker/docker/container" - derr "github.com/docker/docker/errors" ) // ContainerRestart stops and starts a container. It attempts to @@ -17,7 +18,7 @@ func (daemon *Daemon) ContainerRestart(name string, seconds int) error { return err } if err := daemon.containerRestart(container, seconds); err != nil { - return derr.ErrorCodeCantRestart.WithArgs(name, err) + return fmt.Errorf("Cannot restart container %s: %v", name, err) } return nil } diff --git a/daemon/start.go b/daemon/start.go index bf697442d5473..532c6b48dbc00 100644 --- a/daemon/start.go +++ b/daemon/start.go @@ -2,11 +2,12 @@ package daemon import ( "fmt" + "net/http" "runtime" "github.com/Sirupsen/logrus" "github.com/docker/docker/container" - derr "github.com/docker/docker/errors" + "github.com/docker/docker/errors" "github.com/docker/docker/runconfig" containertypes "github.com/docker/engine-api/types/container" ) @@ -19,11 +20,12 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.Hos } if container.IsPaused() { - return derr.ErrorCodeStartPaused + return fmt.Errorf("Cannot start a paused container, try unpause instead.") } if container.IsRunning() { - return derr.ErrorCodeAlreadyStarted + err := fmt.Errorf("Container already started") + return errors.NewErrorWithStatusCode(err, http.StatusNotModified) } // Windows does not have the backwards compatibility issue here. @@ -52,7 +54,7 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.Hos } } else { if hostConfig != nil { - return derr.ErrorCodeHostConfigStart + return fmt.Errorf("Supplying a hostconfig on start is not supported. It should be supplied on create") } } @@ -88,7 +90,7 @@ func (daemon *Daemon) containerStart(container *container.Container) (err error) } if container.RemovalInProgress || container.Dead { - return derr.ErrorCodeContainerBeingRemoved + return fmt.Errorf("Container is marked for removal and cannot be started.") } // if we encounter an error during start we need to ensure that any other diff --git a/daemon/stats_collector_unix.go b/daemon/stats_collector_unix.go index 2fd368cd3446c..a8de5a2062629 100644 --- a/daemon/stats_collector_unix.go +++ b/daemon/stats_collector_unix.go @@ -4,6 +4,7 @@ package daemon import ( "bufio" + "fmt" "os" "strconv" "strings" @@ -13,7 +14,6 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/docker/container" "github.com/docker/docker/daemon/execdriver" - derr "github.com/docker/docker/errors" "github.com/docker/docker/pkg/pubsub" "github.com/opencontainers/runc/libcontainer/system" ) @@ -163,13 +163,13 @@ func (s *statsCollector) getSystemCPUUsage() (uint64, error) { switch parts[0] { case "cpu": if len(parts) < 8 { - return 0, derr.ErrorCodeBadCPUFields + return 0, fmt.Errorf("invalid number of cpu fields") } var totalClockTicks uint64 for _, i := range parts[1:8] { v, err := strconv.ParseUint(i, 10, 64) if err != nil { - return 0, derr.ErrorCodeBadCPUInt.WithArgs(i, err) + return 0, fmt.Errorf("Unable to convert value %s to int: %s", i, err) } totalClockTicks += v } @@ -177,5 +177,5 @@ func (s *statsCollector) getSystemCPUUsage() (uint64, error) { s.clockTicksPerSecond, nil } } - return 0, derr.ErrorCodeBadStatFormat + return 0, fmt.Errorf("invalid stat format. Error trying to parse the '/proc/stat' file") } diff --git a/daemon/stop.go b/daemon/stop.go index 55e3787751fd5..701743008aa0a 100644 --- a/daemon/stop.go +++ b/daemon/stop.go @@ -1,11 +1,13 @@ package daemon import ( + "fmt" + "net/http" "time" "github.com/Sirupsen/logrus" "github.com/docker/docker/container" - derr "github.com/docker/docker/errors" + "github.com/docker/docker/errors" ) // ContainerStop looks for the given container and terminates it, @@ -20,10 +22,11 @@ func (daemon *Daemon) ContainerStop(name string, seconds int) error { return err } if !container.IsRunning() { - return derr.ErrorCodeStopped.WithArgs(name) + err := fmt.Errorf("Container %s is already stopped", name) + return errors.NewErrorWithStatusCode(err, http.StatusNotModified) } if err := daemon.containerStop(container, seconds); err != nil { - return derr.ErrorCodeCantStop.WithArgs(name, err) + return fmt.Errorf("Cannot stop container %s: %v", name, err) } return nil } diff --git a/daemon/top_unix.go b/daemon/top_unix.go index 6d92592eb6248..1f8ab07f04bc9 100644 --- a/daemon/top_unix.go +++ b/daemon/top_unix.go @@ -3,11 +3,11 @@ package daemon import ( + "fmt" "os/exec" "strconv" "strings" - derr "github.com/docker/docker/errors" "github.com/docker/engine-api/types" ) @@ -27,11 +27,11 @@ func (daemon *Daemon) ContainerTop(name string, psArgs string) (*types.Container } if !container.IsRunning() { - return nil, derr.ErrorCodeNotRunning.WithArgs(name) + return nil, errNotRunning{container.ID} } if container.IsRestarting() { - return nil, derr.ErrorCodeContainerRestarting.WithArgs(name) + return nil, errContainerIsRestarting(container.ID) } pids, err := daemon.ExecutionDriver().GetPidsForContainer(container.ID) if err != nil { @@ -40,7 +40,7 @@ func (daemon *Daemon) ContainerTop(name string, psArgs string) (*types.Container output, err := exec.Command("ps", strings.Split(psArgs, " ")...).Output() if err != nil { - return nil, derr.ErrorCodePSError.WithArgs(err) + return nil, fmt.Errorf("Error running ps: %v", err) } procList := &types.ContainerProcessList{} @@ -55,7 +55,7 @@ func (daemon *Daemon) ContainerTop(name string, psArgs string) (*types.Container } } if pidIndex == -1 { - return nil, derr.ErrorCodeNoPID + return nil, fmt.Errorf("Couldn't find PID field in ps output") } // loop through the output and extract the PID from each line @@ -66,7 +66,7 @@ func (daemon *Daemon) ContainerTop(name string, psArgs string) (*types.Container fields := strings.Fields(line) p, err := strconv.Atoi(fields[pidIndex]) if err != nil { - return nil, derr.ErrorCodeBadPID.WithArgs(fields[pidIndex], err) + return nil, fmt.Errorf("Unexpected pid '%s': %s", fields[pidIndex], err) } for _, pid := range pids { diff --git a/daemon/top_windows.go b/daemon/top_windows.go index dc4cace65d50e..8b4fb2c6f0c29 100644 --- a/daemon/top_windows.go +++ b/daemon/top_windows.go @@ -1,11 +1,12 @@ package daemon import ( - derr "github.com/docker/docker/errors" + "fmt" + "github.com/docker/engine-api/types" ) // ContainerTop is not supported on Windows and returns an error. func (daemon *Daemon) ContainerTop(name string, psArgs string) (*types.ContainerProcessList, error) { - return nil, derr.ErrorCodeNoTop + return nil, fmt.Errorf("Top is not supported on Windows") } diff --git a/daemon/unpause.go b/daemon/unpause.go index ace52593d7a1a..4af6f11222bf5 100644 --- a/daemon/unpause.go +++ b/daemon/unpause.go @@ -1,8 +1,9 @@ package daemon import ( + "fmt" + "github.com/docker/docker/container" - derr "github.com/docker/docker/errors" ) // ContainerUnpause unpauses a container @@ -26,16 +27,16 @@ func (daemon *Daemon) containerUnpause(container *container.Container) error { // We cannot unpause the container which is not running if !container.Running { - return derr.ErrorCodeNotRunning.WithArgs(container.ID) + return errNotRunning{container.ID} } // We cannot unpause the container which is not paused if !container.Paused { - return derr.ErrorCodeNotPaused.WithArgs(container.ID) + return fmt.Errorf("Container %s is not paused", container.ID) } if err := daemon.execDriver.Unpause(container.Command); err != nil { - return derr.ErrorCodeCantUnpause.WithArgs(container.ID, err) + return fmt.Errorf("Cannot unpause container %s: %s", container.ID, err) } container.Paused = false diff --git a/daemon/update.go b/daemon/update.go index ccd0b2cc9050f..ffdcc852bddf1 100644 --- a/daemon/update.go +++ b/daemon/update.go @@ -4,7 +4,6 @@ import ( "fmt" "time" - derr "github.com/docker/docker/errors" "github.com/docker/engine-api/types/container" ) @@ -57,18 +56,16 @@ func (daemon *Daemon) update(name string, hostConfig *container.HostConfig) erro }() if container.RemovalInProgress || container.Dead { - errMsg := fmt.Errorf("Container is marked for removal and cannot be \"update\".") - return derr.ErrorCodeCantUpdate.WithArgs(container.ID, errMsg) + return errCannotUpdate(container.ID, fmt.Errorf("Container is marked for removal and cannot be \"update\".")) } if container.IsRunning() && hostConfig.KernelMemory != 0 { - errMsg := fmt.Errorf("Can not update kernel memory to a running container, please stop it first.") - return derr.ErrorCodeCantUpdate.WithArgs(container.ID, errMsg) + return errCannotUpdate(container.ID, fmt.Errorf("Can not update kernel memory to a running container, please stop it first.")) } if err := container.UpdateContainer(hostConfig); err != nil { restoreConfig = true - return derr.ErrorCodeCantUpdate.WithArgs(container.ID, err.Error()) + return errCannotUpdate(container.ID, err) } // if Restart Policy changed, we need to update container monitor @@ -86,7 +83,7 @@ func (daemon *Daemon) update(name string, hostConfig *container.HostConfig) erro if container.IsRunning() && !container.IsRestarting() { if err := daemon.execDriver.Update(container.Command); err != nil { restoreConfig = true - return derr.ErrorCodeCantUpdate.WithArgs(container.ID, err.Error()) + return errCannotUpdate(container.ID, err) } } @@ -94,3 +91,7 @@ func (daemon *Daemon) update(name string, hostConfig *container.HostConfig) erro return nil } + +func errCannotUpdate(containerID string, err error) error { + return fmt.Errorf("Cannot update container %s: %v", containerID, err) +} diff --git a/daemon/volumes.go b/daemon/volumes.go index cf0e11c6c4082..71ec70a1f6153 100644 --- a/daemon/volumes.go +++ b/daemon/volumes.go @@ -2,13 +2,13 @@ package daemon import ( "errors" + "fmt" "os" "path/filepath" "strings" "github.com/docker/docker/container" "github.com/docker/docker/daemon/execdriver" - derr "github.com/docker/docker/errors" "github.com/docker/docker/volume" "github.com/docker/engine-api/types" containertypes "github.com/docker/engine-api/types/container" @@ -114,7 +114,7 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo } if binds[bind.Destination] { - return derr.ErrorCodeMountDup.WithArgs(bind.Destination) + return fmt.Errorf("Duplicate mount point '%s'", bind.Destination) } if len(bind.Name) > 0 { diff --git a/daemon/volumes_windows.go b/daemon/volumes_windows.go index 05a45c385dca4..23c6a3b5e3c2c 100644 --- a/daemon/volumes_windows.go +++ b/daemon/volumes_windows.go @@ -3,11 +3,11 @@ package daemon import ( + "fmt" "sort" "github.com/docker/docker/container" "github.com/docker/docker/daemon/execdriver" - derr "github.com/docker/docker/errors" "github.com/docker/docker/volume" ) @@ -27,7 +27,7 @@ func (daemon *Daemon) setupMounts(container *container.Container) ([]execdriver. s = mount.Volume.Path() } if s == "" { - return nil, derr.ErrorCodeVolumeNoSourceForMount.WithArgs(mount.Name, mount.Driver, mount.Destination) + return nil, fmt.Errorf("No source for mount name '%s' driver %q destination '%s'", mount.Name, mount.Driver, mount.Destination) } mnts = append(mnts, execdriver.Mount{ Source: s, diff --git a/docker/daemon.go b/docker/daemon.go index 2020c2cac9c26..7eac2a1002076 100644 --- a/docker/daemon.go +++ b/docker/daemon.go @@ -14,6 +14,7 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/distribution/uuid" apiserver "github.com/docker/docker/api/server" + "github.com/docker/docker/api/server/router" "github.com/docker/docker/api/server/router/build" "github.com/docker/docker/api/server/router/container" "github.com/docker/docker/api/server/router/image" @@ -396,11 +397,16 @@ func loadDaemonCliConfig(config *daemon.Config, daemonFlags *flag.FlagSet, commo } func initRouter(s *apiserver.Server, d *daemon.Daemon) { - s.InitRouter(utils.IsDebugEnabled(), + routers := []router.Router{ container.NewRouter(d), image.NewRouter(d), - network.NewRouter(d), systemrouter.NewRouter(d), volume.NewRouter(d), - build.NewRouter(dockerfile.NewBuildManager(d))) + build.NewRouter(dockerfile.NewBuildManager(d)), + } + if d.NetworkControllerEnabled() { + routers = append(routers, network.NewRouter(d)) + } + + s.InitRouter(utils.IsDebugEnabled(), routers...) } diff --git a/errors/README.md b/errors/README.md deleted file mode 100644 index 81fa04cccd691..0000000000000 --- a/errors/README.md +++ /dev/null @@ -1,58 +0,0 @@ -Docker 'errors' package -======================= - -This package contains all of the error messages generated by the Docker -engine that might be exposed via the Docker engine's REST API. - -Each top-level engine package will have its own file in this directory -so that there's a clear grouping of errors, instead of just one big -file. The errors for each package are defined here instead of within -their respective package structure so that Docker CLI code that may need -to import these error definition files will not need to know or understand -the engine's package/directory structure. In other words, all they should -need to do is import `.../docker/errors` and they will automatically -pick up all Docker engine defined errors. This also gives the engine -developers the freedom to change the engine packaging structure (e.g. to -CRUD packages) without worrying about breaking existing clients. - -These errors are defined using the 'errcode' package. The `errcode` package -allows for each error to be typed and include all information necessary to -have further processing done on them if necessary. In particular, each error -includes: - -* Value - a unique string (in all caps) associated with this error. -Typically, this string is the same name as the variable name of the error -(w/o the `ErrorCode` text) but in all caps. - -* Message - the human readable sentence that will be displayed for this -error. It can contain '%s' substitutions that allows for the code generating -the error to specify values that will be inserted in the string prior to -being displayed to the end-user. The `WithArgs()` function can be used to -specify the insertion strings. Note, the evaluation of the strings will be -done at the time `WithArgs()` is called. - -* Description - additional human readable text to further explain the -circumstances of the error situation. - -* HTTPStatusCode - when the error is returned back to a CLI, this value -will be used to populate the HTTP status code. If not present the default -value will be `StatusInternalServerError`, 500. - -Not all errors generated within the engine's executable will be propagated -back to the engine's API layer. For example, it is expected that errors -generated by vendored code (under `docker/vendor`) and packaged code -(under `docker/pkg`) will be converted into errors defined by this package. - -When processing an errcode error, if you are looking for a particular -error then you can do something like: - -``` -import derr "github.com/docker/docker/errors" - -... - -err := someFunc() -if err.ErrorCode() == derr.ErrorCodeNoSuchContainer { - ... -} -``` diff --git a/errors/builder.go b/errors/builder.go deleted file mode 100644 index 38d0d3c391654..0000000000000 --- a/errors/builder.go +++ /dev/null @@ -1,93 +0,0 @@ -package errors - -// This file contains all of the errors that can be generated from the -// docker/builder component. - -import ( - "net/http" - - "github.com/docker/distribution/registry/api/errcode" -) - -var ( - // ErrorCodeAtLeastOneArg is generated when the parser comes across a - // Dockerfile command that doesn't have any args. - ErrorCodeAtLeastOneArg = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "ATLEASTONEARG", - Message: "%s requires at least one argument", - Description: "The specified command requires at least one argument", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeExactlyOneArg is generated when the parser comes across a - // Dockerfile command that requires exactly one arg but got less/more. - ErrorCodeExactlyOneArg = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "EXACTLYONEARG", - Message: "%s requires exactly one argument", - Description: "The specified command requires exactly one argument", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeAtLeastTwoArgs is generated when the parser comes across a - // Dockerfile command that requires at least two args but got less. - ErrorCodeAtLeastTwoArgs = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "ATLEASTTWOARGS", - Message: "%s requires at least two arguments", - Description: "The specified command requires at least two arguments", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeTooManyArgs is generated when the parser comes across a - // Dockerfile command that has more args than it should - ErrorCodeTooManyArgs = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "TOOMANYARGS", - Message: "Bad input to %s, too many args", - Description: "The specified command was passed too many arguments", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeChainOnBuild is generated when the parser comes across a - // Dockerfile command that is trying to chain ONBUILD commands. - ErrorCodeChainOnBuild = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "CHAINONBUILD", - Message: "Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed", - Description: "ONBUILD Dockerfile commands aren't allow on ONBUILD commands", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeBadOnBuildCmd is generated when the parser comes across a - // an ONBUILD Dockerfile command with an invalid trigger/command. - ErrorCodeBadOnBuildCmd = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "BADONBUILDCMD", - Message: "%s isn't allowed as an ONBUILD trigger", - Description: "The specified ONBUILD command isn't allowed", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeMissingFrom is generated when the Dockerfile is missing - // a FROM command. - ErrorCodeMissingFrom = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "MISSINGFROM", - Message: "Please provide a source image with `from` prior to run", - Description: "The Dockerfile is missing a FROM command", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeNotOnWindows is generated when the specified Dockerfile - // command is not supported on Windows. - ErrorCodeNotOnWindows = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "NOTONWINDOWS", - Message: "%s is not supported on Windows", - Description: "The specified Dockerfile command is not supported on Windows", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeVolumeEmpty is generated when the specified Volume string - // is empty. - ErrorCodeVolumeEmpty = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "VOLUMEEMPTY", - Message: "Volume specified can not be an empty string", - Description: "The specified volume can not be an empty string", - HTTPStatusCode: http.StatusInternalServerError, - }) -) diff --git a/errors/daemon.go b/errors/daemon.go deleted file mode 100644 index f601dd6a1b0d8..0000000000000 --- a/errors/daemon.go +++ /dev/null @@ -1,1013 +0,0 @@ -package errors - -// This file contains all of the errors that can be generated from the -// docker/daemon component. - -import ( - "net/http" - - "github.com/docker/distribution/registry/api/errcode" -) - -var ( - // ErrorCodeNoSuchContainer is generated when we look for a container by - // name or ID and we can't find it. - ErrorCodeNoSuchContainer = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "NOSUCHCONTAINER", - Message: "No such container: %s", - Description: "The specified container can not be found", - 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", - Description: "An attempt was made to load the storage driver for a container that is not registered with the daemon", - 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.", - Description: "An attempt was made to start a container that is in the process of being deleted", - 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", - Description: "The specified container is paused, before it can be stopped it must be unpaused", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeRemovalContainer is generated when we attempt to connect or disconnect a - // container but it's marked for removal. - ErrorCodeRemovalContainer = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "REMOVALCONTAINER", - Message: "Container %s is marked for removal and cannot be connected or disconnected to the network", - Description: "The specified container is marked for removal and cannot be connected or disconnected to the network", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodePausedContainer is generated when we attempt to attach a - // container but its paused. - ErrorCodePausedContainer = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "CONTAINERPAUSED", - Message: "Container %s is paused. Unpause the container before attach", - Description: "The specified container is paused, unpause the container before attach", - HTTPStatusCode: http.StatusConflict, - }) - // 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", - Description: "The specified container is already in the paused state", - 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", - Description: "The specified container can not be unpaused because it is not in a paused state", - 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", - Description: "An attempt to retrieve the image of a container was made but the container is not registered", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeEmptyID is generated when an ID is the empty string. - ErrorCodeEmptyID = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "EMPTYID", - Message: "Invalid empty id", - Description: "An attempt was made to register a container but the container's ID can not be an empty string", - 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", - Description: "An attempt was made to register a container but the container's ID can not be an empty string", - 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", - Description: "An error occurred while trying to initialize the logging driver", - 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", - Description: "The specified action can not be taken due to the container not being in a running state", - 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", - Description: "An attempt was made to link to a container but the container is not in a running state", - 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", - Description: "There was an error while trying to retrieve the information about a custom device", - 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", - Description: "The specified endpoint for the port mapping is empty", - 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 network settings while building port map info", - Description: "The specified endpoint for the port mapping is empty", - 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", - Description: "There was an error while trying to parse the specified 'port' value", - 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", - Description: "There was an error trying to located the specified networking sandbox", - 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", - Description: "There was an error trying to update the configuration information of the specified network sandbox", - 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", - Description: "There was an error trying to refresh the configuration information of the specified network sandbox", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeHostPort is generated when there was an error while trying - // to parse a "host/port" string. - ErrorCodeHostPort = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "HOSTPORT", - Message: "Error parsing HostPort value(%s):%v", - Description: "There was an error trying to parse the specified 'HostPort' value", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeNetworkConflict is generated when we try to publish a service - // in network mode. - ErrorCodeNetworkConflict = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "NETWORKCONFLICT", - Message: "conflicting options: publishing a service and network mode", - Description: "It is not possible to publish a service when it is in 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", - Description: "There was an error during an attempt update a container's join information", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeIPCRunning is generated when we try to join a container's - // IPC but it's not running. - ErrorCodeIPCRunning = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "IPCRUNNING", - Message: "cannot join IPC of a non running container: %s", - Description: "An attempt was made to join the IPC of a container, but the container is not running", - HTTPStatusCode: http.StatusConflict, - }) - - // 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", - Description: "An attempt was made create a directory, but the location in which it is being created 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", - Description: "The specified reference to a container is missing a ':' as a separator between 'container' and 'name'/'id'", - 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", - Description: "An attempt was made to have a container join its 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", - Description: "An attempt to join the network of a container, but that container isn't running", - HTTPStatusCode: http.StatusConflict, - }) - - // 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", - Description: "An attempt was made to connect to a container's network but the mode wasn't 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", - Description: "There was an error while trying to remove the mount point (volume) of a container", - 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", - Description: "The specified networking mode is not valid", - 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", - Description: "There was an error trying to retrieve the image for the specified image ID", - 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", - Description: "There was an error trying to retrieve the layer of the specified image", - 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", - Description: "There was an error trying to store a layer for the specified image", - 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", - Description: "There was an error trying to retrieve the metadata of a layer for the specified image", - 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", - Description: "While trying to create a container, the specified configuration information was empty", - 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", - Description: "An attempt was made to find an image by its hash, but the lookup failed", - 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", - Description: "An attempt was made to find an image by its name/tag, but the lookup failed", - 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", - Description: "An attempt was made to mount a volume at the same location as a pre-existing file", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeMountSetup is generated when we can't define a mount point - // due to the source and destination being undefined. - ErrorCodeMountSetup = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "MOUNTSETUP", - Message: "Unable to setup mount point, neither source nor volume defined", - Description: "An attempt was made to setup a mount point, but the source and destination are undefined", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeVolumeInvalidMode is generated when the mode of a volume/bind - // mount is invalid. - ErrorCodeVolumeInvalidMode = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "VOLUMEINVALIDMODE", - Message: "invalid mode: %q", - Description: "An invalid 'mode' was specified", - 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'", - Description: "An invalid 'volume' was specified in the mount request", - 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.", - Description: "An invalid 'destination' path was specified in the mount request, it must be an absolute path", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeVolumeName is generated when the name of named volume isn't valid. - ErrorCodeVolumeName = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "VOLUME_NAME_INVALID", - Message: "%q includes invalid characters for a local volume name, only %q are allowed", - Description: "The name of volume is invalid", - HTTPStatusCode: http.StatusBadRequest, - }) - - // ErrorCodeVolumeSlash is generated when destination path to a volume is / - ErrorCodeVolumeSlash = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "VOLUMESLASH", - Message: "Invalid specification: destination can't be '/' in '%s'", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeVolumeDestIsC is generated the destination is c: (Windows specific) - ErrorCodeVolumeDestIsC = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "VOLUMEDESTISC", - Message: "Destination drive letter in '%s' cannot be c:", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeVolumeDestIsCRoot is generated the destination path is c:\ (Windows specific) - ErrorCodeVolumeDestIsCRoot = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "VOLUMEDESTISCROOT", - Message: `Destination path in '%s' cannot be c:\`, - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeVolumeSourceNotFound is generated the source directory could not be found (Windows specific) - ErrorCodeVolumeSourceNotFound = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "VOLUMESOURCENOTFOUND", - Message: "Source directory '%s' could not be found: %s", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeVolumeSourceNotDirectory is generated the source is not a directory (Windows specific) - ErrorCodeVolumeSourceNotDirectory = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "VOLUMESOURCENOTDIRECTORY", - Message: "Source '%s' is not a directory", - 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: %q", - Description: "An invalid 'destination' path was specified in the mount request, it must not be blank", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeMountDup is generated when we try to mount two mounts points - // to the same path. - ErrorCodeMountDup = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "MOUNTDUP", - Message: "Duplicate mount point '%s'", - Description: "An attempt was made to mount a content but the specified destination location is already used in a previous mount", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeVolumeNoSourceForMount is generated when no source directory - // for a volume mount was found. (Windows specific) - ErrorCodeVolumeNoSourceForMount = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "VOLUMENOSOURCEFORMOUNT", - Message: "No source for mount name '%s' driver %q destination '%s'", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeVolumeNameReservedWord is generated when the name in a volume - // uses a reserved word for filenames. (Windows specific) - ErrorCodeVolumeNameReservedWord = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "VOLUMENAMERESERVEDWORD", - Message: "Volume name %q cannot be a reserved word for Windows filenames", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeCantPause is generated when there's an error while trying - // to pause a container. - ErrorCodeCantPause = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "CANTPAUSE", - Message: "Cannot pause container %s: %s", - Description: "An error occurred while trying to pause the specified container", - 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", - Description: "An error occurred while trying to unpause the specified container", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeCantKill is generated when there's an error while trying - // to kill a container. - ErrorCodeCantKill = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "CANTKILL", - Message: "Cannot kill container %s: %s", - Description: "An error occurred while trying to kill the specified container", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeCantUpdate is generated when there's an error while trying - // to update a container. - ErrorCodeCantUpdate = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "CANTUPDATE", - Message: "Cannot update container %s: %s", - Description: "An error occurred while trying to update the specified container", - HTTPStatusCode: http.StatusInternalServerError, - }) - // ErrorCodePSError is generated when trying to run 'ps'. - ErrorCodePSError = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "PSError", - Message: "Error running ps: %s", - Description: "There was an error trying to run the 'ps' command in the specified container", - 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", - Description: "There was no 'PID' field in the output of the 'ps' command that was executed", - 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", - Description: "While trying to parse the output of the 'ps' command, the 'PID' field was not an integer", - 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", - Description: "The 'top' command 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 %s is already stopped", - Description: "An attempt was made to stop a container, but the container is 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", - Description: "An error occurred while tring to stop the specified container", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeBadCPUFields is generated when the number of CPU fields is - // less than 8. - ErrorCodeBadCPUFields = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "BADCPUFIELDS", - Message: "invalid number of cpu fields", - Description: "While reading the '/proc/stat' file, the number of 'cpu' fields is less than 8", - 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", - Description: "While reading the '/proc/stat' file, the 'CPU' field could not be parsed as an integer", - 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", - Description: "There was an error trying to parse the '/proc/stat' file", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeTimedOut is generated when a timer expires. - ErrorCodeTimedOut = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "TIMEDOUT", - Message: "Timed out: %v", - Description: "A timer expired", - 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", - Description: "An attempt to remove a container was made, but the container is already in the process of being removed", - 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.", - Description: "An attempt to start a container was made, but the container is paused. Unpause it first", - 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", - Description: "An attempt to start a container was made, but the container is 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", - Description: "The 'start' command does not accept 'HostConfig' data, try using the 'create' command instead", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeCantRestart is generated when an error occurred while - // trying to restart a container. - ErrorCodeCantRestart = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "CANTRESTART", - Message: "Cannot restart container %s: %s", - Description: "There was an error while trying to restart a container", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeEmptyRename is generated when one of the names on a - // rename is empty. - ErrorCodeEmptyRename = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "EMPTYRENAME", - Message: "Neither old nor new names may be empty", - Description: "An attempt was made to rename a container but either the old or new names were blank", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeRenameTaken is generated when we try to rename but the - // new name isn't available. - ErrorCodeRenameTaken = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "RENAMETAKEN", - Message: "Error when allocating new name: %s", - Description: "The new name specified on the 'rename' command is already being used", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeRenameDelete is generated when we try to rename but - // failed trying to delete the old container. - ErrorCodeRenameDelete = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "RENAMEDELETE", - Message: "Failed to delete container %q: %v", - Description: "There was an error trying to delete the specified container", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodePauseError is generated when we try to pause a container - // but failed. - ErrorCodePauseError = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "PAUSEERROR", - Message: "Cannot pause container %s: %s", - Description: "There was an error trying to pause the specified container", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeNeedStream is generated when we try to stream a container's - // logs but no output stream was specified. - ErrorCodeNeedStream = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "NEEDSTREAM", - Message: "You must choose at least one stream", - Description: "While trying to stream a container's logs, no output stream was specified", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeDanglingOne is generated when we try to specify more than one - // 'dangling' specifier. - ErrorCodeDanglingOne = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "DANLGINGONE", - Message: "Conflict: cannot use more than 1 value for `dangling` filter", - Description: "The specified 'dangling' filter may not have more than one value", - HTTPStatusCode: http.StatusConflict, - }) - - // ErrorCodeImgDelUsed is generated when we try to delete an image - // but it is being used. - ErrorCodeImgDelUsed = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "IMGDELUSED", - Message: "conflict: unable to remove repository reference %q (must force) - container %s is using its referenced image %s", - Description: "An attempt was made to delete an image but it is currently being used", - HTTPStatusCode: http.StatusConflict, - }) - - // ErrorCodeImgNoParent is generated when we try to find an image's - // parent but its not in the graph. - ErrorCodeImgNoParent = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "IMGNOPARENT", - Message: "unable to get parent image: %v", - Description: "There was an error trying to find an image's parent, it was not in the graph", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeExportFailed is generated when an export fails. - ErrorCodeExportFailed = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "EXPORTFAILED", - Message: "%s: %s", - Description: "There was an error during an export operation", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeExecResize is generated when we try to resize an exec - // but its not running. - ErrorCodeExecResize = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "EXECRESIZE", - Message: "Exec %s is not running, so it can not be resized.", - Description: "An attempt was made to resize an 'exec', but the 'exec' is not running", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeContainerNotRunning is generated when we try to get the info - // on an exec but the container is not running. - ErrorCodeContainerNotRunning = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "CONTAINERNOTRUNNING", - Message: "Container %s is not running: %s", - Description: "An attempt was made to retrieve the information about an 'exec' but the container is not running", - HTTPStatusCode: http.StatusConflict, - }) - - // ErrorCodeContainerRestarting is generated when an operation was made - // on a restarting container. - ErrorCodeContainerRestarting = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "CONTAINERRESTARTING", - Message: "Container %s is restarting, wait until the container is running", - Description: "An operation was made on a restarting container", - HTTPStatusCode: http.StatusConflict, - }) - - // ErrorCodeNoExecID is generated when we try to get the info - // on an exec but it can't be found. - ErrorCodeNoExecID = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "NOEXECID", - Message: "No such exec instance '%s' found in daemon", - Description: "The specified 'exec' instance could not be found", - HTTPStatusCode: http.StatusNotFound, - }) - - // ErrorCodeExecPaused is generated when we try to start an exec - // but the container is paused. - ErrorCodeExecPaused = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "EXECPAUSED", - Message: "Container %s is paused, unpause the container before exec", - Description: "An attempt to start an 'exec' was made, but the owning container is paused", - HTTPStatusCode: http.StatusConflict, - }) - - // ErrorCodeExecRunning is generated when we try to start an exec - // but its already running. - ErrorCodeExecRunning = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "EXECRUNNING", - Message: "Error: Exec command %s is already running", - Description: "An attempt to start an 'exec' was made, but 'exec' is already running", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeExecExited is generated when we try to start an exec - // but its already running. - ErrorCodeExecExited = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "EXECEXITED", - Message: "Error: Exec command %s has already run", - Description: "An attempt to start an 'exec' was made, but 'exec' was already run", - HTTPStatusCode: http.StatusConflict, - }) - - // ErrorCodeExecCantRun is generated when we try to start an exec - // but it failed for some reason. - ErrorCodeExecCantRun = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "EXECCANTRUN", - Message: "Cannot run exec command %s in container %s: %s", - Description: "An attempt to start an 'exec' was made, but an error occurred", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeExecAttach is generated when we try to attach to an exec - // but failed. - ErrorCodeExecAttach = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "EXECATTACH", - Message: "attach failed with error: %s", - Description: "There was an error while trying to attach to an 'exec'", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeExecContainerStopped is generated when we try to start - // an exec but then the container stopped. - ErrorCodeExecContainerStopped = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "EXECCONTAINERSTOPPED", - Message: "container stopped while running exec", - Description: "An attempt was made to start an 'exec' but the owning container is in the 'stopped' state", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeDefaultName is generated when we try to delete the - // default name of a container. - ErrorCodeDefaultName = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "DEFAULTNAME", - Message: "Conflict, cannot remove the default name of the container", - Description: "An attempt to delete the default name of a container was made, but that is not allowed", - HTTPStatusCode: http.StatusConflict, - }) - - // ErrorCodeNoParent is generated when we try to delete a container - // but we can't find its parent image. - ErrorCodeNoParent = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "NOPARENT", - Message: "Cannot get parent %s for name %s", - Description: "An attempt was made to delete a container but its parent image could not be found", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeCantDestroy is generated when we try to delete a container - // but failed for some reason. - ErrorCodeCantDestroy = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "CANTDESTROY", - Message: "Cannot destroy container %s: %v", - Description: "An attempt was made to delete a container but it failed", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeRmRunning is generated when we try to delete a container - // but its still running. - ErrorCodeRmRunning = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "RMRUNNING", - Message: "You cannot remove a running container %s. Stop the container before attempting removal or use -f", - Description: "An attempt was made to delete a container but the container is still running, try to either stop it first or use '-f'", - HTTPStatusCode: http.StatusConflict, - }) - - // ErrorCodeRmFailed is generated when we try to delete a container - // but it failed for some reason. - ErrorCodeRmFailed = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "RMFAILED", - Message: "Could not kill running container %s, cannot remove - %v", - Description: "An error occurred while trying to delete a running container", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeRmNotFound is generated when we try to delete a container - // but couldn't find it. - ErrorCodeRmNotFound = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "RMNOTFOUND", - Message: "Could not kill running container, cannot remove - %v", - Description: "An attempt to delete a container was made but the container could not be found", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeRmState is generated when we try to delete a container - // but couldn't set its state to RemovalInProgress. - ErrorCodeRmState = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "RMSTATE", - Message: "Failed to set container %s state to RemovalInProgress: %s", - Description: "An attempt to delete a container was made, but there as an error trying to set its state to 'RemovalInProgress'", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeRmDriverFS is generated when we try to delete a container - // but the driver failed to delete its filesystem. - ErrorCodeRmDriverFS = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "RMDRIVERFS", - Message: "Driver %s failed to remove root filesystem %s: %s", - Description: "While trying to delete a container, the driver failed to remove the root filesystem", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeRmFS is generated when we try to delete a container - // but failed deleting its filesystem. - ErrorCodeRmFS = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "RMFS", - Message: "Unable to remove filesystem for %v: %v", - Description: "While trying to delete a container, the driver failed to remove the filesystem", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeRmExecDriver is generated when we try to delete a container - // but failed deleting its exec driver data. - ErrorCodeRmExecDriver = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "RMEXECDRIVER", - Message: "Unable to remove execdriver data for %s: %s", - Description: "While trying to delete a container, there was an error trying to remove th exec driver data", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeRmVolumeInUse is generated when we try to delete a container - // but failed deleting a volume because its being used. - ErrorCodeRmVolumeInUse = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "RMVOLUMEINUSE", - Message: "Conflict: %v", - Description: "While trying to delete a container, one of its volumes is still being used", - HTTPStatusCode: http.StatusConflict, - }) - - // ErrorCodeRmVolume is generated when we try to delete a container - // but failed deleting a volume. - ErrorCodeRmVolume = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "RMVOLUME", - Message: "Error while removing volume %s: %v", - Description: "While trying to delete a container, there was an error trying to delete one of its volumes", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeInvalidCpusetCpus is generated when user provided cpuset CPUs - // are invalid. - ErrorCodeInvalidCpusetCpus = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "INVALIDCPUSETCPUS", - Message: "Invalid value %s for cpuset cpus.", - Description: "While verifying the container's 'HostConfig', CpusetCpus value was in an incorrect format", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeInvalidCpusetMems is generated when user provided cpuset mems - // are invalid. - ErrorCodeInvalidCpusetMems = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "INVALIDCPUSETMEMS", - Message: "Invalid value %s for cpuset mems.", - Description: "While verifying the container's 'HostConfig', CpusetMems value was in an incorrect format", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeNotAvailableCpusetCpus is generated when user provided cpuset - // CPUs aren't available in the container's cgroup. - ErrorCodeNotAvailableCpusetCpus = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "NOTAVAILABLECPUSETCPUS", - Message: "Requested CPUs are not available - requested %s, available: %s.", - Description: "While verifying the container's 'HostConfig', cpuset CPUs provided aren't available in the container's cgroup available set", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeNotAvailableCpusetMems is generated when user provided cpuset - // memory nodes aren't available in the container's cgroup. - ErrorCodeNotAvailableCpusetMems = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "NOTAVAILABLECPUSETMEMS", - Message: "Requested memory nodes are not available - requested %s, available: %s.", - Description: "While verifying the container's 'HostConfig', cpuset memory nodes provided aren't available in the container's cgroup available set", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorVolumeNameTaken is generated when an error occurred while - // trying to create a volume that has existed using different driver. - ErrorVolumeNameTaken = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "VOLUME_NAME_TAKEN", - Message: "A volume named %s already exists. Choose a different volume name.", - Description: "An attempt to create a volume using a driver but the volume already exists with a different driver", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeCmdNotFound is generated when container cmd can't start, - // container command not found error, exit code 127 - ErrorCodeCmdNotFound = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "CMDNOTFOUND", - Message: "Container command not found or does not exist.", - Description: "Command could not be found, command does not exist", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeCmdCouldNotBeInvoked is generated when container cmd can't start, - // container command permission denied error, exit code 126 - ErrorCodeCmdCouldNotBeInvoked = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "CMDCOULDNOTBEINVOKED", - Message: "Container command could not be invoked.", - Description: "Permission denied, cannot invoke command", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeCantStart is generated when container cmd can't start, - // for any reason other than above 2 errors - ErrorCodeCantStart = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "CANTSTART", - Message: "Cannot start container %s: %s", - Description: "There was an error while trying to start a container", - HTTPStatusCode: http.StatusInternalServerError, - }) - - // ErrorCodeCantDeletePredefinedNetwork is generated when one of the predefined networks - // is attempted to be deleted. - ErrorCodeCantDeletePredefinedNetwork = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "CANT_DELETE_PREDEFINED_NETWORK", - Message: "%s is a pre-defined network and cannot be removed", - Description: "Engine's predefined networks cannot be deleted", - HTTPStatusCode: http.StatusForbidden, - }) - - // ErrorCodeMultipleNetworkConnect is generated when more than one network is passed - // when creating a container - ErrorCodeMultipleNetworkConnect = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "CANNOT_CONNECT_TO_MULTIPLE_NETWORKS", - Message: "Container cannot be connected to %s", - Description: "A container can only be connected to one network at the time", - HTTPStatusCode: http.StatusBadRequest, - }) -) diff --git a/errors/error.go b/errors/error.go deleted file mode 100644 index 37222d443840b..0000000000000 --- a/errors/error.go +++ /dev/null @@ -1,6 +0,0 @@ -package errors - -// This file contains all of the errors that can be generated from the -// docker engine but are not tied to any specific top-level component. - -const errGroup = "engine" diff --git a/errors/errors.go b/errors/errors.go new file mode 100644 index 0000000000000..8070f48fb24b5 --- /dev/null +++ b/errors/errors.go @@ -0,0 +1,41 @@ +package errors + +import "net/http" + +// apiError is an error wrapper that also +// holds information about response status codes. +type apiError struct { + error + statusCode int +} + +// HTTPErrorStatusCode returns a status code. +func (e apiError) HTTPErrorStatusCode() int { + return e.statusCode +} + +// NewErrorWithStatusCode allows you to associate +// a specific HTTP Status Code to an error. +// The Server will take that code and set +// it as the response status. +func NewErrorWithStatusCode(err error, code int) error { + return apiError{err, code} +} + +// NewBadRequestError creates a new API error +// that has the 400 HTTP status code associated to it. +func NewBadRequestError(err error) error { + return NewErrorWithStatusCode(err, http.StatusBadRequest) +} + +// NewRequestNotFoundError creates a new API error +// that has the 404 HTTP status code associated to it. +func NewRequestNotFoundError(err error) error { + return NewErrorWithStatusCode(err, http.StatusNotFound) +} + +// NewRequestConflictError creates a new API error +// that has the 409 HTTP status code associated to it. +func NewRequestConflictError(err error) error { + return NewErrorWithStatusCode(err, http.StatusConflict) +} diff --git a/errors/image.go b/errors/image.go deleted file mode 100644 index 04efe6fcba0f5..0000000000000 --- a/errors/image.go +++ /dev/null @@ -1,20 +0,0 @@ -package errors - -// This file contains all of the errors that can be generated from the -// docker/image component. - -import ( - "net/http" - - "github.com/docker/distribution/registry/api/errcode" -) - -var ( - // ErrorCodeInvalidImageID is generated when image id specified is incorrectly formatted. - ErrorCodeInvalidImageID = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "INVALIDIMAGEID", - Message: "image ID '%s' is invalid ", - Description: "The specified image id is incorrectly formatted", - HTTPStatusCode: http.StatusInternalServerError, - }) -) diff --git a/errors/server.go b/errors/server.go deleted file mode 100644 index b54d2d5436c42..0000000000000 --- a/errors/server.go +++ /dev/null @@ -1,45 +0,0 @@ -package errors - -import ( - "net/http" - - "github.com/docker/distribution/registry/api/errcode" -) - -var ( - // ErrorCodeNewerClientVersion is generated when a request from a client - // specifies a higher version than the server supports. - ErrorCodeNewerClientVersion = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "NEWERCLIENTVERSION", - Message: "client is newer than server (client API version: %s, server API version: %s)", - Description: "The client version is higher than the server version", - HTTPStatusCode: http.StatusBadRequest, - }) - - // ErrorCodeOldClientVersion is generated when a request from a client - // specifies a version lower than the minimum version supported by the server. - ErrorCodeOldClientVersion = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "OLDCLIENTVERSION", - Message: "client version %s is too old. Minimum supported API version is %s, please upgrade your client to a newer version", - Description: "The client version is too old for the server", - HTTPStatusCode: http.StatusBadRequest, - }) - - // ErrorNetworkControllerNotEnabled is generated when the networking stack in not enabled - // for certain platforms, like windows. - ErrorNetworkControllerNotEnabled = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "NETWORK_CONTROLLER_NOT_ENABLED", - Message: "the network controller is not enabled for this platform", - Description: "Docker's networking stack is disabled for this platform", - HTTPStatusCode: http.StatusNotFound, - }) - - // ErrorCodeNoHijackConnection is generated when a request tries to attach to a container - // but the connection to hijack is not provided. - ErrorCodeNoHijackConnection = errcode.Register(errGroup, errcode.ErrorDescriptor{ - Value: "HIJACK_CONNECTION_MISSING", - Message: "error attaching to container %s, hijack connection missing", - Description: "The caller didn't provide a connection to hijack", - HTTPStatusCode: http.StatusBadRequest, - }) -) diff --git a/integration-cli/docker_api_containers_test.go b/integration-cli/docker_api_containers_test.go index 09caa68cfe69c..986b7639b40f0 100644 --- a/integration-cli/docker_api_containers_test.go +++ b/integration-cli/docker_api_containers_test.go @@ -643,7 +643,7 @@ func (s *DockerSuite) TestContainerApiCreateMultipleNetworksConfig(c *check.C) { c.Assert(err, checker.IsNil) c.Assert(status, checker.Equals, http.StatusBadRequest) // network name order in error message is not deterministic - c.Assert(string(b), checker.Contains, "Container cannot be connected to [") + c.Assert(string(b), checker.Contains, "Container cannot be connected to network endpoints") c.Assert(string(b), checker.Contains, "net1") c.Assert(string(b), checker.Contains, "net2") c.Assert(string(b), checker.Contains, "net3") diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index 1cd40408bf899..81b92b1895373 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -463,7 +463,7 @@ func (s *DockerSuite) TestRunVolumesFromInReadWriteMode(c *check.C) { dockerCmd(c, "run", "--name", "parent", "-v", volumeDir, "busybox", "true") dockerCmd(c, "run", "--volumes-from", "parent:rw", "busybox", "touch", fileInVol) - if out, _, err := dockerCmdWithError("run", "--volumes-from", "parent:bar", "busybox", "touch", fileInVol); err == nil || !strings.Contains(out, `invalid mode: "bar"`) { + if out, _, err := dockerCmdWithError("run", "--volumes-from", "parent:bar", "busybox", "touch", fileInVol); err == nil || !strings.Contains(out, `invalid mode: bar`) { c.Fatalf("running --volumes-from parent:bar should have failed with invalid mode: %q", out) } diff --git a/utils/utils.go b/utils/utils.go index 49f50ddd4397f..d3dd00abf40a5 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -7,7 +7,6 @@ import ( "runtime" "strings" - "github.com/docker/distribution/registry/api/errcode" "github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/stringid" ) @@ -86,22 +85,3 @@ func ReplaceOrAppendEnvValues(defaults, overrides []string) []string { return defaults } - -// GetErrorMessage returns the human readable message associated with -// the passed-in error. In some cases the default Error() func returns -// something that is less than useful so based on its types this func -// will go and get a better piece of text. -func GetErrorMessage(err error) string { - switch err.(type) { - case errcode.Error: - e, _ := err.(errcode.Error) - return e.Message - - case errcode.ErrorCode: - ec, _ := err.(errcode.ErrorCode) - return ec.Message() - - default: - return err.Error() - } -} diff --git a/volume/local/local.go b/volume/local/local.go index 1a44c05858b4e..794cb17a13a31 100644 --- a/volume/local/local.go +++ b/volume/local/local.go @@ -4,14 +4,12 @@ package local import ( - "errors" "fmt" "io/ioutil" "os" "path/filepath" "sync" - derr "github.com/docker/docker/errors" "github.com/docker/docker/pkg/idtools" "github.com/docker/docker/utils" "github.com/docker/docker/volume" @@ -27,13 +25,21 @@ const ( var ( // ErrNotFound is the typed error returned when the requested volume name can't be found - ErrNotFound = errors.New("volume not found") + ErrNotFound = fmt.Errorf("volume not found") // volumeNameRegex ensures the name assigned for the volume is valid. // This name is used to create the bind directory, so we need to avoid characters that // would make the path to escape the root directory. volumeNameRegex = utils.RestrictedVolumeNamePattern ) +type validationError struct { + error +} + +func (validationError) IsValidationError() bool { + return true +} + // New instantiates a new Root instance with the provided scope. Scope // is the base path that the Root instance uses to store its // volumes. The base path is created here if it does not exist. @@ -142,7 +148,7 @@ func (r *Root) Remove(v volume.Volume) error { lv, ok := v.(*localVolume) if !ok { - return errors.New("unknown volume type") + return fmt.Errorf("unknown volume type") } realPath, err := filepath.EvalSymlinks(lv.path) @@ -188,7 +194,7 @@ func (r *Root) Get(name string) (volume.Volume, error) { func (r *Root) validateName(name string) error { if !volumeNameRegex.MatchString(name) { - return derr.ErrorCodeVolumeName.WithArgs(name, utils.RestrictedNameChars) + return validationError{fmt.Errorf("%q includes invalid characters for a local volume name, only %q are allowed", name, utils.RestrictedNameChars)} } return nil } diff --git a/volume/volume.go b/volume/volume.go index b75e0ee5b2e15..244c4d682cc1d 100644 --- a/volume/volume.go +++ b/volume/volume.go @@ -1,12 +1,12 @@ package volume import ( + "fmt" "os" "runtime" "strings" "github.com/Sirupsen/logrus" - derr "github.com/docker/docker/errors" "github.com/docker/docker/pkg/system" ) @@ -82,7 +82,7 @@ func (m *MountPoint) Setup() (string, error) { } return m.Source, nil } - return "", derr.ErrorCodeMountSetup + return "", fmt.Errorf("Unable to setup mount point, neither source nor volume defined") } // Path returns the path of a volume in a mount point. @@ -96,7 +96,7 @@ func (m *MountPoint) Path() string { // ParseVolumesFrom ensure that the supplied volumes-from is valid. func ParseVolumesFrom(spec string) (string, string, error) { if len(spec) == 0 { - return "", "", derr.ErrorCodeVolumeFromBlank.WithArgs(spec) + return "", "", fmt.Errorf("malformed volumes-from specification: %s", spec) } specParts := strings.SplitN(spec, ":", 2) @@ -106,15 +106,23 @@ func ParseVolumesFrom(spec string) (string, string, error) { if len(specParts) == 2 { mode = specParts[1] if !ValidMountMode(mode) { - return "", "", derr.ErrorCodeVolumeInvalidMode.WithArgs(mode) + return "", "", errInvalidMode(mode) } // For now don't allow propagation properties while importing // volumes from data container. These volumes will inherit // the same propagation property as of the original volume // in data container. This probably can be relaxed in future. if HasPropagation(mode) { - return "", "", derr.ErrorCodeVolumeInvalidMode.WithArgs(mode) + return "", "", errInvalidMode(mode) } } return id, mode, nil } + +func errInvalidMode(mode string) error { + return fmt.Errorf("invalid mode: %v", mode) +} + +func errInvalidSpec(spec string) error { + return fmt.Errorf("Invalid volume specification: '%s'", spec) +} diff --git a/volume/volume_propagation_linux_test.go b/volume/volume_propagation_linux_test.go index 9cf82528bd650..e579fa05ff940 100644 --- a/volume/volume_propagation_linux_test.go +++ b/volume/volume_propagation_linux_test.go @@ -34,8 +34,8 @@ func TestParseMountSpecPropagation(t *testing.T) { "/hostPath:/containerPath:ro,Z,rprivate", } invalid = map[string]string{ - "/path:/path:ro,rshared,rslave": `invalid mode: "ro,rshared,rslave"`, - "/path:/path:ro,z,rshared,rslave": `invalid mode: "ro,z,rshared,rslave"`, + "/path:/path:ro,rshared,rslave": `invalid mode: ro,rshared,rslave`, + "/path:/path:ro,z,rshared,rslave": `invalid mode: ro,z,rshared,rslave`, "/path:shared": "Invalid volume specification", "/path:slave": "Invalid volume specification", "/path:private": "Invalid volume specification", diff --git a/volume/volume_test.go b/volume/volume_test.go index 6e7bd20c6fc06..0077e82b9981c 100644 --- a/volume/volume_test.go +++ b/volume/volume_test.go @@ -111,8 +111,8 @@ func TestParseMountSpec(t *testing.T) { "/path:ro": "Invalid volume specification", "/rw:rw": "Invalid volume specification", "path:ro": "Invalid volume specification", - "/path:/path:sw": `invalid mode: "sw"`, - "/path:/path:rwz": `invalid mode: "rwz"`, + "/path:/path:sw": `invalid mode: sw`, + "/path:/path:rwz": `invalid mode: rwz`, } } diff --git a/volume/volume_unix.go b/volume/volume_unix.go index 9f3177a37c060..07020a925cd66 100644 --- a/volume/volume_unix.go +++ b/volume/volume_unix.go @@ -6,8 +6,6 @@ import ( "fmt" "path/filepath" "strings" - - derr "github.com/docker/docker/errors" ) // read-write modes @@ -47,12 +45,12 @@ func ParseMountSpec(spec, volumeDriver string) (*MountPoint, error) { Propagation: DefaultPropagationMode, } if strings.Count(spec, ":") > 2 { - return nil, derr.ErrorCodeVolumeInvalid.WithArgs(spec) + return nil, errInvalidSpec(spec) } arr := strings.SplitN(spec, ":", 3) if arr[0] == "" { - return nil, derr.ErrorCodeVolumeInvalid.WithArgs(spec) + return nil, errInvalidSpec(spec) } switch len(arr) { @@ -63,7 +61,7 @@ func ParseMountSpec(spec, volumeDriver string) (*MountPoint, error) { if isValid := ValidMountMode(arr[1]); isValid { // Destination + Mode is not a valid volume - volumes // cannot include a mode. eg /foo:rw - return nil, derr.ErrorCodeVolumeInvalid.WithArgs(spec) + return nil, errInvalidSpec(spec) } // Host Source Path or Name + Destination mp.Source = arr[0] @@ -74,23 +72,23 @@ func ParseMountSpec(spec, volumeDriver string) (*MountPoint, error) { mp.Destination = arr[1] mp.Mode = arr[2] // Mode field is used by SELinux to decide whether to apply label if !ValidMountMode(mp.Mode) { - return nil, derr.ErrorCodeVolumeInvalidMode.WithArgs(mp.Mode) + return nil, errInvalidMode(mp.Mode) } mp.RW = ReadWrite(mp.Mode) mp.Propagation = GetPropagation(mp.Mode) default: - return nil, derr.ErrorCodeVolumeInvalid.WithArgs(spec) + return nil, errInvalidSpec(spec) } //validate the volumes destination path mp.Destination = filepath.Clean(mp.Destination) if !filepath.IsAbs(mp.Destination) { - return nil, derr.ErrorCodeVolumeAbs.WithArgs(mp.Destination) + return nil, fmt.Errorf("Invalid volume destination path: '%s' mount path must be absolute.", mp.Destination) } // Destination cannot be "/" if mp.Destination == "/" { - return nil, derr.ErrorCodeVolumeSlash.WithArgs(spec) + return nil, fmt.Errorf("Invalid specification: destination can't be '/' in '%s'", spec) } name, source := ParseVolumeSource(mp.Source) @@ -106,7 +104,7 @@ func ParseMountSpec(spec, volumeDriver string) (*MountPoint, error) { // cleanup becomes an issue if container does not unmount // submounts explicitly. if HasPropagation(mp.Mode) { - return nil, derr.ErrorCodeVolumeInvalid.WithArgs(spec) + return nil, errInvalidSpec(spec) } } else { mp.Source = filepath.Clean(source) diff --git a/volume/volume_windows.go b/volume/volume_windows.go index ef6e6a1ffe737..d01d10d67138a 100644 --- a/volume/volume_windows.go +++ b/volume/volume_windows.go @@ -1,13 +1,13 @@ package volume import ( + "fmt" "os" "path/filepath" "regexp" "strings" "github.com/Sirupsen/logrus" - derr "github.com/docker/docker/errors" ) // read-write modes @@ -96,7 +96,7 @@ func ParseMountSpec(spec string, volumeDriver string) (*MountPoint, error) { // Must have something back if len(match) == 0 { - return nil, derr.ErrorCodeVolumeInvalid.WithArgs(spec) + return nil, errInvalidSpec(spec) } // Pull out the sub expressions from the named capture groups @@ -116,7 +116,7 @@ func ParseMountSpec(spec string, volumeDriver string) (*MountPoint, error) { // Volumes cannot include an explicitly supplied mode eg c:\path:rw if mp.Source == "" && mp.Destination != "" && matchgroups["mode"] != "" { - return nil, derr.ErrorCodeVolumeInvalid.WithArgs(spec) + return nil, errInvalidSpec(spec) } // Note: No need to check if destination is absolute as it must be by @@ -125,14 +125,14 @@ func ParseMountSpec(spec string, volumeDriver string) (*MountPoint, error) { if filepath.VolumeName(mp.Destination) == mp.Destination { // Ensure the destination path, if a drive letter, is not the c drive if strings.ToLower(mp.Destination) == "c:" { - return nil, derr.ErrorCodeVolumeDestIsC.WithArgs(spec) + return nil, fmt.Errorf("Destination drive letter in '%s' cannot be c:", spec) } } else { // So we know the destination is a path, not drive letter. Clean it up. mp.Destination = filepath.Clean(mp.Destination) // Ensure the destination path, if a path, is not the c root directory if strings.ToLower(mp.Destination) == `c:\` { - return nil, derr.ErrorCodeVolumeDestIsCRoot.WithArgs(spec) + return nil, fmt.Errorf(`Destination path in '%s' cannot be c:\`, spec) } } @@ -163,10 +163,10 @@ func ParseMountSpec(spec string, volumeDriver string) (*MountPoint, error) { var fi os.FileInfo var err error if fi, err = os.Stat(mp.Source); err != nil { - return nil, derr.ErrorCodeVolumeSourceNotFound.WithArgs(mp.Source, err) + return nil, fmt.Errorf("Source directory '%s' could not be found: %s", mp.Source, err) } if !fi.IsDir() { - return nil, derr.ErrorCodeVolumeSourceNotDirectory.WithArgs(mp.Source) + return nil, fmt.Errorf("Source '%s' is not a directory", mp.Source) } } @@ -182,7 +182,7 @@ func IsVolumeNameValid(name string) (bool, error) { } nameExp = regexp.MustCompile(`^` + RXReservedNames + `$`) if nameExp.MatchString(name) { - return false, derr.ErrorCodeVolumeNameReservedWord.WithArgs(name) + return false, fmt.Errorf("Volume name %q cannot be a reserved word for Windows filenames", name) } return true, nil }