github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+incompatible/api/cloudcontroller/ccv2/errors.go (about) 1 package ccv2 2 3 import ( 4 "encoding/json" 5 "net/http" 6 7 "code.cloudfoundry.org/cli/api/cloudcontroller" 8 "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" 9 ) 10 11 // errorWrapper is the wrapper that converts responses with 4xx and 5xx status 12 // codes to an error. 13 type errorWrapper struct { 14 connection cloudcontroller.Connection 15 } 16 17 func newErrorWrapper() *errorWrapper { 18 return new(errorWrapper) 19 } 20 21 // Make converts RawHTTPStatusError, which represents responses with 4xx and 22 // 5xx status codes, to specific errors. 23 func (e *errorWrapper) Make(request *cloudcontroller.Request, passedResponse *cloudcontroller.Response) error { 24 err := e.connection.Make(request, passedResponse) 25 26 if rawHTTPStatusErr, ok := err.(ccerror.RawHTTPStatusError); ok { 27 if passedResponse.HTTPResponse.StatusCode >= http.StatusInternalServerError { 28 return convert500(rawHTTPStatusErr) 29 } 30 31 return convert400(rawHTTPStatusErr) 32 } 33 return err 34 } 35 36 // Wrap wraps a Cloud Controller connection in this error handling wrapper. 37 func (e *errorWrapper) Wrap(innerconnection cloudcontroller.Connection) cloudcontroller.Connection { 38 e.connection = innerconnection 39 return e 40 } 41 42 func convert400(rawHTTPStatusErr ccerror.RawHTTPStatusError) error { 43 // Try to unmarshal the raw error into a CC error. If unmarshaling fails, 44 // either we're not talking to a CC, or the CC returned invalid json. 45 errorResponse, err := unmarshalRawHTTPErr(rawHTTPStatusErr) 46 if err != nil { 47 return err 48 } 49 50 switch rawHTTPStatusErr.StatusCode { 51 case http.StatusBadRequest: // 400 52 return handleBadRequest(errorResponse) 53 case http.StatusUnauthorized: // 401 54 return handleUnauthorized(errorResponse) 55 case http.StatusForbidden: // 403 56 return ccerror.ForbiddenError{Message: errorResponse.Description} 57 case http.StatusNotFound: // 404 58 return ccerror.ResourceNotFoundError{Message: errorResponse.Description} 59 case http.StatusUnprocessableEntity: // 422 60 return handleUnprocessableEntity(errorResponse) 61 default: 62 return ccerror.V2UnexpectedResponseError{ 63 RequestIDs: rawHTTPStatusErr.RequestIDs, 64 ResponseCode: rawHTTPStatusErr.StatusCode, 65 V2ErrorResponse: errorResponse, 66 } 67 } 68 } 69 70 func convert500(rawHTTPStatusErr ccerror.RawHTTPStatusError) error { 71 errorResponse, err := unmarshalRawHTTPErr(rawHTTPStatusErr) 72 if err != nil { 73 return err 74 } 75 76 switch rawHTTPStatusErr.StatusCode { 77 case http.StatusBadGateway: // 502 78 return handleBadGateway(errorResponse, rawHTTPStatusErr) 79 default: 80 return v2UnexpectedResponseError(rawHTTPStatusErr) 81 } 82 } 83 84 func handleBadGateway(errorResponse ccerror.V2ErrorResponse, rawHTTPStatusErr ccerror.RawHTTPStatusError) error { 85 switch errorResponse.ErrorCode { 86 case "CF-ServiceBrokerCatalogInvalid": 87 return ccerror.ServiceBrokerCatalogInvalidError{Message: errorResponse.Description} 88 case "CF-ServiceBrokerRequestRejected": 89 return ccerror.ServiceBrokerRequestRejectedError{Message: errorResponse.Description} 90 case "CF-ServiceBrokerBadResponse": 91 return ccerror.ServiceBrokerBadResponseError{Message: errorResponse.Description} 92 default: 93 return v2UnexpectedResponseError(rawHTTPStatusErr) 94 } 95 } 96 97 func handleBadRequest(errorResponse ccerror.V2ErrorResponse) error { 98 switch errorResponse.ErrorCode { 99 case "CF-AppStoppedStatsError": 100 return ccerror.ApplicationStoppedStatsError{Message: errorResponse.Description} 101 case "CF-BuildpackInvalid": 102 return ccerror.BuildpackInvalidError{Message: errorResponse.Description} 103 case "CF-BuildpackNameTaken": 104 return ccerror.BuildpackNameTakenError{Message: errorResponse.Description} 105 case "CF-InstancesError": 106 return ccerror.InstancesError{Message: errorResponse.Description} 107 case "CF-InvalidRelation": 108 return ccerror.InvalidRelationError{Message: errorResponse.Description} 109 case "CF-NotStaged": 110 return ccerror.NotStagedError{Message: errorResponse.Description} 111 case "CF-ServiceBindingAppServiceTaken": 112 return ccerror.ServiceBindingTakenError{Message: errorResponse.Description} 113 case "CF-ServiceKeyNameTaken": 114 return ccerror.ServiceKeyTakenError{Message: errorResponse.Description} 115 case "CF-OrganizationNameTaken": 116 return ccerror.OrganizationNameTakenError{} 117 case "CF-SpaceNameTaken": 118 return ccerror.SpaceNameTakenError{Message: errorResponse.Description} 119 case "CF-ServiceInstanceNameTaken": 120 return ccerror.ServiceInstanceNameTakenError{Message: errorResponse.Description} 121 case "CF-ServicePlanVisibilityAlreadyExists": 122 return ccerror.ServicePlanVisibilityExistsError{Message: errorResponse.Description} 123 default: 124 return ccerror.BadRequestError{Message: errorResponse.Description} 125 } 126 } 127 128 func handleUnauthorized(errorResponse ccerror.V2ErrorResponse) error { 129 if errorResponse.ErrorCode == "CF-InvalidAuthToken" { 130 return ccerror.InvalidAuthTokenError{Message: errorResponse.Description} 131 } 132 133 return ccerror.UnauthorizedError{Message: errorResponse.Description} 134 } 135 136 func handleUnprocessableEntity(errorResponse ccerror.V2ErrorResponse) error { 137 if errorResponse.ErrorCode == "CF-BuildpackNameStackTaken" { 138 return ccerror.BuildpackAlreadyExistsForStackError{Message: errorResponse.Description} 139 } 140 return ccerror.UnprocessableEntityError{Message: errorResponse.Description} 141 } 142 143 func unmarshalRawHTTPErr(rawHTTPStatusErr ccerror.RawHTTPStatusError) (ccerror.V2ErrorResponse, error) { 144 var errorResponse ccerror.V2ErrorResponse 145 err := json.Unmarshal(rawHTTPStatusErr.RawResponse, &errorResponse) 146 if err != nil { 147 // ccv2/info.go converts this error to an APINotFoundError. 148 return ccerror.V2ErrorResponse{}, ccerror.UnknownHTTPSourceError{StatusCode: rawHTTPStatusErr.StatusCode, RawResponse: rawHTTPStatusErr.RawResponse} 149 } 150 return errorResponse, nil 151 } 152 153 func v2UnexpectedResponseError(rawHTTPStatusErr ccerror.RawHTTPStatusError) ccerror.V2UnexpectedResponseError { 154 return ccerror.V2UnexpectedResponseError{ 155 ResponseCode: rawHTTPStatusErr.StatusCode, 156 RequestIDs: rawHTTPStatusErr.RequestIDs, 157 V2ErrorResponse: ccerror.V2ErrorResponse{ 158 Description: string(rawHTTPStatusErr.RawResponse), 159 }, 160 } 161 }