Files
fn-serverless/api/models/error.go
Reed Allman e13a6fd029 death to format (#1281)
* get rid of old format stuff, utils usage, fix up for fdk2.0 interface

* pure agent format removal, TODO remove format field, fix up all tests

* shitter's clogged

* fix agent tests

* start rolling through server tests

* tests compile, some failures

* remove json / content type detection on invoke/httptrigger, fix up tests

* remove hello, fixup system tests

the fucking status checker test just hangs and it's testing that it doesn't
work so the test passes but the test doesn't pass fuck life it's not worth it

* fix migration

* meh

* make dbhelper shut up about dbhelpers not being used

* move fail status at least into main thread, jfc

* fix status call to have FN_LISTENER

also turns off the stdout/stderr blocking between calls, because it's
impossible to debug without that (without syslog), now that stdout and stderr
go to the same place (either to host stderr or nowhere) and isn't used for
function output this shouldn't be a big fuss really

* remove stdin

* cleanup/remind: fixed bug where watcher would leak if container dies first

* silence system-test logs until fail, fix datastore tests

postgres does weird things with constraints when renaming tables, took the
easy way out

system-tests were loud as fuck and made you download a circleci text file of
the logs, made them only yell when they goof

* fix fdk-go dep for test image. fun

* fix swagger and remove test about format

* update all the gopkg files

* add back FN_FORMAT for fdks that assert things. pfft

* add useful error for functions that exit

this error is really confounding because containers can exit for all manner of
reason, we're just guessing that this is the most likely cause for now, and
this error message should very likely change or be removed from the client
path anyway (context.Canceled wasn't all that useful either, but anyway, I'd
been hunting for this... so found it). added a test to avoid being publicly
shamed for 1 line commits (beware...).
2018-10-26 10:43:04 -07:00

226 lines
6.0 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"),
}
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"),
}
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"),
}
// TODO consider removal. see rationale at uses, or remove if none.
ErrContainerExitedEarly = err{
code: http.StatusBadGateway,
error: errors.New("container exited early, 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,
}
}