mirror of https://github.com/k3s-io/k3s
Updated documentation and adjusted field names
parent
524f8731b5
commit
aa44d29d10
|
@ -232,6 +232,8 @@ TODO: Plugins, extensions, nested kinds, headers
|
|||
HTTP Status codes
|
||||
-----------------
|
||||
|
||||
The server will respond with HTTP status codes that match the HTTP spec. See the section below for a breakdown of the types of status codes the server will send.
|
||||
|
||||
The following HTTP status codes may be returned by the API.
|
||||
|
||||
#### Success codes
|
||||
|
@ -253,6 +255,11 @@ The following HTTP status codes may be returned by the API.
|
|||
* Indicates the requested is invalid.
|
||||
* Suggested client recovery behavior:
|
||||
* Do not retry. Fix the request.
|
||||
* `401 StatusUnauthorized`
|
||||
* Indicates that the server can be reached and understood the request, but refuses to take any further action, because the client must provide authorization. If the client has provided authorization, the server is indicating the provided authorization is unsuitable or invalid.
|
||||
* Suggested client recovery behavior
|
||||
* If the user has not supplied authorization information, prompt them for the appropriate credentials
|
||||
* If the user has supplied authorization information, inform them their credentials were rejected and optionally prompt them again.
|
||||
* `403 StatusForbidden`
|
||||
* Indicates that the server can be reached and understood the request, but refuses to take any further action, because it is configured to deny access for some reason to the requested resource by the client.
|
||||
* Suggested client recovery behavior
|
||||
|
@ -295,7 +302,7 @@ The following HTTP status codes may be returned by the API.
|
|||
* Increase the value of the timeout param and retry with exponential backoff
|
||||
|
||||
Response Status Kind
|
||||
---------------------
|
||||
--------------------
|
||||
|
||||
Kubernetes will always return the ```Status``` kind from any API endpoint when an error occurs.
|
||||
Clients SHOULD handle these types of objects when appropriate.
|
||||
|
@ -304,7 +311,7 @@ A ```Status``` kind will be returned by the API in two cases:
|
|||
* When an operation is not successful (i.e. when the server would return a non 2xx HTTP status code).
|
||||
* When a HTTP ```DELETE``` call is successful.
|
||||
|
||||
The status object is encoded as JSON and provided as the body of the response. The status object contains fields for humans and machine consumers of the API to get more detailed information for the cause of the failure. The information in the status object supplements, but does not override, the HTTP status code's meaning.
|
||||
The status object is encoded as JSON and provided as the body of the response. The status object contains fields for humans and machine consumers of the API to get more detailed information for the cause of the failure. The information in the status object supplements, but does not override, the HTTP status code's meaning. When fields in the status object have the same meaning as generally defined HTTP headers and that header is returned with the response, the header should be considered as having higher priority.
|
||||
|
||||
**Example:**
|
||||
```JSON
|
||||
|
@ -341,6 +348,19 @@ Content-Length: 144
|
|||
```details``` may contain extended data associated with the reason. Each reason may define its own extended details. This field is optional and the data returned is not guaranteed to conform to any schema except that defined by the reason type.
|
||||
|
||||
Possible values for the ```reason``` and ```details``` fields:
|
||||
* `BadRequest`
|
||||
* Indicates that the request itself was invalid, because the request doesn't make any sense, for example deleting a read-only object.
|
||||
* This is different than `status reason` `Invalid` above which indicates that the API call could possibly succeed, but the data was invalid.
|
||||
* API calls that return BadRequest can never succeed.
|
||||
* Http status code: `400 StatusBadRequest`
|
||||
* `Unauthorized`
|
||||
* Indicates that the server can be reached and understood the request, but refuses to take any further action without the client providing appropriate authorization. If the client has provided authorization, this error indicates the provided credentials are insufficient or invalid.
|
||||
* Details (optional):
|
||||
* `kind string`
|
||||
* The kind attribute of the unauthorized resource (on some operations may differ from the requested resource).
|
||||
* `id string`
|
||||
* The identifier of the unauthorized resource.
|
||||
* HTTP status code: `401 StatusUnauthorized`
|
||||
* `Forbidden`
|
||||
* Indicates that the server can be reached and understood the request, but refuses to take any further action, because it is configured to deny access for some reason to the requested resource by the client.
|
||||
* Details (optional):
|
||||
|
@ -378,6 +398,10 @@ Possible values for the ```reason``` and ```details``` fields:
|
|||
* `causes`
|
||||
* One or more `StatusCause` entries indicating the data in the provided resource that was invalid. The `reason`, `message`, and `field` attributes will be set.
|
||||
* HTTP status code: `422 StatusUnprocessableEntity`
|
||||
* `Timeout`
|
||||
* Indicates that the request could not be completed within the given time. Clients may receive this response if the server has decided to rate limit the client, or if the server is overloaded and cannot process the request at this time.
|
||||
* Http status code: `429 TooManyRequests`
|
||||
* The server should set the `Retry-After` HTTP header and return `retryAfterSeconds` in the details field of the object. A value of `0` is the default.
|
||||
* `ServerTimeout`
|
||||
* Indicates that the server can be reached and understood the request, but cannot complete the action in a reasonable time. This maybe due to temporary server load or a transient communication issue with another server.
|
||||
* Details (optional):
|
||||
|
@ -385,15 +409,8 @@ Possible values for the ```reason``` and ```details``` fields:
|
|||
* The kind attribute of the resource being acted on.
|
||||
* `id string`
|
||||
* The operation that is being attempted.
|
||||
* Http status code: `500 StatusInternalServerError`
|
||||
* `Timeout`
|
||||
* Indicates that the request could not be completed within the given time. Clients can get this response ONLY when they specified a timeout param in the request. The request might succeed with an increased value of timeout param.
|
||||
* The server should set the `Retry-After` HTTP header and return `retryAfterSeconds` in the details field of the object. A value of `0` is the default.
|
||||
* Http status code: `504 StatusServerTimeout`
|
||||
* `BadRequest`
|
||||
* Indicates that the request itself was invalid, because the request doesn't make any sense, for example deleting a read-only object.
|
||||
* This is different than `status reason` `Invalid` above which indicates that the API call could possibly succeed, but the data was invalid.
|
||||
* API calls that return BadRequest can never succeed.
|
||||
* Http status code: `400 StatusBadRequest`
|
||||
* `MethodNotAllowed`
|
||||
* Indicates that that the action the client attempted to perform on the resource was not supported by the code.
|
||||
* For instance, attempting to delete a resource that can only be created.
|
||||
|
|
|
@ -198,15 +198,15 @@ func NewMethodNotSupported(kind, action string) error {
|
|||
|
||||
// NewServerTimeout returns an error indicating the requested action could not be completed due to a
|
||||
// transient error, and the client should try again.
|
||||
func NewServerTimeout(kind, operation string, retryAfter int) error {
|
||||
func NewServerTimeout(kind, operation string, retryAfterSeconds int) error {
|
||||
return &StatusError{api.Status{
|
||||
Status: api.StatusFailure,
|
||||
Code: http.StatusInternalServerError,
|
||||
Reason: api.StatusReasonServerTimeout,
|
||||
Details: &api.StatusDetails{
|
||||
Kind: kind,
|
||||
ID: operation,
|
||||
RetryAfter: retryAfter,
|
||||
Kind: kind,
|
||||
ID: operation,
|
||||
RetryAfterSeconds: retryAfterSeconds,
|
||||
},
|
||||
Message: fmt.Sprintf("The %s operation against %s could not be completed at this time, please try again.", operation, kind),
|
||||
}}
|
||||
|
@ -227,14 +227,14 @@ func NewInternalError(err error) error {
|
|||
|
||||
// NewTimeoutError returns an error indicating that a timeout occurred before the request
|
||||
// could be completed. Clients may retry, but the operation may still complete.
|
||||
func NewTimeoutError(message string, retryAfter int) error {
|
||||
func NewTimeoutError(message string, retryAfterSeconds int) error {
|
||||
return &StatusError{api.Status{
|
||||
Status: api.StatusFailure,
|
||||
Code: StatusServerTimeout,
|
||||
Reason: api.StatusReasonTimeout,
|
||||
Message: fmt.Sprintf("Timeout: %s", message),
|
||||
Details: &api.StatusDetails{
|
||||
RetryAfter: retryAfter,
|
||||
RetryAfterSeconds: retryAfterSeconds,
|
||||
},
|
||||
}}
|
||||
}
|
||||
|
@ -308,7 +308,7 @@ func SuggestsClientDelay(err error) (int, bool) {
|
|||
if t.Status().Details != nil {
|
||||
switch t.Status().Reason {
|
||||
case api.StatusReasonServerTimeout, api.StatusReasonTimeout:
|
||||
return t.Status().Details.RetryAfter, true
|
||||
return t.Status().Details.RetryAfterSeconds, true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1201,7 +1201,7 @@ type StatusDetails struct {
|
|||
// failure. Not all StatusReasons may provide detailed causes.
|
||||
Causes []StatusCause `json:"causes,omitempty"`
|
||||
// If specified, the time in seconds before the operation should be retried.
|
||||
RetryAfter int `json:"retryAfter,omitempty"`
|
||||
RetryAfterSeconds int `json:"retryAfterSeconds,omitempty"`
|
||||
}
|
||||
|
||||
// Values of Status.Status
|
||||
|
@ -1285,7 +1285,7 @@ const (
|
|||
// Details (optional):
|
||||
// "kind" string - the kind attribute of the resource being acted on.
|
||||
// "id" string - the operation that is being attempted.
|
||||
// "retryAfter" int - the number of seconds before the operation should be retried
|
||||
// "retryAfterSeconds" int - the number of seconds before the operation should be retried
|
||||
// Status code 500
|
||||
StatusReasonServerTimeout StatusReason = "ServerTimeout"
|
||||
|
||||
|
@ -1293,9 +1293,9 @@ const (
|
|||
// Clients can get this response only when they specified a timeout param in the request,
|
||||
// or if the server cannot complete the operation within a reasonable amount of time.
|
||||
// The request might succeed with an increased value of timeout param. The client *should*
|
||||
// wait at least the number of seconds specified by the retryAfter field.
|
||||
// wait at least the number of seconds specified by the retryAfterSeconds field.
|
||||
// Details (optional):
|
||||
// "retryAfter" int - the number of seconds before the operation should be retried
|
||||
// "retryAfterSeconds" int - the number of seconds before the operation should be retried
|
||||
// Status code 504
|
||||
StatusReasonTimeout StatusReason = "Timeout"
|
||||
|
||||
|
|
|
@ -1015,7 +1015,7 @@ type StatusDetails struct {
|
|||
// failure. Not all StatusReasons may provide detailed causes.
|
||||
Causes []StatusCause `json:"causes,omitempty" description:"the Causes array includes more details associated with the StatusReason failure; not all StatusReasons may provide detailed causes"`
|
||||
// If specified, the time in seconds before the operation should be retried.
|
||||
RetryAfter int `json:"retryAfter,omitempty" description:"the number of seconds before the client should attempt to retry this operation"`
|
||||
RetryAfterSeconds int `json:"retryAfterSeconds,omitempty" description:"the number of seconds before the client should attempt to retry this operation"`
|
||||
}
|
||||
|
||||
// Values of Status.Status
|
||||
|
|
|
@ -1029,7 +1029,7 @@ type StatusDetails struct {
|
|||
// failure. Not all StatusReasons may provide detailed causes.
|
||||
Causes []StatusCause `json:"causes,omitempty" description:"the Causes array includes more details associated with the StatusReason failure; not all StatusReasons may provide detailed causes"`
|
||||
// If specified, the time in seconds before the operation should be retried.
|
||||
RetryAfter int `json:"retryAfter,omitempty" description:"the number of seconds before the client should attempt to retry this operation"`
|
||||
RetryAfterSeconds int `json:"retryAfterSeconds,omitempty" description:"the number of seconds before the client should attempt to retry this operation"`
|
||||
}
|
||||
|
||||
// Values of Status.Status
|
||||
|
|
|
@ -1188,7 +1188,7 @@ type StatusDetails struct {
|
|||
// failure. Not all StatusReasons may provide detailed causes.
|
||||
Causes []StatusCause `json:"causes,omitempty" description:"the Causes array includes more details associated with the StatusReason failure; not all StatusReasons may provide detailed causes"`
|
||||
// If specified, the time in seconds before the operation should be retried.
|
||||
RetryAfter int `json:"retryAfter,omitempty" description:"the number of seconds before the client should attempt to retry this operation"`
|
||||
RetryAfterSeconds int `json:"retryAfterSeconds,omitempty" description:"the number of seconds before the client should attempt to retry this operation"`
|
||||
}
|
||||
|
||||
// Values of Status.Status
|
||||
|
|
|
@ -645,6 +645,24 @@ func (r *Request) transformResponse(resp *http.Response, req *http.Request, body
|
|||
}
|
||||
|
||||
// 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 further levels of refinement that allow a client to distinguish between 1 and 2-3.
|
||||
// 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 {
|
||||
|
@ -679,11 +697,11 @@ func (r *Request) transformUnstructuredResponseError(resp *http.Response, req *h
|
|||
case errors.StatusUnprocessableEntity:
|
||||
err = errors.NewInvalid(r.resource, r.resourceName, nil)
|
||||
case errors.StatusServerTimeout:
|
||||
retryAfter, _ := retryAfter(resp)
|
||||
err = errors.NewServerTimeout(r.resource, r.verb, retryAfter)
|
||||
retryAfterSeconds, _ := retryAfterSeconds(resp)
|
||||
err = errors.NewServerTimeout(r.resource, r.verb, retryAfterSeconds)
|
||||
case errors.StatusTooManyRequests:
|
||||
retryAfter, _ := retryAfter(resp)
|
||||
err = errors.NewServerTimeout(r.resource, r.verb, retryAfter)
|
||||
retryAfterSeconds, _ := retryAfterSeconds(resp)
|
||||
err = errors.NewServerTimeout(r.resource, r.verb, retryAfterSeconds)
|
||||
case http.StatusInternalServerError:
|
||||
err = errors.NewInternalError(fmt.Errorf(message))
|
||||
}
|
||||
|
@ -703,9 +721,9 @@ func isTextResponse(resp *http.Response) bool {
|
|||
return strings.HasPrefix(media, "text/")
|
||||
}
|
||||
|
||||
// retryAfter returns the value of the Retry-After header and true, or 0 and false if
|
||||
// retryAfterSeconds returns the value of the Retry-After header and true, or 0 and false if
|
||||
// the header was missing or not a valid number.
|
||||
func retryAfter(resp *http.Response) (int, bool) {
|
||||
func retryAfterSeconds(resp *http.Response) (int, bool) {
|
||||
if h := resp.Header.Get("Retry-After"); len(h) > 0 {
|
||||
if i, err := strconv.Atoi(h); err == nil {
|
||||
return i, true
|
||||
|
|
Loading…
Reference in New Issue