forked from cloudfoundry/cli
/
errors.go
105 lines (91 loc) · 3.62 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
package ccv2
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)
}
// Make converts RawHTTPStatusError, which represents responses with 4xx and
// 5xx status codes, to specific errors.
func (e *errorWrapper) Make(request *cloudcontroller.Request, passedResponse *cloudcontroller.Response) error {
err := e.connection.Make(request, passedResponse)
if rawHTTPStatusErr, ok := err.(ccerror.RawHTTPStatusError); ok {
if passedResponse.HTTPResponse.StatusCode >= http.StatusInternalServerError {
return convert500(rawHTTPStatusErr)
}
return convert400(rawHTTPStatusErr)
}
return err
}
// 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
}
func convert400(rawHTTPStatusErr ccerror.RawHTTPStatusError) error {
// Try to unmarshal the raw error into a CC error. If unmarshaling fails,
// either we're not talking to a CC, or the CC returned invalid json.
var errorResponse ccerror.V2ErrorResponse
err := json.Unmarshal(rawHTTPStatusErr.RawResponse, &errorResponse)
if err != nil {
// ccv2/info.go converts this error to an APINotFoundError.
return ccerror.UnknownHTTPSourceError{StatusCode: rawHTTPStatusErr.StatusCode, RawResponse: rawHTTPStatusErr.RawResponse}
}
switch rawHTTPStatusErr.StatusCode {
case http.StatusBadRequest: // 400
return handleBadRequest(errorResponse)
case http.StatusUnauthorized: // 401
return handleUnauthorized(errorResponse)
case http.StatusForbidden: // 403
return ccerror.ForbiddenError{Message: errorResponse.Description}
case http.StatusNotFound: // 404
return ccerror.ResourceNotFoundError{Message: errorResponse.Description}
case http.StatusUnprocessableEntity: // 422
return ccerror.UnprocessableEntityError{Message: errorResponse.Description}
default:
return ccerror.V2UnexpectedResponseError{
RequestIDs: rawHTTPStatusErr.RequestIDs,
ResponseCode: rawHTTPStatusErr.StatusCode,
V2ErrorResponse: errorResponse,
}
}
}
func convert500(rawHTTPStatusErr ccerror.RawHTTPStatusError) error {
return ccerror.V2UnexpectedResponseError{
ResponseCode: rawHTTPStatusErr.StatusCode,
RequestIDs: rawHTTPStatusErr.RequestIDs,
V2ErrorResponse: ccerror.V2ErrorResponse{
Description: string(rawHTTPStatusErr.RawResponse),
},
}
}
func handleBadRequest(errorResponse ccerror.V2ErrorResponse) error {
switch errorResponse.ErrorCode {
case "CF-AppStoppedStatsError":
return ccerror.ApplicationStoppedStatsError{Message: errorResponse.Description}
case "CF-InstancesError":
return ccerror.InstancesError{Message: errorResponse.Description}
case "CF-InvalidRelation":
return ccerror.InvalidRelationError{Message: errorResponse.Description}
case "CF-NotStaged":
return ccerror.NotStagedError{Message: errorResponse.Description}
case "CF-ServiceBindingAppServiceTaken":
return ccerror.ServiceBindingTakenError{Message: errorResponse.Description}
default:
return ccerror.BadRequestError{Message: errorResponse.Description}
}
}
func handleUnauthorized(errorResponse ccerror.V2ErrorResponse) error {
if errorResponse.ErrorCode == "CF-InvalidAuthToken" {
return ccerror.InvalidAuthTokenError{Message: errorResponse.Description}
}
return ccerror.UnauthorizedError{Message: errorResponse.Description}
}