github.com/rawahars/moby@v24.0.4+incompatible/daemon/errors.go (about) 1 package daemon // import "github.com/docker/docker/daemon" 2 3 import ( 4 "fmt" 5 "strings" 6 "syscall" 7 8 "github.com/docker/docker/errdefs" 9 "github.com/pkg/errors" 10 "google.golang.org/grpc/status" 11 ) 12 13 func errNotRunning(id string) error { 14 return errdefs.Conflict(errors.Errorf("Container %s is not running", id)) 15 } 16 17 func containerNotFound(id string) error { 18 return objNotFoundError{"container", id} 19 } 20 21 type objNotFoundError struct { 22 object string 23 id string 24 } 25 26 func (e objNotFoundError) Error() string { 27 return "No such " + e.object + ": " + e.id 28 } 29 30 func (e objNotFoundError) NotFound() {} 31 32 func errContainerIsRestarting(containerID string) error { 33 cause := errors.Errorf("Container %s is restarting, wait until the container is running", containerID) 34 return errdefs.Conflict(cause) 35 } 36 37 func errExecNotFound(id string) error { 38 return objNotFoundError{"exec instance", id} 39 } 40 41 func errExecPaused(id string) error { 42 cause := errors.Errorf("Container %s is paused, unpause the container before exec", id) 43 return errdefs.Conflict(cause) 44 } 45 46 func errNotPaused(id string) error { 47 cause := errors.Errorf("Container %s is already paused", id) 48 return errdefs.Conflict(cause) 49 } 50 51 type nameConflictError struct { 52 id string 53 name string 54 } 55 56 func (e nameConflictError) Error() string { 57 return fmt.Sprintf("Conflict. The container name %q is already in use by container %q. You have to remove (or rename) that container to be able to reuse that name.", e.name, e.id) 58 } 59 60 func (nameConflictError) Conflict() {} 61 62 type containerNotModifiedError struct { 63 running bool 64 } 65 66 func (e containerNotModifiedError) Error() string { 67 if e.running { 68 return "Container is already started" 69 } 70 return "Container is already stopped" 71 } 72 73 func (e containerNotModifiedError) NotModified() {} 74 75 type invalidIdentifier string 76 77 func (e invalidIdentifier) Error() string { 78 return fmt.Sprintf("invalid name or ID supplied: %q", string(e)) 79 } 80 81 func (invalidIdentifier) InvalidParameter() {} 82 83 type incompatibleDeviceRequest struct { 84 driver string 85 caps [][]string 86 } 87 88 func (i incompatibleDeviceRequest) Error() string { 89 return fmt.Sprintf("could not select device driver %q with capabilities: %v", i.driver, i.caps) 90 } 91 92 func (incompatibleDeviceRequest) InvalidParameter() {} 93 94 type duplicateMountPointError string 95 96 func (e duplicateMountPointError) Error() string { 97 return "Duplicate mount point: " + string(e) 98 } 99 func (duplicateMountPointError) InvalidParameter() {} 100 101 type containerFileNotFound struct { 102 file string 103 container string 104 } 105 106 func (e containerFileNotFound) Error() string { 107 return "Could not find the file " + e.file + " in container " + e.container 108 } 109 110 func (containerFileNotFound) NotFound() {} 111 112 type startInvalidConfigError string 113 114 func (e startInvalidConfigError) Error() string { 115 return string(e) 116 } 117 118 func (e startInvalidConfigError) InvalidParameter() {} // Is this right??? 119 120 // exitStatus is the exit-code as set by setExitCodeFromError 121 type exitStatus = int 122 123 const ( 124 exitEaccess exitStatus = 126 // container cmd can't be invoked (permission denied) 125 exitCmdNotFound exitStatus = 127 // container cmd not found/does not exist or invalid bind-mount 126 exitUnknown exitStatus = 128 // unknown error 127 ) 128 129 // setExitCodeFromError converts the error returned by containerd 130 // when starting a container, and applies the corresponding exitStatus to the 131 // container. It returns an errdefs error (either errdefs.ErrInvalidParameter 132 // or errdefs.ErrUnknown). 133 func setExitCodeFromError(setExitCode func(exitStatus), err error) error { 134 if err == nil { 135 return nil 136 } 137 errDesc := status.Convert(err).Message() 138 contains := func(s1, s2 string) bool { 139 return strings.Contains(strings.ToLower(s1), s2) 140 } 141 142 // set to 126 for container cmd can't be invoked errors 143 if contains(errDesc, syscall.EACCES.Error()) { 144 setExitCode(exitEaccess) 145 return startInvalidConfigError(errDesc) 146 } 147 148 // Go 1.20 changed the error for attempting to execute a directory from 149 // syscall.EACCESS to syscall.EISDIR. Unfortunately docker/cli checks 150 // whether the error message contains syscall.EACCESS.Error() to 151 // determine whether to exit with code 126 or 125, so we have little 152 // choice but to fudge the error string. 153 if contains(errDesc, syscall.EISDIR.Error()) { 154 errDesc += ": " + syscall.EACCES.Error() 155 setExitCode(exitEaccess) 156 return startInvalidConfigError(errDesc) 157 } 158 159 // attempted to mount a file onto a directory, or a directory onto a file, maybe from user specified bind mounts 160 if contains(errDesc, syscall.ENOTDIR.Error()) { 161 errDesc += ": Are you trying to mount a directory onto a file (or vice-versa)? Check if the specified host path exists and is the expected type" 162 setExitCode(exitCmdNotFound) 163 return startInvalidConfigError(errDesc) 164 } 165 166 // if we receive an internal error from the initial start of a container then lets 167 // return it instead of entering the restart loop 168 // set to 127 for container cmd not found/does not exist. 169 if isInvalidCommand(errDesc) { 170 setExitCode(exitCmdNotFound) 171 return startInvalidConfigError(errDesc) 172 } 173 174 // TODO: it would be nice to get some better errors from containerd so we can return better errors here 175 setExitCode(exitUnknown) 176 return errdefs.Unknown(errors.New(errDesc)) 177 } 178 179 // isInvalidCommand tries to detect if the reason the container failed to start 180 // was due to an invalid command for the container (command not found, or not 181 // a valid executable). 182 func isInvalidCommand(errMessage string) bool { 183 errMessage = strings.ToLower(errMessage) 184 errMessages := []string{ 185 "executable file not found", 186 "no such file or directory", 187 "system cannot find the file specified", 188 "failed to run runc create/exec call", 189 } 190 191 for _, msg := range errMessages { 192 if strings.Contains(errMessage, msg) { 193 return true 194 } 195 } 196 return false 197 }