Merge pull request #20699 from calavera/remove_static_error_declarations

Remove static errors from errors package.
This commit is contained in:
David Calavera 2016-02-26 16:30:12 -08:00
commit df2b74188e
67 changed files with 452 additions and 1626 deletions

View File

@ -11,7 +11,6 @@ import (
"github.com/Sirupsen/logrus"
Cli "github.com/docker/docker/cli"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/opts"
"github.com/docker/docker/pkg/promise"
"github.com/docker/docker/pkg/signal"
@ -21,6 +20,11 @@ import (
"github.com/docker/libnetwork/resolvconf/dns"
)
const (
errCmdNotFound = "Container command not found or does not exist."
errCmdCouldNotBeInvoked = "Container command could not be invoked."
)
func (cid *cidFile) Close() error {
cid.file.Close()
@ -46,20 +50,13 @@ func (cid *cidFile) Write(id string) error {
// return 125 for generic docker daemon failures
func runStartContainerErr(err error) error {
trimmedErr := strings.Trim(err.Error(), "Error response from daemon: ")
statusError := Cli.StatusError{}
derrCmdNotFound := derr.ErrorCodeCmdNotFound.Message()
derrCouldNotInvoke := derr.ErrorCodeCmdCouldNotBeInvoked.Message()
derrNoSuchImage := derr.ErrorCodeNoSuchImageHash.Message()
derrNoSuchImageTag := derr.ErrorCodeNoSuchImageTag.Message()
statusError := Cli.StatusError{StatusCode: 125}
switch trimmedErr {
case derrCmdNotFound:
case errCmdNotFound:
statusError = Cli.StatusError{StatusCode: 127}
case derrCouldNotInvoke:
case errCmdCouldNotBeInvoked:
statusError = Cli.StatusError{StatusCode: 126}
case derrNoSuchImage, derrNoSuchImageTag:
statusError = Cli.StatusError{StatusCode: 125}
default:
statusError = Cli.StatusError{StatusCode: 125}
}
return statusError
}

View File

@ -0,0 +1,69 @@
package httputils
import (
"net/http"
"strings"
"github.com/Sirupsen/logrus"
)
// httpStatusError is an interface
// that errors with custom status codes
// implement to tell the api layer
// which response status to set.
type httpStatusError interface {
HTTPErrorStatusCode() int
}
// inputValidationError is an interface
// that errors generated by invalid
// inputs can implement to tell the
// api layer to set a 400 status code
// in the response.
type inputValidationError interface {
IsValidationError() bool
}
// WriteError decodes a specific docker error and sends it in the response.
func WriteError(w http.ResponseWriter, err error) {
if err == nil || w == nil {
logrus.WithFields(logrus.Fields{"error": err, "writer": w}).Error("unexpected HTTP error handling")
return
}
var statusCode int
errMsg := err.Error()
switch e := err.(type) {
case httpStatusError:
statusCode = e.HTTPErrorStatusCode()
case inputValidationError:
statusCode = http.StatusBadRequest
default:
// FIXME: this is brittle and should not be necessary, but we still need to identify if
// there are errors falling back into this logic.
// If we need to differentiate between different possible error types,
// we should create appropriate error types that implement the httpStatusError interface.
errStr := strings.ToLower(errMsg)
for keyword, status := range map[string]int{
"not found": http.StatusNotFound,
"no such": http.StatusNotFound,
"bad parameter": http.StatusBadRequest,
"conflict": http.StatusConflict,
"impossible": http.StatusNotAcceptable,
"wrong login/password": http.StatusUnauthorized,
"hasn't been activated": http.StatusForbidden,
} {
if strings.Contains(errStr, keyword) {
statusCode = status
break
}
}
}
if statusCode == 0 {
statusCode = http.StatusInternalServerError
}
http.Error(w, errMsg, statusCode)
}

View File

@ -9,8 +9,6 @@ import (
"golang.org/x/net/context"
"github.com/Sirupsen/logrus"
"github.com/docker/distribution/registry/api/errcode"
"github.com/docker/docker/api"
"github.com/docker/docker/pkg/version"
)
@ -85,78 +83,6 @@ func ParseMultipartForm(r *http.Request) error {
return nil
}
// WriteError decodes a specific docker error and sends it in the response.
func WriteError(w http.ResponseWriter, err error) {
if err == nil || w == nil {
logrus.WithFields(logrus.Fields{"error": err, "writer": w}).Error("unexpected HTTP error handling")
return
}
statusCode := http.StatusInternalServerError
errMsg := err.Error()
// Based on the type of error we get we need to process things
// slightly differently to extract the error message.
// In the 'errcode.*' cases there are two different type of
// error that could be returned. errocode.ErrorCode is the base
// type of error object - it is just an 'int' that can then be
// used as the look-up key to find the message. errorcode.Error
// extends errorcode.Error by adding error-instance specific
// data, like 'details' or variable strings to be inserted into
// the message.
//
// Ideally, we should just be able to call err.Error() for all
// cases but the errcode package doesn't support that yet.
//
// Additionally, in both errcode cases, there might be an http
// status code associated with it, and if so use it.
switch err.(type) {
case errcode.ErrorCode:
daError, _ := err.(errcode.ErrorCode)
statusCode = daError.Descriptor().HTTPStatusCode
errMsg = daError.Message()
case errcode.Error:
// For reference, if you're looking for a particular error
// then you can do something like :
// import ( derr "github.com/docker/docker/errors" )
// if daError.ErrorCode() == derr.ErrorCodeNoSuchContainer { ... }
daError, _ := err.(errcode.Error)
statusCode = daError.ErrorCode().Descriptor().HTTPStatusCode
errMsg = daError.Message
default:
// This part of will be removed once we've
// converted everything over to use the errcode package
// FIXME: this is brittle and should not be necessary.
// If we need to differentiate between different possible error types,
// we should create appropriate error types with clearly defined meaning
errStr := strings.ToLower(err.Error())
for keyword, status := range map[string]int{
"not found": http.StatusNotFound,
"no such": http.StatusNotFound,
"bad parameter": http.StatusBadRequest,
"conflict": http.StatusConflict,
"impossible": http.StatusNotAcceptable,
"wrong login/password": http.StatusUnauthorized,
"hasn't been activated": http.StatusForbidden,
} {
if strings.Contains(errStr, keyword) {
statusCode = status
break
}
}
}
if statusCode == 0 {
statusCode = http.StatusInternalServerError
}
http.Error(w, errMsg, statusCode)
}
// WriteJSON writes the value v to the http response stream as json with standard json encoding.
func WriteJSON(w http.ResponseWriter, code int, v interface{}) error {
w.Header().Set("Content-Type", "application/json")

View File

@ -6,11 +6,18 @@ import (
"runtime"
"github.com/docker/docker/api/server/httputils"
"github.com/docker/docker/errors"
"github.com/docker/docker/pkg/version"
"golang.org/x/net/context"
)
type badRequestError struct {
error
}
func (badRequestError) HTTPErrorStatusCode() int {
return http.StatusBadRequest
}
// NewVersionMiddleware creates a new Version middleware.
func NewVersionMiddleware(versionCheck string, defaultVersion, minVersion version.Version) Middleware {
serverVersion := version.Version(versionCheck)
@ -23,10 +30,10 @@ func NewVersionMiddleware(versionCheck string, defaultVersion, minVersion versio
}
if apiVersion.GreaterThan(defaultVersion) {
return errors.ErrorCodeNewerClientVersion.WithArgs(apiVersion, defaultVersion)
return badRequestError{fmt.Errorf("client is newer than server (client API version: %s, server API version: %s)", apiVersion, defaultVersion)}
}
if apiVersion.LessThan(minVersion) {
return errors.ErrorCodeOldClientVersion.WithArgs(apiVersion, minVersion)
return badRequestError{fmt.Errorf("client version %s is too old. Minimum supported API version is %s, please upgrade your client to a newer version", apiVersion, minVersion)}
}
header := fmt.Sprintf("Docker/%s (%s)", serverVersion, runtime.GOOS)

View File

@ -53,12 +53,12 @@ func TestVersionMiddlewareWithErrors(t *testing.T) {
err := h(ctx, resp, req, vars)
if !strings.Contains(err.Error(), "client version 0.1 is too old. Minimum supported API version is 1.2.0") {
t.Fatalf("Expected ErrorCodeOldClientVersion, got %v", err)
t.Fatalf("Expected too old client error, got %v", err)
}
vars["version"] = "100000"
err = h(ctx, resp, req, vars)
if !strings.Contains(err.Error(), "client is newer than server") {
t.Fatalf("Expected ErrorCodeNewerClientVersion, got %v", err)
t.Fatalf("Expected client newer than server error, got %v", err)
}
}

View File

@ -4,7 +4,6 @@ import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
@ -17,7 +16,6 @@ import (
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/progress"
"github.com/docker/docker/pkg/streamformatter"
"github.com/docker/docker/utils"
"github.com/docker/engine-api/types"
"github.com/docker/engine-api/types/container"
"github.com/docker/go-units"
@ -117,7 +115,7 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r *
if !output.Flushed() {
return err
}
_, err = w.Write(sf.FormatError(errors.New(utils.GetErrorMessage(err))))
_, err = w.Write(sf.FormatError(err))
if err != nil {
logrus.Warnf("could not write error response: %v", err)
}

View File

@ -11,15 +11,12 @@ import (
"time"
"github.com/Sirupsen/logrus"
"github.com/docker/distribution/registry/api/errcode"
"github.com/docker/docker/api/server/httputils"
"github.com/docker/docker/api/types/backend"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/signal"
"github.com/docker/docker/pkg/term"
"github.com/docker/docker/runconfig"
"github.com/docker/docker/utils"
"github.com/docker/engine-api/types"
"github.com/docker/engine-api/types/container"
"github.com/docker/engine-api/types/filters"
@ -126,7 +123,7 @@ func (s *containerRouter) getContainersLogs(ctx context.Context, w http.Response
// The client may be expecting all of the data we're sending to
// be multiplexed, so send it through OutStream, which will
// have been set up to handle that if needed.
fmt.Fprintf(logsConfig.OutStream, "Error running logs job: %s\n", utils.GetErrorMessage(err))
fmt.Fprintf(logsConfig.OutStream, "Error running logs job: %v\n", err)
default:
return err
}
@ -182,6 +179,10 @@ func (s *containerRouter) postContainersStop(ctx context.Context, w http.Respons
return nil
}
type errContainerIsRunning interface {
ContainerIsRunning() bool
}
func (s *containerRouter) postContainersKill(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
if err := httputils.ParseForm(r); err != nil {
return err
@ -199,15 +200,17 @@ func (s *containerRouter) postContainersKill(ctx context.Context, w http.Respons
}
if err := s.backend.ContainerKill(name, uint64(sig)); err != nil {
theErr, isDerr := err.(errcode.ErrorCoder)
isStopped := isDerr && theErr.ErrorCode() == derr.ErrorCodeNotRunning
var isStopped bool
if e, ok := err.(errContainerIsRunning); ok {
isStopped = !e.ContainerIsRunning()
}
// Return error that's not caused because the container is stopped.
// Return error if the container is not running and the api is >= 1.20
// to keep backwards compatibility.
version := httputils.VersionFromContext(ctx)
if version.GreaterThanOrEqualTo("1.20") || !isStopped {
return fmt.Errorf("Cannot kill container %s: %v", name, utils.GetErrorMessage(err))
return fmt.Errorf("Cannot kill container %s: %v", name, err)
}
}
@ -430,7 +433,7 @@ func (s *containerRouter) postContainersAttach(ctx context.Context, w http.Respo
hijacker, ok := w.(http.Hijacker)
if !ok {
return derr.ErrorCodeNoHijackConnection.WithArgs(containerName)
return fmt.Errorf("error attaching to container %s, hijack connection missing", containerName)
}
setupStreams := func() (io.ReadCloser, io.Writer, io.Writer, error) {

View File

@ -10,7 +10,6 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api/server/httputils"
"github.com/docker/docker/pkg/stdcopy"
"github.com/docker/docker/utils"
"github.com/docker/engine-api/types"
"golang.org/x/net/context"
)
@ -46,7 +45,7 @@ func (s *containerRouter) postContainerExecCreate(ctx context.Context, w http.Re
// Register an instance of Exec in container.
id, err := s.backend.ContainerExecCreate(execConfig)
if err != nil {
logrus.Errorf("Error setting up exec command in container %s: %s", name, utils.GetErrorMessage(err))
logrus.Errorf("Error setting up exec command in container %s: %v", name, err)
return err
}
@ -113,7 +112,7 @@ func (s *containerRouter) postContainerExecStart(ctx context.Context, w http.Res
if execStartCheck.Detach {
return err
}
logrus.Errorf("Error running exec in container: %v\n", utils.GetErrorMessage(err))
logrus.Errorf("Error running exec in container: %v\n", err)
}
return nil
}

View File

@ -20,7 +20,6 @@ type Backend interface {
type containerBackend interface {
Commit(name string, config *types.ContainerCommitConfig) (imageID string, err error)
Exists(containerName string) bool
}
type imageBackend interface {

View File

@ -14,7 +14,6 @@ import (
"github.com/docker/distribution/registry/api/errcode"
"github.com/docker/docker/api/server/httputils"
"github.com/docker/docker/builder/dockerfile"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/streamformatter"
"github.com/docker/docker/reference"
@ -49,10 +48,6 @@ func (s *imageRouter) postCommit(ctx context.Context, w http.ResponseWriter, r *
c = &container.Config{}
}
if !s.backend.Exists(cname) {
return derr.ErrorCodeNoSuchContainer.WithArgs(cname)
}
newConfig, err := dockerfile.BuildFromConfig(c, r.Form["changes"])
if err != nil {
return err

View File

@ -8,8 +8,6 @@ import (
// Backend is all the methods that need to be implemented
// to provide network specific functionality.
type Backend interface {
NetworkControllerEnabled() bool
FindNetwork(idName string) (libnetwork.Network, error)
GetNetworkByName(idName string) (libnetwork.Network, error)
GetNetworksByID(partialID string) []libnetwork.Network

View File

@ -1,13 +1,6 @@
package network
import (
"net/http"
"github.com/docker/docker/api/server/httputils"
"github.com/docker/docker/api/server/router"
"github.com/docker/docker/errors"
"golang.org/x/net/context"
)
import "github.com/docker/docker/api/server/router"
// networkRouter is a router to talk with the network controller
type networkRouter struct {
@ -32,24 +25,13 @@ func (r *networkRouter) Routes() []router.Route {
func (r *networkRouter) initRoutes() {
r.routes = []router.Route{
// GET
router.NewGetRoute("/networks", r.controllerEnabledMiddleware(r.getNetworksList)),
router.NewGetRoute("/networks/{id:.*}", r.controllerEnabledMiddleware(r.getNetwork)),
router.NewGetRoute("/networks", r.getNetworksList),
router.NewGetRoute("/networks/{id:.*}", r.getNetwork),
// POST
router.NewPostRoute("/networks/create", r.controllerEnabledMiddleware(r.postNetworkCreate)),
router.NewPostRoute("/networks/{id:.*}/connect", r.controllerEnabledMiddleware(r.postNetworkConnect)),
router.NewPostRoute("/networks/{id:.*}/disconnect", r.controllerEnabledMiddleware(r.postNetworkDisconnect)),
router.NewPostRoute("/networks/create", r.postNetworkCreate),
router.NewPostRoute("/networks/{id:.*}/connect", r.postNetworkConnect),
router.NewPostRoute("/networks/{id:.*}/disconnect", r.postNetworkDisconnect),
// DELETE
router.NewDeleteRoute("/networks/{id:.*}", r.controllerEnabledMiddleware(r.deleteNetwork)),
router.NewDeleteRoute("/networks/{id:.*}", r.deleteNetwork),
}
}
func (r *networkRouter) controllerEnabledMiddleware(handler httputils.APIFunc) httputils.APIFunc {
if r.backend.NetworkControllerEnabled() {
return handler
}
return networkControllerDisabled
}
func networkControllerDisabled(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
return errors.ErrorNetworkControllerNotEnabled.WithArgs()
}

View File

@ -10,7 +10,6 @@ import (
"github.com/docker/docker/api/server/httputils"
"github.com/docker/docker/api/server/router"
"github.com/docker/docker/pkg/authorization"
"github.com/docker/docker/utils"
"github.com/gorilla/mux"
"golang.org/x/net/context"
)
@ -134,7 +133,7 @@ func (s *Server) makeHTTPHandler(handler httputils.APIFunc) http.HandlerFunc {
}
if err := handlerFunc(ctx, w, r, vars); err != nil {
logrus.Errorf("Handler for %s %s returned error: %s", r.Method, r.URL.Path, utils.GetErrorMessage(err))
logrus.Errorf("Handler for %s %s returned error: %v", r.Method, r.URL.Path, err)
httputils.WriteError(w, err)
}
}

View File

@ -19,7 +19,6 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api"
"github.com/docker/docker/builder"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/pkg/signal"
"github.com/docker/docker/pkg/system"
runconfigopts "github.com/docker/docker/runconfig/opts"
@ -40,12 +39,12 @@ func nullDispatch(b *Builder, args []string, attributes map[string]bool, origina
//
func env(b *Builder, args []string, attributes map[string]bool, original string) error {
if len(args) == 0 {
return derr.ErrorCodeAtLeastOneArg.WithArgs("ENV")
return errAtLeastOneArgument("ENV")
}
if len(args)%2 != 0 {
// should never get here, but just in case
return derr.ErrorCodeTooManyArgs.WithArgs("ENV")
return errTooManyArguments("ENV")
}
if err := b.flags.Parse(); err != nil {
@ -99,7 +98,7 @@ func env(b *Builder, args []string, attributes map[string]bool, original string)
// Sets the maintainer metadata.
func maintainer(b *Builder, args []string, attributes map[string]bool, original string) error {
if len(args) != 1 {
return derr.ErrorCodeExactlyOneArg.WithArgs("MAINTAINER")
return errExactlyOneArgument("MAINTAINER")
}
if err := b.flags.Parse(); err != nil {
@ -116,11 +115,11 @@ func maintainer(b *Builder, args []string, attributes map[string]bool, original
//
func label(b *Builder, args []string, attributes map[string]bool, original string) error {
if len(args) == 0 {
return derr.ErrorCodeAtLeastOneArg.WithArgs("LABEL")
return errAtLeastOneArgument("LABEL")
}
if len(args)%2 != 0 {
// should never get here, but just in case
return derr.ErrorCodeTooManyArgs.WithArgs("LABEL")
return errTooManyArguments("LABEL")
}
if err := b.flags.Parse(); err != nil {
@ -152,7 +151,7 @@ func label(b *Builder, args []string, attributes map[string]bool, original strin
//
func add(b *Builder, args []string, attributes map[string]bool, original string) error {
if len(args) < 2 {
return derr.ErrorCodeAtLeastTwoArgs.WithArgs("ADD")
return errAtLeastOneArgument("ADD")
}
if err := b.flags.Parse(); err != nil {
@ -168,7 +167,7 @@ func add(b *Builder, args []string, attributes map[string]bool, original string)
//
func dispatchCopy(b *Builder, args []string, attributes map[string]bool, original string) error {
if len(args) < 2 {
return derr.ErrorCodeAtLeastTwoArgs.WithArgs("COPY")
return errAtLeastOneArgument("COPY")
}
if err := b.flags.Parse(); err != nil {
@ -184,7 +183,7 @@ func dispatchCopy(b *Builder, args []string, attributes map[string]bool, origina
//
func from(b *Builder, args []string, attributes map[string]bool, original string) error {
if len(args) != 1 {
return derr.ErrorCodeExactlyOneArg.WithArgs("FROM")
return errExactlyOneArgument("FROM")
}
if err := b.flags.Parse(); err != nil {
@ -233,7 +232,7 @@ func from(b *Builder, args []string, attributes map[string]bool, original string
//
func onbuild(b *Builder, args []string, attributes map[string]bool, original string) error {
if len(args) == 0 {
return derr.ErrorCodeAtLeastOneArg.WithArgs("ONBUILD")
return errAtLeastOneArgument("ONBUILD")
}
if err := b.flags.Parse(); err != nil {
@ -243,9 +242,9 @@ func onbuild(b *Builder, args []string, attributes map[string]bool, original str
triggerInstruction := strings.ToUpper(strings.TrimSpace(args[0]))
switch triggerInstruction {
case "ONBUILD":
return derr.ErrorCodeChainOnBuild
return fmt.Errorf("Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed")
case "MAINTAINER", "FROM":
return derr.ErrorCodeBadOnBuildCmd.WithArgs(triggerInstruction)
return fmt.Errorf("%s isn't allowed as an ONBUILD trigger", triggerInstruction)
}
original = regexp.MustCompile(`(?i)^\s*ONBUILD\s*`).ReplaceAllString(original, "")
@ -260,7 +259,7 @@ func onbuild(b *Builder, args []string, attributes map[string]bool, original str
//
func workdir(b *Builder, args []string, attributes map[string]bool, original string) error {
if len(args) != 1 {
return derr.ErrorCodeExactlyOneArg.WithArgs("WORKDIR")
return errExactlyOneArgument("WORKDIR")
}
if err := b.flags.Parse(); err != nil {
@ -293,7 +292,7 @@ func workdir(b *Builder, args []string, attributes map[string]bool, original str
//
func run(b *Builder, args []string, attributes map[string]bool, original string) error {
if b.image == "" && !b.noBaseImage {
return derr.ErrorCodeMissingFrom
return fmt.Errorf("Please provide a source image with `from` prior to run")
}
if err := b.flags.Parse(); err != nil {
@ -491,7 +490,7 @@ func expose(b *Builder, args []string, attributes map[string]bool, original stri
portsTab := args
if len(args) == 0 {
return derr.ErrorCodeAtLeastOneArg.WithArgs("EXPOSE")
return errAtLeastOneArgument("EXPOSE")
}
if err := b.flags.Parse(); err != nil {
@ -530,7 +529,7 @@ func expose(b *Builder, args []string, attributes map[string]bool, original stri
//
func user(b *Builder, args []string, attributes map[string]bool, original string) error {
if len(args) != 1 {
return derr.ErrorCodeExactlyOneArg.WithArgs("USER")
return errExactlyOneArgument("USER")
}
if err := b.flags.Parse(); err != nil {
@ -547,7 +546,7 @@ func user(b *Builder, args []string, attributes map[string]bool, original string
//
func volume(b *Builder, args []string, attributes map[string]bool, original string) error {
if len(args) == 0 {
return derr.ErrorCodeAtLeastOneArg.WithArgs("VOLUME")
return errAtLeastOneArgument("VOLUME")
}
if err := b.flags.Parse(); err != nil {
@ -560,7 +559,7 @@ func volume(b *Builder, args []string, attributes map[string]bool, original stri
for _, v := range args {
v = strings.TrimSpace(v)
if v == "" {
return derr.ErrorCodeVolumeEmpty
return fmt.Errorf("Volume specified can not be an empty string")
}
b.runConfig.Volumes[v] = struct{}{}
}
@ -631,3 +630,15 @@ func arg(b *Builder, args []string, attributes map[string]bool, original string)
return b.commit("", b.runConfig.Cmd, fmt.Sprintf("ARG %s", arg))
}
func errAtLeastOneArgument(command string) error {
return fmt.Errorf("%s requires at least one argument", command)
}
func errExactlyOneArgument(command string) error {
return fmt.Errorf("%s requires exactly one argument", command)
}
func errTooManyArguments(command string) error {
return fmt.Errorf("Bad input to %s, too many arguments", command)
}

View File

@ -16,7 +16,6 @@ import (
"github.com/docker/docker/daemon/logger"
"github.com/docker/docker/daemon/logger/jsonfilelog"
"github.com/docker/docker/daemon/network"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/image"
"github.com/docker/docker/layer"
"github.com/docker/docker/pkg/promise"
@ -199,7 +198,7 @@ func (container *Container) SetupWorkingDirectory() error {
if err := system.MkdirAll(pth, 0755); err != nil {
pthInfo, err2 := os.Stat(pth)
if err2 == nil && pthInfo != nil && !pthInfo.IsDir() {
return derr.ErrorCodeNotADir.WithArgs(container.Config.WorkingDir)
return fmt.Errorf("Cannot mkdir: %s is not a directory", container.Config.WorkingDir)
}
return err
@ -277,13 +276,6 @@ func (container *Container) ConfigPath() (string, error) {
return container.GetRootResourcePath(configFileName)
}
func validateID(id string) error {
if id == "" {
return derr.ErrorCodeEmptyID
}
return nil
}
// Returns true if the container exposes a certain port
func (container *Container) exposes(p nat.Port) bool {
_, exists := container.Config.ExposedPorts[p]
@ -307,7 +299,7 @@ func (container *Container) GetLogConfig(defaultConfig containertypes.LogConfig)
func (container *Container) StartLogger(cfg containertypes.LogConfig) (logger.Logger, error) {
c, err := logger.GetLogDriver(cfg.Type)
if err != nil {
return nil, derr.ErrorCodeLoggingFactory.WithArgs(err)
return nil, fmt.Errorf("Failed to get logging factory: %v", err)
}
ctx := logger.Context{
Config: cfg.Config,

View File

@ -14,7 +14,6 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/docker/daemon/execdriver"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/pkg/chrootarchive"
"github.com/docker/docker/pkg/symlink"
"github.com/docker/docker/pkg/system"
@ -34,6 +33,11 @@ import (
// DefaultSHMSize is the default size (64MB) of the SHM which will be mounted in the container
const DefaultSHMSize int64 = 67108864
var (
errInvalidEndpoint = fmt.Errorf("invalid endpoint while building port map info")
errInvalidNetwork = fmt.Errorf("invalid network settings while building port map info")
)
// Container holds the fields specific to unixen implementations.
// See CommonContainer for standard fields common to all containers.
type Container struct {
@ -116,12 +120,12 @@ func (container *Container) GetEndpointInNetwork(n libnetwork.Network) (libnetwo
func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint) error {
if ep == nil {
return derr.ErrorCodeEmptyEndpoint
return errInvalidEndpoint
}
networkSettings := container.NetworkSettings
if networkSettings == nil {
return derr.ErrorCodeEmptyNetwork
return errInvalidNetwork
}
if len(networkSettings.Ports) == 0 {
@ -151,7 +155,7 @@ func getEndpointPortMapInfo(ep libnetwork.Endpoint) (nat.PortMap, error) {
for _, tp := range exposedPorts {
natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port)))
if err != nil {
return pm, derr.ErrorCodeParsingPort.WithArgs(tp.Port, err)
return pm, fmt.Errorf("Error parsing Port value(%v):%v", tp.Port, err)
}
pm[natPort] = nil
}
@ -195,12 +199,12 @@ func getSandboxPortMapInfo(sb libnetwork.Sandbox) nat.PortMap {
// BuildEndpointInfo sets endpoint-related fields on container.NetworkSettings based on the provided network and endpoint.
func (container *Container) BuildEndpointInfo(n libnetwork.Network, ep libnetwork.Endpoint) error {
if ep == nil {
return derr.ErrorCodeEmptyEndpoint
return errInvalidEndpoint
}
networkSettings := container.NetworkSettings
if networkSettings == nil {
return derr.ErrorCodeEmptyNetwork
return errInvalidNetwork
}
epInfo := ep.Info()
@ -377,7 +381,7 @@ func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epC
portStart, portEnd, err = newP.Range()
}
if err != nil {
return nil, derr.ErrorCodeHostPort.WithArgs(binding[i].HostPort, err)
return nil, fmt.Errorf("Error parsing HostPort value(%s):%v", binding[i].HostPort, err)
}
pbCopy.HostPort = uint16(portStart)
pbCopy.HostPortEnd = uint16(portEnd)

View File

@ -1,6 +1,7 @@
package container
import (
"fmt"
"io"
"os/exec"
"strings"
@ -10,10 +11,8 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/docker/daemon/execdriver"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/pkg/promise"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/utils"
"github.com/docker/engine-api/types/container"
)
@ -190,7 +189,7 @@ func (m *containerMonitor) start() error {
if m.container.RestartCount == 0 {
m.container.ExitCode = 127
m.resetContainer(false)
return derr.ErrorCodeCmdNotFound
return fmt.Errorf("Container command not found or does not exist.")
}
}
// set to 126 for container cmd can't be invoked errors
@ -198,7 +197,7 @@ func (m *containerMonitor) start() error {
if m.container.RestartCount == 0 {
m.container.ExitCode = 126
m.resetContainer(false)
return derr.ErrorCodeCmdCouldNotBeInvoked
return fmt.Errorf("Container command could not be invoked.")
}
}
@ -206,7 +205,7 @@ func (m *containerMonitor) start() error {
m.container.ExitCode = -1
m.resetContainer(false)
return derr.ErrorCodeCantStart.WithArgs(m.container.ID, utils.GetErrorMessage(err))
return fmt.Errorf("Cannot start container %s: %v", m.container.ID, err)
}
logrus.Errorf("Error running container: %s", err)

View File

@ -6,7 +6,6 @@ import (
"time"
"github.com/docker/docker/daemon/execdriver"
derr "github.com/docker/docker/errors"
"github.com/docker/go-units"
)
@ -113,7 +112,7 @@ func wait(waitChan <-chan struct{}, timeout time.Duration) error {
}
select {
case <-time.After(timeout):
return derr.ErrorCodeTimedOut.WithArgs(timeout)
return fmt.Errorf("Timed out: %v", timeout)
case <-waitChan:
return nil
}
@ -256,14 +255,15 @@ func (s *State) IsRestarting() bool {
}
// SetRemovalInProgress sets the container state as being removed.
func (s *State) SetRemovalInProgress() error {
// It returns true if the container was already in that state.
func (s *State) SetRemovalInProgress() bool {
s.Lock()
defer s.Unlock()
if s.RemovalInProgress {
return derr.ErrorCodeAlreadyRemoving
return true
}
s.RemovalInProgress = true
return nil
return false
}
// ResetRemovalInProgress make the RemovalInProgress state to false.

View File

@ -9,7 +9,7 @@ import (
"github.com/docker/docker/api/types/backend"
"github.com/docker/docker/container"
"github.com/docker/docker/daemon/logger"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/errors"
"github.com/docker/docker/pkg/stdcopy"
)
@ -17,10 +17,11 @@ import (
func (daemon *Daemon) ContainerAttach(prefixOrName string, c *backend.ContainerAttachConfig) error {
container, err := daemon.GetContainer(prefixOrName)
if err != nil {
return derr.ErrorCodeNoSuchContainer.WithArgs(prefixOrName)
return err
}
if container.IsPaused() {
return derr.ErrorCodePausedContainer.WithArgs(prefixOrName)
err := fmt.Errorf("Container %s is paused. Unpause the container before attach", prefixOrName)
return errors.NewRequestConflictError(err)
}
inStream, outStream, errStream, err := c.GetStreams()

View File

@ -17,7 +17,7 @@ import (
"github.com/docker/docker/daemon/execdriver"
"github.com/docker/docker/daemon/links"
"github.com/docker/docker/daemon/network"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/errors"
"github.com/docker/docker/pkg/fileutils"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/mount"
@ -45,7 +45,7 @@ func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]s
for linkAlias, child := range children {
if !child.IsRunning() {
return nil, derr.ErrorCodeLinkNotRunning.WithArgs(child.Name, linkAlias)
return nil, fmt.Errorf("Cannot link to a non running container: %s AS %s", child.Name, linkAlias)
}
childBridgeSettings := child.NetworkSettings.Networks["bridge"]
@ -509,7 +509,7 @@ func (daemon *Daemon) updateNetwork(container *container.Container) error {
sb, err := ctrl.SandboxByID(sid)
if err != nil {
return derr.ErrorCodeNoSandbox.WithArgs(sid, err)
return fmt.Errorf("error locating sandbox id %s: %v", sid, err)
}
// Find if container is connected to the default bridge network
@ -532,11 +532,11 @@ func (daemon *Daemon) updateNetwork(container *container.Container) error {
options, err := daemon.buildSandboxOptions(container, n)
if err != nil {
return derr.ErrorCodeNetworkUpdate.WithArgs(err)
return fmt.Errorf("Update network failed: %v", err)
}
if err := sb.Refresh(options...); err != nil {
return derr.ErrorCodeNetworkRefresh.WithArgs(sid, err)
return fmt.Errorf("Update network failed: Failure in refresh sandbox %s: %v", sid, err)
}
return nil
@ -730,7 +730,7 @@ func (daemon *Daemon) updateNetworkConfig(container *container.Container, idOrNa
func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings) error {
if !container.Running {
if container.RemovalInProgress || container.Dead {
return derr.ErrorCodeRemovalContainer.WithArgs(container.ID)
return errRemovalContainer(container.ID)
}
if _, err := daemon.updateNetworkConfig(container, idOrName, endpointConfig, true); err != nil {
return err
@ -810,7 +810,7 @@ func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName
}
if err := container.UpdateJoinInfo(n, ep); err != nil {
return derr.ErrorCodeJoinInfo.WithArgs(err)
return fmt.Errorf("Updating join info failed: %v", err)
}
daemon.LogNetworkEventWithAttributes(n, "connect", map[string]string{"container": container.ID})
@ -833,7 +833,7 @@ func (daemon *Daemon) DisconnectFromNetwork(container *container.Container, n li
}
if !container.Running {
if container.RemovalInProgress || container.Dead {
return derr.ErrorCodeRemovalContainer.WithArgs(container.ID)
return errRemovalContainer(container.ID)
}
if _, ok := container.NetworkSettings.Networks[n.Name()]; ok {
delete(container.NetworkSettings.Networks, n.Name())
@ -950,7 +950,7 @@ func (daemon *Daemon) setNetworkNamespaceKey(containerID string, pid int) error
search := libnetwork.SandboxContainerWalker(&sandbox, containerID)
daemon.netController.WalkSandboxes(search)
if sandbox == nil {
return derr.ErrorCodeNoSandbox.WithArgs(containerID, "no sandbox found")
return fmt.Errorf("error locating sandbox id %s: no sandbox found", containerID)
}
return sandbox.SetKey(path)
@ -963,10 +963,10 @@ func (daemon *Daemon) getIpcContainer(container *container.Container) (*containe
return nil, err
}
if !c.IsRunning() {
return nil, derr.ErrorCodeIPCRunning.WithArgs(containerID)
return nil, fmt.Errorf("cannot join IPC of a non running container: %s", containerID)
}
if c.IsRestarting() {
return nil, derr.ErrorCodeContainerRestarting.WithArgs(containerID)
return nil, errContainerIsRestarting(container.ID)
}
return c, nil
}
@ -977,13 +977,14 @@ func (daemon *Daemon) getNetworkedContainer(containerID, connectedContainerID st
return nil, err
}
if containerID == nc.ID {
return nil, derr.ErrorCodeJoinSelf
return nil, fmt.Errorf("cannot join own network")
}
if !nc.IsRunning() {
return nil, derr.ErrorCodeJoinRunning.WithArgs(connectedContainerID)
err := fmt.Errorf("cannot join network of a non running container: %s", connectedContainerID)
return nil, errors.NewRequestConflictError(err)
}
if nc.IsRestarting() {
return nil, derr.ErrorCodeContainerRestarting.WithArgs(connectedContainerID)
return nil, errContainerIsRestarting(connectedContainerID)
}
return nc, nil
}
@ -1141,7 +1142,7 @@ func getDevicesFromPath(deviceMapping containertypes.DeviceMapping) (devs []*con
return devs, nil
}
return devs, derr.ErrorCodeDeviceInfo.WithArgs(deviceMapping.PathOnHost, err)
return devs, fmt.Errorf("error gathering device information while adding custom device %q: %s", deviceMapping.PathOnHost, err)
}
func mergeDevices(defaultDevices, userDevices []*configs.Device) []*configs.Device {
@ -1172,3 +1173,7 @@ func isLinkable(child *container.Container) bool {
_, ok := child.NetworkSettings.Networks["bridge"]
return ok
}
func errRemovalContainer(containerID string) error {
return fmt.Errorf("Container %s is marked for removal and cannot be connected or disconnected to the network", containerID)
}

View File

@ -3,12 +3,12 @@
package daemon
import (
"fmt"
"strings"
"github.com/docker/docker/container"
"github.com/docker/docker/daemon/execdriver"
"github.com/docker/docker/daemon/execdriver/windows"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/layer"
networktypes "github.com/docker/engine-api/types/network"
"github.com/docker/libnetwork"
@ -64,7 +64,7 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro
}
}
default:
return derr.ErrorCodeInvalidNetworkMode.WithArgs(c.HostConfig.NetworkMode)
return fmt.Errorf("invalid network mode: %s", c.HostConfig.NetworkMode)
}
// TODO Windows. More resource controls to be implemented later.
@ -88,7 +88,7 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro
var layerPaths []string
img, err := daemon.imageStore.Get(c.ImageID)
if err != nil {
return derr.ErrorCodeGetGraph.WithArgs(c.ImageID, err)
return fmt.Errorf("Failed to graph.Get on ImageID %s - %s", c.ImageID, err)
}
if img.RootFS != nil && img.RootFS.Type == "layers+base" {
@ -97,7 +97,7 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro
img.RootFS.DiffIDs = img.RootFS.DiffIDs[:i]
path, err := layer.GetLayerPath(daemon.layerStore, img.RootFS.ChainID())
if err != nil {
return derr.ErrorCodeGetLayer.WithArgs(err)
return fmt.Errorf("Failed to get layer path from graphdriver %s for ImageID %s - %s", daemon.layerStore, img.RootFS.ChainID(), err)
}
// Reverse order, expecting parent most first
layerPaths = append([]string{path}, layerPaths...)
@ -106,7 +106,7 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro
m, err := c.RWLayer.Metadata()
if err != nil {
return derr.ErrorCodeGetLayerMetadata.WithArgs(err)
return fmt.Errorf("Failed to get layer metadata - %s", err)
}
layerFolder := m["dir"]

View File

@ -1,9 +1,10 @@
package daemon
import (
"fmt"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/container"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/image"
"github.com/docker/docker/layer"
"github.com/docker/docker/pkg/idtools"
@ -18,7 +19,7 @@ import (
// ContainerCreate creates a container.
func (daemon *Daemon) ContainerCreate(params types.ContainerCreateConfig) (types.ContainerCreateResponse, error) {
if params.Config == nil {
return types.ContainerCreateResponse{}, derr.ErrorCodeEmptyConfig
return types.ContainerCreateResponse{}, fmt.Errorf("Config cannot be empty in order to create a container")
}
warnings, err := daemon.verifyContainerSettings(params.HostConfig, params.Config, false)
@ -174,7 +175,7 @@ func (daemon *Daemon) VolumeCreate(name, driverName string, opts map[string]stri
v, err := daemon.volumes.Create(name, driverName, opts)
if err != nil {
if volumestore.IsNameConflict(err) {
return nil, derr.ErrorVolumeNameTaken.WithArgs(name)
return nil, fmt.Errorf("A volume named %s already exists. Choose a different volume name.", name)
}
return nil, err
}

View File

@ -3,12 +3,12 @@
package daemon
import (
"fmt"
"os"
"path/filepath"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/container"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/pkg/stringid"
containertypes "github.com/docker/engine-api/types/container"
"github.com/opencontainers/runc/libcontainer/label"
@ -41,7 +41,7 @@ func (daemon *Daemon) createContainerPlatformSpecificSettings(container *contain
stat, err := os.Stat(path)
if err == nil && !stat.IsDir() {
return derr.ErrorCodeMountOverFile.WithArgs(path)
return fmt.Errorf("cannot mount volume over existing file, file exists %s", path)
}
v, err := daemon.volumes.CreateWithRef(name, hostConfig.VolumeDriver, container.ID, nil)

View File

@ -6,7 +6,6 @@
package daemon
import (
"errors"
"fmt"
"io"
"io/ioutil"
@ -15,6 +14,7 @@ import (
"path"
"path/filepath"
"runtime"
"strings"
"sync"
"syscall"
"time"
@ -28,6 +28,7 @@ import (
"github.com/docker/docker/daemon/exec"
"github.com/docker/docker/daemon/execdriver"
"github.com/docker/docker/daemon/execdriver/execdrivers"
"github.com/docker/docker/errors"
"github.com/docker/engine-api/types"
containertypes "github.com/docker/engine-api/types/container"
eventtypes "github.com/docker/engine-api/types/events"
@ -43,7 +44,6 @@ import (
dmetadata "github.com/docker/docker/distribution/metadata"
"github.com/docker/docker/distribution/xfer"
"github.com/docker/docker/dockerversion"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/image"
"github.com/docker/docker/image/tarexport"
"github.com/docker/docker/layer"
@ -90,7 +90,7 @@ var (
validContainerNameChars = utils.RestrictedNameChars
validContainerNamePattern = utils.RestrictedNamePattern
errSystemNotSupported = errors.New("The Docker daemon is not supported on this platform.")
errSystemNotSupported = fmt.Errorf("The Docker daemon is not supported on this platform.")
)
// ErrImageDoesNotExist is error returned when no image can be found for a reference.
@ -157,7 +157,8 @@ func (daemon *Daemon) GetContainer(prefixOrName string) (*container.Container, e
if indexError != nil {
// When truncindex defines an error type, use that instead
if indexError == truncindex.ErrNotExist {
return nil, derr.ErrorCodeNoSuchContainer.WithArgs(prefixOrName)
err := fmt.Errorf("No such container: %s", prefixOrName)
return nil, errors.NewRequestNotFoundError(err)
}
return nil, indexError
}
@ -1211,7 +1212,7 @@ func (daemon *Daemon) ImageHistory(name string) ([]*types.ImageHistory, error) {
if !h.EmptyLayer {
if len(img.RootFS.DiffIDs) <= layerCounter {
return nil, errors.New("too many non-empty layers in History section")
return nil, fmt.Errorf("too many non-empty layers in History section")
}
rootFS.Append(img.RootFS.DiffIDs[layerCounter])
@ -1499,7 +1500,8 @@ func (daemon *Daemon) verifyNetworkingConfig(nwConfig *networktypes.NetworkingCo
for k := range nwConfig.EndpointsConfig {
l = append(l, k)
}
return derr.ErrorCodeMultipleNetworkConnect.WithArgs(fmt.Sprintf("%v", l))
err := fmt.Errorf("Container cannot be connected to network endpoints: %s", strings.Join(l, ", "))
return errors.NewBadRequestError(err)
}
func configureVolumes(config *Config, rootUID, rootGID int) (*store.VolumeStore, error) {
@ -1671,7 +1673,7 @@ func convertLnNetworkStats(name string, stats *lntypes.InterfaceStatistics) *lib
func validateID(id string) error {
if id == "" {
return derr.ErrorCodeEmptyID
return fmt.Errorf("Invalid empty id")
}
return nil
}

View File

@ -16,7 +16,6 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/docker/container"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/image"
"github.com/docker/docker/layer"
"github.com/docker/docker/pkg/idtools"
@ -312,17 +311,17 @@ func verifyContainerResources(resources *containertypes.Resources, sysInfo *sysi
}
cpusAvailable, err := sysInfo.IsCpusetCpusAvailable(resources.CpusetCpus)
if err != nil {
return warnings, derr.ErrorCodeInvalidCpusetCpus.WithArgs(resources.CpusetCpus)
return warnings, fmt.Errorf("Invalid value %s for cpuset cpus.", resources.CpusetCpus)
}
if !cpusAvailable {
return warnings, derr.ErrorCodeNotAvailableCpusetCpus.WithArgs(resources.CpusetCpus, sysInfo.Cpus)
return warnings, fmt.Errorf("Requested CPUs are not available - requested %s, available: %s.", resources.CpusetCpus, sysInfo.Cpus)
}
memsAvailable, err := sysInfo.IsCpusetMemsAvailable(resources.CpusetMems)
if err != nil {
return warnings, derr.ErrorCodeInvalidCpusetMems.WithArgs(resources.CpusetMems)
return warnings, fmt.Errorf("Invalid value %s for cpuset mems.", resources.CpusetMems)
}
if !memsAvailable {
return warnings, derr.ErrorCodeNotAvailableCpusetMems.WithArgs(resources.CpusetMems, sysInfo.Mems)
return warnings, fmt.Errorf("Requested memory nodes are not available - requested %s, available: %s.", resources.CpusetMems, sysInfo.Mems)
}
// blkio subsystem checks and adjustments

View File

@ -8,7 +8,7 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/docker/container"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/errors"
"github.com/docker/docker/layer"
volumestore "github.com/docker/docker/volume/store"
"github.com/docker/engine-api/types"
@ -25,12 +25,8 @@ func (daemon *Daemon) ContainerRm(name string, config *types.ContainerRmConfig)
}
// Container state RemovalInProgress should be used to avoid races.
if err = container.SetRemovalInProgress(); err != nil {
if err == derr.ErrorCodeAlreadyRemoving {
// do not fail when the removal is in progress started by other request.
return nil
}
return derr.ErrorCodeRmState.WithArgs(container.ID, err)
if inProgress := container.SetRemovalInProgress(); inProgress {
return nil
}
defer container.ResetRemovalInProgress()
@ -84,10 +80,11 @@ func (daemon *Daemon) rmLink(container *container.Container, name string) error
func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemove bool) (err error) {
if container.IsRunning() {
if !forceRemove {
return derr.ErrorCodeRmRunning.WithArgs(container.ID)
err := fmt.Errorf("You cannot remove a running container %s. Stop the container before attempting removal or use -f", container.ID)
return errors.NewRequestConflictError(err)
}
if err := daemon.Kill(container); err != nil {
return derr.ErrorCodeRmFailed.WithArgs(container.ID, err)
return fmt.Errorf("Could not kill running container %s, cannot remove - %v", container.ID, err)
}
}
@ -123,17 +120,17 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemo
}()
if err = os.RemoveAll(container.Root); err != nil {
return derr.ErrorCodeRmFS.WithArgs(container.ID, err)
return fmt.Errorf("Unable to remove filesystem for %v: %v", container.ID, err)
}
metadata, err := daemon.layerStore.ReleaseRWLayer(container.RWLayer)
layer.LogReleaseMetadata(metadata)
if err != nil && err != layer.ErrMountDoesNotExist {
return derr.ErrorCodeRmDriverFS.WithArgs(daemon.GraphDriverName(), container.ID, err)
return fmt.Errorf("Driver %s failed to remove root filesystem %s: %s", daemon.GraphDriverName(), container.ID, err)
}
if err = daemon.execDriver.Clean(container.ID); err != nil {
return derr.ErrorCodeRmExecDriver.WithArgs(container.ID, err)
return fmt.Errorf("Unable to remove execdriver data for %s: %s", container.ID, err)
}
return nil
}
@ -149,9 +146,10 @@ func (daemon *Daemon) VolumeRm(name string) error {
if err := daemon.volumes.Remove(v); err != nil {
if volumestore.IsInUse(err) {
return derr.ErrorCodeRmVolumeInUse.WithArgs(err)
err := fmt.Errorf("Unable to remove volume, volume still in use: %v", err)
return errors.NewRequestConflictError(err)
}
return derr.ErrorCodeRmVolume.WithArgs(name, err)
return fmt.Errorf("Error while removing volume %s: %v", name, err)
}
daemon.LogVolumeEvent(v.Name(), "destroy", map[string]string{"driver": v.DriverName()})
return nil

View File

@ -32,9 +32,7 @@ func TestContainerDoubleDelete(t *testing.T) {
daemon.containers.Add(container.ID, container)
// Mark the container as having a delete in progress
if err := container.SetRemovalInProgress(); err != nil {
t.Fatal(err)
}
container.SetRemovalInProgress()
// Try to remove the container when it's start is removalInProgress.
// It should ignore the container and not return an error.

View File

@ -1,26 +1,57 @@
package daemon
import (
"fmt"
"strings"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/errors"
"github.com/docker/docker/reference"
)
func (d *Daemon) imageNotExistToErrcode(err error) error {
if dne, isDNE := err.(ErrImageDoesNotExist); isDNE {
if strings.Contains(dne.RefOrID, "@") {
return derr.ErrorCodeNoSuchImageHash.WithArgs(dne.RefOrID)
e := fmt.Errorf("No such image: %s", dne.RefOrID)
return errors.NewRequestNotFoundError(e)
}
tag := reference.DefaultTag
ref, err := reference.ParseNamed(dne.RefOrID)
if err != nil {
return derr.ErrorCodeNoSuchImageTag.WithArgs(dne.RefOrID, tag)
e := fmt.Errorf("No such image: %s:%s", dne.RefOrID, tag)
return errors.NewRequestNotFoundError(e)
}
if tagged, isTagged := ref.(reference.NamedTagged); isTagged {
tag = tagged.Tag()
}
return derr.ErrorCodeNoSuchImageTag.WithArgs(ref.Name(), tag)
e := fmt.Errorf("No such image: %s:%s", ref.Name(), tag)
return errors.NewRequestNotFoundError(e)
}
return err
}
type errNotRunning struct {
containerID string
}
func (e errNotRunning) Error() string {
return fmt.Sprintf("Container %s is not running", e.containerID)
}
func (e errNotRunning) ContainerIsRunning() bool {
return false
}
func errContainerIsRestarting(containerID string) error {
err := fmt.Errorf("Container %s is restarting, wait until the container is running", containerID)
return errors.NewRequestConflictError(err)
}
func errExecNotFound(id string) error {
err := fmt.Errorf("No such exec instance '%s' found in daemon", id)
return errors.NewRequestNotFoundError(err)
}
func errExecPaused(id string) error {
err := fmt.Errorf("Container %s is paused, unpause the container before exec", id)
return errors.NewRequestConflictError(err)
}

View File

@ -1,6 +1,7 @@
package daemon
import (
"fmt"
"io"
"strings"
"time"
@ -9,7 +10,7 @@ import (
"github.com/docker/docker/container"
"github.com/docker/docker/daemon/exec"
"github.com/docker/docker/daemon/execdriver"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/errors"
"github.com/docker/docker/pkg/pools"
"github.com/docker/docker/pkg/promise"
"github.com/docker/docker/pkg/term"
@ -47,19 +48,19 @@ func (d *Daemon) getExecConfig(name string) (*exec.Config, error) {
if ec != nil {
if container := d.containers.Get(ec.ContainerID); container != nil {
if !container.IsRunning() {
return nil, derr.ErrorCodeContainerNotRunning.WithArgs(container.ID, container.State.String())
return nil, fmt.Errorf("Container %s is not running: %s", container.ID, container.State.String())
}
if container.IsPaused() {
return nil, derr.ErrorCodeExecPaused.WithArgs(container.ID)
return nil, errExecPaused(container.ID)
}
if container.IsRestarting() {
return nil, derr.ErrorCodeContainerRestarting.WithArgs(container.ID)
return nil, errContainerIsRestarting(container.ID)
}
return ec, nil
}
}
return nil, derr.ErrorCodeNoExecID.WithArgs(name)
return nil, errExecNotFound(name)
}
func (d *Daemon) unregisterExecCommand(container *container.Container, execConfig *exec.Config) {
@ -74,13 +75,13 @@ func (d *Daemon) getActiveContainer(name string) (*container.Container, error) {
}
if !container.IsRunning() {
return nil, derr.ErrorCodeNotRunning.WithArgs(name)
return nil, errNotRunning{container.ID}
}
if container.IsPaused() {
return nil, derr.ErrorCodeExecPaused.WithArgs(name)
return nil, errExecPaused(name)
}
if container.IsRestarting() {
return nil, derr.ErrorCodeContainerRestarting.WithArgs(name)
return nil, errContainerIsRestarting(container.ID)
}
return container, nil
}
@ -137,18 +138,19 @@ func (d *Daemon) ContainerExecStart(name string, stdin io.ReadCloser, stdout io.
ec, err := d.getExecConfig(name)
if err != nil {
return derr.ErrorCodeNoExecID.WithArgs(name)
return errExecNotFound(name)
}
ec.Lock()
if ec.ExitCode != nil {
ec.Unlock()
return derr.ErrorCodeExecExited.WithArgs(ec.ID)
err := fmt.Errorf("Error: Exec command %s has already run", ec.ID)
return errors.NewRequestConflictError(err)
}
if ec.Running {
ec.Unlock()
return derr.ErrorCodeExecRunning.WithArgs(ec.ID)
return fmt.Errorf("Error: Exec command %s is already running", ec.ID)
}
ec.Running = true
ec.Unlock()
@ -194,12 +196,12 @@ func (d *Daemon) ContainerExecStart(name string, stdin io.ReadCloser, stdout io.
select {
case err := <-attachErr:
if err != nil {
return derr.ErrorCodeExecAttach.WithArgs(err)
return fmt.Errorf("attach failed with error: %v", err)
}
return nil
case err := <-execErr:
if aErr := <-attachErr; aErr != nil && err == nil {
return derr.ErrorCodeExecAttach.WithArgs(aErr)
return fmt.Errorf("attach failed with error: %v", aErr)
}
if err == nil {
return nil
@ -207,9 +209,9 @@ func (d *Daemon) ContainerExecStart(name string, stdin io.ReadCloser, stdout io.
// Maybe the container stopped while we were trying to exec
if !c.IsRunning() {
return derr.ErrorCodeExecContainerStopped
return fmt.Errorf("container stopped while running exec: %s", c.ID)
}
return derr.ErrorCodeExecCantRun.WithArgs(ec.ID, c.ID, err)
return fmt.Errorf("Cannot run exec command %s in container %s: %s", ec.ID, c.ID, err)
}
}

View File

@ -1,11 +1,11 @@
package exec
import (
"fmt"
"sync"
"time"
"github.com/docker/docker/daemon/execdriver"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/runconfig"
)
@ -116,7 +116,7 @@ func (c *Config) Resize(h, w int) error {
select {
case <-c.waitStart:
case <-time.After(time.Second):
return derr.ErrorCodeExecResize.WithArgs(c.ID)
return fmt.Errorf("Exec %s is not running, so it can not be resized.", c.ID)
}
return c.ProcessConfig.Terminal.Resize(h, w)
}

View File

@ -9,7 +9,6 @@ import (
"syscall"
"github.com/docker/docker/daemon/execdriver"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/pkg/mount"
"github.com/docker/docker/profiles/seccomp"
@ -430,7 +429,7 @@ func (d *Driver) setupMounts(container *configs.Config, c *execdriver.Command) e
for _, m := range c.Mounts {
for _, cm := range container.Mounts {
if cm.Destination == m.Destination {
return derr.ErrorCodeMountDup.WithArgs(m.Destination)
return fmt.Errorf("Duplicate mount point '%s'", m.Destination)
}
}

View File

@ -1,10 +1,10 @@
package daemon
import (
"fmt"
"io"
"github.com/docker/docker/container"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/ioutils"
)
@ -19,13 +19,13 @@ func (daemon *Daemon) ContainerExport(name string, out io.Writer) error {
data, err := daemon.containerExport(container)
if err != nil {
return derr.ErrorCodeExportFailed.WithArgs(name, err)
return fmt.Errorf("Error exporting container %s: %v", name, err)
}
defer data.Close()
// Stream the entire contents of the container (basically a volatile snapshot)
if _, err := io.Copy(out, data); err != nil {
return derr.ErrorCodeExportFailed.WithArgs(name, err)
return fmt.Errorf("Error exporting container %s: %v", name, err)
}
return nil
}

View File

@ -5,7 +5,7 @@ import (
"strings"
"github.com/docker/docker/container"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/errors"
"github.com/docker/docker/image"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/reference"
@ -82,7 +82,8 @@ func (daemon *Daemon) ImageDelete(imageRef string, force, prune bool) ([]types.I
// this image would remain "dangling" and since
// we really want to avoid that the client must
// explicitly force its removal.
return nil, derr.ErrorCodeImgDelUsed.WithArgs(imageRef, stringid.TruncateID(container.ID), stringid.TruncateID(imgID.String()))
err := fmt.Errorf("conflict: unable to remove repository reference %q (must force) - container %s is using its referenced image %s", imageRef, stringid.TruncateID(container.ID), stringid.TruncateID(imgID.String()))
return nil, errors.NewRequestConflictError(err)
}
}

View File

@ -8,7 +8,6 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/docker/container"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/pkg/signal"
)
@ -45,11 +44,11 @@ func (daemon *Daemon) killWithSignal(container *container.Container, sig int) er
// We could unpause the container for them rather than returning this error
if container.Paused {
return derr.ErrorCodeUnpauseContainer.WithArgs(container.ID)
return fmt.Errorf("Container %s is paused. Unpause the container before stopping", container.ID)
}
if !container.Running {
return derr.ErrorCodeNotRunning.WithArgs(container.ID)
return errNotRunning{container.ID}
}
container.ExitOnNext()
@ -62,7 +61,7 @@ func (daemon *Daemon) killWithSignal(container *container.Container, sig int) er
}
if err := daemon.kill(container, sig); err != nil {
return derr.ErrorCodeCantKill.WithArgs(container.ID, err)
return fmt.Errorf("Cannot kill container %s: %s", container.ID, err)
}
attributes := map[string]string{
@ -75,7 +74,7 @@ func (daemon *Daemon) killWithSignal(container *container.Container, sig int) er
// Kill forcefully terminates a container.
func (daemon *Daemon) Kill(container *container.Container) error {
if !container.IsRunning() {
return derr.ErrorCodeNotRunning.WithArgs(container.ID)
return errNotRunning{container.ID}
}
// 1. Send SIGKILL

View File

@ -1,6 +1,7 @@
package daemon
import (
"fmt"
"io"
"strconv"
"time"
@ -10,7 +11,6 @@ import (
"github.com/docker/docker/container"
"github.com/docker/docker/daemon/logger"
"github.com/docker/docker/daemon/logger/jsonfilelog"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/stdcopy"
timetypes "github.com/docker/engine-api/types/time"
@ -21,11 +21,11 @@ import (
func (daemon *Daemon) ContainerLogs(containerName string, config *backend.ContainerLogsConfig, started chan struct{}) error {
container, err := daemon.GetContainer(containerName)
if err != nil {
return derr.ErrorCodeNoSuchContainer.WithArgs(containerName)
return err
}
if !(config.ShowStdout || config.ShowStderr) {
return derr.ErrorCodeNeedStream
return fmt.Errorf("You must choose at least one stream")
}
cLog, err := daemon.getLogger(container)
@ -122,7 +122,7 @@ func (daemon *Daemon) StartLogging(container *container.Container) error {
}
l, err := container.StartLogger(cfg)
if err != nil {
return derr.ErrorCodeInitLogger.WithArgs(err)
return fmt.Errorf("Failed to initialize logging driver: %v", err)
}
copier := logger.NewCopier(container.ID, map[string]io.Reader{"stdout": container.StdoutPipe(), "stderr": container.StderrPipe()}, l)

View File

@ -1,10 +1,10 @@
package daemon
import (
"fmt"
"strings"
"github.com/docker/docker/container"
derr "github.com/docker/docker/errors"
volumestore "github.com/docker/docker/volume/store"
)
@ -42,7 +42,7 @@ func (daemon *Daemon) removeMountPoints(container *container.Container, rm bool)
}
}
if len(rmErrors) > 0 {
return derr.ErrorCodeRemovingVolume.WithArgs(strings.Join(rmErrors, "\n"))
return fmt.Errorf("Error removing volumes:\n%v", strings.Join(rmErrors, "\n"))
}
return nil
}

View File

@ -3,9 +3,10 @@ package daemon
import (
"fmt"
"net"
"net/http"
"strings"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/errors"
"github.com/docker/docker/runconfig"
"github.com/docker/engine-api/types/network"
"github.com/docker/libnetwork"
@ -191,7 +192,8 @@ func (daemon *Daemon) DeleteNetwork(networkID string) error {
}
if runconfig.IsPreDefinedNetwork(nw.Name()) {
return derr.ErrorCodeCantDeletePredefinedNetwork.WithArgs(nw.Name())
err := fmt.Errorf("%s is a pre-defined network and cannot be removed", nw.Name())
return errors.NewErrorWithStatusCode(err, http.StatusForbidden)
}
if err := nw.Delete(); err != nil {

View File

@ -1,8 +1,9 @@
package daemon
import (
"fmt"
"github.com/docker/docker/container"
derr "github.com/docker/docker/errors"
)
// ContainerPause pauses a container
@ -27,21 +28,21 @@ func (daemon *Daemon) containerPause(container *container.Container) error {
// We cannot Pause the container which is not running
if !container.Running {
return derr.ErrorCodeNotRunning.WithArgs(container.ID)
return errNotRunning{container.ID}
}
// We cannot Pause the container which is already paused
if container.Paused {
return derr.ErrorCodeAlreadyPaused.WithArgs(container.ID)
return fmt.Errorf("Container %s is already paused", container.ID)
}
// We cannot Pause the container which is restarting
if container.Restarting {
return derr.ErrorCodeContainerRestarting.WithArgs(container.ID)
return errContainerIsRestarting(container.ID)
}
if err := daemon.execDriver.Pause(container.Command); err != nil {
return derr.ErrorCodeCantPause.WithArgs(container.ID, err)
return fmt.Errorf("Cannot pause container %s: %s", container.ID, err)
}
container.Paused = true
daemon.LogContainerEvent(container, "pause")

View File

@ -1,10 +1,10 @@
package daemon
import (
"fmt"
"strings"
"github.com/Sirupsen/logrus"
derr "github.com/docker/docker/errors"
"github.com/docker/libnetwork"
)
@ -18,7 +18,7 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) error {
)
if oldName == "" || newName == "" {
return derr.ErrorCodeEmptyRename
return fmt.Errorf("Neither old nor new names may be empty")
}
container, err := daemon.GetContainer(oldName)
@ -31,7 +31,7 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) error {
container.Lock()
defer container.Unlock()
if newName, err = daemon.reserveName(container.ID, newName); err != nil {
return derr.ErrorCodeRenameTaken.WithArgs(err)
return fmt.Errorf("Error when allocating new name: %v", err)
}
container.Name = newName

View File

@ -1,10 +1,6 @@
package daemon
import (
"fmt"
derr "github.com/docker/docker/errors"
)
import "fmt"
// ContainerResize changes the size of the TTY of the process running
// in the container with the given name to the given height and width.
@ -15,7 +11,7 @@ func (daemon *Daemon) ContainerResize(name string, height, width int) error {
}
if !container.IsRunning() {
return derr.ErrorCodeNotRunning.WithArgs(container.ID)
return errNotRunning{container.ID}
}
if err = container.Resize(height, width); err == nil {

View File

@ -1,8 +1,9 @@
package daemon
import (
"fmt"
"github.com/docker/docker/container"
derr "github.com/docker/docker/errors"
)
// ContainerRestart stops and starts a container. It attempts to
@ -17,7 +18,7 @@ func (daemon *Daemon) ContainerRestart(name string, seconds int) error {
return err
}
if err := daemon.containerRestart(container, seconds); err != nil {
return derr.ErrorCodeCantRestart.WithArgs(name, err)
return fmt.Errorf("Cannot restart container %s: %v", name, err)
}
return nil
}

View File

@ -2,11 +2,12 @@ package daemon
import (
"fmt"
"net/http"
"runtime"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/container"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/errors"
"github.com/docker/docker/runconfig"
containertypes "github.com/docker/engine-api/types/container"
)
@ -19,11 +20,12 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.Hos
}
if container.IsPaused() {
return derr.ErrorCodeStartPaused
return fmt.Errorf("Cannot start a paused container, try unpause instead.")
}
if container.IsRunning() {
return derr.ErrorCodeAlreadyStarted
err := fmt.Errorf("Container already started")
return errors.NewErrorWithStatusCode(err, http.StatusNotModified)
}
// Windows does not have the backwards compatibility issue here.
@ -52,7 +54,7 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.Hos
}
} else {
if hostConfig != nil {
return derr.ErrorCodeHostConfigStart
return fmt.Errorf("Supplying a hostconfig on start is not supported. It should be supplied on create")
}
}
@ -88,7 +90,7 @@ func (daemon *Daemon) containerStart(container *container.Container) (err error)
}
if container.RemovalInProgress || container.Dead {
return derr.ErrorCodeContainerBeingRemoved
return fmt.Errorf("Container is marked for removal and cannot be started.")
}
// if we encounter an error during start we need to ensure that any other

View File

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

View File

@ -1,11 +1,13 @@
package daemon
import (
"fmt"
"net/http"
"time"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/container"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/errors"
)
// ContainerStop looks for the given container and terminates it,
@ -20,10 +22,11 @@ func (daemon *Daemon) ContainerStop(name string, seconds int) error {
return err
}
if !container.IsRunning() {
return derr.ErrorCodeStopped.WithArgs(name)
err := fmt.Errorf("Container %s is already stopped", name)
return errors.NewErrorWithStatusCode(err, http.StatusNotModified)
}
if err := daemon.containerStop(container, seconds); err != nil {
return derr.ErrorCodeCantStop.WithArgs(name, err)
return fmt.Errorf("Cannot stop container %s: %v", name, err)
}
return nil
}

View File

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

View File

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

View File

@ -1,8 +1,9 @@
package daemon
import (
"fmt"
"github.com/docker/docker/container"
derr "github.com/docker/docker/errors"
)
// ContainerUnpause unpauses a container
@ -26,16 +27,16 @@ func (daemon *Daemon) containerUnpause(container *container.Container) error {
// We cannot unpause the container which is not running
if !container.Running {
return derr.ErrorCodeNotRunning.WithArgs(container.ID)
return errNotRunning{container.ID}
}
// We cannot unpause the container which is not paused
if !container.Paused {
return derr.ErrorCodeNotPaused.WithArgs(container.ID)
return fmt.Errorf("Container %s is not paused", container.ID)
}
if err := daemon.execDriver.Unpause(container.Command); err != nil {
return derr.ErrorCodeCantUnpause.WithArgs(container.ID, err)
return fmt.Errorf("Cannot unpause container %s: %s", container.ID, err)
}
container.Paused = false

View File

@ -4,7 +4,6 @@ import (
"fmt"
"time"
derr "github.com/docker/docker/errors"
"github.com/docker/engine-api/types/container"
)
@ -57,18 +56,16 @@ func (daemon *Daemon) update(name string, hostConfig *container.HostConfig) erro
}()
if container.RemovalInProgress || container.Dead {
errMsg := fmt.Errorf("Container is marked for removal and cannot be \"update\".")
return derr.ErrorCodeCantUpdate.WithArgs(container.ID, errMsg)
return errCannotUpdate(container.ID, fmt.Errorf("Container is marked for removal and cannot be \"update\"."))
}
if container.IsRunning() && hostConfig.KernelMemory != 0 {
errMsg := fmt.Errorf("Can not update kernel memory to a running container, please stop it first.")
return derr.ErrorCodeCantUpdate.WithArgs(container.ID, errMsg)
return errCannotUpdate(container.ID, fmt.Errorf("Can not update kernel memory to a running container, please stop it first."))
}
if err := container.UpdateContainer(hostConfig); err != nil {
restoreConfig = true
return derr.ErrorCodeCantUpdate.WithArgs(container.ID, err.Error())
return errCannotUpdate(container.ID, err)
}
// if Restart Policy changed, we need to update container monitor
@ -86,7 +83,7 @@ func (daemon *Daemon) update(name string, hostConfig *container.HostConfig) erro
if container.IsRunning() && !container.IsRestarting() {
if err := daemon.execDriver.Update(container.Command); err != nil {
restoreConfig = true
return derr.ErrorCodeCantUpdate.WithArgs(container.ID, err.Error())
return errCannotUpdate(container.ID, err)
}
}
@ -94,3 +91,7 @@ func (daemon *Daemon) update(name string, hostConfig *container.HostConfig) erro
return nil
}
func errCannotUpdate(containerID string, err error) error {
return fmt.Errorf("Cannot update container %s: %v", containerID, err)
}

View File

@ -2,13 +2,13 @@ package daemon
import (
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"github.com/docker/docker/container"
"github.com/docker/docker/daemon/execdriver"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/volume"
"github.com/docker/engine-api/types"
containertypes "github.com/docker/engine-api/types/container"
@ -114,7 +114,7 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
}
if binds[bind.Destination] {
return derr.ErrorCodeMountDup.WithArgs(bind.Destination)
return fmt.Errorf("Duplicate mount point '%s'", bind.Destination)
}
if len(bind.Name) > 0 {

View File

@ -3,11 +3,11 @@
package daemon
import (
"fmt"
"sort"
"github.com/docker/docker/container"
"github.com/docker/docker/daemon/execdriver"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/volume"
)
@ -27,7 +27,7 @@ func (daemon *Daemon) setupMounts(container *container.Container) ([]execdriver.
s = mount.Volume.Path()
}
if s == "" {
return nil, derr.ErrorCodeVolumeNoSourceForMount.WithArgs(mount.Name, mount.Driver, mount.Destination)
return nil, fmt.Errorf("No source for mount name '%s' driver %q destination '%s'", mount.Name, mount.Driver, mount.Destination)
}
mnts = append(mnts, execdriver.Mount{
Source: s,

View File

@ -14,6 +14,7 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/distribution/uuid"
apiserver "github.com/docker/docker/api/server"
"github.com/docker/docker/api/server/router"
"github.com/docker/docker/api/server/router/build"
"github.com/docker/docker/api/server/router/container"
"github.com/docker/docker/api/server/router/image"
@ -396,11 +397,16 @@ func loadDaemonCliConfig(config *daemon.Config, daemonFlags *flag.FlagSet, commo
}
func initRouter(s *apiserver.Server, d *daemon.Daemon) {
s.InitRouter(utils.IsDebugEnabled(),
routers := []router.Router{
container.NewRouter(d),
image.NewRouter(d),
network.NewRouter(d),
systemrouter.NewRouter(d),
volume.NewRouter(d),
build.NewRouter(dockerfile.NewBuildManager(d)))
build.NewRouter(dockerfile.NewBuildManager(d)),
}
if d.NetworkControllerEnabled() {
routers = append(routers, network.NewRouter(d))
}
s.InitRouter(utils.IsDebugEnabled(), routers...)
}

View File

@ -1,58 +0,0 @@
Docker 'errors' package
=======================
This package contains all of the error messages generated by the Docker
engine that might be exposed via the Docker engine's REST API.
Each top-level engine package will have its own file in this directory
so that there's a clear grouping of errors, instead of just one big
file. The errors for each package are defined here instead of within
their respective package structure so that Docker CLI code that may need
to import these error definition files will not need to know or understand
the engine's package/directory structure. In other words, all they should
need to do is import `.../docker/errors` and they will automatically
pick up all Docker engine defined errors. This also gives the engine
developers the freedom to change the engine packaging structure (e.g. to
CRUD packages) without worrying about breaking existing clients.
These errors are defined using the 'errcode' package. The `errcode` package
allows for each error to be typed and include all information necessary to
have further processing done on them if necessary. In particular, each error
includes:
* Value - a unique string (in all caps) associated with this error.
Typically, this string is the same name as the variable name of the error
(w/o the `ErrorCode` text) but in all caps.
* Message - the human readable sentence that will be displayed for this
error. It can contain '%s' substitutions that allows for the code generating
the error to specify values that will be inserted in the string prior to
being displayed to the end-user. The `WithArgs()` function can be used to
specify the insertion strings. Note, the evaluation of the strings will be
done at the time `WithArgs()` is called.
* Description - additional human readable text to further explain the
circumstances of the error situation.
* HTTPStatusCode - when the error is returned back to a CLI, this value
will be used to populate the HTTP status code. If not present the default
value will be `StatusInternalServerError`, 500.
Not all errors generated within the engine's executable will be propagated
back to the engine's API layer. For example, it is expected that errors
generated by vendored code (under `docker/vendor`) and packaged code
(under `docker/pkg`) will be converted into errors defined by this package.
When processing an errcode error, if you are looking for a particular
error then you can do something like:
```
import derr "github.com/docker/docker/errors"
...
err := someFunc()
if err.ErrorCode() == derr.ErrorCodeNoSuchContainer {
...
}
```

View File

@ -1,93 +0,0 @@
package errors
// This file contains all of the errors that can be generated from the
// docker/builder component.
import (
"net/http"
"github.com/docker/distribution/registry/api/errcode"
)
var (
// ErrorCodeAtLeastOneArg is generated when the parser comes across a
// Dockerfile command that doesn't have any args.
ErrorCodeAtLeastOneArg = errcode.Register(errGroup, errcode.ErrorDescriptor{
Value: "ATLEASTONEARG",
Message: "%s requires at least one argument",
Description: "The specified command requires at least one argument",
HTTPStatusCode: http.StatusInternalServerError,
})
// ErrorCodeExactlyOneArg is generated when the parser comes across a
// Dockerfile command that requires exactly one arg but got less/more.
ErrorCodeExactlyOneArg = errcode.Register(errGroup, errcode.ErrorDescriptor{
Value: "EXACTLYONEARG",
Message: "%s requires exactly one argument",
Description: "The specified command requires exactly one argument",
HTTPStatusCode: http.StatusInternalServerError,
})
// ErrorCodeAtLeastTwoArgs is generated when the parser comes across a
// Dockerfile command that requires at least two args but got less.
ErrorCodeAtLeastTwoArgs = errcode.Register(errGroup, errcode.ErrorDescriptor{
Value: "ATLEASTTWOARGS",
Message: "%s requires at least two arguments",
Description: "The specified command requires at least two arguments",
HTTPStatusCode: http.StatusInternalServerError,
})
// ErrorCodeTooManyArgs is generated when the parser comes across a
// Dockerfile command that has more args than it should
ErrorCodeTooManyArgs = errcode.Register(errGroup, errcode.ErrorDescriptor{
Value: "TOOMANYARGS",
Message: "Bad input to %s, too many args",
Description: "The specified command was passed too many arguments",
HTTPStatusCode: http.StatusInternalServerError,
})
// ErrorCodeChainOnBuild is generated when the parser comes across a
// Dockerfile command that is trying to chain ONBUILD commands.
ErrorCodeChainOnBuild = errcode.Register(errGroup, errcode.ErrorDescriptor{
Value: "CHAINONBUILD",
Message: "Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed",
Description: "ONBUILD Dockerfile commands aren't allow on ONBUILD commands",
HTTPStatusCode: http.StatusInternalServerError,
})
// ErrorCodeBadOnBuildCmd is generated when the parser comes across a
// an ONBUILD Dockerfile command with an invalid trigger/command.
ErrorCodeBadOnBuildCmd = errcode.Register(errGroup, errcode.ErrorDescriptor{
Value: "BADONBUILDCMD",
Message: "%s isn't allowed as an ONBUILD trigger",
Description: "The specified ONBUILD command isn't allowed",
HTTPStatusCode: http.StatusInternalServerError,
})
// ErrorCodeMissingFrom is generated when the Dockerfile is missing
// a FROM command.
ErrorCodeMissingFrom = errcode.Register(errGroup, errcode.ErrorDescriptor{
Value: "MISSINGFROM",
Message: "Please provide a source image with `from` prior to run",
Description: "The Dockerfile is missing a FROM command",
HTTPStatusCode: http.StatusInternalServerError,
})
// ErrorCodeNotOnWindows is generated when the specified Dockerfile
// command is not supported on Windows.
ErrorCodeNotOnWindows = errcode.Register(errGroup, errcode.ErrorDescriptor{
Value: "NOTONWINDOWS",
Message: "%s is not supported on Windows",
Description: "The specified Dockerfile command is not supported on Windows",
HTTPStatusCode: http.StatusInternalServerError,
})
// ErrorCodeVolumeEmpty is generated when the specified Volume string
// is empty.
ErrorCodeVolumeEmpty = errcode.Register(errGroup, errcode.ErrorDescriptor{
Value: "VOLUMEEMPTY",
Message: "Volume specified can not be an empty string",
Description: "The specified volume can not be an empty string",
HTTPStatusCode: http.StatusInternalServerError,
})
)

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +0,0 @@
package errors
// This file contains all of the errors that can be generated from the
// docker engine but are not tied to any specific top-level component.
const errGroup = "engine"

41
errors/errors.go Normal file
View File

@ -0,0 +1,41 @@
package errors
import "net/http"
// apiError is an error wrapper that also
// holds information about response status codes.
type apiError struct {
error
statusCode int
}
// HTTPErrorStatusCode returns a status code.
func (e apiError) HTTPErrorStatusCode() int {
return e.statusCode
}
// NewErrorWithStatusCode allows you to associate
// a specific HTTP Status Code to an error.
// The Server will take that code and set
// it as the response status.
func NewErrorWithStatusCode(err error, code int) error {
return apiError{err, code}
}
// NewBadRequestError creates a new API error
// that has the 400 HTTP status code associated to it.
func NewBadRequestError(err error) error {
return NewErrorWithStatusCode(err, http.StatusBadRequest)
}
// NewRequestNotFoundError creates a new API error
// that has the 404 HTTP status code associated to it.
func NewRequestNotFoundError(err error) error {
return NewErrorWithStatusCode(err, http.StatusNotFound)
}
// NewRequestConflictError creates a new API error
// that has the 409 HTTP status code associated to it.
func NewRequestConflictError(err error) error {
return NewErrorWithStatusCode(err, http.StatusConflict)
}

View File

@ -1,20 +0,0 @@
package errors
// This file contains all of the errors that can be generated from the
// docker/image component.
import (
"net/http"
"github.com/docker/distribution/registry/api/errcode"
)
var (
// ErrorCodeInvalidImageID is generated when image id specified is incorrectly formatted.
ErrorCodeInvalidImageID = errcode.Register(errGroup, errcode.ErrorDescriptor{
Value: "INVALIDIMAGEID",
Message: "image ID '%s' is invalid ",
Description: "The specified image id is incorrectly formatted",
HTTPStatusCode: http.StatusInternalServerError,
})
)

View File

@ -1,45 +0,0 @@
package errors
import (
"net/http"
"github.com/docker/distribution/registry/api/errcode"
)
var (
// ErrorCodeNewerClientVersion is generated when a request from a client
// specifies a higher version than the server supports.
ErrorCodeNewerClientVersion = errcode.Register(errGroup, errcode.ErrorDescriptor{
Value: "NEWERCLIENTVERSION",
Message: "client is newer than server (client API version: %s, server API version: %s)",
Description: "The client version is higher than the server version",
HTTPStatusCode: http.StatusBadRequest,
})
// ErrorCodeOldClientVersion is generated when a request from a client
// specifies a version lower than the minimum version supported by the server.
ErrorCodeOldClientVersion = errcode.Register(errGroup, errcode.ErrorDescriptor{
Value: "OLDCLIENTVERSION",
Message: "client version %s is too old. Minimum supported API version is %s, please upgrade your client to a newer version",
Description: "The client version is too old for the server",
HTTPStatusCode: http.StatusBadRequest,
})
// ErrorNetworkControllerNotEnabled is generated when the networking stack in not enabled
// for certain platforms, like windows.
ErrorNetworkControllerNotEnabled = errcode.Register(errGroup, errcode.ErrorDescriptor{
Value: "NETWORK_CONTROLLER_NOT_ENABLED",
Message: "the network controller is not enabled for this platform",
Description: "Docker's networking stack is disabled for this platform",
HTTPStatusCode: http.StatusNotFound,
})
// ErrorCodeNoHijackConnection is generated when a request tries to attach to a container
// but the connection to hijack is not provided.
ErrorCodeNoHijackConnection = errcode.Register(errGroup, errcode.ErrorDescriptor{
Value: "HIJACK_CONNECTION_MISSING",
Message: "error attaching to container %s, hijack connection missing",
Description: "The caller didn't provide a connection to hijack",
HTTPStatusCode: http.StatusBadRequest,
})
)

View File

@ -643,7 +643,7 @@ func (s *DockerSuite) TestContainerApiCreateMultipleNetworksConfig(c *check.C) {
c.Assert(err, checker.IsNil)
c.Assert(status, checker.Equals, http.StatusBadRequest)
// network name order in error message is not deterministic
c.Assert(string(b), checker.Contains, "Container cannot be connected to [")
c.Assert(string(b), checker.Contains, "Container cannot be connected to network endpoints")
c.Assert(string(b), checker.Contains, "net1")
c.Assert(string(b), checker.Contains, "net2")
c.Assert(string(b), checker.Contains, "net3")

View File

@ -463,7 +463,7 @@ func (s *DockerSuite) TestRunVolumesFromInReadWriteMode(c *check.C) {
dockerCmd(c, "run", "--name", "parent", "-v", volumeDir, "busybox", "true")
dockerCmd(c, "run", "--volumes-from", "parent:rw", "busybox", "touch", fileInVol)
if out, _, err := dockerCmdWithError("run", "--volumes-from", "parent:bar", "busybox", "touch", fileInVol); err == nil || !strings.Contains(out, `invalid mode: "bar"`) {
if out, _, err := dockerCmdWithError("run", "--volumes-from", "parent:bar", "busybox", "touch", fileInVol); err == nil || !strings.Contains(out, `invalid mode: bar`) {
c.Fatalf("running --volumes-from parent:bar should have failed with invalid mode: %q", out)
}

View File

@ -7,7 +7,6 @@ import (
"runtime"
"strings"
"github.com/docker/distribution/registry/api/errcode"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/stringid"
)
@ -86,22 +85,3 @@ func ReplaceOrAppendEnvValues(defaults, overrides []string) []string {
return defaults
}
// GetErrorMessage returns the human readable message associated with
// the passed-in error. In some cases the default Error() func returns
// something that is less than useful so based on its types this func
// will go and get a better piece of text.
func GetErrorMessage(err error) string {
switch err.(type) {
case errcode.Error:
e, _ := err.(errcode.Error)
return e.Message
case errcode.ErrorCode:
ec, _ := err.(errcode.ErrorCode)
return ec.Message()
default:
return err.Error()
}
}

View File

@ -4,14 +4,12 @@
package local
import (
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"sync"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/utils"
"github.com/docker/docker/volume"
@ -27,13 +25,21 @@ const (
var (
// ErrNotFound is the typed error returned when the requested volume name can't be found
ErrNotFound = errors.New("volume not found")
ErrNotFound = fmt.Errorf("volume not found")
// volumeNameRegex ensures the name assigned for the volume is valid.
// This name is used to create the bind directory, so we need to avoid characters that
// would make the path to escape the root directory.
volumeNameRegex = utils.RestrictedVolumeNamePattern
)
type validationError struct {
error
}
func (validationError) IsValidationError() bool {
return true
}
// New instantiates a new Root instance with the provided scope. Scope
// is the base path that the Root instance uses to store its
// volumes. The base path is created here if it does not exist.
@ -142,7 +148,7 @@ func (r *Root) Remove(v volume.Volume) error {
lv, ok := v.(*localVolume)
if !ok {
return errors.New("unknown volume type")
return fmt.Errorf("unknown volume type")
}
realPath, err := filepath.EvalSymlinks(lv.path)
@ -188,7 +194,7 @@ func (r *Root) Get(name string) (volume.Volume, error) {
func (r *Root) validateName(name string) error {
if !volumeNameRegex.MatchString(name) {
return derr.ErrorCodeVolumeName.WithArgs(name, utils.RestrictedNameChars)
return validationError{fmt.Errorf("%q includes invalid characters for a local volume name, only %q are allowed", name, utils.RestrictedNameChars)}
}
return nil
}

View File

@ -1,12 +1,12 @@
package volume
import (
"fmt"
"os"
"runtime"
"strings"
"github.com/Sirupsen/logrus"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/pkg/system"
)
@ -82,7 +82,7 @@ func (m *MountPoint) Setup() (string, error) {
}
return m.Source, nil
}
return "", derr.ErrorCodeMountSetup
return "", fmt.Errorf("Unable to setup mount point, neither source nor volume defined")
}
// Path returns the path of a volume in a mount point.
@ -96,7 +96,7 @@ func (m *MountPoint) Path() string {
// ParseVolumesFrom ensure that the supplied volumes-from is valid.
func ParseVolumesFrom(spec string) (string, string, error) {
if len(spec) == 0 {
return "", "", derr.ErrorCodeVolumeFromBlank.WithArgs(spec)
return "", "", fmt.Errorf("malformed volumes-from specification: %s", spec)
}
specParts := strings.SplitN(spec, ":", 2)
@ -106,15 +106,23 @@ func ParseVolumesFrom(spec string) (string, string, error) {
if len(specParts) == 2 {
mode = specParts[1]
if !ValidMountMode(mode) {
return "", "", derr.ErrorCodeVolumeInvalidMode.WithArgs(mode)
return "", "", errInvalidMode(mode)
}
// For now don't allow propagation properties while importing
// volumes from data container. These volumes will inherit
// the same propagation property as of the original volume
// in data container. This probably can be relaxed in future.
if HasPropagation(mode) {
return "", "", derr.ErrorCodeVolumeInvalidMode.WithArgs(mode)
return "", "", errInvalidMode(mode)
}
}
return id, mode, nil
}
func errInvalidMode(mode string) error {
return fmt.Errorf("invalid mode: %v", mode)
}
func errInvalidSpec(spec string) error {
return fmt.Errorf("Invalid volume specification: '%s'", spec)
}

View File

@ -34,8 +34,8 @@ func TestParseMountSpecPropagation(t *testing.T) {
"/hostPath:/containerPath:ro,Z,rprivate",
}
invalid = map[string]string{
"/path:/path:ro,rshared,rslave": `invalid mode: "ro,rshared,rslave"`,
"/path:/path:ro,z,rshared,rslave": `invalid mode: "ro,z,rshared,rslave"`,
"/path:/path:ro,rshared,rslave": `invalid mode: ro,rshared,rslave`,
"/path:/path:ro,z,rshared,rslave": `invalid mode: ro,z,rshared,rslave`,
"/path:shared": "Invalid volume specification",
"/path:slave": "Invalid volume specification",
"/path:private": "Invalid volume specification",

View File

@ -111,8 +111,8 @@ func TestParseMountSpec(t *testing.T) {
"/path:ro": "Invalid volume specification",
"/rw:rw": "Invalid volume specification",
"path:ro": "Invalid volume specification",
"/path:/path:sw": `invalid mode: "sw"`,
"/path:/path:rwz": `invalid mode: "rwz"`,
"/path:/path:sw": `invalid mode: sw`,
"/path:/path:rwz": `invalid mode: rwz`,
}
}

View File

@ -6,8 +6,6 @@ import (
"fmt"
"path/filepath"
"strings"
derr "github.com/docker/docker/errors"
)
// read-write modes
@ -47,12 +45,12 @@ func ParseMountSpec(spec, volumeDriver string) (*MountPoint, error) {
Propagation: DefaultPropagationMode,
}
if strings.Count(spec, ":") > 2 {
return nil, derr.ErrorCodeVolumeInvalid.WithArgs(spec)
return nil, errInvalidSpec(spec)
}
arr := strings.SplitN(spec, ":", 3)
if arr[0] == "" {
return nil, derr.ErrorCodeVolumeInvalid.WithArgs(spec)
return nil, errInvalidSpec(spec)
}
switch len(arr) {
@ -63,7 +61,7 @@ func ParseMountSpec(spec, volumeDriver string) (*MountPoint, error) {
if isValid := ValidMountMode(arr[1]); isValid {
// Destination + Mode is not a valid volume - volumes
// cannot include a mode. eg /foo:rw
return nil, derr.ErrorCodeVolumeInvalid.WithArgs(spec)
return nil, errInvalidSpec(spec)
}
// Host Source Path or Name + Destination
mp.Source = arr[0]
@ -74,23 +72,23 @@ func ParseMountSpec(spec, volumeDriver string) (*MountPoint, error) {
mp.Destination = arr[1]
mp.Mode = arr[2] // Mode field is used by SELinux to decide whether to apply label
if !ValidMountMode(mp.Mode) {
return nil, derr.ErrorCodeVolumeInvalidMode.WithArgs(mp.Mode)
return nil, errInvalidMode(mp.Mode)
}
mp.RW = ReadWrite(mp.Mode)
mp.Propagation = GetPropagation(mp.Mode)
default:
return nil, derr.ErrorCodeVolumeInvalid.WithArgs(spec)
return nil, errInvalidSpec(spec)
}
//validate the volumes destination path
mp.Destination = filepath.Clean(mp.Destination)
if !filepath.IsAbs(mp.Destination) {
return nil, derr.ErrorCodeVolumeAbs.WithArgs(mp.Destination)
return nil, fmt.Errorf("Invalid volume destination path: '%s' mount path must be absolute.", mp.Destination)
}
// Destination cannot be "/"
if mp.Destination == "/" {
return nil, derr.ErrorCodeVolumeSlash.WithArgs(spec)
return nil, fmt.Errorf("Invalid specification: destination can't be '/' in '%s'", spec)
}
name, source := ParseVolumeSource(mp.Source)
@ -106,7 +104,7 @@ func ParseMountSpec(spec, volumeDriver string) (*MountPoint, error) {
// cleanup becomes an issue if container does not unmount
// submounts explicitly.
if HasPropagation(mp.Mode) {
return nil, derr.ErrorCodeVolumeInvalid.WithArgs(spec)
return nil, errInvalidSpec(spec)
}
} else {
mp.Source = filepath.Clean(source)

View File

@ -1,13 +1,13 @@
package volume
import (
"fmt"
"os"
"path/filepath"
"regexp"
"strings"
"github.com/Sirupsen/logrus"
derr "github.com/docker/docker/errors"
)
// read-write modes
@ -96,7 +96,7 @@ func ParseMountSpec(spec string, volumeDriver string) (*MountPoint, error) {
// Must have something back
if len(match) == 0 {
return nil, derr.ErrorCodeVolumeInvalid.WithArgs(spec)
return nil, errInvalidSpec(spec)
}
// Pull out the sub expressions from the named capture groups
@ -116,7 +116,7 @@ func ParseMountSpec(spec string, volumeDriver string) (*MountPoint, error) {
// Volumes cannot include an explicitly supplied mode eg c:\path:rw
if mp.Source == "" && mp.Destination != "" && matchgroups["mode"] != "" {
return nil, derr.ErrorCodeVolumeInvalid.WithArgs(spec)
return nil, errInvalidSpec(spec)
}
// Note: No need to check if destination is absolute as it must be by
@ -125,14 +125,14 @@ func ParseMountSpec(spec string, volumeDriver string) (*MountPoint, error) {
if filepath.VolumeName(mp.Destination) == mp.Destination {
// Ensure the destination path, if a drive letter, is not the c drive
if strings.ToLower(mp.Destination) == "c:" {
return nil, derr.ErrorCodeVolumeDestIsC.WithArgs(spec)
return nil, fmt.Errorf("Destination drive letter in '%s' cannot be c:", spec)
}
} else {
// So we know the destination is a path, not drive letter. Clean it up.
mp.Destination = filepath.Clean(mp.Destination)
// Ensure the destination path, if a path, is not the c root directory
if strings.ToLower(mp.Destination) == `c:\` {
return nil, derr.ErrorCodeVolumeDestIsCRoot.WithArgs(spec)
return nil, fmt.Errorf(`Destination path in '%s' cannot be c:\`, spec)
}
}
@ -163,10 +163,10 @@ func ParseMountSpec(spec string, volumeDriver string) (*MountPoint, error) {
var fi os.FileInfo
var err error
if fi, err = os.Stat(mp.Source); err != nil {
return nil, derr.ErrorCodeVolumeSourceNotFound.WithArgs(mp.Source, err)
return nil, fmt.Errorf("Source directory '%s' could not be found: %s", mp.Source, err)
}
if !fi.IsDir() {
return nil, derr.ErrorCodeVolumeSourceNotDirectory.WithArgs(mp.Source)
return nil, fmt.Errorf("Source '%s' is not a directory", mp.Source)
}
}
@ -182,7 +182,7 @@ func IsVolumeNameValid(name string) (bool, error) {
}
nameExp = regexp.MustCompile(`^` + RXReservedNames + `$`)
if nameExp.MatchString(name) {
return false, derr.ErrorCodeVolumeNameReservedWord.WithArgs(name)
return false, fmt.Errorf("Volume name %q cannot be a reserved word for Windows filenames", name)
}
return true, nil
}