// transformUnstructuredResponseError handles an error from the server that is not in a structured form. // It is expected to transform any response that is not recognizable as a clear server sent error from the // K8S API using the information provided with the request. In practice, HTTP proxies and client libraries // introduce a level of uncertainty to the responses returned by servers that in common use result in // unexpected responses. The rough structure is: // // 1. Assume the server sends you something sane - JSON + well defined error objects + proper codes // - this is the happy path // - when you get this output, trust what the server sends // 2. Guard against empty fields / bodies in received JSON and attempt to cull sufficient info from them to // generate a reasonable facsimile of the original failure. // - Be sure to use a distinct error type or flag that allows a client to distinguish between this and error 1 above // 3. Handle true disconnect failures / completely malformed data by moving up to a more generic client error // 4. Distinguish between various connection failures like SSL certificates, timeouts, proxy errors, unexpected // initial contact, the presence of mismatched body contents from posted content types // - Give these a separate distinct error type and capture as much as possible of the original message // // TODO: introduce transformation of generic http.Client.Do() errors that separates 4. func (r *Request) transformUnstructuredResponseError(resp *http.Response, req *http.Request, body []byte) error { if body == nil && resp.Body != nil { if data, err := ioutil.ReadAll(resp.Body); err == nil { body = data } } message := "unknown" if isTextResponse(resp) { message = strings.TrimSpace(string(body)) } retryAfter, _ := retryAfterSeconds(resp) return errors.NewGenericServerResponse(resp.StatusCode, req.Method, r.resource, r.resourceName, message, retryAfter, true) }
func serviceErrorHandler(requestResolver *APIRequestInfoResolver, apiVersions []string, serviceErr restful.ServiceError, request *restful.Request, response *restful.Response) { requestInfo, err := requestResolver.GetAPIRequestInfo(request.Request) codec := latest.Codec if err == nil && requestInfo.APIVersion != "" { // check if the api version is valid. for _, version := range apiVersions { if requestInfo.APIVersion == version { // valid api version. codec = runtime.CodecFor(api.Scheme, requestInfo.APIVersion) break } } } errorJSON(apierrors.NewGenericServerResponse(serviceErr.Code, "", "", "", "", 0, false), codec, response.ResponseWriter) }