github.com/hernad/nomad@v1.6.112/nomad/structs/errors.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package structs 5 6 import ( 7 "errors" 8 "fmt" 9 "strconv" 10 "strings" 11 ) 12 13 const ( 14 errNoLeader = "No cluster leader" 15 errNotReadyForConsistentReads = "Not ready to serve consistent reads" 16 errNoRegionPath = "No path to region" 17 errTokenNotFound = "ACL token not found" 18 errTokenExpired = "ACL token expired" 19 errTokenInvalid = "ACL token is invalid" // not a UUID 20 errPermissionDenied = "Permission denied" 21 errJobRegistrationDisabled = "Job registration, dispatch, and scale are disabled by the scheduler configuration" 22 errNoNodeConn = "No path to node" 23 errUnknownMethod = "Unknown rpc method" 24 errUnknownNomadVersion = "Unable to determine Nomad version" 25 errNodeLacksRpc = "Node does not support RPC; requires 0.8 or later" 26 errMissingAllocID = "Missing allocation ID" 27 errIncompatibleFiltering = "Filter expression cannot be used with other filter parameters" 28 errMalformedChooseParameter = "Parameter for choose must be in form '<number>|<key>'" 29 30 // Prefix based errors that are used to check if the error is of a given 31 // type. These errors should be created with the associated constructor. 32 ErrUnknownAllocationPrefix = "Unknown allocation" 33 ErrUnknownNodePrefix = "Unknown node" 34 ErrUnknownJobPrefix = "Unknown job" 35 ErrUnknownEvaluationPrefix = "Unknown evaluation" 36 ErrUnknownDeploymentPrefix = "Unknown deployment" 37 38 errRPCCodedErrorPrefix = "RPC Error:: " 39 40 errDeploymentTerminalNoCancel = "can't cancel terminal deployment" 41 errDeploymentTerminalNoFail = "can't fail terminal deployment" 42 errDeploymentTerminalNoPause = "can't pause terminal deployment" 43 errDeploymentTerminalNoPromote = "can't promote terminal deployment" 44 errDeploymentTerminalNoResume = "can't resume terminal deployment" 45 errDeploymentTerminalNoUnblock = "can't unblock terminal deployment" 46 errDeploymentTerminalNoRun = "can't run terminal deployment" 47 errDeploymentTerminalNoSetHealth = "can't set health of allocations for a terminal deployment" 48 errDeploymentRunningNoUnblock = "can't unblock running deployment" 49 ) 50 51 var ( 52 ErrNoLeader = errors.New(errNoLeader) 53 ErrNotReadyForConsistentReads = errors.New(errNotReadyForConsistentReads) 54 ErrNoRegionPath = errors.New(errNoRegionPath) 55 ErrTokenNotFound = errors.New(errTokenNotFound) 56 ErrTokenExpired = errors.New(errTokenExpired) 57 ErrTokenInvalid = errors.New(errTokenInvalid) 58 ErrPermissionDenied = errors.New(errPermissionDenied) 59 ErrJobRegistrationDisabled = errors.New(errJobRegistrationDisabled) 60 ErrNoNodeConn = errors.New(errNoNodeConn) 61 ErrUnknownMethod = errors.New(errUnknownMethod) 62 ErrUnknownNomadVersion = errors.New(errUnknownNomadVersion) 63 ErrNodeLacksRpc = errors.New(errNodeLacksRpc) 64 ErrMissingAllocID = errors.New(errMissingAllocID) 65 ErrIncompatibleFiltering = errors.New(errIncompatibleFiltering) 66 ErrMalformedChooseParameter = errors.New(errMalformedChooseParameter) 67 68 ErrUnknownNode = errors.New(ErrUnknownNodePrefix) 69 70 ErrDeploymentTerminalNoCancel = errors.New(errDeploymentTerminalNoCancel) 71 ErrDeploymentTerminalNoFail = errors.New(errDeploymentTerminalNoFail) 72 ErrDeploymentTerminalNoPause = errors.New(errDeploymentTerminalNoPause) 73 ErrDeploymentTerminalNoPromote = errors.New(errDeploymentTerminalNoPromote) 74 ErrDeploymentTerminalNoResume = errors.New(errDeploymentTerminalNoResume) 75 ErrDeploymentTerminalNoUnblock = errors.New(errDeploymentTerminalNoUnblock) 76 ErrDeploymentTerminalNoRun = errors.New(errDeploymentTerminalNoRun) 77 ErrDeploymentTerminalNoSetHealth = errors.New(errDeploymentTerminalNoSetHealth) 78 ErrDeploymentRunningNoUnblock = errors.New(errDeploymentRunningNoUnblock) 79 80 ErrCSIClientRPCIgnorable = errors.New("CSI client error (ignorable)") 81 ErrCSIClientRPCRetryable = errors.New("CSI client error (retryable)") 82 ErrCSIVolumeMaxClaims = errors.New("volume max claims reached") 83 ErrCSIVolumeUnschedulable = errors.New("volume is currently unschedulable") 84 ) 85 86 // IsErrNoLeader returns whether the error is due to there being no leader. 87 func IsErrNoLeader(err error) bool { 88 return err != nil && strings.Contains(err.Error(), errNoLeader) 89 } 90 91 // IsErrNoRegionPath returns whether the error is due to there being no path to 92 // the given region. 93 func IsErrNoRegionPath(err error) bool { 94 return err != nil && strings.Contains(err.Error(), errNoRegionPath) 95 } 96 97 // IsErrTokenNotFound returns whether the error is due to the passed token not 98 // being resolvable. 99 func IsErrTokenNotFound(err error) bool { 100 return err != nil && strings.Contains(err.Error(), errTokenNotFound) 101 } 102 103 // IsErrPermissionDenied returns whether the error is due to the operation not 104 // being allowed due to lack of permissions. 105 func IsErrPermissionDenied(err error) bool { 106 return err != nil && strings.Contains(err.Error(), errPermissionDenied) 107 } 108 109 // IsErrNoNodeConn returns whether the error is due to there being no path to 110 // the given node. 111 func IsErrNoNodeConn(err error) bool { 112 return err != nil && strings.Contains(err.Error(), errNoNodeConn) 113 } 114 115 // IsErrUnknownMethod returns whether the error is due to the operation not 116 // being allowed due to lack of permissions. 117 func IsErrUnknownMethod(err error) bool { 118 return err != nil && strings.Contains(err.Error(), errUnknownMethod) 119 } 120 121 func IsErrRPCCoded(err error) bool { 122 return err != nil && strings.HasPrefix(err.Error(), errRPCCodedErrorPrefix) 123 } 124 125 // NewErrUnknownAllocation returns a new error caused by the allocation being 126 // unknown. 127 func NewErrUnknownAllocation(allocID string) error { 128 return fmt.Errorf("%s %q", ErrUnknownAllocationPrefix, allocID) 129 } 130 131 // NewErrUnknownNode returns a new error caused by the node being unknown. 132 func NewErrUnknownNode(nodeID string) error { 133 return fmt.Errorf("%s %q", ErrUnknownNodePrefix, nodeID) 134 } 135 136 // NewErrUnknownJob returns a new error caused by the job being unknown. 137 func NewErrUnknownJob(jobID string) error { 138 return fmt.Errorf("%s %q", ErrUnknownJobPrefix, jobID) 139 } 140 141 // NewErrUnknownEvaluation returns a new error caused by the evaluation being 142 // unknown. 143 func NewErrUnknownEvaluation(evaluationID string) error { 144 return fmt.Errorf("%s %q", ErrUnknownEvaluationPrefix, evaluationID) 145 } 146 147 // NewErrUnknownDeployment returns a new error caused by the deployment being 148 // unknown. 149 func NewErrUnknownDeployment(deploymentID string) error { 150 return fmt.Errorf("%s %q", ErrUnknownDeploymentPrefix, deploymentID) 151 } 152 153 // IsErrUnknownAllocation returns whether the error is due to an unknown 154 // allocation. 155 func IsErrUnknownAllocation(err error) bool { 156 return err != nil && strings.Contains(err.Error(), ErrUnknownAllocationPrefix) 157 } 158 159 // IsErrUnknownNode returns whether the error is due to an unknown 160 // node. 161 func IsErrUnknownNode(err error) bool { 162 return err != nil && strings.Contains(err.Error(), ErrUnknownNodePrefix) 163 } 164 165 // IsErrUnknownJob returns whether the error is due to an unknown 166 // job. 167 func IsErrUnknownJob(err error) bool { 168 return err != nil && strings.Contains(err.Error(), ErrUnknownJobPrefix) 169 } 170 171 // IsErrUnknownEvaluation returns whether the error is due to an unknown 172 // evaluation. 173 func IsErrUnknownEvaluation(err error) bool { 174 return err != nil && strings.Contains(err.Error(), ErrUnknownEvaluationPrefix) 175 } 176 177 // IsErrUnknownDeployment returns whether the error is due to an unknown 178 // deployment. 179 func IsErrUnknownDeployment(err error) bool { 180 return err != nil && strings.Contains(err.Error(), ErrUnknownDeploymentPrefix) 181 } 182 183 // IsErrUnknownNomadVersion returns whether the error is due to Nomad being 184 // unable to determine the version of a node. 185 func IsErrUnknownNomadVersion(err error) bool { 186 return err != nil && strings.Contains(err.Error(), errUnknownNomadVersion) 187 } 188 189 // IsErrNodeLacksRpc returns whether error is due to a Nomad server being 190 // unable to connect to a client node because the client is too old (pre-v0.8). 191 func IsErrNodeLacksRpc(err error) bool { 192 return err != nil && strings.Contains(err.Error(), errNodeLacksRpc) 193 } 194 195 func IsErrNoSuchFileOrDirectory(err error) bool { 196 return err != nil && strings.Contains(err.Error(), "no such file or directory") 197 } 198 199 // NewErrRPCCoded wraps an RPC error with a code to be converted to HTTP status 200 // code 201 func NewErrRPCCoded(code int, msg string) error { 202 return fmt.Errorf("%s%d,%s", errRPCCodedErrorPrefix, code, msg) 203 } 204 205 // NewErrRPCCodedf wraps an RPC error with a code to be converted to HTTP 206 // status code. 207 func NewErrRPCCodedf(code int, format string, args ...interface{}) error { 208 msg := fmt.Sprintf(format, args...) 209 return fmt.Errorf("%s%d,%s", errRPCCodedErrorPrefix, code, msg) 210 } 211 212 // CodeFromRPCCodedErr returns the code and message of error if it's an RPC error 213 // created through NewErrRPCCoded function. Returns `ok` false if error is not 214 // an rpc error 215 func CodeFromRPCCodedErr(err error) (code int, msg string, ok bool) { 216 if err == nil || !strings.HasPrefix(err.Error(), errRPCCodedErrorPrefix) { 217 return 0, "", false 218 } 219 220 headerLen := len(errRPCCodedErrorPrefix) 221 parts := strings.SplitN(err.Error()[headerLen:], ",", 2) 222 if len(parts) != 2 { 223 return 0, "", false 224 } 225 226 code, err = strconv.Atoi(parts[0]) 227 if err != nil { 228 return 0, "", false 229 } 230 231 return code, parts[1], true 232 }