github.com/dcarley/cf-cli@v6.24.1-0.20170220111324-4225ff346898+incompatible/api/cloudcontroller/ccv2/errors.go (about) 1 package ccv2 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "net/http" 7 8 "code.cloudfoundry.org/cli/api/cloudcontroller" 9 ) 10 11 // CCErrorResponse represents a generic Cloud Controller V2 error response. 12 type CCErrorResponse struct { 13 Code int `json:"code"` 14 Description string `json:"description"` 15 ErrorCode string `json:"error_code"` 16 } 17 18 // UnexpectedResponseError is returned when the client gets an error that has 19 // not been accounted for. 20 type UnexpectedResponseError struct { 21 CCErrorResponse 22 23 RequestIDs []string 24 ResponseCode int 25 } 26 27 func (e UnexpectedResponseError) Error() string { 28 message := fmt.Sprintf("Unexpected Response\nResponse code: %d\nCC code: %d\nCC error code: %s", e.ResponseCode, e.Code, e.ErrorCode) 29 for _, id := range e.RequestIDs { 30 message = fmt.Sprintf("%s\nRequest ID: %s", message, id) 31 } 32 return fmt.Sprintf("%s\nDescription: %s", message, e.Description) 33 } 34 35 // AppStoppedStatsError is returned when requesting instance information from a 36 // stopped app. 37 type AppStoppedStatsError struct { 38 Message string 39 } 40 41 func (e AppStoppedStatsError) Error() string { 42 return e.Message 43 } 44 45 // NotStagedError is returned when requesting instance information from a 46 // not staged app. 47 type NotStagedError struct { 48 Message string 49 } 50 51 func (e NotStagedError) Error() string { 52 return e.Message 53 } 54 55 // InstancesError is returned when requesting instance information encounters 56 // an error. 57 type InstancesError struct { 58 Message string 59 } 60 61 func (e InstancesError) Error() string { 62 return e.Message 63 } 64 65 // errorWrapper is the wrapper that converts responses with 4xx and 5xx status 66 // codes to an error. 67 type errorWrapper struct { 68 connection cloudcontroller.Connection 69 } 70 71 func newErrorWrapper() *errorWrapper { 72 return new(errorWrapper) 73 } 74 75 // Wrap wraps a Cloud Controller connection in this error handling wrapper. 76 func (e *errorWrapper) Wrap(innerconnection cloudcontroller.Connection) cloudcontroller.Connection { 77 e.connection = innerconnection 78 return e 79 } 80 81 // Make converts RawHTTPStatusError, which represents responses with 4xx and 82 // 5xx status codes, to specific errors. 83 func (e *errorWrapper) Make(request *http.Request, passedResponse *cloudcontroller.Response) error { 84 err := e.connection.Make(request, passedResponse) 85 86 if rawHTTPStatusErr, ok := err.(cloudcontroller.RawHTTPStatusError); ok { 87 return convert(rawHTTPStatusErr) 88 } 89 return err 90 } 91 92 func convert(rawHTTPStatusErr cloudcontroller.RawHTTPStatusError) error { 93 // Try to unmarshal the raw error into a CC error. If unmarshaling fails, 94 // return the raw error. 95 var errorResponse CCErrorResponse 96 err := json.Unmarshal(rawHTTPStatusErr.RawResponse, &errorResponse) 97 if err != nil { 98 if rawHTTPStatusErr.StatusCode == http.StatusNotFound { 99 return cloudcontroller.NotFoundError{Message: string(rawHTTPStatusErr.RawResponse)} 100 } 101 return rawHTTPStatusErr 102 } 103 104 switch rawHTTPStatusErr.StatusCode { 105 case http.StatusBadRequest: // 400 106 return handleBadRequest(errorResponse) 107 case http.StatusUnauthorized: // 401 108 return handleUnauthorized(errorResponse) 109 case http.StatusForbidden: // 403 110 return cloudcontroller.ForbiddenError{Message: errorResponse.Description} 111 case http.StatusNotFound: // 404 112 return cloudcontroller.ResourceNotFoundError{Message: errorResponse.Description} 113 case http.StatusUnprocessableEntity: // 422 114 return cloudcontroller.UnprocessableEntityError{Message: errorResponse.Description} 115 default: 116 return UnexpectedResponseError{ 117 CCErrorResponse: errorResponse, 118 RequestIDs: rawHTTPStatusErr.RequestIDs, 119 ResponseCode: rawHTTPStatusErr.StatusCode, 120 } 121 } 122 return nil 123 } 124 125 func handleBadRequest(errorResponse CCErrorResponse) error { 126 switch errorResponse.ErrorCode { 127 case "CF-AppStoppedStatsError": 128 return AppStoppedStatsError{Message: errorResponse.Description} 129 case "CF-InstancesError": 130 return InstancesError{Message: errorResponse.Description} 131 case "CF-NotStaged": 132 return NotStagedError{Message: errorResponse.Description} 133 default: 134 return cloudcontroller.BadRequestError{Message: errorResponse.Description} 135 } 136 } 137 138 func handleUnauthorized(errorResponse CCErrorResponse) error { 139 if errorResponse.ErrorCode == "CF-InvalidAuthToken" { 140 return cloudcontroller.InvalidAuthTokenError{Message: errorResponse.Description} 141 } 142 143 return cloudcontroller.UnauthorizedError{Message: errorResponse.Description} 144 }