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