mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #15069 from duglin/UseErrorPackage
Use the new error package
This commit is contained in:
commit
e91f2c26ce
9 changed files with 286 additions and 37 deletions
58
api/errors/README.md
Normal file
58
api/errors/README.md
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
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/api/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/api/errors"
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
err := someFunc()
|
||||||
|
if err.ErrorCode() == derr.ErrorCodeNoSuchContainer {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
93
api/errors/builder.go
Normal file
93
api/errors/builder.go
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
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,
|
||||||
|
})
|
||||||
|
)
|
21
api/errors/daemon.go
Normal file
21
api/errors/daemon.go
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
package errors
|
||||||
|
|
||||||
|
// This file contains all of the errors that can be generated from the
|
||||||
|
// docker/daemon component.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/docker/distribution/registry/api/errcode"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrorCodeNoSuchContainer is generated when we look for a container by
|
||||||
|
// name or ID and we can't find it.
|
||||||
|
ErrorCodeNoSuchContainer = errcode.Register(errGroup, errcode.ErrorDescriptor{
|
||||||
|
Value: "NOSUCHCONTAINER",
|
||||||
|
Message: "no such id: %s",
|
||||||
|
Description: "The specified container can not be found",
|
||||||
|
HTTPStatusCode: http.StatusNotFound,
|
||||||
|
})
|
||||||
|
)
|
6
api/errors/error.go
Normal file
6
api/errors/error.go
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
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"
|
|
@ -3,6 +3,7 @@ package server
|
||||||
import (
|
import (
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -343,7 +344,7 @@ func (s *Server) postBuild(ctx context.Context, w http.ResponseWriter, r *http.R
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
sf := streamformatter.NewJSONStreamFormatter()
|
sf := streamformatter.NewJSONStreamFormatter()
|
||||||
w.Write(sf.FormatError(err))
|
w.Write(sf.FormatError(errors.New(utils.GetErrorMessage(err))))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import (
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
"github.com/docker/distribution/registry/api/errcode"
|
||||||
"github.com/docker/docker/api"
|
"github.com/docker/docker/api"
|
||||||
"github.com/docker/docker/autogen/dockerversion"
|
"github.com/docker/docker/autogen/dockerversion"
|
||||||
"github.com/docker/docker/context"
|
"github.com/docker/docker/context"
|
||||||
|
@ -189,10 +190,48 @@ func httpError(w http.ResponseWriter, err error) {
|
||||||
logrus.WithFields(logrus.Fields{"error": err, "writer": w}).Error("unexpected HTTP error handling")
|
logrus.WithFields(logrus.Fields{"error": err, "writer": w}).Error("unexpected HTTP error handling")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
statusCode := http.StatusInternalServerError
|
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/api/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.
|
// FIXME: this is brittle and should not be necessary.
|
||||||
// If we need to differentiate between different possible error types, we should
|
// If we need to differentiate between different possible error types,
|
||||||
// create appropriate error types with clearly defined meaning.
|
// we should create appropriate error types with clearly defined meaning
|
||||||
errStr := strings.ToLower(err.Error())
|
errStr := strings.ToLower(err.Error())
|
||||||
for keyword, status := range map[string]int{
|
for keyword, status := range map[string]int{
|
||||||
"not found": http.StatusNotFound,
|
"not found": http.StatusNotFound,
|
||||||
|
@ -208,9 +247,14 @@ func httpError(w http.ResponseWriter, err error) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if statusCode == 0 {
|
||||||
|
statusCode = http.StatusInternalServerError
|
||||||
|
}
|
||||||
|
|
||||||
logrus.WithFields(logrus.Fields{"statusCode": statusCode, "err": err}).Error("HTTP Error")
|
logrus.WithFields(logrus.Fields{"statusCode": statusCode, "err": err}).Error("HTTP Error")
|
||||||
http.Error(w, err.Error(), statusCode)
|
http.Error(w, errMsg, statusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeJSON writes the value v to the http response stream as json with standard
|
// writeJSON writes the value v to the http response stream as json with standard
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
|
derr "github.com/docker/docker/api/errors"
|
||||||
flag "github.com/docker/docker/pkg/mflag"
|
flag "github.com/docker/docker/pkg/mflag"
|
||||||
"github.com/docker/docker/pkg/nat"
|
"github.com/docker/docker/pkg/nat"
|
||||||
"github.com/docker/docker/pkg/signal"
|
"github.com/docker/docker/pkg/signal"
|
||||||
|
@ -44,12 +45,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 {
|
func env(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return fmt.Errorf("ENV requires at least one argument")
|
return derr.ErrorCodeAtLeastOneArg.WithArgs("ENV")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(args)%2 != 0 {
|
if len(args)%2 != 0 {
|
||||||
// should never get here, but just in case
|
// should never get here, but just in case
|
||||||
return fmt.Errorf("Bad input to ENV, too many args")
|
return derr.ErrorCodeTooManyArgs.WithArgs("ENV")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.BuilderFlags.Parse(); err != nil {
|
if err := b.BuilderFlags.Parse(); err != nil {
|
||||||
|
@ -103,7 +104,7 @@ func env(b *builder, args []string, attributes map[string]bool, original string)
|
||||||
// Sets the maintainer metadata.
|
// Sets the maintainer metadata.
|
||||||
func maintainer(b *builder, args []string, attributes map[string]bool, original string) error {
|
func maintainer(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||||
if len(args) != 1 {
|
if len(args) != 1 {
|
||||||
return fmt.Errorf("MAINTAINER requires exactly one argument")
|
return derr.ErrorCodeExactlyOneArg.WithArgs("MAINTAINER")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.BuilderFlags.Parse(); err != nil {
|
if err := b.BuilderFlags.Parse(); err != nil {
|
||||||
|
@ -120,11 +121,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 {
|
func label(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return fmt.Errorf("LABEL requires at least one argument")
|
return derr.ErrorCodeAtLeastOneArg.WithArgs("LABEL")
|
||||||
}
|
}
|
||||||
if len(args)%2 != 0 {
|
if len(args)%2 != 0 {
|
||||||
// should never get here, but just in case
|
// should never get here, but just in case
|
||||||
return fmt.Errorf("Bad input to LABEL, too many args")
|
return derr.ErrorCodeTooManyArgs.WithArgs("LABEL")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.BuilderFlags.Parse(); err != nil {
|
if err := b.BuilderFlags.Parse(); err != nil {
|
||||||
|
@ -156,7 +157,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 {
|
func add(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||||
if len(args) < 2 {
|
if len(args) < 2 {
|
||||||
return fmt.Errorf("ADD requires at least two arguments")
|
return derr.ErrorCodeAtLeastTwoArgs.WithArgs("ADD")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.BuilderFlags.Parse(); err != nil {
|
if err := b.BuilderFlags.Parse(); err != nil {
|
||||||
|
@ -172,7 +173,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 {
|
func dispatchCopy(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||||
if len(args) < 2 {
|
if len(args) < 2 {
|
||||||
return fmt.Errorf("COPY requires at least two arguments")
|
return derr.ErrorCodeAtLeastTwoArgs.WithArgs("COPY")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.BuilderFlags.Parse(); err != nil {
|
if err := b.BuilderFlags.Parse(); err != nil {
|
||||||
|
@ -188,7 +189,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 {
|
func from(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||||
if len(args) != 1 {
|
if len(args) != 1 {
|
||||||
return fmt.Errorf("FROM requires one argument")
|
return derr.ErrorCodeExactlyOneArg.WithArgs("FROM")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.BuilderFlags.Parse(); err != nil {
|
if err := b.BuilderFlags.Parse(); err != nil {
|
||||||
|
@ -240,7 +241,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 {
|
func onbuild(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return fmt.Errorf("ONBUILD requires at least one argument")
|
return derr.ErrorCodeAtLeastOneArg.WithArgs("ONBUILD")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.BuilderFlags.Parse(); err != nil {
|
if err := b.BuilderFlags.Parse(); err != nil {
|
||||||
|
@ -250,9 +251,9 @@ func onbuild(b *builder, args []string, attributes map[string]bool, original str
|
||||||
triggerInstruction := strings.ToUpper(strings.TrimSpace(args[0]))
|
triggerInstruction := strings.ToUpper(strings.TrimSpace(args[0]))
|
||||||
switch triggerInstruction {
|
switch triggerInstruction {
|
||||||
case "ONBUILD":
|
case "ONBUILD":
|
||||||
return fmt.Errorf("Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed")
|
return derr.ErrorCodeChainOnBuild
|
||||||
case "MAINTAINER", "FROM":
|
case "MAINTAINER", "FROM":
|
||||||
return fmt.Errorf("%s isn't allowed as an ONBUILD trigger", triggerInstruction)
|
return derr.ErrorCodeBadOnBuildCmd.WithArgs(triggerInstruction)
|
||||||
}
|
}
|
||||||
|
|
||||||
original = regexp.MustCompile(`(?i)^\s*ONBUILD\s*`).ReplaceAllString(original, "")
|
original = regexp.MustCompile(`(?i)^\s*ONBUILD\s*`).ReplaceAllString(original, "")
|
||||||
|
@ -267,7 +268,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 {
|
func workdir(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||||
if len(args) != 1 {
|
if len(args) != 1 {
|
||||||
return fmt.Errorf("WORKDIR requires exactly one argument")
|
return derr.ErrorCodeExactlyOneArg.WithArgs("WORKDIR")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.BuilderFlags.Parse(); err != nil {
|
if err := b.BuilderFlags.Parse(); err != nil {
|
||||||
|
@ -300,7 +301,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 {
|
func run(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||||
if b.image == "" && !b.noBaseImage {
|
if b.image == "" && !b.noBaseImage {
|
||||||
return fmt.Errorf("Please provide a source image with `from` prior to run")
|
return derr.ErrorCodeMissingFrom
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.BuilderFlags.Parse(); err != nil {
|
if err := b.BuilderFlags.Parse(); err != nil {
|
||||||
|
@ -450,7 +451,7 @@ func expose(b *builder, args []string, attributes map[string]bool, original stri
|
||||||
portsTab := args
|
portsTab := args
|
||||||
|
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return fmt.Errorf("EXPOSE requires at least one argument")
|
return derr.ErrorCodeAtLeastOneArg.WithArgs("EXPOSE")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.BuilderFlags.Parse(); err != nil {
|
if err := b.BuilderFlags.Parse(); err != nil {
|
||||||
|
@ -489,11 +490,11 @@ 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 {
|
func user(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
return fmt.Errorf("USER is not supported on Windows")
|
return derr.ErrorCodeNotOnWindows.WithArgs("USER")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(args) != 1 {
|
if len(args) != 1 {
|
||||||
return fmt.Errorf("USER requires exactly one argument")
|
return derr.ErrorCodeExactlyOneArg.WithArgs("USER")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.BuilderFlags.Parse(); err != nil {
|
if err := b.BuilderFlags.Parse(); err != nil {
|
||||||
|
@ -510,10 +511,10 @@ 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 {
|
func volume(b *builder, args []string, attributes map[string]bool, original string) error {
|
||||||
if runtime.GOOS == "windows" {
|
if runtime.GOOS == "windows" {
|
||||||
return fmt.Errorf("VOLUME is not supported on Windows")
|
return derr.ErrorCodeNotOnWindows.WithArgs("VOLUME")
|
||||||
}
|
}
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
return fmt.Errorf("VOLUME requires at least one argument")
|
return derr.ErrorCodeAtLeastOneArg.WithArgs("VOLUME")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := b.BuilderFlags.Parse(); err != nil {
|
if err := b.BuilderFlags.Parse(); err != nil {
|
||||||
|
@ -526,7 +527,7 @@ func volume(b *builder, args []string, attributes map[string]bool, original stri
|
||||||
for _, v := range args {
|
for _, v := range args {
|
||||||
v = strings.TrimSpace(v)
|
v = strings.TrimSpace(v)
|
||||||
if v == "" {
|
if v == "" {
|
||||||
return fmt.Errorf("Volume specified can not be an empty string")
|
return derr.ErrorCodeVolumeEmpty
|
||||||
}
|
}
|
||||||
b.Config.Volumes[v] = struct{}{}
|
b.Config.Volumes[v] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/docker/docker/api"
|
"github.com/docker/docker/api"
|
||||||
|
derr "github.com/docker/docker/api/errors"
|
||||||
"github.com/docker/docker/daemon/events"
|
"github.com/docker/docker/daemon/events"
|
||||||
"github.com/docker/docker/daemon/execdriver"
|
"github.com/docker/docker/daemon/execdriver"
|
||||||
"github.com/docker/docker/daemon/execdriver/execdrivers"
|
"github.com/docker/docker/daemon/execdriver/execdrivers"
|
||||||
|
@ -137,6 +138,10 @@ func (daemon *Daemon) Get(prefixOrName string) (*Container, error) {
|
||||||
|
|
||||||
containerID, indexError := daemon.idIndex.Get(prefixOrName)
|
containerID, indexError := daemon.idIndex.Get(prefixOrName)
|
||||||
if indexError != nil {
|
if indexError != nil {
|
||||||
|
// When truncindex defines an error type, use that instead
|
||||||
|
if strings.Contains(indexError.Error(), "no such id") {
|
||||||
|
return nil, derr.ErrorCodeNoSuchContainer.WithArgs(prefixOrName)
|
||||||
|
}
|
||||||
return nil, indexError
|
return nil, indexError
|
||||||
}
|
}
|
||||||
return daemon.containers.Get(containerID), nil
|
return daemon.containers.Get(containerID), nil
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/docker/distribution/registry/api/errcode"
|
||||||
"github.com/docker/docker/autogen/dockerversion"
|
"github.com/docker/docker/autogen/dockerversion"
|
||||||
"github.com/docker/docker/pkg/archive"
|
"github.com/docker/docker/pkg/archive"
|
||||||
"github.com/docker/docker/pkg/fileutils"
|
"github.com/docker/docker/pkg/fileutils"
|
||||||
|
@ -286,3 +287,22 @@ func ImageReference(repo, ref string) string {
|
||||||
func DigestReference(ref string) bool {
|
func DigestReference(ref string) bool {
|
||||||
return strings.Contains(ref, ":")
|
return strings.Contains(ref, ":")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue