forked from cloudfoundry/cli
-
Notifications
You must be signed in to change notification settings - Fork 0
/
errors.go
110 lines (97 loc) · 3.45 KB
/
errors.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package ccv3
import (
"encoding/json"
"net/http"
"code.cloudfoundry.org/cli/api/cloudcontroller"
"code.cloudfoundry.org/cli/api/cloudcontroller/ccerror"
)
// errorWrapper is the wrapper that converts responses with 4xx and 5xx status
// codes to an error.
type errorWrapper struct {
connection cloudcontroller.Connection
}
func newErrorWrapper() *errorWrapper {
return new(errorWrapper)
}
// Wrap wraps a Cloud Controller connection in this error handling wrapper.
func (e *errorWrapper) Wrap(innerconnection cloudcontroller.Connection) cloudcontroller.Connection {
e.connection = innerconnection
return e
}
// Make creates a connection in the wrapped connection and handles errors
// that it returns.
func (e *errorWrapper) Make(request *cloudcontroller.Request, passedResponse *cloudcontroller.Response) error {
err := e.connection.Make(request, passedResponse)
if rawHTTPStatusErr, ok := err.(ccerror.RawHTTPStatusError); ok {
return convert(rawHTTPStatusErr)
}
return err
}
func convert(rawHTTPStatusErr ccerror.RawHTTPStatusError) error {
// Try to unmarshal the raw error into a CC error. If unmarshaling fails,
// return the raw error.
var errorResponse ccerror.V3ErrorResponse
err := json.Unmarshal(rawHTTPStatusErr.RawResponse, &errorResponse)
// error parsing json
if err != nil {
return ccerror.UnknownHTTPSourceError{StatusCode: rawHTTPStatusErr.StatusCode, RawResponse: rawHTTPStatusErr.RawResponse}
}
errors := errorResponse.Errors
if len(errors) == 0 {
return ccerror.V3UnexpectedResponseError{
ResponseCode: rawHTTPStatusErr.StatusCode,
V3ErrorResponse: errorResponse,
}
}
// There could be multiple errors in the future but for now we only convert
// the first error.
firstErr := errors[0]
switch rawHTTPStatusErr.StatusCode {
case http.StatusUnauthorized: // 401
if firstErr.Title == "CF-InvalidAuthToken" {
return ccerror.InvalidAuthTokenError{Message: firstErr.Detail}
}
return ccerror.UnauthorizedError{Message: firstErr.Detail}
case http.StatusForbidden: // 403
return ccerror.ForbiddenError{Message: firstErr.Detail}
case http.StatusNotFound: // 404
return handleNotFound(firstErr)
case http.StatusUnprocessableEntity: // 422
return handleUnprocessableEntity(firstErr)
case http.StatusServiceUnavailable: // 503
if firstErr.Title == "CF-TaskWorkersUnavailable" {
return ccerror.TaskWorkersUnavailableError{Message: firstErr.Detail}
}
return ccerror.ServiceUnavailableError{Message: firstErr.Detail}
default:
return ccerror.V3UnexpectedResponseError{
ResponseCode: rawHTTPStatusErr.StatusCode,
RequestIDs: rawHTTPStatusErr.RequestIDs,
V3ErrorResponse: errorResponse,
}
}
}
func handleNotFound(errorResponse ccerror.V3Error) error {
switch errorResponse.Detail {
case "App not found":
return ccerror.ApplicationNotFoundError{}
case "Droplet not found":
return ccerror.DropletNotFoundError{}
case "Instance not found":
return ccerror.InstanceNotFoundError{}
case "Process not found":
return ccerror.ProcessNotFoundError{}
default:
return ccerror.ResourceNotFoundError{Message: errorResponse.Detail}
}
}
func handleUnprocessableEntity(errorResponse ccerror.V3Error) error {
switch errorResponse.Detail {
case "name must be unique in space":
return ccerror.NameNotUniqueInSpaceError{}
case "Buildpack must be an existing admin buildpack or a valid git URI":
return ccerror.InvalidBuildpackError{}
default:
return ccerror.UnprocessableEntityError{Message: errorResponse.Detail}
}
}