1package daemon 2 3import ( 4 "fmt" 5 "strings" 6 "syscall" 7 8 "github.com/pkg/errors" 9 "google.golang.org/grpc" 10) 11 12func errNotRunning(id string) error { 13 return stateConflictError{errors.Errorf("Container %s is not running", id)} 14} 15 16func containerNotFound(id string) error { 17 return objNotFoundError{"container", id} 18} 19 20func volumeNotFound(id string) error { 21 return objNotFoundError{"volume", id} 22} 23 24type objNotFoundError struct { 25 object string 26 id string 27} 28 29func (e objNotFoundError) Error() string { 30 return "No such " + e.object + ": " + e.id 31} 32 33func (e objNotFoundError) NotFound() {} 34 35type stateConflictError struct { 36 cause error 37} 38 39func (e stateConflictError) Error() string { 40 return e.cause.Error() 41} 42 43func (e stateConflictError) Cause() error { 44 return e.cause 45} 46 47func (e stateConflictError) Conflict() {} 48 49func errContainerIsRestarting(containerID string) error { 50 cause := errors.Errorf("Container %s is restarting, wait until the container is running", containerID) 51 return stateConflictError{cause} 52} 53 54func errExecNotFound(id string) error { 55 return objNotFoundError{"exec instance", id} 56} 57 58func errExecPaused(id string) error { 59 cause := errors.Errorf("Container %s is paused, unpause the container before exec", id) 60 return stateConflictError{cause} 61} 62 63func errNotPaused(id string) error { 64 cause := errors.Errorf("Container %s is already paused", id) 65 return stateConflictError{cause} 66} 67 68type nameConflictError struct { 69 id string 70 name string 71} 72 73func (e nameConflictError) Error() string { 74 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) 75} 76 77func (nameConflictError) Conflict() {} 78 79type validationError struct { 80 cause error 81} 82 83func (e validationError) Error() string { 84 return e.cause.Error() 85} 86 87func (e validationError) InvalidParameter() {} 88 89func (e validationError) Cause() error { 90 return e.cause 91} 92 93type notAllowedError struct { 94 cause error 95} 96 97func (e notAllowedError) Error() string { 98 return e.cause.Error() 99} 100 101func (e notAllowedError) Forbidden() {} 102 103func (e notAllowedError) Cause() error { 104 return e.cause 105} 106 107type containerNotModifiedError struct { 108 running bool 109} 110 111func (e containerNotModifiedError) Error() string { 112 if e.running { 113 return "Container is already started" 114 } 115 return "Container is already stopped" 116} 117 118func (e containerNotModifiedError) NotModified() {} 119 120type systemError struct { 121 cause error 122} 123 124func (e systemError) Error() string { 125 return e.cause.Error() 126} 127 128func (e systemError) SystemError() {} 129 130func (e systemError) Cause() error { 131 return e.cause 132} 133 134type invalidIdentifier string 135 136func (e invalidIdentifier) Error() string { 137 return fmt.Sprintf("invalid name or ID supplied: %q", string(e)) 138} 139 140func (invalidIdentifier) InvalidParameter() {} 141 142type duplicateMountPointError string 143 144func (e duplicateMountPointError) Error() string { 145 return "Duplicate mount point: " + string(e) 146} 147func (duplicateMountPointError) InvalidParameter() {} 148 149type containerFileNotFound struct { 150 file string 151 container string 152} 153 154func (e containerFileNotFound) Error() string { 155 return "Could not find the file " + e.file + " in container " + e.container 156} 157 158func (containerFileNotFound) NotFound() {} 159 160type invalidFilter struct { 161 filter string 162 value interface{} 163} 164 165func (e invalidFilter) Error() string { 166 msg := "Invalid filter '" + e.filter 167 if e.value != nil { 168 msg += fmt.Sprintf("=%s", e.value) 169 } 170 return msg + "'" 171} 172 173func (e invalidFilter) InvalidParameter() {} 174 175type unknownError struct { 176 cause error 177} 178 179func (e unknownError) Error() string { 180 return e.cause.Error() 181} 182 183func (unknownError) Unknown() {} 184 185func (e unknownError) Cause() error { 186 return e.cause 187} 188 189type startInvalidConfigError string 190 191func (e startInvalidConfigError) Error() string { 192 return string(e) 193} 194 195func (e startInvalidConfigError) InvalidParameter() {} // Is this right??? 196 197func translateContainerdStartErr(cmd string, setExitCode func(int), err error) error { 198 errDesc := grpc.ErrorDesc(err) 199 contains := func(s1, s2 string) bool { 200 return strings.Contains(strings.ToLower(s1), s2) 201 } 202 var retErr error = unknownError{errors.New(errDesc)} 203 // if we receive an internal error from the initial start of a container then lets 204 // return it instead of entering the restart loop 205 // set to 127 for container cmd not found/does not exist) 206 if contains(errDesc, cmd) && 207 (contains(errDesc, "executable file not found") || 208 contains(errDesc, "no such file or directory") || 209 contains(errDesc, "system cannot find the file specified")) { 210 setExitCode(127) 211 retErr = startInvalidConfigError(errDesc) 212 } 213 // set to 126 for container cmd can't be invoked errors 214 if contains(errDesc, syscall.EACCES.Error()) { 215 setExitCode(126) 216 retErr = startInvalidConfigError(errDesc) 217 } 218 219 // attempted to mount a file onto a directory, or a directory onto a file, maybe from user specified bind mounts 220 if contains(errDesc, syscall.ENOTDIR.Error()) { 221 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" 222 setExitCode(127) 223 retErr = startInvalidConfigError(errDesc) 224 } 225 226 // TODO: it would be nice to get some better errors from containerd so we can return better errors here 227 return retErr 228} 229 230// TODO: cpuguy83 take care of it once the new library is ready 231type errNotFound struct{ error } 232 233func (errNotFound) NotFound() {} 234 235func (e errNotFound) Cause() error { 236 return e.error 237} 238 239// notFound is a helper to create an error of the class with the same name from any error type 240func notFound(err error) error { 241 if err == nil { 242 return nil 243 } 244 return errNotFound{err} 245} 246