Files
fn-serverless/api/models/error.go
Tolga Ceylan 6eaf1578e6 fn: container initialization monitoring (#1288)
Container initialization phase consumes resource tracker
resources (token), during lengthy operations.
In order for agent stability/liveness, this phase has
to be evictable/cancelable and time bounded.

With this change, introducing a new system wide environment setting
to bound the time spent in container initialization phase. This phase
includes docker-pull, docker-create, docker-attach, docker-start
and UDS wait operations. This initialization period is also now
considered evictable.
2018-11-15 13:37:43 -08:00

245 lines
6.6 KiB
Go

package models
import (
"errors"
"fmt"
"net/http"
)
// TODO we can put constants all in this file too
const (
maxAppName = 30
maxFnName = 30
MaxTriggerName = 30
)
var (
ErrInvalidJSON = err{
code: http.StatusBadRequest,
error: errors.New("Invalid JSON"),
}
ErrClientCancel = err{
// The special custom error code to close connection without any response
code: 444,
error: errors.New("Client cancelled context"),
}
ErrCallTimeout = err{
code: http.StatusGatewayTimeout,
error: errors.New("Timed out"),
}
ErrCallTimeoutServerBusy = err{
code: http.StatusServiceUnavailable,
error: errors.New("Timed out - server too busy"),
}
ErrDockerPullTimeout = err{
code: http.StatusServiceUnavailable,
error: errors.New("Docker pull timed out"),
}
ErrContainerInitTimeout = err{
code: http.StatusServiceUnavailable,
error: errors.New("Container initialization timed out, please ensure you are using the latest fdk / format and check the logs"),
}
ErrUnsupportedMediaType = err{
code: http.StatusUnsupportedMediaType,
error: errors.New("Content Type not supported")}
ErrMissingID = err{
code: http.StatusBadRequest,
error: errors.New("Missing ID")}
ErrMissingAppID = err{
code: http.StatusBadRequest,
error: errors.New("Missing App ID")}
ErrMissingFnID = err{
code: http.StatusBadRequest,
error: errors.New("Missing Fn ID")}
ErrMissingName = err{
code: http.StatusBadRequest,
error: errors.New("Missing Name")}
ErrCreatedAtProvided = err{
code: http.StatusBadRequest,
error: errors.New("Trigger Created At Provided for Create")}
ErrUpdatedAtProvided = err{
code: http.StatusBadRequest,
error: errors.New("Trigger ID Provided for Create")}
ErrDatastoreEmptyApp = err{
code: http.StatusBadRequest,
error: errors.New("Missing app"),
}
ErrDatastoreEmptyCallID = err{
code: http.StatusBadRequest,
error: errors.New("Missing call ID"),
}
ErrDatastoreEmptyFn = err{
code: http.StatusBadRequest,
error: errors.New("Missing Fn"),
}
ErrDatastoreEmptyFnID = err{
code: http.StatusBadRequest,
error: errors.New("Missing Fn ID"),
}
ErrInvalidPayload = err{
code: http.StatusBadRequest,
error: errors.New("Invalid payload"),
}
ErrFoundDynamicURL = err{
code: http.StatusBadRequest,
error: errors.New("Dynamic URL is not allowed"),
}
ErrPathMalformed = err{
code: http.StatusBadRequest,
error: errors.New("Path malformed"),
}
ErrInvalidToTime = err{
code: http.StatusBadRequest,
error: errors.New("to_time is not an epoch time"),
}
ErrInvalidFromTime = err{
code: http.StatusBadRequest,
error: errors.New("from_time is not an epoch time"),
}
ErrInvalidMemory = err{
code: http.StatusBadRequest,
error: fmt.Errorf("memory value is out of range. It should be between 0 and %d", MaxMemory),
}
ErrCallResourceTooBig = err{
code: http.StatusBadRequest,
error: fmt.Errorf("Requested CPU/Memory cannot be allocated"),
}
ErrCallNotFound = err{
code: http.StatusNotFound,
error: errors.New("Call not found"),
}
ErrInvalidCPUs = err{
code: http.StatusBadRequest,
error: fmt.Errorf("Cpus is invalid. Value should be either between [%.3f and %.3f] or [%dm and %dm] milliCPU units",
float64(MinMilliCPUs)/1000.0, float64(MaxMilliCPUs)/1000.0, MinMilliCPUs, MaxMilliCPUs),
}
ErrCallLogNotFound = err{
code: http.StatusNotFound,
error: errors.New("Call log not found"),
}
ErrPathNotFound = err{
code: http.StatusNotFound,
error: errors.New("Path not found"),
}
ErrFunctionResponseTooBig = err{
code: http.StatusBadGateway,
error: fmt.Errorf("function response too large"),
}
ErrFunctionResponse = err{
code: http.StatusBadGateway,
error: fmt.Errorf("error receiving function response"),
}
ErrRequestContentTooBig = err{
code: http.StatusRequestEntityTooLarge,
error: fmt.Errorf("Request content too large"),
}
ErrInvalidAnnotationKey = err{
code: http.StatusBadRequest,
error: errors.New("Invalid annotation key, annotation keys must be non-empty ascii strings excluding whitespace"),
}
ErrInvalidAnnotationKeyLength = err{
code: http.StatusBadRequest,
error: fmt.Errorf("Invalid annotation key length, annotation keys may not be larger than %d bytes", maxAnnotationKeyBytes),
}
ErrInvalidAnnotationValue = err{
code: http.StatusBadRequest,
error: errors.New("Invalid annotation value, annotation values may only be non-empty strings, numbers, objects, or arrays"),
}
ErrInvalidAnnotationValueLength = err{
code: http.StatusBadRequest,
error: fmt.Errorf("Invalid annotation value length, annotation values may not be larger than %d bytes when serialized as JSON", maxAnnotationValueBytes),
}
ErrTooManyAnnotationKeys = err{
code: http.StatusBadRequest,
error: fmt.Errorf("Invalid annotation change, new key(s) exceed maximum permitted number of annotations keys (%d)", maxAnnotationsKeys),
}
ErrTooManyRequests = err{
code: http.StatusTooManyRequests,
error: errors.New("Too many requests submitted"),
}
ErrAsyncUnsupported = err{
code: http.StatusBadRequest,
error: errors.New("Async functions are not supported on this server"),
}
ErrDetachUnsupported = err{
code: http.StatusNotImplemented,
error: errors.New("Detach call functions are not supported on this server"),
}
ErrCallHandlerNotFound = err{
code: http.StatusInternalServerError,
error: errors.New("Unable to find the call handle"),
}
ErrContainerInitFail = err{
code: http.StatusBadGateway,
error: errors.New("container failed to initialize, please ensure you are using the latest fdk / format and check the logs"),
}
)
// APIError any error that implements this interface will return an API response
// with the provided status code and error message body
type APIError interface {
Code() int
error
}
type err struct {
code int
error
}
func (e err) Code() int { return e.code }
func NewAPIError(code int, e error) APIError { return err{code, e} }
func IsAPIError(e error) bool {
_, ok := e.(APIError)
return ok
}
func GetAPIErrorCode(e error) int {
err, ok := e.(APIError)
if ok {
return err.Code()
}
return 0
}
// ErrorWrapper uniform error output (v1) only
type ErrorWrapper struct {
Error *Error `json:"error,omitempty"`
}
func (m *ErrorWrapper) Validate() error {
return nil
}
// APIErrorWrapper wraps an error with an APIError such that the APIError
// governs the HTTP response but the root error remains accessible.
type APIErrorWrapper interface {
APIError
RootError() error
}
type apiErrorWrapper struct {
APIError
root error
}
func (w apiErrorWrapper) RootError() error {
return w.root
}
func NewAPIErrorWrapper(apiErr APIError, rootErr error) APIErrorWrapper {
return &apiErrorWrapper{
APIError: apiErr,
root: rootErr,
}
}