diff --git a/api/server/httputils/errors.go b/api/server/httputils/errors.go index 05a842c3af..f5008223c9 100644 --- a/api/server/httputils/errors.go +++ b/api/server/httputils/errors.go @@ -4,9 +4,9 @@ import ( "fmt" "net/http" - "github.com/docker/docker/api/errdefs" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/versions" + "github.com/docker/docker/errdefs" "github.com/gorilla/mux" "github.com/sirupsen/logrus" "google.golang.org/grpc" @@ -35,7 +35,7 @@ func GetHTTPErrorStatusCode(err error) int { statusCode = http.StatusNotFound case errdefs.IsInvalidParameter(err): statusCode = http.StatusBadRequest - case errdefs.IsConflict(err): + case errdefs.IsConflict(err) || errdefs.IsAlreadyExists(err): statusCode = http.StatusConflict case errdefs.IsUnauthorized(err): statusCode = http.StatusUnauthorized @@ -47,7 +47,7 @@ func GetHTTPErrorStatusCode(err error) int { statusCode = http.StatusNotModified case errdefs.IsNotImplemented(err): statusCode = http.StatusNotImplemented - case errdefs.IsSystem(err) || errdefs.IsUnknown(err): + case errdefs.IsSystem(err) || errdefs.IsUnknown(err) || errdefs.IsDataLoss(err) || errdefs.IsDeadline(err) || errdefs.IsCancelled(err): statusCode = http.StatusInternalServerError default: statusCode = statusCodeFromGRPCError(err) diff --git a/api/server/httputils/httputils.go b/api/server/httputils/httputils.go index 47b82ef1ba..81fbabac17 100644 --- a/api/server/httputils/httputils.go +++ b/api/server/httputils/httputils.go @@ -6,6 +6,7 @@ import ( "net/http" "strings" + "github.com/docker/docker/errdefs" "github.com/pkg/errors" "github.com/sirupsen/logrus" "golang.org/x/net/context" @@ -45,20 +46,6 @@ func CloseStreams(streams ...interface{}) { } } -type validationError struct { - cause error -} - -func (e validationError) Error() string { - return e.cause.Error() -} - -func (e validationError) Cause() error { - return e.cause -} - -func (e validationError) InvalidParameter() {} - // CheckForJSON makes sure that the request's Content-Type is application/json. func CheckForJSON(r *http.Request) error { ct := r.Header.Get("Content-Type") @@ -74,7 +61,7 @@ func CheckForJSON(r *http.Request) error { if matchesContentType(ct, "application/json") { return nil } - return validationError{errors.Errorf("Content-Type specified (%s) must be 'application/json'", ct)} + return errdefs.InvalidParameter(errors.Errorf("Content-Type specified (%s) must be 'application/json'", ct)) } // ParseForm ensures the request form is parsed even with invalid content types. @@ -84,7 +71,7 @@ func ParseForm(r *http.Request) error { return nil } if err := r.ParseForm(); err != nil && !strings.HasPrefix(err.Error(), "mime:") { - return validationError{err} + return errdefs.InvalidParameter(err) } return nil } diff --git a/api/server/router/build/build_routes.go b/api/server/router/build/build_routes.go index fefb875de1..491fa85a86 100644 --- a/api/server/router/build/build_routes.go +++ b/api/server/router/build/build_routes.go @@ -18,6 +18,7 @@ import ( "github.com/docker/docker/api/types/backend" "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/versions" + "github.com/docker/docker/errdefs" "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/progress" "github.com/docker/docker/pkg/streamformatter" @@ -83,7 +84,7 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBui } p := system.ParsePlatform(apiPlatform) if err := system.ValidatePlatform(p); err != nil { - return nil, validationError{fmt.Errorf("invalid platform: %s", err)} + return nil, errdefs.InvalidParameter(errors.Errorf("invalid platform: %s", err)) } options.Platform = p.OS } @@ -104,14 +105,14 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBui } if runtime.GOOS != "windows" && options.SecurityOpt != nil { - return nil, validationError{fmt.Errorf("The daemon on this platform does not support setting security options on build")} + return nil, errdefs.InvalidParameter(errors.New("The daemon on this platform does not support setting security options on build")) } var buildUlimits = []*units.Ulimit{} ulimitsJSON := r.FormValue("ulimits") if ulimitsJSON != "" { if err := json.Unmarshal([]byte(ulimitsJSON), &buildUlimits); err != nil { - return nil, errors.Wrap(validationError{err}, "error reading ulimit settings") + return nil, errors.Wrap(errdefs.InvalidParameter(err), "error reading ulimit settings") } options.Ulimits = buildUlimits } @@ -132,7 +133,7 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBui if buildArgsJSON != "" { var buildArgs = map[string]*string{} if err := json.Unmarshal([]byte(buildArgsJSON), &buildArgs); err != nil { - return nil, errors.Wrap(validationError{err}, "error reading build args") + return nil, errors.Wrap(errdefs.InvalidParameter(err), "error reading build args") } options.BuildArgs = buildArgs } @@ -141,7 +142,7 @@ func newImageBuildOptions(ctx context.Context, r *http.Request) (*types.ImageBui if labelsJSON != "" { var labels = map[string]string{} if err := json.Unmarshal([]byte(labelsJSON), &labels); err != nil { - return nil, errors.Wrap(validationError{err}, "error reading labels") + return nil, errors.Wrap(errdefs.InvalidParameter(err), "error reading labels") } options.Labels = labels } @@ -167,16 +168,6 @@ func (br *buildRouter) postPrune(ctx context.Context, w http.ResponseWriter, r * return httputils.WriteJSON(w, http.StatusOK, report) } -type validationError struct { - cause error -} - -func (e validationError) Error() string { - return e.cause.Error() -} - -func (e validationError) InvalidParameter() {} - func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { var ( notVerboseBuffer = bytes.NewBuffer(nil) @@ -210,7 +201,7 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r * buildOptions.AuthConfigs = getAuthConfigs(r.Header) if buildOptions.Squash && !br.daemon.HasExperimental() { - return validationError{errors.New("squash is only supported with experimental mode")} + return errdefs.InvalidParameter(errors.New("squash is only supported with experimental mode")) } out := io.Writer(output) diff --git a/api/server/router/container/container.go b/api/server/router/container/container.go index 90ae6dc38e..e3637824b6 100644 --- a/api/server/router/container/container.go +++ b/api/server/router/container/container.go @@ -5,20 +5,6 @@ import ( "github.com/docker/docker/api/server/router" ) -type validationError struct { - cause error -} - -func (e validationError) Error() string { - return e.cause.Error() -} - -func (e validationError) Cause() error { - return e.cause -} - -func (e validationError) InvalidParameter() {} - // containerRouter is a router to talk with the container controller type containerRouter struct { backend Backend diff --git a/api/server/router/container/container_routes.go b/api/server/router/container/container_routes.go index b7848a3c94..5f8456d706 100644 --- a/api/server/router/container/container_routes.go +++ b/api/server/router/container/container_routes.go @@ -8,7 +8,6 @@ import ( "strconv" "syscall" - "github.com/docker/docker/api/errdefs" "github.com/docker/docker/api/server/httputils" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/backend" @@ -16,6 +15,7 @@ import ( "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/versions" containerpkg "github.com/docker/docker/container" + "github.com/docker/docker/errdefs" "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/signal" "github.com/pkg/errors" @@ -88,7 +88,7 @@ func (s *containerRouter) getContainersLogs(ctx context.Context, w http.Response // with the appropriate status code. stdout, stderr := httputils.BoolValue(r, "stdout"), httputils.BoolValue(r, "stderr") if !(stdout || stderr) { - return validationError{errors.New("Bad parameters: you must choose at least one stream")} + return errdefs.InvalidParameter(errors.New("Bad parameters: you must choose at least one stream")) } containerName := vars["name"] @@ -203,7 +203,7 @@ func (s *containerRouter) postContainersKill(ctx context.Context, w http.Respons if sigStr := r.Form.Get("signal"); sigStr != "" { var err error if sig, err = signal.ParseSignal(sigStr); err != nil { - return validationError{err} + return errdefs.InvalidParameter(err) } } @@ -468,11 +468,11 @@ func (s *containerRouter) postContainersResize(ctx context.Context, w http.Respo height, err := strconv.Atoi(r.Form.Get("h")) if err != nil { - return validationError{err} + return errdefs.InvalidParameter(err) } width, err := strconv.Atoi(r.Form.Get("w")) if err != nil { - return validationError{err} + return errdefs.InvalidParameter(err) } return s.backend.ContainerResize(vars["name"], height, width) @@ -490,7 +490,7 @@ func (s *containerRouter) postContainersAttach(ctx context.Context, w http.Respo hijacker, ok := w.(http.Hijacker) if !ok { - return validationError{errors.Errorf("error attaching to container %s, hijack connection missing", containerName)} + return errdefs.InvalidParameter(errors.Errorf("error attaching to container %s, hijack connection missing", containerName)) } setupStreams := func() (io.ReadCloser, io.Writer, io.Writer, error) { @@ -611,7 +611,7 @@ func (s *containerRouter) postContainersPrune(ctx context.Context, w http.Respon pruneFilters, err := filters.FromJSON(r.Form.Get("filters")) if err != nil { - return validationError{err} + return errdefs.InvalidParameter(err) } pruneReport, err := s.backend.ContainersPrune(ctx, pruneFilters) diff --git a/api/server/router/container/exec.go b/api/server/router/container/exec.go index 97c27d844f..6dfca729c5 100644 --- a/api/server/router/container/exec.go +++ b/api/server/router/container/exec.go @@ -10,6 +10,7 @@ import ( "github.com/docker/docker/api/server/httputils" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/versions" + "github.com/docker/docker/errdefs" "github.com/docker/docker/pkg/stdcopy" "github.com/sirupsen/logrus" "golang.org/x/net/context" @@ -137,11 +138,11 @@ func (s *containerRouter) postContainerExecResize(ctx context.Context, w http.Re } height, err := strconv.Atoi(r.Form.Get("h")) if err != nil { - return validationError{err} + return errdefs.InvalidParameter(err) } width, err := strconv.Atoi(r.Form.Get("w")) if err != nil { - return validationError{err} + return errdefs.InvalidParameter(err) } return s.backend.ContainerExecResize(vars["name"], height, width) diff --git a/api/server/router/image/image_routes.go b/api/server/router/image/image_routes.go index fd95420ef8..dc16a23af0 100644 --- a/api/server/router/image/image_routes.go +++ b/api/server/router/image/image_routes.go @@ -15,6 +15,7 @@ import ( "github.com/docker/docker/api/types/backend" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/versions" + "github.com/docker/docker/errdefs" "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/streamformatter" "github.com/docker/docker/pkg/system" @@ -144,20 +145,6 @@ func (s *imageRouter) postImagesCreate(ctx context.Context, w http.ResponseWrite return nil } -type validationError struct { - cause error -} - -func (e validationError) Error() string { - return e.cause.Error() -} - -func (e validationError) Cause() error { - return e.cause -} - -func (validationError) InvalidParameter() {} - func (s *imageRouter) postImagesPush(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { metaHeaders := map[string][]string{} for k, v := range r.Header { @@ -181,7 +168,7 @@ func (s *imageRouter) postImagesPush(ctx context.Context, w http.ResponseWriter, } else { // the old format is supported for compatibility if there was no authConfig header if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil { - return errors.Wrap(validationError{err}, "Bad parameters and missing X-Registry-Auth") + return errors.Wrap(errdefs.InvalidParameter(err), "Bad parameters and missing X-Registry-Auth") } } diff --git a/api/server/router/network/network_routes.go b/api/server/router/network/network_routes.go index f124813439..fcfeb83f55 100644 --- a/api/server/router/network/network_routes.go +++ b/api/server/router/network/network_routes.go @@ -2,7 +2,6 @@ package network import ( "encoding/json" - "fmt" "net/http" "strconv" "strings" @@ -14,6 +13,7 @@ import ( "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/network" "github.com/docker/docker/api/types/versions" + "github.com/docker/docker/errdefs" "github.com/docker/libnetwork" netconst "github.com/docker/libnetwork/datastore" "github.com/docker/libnetwork/networkdb" @@ -101,22 +101,8 @@ func (e ambigousResultsError) Error() string { func (ambigousResultsError) InvalidParameter() {} -type conflictError struct { - cause error -} - -func (e conflictError) Error() string { - return e.cause.Error() -} - -func (e conflictError) Cause() error { - return e.cause -} - -func (e conflictError) Conflict() {} - func nameConflict(name string) error { - return conflictError{libnetwork.NetworkNameError(name)} + return errdefs.Conflict(libnetwork.NetworkNameError(name)) } func (n *networkRouter) getNetwork(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { @@ -589,7 +575,7 @@ func (n *networkRouter) findUniqueNetwork(term string) (types.NetworkResource, e } } if len(listByFullName) > 1 { - return types.NetworkResource{}, fmt.Errorf("network %s is ambiguous (%d matches found based on name)", term, len(listByFullName)) + return types.NetworkResource{}, errdefs.InvalidParameter(errors.Errorf("network %s is ambiguous (%d matches found based on name)", term, len(listByFullName))) } // Find based on partial ID, returns true only if no duplicates @@ -599,8 +585,8 @@ func (n *networkRouter) findUniqueNetwork(term string) (types.NetworkResource, e } } if len(listByPartialID) > 1 { - return types.NetworkResource{}, fmt.Errorf("network %s is ambiguous (%d matches found based on ID prefix)", term, len(listByPartialID)) + return types.NetworkResource{}, errdefs.InvalidParameter(errors.Errorf("network %s is ambiguous (%d matches found based on ID prefix)", term, len(listByPartialID))) } - return types.NetworkResource{}, libnetwork.ErrNoSuchNetwork(term) + return types.NetworkResource{}, errdefs.NotFound(libnetwork.ErrNoSuchNetwork(term)) } diff --git a/api/server/router/session/session_routes.go b/api/server/router/session/session_routes.go index bccd764226..8eb8074ebc 100644 --- a/api/server/router/session/session_routes.go +++ b/api/server/router/session/session_routes.go @@ -3,27 +3,14 @@ package session import ( "net/http" + "github.com/docker/docker/errdefs" "golang.org/x/net/context" ) -type invalidRequest struct { - cause error -} - -func (e invalidRequest) Error() string { - return e.cause.Error() -} - -func (e invalidRequest) Cause() error { - return e.cause -} - -func (e invalidRequest) InvalidParameter() {} - func (sr *sessionRouter) startSession(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { err := sr.backend.HandleHTTPRequest(ctx, w, r) if err != nil { - return invalidRequest{err} + return errdefs.InvalidParameter(err) } return nil } diff --git a/api/server/router/swarm/cluster_routes.go b/api/server/router/swarm/cluster_routes.go index 5b6c19d9c1..bd98acfcf1 100644 --- a/api/server/router/swarm/cluster_routes.go +++ b/api/server/router/swarm/cluster_routes.go @@ -12,6 +12,7 @@ import ( "github.com/docker/docker/api/types/filters" types "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/api/types/versions" + "github.com/docker/docker/errdefs" "github.com/pkg/errors" "github.com/sirupsen/logrus" "golang.org/x/net/context" @@ -57,20 +58,6 @@ func (sr *swarmRouter) inspectCluster(ctx context.Context, w http.ResponseWriter return httputils.WriteJSON(w, http.StatusOK, swarm) } -type invalidRequestError struct { - err error -} - -func (e invalidRequestError) Error() string { - return e.err.Error() -} - -func (e invalidRequestError) Cause() error { - return e.err -} - -func (e invalidRequestError) InvalidParameter() {} - func (sr *swarmRouter) updateCluster(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { var swarm types.Spec if err := json.NewDecoder(r.Body).Decode(&swarm); err != nil { @@ -81,7 +68,7 @@ func (sr *swarmRouter) updateCluster(ctx context.Context, w http.ResponseWriter, version, err := strconv.ParseUint(rawVersion, 10, 64) if err != nil { err := fmt.Errorf("invalid swarm version '%s': %v", rawVersion, err) - return invalidRequestError{err} + return errdefs.InvalidParameter(err) } var flags types.UpdateFlags @@ -90,7 +77,7 @@ func (sr *swarmRouter) updateCluster(ctx context.Context, w http.ResponseWriter, rot, err := strconv.ParseBool(value) if err != nil { err := fmt.Errorf("invalid value for rotateWorkerToken: %s", value) - return invalidRequestError{err} + return errdefs.InvalidParameter(err) } flags.RotateWorkerToken = rot @@ -100,7 +87,7 @@ func (sr *swarmRouter) updateCluster(ctx context.Context, w http.ResponseWriter, rot, err := strconv.ParseBool(value) if err != nil { err := fmt.Errorf("invalid value for rotateManagerToken: %s", value) - return invalidRequestError{err} + return errdefs.InvalidParameter(err) } flags.RotateManagerToken = rot @@ -109,7 +96,7 @@ func (sr *swarmRouter) updateCluster(ctx context.Context, w http.ResponseWriter, if value := r.URL.Query().Get("rotateManagerUnlockKey"); value != "" { rot, err := strconv.ParseBool(value) if err != nil { - return invalidRequestError{fmt.Errorf("invalid value for rotateManagerUnlockKey: %s", value)} + return errdefs.InvalidParameter(fmt.Errorf("invalid value for rotateManagerUnlockKey: %s", value)) } flags.RotateManagerUnlockKey = rot @@ -153,7 +140,7 @@ func (sr *swarmRouter) getServices(ctx context.Context, w http.ResponseWriter, r } filter, err := filters.FromJSON(r.Form.Get("filters")) if err != nil { - return invalidRequestError{err} + return errdefs.InvalidParameter(err) } services, err := sr.backend.GetServices(basictypes.ServiceListOptions{Filters: filter}) @@ -172,7 +159,7 @@ func (sr *swarmRouter) getService(ctx context.Context, w http.ResponseWriter, r insertDefaults, err = strconv.ParseBool(value) if err != nil { err := fmt.Errorf("invalid value for insertDefaults: %s", value) - return errors.Wrapf(invalidRequestError{err}, "invalid value for insertDefaults: %s", value) + return errors.Wrapf(errdefs.InvalidParameter(err), "invalid value for insertDefaults: %s", value) } } @@ -218,7 +205,7 @@ func (sr *swarmRouter) updateService(ctx context.Context, w http.ResponseWriter, version, err := strconv.ParseUint(rawVersion, 10, 64) if err != nil { err := fmt.Errorf("invalid service version '%s': %v", rawVersion, err) - return invalidRequestError{err} + return errdefs.InvalidParameter(err) } var flags basictypes.ServiceUpdateOptions @@ -311,7 +298,7 @@ func (sr *swarmRouter) updateNode(ctx context.Context, w http.ResponseWriter, r version, err := strconv.ParseUint(rawVersion, 10, 64) if err != nil { err := fmt.Errorf("invalid node version '%s': %v", rawVersion, err) - return invalidRequestError{err} + return errdefs.InvalidParameter(err) } if err := sr.backend.UpdateNode(vars["id"], version, node); err != nil { @@ -417,13 +404,13 @@ func (sr *swarmRouter) getSecret(ctx context.Context, w http.ResponseWriter, r * func (sr *swarmRouter) updateSecret(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { var secret types.SecretSpec if err := json.NewDecoder(r.Body).Decode(&secret); err != nil { - return invalidRequestError{err} + return errdefs.InvalidParameter(err) } rawVersion := r.URL.Query().Get("version") version, err := strconv.ParseUint(rawVersion, 10, 64) if err != nil { - return invalidRequestError{fmt.Errorf("invalid secret version")} + return errdefs.InvalidParameter(fmt.Errorf("invalid secret version")) } id := vars["id"] @@ -484,13 +471,13 @@ func (sr *swarmRouter) getConfig(ctx context.Context, w http.ResponseWriter, r * func (sr *swarmRouter) updateConfig(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error { var config types.ConfigSpec if err := json.NewDecoder(r.Body).Decode(&config); err != nil { - return invalidRequestError{err} + return errdefs.InvalidParameter(err) } rawVersion := r.URL.Query().Get("version") version, err := strconv.ParseUint(rawVersion, 10, 64) if err != nil { - return invalidRequestError{fmt.Errorf("invalid config version")} + return errdefs.InvalidParameter(fmt.Errorf("invalid config version")) } id := vars["id"] diff --git a/builder/dockerfile/builder.go b/builder/dockerfile/builder.go index 20f1650825..0354b2d3f9 100644 --- a/builder/dockerfile/builder.go +++ b/builder/dockerfile/builder.go @@ -17,6 +17,7 @@ import ( "github.com/docker/docker/builder/dockerfile/parser" "github.com/docker/docker/builder/fscache" "github.com/docker/docker/builder/remotecontext" + "github.com/docker/docker/errdefs" "github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/streamformatter" "github.com/docker/docker/pkg/stringid" @@ -225,7 +226,7 @@ func (b *Builder) build(source builder.Source, dockerfile *parser.Result) (*buil if instructions.IsUnknownInstruction(err) { buildsFailed.WithValues(metricsUnknownInstructionError).Inc() } - return nil, validationError{err} + return nil, errdefs.InvalidParameter(err) } if b.options.Target != "" { targetIx, found := instructions.HasStage(stages, b.options.Target) @@ -363,7 +364,7 @@ func BuildFromConfig(config *container.Config, changes []string) (*container.Con dockerfile, err := parser.Parse(bytes.NewBufferString(strings.Join(changes, "\n"))) if err != nil { - return nil, validationError{err} + return nil, errdefs.InvalidParameter(err) } os := runtime.GOOS @@ -378,7 +379,7 @@ func BuildFromConfig(config *container.Config, changes []string) (*container.Con // ensure that the commands are valid for _, n := range dockerfile.AST.Children { if !validCommitCommands[n.Value] { - return nil, validationError{errors.Errorf("%s is not a valid change command", n.Value)} + return nil, errdefs.InvalidParameter(errors.Errorf("%s is not a valid change command", n.Value)) } } @@ -390,7 +391,7 @@ func BuildFromConfig(config *container.Config, changes []string) (*container.Con for _, n := range dockerfile.AST.Children { cmd, err := instructions.ParseCommand(n) if err != nil { - return nil, validationError{err} + return nil, errdefs.InvalidParameter(err) } commands = append(commands, cmd) } @@ -402,7 +403,7 @@ func BuildFromConfig(config *container.Config, changes []string) (*container.Con for _, cmd := range commands { err := dispatch(dispatchRequest, cmd) if err != nil { - return nil, validationError{err} + return nil, errdefs.InvalidParameter(err) } dispatchRequest.state.updateRunConfig() } diff --git a/builder/dockerfile/dispatchers.go b/builder/dockerfile/dispatchers.go index 8d3ea7ed62..1cf275d8c4 100644 --- a/builder/dockerfile/dispatchers.go +++ b/builder/dockerfile/dispatchers.go @@ -20,6 +20,7 @@ import ( "github.com/docker/docker/builder" "github.com/docker/docker/builder/dockerfile/instructions" "github.com/docker/docker/builder/dockerfile/parser" + "github.com/docker/docker/errdefs" "github.com/docker/docker/image" "github.com/docker/docker/pkg/jsonmessage" "github.com/docker/docker/pkg/signal" @@ -510,7 +511,7 @@ func dispatchStopSignal(d dispatchRequest, c *instructions.StopSignalCommand) er _, err := signal.ParseSignal(c.Signal) if err != nil { - return validationError{err} + return errdefs.InvalidParameter(err) } d.state.runConfig.StopSignal = c.Signal return d.builder.commit(d.state, fmt.Sprintf("STOPSIGNAL %v", c.Signal)) diff --git a/builder/dockerfile/errors.go b/builder/dockerfile/errors.go deleted file mode 100644 index 25664dee78..0000000000 --- a/builder/dockerfile/errors.go +++ /dev/null @@ -1,15 +0,0 @@ -package dockerfile - -type validationError struct { - err error -} - -func (e validationError) Error() string { - return e.err.Error() -} - -func (e validationError) InvalidParameter() {} - -func (e validationError) Cause() error { - return e.err -} diff --git a/builder/dockerfile/evaluator.go b/builder/dockerfile/evaluator.go index 6236a194d3..cf3d4fd01e 100644 --- a/builder/dockerfile/evaluator.go +++ b/builder/dockerfile/evaluator.go @@ -27,6 +27,7 @@ import ( "github.com/docker/docker/api/types/container" "github.com/docker/docker/builder" "github.com/docker/docker/builder/dockerfile/instructions" + "github.com/docker/docker/errdefs" "github.com/docker/docker/pkg/system" "github.com/docker/docker/runconfig/opts" "github.com/pkg/errors" @@ -37,7 +38,7 @@ func dispatch(d dispatchRequest, cmd instructions.Command) (err error) { optionsOS := system.ParsePlatform(d.builder.options.Platform).OS err := c.CheckPlatform(optionsOS) if err != nil { - return validationError{err} + return errdefs.InvalidParameter(err) } } runConfigEnv := d.state.runConfig.Env @@ -48,7 +49,7 @@ func dispatch(d dispatchRequest, cmd instructions.Command) (err error) { return d.shlex.ProcessWord(word, envs) }) if err != nil { - return validationError{err} + return errdefs.InvalidParameter(err) } } diff --git a/builder/remotecontext/errors.go b/builder/remotecontext/errors.go deleted file mode 100644 index 8ee33bc607..0000000000 --- a/builder/remotecontext/errors.go +++ /dev/null @@ -1,75 +0,0 @@ -package remotecontext - -type notFoundError string - -func (e notFoundError) Error() string { - return string(e) -} - -func (notFoundError) NotFound() {} - -type requestError string - -func (e requestError) Error() string { - return string(e) -} - -func (e requestError) InvalidParameter() {} - -type unauthorizedError string - -func (e unauthorizedError) Error() string { - return string(e) -} - -func (unauthorizedError) Unauthorized() {} - -type forbiddenError string - -func (e forbiddenError) Error() string { - return string(e) -} - -func (forbiddenError) Forbidden() {} - -type dnsError struct { - cause error -} - -func (e dnsError) Error() string { - return e.cause.Error() -} - -func (e dnsError) NotFound() {} - -func (e dnsError) Cause() error { - return e.cause -} - -type systemError struct { - cause error -} - -func (e systemError) Error() string { - return e.cause.Error() -} - -func (e systemError) SystemError() {} - -func (e systemError) Cause() error { - return e.cause -} - -type unknownError struct { - cause error -} - -func (e unknownError) Error() string { - return e.cause.Error() -} - -func (unknownError) Unknown() {} - -func (e unknownError) Cause() error { - return e.cause -} diff --git a/builder/remotecontext/remote.go b/builder/remotecontext/remote.go index ee0282f706..b67914cc11 100644 --- a/builder/remotecontext/remote.go +++ b/builder/remotecontext/remote.go @@ -10,6 +10,7 @@ import ( "net/url" "regexp" + "github.com/docker/docker/errdefs" "github.com/docker/docker/pkg/ioutils" "github.com/pkg/errors" ) @@ -26,7 +27,7 @@ var mimeRe = regexp.MustCompile(acceptableRemoteMIME) func downloadRemote(remoteURL string) (string, io.ReadCloser, error) { response, err := GetWithStatusError(remoteURL) if err != nil { - return "", nil, fmt.Errorf("error downloading remote context %s: %v", remoteURL, err) + return "", nil, errors.Wrapf(err, "error downloading remote context %s", remoteURL) } contentType, contextReader, err := inspectResponse( @@ -35,7 +36,7 @@ func downloadRemote(remoteURL string) (string, io.ReadCloser, error) { response.ContentLength) if err != nil { response.Body.Close() - return "", nil, fmt.Errorf("error detecting content type for remote %s: %v", remoteURL, err) + return "", nil, errors.Wrapf(err, "error detecting content type for remote %s", remoteURL) } return contentType, ioutils.NewReadCloserWrapper(contextReader, response.Body.Close), nil @@ -47,10 +48,10 @@ func GetWithStatusError(address string) (resp *http.Response, err error) { if resp, err = http.Get(address); err != nil { if uerr, ok := err.(*url.Error); ok { if derr, ok := uerr.Err.(*net.DNSError); ok && !derr.IsTimeout { - return nil, dnsError{err} + return nil, errdefs.NotFound(err) } } - return nil, systemError{err} + return nil, errdefs.System(err) } if resp.StatusCode < 400 { return resp, nil @@ -59,21 +60,21 @@ func GetWithStatusError(address string) (resp *http.Response, err error) { body, err := ioutil.ReadAll(resp.Body) resp.Body.Close() if err != nil { - return nil, errors.Wrap(systemError{err}, msg+": error reading body") + return nil, errdefs.System(errors.New(msg + ": error reading body")) } msg += ": " + string(bytes.TrimSpace(body)) switch resp.StatusCode { case http.StatusNotFound: - return nil, notFoundError(msg) + return nil, errdefs.NotFound(errors.New(msg)) case http.StatusBadRequest: - return nil, requestError(msg) + return nil, errdefs.InvalidParameter(errors.New(msg)) case http.StatusUnauthorized: - return nil, unauthorizedError(msg) + return nil, errdefs.Unauthorized(errors.New(msg)) case http.StatusForbidden: - return nil, forbiddenError(msg) + return nil, errdefs.Forbidden(errors.New(msg)) } - return nil, unknownError{errors.New(msg)} + return nil, errdefs.Unknown(errors.New(msg)) } // inspectResponse looks into the http response data at r to determine whether its diff --git a/daemon/archive.go b/daemon/archive.go index c52d3b8509..69301342ef 100644 --- a/daemon/archive.go +++ b/daemon/archive.go @@ -7,6 +7,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/container" + "github.com/docker/docker/errdefs" "github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/chrootarchive" "github.com/docker/docker/pkg/ioutils" @@ -54,7 +55,7 @@ func (daemon *Daemon) ContainerCopy(name string, res string) (io.ReadCloser, err // Make sure an online file-system operation is permitted. if err := daemon.isOnlineFSOperationPermitted(container); err != nil { - return nil, systemError{err} + return nil, errdefs.System(err) } data, err := daemon.containerCopy(container, res) @@ -65,7 +66,7 @@ func (daemon *Daemon) ContainerCopy(name string, res string) (io.ReadCloser, err if os.IsNotExist(err) { return nil, containerFileNotFound{res, name} } - return nil, systemError{err} + return nil, errdefs.System(err) } // ContainerStatPath stats the filesystem resource at the specified path in the @@ -78,7 +79,7 @@ func (daemon *Daemon) ContainerStatPath(name string, path string) (stat *types.C // Make sure an online file-system operation is permitted. if err := daemon.isOnlineFSOperationPermitted(container); err != nil { - return nil, systemError{err} + return nil, errdefs.System(err) } stat, err = daemon.containerStatPath(container, path) @@ -89,7 +90,7 @@ func (daemon *Daemon) ContainerStatPath(name string, path string) (stat *types.C if os.IsNotExist(err) { return nil, containerFileNotFound{path, name} } - return nil, systemError{err} + return nil, errdefs.System(err) } // ContainerArchivePath creates an archive of the filesystem resource at the @@ -103,7 +104,7 @@ func (daemon *Daemon) ContainerArchivePath(name string, path string) (content io // Make sure an online file-system operation is permitted. if err := daemon.isOnlineFSOperationPermitted(container); err != nil { - return nil, nil, systemError{err} + return nil, nil, errdefs.System(err) } content, stat, err = daemon.containerArchivePath(container, path) @@ -114,7 +115,7 @@ func (daemon *Daemon) ContainerArchivePath(name string, path string) (content io if os.IsNotExist(err) { return nil, nil, containerFileNotFound{path, name} } - return nil, nil, systemError{err} + return nil, nil, errdefs.System(err) } // ContainerExtractToDir extracts the given archive to the specified location @@ -131,7 +132,7 @@ func (daemon *Daemon) ContainerExtractToDir(name, path string, copyUIDGID, noOve // Make sure an online file-system operation is permitted. if err := daemon.isOnlineFSOperationPermitted(container); err != nil { - return systemError{err} + return errdefs.System(err) } err = daemon.containerExtractToDir(container, path, copyUIDGID, noOverwriteDirNonDir, content) @@ -142,7 +143,7 @@ func (daemon *Daemon) ContainerExtractToDir(name, path string, copyUIDGID, noOve if os.IsNotExist(err) { return containerFileNotFound{path, name} } - return systemError{err} + return errdefs.System(err) } // containerStatPath stats the filesystem resource at the specified path in this diff --git a/daemon/attach.go b/daemon/attach.go index 651a964c05..d63eaa6632 100644 --- a/daemon/attach.go +++ b/daemon/attach.go @@ -9,6 +9,7 @@ import ( "github.com/docker/docker/container" "github.com/docker/docker/container/stream" "github.com/docker/docker/daemon/logger" + "github.com/docker/docker/errdefs" "github.com/docker/docker/pkg/stdcopy" "github.com/docker/docker/pkg/term" "github.com/pkg/errors" @@ -22,7 +23,7 @@ func (daemon *Daemon) ContainerAttach(prefixOrName string, c *backend.ContainerA if c.DetachKeys != "" { keys, err = term.ToBytes(c.DetachKeys) if err != nil { - return validationError{errors.Errorf("Invalid detach keys (%s) provided", c.DetachKeys)} + return errdefs.InvalidParameter(errors.Errorf("Invalid detach keys (%s) provided", c.DetachKeys)) } } @@ -32,11 +33,11 @@ func (daemon *Daemon) ContainerAttach(prefixOrName string, c *backend.ContainerA } if container.IsPaused() { err := fmt.Errorf("container %s is paused, unpause the container before attach", prefixOrName) - return stateConflictError{err} + return errdefs.Conflict(err) } if container.IsRestarting() { err := fmt.Errorf("container %s is restarting, wait until the container is running", prefixOrName) - return stateConflictError{err} + return errdefs.Conflict(err) } cfg := stream.AttachConfig{ diff --git a/daemon/cluster/controllers/plugin/controller.go b/daemon/cluster/controllers/plugin/controller.go index b48c9fd4e2..d4f24e82df 100644 --- a/daemon/cluster/controllers/plugin/controller.go +++ b/daemon/cluster/controllers/plugin/controller.go @@ -6,9 +6,9 @@ import ( "net/http" "github.com/docker/distribution/reference" - "github.com/docker/docker/api/errdefs" enginetypes "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/swarm/runtime" + "github.com/docker/docker/errdefs" "github.com/docker/docker/plugin" "github.com/docker/docker/plugin/v2" "github.com/docker/swarmkit/api" diff --git a/daemon/cluster/errors.go b/daemon/cluster/errors.go index 0ffe78b98b..9b2e81e0a8 100644 --- a/daemon/cluster/errors.go +++ b/daemon/cluster/errors.go @@ -20,48 +20,6 @@ const ( errSwarmNotManager notAvailableError = "This node is not a swarm manager. Worker nodes can't be used to view or modify cluster state. Please run this command on a manager node or promote the current node to a manager." ) -type notFoundError struct { - cause error -} - -func (e notFoundError) Error() string { - return e.cause.Error() -} - -func (e notFoundError) NotFound() {} - -func (e notFoundError) Cause() error { - return e.cause -} - -type ambiguousResultsError struct { - cause error -} - -func (e ambiguousResultsError) Error() string { - return e.cause.Error() -} - -func (e ambiguousResultsError) InvalidParameter() {} - -func (e ambiguousResultsError) Cause() error { - return e.cause -} - -type convertError struct { - cause error -} - -func (e convertError) Error() string { - return e.cause.Error() -} - -func (e convertError) InvalidParameter() {} - -func (e convertError) Cause() error { - return e.cause -} - type notAllowedError string func (e notAllowedError) Error() string { @@ -70,20 +28,6 @@ func (e notAllowedError) Error() string { func (e notAllowedError) Forbidden() {} -type validationError struct { - cause error -} - -func (e validationError) Error() string { - return e.cause.Error() -} - -func (e validationError) InvalidParameter() {} - -func (e validationError) Cause() error { - return e.cause -} - type notAvailableError string func (e notAvailableError) Error() string { diff --git a/daemon/cluster/helpers.go b/daemon/cluster/helpers.go index fd50eef66e..9541bff390 100644 --- a/daemon/cluster/helpers.go +++ b/daemon/cluster/helpers.go @@ -3,6 +3,7 @@ package cluster import ( "fmt" + "github.com/docker/docker/errdefs" swarmapi "github.com/docker/swarmkit/api" "github.com/pkg/errors" "golang.org/x/net/context" @@ -48,11 +49,11 @@ func getNode(ctx context.Context, c swarmapi.ControlClient, input string) (*swar if len(rl.Nodes) == 0 { err := fmt.Errorf("node %s not found", input) - return nil, notFoundError{err} + return nil, errdefs.NotFound(err) } if l := len(rl.Nodes); l > 1 { - return nil, ambiguousResultsError{fmt.Errorf("node %s is ambiguous (%d matches found)", input, l)} + return nil, errdefs.InvalidParameter(fmt.Errorf("node %s is ambiguous (%d matches found)", input, l)) } return rl.Nodes[0], nil @@ -84,11 +85,11 @@ func getService(ctx context.Context, c swarmapi.ControlClient, input string, ins if len(rl.Services) == 0 { err := fmt.Errorf("service %s not found", input) - return nil, notFoundError{err} + return nil, errdefs.NotFound(err) } if l := len(rl.Services); l > 1 { - return nil, ambiguousResultsError{fmt.Errorf("service %s is ambiguous (%d matches found)", input, l)} + return nil, errdefs.InvalidParameter(fmt.Errorf("service %s is ambiguous (%d matches found)", input, l)) } if !insertDefaults { @@ -128,11 +129,11 @@ func getTask(ctx context.Context, c swarmapi.ControlClient, input string) (*swar if len(rl.Tasks) == 0 { err := fmt.Errorf("task %s not found", input) - return nil, notFoundError{err} + return nil, errdefs.NotFound(err) } if l := len(rl.Tasks); l > 1 { - return nil, ambiguousResultsError{fmt.Errorf("task %s is ambiguous (%d matches found)", input, l)} + return nil, errdefs.InvalidParameter(fmt.Errorf("task %s is ambiguous (%d matches found)", input, l)) } return rl.Tasks[0], nil @@ -164,11 +165,11 @@ func getSecret(ctx context.Context, c swarmapi.ControlClient, input string) (*sw if len(rl.Secrets) == 0 { err := fmt.Errorf("secret %s not found", input) - return nil, notFoundError{err} + return nil, errdefs.NotFound(err) } if l := len(rl.Secrets); l > 1 { - return nil, ambiguousResultsError{fmt.Errorf("secret %s is ambiguous (%d matches found)", input, l)} + return nil, errdefs.InvalidParameter(fmt.Errorf("secret %s is ambiguous (%d matches found)", input, l)) } return rl.Secrets[0], nil @@ -200,11 +201,11 @@ func getConfig(ctx context.Context, c swarmapi.ControlClient, input string) (*sw if len(rl.Configs) == 0 { err := fmt.Errorf("config %s not found", input) - return nil, notFoundError{err} + return nil, errdefs.NotFound(err) } if l := len(rl.Configs); l > 1 { - return nil, ambiguousResultsError{fmt.Errorf("config %s is ambiguous (%d matches found)", input, l)} + return nil, errdefs.InvalidParameter(fmt.Errorf("config %s is ambiguous (%d matches found)", input, l)) } return rl.Configs[0], nil @@ -238,7 +239,7 @@ func getNetwork(ctx context.Context, c swarmapi.ControlClient, input string) (*s } if l := len(rl.Networks); l > 1 { - return nil, ambiguousResultsError{fmt.Errorf("network %s is ambiguous (%d matches found)", input, l)} + return nil, errdefs.InvalidParameter(fmt.Errorf("network %s is ambiguous (%d matches found)", input, l)) } return rl.Networks[0], nil diff --git a/daemon/cluster/networks.go b/daemon/cluster/networks.go index 3b01ea4efb..081526f768 100644 --- a/daemon/cluster/networks.go +++ b/daemon/cluster/networks.go @@ -7,6 +7,7 @@ import ( "github.com/docker/docker/api/types/network" types "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/daemon/cluster/convert" + "github.com/docker/docker/errdefs" "github.com/docker/docker/runconfig" swarmapi "github.com/docker/swarmkit/api" "github.com/pkg/errors" @@ -298,7 +299,7 @@ func (c *Cluster) populateNetworkID(ctx context.Context, client swarmapi.Control // and use its id for the request. apiNetwork, err = getNetwork(ctx, client, ln.Name()) if err != nil { - return errors.Wrap(notFoundError{err}, "could not find the corresponding predefined swarm network") + return errors.Wrap(errdefs.NotFound(err), "could not find the corresponding predefined swarm network") } goto setid } diff --git a/daemon/cluster/nodes.go b/daemon/cluster/nodes.go index 582e7cdc74..879d272e75 100644 --- a/daemon/cluster/nodes.go +++ b/daemon/cluster/nodes.go @@ -4,6 +4,7 @@ import ( apitypes "github.com/docker/docker/api/types" types "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/daemon/cluster/convert" + "github.com/docker/docker/errdefs" swarmapi "github.com/docker/swarmkit/api" "golang.org/x/net/context" ) @@ -64,7 +65,7 @@ func (c *Cluster) UpdateNode(input string, version uint64, spec types.NodeSpec) return c.lockedManagerAction(func(ctx context.Context, state nodeState) error { nodeSpec, err := convert.NodeSpecToGRPC(spec) if err != nil { - return convertError{err} + return errdefs.InvalidParameter(err) } ctx, cancel := c.getRequestContext() diff --git a/daemon/cluster/services.go b/daemon/cluster/services.go index f3fba8d9d1..931d17c75f 100644 --- a/daemon/cluster/services.go +++ b/daemon/cluster/services.go @@ -16,6 +16,7 @@ import ( types "github.com/docker/docker/api/types/swarm" timetypes "github.com/docker/docker/api/types/time" "github.com/docker/docker/daemon/cluster/convert" + "github.com/docker/docker/errdefs" runconfigopts "github.com/docker/docker/runconfig/opts" swarmapi "github.com/docker/swarmkit/api" gogotypes "github.com/gogo/protobuf/types" @@ -128,7 +129,7 @@ func (c *Cluster) CreateService(s types.ServiceSpec, encodedAuth string, queryRe serviceSpec, err := convert.ServiceSpecToGRPC(s) if err != nil { - return convertError{err} + return errdefs.InvalidParameter(err) } resp = &apitypes.ServiceCreateResponse{} @@ -232,7 +233,7 @@ func (c *Cluster) UpdateService(serviceIDOrName string, version uint64, spec typ serviceSpec, err := convert.ServiceSpecToGRPC(spec) if err != nil { - return convertError{err} + return errdefs.InvalidParameter(err) } currentService, err := getService(ctx, state.controlClient, serviceIDOrName, false) diff --git a/daemon/cluster/swarm.go b/daemon/cluster/swarm.go index ec527ce59f..3c7a23b71d 100644 --- a/daemon/cluster/swarm.go +++ b/daemon/cluster/swarm.go @@ -10,6 +10,7 @@ import ( "github.com/docker/docker/api/types/filters" types "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/daemon/cluster/convert" + "github.com/docker/docker/errdefs" "github.com/docker/docker/opts" "github.com/docker/docker/pkg/signal" swarmapi "github.com/docker/swarmkit/api" @@ -44,7 +45,7 @@ func (c *Cluster) Init(req types.InitRequest) (string, error) { } if err := validateAndSanitizeInitRequest(&req); err != nil { - return "", validationError{err} + return "", errdefs.InvalidParameter(err) } listenHost, listenPort, err := resolveListenAddr(req.ListenAddr) @@ -140,7 +141,7 @@ func (c *Cluster) Join(req types.JoinRequest) error { c.mu.Unlock() if err := validateAndSanitizeJoinRequest(&req); err != nil { - return validationError{err} + return errdefs.InvalidParameter(err) } listenHost, listenPort, err := resolveListenAddr(req.ListenAddr) @@ -232,7 +233,7 @@ func (c *Cluster) Update(version uint64, spec types.Spec, flags types.UpdateFlag if spec.Annotations.Name == "" { spec.Annotations.Name = "default" } else if spec.Annotations.Name != "default" { - return validationError{errors.New(`swarm spec must be named "default"`)} + return errdefs.InvalidParameter(errors.New(`swarm spec must be named "default"`)) } // In update, client should provide the complete spec of the swarm, including @@ -240,7 +241,7 @@ func (c *Cluster) Update(version uint64, spec types.Spec, flags types.UpdateFlag // will be used to swarmkit. clusterSpec, err := convert.SwarmSpecToGRPC(spec) if err != nil { - return convertError{err} + return errdefs.InvalidParameter(err) } _, err = state.controlClient.UpdateCluster( @@ -311,7 +312,7 @@ func (c *Cluster) UnlockSwarm(req types.UnlockRequest) error { key, err := encryption.ParseHumanReadableKey(req.UnlockKey) if err != nil { - return validationError{err} + return errdefs.InvalidParameter(err) } config := nr.config diff --git a/daemon/commit.go b/daemon/commit.go index 1bdbd6be4f..b2c969316b 100644 --- a/daemon/commit.go +++ b/daemon/commit.go @@ -13,6 +13,7 @@ import ( containertypes "github.com/docker/docker/api/types/container" "github.com/docker/docker/builder/dockerfile" "github.com/docker/docker/container" + "github.com/docker/docker/errdefs" "github.com/docker/docker/image" "github.com/docker/docker/layer" "github.com/docker/docker/pkg/ioutils" @@ -136,12 +137,12 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str if container.IsDead() { err := fmt.Errorf("You cannot commit container %s which is Dead", container.ID) - return "", stateConflictError{err} + return "", errdefs.Conflict(err) } if container.IsRemovalInProgress() { err := fmt.Errorf("You cannot commit container %s which is being removed", container.ID) - return "", stateConflictError{err} + return "", errdefs.Conflict(err) } if c.Pause && !container.IsPaused() { diff --git a/daemon/container.go b/daemon/container.go index b2f4f1053f..d55c98f5a7 100644 --- a/daemon/container.go +++ b/daemon/container.go @@ -13,6 +13,7 @@ import ( "github.com/docker/docker/api/types/strslice" "github.com/docker/docker/container" "github.com/docker/docker/daemon/network" + "github.com/docker/docker/errdefs" "github.com/docker/docker/image" "github.com/docker/docker/opts" "github.com/docker/docker/pkg/signal" @@ -54,7 +55,7 @@ func (daemon *Daemon) GetContainer(prefixOrName string) (*container.Container, e if indexError == truncindex.ErrNotExist { return nil, containerNotFound(prefixOrName) } - return nil, systemError{indexError} + return nil, errdefs.System(indexError) } return daemon.containers.Get(containerID), nil } @@ -139,7 +140,7 @@ func (daemon *Daemon) newContainer(name string, operatingSystem string, config * if config.Hostname == "" { config.Hostname, err = os.Hostname() if err != nil { - return nil, systemError{err} + return nil, errdefs.System(err) } } } else { diff --git a/daemon/container_linux.go b/daemon/container_linux.go index d05992d0fe..d63f4b72a5 100644 --- a/daemon/container_linux.go +++ b/daemon/container_linux.go @@ -4,6 +4,7 @@ package daemon import ( "github.com/docker/docker/container" + "github.com/docker/docker/errdefs" ) func (daemon *Daemon) saveApparmorConfig(container *container.Container) error { @@ -14,7 +15,7 @@ func (daemon *Daemon) saveApparmorConfig(container *container.Container) error { } if err := parseSecurityOpt(container, container.HostConfig); err != nil { - return validationError{err} + return errdefs.InvalidParameter(err) } if !container.HostConfig.Privileged { diff --git a/daemon/container_operations.go b/daemon/container_operations.go index 355d5496ea..32846a2f77 100644 --- a/daemon/container_operations.go +++ b/daemon/container_operations.go @@ -14,6 +14,7 @@ import ( networktypes "github.com/docker/docker/api/types/network" "github.com/docker/docker/container" "github.com/docker/docker/daemon/network" + "github.com/docker/docker/errdefs" "github.com/docker/docker/opts" "github.com/docker/docker/pkg/stringid" "github.com/docker/docker/runconfig" @@ -922,7 +923,7 @@ func (daemon *Daemon) getNetworkedContainer(containerID, connectedContainerID st } if !nc.IsRunning() { err := fmt.Errorf("cannot join network of a non running container: %s", connectedContainerID) - return nil, stateConflictError{err} + return nil, errdefs.Conflict(err) } if nc.IsRestarting() { return nil, errContainerIsRestarting(connectedContainerID) diff --git a/daemon/container_operations_unix.go b/daemon/container_operations_unix.go index 09b9b3f4bb..9fe899b623 100644 --- a/daemon/container_operations_unix.go +++ b/daemon/container_operations_unix.go @@ -13,6 +13,7 @@ import ( "github.com/docker/docker/container" "github.com/docker/docker/daemon/links" + "github.com/docker/docker/errdefs" "github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/mount" "github.com/docker/docker/pkg/stringid" @@ -91,7 +92,7 @@ func (daemon *Daemon) getPidContainer(container *container.Container) (*containe func containerIsRunning(c *container.Container) error { if !c.IsRunning() { - return stateConflictError{errors.Errorf("container %s is not running", c.ID)} + return errdefs.Conflict(errors.Errorf("container %s is not running", c.ID)) } return nil } diff --git a/daemon/create.go b/daemon/create.go index e4d17cc2df..54ce12c239 100644 --- a/daemon/create.go +++ b/daemon/create.go @@ -13,6 +13,7 @@ import ( containertypes "github.com/docker/docker/api/types/container" networktypes "github.com/docker/docker/api/types/network" "github.com/docker/docker/container" + "github.com/docker/docker/errdefs" "github.com/docker/docker/image" "github.com/docker/docker/layer" "github.com/docker/docker/pkg/idtools" @@ -36,7 +37,7 @@ func (daemon *Daemon) ContainerCreate(params types.ContainerCreateConfig) (conta func (daemon *Daemon) containerCreate(params types.ContainerCreateConfig, managed bool) (containertypes.ContainerCreateCreatedBody, error) { start := time.Now() if params.Config == nil { - return containertypes.ContainerCreateCreatedBody{}, validationError{errors.New("Config cannot be empty in order to create a container")} + return containertypes.ContainerCreateCreatedBody{}, errdefs.InvalidParameter(errors.New("Config cannot be empty in order to create a container")) } os := runtime.GOOS @@ -55,12 +56,12 @@ func (daemon *Daemon) containerCreate(params types.ContainerCreateConfig, manage warnings, err := daemon.verifyContainerSettings(os, params.HostConfig, params.Config, false) if err != nil { - return containertypes.ContainerCreateCreatedBody{Warnings: warnings}, validationError{err} + return containertypes.ContainerCreateCreatedBody{Warnings: warnings}, errdefs.InvalidParameter(err) } err = verifyNetworkingConfig(params.NetworkingConfig) if err != nil { - return containertypes.ContainerCreateCreatedBody{Warnings: warnings}, validationError{err} + return containertypes.ContainerCreateCreatedBody{Warnings: warnings}, errdefs.InvalidParameter(err) } if params.HostConfig == nil { @@ -68,7 +69,7 @@ func (daemon *Daemon) containerCreate(params types.ContainerCreateConfig, manage } err = daemon.adaptContainerSettings(params.HostConfig, params.AdjustCPUShares) if err != nil { - return containertypes.ContainerCreateCreatedBody{Warnings: warnings}, validationError{err} + return containertypes.ContainerCreateCreatedBody{Warnings: warnings}, errdefs.InvalidParameter(err) } container, err := daemon.create(params, managed) @@ -115,11 +116,11 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) ( } if err := daemon.mergeAndVerifyConfig(params.Config, img); err != nil { - return nil, validationError{err} + return nil, errdefs.InvalidParameter(err) } if err := daemon.mergeAndVerifyLogConfig(¶ms.HostConfig.LogConfig); err != nil { - return nil, validationError{err} + return nil, errdefs.InvalidParameter(err) } if container, err = daemon.newContainer(params.Name, os, params.Config, params.HostConfig, imgID, managed); err != nil { @@ -158,7 +159,7 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) ( // Set RWLayer for container after mount labels have been set if err := daemon.setRWLayer(container); err != nil { - return nil, systemError{err} + return nil, errdefs.System(err) } rootIDs := daemon.idMappings.RootPair() diff --git a/daemon/daemon.go b/daemon/daemon.go index 98d395d3dc..3378411fd6 100644 --- a/daemon/daemon.go +++ b/daemon/daemon.go @@ -18,7 +18,6 @@ import ( "sync" "time" - "github.com/docker/docker/api/errdefs" "github.com/docker/docker/api/types" containertypes "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/swarm" @@ -29,6 +28,7 @@ import ( "github.com/docker/docker/daemon/exec" "github.com/docker/docker/daemon/logger" "github.com/docker/docker/daemon/network" + "github.com/docker/docker/errdefs" "github.com/sirupsen/logrus" // register graph drivers _ "github.com/docker/docker/daemon/graphdriver/register" diff --git a/daemon/daemon_test.go b/daemon/daemon_test.go index 44bf3414c0..8ca1f0dd57 100644 --- a/daemon/daemon_test.go +++ b/daemon/daemon_test.go @@ -7,9 +7,9 @@ import ( "runtime" "testing" - "github.com/docker/docker/api/errdefs" containertypes "github.com/docker/docker/api/types/container" "github.com/docker/docker/container" + "github.com/docker/docker/errdefs" _ "github.com/docker/docker/pkg/discovery/memory" "github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/truncindex" diff --git a/daemon/delete.go b/daemon/delete.go index 4d56d14529..5fb9b9a1d9 100644 --- a/daemon/delete.go +++ b/daemon/delete.go @@ -9,6 +9,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/container" + "github.com/docker/docker/errdefs" "github.com/docker/docker/layer" "github.com/docker/docker/pkg/system" "github.com/docker/docker/volume" @@ -31,7 +32,7 @@ func (daemon *Daemon) ContainerRm(name string, config *types.ContainerRmConfig) // Container state RemovalInProgress should be used to avoid races. if inProgress := container.SetRemovalInProgress(); inProgress { err := fmt.Errorf("removal of container %s is already in progress", name) - return stateConflictError{err} + return errdefs.Conflict(err) } defer container.ResetRemovalInProgress() @@ -87,7 +88,7 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemo procedure = "Unpause and then " + strings.ToLower(procedure) } err := fmt.Errorf("You cannot remove a %s container %s. %s", state, container.ID, procedure) - return stateConflictError{err} + return errdefs.Conflict(err) } if err := daemon.Kill(container); err != nil { return fmt.Errorf("Could not kill running container %s, cannot remove - %v", container.ID, err) @@ -164,7 +165,7 @@ func (daemon *Daemon) VolumeRm(name string, force bool) error { err = daemon.volumeRm(v) if err != nil && volumestore.IsInUse(err) { - return stateConflictError{err} + return errdefs.Conflict(err) } if err == nil || force { diff --git a/daemon/errors.go b/daemon/errors.go index 69c09fb83d..e3a16b0586 100644 --- a/daemon/errors.go +++ b/daemon/errors.go @@ -5,12 +5,13 @@ import ( "strings" "syscall" + "github.com/docker/docker/errdefs" "github.com/pkg/errors" "google.golang.org/grpc" ) func errNotRunning(id string) error { - return stateConflictError{errors.Errorf("Container %s is not running", id)} + return errdefs.Conflict(errors.Errorf("Container %s is not running", id)) } func containerNotFound(id string) error { @@ -32,23 +33,9 @@ func (e objNotFoundError) Error() string { func (e objNotFoundError) NotFound() {} -type stateConflictError struct { - cause error -} - -func (e stateConflictError) Error() string { - return e.cause.Error() -} - -func (e stateConflictError) Cause() error { - return e.cause -} - -func (e stateConflictError) Conflict() {} - func errContainerIsRestarting(containerID string) error { cause := errors.Errorf("Container %s is restarting, wait until the container is running", containerID) - return stateConflictError{cause} + return errdefs.Conflict(cause) } func errExecNotFound(id string) error { @@ -57,12 +44,12 @@ func errExecNotFound(id string) error { func errExecPaused(id string) error { cause := errors.Errorf("Container %s is paused, unpause the container before exec", id) - return stateConflictError{cause} + return errdefs.Conflict(cause) } func errNotPaused(id string) error { cause := errors.Errorf("Container %s is already paused", id) - return stateConflictError{cause} + return errdefs.Conflict(cause) } type nameConflictError struct { @@ -76,34 +63,6 @@ func (e nameConflictError) Error() string { func (nameConflictError) Conflict() {} -type validationError struct { - cause error -} - -func (e validationError) Error() string { - return e.cause.Error() -} - -func (e validationError) InvalidParameter() {} - -func (e validationError) Cause() error { - return e.cause -} - -type notAllowedError struct { - cause error -} - -func (e notAllowedError) Error() string { - return e.cause.Error() -} - -func (e notAllowedError) Forbidden() {} - -func (e notAllowedError) Cause() error { - return e.cause -} - type containerNotModifiedError struct { running bool } @@ -117,20 +76,6 @@ func (e containerNotModifiedError) Error() string { func (e containerNotModifiedError) NotModified() {} -type systemError struct { - cause error -} - -func (e systemError) Error() string { - return e.cause.Error() -} - -func (e systemError) SystemError() {} - -func (e systemError) Cause() error { - return e.cause -} - type invalidIdentifier string func (e invalidIdentifier) Error() string { @@ -172,20 +117,6 @@ func (e invalidFilter) Error() string { func (e invalidFilter) InvalidParameter() {} -type unknownError struct { - cause error -} - -func (e unknownError) Error() string { - return e.cause.Error() -} - -func (unknownError) Unknown() {} - -func (e unknownError) Cause() error { - return e.cause -} - type startInvalidConfigError string func (e startInvalidConfigError) Error() string { @@ -199,7 +130,7 @@ func translateContainerdStartErr(cmd string, setExitCode func(int), err error) e contains := func(s1, s2 string) bool { return strings.Contains(strings.ToLower(s1), s2) } - var retErr error = unknownError{errors.New(errDesc)} + var retErr = errdefs.Unknown(errors.New(errDesc)) // if we receive an internal error from the initial start of a container then lets // return it instead of entering the restart loop // set to 127 for container cmd not found/does not exist) diff --git a/daemon/exec.go b/daemon/exec.go index 83b7de2255..6fe107987a 100644 --- a/daemon/exec.go +++ b/daemon/exec.go @@ -13,6 +13,7 @@ import ( "github.com/docker/docker/container" "github.com/docker/docker/container/stream" "github.com/docker/docker/daemon/exec" + "github.com/docker/docker/errdefs" "github.com/docker/docker/pkg/pools" "github.com/docker/docker/pkg/signal" "github.com/docker/docker/pkg/term" @@ -161,12 +162,12 @@ func (d *Daemon) ContainerExecStart(ctx context.Context, name string, stdin io.R if ec.ExitCode != nil { ec.Unlock() err := fmt.Errorf("Error: Exec command %s has already run", ec.ID) - return stateConflictError{err} + return errdefs.Conflict(err) } if ec.Running { ec.Unlock() - return stateConflictError{fmt.Errorf("Error: Exec command %s is already running", ec.ID)} + return errdefs.Conflict(fmt.Errorf("Error: Exec command %s is already running", ec.ID)) } ec.Running = true ec.Unlock() @@ -267,7 +268,7 @@ func (d *Daemon) ContainerExecStart(ctx context.Context, name string, stdin io.R case err := <-attachErr: if err != nil { if _, ok := err.(term.EscapeError); !ok { - return errors.Wrap(systemError{err}, "exec attach failed") + return errdefs.System(errors.Wrap(err, "exec attach failed")) } d.LogContainerEvent(c, "exec_detach") } diff --git a/daemon/export.go b/daemon/export.go index c0e6affbe0..66a0cca048 100644 --- a/daemon/export.go +++ b/daemon/export.go @@ -6,6 +6,7 @@ import ( "runtime" "github.com/docker/docker/container" + "github.com/docker/docker/errdefs" "github.com/docker/docker/pkg/archive" "github.com/docker/docker/pkg/ioutils" ) @@ -24,12 +25,12 @@ func (daemon *Daemon) ContainerExport(name string, out io.Writer) error { if container.IsDead() { err := fmt.Errorf("You cannot export container %s which is Dead", container.ID) - return stateConflictError{err} + return errdefs.Conflict(err) } if container.IsRemovalInProgress() { err := fmt.Errorf("You cannot export container %s which is being removed", container.ID) - return stateConflictError{err} + return errdefs.Conflict(err) } data, err := daemon.containerExport(container) diff --git a/daemon/graphdriver/quota/errors.go b/daemon/graphdriver/quota/errors.go index 1741f2f5db..6d755904a8 100644 --- a/daemon/graphdriver/quota/errors.go +++ b/daemon/graphdriver/quota/errors.go @@ -1,6 +1,6 @@ package quota -import "github.com/docker/docker/api/errdefs" +import "github.com/docker/docker/errdefs" var ( _ errdefs.ErrNotImplemented = (*errQuotaNotSupported)(nil) diff --git a/daemon/image.go b/daemon/image.go index 486f2a2c17..fdbd6e2be7 100644 --- a/daemon/image.go +++ b/daemon/image.go @@ -5,6 +5,7 @@ import ( "runtime" "github.com/docker/distribution/reference" + "github.com/docker/docker/errdefs" "github.com/docker/docker/image" ) @@ -28,7 +29,7 @@ func (e errImageDoesNotExist) NotFound() {} func (daemon *Daemon) GetImageIDAndOS(refOrID string) (image.ID, string, error) { ref, err := reference.ParseAnyReference(refOrID) if err != nil { - return "", "", validationError{err} + return "", "", errdefs.InvalidParameter(err) } namedRef, ok := ref.(reference.Named) if !ok { diff --git a/daemon/image_delete.go b/daemon/image_delete.go index 8e51931cc4..36ac2c7c68 100644 --- a/daemon/image_delete.go +++ b/daemon/image_delete.go @@ -8,6 +8,7 @@ import ( "github.com/docker/distribution/reference" "github.com/docker/docker/api/types" "github.com/docker/docker/container" + "github.com/docker/docker/errdefs" "github.com/docker/docker/image" "github.com/docker/docker/pkg/stringid" "github.com/pkg/errors" @@ -85,7 +86,7 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I // we really want to avoid that the client must // explicitly force its removal. err := errors.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, stateConflictError{err} + return nil, errdefs.Conflict(err) } } diff --git a/daemon/image_pull.go b/daemon/image_pull.go index aef1876bad..4944721f9f 100644 --- a/daemon/image_pull.go +++ b/daemon/image_pull.go @@ -10,6 +10,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/distribution" progressutils "github.com/docker/docker/distribution/utils" + "github.com/docker/docker/errdefs" "github.com/docker/docker/pkg/progress" "github.com/docker/docker/registry" "github.com/opencontainers/go-digest" @@ -26,7 +27,7 @@ func (daemon *Daemon) PullImage(ctx context.Context, image, tag, platform string ref, err := reference.ParseNormalizedNamed(image) if err != nil { - return validationError{err} + return errdefs.InvalidParameter(err) } if tag != "" { @@ -39,7 +40,7 @@ func (daemon *Daemon) PullImage(ctx context.Context, image, tag, platform string ref, err = reference.WithTag(ref, tag) } if err != nil { - return validationError{err} + return errdefs.InvalidParameter(err) } } @@ -96,7 +97,7 @@ func (daemon *Daemon) GetRepository(ctx context.Context, ref reference.Named, au } // makes sure name is not empty or `scratch` if err := distribution.ValidateRepoName(repoInfo.Name); err != nil { - return nil, false, validationError{err} + return nil, false, errdefs.InvalidParameter(err) } // get endpoints diff --git a/daemon/import.go b/daemon/import.go index 3a25bb823e..3ac83a9fa9 100644 --- a/daemon/import.go +++ b/daemon/import.go @@ -14,6 +14,7 @@ import ( "github.com/docker/docker/builder/dockerfile" "github.com/docker/docker/builder/remotecontext" "github.com/docker/docker/dockerversion" + "github.com/docker/docker/errdefs" "github.com/docker/docker/image" "github.com/docker/docker/layer" "github.com/docker/docker/pkg/archive" @@ -42,16 +43,16 @@ func (daemon *Daemon) ImportImage(src string, repository, os string, tag string, var err error newRef, err = reference.ParseNormalizedNamed(repository) if err != nil { - return validationError{err} + return errdefs.InvalidParameter(err) } if _, isCanonical := newRef.(reference.Canonical); isCanonical { - return validationError{errors.New("cannot import digest reference")} + return errdefs.InvalidParameter(errors.New("cannot import digest reference")) } if tag != "" { newRef, err = reference.WithTag(newRef, tag) if err != nil { - return validationError{err} + return errdefs.InvalidParameter(err) } } } @@ -69,7 +70,7 @@ func (daemon *Daemon) ImportImage(src string, repository, os string, tag string, } u, err := url.Parse(src) if err != nil { - return validationError{err} + return errdefs.InvalidParameter(err) } resp, err = remotecontext.GetWithStatusError(u.String()) diff --git a/daemon/inspect.go b/daemon/inspect.go index 20cfa6ce2b..cab4f9279c 100644 --- a/daemon/inspect.go +++ b/daemon/inspect.go @@ -11,6 +11,7 @@ import ( "github.com/docker/docker/api/types/versions/v1p20" "github.com/docker/docker/container" "github.com/docker/docker/daemon/network" + "github.com/docker/docker/errdefs" volumestore "github.com/docker/docker/volume/store" "github.com/docker/go-connections/nat" ) @@ -188,7 +189,7 @@ func (daemon *Daemon) getInspectData(container *container.Container) (*types.Con // could have been removed, it will cause error if we try to get the metadata, // we can ignore the error if the container is dead. if err != nil && !container.Dead { - return nil, systemError{err} + return nil, errdefs.System(err) } contJSONBase.GraphDriver.Data = graphDriverData @@ -232,7 +233,7 @@ func (daemon *Daemon) VolumeInspect(name string) (*types.Volume, error) { if volumestore.IsNotExist(err) { return nil, volumeNotFound(name) } - return nil, systemError{err} + return nil, errdefs.System(err) } apiV := volumeToAPIType(v) apiV.Mountpoint = v.Path() diff --git a/daemon/kill.go b/daemon/kill.go index 5cde0d776d..ad6104bfe9 100644 --- a/daemon/kill.go +++ b/daemon/kill.go @@ -7,8 +7,8 @@ import ( "syscall" "time" - "github.com/docker/docker/api/errdefs" containerpkg "github.com/docker/docker/container" + "github.com/docker/docker/errdefs" "github.com/docker/docker/libcontainerd" "github.com/docker/docker/pkg/signal" "github.com/pkg/errors" diff --git a/daemon/list.go b/daemon/list.go index c87dd6ec1e..8598d25280 100644 --- a/daemon/list.go +++ b/daemon/list.go @@ -9,6 +9,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/container" + "github.com/docker/docker/errdefs" "github.com/docker/docker/image" "github.com/docker/docker/volume" "github.com/docker/go-connections/nat" @@ -290,7 +291,7 @@ func (daemon *Daemon) foldFilter(view container.View, config *types.ContainerLis err = psFilters.WalkValues("health", func(value string) error { if !container.IsValidHealthString(value) { - return validationError{errors.Errorf("Unrecognised filter value for health: %s", value)} + return errdefs.InvalidParameter(errors.Errorf("Unrecognised filter value for health: %s", value)) } return nil diff --git a/daemon/logs.go b/daemon/logs.go index 131360b7b4..c819768dc3 100644 --- a/daemon/logs.go +++ b/daemon/logs.go @@ -13,6 +13,7 @@ import ( timetypes "github.com/docker/docker/api/types/time" "github.com/docker/docker/container" "github.com/docker/docker/daemon/logger" + "github.com/docker/docker/errdefs" "github.com/sirupsen/logrus" ) @@ -30,7 +31,7 @@ func (daemon *Daemon) ContainerLogs(ctx context.Context, containerName string, c }) if !(config.ShowStdout || config.ShowStderr) { - return nil, false, validationError{errors.New("You must choose at least one stream")} + return nil, false, errdefs.InvalidParameter(errors.New("You must choose at least one stream")) } container, err := daemon.GetContainer(containerName) if err != nil { @@ -38,7 +39,7 @@ func (daemon *Daemon) ContainerLogs(ctx context.Context, containerName string, c } if container.RemovalInProgress || container.Dead { - return nil, false, stateConflictError{errors.New("can not get logs from container which is dead or marked for removal")} + return nil, false, errdefs.Conflict(errors.New("can not get logs from container which is dead or marked for removal")) } if container.HostConfig.LogConfig.Type == "none" { diff --git a/daemon/names.go b/daemon/names.go index 3ef96b1cdc..0e43738849 100644 --- a/daemon/names.go +++ b/daemon/names.go @@ -6,6 +6,7 @@ import ( "github.com/docker/docker/container" "github.com/docker/docker/daemon/names" + "github.com/docker/docker/errdefs" "github.com/docker/docker/pkg/namesgenerator" "github.com/docker/docker/pkg/stringid" "github.com/pkg/errors" @@ -56,7 +57,7 @@ func (daemon *Daemon) generateIDAndName(name string) (string, string, error) { func (daemon *Daemon) reserveName(id, name string) (string, error) { if !validContainerNamePattern.MatchString(strings.TrimPrefix(name, "/")) { - return "", validationError{errors.Errorf("Invalid container name (%s), only %s are allowed", name, validContainerNameChars)} + return "", errdefs.InvalidParameter(errors.Errorf("Invalid container name (%s), only %s are allowed", name, validContainerNameChars)) } if name[0] != '/' { name = "/" + name diff --git a/daemon/network.go b/daemon/network.go index cf3d015b80..35db27148a 100644 --- a/daemon/network.go +++ b/daemon/network.go @@ -11,6 +11,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/network" clustertypes "github.com/docker/docker/daemon/cluster/provider" + "github.com/docker/docker/errdefs" "github.com/docker/docker/pkg/plugingetter" "github.com/docker/docker/runconfig" "github.com/docker/libnetwork" @@ -52,13 +53,17 @@ func (daemon *Daemon) FindUniqueNetwork(term string) (libnetwork.Network, error) case len(listByFullName) == 1: return listByFullName[0], nil case len(listByFullName) > 1: - return nil, fmt.Errorf("network %s is ambiguous (%d matches found based on name)", term, len(listByFullName)) + return nil, errdefs.InvalidParameter(errors.Errorf("network %s is ambiguous (%d matches found on name)", term, len(listByFullName))) case len(listByPartialID) == 1: return listByPartialID[0], nil case len(listByPartialID) > 1: - return nil, fmt.Errorf("network %s is ambiguous (%d matches found based on ID prefix)", term, len(listByPartialID)) + return nil, errdefs.InvalidParameter(errors.Errorf("network %s is ambiguous (%d matches found based on ID prefix)", term, len(listByPartialID))) } - return nil, libnetwork.ErrNoSuchNetwork(term) + + // Be very careful to change the error type here, the + // libnetwork.ErrNoSuchNetwork error is used by the controller + // to retry the creation of the network as managed through the swarm manager + return nil, errdefs.NotFound(libnetwork.ErrNoSuchNetwork(term)) } // GetNetworkByID function returns a network whose ID matches the given ID. @@ -264,7 +269,7 @@ func (daemon *Daemon) CreateNetwork(create types.NetworkCreateRequest) (*types.N func (daemon *Daemon) createNetwork(create types.NetworkCreateRequest, id string, agent bool) (*types.NetworkCreateResponse, error) { if runconfig.IsPreDefinedNetwork(create.Name) && !agent { err := fmt.Errorf("%s is a pre-defined network and cannot be created", create.Name) - return nil, notAllowedError{err} + return nil, errdefs.Forbidden(err) } var warning string @@ -522,7 +527,7 @@ func (daemon *Daemon) deleteLoadBalancerSandbox(n libnetwork.Network) { func (daemon *Daemon) deleteNetwork(nw libnetwork.Network, dynamic bool) error { if runconfig.IsPreDefinedNetwork(nw.Name()) && !dynamic { err := fmt.Errorf("%s is a pre-defined network and cannot be removed", nw.Name()) - return notAllowedError{err} + return errdefs.Forbidden(err) } if dynamic && !nw.Info().Dynamic() { @@ -532,7 +537,7 @@ func (daemon *Daemon) deleteNetwork(nw libnetwork.Network, dynamic bool) error { return nil } err := fmt.Errorf("%s is not a dynamic network", nw.Name()) - return notAllowedError{err} + return errdefs.Forbidden(err) } if err := nw.Delete(); err != nil { diff --git a/daemon/rename.go b/daemon/rename.go index 26ee9beaea..fd13d898e2 100644 --- a/daemon/rename.go +++ b/daemon/rename.go @@ -4,6 +4,7 @@ import ( "strings" dockercontainer "github.com/docker/docker/container" + "github.com/docker/docker/errdefs" "github.com/docker/libnetwork" "github.com/pkg/errors" "github.com/sirupsen/logrus" @@ -19,7 +20,7 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) error { ) if oldName == "" || newName == "" { - return validationError{errors.New("Neither old nor new names may be empty")} + return errdefs.InvalidParameter(errors.New("Neither old nor new names may be empty")) } if newName[0] != '/' { @@ -38,13 +39,13 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) error { oldIsAnonymousEndpoint := container.NetworkSettings.IsAnonymousEndpoint if oldName == newName { - return validationError{errors.New("Renaming a container with the same name as its current name")} + return errdefs.InvalidParameter(errors.New("Renaming a container with the same name as its current name")) } links := map[string]*dockercontainer.Container{} for k, v := range daemon.linkIndex.children(container) { if !strings.HasPrefix(k, oldName) { - return validationError{errors.Errorf("Linked container %s does not match parent %s", k, oldName)} + return errdefs.InvalidParameter(errors.Errorf("Linked container %s does not match parent %s", k, oldName)) } links[strings.TrimPrefix(k, oldName)] = v } diff --git a/daemon/start.go b/daemon/start.go index 7f9d682f02..008fb050d4 100644 --- a/daemon/start.go +++ b/daemon/start.go @@ -8,6 +8,7 @@ import ( "github.com/docker/docker/api/types" containertypes "github.com/docker/docker/api/types/container" "github.com/docker/docker/container" + "github.com/docker/docker/errdefs" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -15,7 +16,7 @@ import ( // ContainerStart starts a container. func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.HostConfig, checkpoint string, checkpointDir string) error { if checkpoint != "" && !daemon.HasExperimental() { - return validationError{errors.New("checkpoint is only supported in experimental mode")} + return errdefs.InvalidParameter(errors.New("checkpoint is only supported in experimental mode")) } container, err := daemon.GetContainer(name) @@ -28,7 +29,7 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.Hos defer container.Unlock() if container.Paused { - return stateConflictError{errors.New("cannot start a paused container, try unpause instead")} + return errdefs.Conflict(errors.New("cannot start a paused container, try unpause instead")) } if container.Running { @@ -36,7 +37,7 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.Hos } if container.RemovalInProgress || container.Dead { - return stateConflictError{errors.New("container is marked for removal and cannot be started")} + return errdefs.Conflict(errors.New("container is marked for removal and cannot be started")) } return nil } @@ -53,13 +54,13 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.Hos logrus.Warn("DEPRECATED: Setting host configuration options when the container starts is deprecated and has been removed in Docker 1.12") oldNetworkMode := container.HostConfig.NetworkMode if err := daemon.setSecurityOptions(container, hostConfig); err != nil { - return validationError{err} + return errdefs.InvalidParameter(err) } if err := daemon.mergeAndVerifyLogConfig(&hostConfig.LogConfig); err != nil { - return validationError{err} + return errdefs.InvalidParameter(err) } if err := daemon.setHostConfig(container, hostConfig); err != nil { - return validationError{err} + return errdefs.InvalidParameter(err) } newNetworkMode := container.HostConfig.NetworkMode if string(oldNetworkMode) != string(newNetworkMode) { @@ -67,27 +68,27 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.Hos // old networks. It is a deprecated feature and has been removed in Docker 1.12 container.NetworkSettings.Networks = nil if err := container.CheckpointTo(daemon.containersReplica); err != nil { - return systemError{err} + return errdefs.System(err) } } container.InitDNSHostConfig() } } else { if hostConfig != nil { - return validationError{errors.New("Supplying a hostconfig on start is not supported. It should be supplied on create")} + return errdefs.InvalidParameter(errors.New("Supplying a hostconfig on start is not supported. It should be supplied on create")) } } // check if hostConfig is in line with the current system settings. // It may happen cgroups are umounted or the like. if _, err = daemon.verifyContainerSettings(container.OS, container.HostConfig, nil, false); err != nil { - return validationError{err} + return errdefs.InvalidParameter(err) } // Adapt for old containers in case we have updates in this function and // old containers never have chance to call the new function in create stage. if hostConfig != nil { if err := daemon.adaptContainerSettings(container.HostConfig, false); err != nil { - return validationError{err} + return errdefs.InvalidParameter(err) } } return daemon.containerStart(container, checkpoint, checkpointDir, true) @@ -107,12 +108,12 @@ func (daemon *Daemon) containerStart(container *container.Container, checkpoint } if container.RemovalInProgress || container.Dead { - return stateConflictError{errors.New("container is marked for removal and cannot be started")} + return errdefs.Conflict(errors.New("container is marked for removal and cannot be started")) } if checkpointDir != "" { // TODO(mlaventure): how would we support that? - return notAllowedError{errors.New("custom checkpointdir is not supported")} + return errdefs.Forbidden(errors.New("custom checkpointdir is not supported")) } // if we encounter an error during start we need to ensure that any other @@ -151,7 +152,7 @@ func (daemon *Daemon) containerStart(container *container.Container, checkpoint spec, err := daemon.createSpec(container) if err != nil { - return systemError{err} + return errdefs.System(err) } if resetRestartManager { diff --git a/daemon/start_unix.go b/daemon/start_unix.go index 119b0a9240..ca0183ec5c 100644 --- a/daemon/start_unix.go +++ b/daemon/start_unix.go @@ -9,6 +9,7 @@ import ( "github.com/containerd/containerd/linux/runctypes" "github.com/docker/docker/container" + "github.com/docker/docker/errdefs" "github.com/pkg/errors" ) @@ -16,7 +17,7 @@ func (daemon *Daemon) getRuntimeScript(container *container.Container) (string, name := container.HostConfig.Runtime rt := daemon.configStore.GetRuntime(name) if rt == nil { - return "", validationError{errors.Errorf("no such runtime '%s'", name)} + return "", errdefs.InvalidParameter(errors.Errorf("no such runtime '%s'", name)) } if len(rt.Args) > 0 { diff --git a/daemon/stop.go b/daemon/stop.go index 71d0b2ab9c..d3b5297fb2 100644 --- a/daemon/stop.go +++ b/daemon/stop.go @@ -5,6 +5,7 @@ import ( "time" containerpkg "github.com/docker/docker/container" + "github.com/docker/docker/errdefs" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -28,7 +29,7 @@ func (daemon *Daemon) ContainerStop(name string, seconds *int) error { seconds = &stopTimeout } if err := daemon.containerStop(container, *seconds); err != nil { - return errors.Wrapf(systemError{err}, "cannot stop container: %s", name) + return errdefs.System(errors.Wrapf(err, "cannot stop container: %s", name)) } return nil } diff --git a/daemon/update.go b/daemon/update.go index 0a79c199f3..d2eb33a75e 100644 --- a/daemon/update.go +++ b/daemon/update.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/docker/docker/api/types/container" + "github.com/docker/docker/errdefs" "github.com/pkg/errors" ) @@ -19,7 +20,7 @@ func (daemon *Daemon) ContainerUpdate(name string, hostConfig *container.HostCon warnings, err = daemon.verifyContainerSettings(c.OS, hostConfig, nil, true) if err != nil { - return container.ContainerUpdateOKBody{Warnings: warnings}, validationError{err} + return container.ContainerUpdateOKBody{Warnings: warnings}, errdefs.InvalidParameter(err) } if err := daemon.update(name, hostConfig); err != nil { @@ -80,7 +81,7 @@ func (daemon *Daemon) update(name string, hostConfig *container.HostConfig) erro if err := daemon.containerd.UpdateResources(context.Background(), container.ID, toContainerdResources(hostConfig.Resources)); err != nil { restoreConfig = true // TODO: it would be nice if containerd responded with better errors here so we can classify this better. - return errCannotUpdate(container.ID, systemError{err}) + return errCannotUpdate(container.ID, errdefs.System(err)) } } diff --git a/daemon/volumes.go b/daemon/volumes.go index 6a42ec23e5..2e75feebda 100644 --- a/daemon/volumes.go +++ b/daemon/volumes.go @@ -12,6 +12,7 @@ import ( containertypes "github.com/docker/docker/api/types/container" mounttypes "github.com/docker/docker/api/types/mount" "github.com/docker/docker/container" + "github.com/docker/docker/errdefs" "github.com/docker/docker/volume" "github.com/docker/docker/volume/drivers" "github.com/pkg/errors" @@ -175,7 +176,7 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo for _, cfg := range hostConfig.Mounts { mp, err := parser.ParseMountSpec(cfg) if err != nil { - return validationError{err} + return errdefs.InvalidParameter(err) } if binds[mp.Destination] { diff --git a/distribution/errors.go b/distribution/errors.go index 355e9da1bd..49e8e5c0c1 100644 --- a/distribution/errors.go +++ b/distribution/errors.go @@ -13,6 +13,7 @@ import ( "github.com/docker/distribution/registry/client" "github.com/docker/distribution/registry/client/auth" "github.com/docker/docker/distribution/xfer" + "github.com/docker/docker/errdefs" "github.com/sirupsen/logrus" ) @@ -85,20 +86,6 @@ func (e notFoundError) Cause() error { return e.cause } -type unknownError struct { - cause error -} - -func (e unknownError) Error() string { - return e.cause.Error() -} - -func (e unknownError) Cause() error { - return e.cause -} - -func (e unknownError) Unknown() {} - // TranslatePullError is used to convert an error from a registry pull // operation to an error representing the entire pull operation. Any error // information which is not used by the returned error gets output to @@ -121,7 +108,7 @@ func TranslatePullError(err error, ref reference.Named) error { return TranslatePullError(v.Err, ref) } - return unknownError{err} + return errdefs.Unknown(err) } // continueOnError returns true if we should fallback to the next endpoint diff --git a/api/errdefs/defs.go b/errdefs/defs.go similarity index 75% rename from api/errdefs/defs.go rename to errdefs/defs.go index 4987c623f0..29c3619600 100644 --- a/api/errdefs/defs.go +++ b/errdefs/defs.go @@ -43,6 +43,11 @@ type ErrNotModified interface { NotModified() } +// ErrAlreadyExists is a special case of ErrConflict which signals that the desired object already exists +type ErrAlreadyExists interface { + AlreadyExists() +} + // ErrNotImplemented signals that the requested action/feature is not implemented on the system as configured. type ErrNotImplemented interface { NotImplemented() @@ -52,3 +57,18 @@ type ErrNotImplemented interface { type ErrUnknown interface { Unknown() } + +// ErrCancelled signals that the action was cancelled. +type ErrCancelled interface { + Cancelled() +} + +// ErrDeadline signals that the deadline was reached before the action completed. +type ErrDeadline interface { + DeadlineExceeded() +} + +// ErrDataLoss indicates that data was lost or there is data corruption. +type ErrDataLoss interface { + DataLoss() +} diff --git a/api/errdefs/doc.go b/errdefs/doc.go similarity index 100% rename from api/errdefs/doc.go rename to errdefs/doc.go diff --git a/errdefs/helpers.go b/errdefs/helpers.go new file mode 100644 index 0000000000..5afa944461 --- /dev/null +++ b/errdefs/helpers.go @@ -0,0 +1,240 @@ +package errdefs + +import "context" + +type errNotFound struct{ error } + +func (errNotFound) NotFound() {} + +func (e errNotFound) Cause() error { + return e.error +} + +// NotFound is a helper to create an error of the class with the same name from any error type +func NotFound(err error) error { + if err == nil { + return nil + } + return errNotFound{err} +} + +type errInvalidParameter struct{ error } + +func (errInvalidParameter) InvalidParameter() {} + +func (e errInvalidParameter) Cause() error { + return e.error +} + +// InvalidParameter is a helper to create an error of the class with the same name from any error type +func InvalidParameter(err error) error { + if err == nil { + return nil + } + return errInvalidParameter{err} +} + +type errConflict struct{ error } + +func (errConflict) Conflict() {} + +func (e errConflict) Cause() error { + return e.error +} + +// Conflict is a helper to create an error of the class with the same name from any error type +func Conflict(err error) error { + if err == nil { + return nil + } + return errConflict{err} +} + +type errUnauthorized struct{ error } + +func (errUnauthorized) Unauthorized() {} + +func (e errUnauthorized) Cause() error { + return e.error +} + +// Unauthorized is a helper to create an error of the class with the same name from any error type +func Unauthorized(err error) error { + if err == nil { + return nil + } + return errUnauthorized{err} +} + +type errUnavailable struct{ error } + +func (errUnavailable) Unavailable() {} + +func (e errUnavailable) Cause() error { + return e.error +} + +// Unavailable is a helper to create an error of the class with the same name from any error type +func Unavailable(err error) error { + return errUnavailable{err} +} + +type errForbidden struct{ error } + +func (errForbidden) Forbidden() {} + +func (e errForbidden) Cause() error { + return e.error +} + +// Forbidden is a helper to create an error of the class with the same name from any error type +func Forbidden(err error) error { + if err == nil { + return nil + } + return errForbidden{err} +} + +type errSystem struct{ error } + +func (errSystem) System() {} + +func (e errSystem) Cause() error { + return e.error +} + +// System is a helper to create an error of the class with the same name from any error type +func System(err error) error { + if err == nil { + return nil + } + return errSystem{err} +} + +type errNotModified struct{ error } + +func (errNotModified) NotModified() {} + +func (e errNotModified) Cause() error { + return e.error +} + +// NotModified is a helper to create an error of the class with the same name from any error type +func NotModified(err error) error { + if err == nil { + return nil + } + return errNotModified{err} +} + +type errAlreadyExists struct{ error } + +func (errAlreadyExists) AlreadyExists() {} + +func (e errAlreadyExists) Cause() error { + return e.error +} + +// AlreadyExists is a helper to create an error of the class with the same name from any error type +func AlreadyExists(err error) error { + if err == nil { + return nil + } + return errAlreadyExists{err} +} + +type errNotImplemented struct{ error } + +func (errNotImplemented) NotImplemented() {} + +func (e errNotImplemented) Cause() error { + return e.error +} + +// NotImplemented is a helper to create an error of the class with the same name from any error type +func NotImplemented(err error) error { + if err == nil { + return nil + } + return errNotImplemented{err} +} + +type errUnknown struct{ error } + +func (errUnknown) Unknown() {} + +func (e errUnknown) Cause() error { + return e.error +} + +// Unknown is a helper to create an error of the class with the same name from any error type +func Unknown(err error) error { + if err == nil { + return nil + } + return errUnknown{err} +} + +type errCancelled struct{ error } + +func (errCancelled) Cancelled() {} + +func (e errCancelled) Cause() error { + return e.error +} + +// Cancelled is a helper to create an error of the class with the same name from any error type +func Cancelled(err error) error { + if err == nil { + return nil + } + return errCancelled{err} +} + +type errDeadline struct{ error } + +func (errDeadline) DeadlineExceeded() {} + +func (e errDeadline) Cause() error { + return e.error +} + +// Deadline is a helper to create an error of the class with the same name from any error type +func Deadline(err error) error { + if err == nil { + return nil + } + return errDeadline{err} +} + +type errDataLoss struct{ error } + +func (errDataLoss) DataLoss() {} + +func (e errDataLoss) Cause() error { + return e.error +} + +// DataLoss is a helper to create an error of the class with the same name from any error type +func DataLoss(err error) error { + if err == nil { + return nil + } + return errDataLoss{err} +} + +// FromContext returns the error class from the passed in context +func FromContext(ctx context.Context) error { + e := ctx.Err() + if e == nil { + return nil + } + + if e == context.Canceled { + return Cancelled(e) + } + if e == context.DeadlineExceeded { + return Deadline(e) + } + return Unknown(e) +} diff --git a/errdefs/helpers_test.go b/errdefs/helpers_test.go new file mode 100644 index 0000000000..984f0a77a9 --- /dev/null +++ b/errdefs/helpers_test.go @@ -0,0 +1,132 @@ +package errdefs + +import ( + "errors" + "testing" +) + +var errTest = errors.New("this is a test") + +type causal interface { + Cause() error +} + +func TestNotFound(t *testing.T) { + e := NotFound(errTest) + if !IsNotFound(e) { + t.Fatalf("expected not found error, got: %T", e) + } + if cause := e.(causal).Cause(); cause != errTest { + t.Fatalf("causual should be errTest, got: %v", cause) + } +} + +func TestConflict(t *testing.T) { + e := Conflict(errTest) + if !IsConflict(e) { + t.Fatalf("expected conflcit error, got: %T", e) + } + if cause := e.(causal).Cause(); cause != errTest { + t.Fatalf("causual should be errTest, got: %v", cause) + } +} + +func TestForbidden(t *testing.T) { + e := Forbidden(errTest) + if !IsForbidden(e) { + t.Fatalf("expected forbidden error, got: %T", e) + } + if cause := e.(causal).Cause(); cause != errTest { + t.Fatalf("causual should be errTest, got: %v", cause) + } +} + +func TestInvalidParameter(t *testing.T) { + e := InvalidParameter(errTest) + if !IsInvalidParameter(e) { + t.Fatalf("expected invalid argument error, got %T", e) + } + if cause := e.(causal).Cause(); cause != errTest { + t.Fatalf("causual should be errTest, got: %v", cause) + } +} + +func TestNotImplemented(t *testing.T) { + e := NotImplemented(errTest) + if !IsNotImplemented(e) { + t.Fatalf("expected not implemented error, got %T", e) + } + if cause := e.(causal).Cause(); cause != errTest { + t.Fatalf("causual should be errTest, got: %v", cause) + } +} + +func TestNotModified(t *testing.T) { + e := NotModified(errTest) + if !IsNotModified(e) { + t.Fatalf("expected not modified error, got %T", e) + } + if cause := e.(causal).Cause(); cause != errTest { + t.Fatalf("causual should be errTest, got: %v", cause) + } +} + +func TestAlreadyExists(t *testing.T) { + e := AlreadyExists(errTest) + if !IsAlreadyExists(e) { + t.Fatalf("expected already exists error, got %T", e) + } + if cause := e.(causal).Cause(); cause != errTest { + t.Fatalf("causual should be errTest, got: %v", cause) + } +} + +func TestUnauthorized(t *testing.T) { + e := Unauthorized(errTest) + if !IsUnauthorized(e) { + t.Fatalf("expected unauthorized error, got %T", e) + } + if cause := e.(causal).Cause(); cause != errTest { + t.Fatalf("causual should be errTest, got: %v", cause) + } +} + +func TestUnknown(t *testing.T) { + e := Unknown(errTest) + if !IsUnknown(e) { + t.Fatalf("expected unknown error, got %T", e) + } + if cause := e.(causal).Cause(); cause != errTest { + t.Fatalf("causual should be errTest, got: %v", cause) + } +} + +func TestCancelled(t *testing.T) { + e := Cancelled(errTest) + if !IsCancelled(e) { + t.Fatalf("expected canclled error, got %T", e) + } + if cause := e.(causal).Cause(); cause != errTest { + t.Fatalf("causual should be errTest, got: %v", cause) + } +} + +func TestDeadline(t *testing.T) { + e := Deadline(errTest) + if !IsDeadline(e) { + t.Fatalf("expected deadline error, got %T", e) + } + if cause := e.(causal).Cause(); cause != errTest { + t.Fatalf("causual should be errTest, got: %v", cause) + } +} + +func TestIsDataLoss(t *testing.T) { + e := DataLoss(errTest) + if !IsDataLoss(e) { + t.Fatalf("expected data loss error, got %T", e) + } + if cause := e.(causal).Cause(); cause != errTest { + t.Fatalf("causual should be errTest, got: %v", cause) + } +} diff --git a/api/errdefs/is.go b/errdefs/is.go similarity index 74% rename from api/errdefs/is.go rename to errdefs/is.go index b0be0b8147..286ffd694a 100644 --- a/api/errdefs/is.go +++ b/errdefs/is.go @@ -15,7 +15,11 @@ func getImplementer(err error) error { ErrForbidden, ErrSystem, ErrNotModified, + ErrAlreadyExists, ErrNotImplemented, + ErrCancelled, + ErrDeadline, + ErrDataLoss, ErrUnknown: return e case causer: @@ -73,6 +77,12 @@ func IsNotModified(err error) bool { return ok } +// IsAlreadyExists returns if the passed in error is a AlreadyExists error +func IsAlreadyExists(err error) bool { + _, ok := getImplementer(err).(ErrAlreadyExists) + return ok +} + // IsNotImplemented returns if the passed in error is an ErrNotImplemented func IsNotImplemented(err error) bool { _, ok := getImplementer(err).(ErrNotImplemented) @@ -84,3 +94,21 @@ func IsUnknown(err error) bool { _, ok := getImplementer(err).(ErrUnknown) return ok } + +// IsCancelled returns if the passed in error is an ErrCancelled +func IsCancelled(err error) bool { + _, ok := getImplementer(err).(ErrCancelled) + return ok +} + +// IsDeadline returns if the passed in error is an ErrDeadline +func IsDeadline(err error) bool { + _, ok := getImplementer(err).(ErrDeadline) + return ok +} + +// IsDataLoss returns if the passed in error is an ErrDataLoss +func IsDataLoss(err error) bool { + _, ok := getImplementer(err).(ErrDataLoss) + return ok +} diff --git a/libcontainerd/client_daemon.go b/libcontainerd/client_daemon.go index eb76fe117b..9e66d224c6 100644 --- a/libcontainerd/client_daemon.go +++ b/libcontainerd/client_daemon.go @@ -27,10 +27,11 @@ import ( "github.com/containerd/containerd/archive" "github.com/containerd/containerd/cio" "github.com/containerd/containerd/content" - "github.com/containerd/containerd/errdefs" + containerderrors "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" "github.com/containerd/containerd/linux/runctypes" "github.com/containerd/typeurl" + "github.com/docker/docker/errdefs" "github.com/docker/docker/pkg/ioutils" "github.com/opencontainers/image-spec/specs-go/v1" specs "github.com/opencontainers/runtime-spec/specs-go" @@ -181,7 +182,7 @@ func (c *client) Create(ctx context.Context, id string, ociSpec *specs.Spec, run bdir, err := prepareBundleDir(filepath.Join(c.stateDir, id), ociSpec) if err != nil { - return wrapSystemError(errors.Wrap(err, "prepare bundle dir failed")) + return errdefs.System(errors.Wrap(err, "prepare bundle dir failed")) } c.logger.WithField("bundle", bdir).WithField("root", ociSpec.Root.Path).Debug("bundle dir created") @@ -536,11 +537,11 @@ func (c *client) CreateCheckpoint(ctx context.Context, containerID, checkpointDi b, err := content.ReadBlob(ctx, c.remote.ContentStore(), img.Target().Digest) if err != nil { - return wrapSystemError(errors.Wrapf(err, "failed to retrieve checkpoint data")) + return errdefs.System(errors.Wrapf(err, "failed to retrieve checkpoint data")) } var index v1.Index if err := json.Unmarshal(b, &index); err != nil { - return wrapSystemError(errors.Wrapf(err, "failed to decode checkpoint data")) + return errdefs.System(errors.Wrapf(err, "failed to decode checkpoint data")) } var cpDesc *v1.Descriptor @@ -551,17 +552,17 @@ func (c *client) CreateCheckpoint(ctx context.Context, containerID, checkpointDi } } if cpDesc == nil { - return wrapSystemError(errors.Wrapf(err, "invalid checkpoint")) + return errdefs.System(errors.Wrapf(err, "invalid checkpoint")) } rat, err := c.remote.ContentStore().ReaderAt(ctx, cpDesc.Digest) if err != nil { - return wrapSystemError(errors.Wrapf(err, "failed to get checkpoint reader")) + return errdefs.System(errors.Wrapf(err, "failed to get checkpoint reader")) } defer rat.Close() _, err = archive.Apply(ctx, checkpointDir, content.NewReader(rat)) if err != nil { - return wrapSystemError(errors.Wrapf(err, "failed to read checkpoint reader")) + return errdefs.System(errors.Wrapf(err, "failed to read checkpoint reader")) } return err @@ -847,14 +848,14 @@ func wrapError(err error) error { switch { case err == nil: return nil - case errdefs.IsNotFound(err): - return wrapNotFoundError(err) + case containerderrors.IsNotFound(err): + return errdefs.NotFound(err) } msg := err.Error() for _, s := range []string{"container does not exist", "not found", "no such container"} { if strings.Contains(msg, s) { - return wrapNotFoundError(err) + return errdefs.NotFound(err) } } return err diff --git a/libcontainerd/errors.go b/libcontainerd/errors.go index db59ea878c..dcd2525312 100644 --- a/libcontainerd/errors.go +++ b/libcontainerd/errors.go @@ -1,46 +1,13 @@ package libcontainerd -import "errors" +import ( + "errors" -type liberr struct { - err error -} + "github.com/docker/docker/errdefs" +) -func (e liberr) Error() string { - return e.err.Error() -} +func newNotFoundError(err string) error { return errdefs.NotFound(errors.New(err)) } -func (e liberr) Cause() error { - return e.err -} +func newInvalidParameterError(err string) error { return errdefs.InvalidParameter(errors.New(err)) } -type notFoundErr struct { - liberr -} - -func (notFoundErr) NotFound() {} - -func newNotFoundError(err string) error { return notFoundErr{liberr{errors.New(err)}} } -func wrapNotFoundError(err error) error { return notFoundErr{liberr{err}} } - -type invalidParamErr struct { - liberr -} - -func (invalidParamErr) InvalidParameter() {} - -func newInvalidParameterError(err string) error { return invalidParamErr{liberr{errors.New(err)}} } - -type conflictErr struct { - liberr -} - -func (conflictErr) ConflictErr() {} - -func newConflictError(err string) error { return conflictErr{liberr{errors.New(err)}} } - -type sysErr struct { - liberr -} - -func wrapSystemError(err error) error { return sysErr{liberr{err}} } +func newConflictError(err string) error { return errdefs.Conflict(errors.New(err)) } diff --git a/plugin/backend_linux.go b/plugin/backend_linux.go index 1f2830a899..46bdfdbb1f 100644 --- a/plugin/backend_linux.go +++ b/plugin/backend_linux.go @@ -20,6 +20,7 @@ import ( progressutils "github.com/docker/docker/distribution/utils" "github.com/docker/docker/distribution/xfer" "github.com/docker/docker/dockerversion" + "github.com/docker/docker/errdefs" "github.com/docker/docker/image" "github.com/docker/docker/layer" "github.com/docker/docker/pkg/authorization" @@ -233,7 +234,7 @@ func (pm *Manager) Privileges(ctx context.Context, ref reference.Named, metaHead } var config types.PluginConfig if err := json.Unmarshal(cs.config, &config); err != nil { - return nil, systemError{err} + return nil, errdefs.System(err) } return computePrivileges(config), nil @@ -255,12 +256,12 @@ func (pm *Manager) Upgrade(ctx context.Context, ref reference.Named, name string // revalidate because Pull is public if _, err := reference.ParseNormalizedNamed(name); err != nil { - return errors.Wrapf(validationError{err}, "failed to parse %q", name) + return errors.Wrapf(errdefs.InvalidParameter(err), "failed to parse %q", name) } tmpRootFSDir, err := ioutil.TempDir(pm.tmpDir(), ".rootfs") if err != nil { - return errors.Wrap(systemError{err}, "error preparing upgrade") + return errors.Wrap(errdefs.System(err), "error preparing upgrade") } defer os.RemoveAll(tmpRootFSDir) @@ -302,17 +303,17 @@ func (pm *Manager) Pull(ctx context.Context, ref reference.Named, name string, m // revalidate because Pull is public nameref, err := reference.ParseNormalizedNamed(name) if err != nil { - return errors.Wrapf(validationError{err}, "failed to parse %q", name) + return errors.Wrapf(errdefs.InvalidParameter(err), "failed to parse %q", name) } name = reference.FamiliarString(reference.TagNameOnly(nameref)) if err := pm.config.Store.validateName(name); err != nil { - return validationError{err} + return errdefs.InvalidParameter(err) } tmpRootFSDir, err := ioutil.TempDir(pm.tmpDir(), ".rootfs") if err != nil { - return errors.Wrap(systemError{err}, "error preparing pull") + return errors.Wrap(errdefs.System(err), "error preparing pull") } defer os.RemoveAll(tmpRootFSDir) diff --git a/plugin/errors.go b/plugin/errors.go index 0a101d4dc5..a4f6fa8103 100644 --- a/plugin/errors.go +++ b/plugin/errors.go @@ -26,34 +26,6 @@ func (name errDisabled) Error() string { func (name errDisabled) Conflict() {} -type validationError struct { - cause error -} - -func (e validationError) Error() string { - return e.cause.Error() -} - -func (validationError) Conflict() {} - -func (e validationError) Cause() error { - return e.cause -} - -type systemError struct { - cause error -} - -func (e systemError) Error() string { - return e.cause.Error() -} - -func (systemError) SystemError() {} - -func (e systemError) Cause() error { - return e.cause -} - type invalidFilter struct { filter string value []string diff --git a/plugin/executor/containerd/containerd.go b/plugin/executor/containerd/containerd.go index 38dcfcd58c..7b35136a1f 100644 --- a/plugin/executor/containerd/containerd.go +++ b/plugin/executor/containerd/containerd.go @@ -8,7 +8,7 @@ import ( "github.com/containerd/containerd/cio" "github.com/containerd/containerd/linux/runctypes" - "github.com/docker/docker/api/errdefs" + "github.com/docker/docker/errdefs" "github.com/docker/docker/libcontainerd" "github.com/opencontainers/runtime-spec/specs-go" "github.com/pkg/errors" diff --git a/plugin/manager_linux.go b/plugin/manager_linux.go index 59066c1d79..65380af06f 100644 --- a/plugin/manager_linux.go +++ b/plugin/manager_linux.go @@ -9,6 +9,7 @@ import ( "github.com/docker/docker/api/types" "github.com/docker/docker/daemon/initlayer" + "github.com/docker/docker/errdefs" "github.com/docker/docker/pkg/containerfs" "github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/mount" @@ -217,12 +218,12 @@ func (pm *Manager) upgradePlugin(p *v2.Plugin, configDigest digest.Digest, blobs // This could happen if the plugin was disabled with `-f` with active mounts. // If there is anything in `orig` is still mounted, this should error out. if err := mount.RecursiveUnmount(orig); err != nil { - return systemError{err} + return errdefs.System(err) } backup := orig + "-old" if err := os.Rename(orig, backup); err != nil { - return errors.Wrap(systemError{err}, "error backing up plugin data before upgrade") + return errors.Wrap(errdefs.System(err), "error backing up plugin data before upgrade") } defer func() { @@ -248,7 +249,7 @@ func (pm *Manager) upgradePlugin(p *v2.Plugin, configDigest digest.Digest, blobs }() if err := os.Rename(tmpRootFSDir, orig); err != nil { - return errors.Wrap(systemError{err}, "error upgrading") + return errors.Wrap(errdefs.System(err), "error upgrading") } p.PluginObj.Config = config @@ -288,7 +289,7 @@ func (pm *Manager) setupNewPlugin(configDigest digest.Digest, blobsums []digest. // createPlugin creates a new plugin. take lock before calling. func (pm *Manager) createPlugin(name string, configDigest digest.Digest, blobsums []digest.Digest, rootFSDir string, privileges *types.PluginPrivileges, opts ...CreateOpt) (p *v2.Plugin, err error) { if err := pm.config.Store.validateName(name); err != nil { // todo: this check is wrong. remove store - return nil, validationError{err} + return nil, errdefs.InvalidParameter(err) } config, err := pm.setupNewPlugin(configDigest, blobsums, privileges) diff --git a/plugin/store.go b/plugin/store.go index b3398145d7..9768c25068 100644 --- a/plugin/store.go +++ b/plugin/store.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/docker/distribution/reference" + "github.com/docker/docker/errdefs" "github.com/docker/docker/pkg/plugingetter" "github.com/docker/docker/pkg/plugins" "github.com/docker/docker/plugin/v2" @@ -144,7 +145,7 @@ func (ps *Store) Get(name, capability string, mode int) (plugingetter.CompatPlug if errors.Cause(err) == plugins.ErrNotFound { return nil, errNotFound(name) } - return nil, errors.Wrap(systemError{err}, "legacy plugin") + return nil, errors.Wrap(errdefs.System(err), "legacy plugin") } // GetAllManagedPluginsByCap returns a list of managed plugins matching the given capability. @@ -172,7 +173,7 @@ func (ps *Store) GetAllByCap(capability string) ([]plugingetter.CompatPlugin, er if allowV1PluginsFallback { pl, err := plugins.GetAll(capability) if err != nil { - return nil, errors.Wrap(systemError{err}, "legacy plugin") + return nil, errors.Wrap(errdefs.System(err), "legacy plugin") } for _, p := range pl { result = append(result, p) diff --git a/registry/auth.go b/registry/auth.go index 11937d801a..56b9c88295 100644 --- a/registry/auth.go +++ b/registry/auth.go @@ -12,6 +12,7 @@ import ( "github.com/docker/distribution/registry/client/transport" "github.com/docker/docker/api/types" registrytypes "github.com/docker/docker/api/types/registry" + "github.com/docker/docker/errdefs" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -29,7 +30,7 @@ func loginV1(authConfig *types.AuthConfig, apiEndpoint APIEndpoint, userAgent st logrus.Debugf("attempting v1 login to registry endpoint %s", serverAddress) if serverAddress == "" { - return "", "", systemError{errors.New("server Error: Server Address not set")} + return "", "", errdefs.System(errors.New("server Error: Server Address not set")) } req, err := http.NewRequest("GET", serverAddress+"users/", nil) @@ -47,23 +48,23 @@ func loginV1(authConfig *types.AuthConfig, apiEndpoint APIEndpoint, userAgent st defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { - return "", "", systemError{err} + return "", "", errdefs.System(err) } switch resp.StatusCode { case http.StatusOK: return "Login Succeeded", "", nil case http.StatusUnauthorized: - return "", "", unauthorizedError{errors.New("Wrong login/password, please try again")} + return "", "", errdefs.Unauthorized(errors.New("Wrong login/password, please try again")) case http.StatusForbidden: // *TODO: Use registry configuration to determine what this says, if anything? - return "", "", notActivatedError{errors.Errorf("Login: Account is not active. Please see the documentation of the registry %s for instructions how to activate it.", serverAddress)} + return "", "", errdefs.Forbidden(errors.Errorf("Login: Account is not active. Please see the documentation of the registry %s for instructions how to activate it.", serverAddress)) case http.StatusInternalServerError: logrus.Errorf("%s returned status code %d. Response Body :\n%s", req.URL.String(), resp.StatusCode, body) - return "", "", systemError{errors.New("Internal Server Error")} + return "", "", errdefs.System(errors.New("Internal Server Error")) } - return "", "", systemError{errors.Errorf("Login: %s (Code: %d; Headers: %s)", body, - resp.StatusCode, resp.Header)} + return "", "", errdefs.System(errors.Errorf("Login: %s (Code: %d; Headers: %s)", body, + resp.StatusCode, resp.Header)) } type loginCredentialStore struct { diff --git a/registry/errors.go b/registry/errors.go index b388efca73..55f74d97ed 100644 --- a/registry/errors.go +++ b/registry/errors.go @@ -4,6 +4,7 @@ import ( "net/url" "github.com/docker/distribution/registry/api/errcode" + "github.com/docker/docker/errdefs" ) type notFoundError string @@ -14,62 +15,6 @@ func (e notFoundError) Error() string { func (notFoundError) NotFound() {} -type validationError struct { - cause error -} - -func (e validationError) Error() string { - return e.cause.Error() -} - -func (e validationError) InvalidParameter() {} - -func (e validationError) Cause() error { - return e.cause -} - -type unauthorizedError struct { - cause error -} - -func (e unauthorizedError) Error() string { - return e.cause.Error() -} - -func (e unauthorizedError) Unauthorized() {} - -func (e unauthorizedError) Cause() error { - return e.cause -} - -type systemError struct { - cause error -} - -func (e systemError) Error() string { - return e.cause.Error() -} - -func (e systemError) SystemError() {} - -func (e systemError) Cause() error { - return e.cause -} - -type notActivatedError struct { - cause error -} - -func (e notActivatedError) Error() string { - return e.cause.Error() -} - -func (e notActivatedError) Forbidden() {} - -func (e notActivatedError) Cause() error { - return e.cause -} - func translateV2AuthError(err error) error { switch e := err.(type) { case *url.Error: @@ -77,7 +22,7 @@ func translateV2AuthError(err error) error { case errcode.Error: switch e2.Code { case errcode.ErrorCodeUnauthorized: - return unauthorizedError{err} + return errdefs.Unauthorized(err) } } } diff --git a/registry/service.go b/registry/service.go index f3f1b4a567..bf4ab94d9f 100644 --- a/registry/service.go +++ b/registry/service.go @@ -13,6 +13,7 @@ import ( "github.com/docker/distribution/registry/client/auth" "github.com/docker/docker/api/types" registrytypes "github.com/docker/docker/api/types/registry" + "github.com/docker/docker/errdefs" "github.com/pkg/errors" "github.com/sirupsen/logrus" ) @@ -117,12 +118,12 @@ func (s *DefaultService) Auth(ctx context.Context, authConfig *types.AuthConfig, } u, err := url.Parse(serverAddress) if err != nil { - return "", "", validationError{errors.Errorf("unable to parse server address: %v", err)} + return "", "", errdefs.InvalidParameter(errors.Errorf("unable to parse server address: %v", err)) } endpoints, err := s.LookupPushEndpoints(u.Host) if err != nil { - return "", "", validationError{err} + return "", "", errdefs.InvalidParameter(err) } for _, endpoint := range endpoints { diff --git a/registry/session.go b/registry/session.go index e619d9f644..ae0ec1b4bf 100644 --- a/registry/session.go +++ b/registry/session.go @@ -21,6 +21,7 @@ import ( "github.com/docker/distribution/registry/api/errcode" "github.com/docker/docker/api/types" registrytypes "github.com/docker/docker/api/types/registry" + "github.com/docker/docker/errdefs" "github.com/docker/docker/pkg/ioutils" "github.com/docker/docker/pkg/jsonmessage" "github.com/docker/docker/pkg/stringid" @@ -734,20 +735,20 @@ func shouldRedirect(response *http.Response) bool { // SearchRepositories performs a search against the remote repository func (r *Session) SearchRepositories(term string, limit int) (*registrytypes.SearchResults, error) { if limit < 1 || limit > 100 { - return nil, validationError{errors.Errorf("Limit %d is outside the range of [1, 100]", limit)} + return nil, errdefs.InvalidParameter(errors.Errorf("Limit %d is outside the range of [1, 100]", limit)) } logrus.Debugf("Index server: %s", r.indexEndpoint) u := r.indexEndpoint.String() + "search?q=" + url.QueryEscape(term) + "&n=" + url.QueryEscape(fmt.Sprintf("%d", limit)) req, err := http.NewRequest("GET", u, nil) if err != nil { - return nil, errors.Wrap(validationError{err}, "Error building request") + return nil, errors.Wrap(errdefs.InvalidParameter(err), "Error building request") } // Have the AuthTransport send authentication, when logged in. req.Header.Set("X-Docker-Token", "true") res, err := r.client.Do(req) if err != nil { - return nil, systemError{err} + return nil, errdefs.System(err) } defer res.Body.Close() if res.StatusCode != 200 { diff --git a/volume/local/local.go b/volume/local/local.go index c11a18c3dc..206d96506c 100644 --- a/volume/local/local.go +++ b/volume/local/local.go @@ -14,6 +14,7 @@ import ( "sync" "github.com/docker/docker/daemon/names" + "github.com/docker/docker/errdefs" "github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/mount" "github.com/docker/docker/volume" @@ -139,20 +140,6 @@ func (r *Root) Name() string { return volume.DefaultDriverName } -type systemError struct { - err error -} - -func (e systemError) Error() string { - return e.err.Error() -} - -func (e systemError) SystemError() {} - -func (e systemError) Cause() error { - return e.err -} - // Create creates a new volume.Volume with the provided name, creating // the underlying directory tree required for this volume in the // process. @@ -171,7 +158,7 @@ func (r *Root) Create(name string, opts map[string]string) (volume.Volume, error path := r.DataPath(name) if err := idtools.MkdirAllAndChown(path, 0755, r.rootIDs); err != nil { - return nil, errors.Wrapf(systemError{err}, "error while creating volume path '%s'", path) + return nil, errors.Wrapf(errdefs.System(err), "error while creating volume path '%s'", path) } var err error @@ -197,7 +184,7 @@ func (r *Root) Create(name string, opts map[string]string) (volume.Volume, error return nil, err } if err = ioutil.WriteFile(filepath.Join(filepath.Dir(path), "opts.json"), b, 600); err != nil { - return nil, errors.Wrap(systemError{err}, "error while persisting volume options") + return nil, errdefs.System(errors.Wrap(err, "error while persisting volume options")) } } @@ -215,11 +202,11 @@ func (r *Root) Remove(v volume.Volume) error { lv, ok := v.(*localVolume) if !ok { - return systemError{errors.Errorf("unknown volume type %T", v)} + return errdefs.System(errors.Errorf("unknown volume type %T", v)) } if lv.active.count > 0 { - return systemError{errors.Errorf("volume has active mounts")} + return errdefs.System(errors.Errorf("volume has active mounts")) } if err := lv.unmount(); err != nil { @@ -235,7 +222,7 @@ func (r *Root) Remove(v volume.Volume) error { } if !r.scopedPath(realPath) { - return systemError{errors.Errorf("Unable to remove a directory of out the Docker root %s: %s", r.scope, realPath)} + return errdefs.System(errors.Errorf("Unable to remove a directory of out the Docker root %s: %s", r.scope, realPath)) } if err := removePath(realPath); err != nil { @@ -251,7 +238,7 @@ func removePath(path string) error { if os.IsNotExist(err) { return nil } - return errors.Wrapf(systemError{err}, "error removing volume path '%s'", path) + return errdefs.System(errors.Wrapf(err, "error removing volume path '%s'", path)) } return nil } @@ -334,7 +321,7 @@ func (v *localVolume) Mount(id string) (string, error) { if v.opts != nil { if !v.active.mounted { if err := v.mount(); err != nil { - return "", systemError{err} + return "", errdefs.System(err) } v.active.mounted = true } @@ -368,7 +355,7 @@ func (v *localVolume) unmount() error { if v.opts != nil { if err := mount.Unmount(v.path); err != nil { if mounted, mErr := mount.Mounted(v.path); mounted || mErr != nil { - return errors.Wrapf(systemError{err}, "error while unmounting volume path '%s'", v.path) + return errdefs.System(errors.Wrapf(err, "error while unmounting volume path '%s'", v.path)) } } v.active.mounted = false