1/* 2Copyright 2015 Gravitational, Inc. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package trace 18 19import ( 20 "crypto/x509" 21 "fmt" 22 "io" 23 "net" 24 "net/url" 25 "os" 26) 27 28// NotFound returns new instance of not found error 29func NotFound(message string, args ...interface{}) Error { 30 return WrapWithMessage(&NotFoundError{ 31 Message: fmt.Sprintf(message, args...), 32 }, message, args...) 33} 34 35// NotFoundError indicates that object has not been found 36type NotFoundError struct { 37 Message string `json:"message"` 38} 39 40// IsNotFoundError returns true to indicate that is NotFoundError 41func (e *NotFoundError) IsNotFoundError() bool { 42 return true 43} 44 45// Error returns log friendly description of an error 46func (e *NotFoundError) Error() string { 47 if e.Message != "" { 48 return e.Message 49 } 50 return "object not found" 51} 52 53// OrigError returns original error (in this case this is the error itself) 54func (e *NotFoundError) OrigError() error { 55 return e 56} 57 58// IsNotFound returns whether this error is of NotFoundError type 59func IsNotFound(e error) bool { 60 type nf interface { 61 IsNotFoundError() bool 62 } 63 err := Unwrap(e) 64 _, ok := err.(nf) 65 if !ok { 66 return os.IsNotExist(err) 67 } 68 return ok 69} 70 71// AlreadyExists returns a new instance of AlreadyExists error 72func AlreadyExists(message string, args ...interface{}) Error { 73 return WrapWithMessage(&AlreadyExistsError{ 74 fmt.Sprintf(message, args...), 75 }, message, args...) 76} 77 78// AlreadyExistsError indicates that there's a duplicate object that already 79// exists in the storage/system 80type AlreadyExistsError struct { 81 Message string `json:"message"` 82} 83 84// Error returns log friendly description of an error 85func (n *AlreadyExistsError) Error() string { 86 if n.Message != "" { 87 return n.Message 88 } 89 return "object already exists" 90} 91 92// IsAlreadyExistsError indicates that this error of the AlreadyExistsError type 93func (AlreadyExistsError) IsAlreadyExistsError() bool { 94 return true 95} 96 97// OrigError returns original error (in this case this is the error itself) 98func (e *AlreadyExistsError) OrigError() error { 99 return e 100} 101 102// IsAlreadyExists returns whether this is error indicating that object 103// already exists 104func IsAlreadyExists(e error) bool { 105 type ae interface { 106 IsAlreadyExistsError() bool 107 } 108 _, ok := Unwrap(e).(ae) 109 return ok 110} 111 112// BadParameter returns a new instance of BadParameterError 113func BadParameter(message string, args ...interface{}) Error { 114 return WrapWithMessage(&BadParameterError{ 115 Message: fmt.Sprintf(message, args...), 116 }, message, args...) 117} 118 119// BadParameterError indicates that something is wrong with passed 120// parameter to API method 121type BadParameterError struct { 122 Message string `json:"message"` 123} 124 125// Error returns log friendly description of an error 126func (b *BadParameterError) Error() string { 127 return b.Message 128} 129 130// OrigError returns original error (in this case this is the error itself) 131func (b *BadParameterError) OrigError() error { 132 return b 133} 134 135// IsBadParameterError indicates that this error is of BadParameterError type 136func (b *BadParameterError) IsBadParameterError() bool { 137 return true 138} 139 140// IsBadParameter returns whether this error is of BadParameterType 141func IsBadParameter(e error) bool { 142 type bp interface { 143 IsBadParameterError() bool 144 } 145 _, ok := Unwrap(e).(bp) 146 return ok 147} 148 149// NotImplemented returns a new instance of NotImplementedError 150func NotImplemented(message string, args ...interface{}) Error { 151 return WrapWithMessage(&NotImplementedError{ 152 Message: fmt.Sprintf(message, args...), 153 }, message, args...) 154} 155 156// NotImplementedError defines an error condition to describe the result 157// of a call to an unimplemented API 158type NotImplementedError struct { 159 Message string `json:"message"` 160} 161 162// Error returns log friendly description of an error 163func (e *NotImplementedError) Error() string { 164 return e.Message 165} 166 167// OrigError returns original error 168func (e *NotImplementedError) OrigError() error { 169 return e 170} 171 172// IsNotImplementedError indicates that this error is of NotImplementedError type 173func (e *NotImplementedError) IsNotImplementedError() bool { 174 return true 175} 176 177// IsNotImplemented returns whether this error is of NotImplementedError type 178func IsNotImplemented(e error) bool { 179 type ni interface { 180 IsNotImplementedError() bool 181 } 182 err, ok := Unwrap(e).(ni) 183 return ok && err.IsNotImplementedError() 184} 185 186// CompareFailed returns new instance of CompareFailedError 187func CompareFailed(message string, args ...interface{}) Error { 188 return WrapWithMessage(&CompareFailedError{Message: fmt.Sprintf(message, args...)}, message, args...) 189} 190 191// CompareFailedError indicates a failed comparison (e.g. bad password or hash) 192type CompareFailedError struct { 193 // Message is user-friendly error message 194 Message string `json:"message"` 195} 196 197// Error is debug - friendly message 198func (e *CompareFailedError) Error() string { 199 if e.Message != "" { 200 return e.Message 201 } 202 return "compare failed" 203} 204 205// OrigError returns original error (in this case this is the error itself) 206func (e *CompareFailedError) OrigError() error { 207 return e 208} 209 210// IsCompareFailedError indicates that this is CompareFailedError 211func (e *CompareFailedError) IsCompareFailedError() bool { 212 return true 213} 214 215// IsCompareFailed detects if this error is of CompareFailed type 216func IsCompareFailed(e error) bool { 217 type cf interface { 218 IsCompareFailedError() bool 219 } 220 _, ok := Unwrap(e).(cf) 221 return ok 222} 223 224// AccessDenied returns new instance of AccessDeniedError 225func AccessDenied(message string, args ...interface{}) Error { 226 return WrapWithMessage(&AccessDeniedError{ 227 Message: fmt.Sprintf(message, args...), 228 }, message, args...) 229} 230 231// AccessDeniedError indicates denied access 232type AccessDeniedError struct { 233 Message string `json:"message"` 234} 235 236// Error is debug - friendly error message 237func (e *AccessDeniedError) Error() string { 238 if e.Message != "" { 239 return e.Message 240 } 241 return "access denied" 242} 243 244// IsAccessDeniedError indicates that this error is of AccessDeniedError type 245func (e *AccessDeniedError) IsAccessDeniedError() bool { 246 return true 247} 248 249// OrigError returns original error (in this case this is the error itself) 250func (e *AccessDeniedError) OrigError() error { 251 return e 252} 253 254// IsAccessDenied detects if this error is of AccessDeniedError type 255func IsAccessDenied(e error) bool { 256 type ad interface { 257 IsAccessDeniedError() bool 258 } 259 _, ok := Unwrap(e).(ad) 260 return ok 261} 262 263// ConvertSystemError converts system error to appropriate trace error 264// if it is possible, otherwise, returns original error 265func ConvertSystemError(err error) error { 266 innerError := Unwrap(err) 267 268 if os.IsExist(innerError) { 269 return WrapWithMessage(&AlreadyExistsError{Message: innerError.Error()}, innerError.Error()) 270 } 271 if os.IsNotExist(innerError) { 272 return WrapWithMessage(&NotFoundError{Message: innerError.Error()}, innerError.Error()) 273 } 274 if os.IsPermission(innerError) { 275 return WrapWithMessage(&AccessDeniedError{Message: innerError.Error()}, innerError.Error()) 276 } 277 switch realErr := innerError.(type) { 278 case *net.OpError: 279 return WrapWithMessage(&ConnectionProblemError{ 280 Message: realErr.Error(), 281 Err: realErr}, realErr.Error()) 282 case *os.PathError: 283 message := fmt.Sprintf("failed to execute command %v error: %v", realErr.Path, realErr.Err) 284 return WrapWithMessage(&AccessDeniedError{ 285 Message: message, 286 }, message) 287 case x509.SystemRootsError, x509.UnknownAuthorityError: 288 return wrapWithDepth(&TrustError{Err: innerError}, 2) 289 } 290 if _, ok := innerError.(net.Error); ok { 291 return WrapWithMessage(&ConnectionProblemError{ 292 Message: innerError.Error(), 293 Err: innerError}, innerError.Error()) 294 } 295 return err 296} 297 298// ConnectionProblem returns new instance of ConnectionProblemError 299func ConnectionProblem(err error, message string, args ...interface{}) Error { 300 return WrapWithMessage(&ConnectionProblemError{ 301 Message: fmt.Sprintf(message, args...), 302 Err: err, 303 }, message, args...) 304} 305 306// ConnectionProblemError indicates a network related problem 307type ConnectionProblemError struct { 308 Message string `json:"message"` 309 Err error `json:"-"` 310} 311 312// Error is debug - friendly error message 313func (c *ConnectionProblemError) Error() string { 314 if c.Err == nil { 315 return c.Message 316 } 317 return c.Err.Error() 318} 319 320// IsConnectionProblemError indicates that this error is of ConnectionProblemError type 321func (c *ConnectionProblemError) IsConnectionProblemError() bool { 322 return true 323} 324 325// OrigError returns original error (in this case this is the error itself) 326func (c *ConnectionProblemError) OrigError() error { 327 return c 328} 329 330// IsConnectionProblem returns whether this error is of ConnectionProblemError 331func IsConnectionProblem(e error) bool { 332 type ad interface { 333 IsConnectionProblemError() bool 334 } 335 _, ok := Unwrap(e).(ad) 336 return ok 337} 338 339// LimitExceeded returns whether new instance of LimitExceededError 340func LimitExceeded(message string, args ...interface{}) Error { 341 return WrapWithMessage(&LimitExceededError{ 342 Message: fmt.Sprintf(message, args...), 343 }, message, args...) 344} 345 346// LimitExceededError indicates rate limit or connection limit problem 347type LimitExceededError struct { 348 Message string `json:"message"` 349} 350 351// Error is debug - friendly error message 352func (c *LimitExceededError) Error() string { 353 return c.Message 354} 355 356// IsLimitExceededError indicates that this error is of ConnectionProblem 357func (c *LimitExceededError) IsLimitExceededError() bool { 358 return true 359} 360 361// OrigError returns original error (in this case this is the error itself) 362func (c *LimitExceededError) OrigError() error { 363 return c 364} 365 366// IsLimitExceeded detects if this error is of LimitExceededError 367func IsLimitExceeded(e error) bool { 368 type ad interface { 369 IsLimitExceededError() bool 370 } 371 _, ok := Unwrap(e).(ad) 372 return ok 373} 374 375// TrustError indicates trust-related validation error (e.g. untrusted cert) 376type TrustError struct { 377 // Err is original error 378 Err error `json:"-"` 379 Message string `json:"message"` 380} 381 382// Error returns log-friendly error description 383func (t *TrustError) Error() string { 384 return t.Err.Error() 385} 386 387// IsTrustError indicates that this error is of TrustError type 388func (*TrustError) IsTrustError() bool { 389 return true 390} 391 392// OrigError returns original error (in this case this is the error itself) 393func (t *TrustError) OrigError() error { 394 return t 395} 396 397// IsTrustError returns if this is a trust error 398func IsTrustError(e error) bool { 399 type te interface { 400 IsTrustError() bool 401 } 402 _, ok := Unwrap(e).(te) 403 return ok 404} 405 406// OAuth2 returns new instance of OAuth2Error 407func OAuth2(code, message string, query url.Values) Error { 408 return WrapWithMessage(&OAuth2Error{ 409 Code: code, 410 Message: message, 411 Query: query, 412 }, message) 413} 414 415// OAuth2Error defined an error used in OpenID Connect Flow (OIDC) 416type OAuth2Error struct { 417 Code string `json:"code"` 418 Message string `json:"message"` 419 Query url.Values `json:"query"` 420} 421 422//Error returns log friendly description of an error 423func (o *OAuth2Error) Error() string { 424 return fmt.Sprintf("OAuth2 error code=%v, message=%v", o.Code, o.Message) 425} 426 427// IsOAuth2Error returns whether this error of OAuth2Error type 428func (o *OAuth2Error) IsOAuth2Error() bool { 429 return true 430} 431 432// IsOAuth2 returns if this is a OAuth2-related error 433func IsOAuth2(e error) bool { 434 type oe interface { 435 IsOAuth2Error() bool 436 } 437 _, ok := Unwrap(e).(oe) 438 return ok 439} 440 441// IsEOF returns true if the passed error is io.EOF 442func IsEOF(e error) bool { 443 return Unwrap(e) == io.EOF 444} 445 446// Retry return new instance of RetryError which indicates a transient error type 447func Retry(err error, message string, args ...interface{}) Error { 448 return WrapWithMessage(&RetryError{ 449 Message: fmt.Sprintf(message, args...), 450 Err: err, 451 }, message, args...) 452} 453 454// RetryError indicates a transient error type 455type RetryError struct { 456 Message string `json:"message"` 457 Err error `json:"-"` 458} 459 460// Error is debug-friendly error message 461func (c *RetryError) Error() string { 462 if c.Err == nil { 463 return c.Message 464 } 465 return c.Err.Error() 466} 467 468// IsRetryError indicates that this error is of RetryError type 469func (c *RetryError) IsRetryError() bool { 470 return true 471} 472 473// OrigError returns original error (in this case this is the error itself) 474func (c *RetryError) OrigError() error { 475 return c 476} 477 478// IsRetryError returns whether this error is of ConnectionProblemError 479func IsRetryError(e error) bool { 480 type ad interface { 481 IsRetryError() bool 482 } 483 _, ok := Unwrap(e).(ad) 484 return ok 485} 486