mirror of
https://github.com/openziti/ziti.git
synced 2026-10-26 05:30:03 +00:00
b6a2d2e951
- adds common/slogbridge, a slog.Handler that emits records as logrus entries at the matching level, with attrs as fields, groups flattened to dotted keys, and the record caller set on the entry so pfxlog attributes each line to the library function that logged it - gates on the logrus level at call time, so the configured level and agent set-log-level apply to library output without mirroring - installs the handler as the root of foundation's logging registry and as the log/slog default, with the registry opened to trace so logrus is the only filter, in the CLI root init and both test package inits - emits fatal and panic records at their own severity; Entry.Log never exits or panics - moves foundation from the v2.0.86 pin to the commit carrying its logging registry, pending the v2.0.102 tag, and drops the replace directives in the root module and zititest - renames errorz.ApiError.Code to AppCode at every site that range requires, in controller/apierror, api_impl, command, internal/routes, model, oidc_auth, raft and response
147 lines
4.7 KiB
Go
147 lines
4.7 KiB
Go
package api_impl
|
|
|
|
import (
|
|
"fmt"
|
|
openApiErrors "github.com/go-openapi/errors"
|
|
"github.com/michaelquigley/pfxlog"
|
|
"github.com/openziti/foundation/v2/errorz"
|
|
"github.com/openziti/ziti/controller/api"
|
|
apierror2 "github.com/openziti/ziti/controller/apierror"
|
|
"github.com/openziti/ziti/controller/rest_model"
|
|
"net/http"
|
|
)
|
|
|
|
// Wrapper for the OpenAPI REST server to allow the the Edge API Error message responses to be used
|
|
func ServeError(rw http.ResponseWriter, r *http.Request, inErr error) {
|
|
if openApiError, ok := inErr.(openApiErrors.Error); ok {
|
|
//openApiErrors from the Open API framework mean that we never hit any of the Edge logic and thus
|
|
//do not have any context established (i.e. no request id)
|
|
var apiError *errorz.ApiError
|
|
if openApiError.Code() == http.StatusUnprocessableEntity {
|
|
// triggered by validation failures and consumer errors
|
|
var newApiError *errorz.ApiError
|
|
|
|
if compositeError, ok := openApiError.(*openApiErrors.CompositeError); ok {
|
|
if len(compositeError.Errors) > 0 {
|
|
//validation errors
|
|
if validationError, ok := compositeError.Errors[0].(*openApiErrors.Validation); ok {
|
|
newApiError = errorz.NewCouldNotValidate(validationError)
|
|
}
|
|
}
|
|
}
|
|
|
|
// only other option is could not parse
|
|
if newApiError == nil {
|
|
newApiError = apierror2.NewCouldNotParseBody(openApiError)
|
|
}
|
|
|
|
apiError = newApiError
|
|
|
|
} else if openApiError.Code() == http.StatusNotFound {
|
|
// handle open API openApiErrors we have existing ApiErrors for
|
|
apiError = errorz.NewNotFound()
|
|
} else if openApiError.Code() == http.StatusMethodNotAllowed {
|
|
apiError = apierror2.NewMethodNotAllowed()
|
|
} else if openApiError.Code() == http.StatusUnauthorized {
|
|
apiError = errorz.NewUnauthorized()
|
|
} else if openApiError.Code() >= 600 && openApiError.Code() < 700 {
|
|
//openapi defines error codes 601+ for validation errors
|
|
apiError = errorz.NewCouldNotValidate(inErr)
|
|
|
|
} else {
|
|
apiError = errorz.NewUnhandled(openApiError)
|
|
}
|
|
apiError.Cause = openApiError
|
|
|
|
NewRequestContext(rw, r).RespondWithApiError(apiError)
|
|
return
|
|
}
|
|
|
|
requestContext, err := api.GetRequestContextFromHttpContext(r)
|
|
if requestContext == nil || err != nil {
|
|
pfxlog.Logger().WithError(err).Error("failed to retrieve request context")
|
|
requestContext = NewRequestContext(rw, r)
|
|
}
|
|
|
|
requestContext.RespondWithError(inErr)
|
|
}
|
|
|
|
func ToRestModel(e *errorz.ApiError, requestId string) *rest_model.APIError {
|
|
ret := &rest_model.APIError{
|
|
Args: nil,
|
|
Code: e.AppCode,
|
|
Message: e.Message,
|
|
RequestID: requestId,
|
|
}
|
|
|
|
if e.Cause != nil {
|
|
|
|
//unwrap first error in composite error
|
|
compositeErr, ok := e.Cause.(*openApiErrors.CompositeError)
|
|
for ok {
|
|
e.Cause = compositeErr.Errors[0]
|
|
compositeErr, ok = e.Cause.(*openApiErrors.CompositeError)
|
|
}
|
|
|
|
if causeApiError, ok := e.Cause.(*errorz.ApiError); ok {
|
|
//standard apierror
|
|
ret.Cause = &rest_model.APIErrorCause{
|
|
APIError: *ToRestModel(causeApiError, requestId),
|
|
}
|
|
} else if causeJsonSchemaError, ok := e.Cause.(*apierror2.ValidationErrors); ok {
|
|
//only possible from config type JSON schema validation
|
|
ret.Cause = &rest_model.APIErrorCause{
|
|
APIFieldError: rest_model.APIFieldError{
|
|
Field: causeJsonSchemaError.Errors[0].Field,
|
|
Reason: causeJsonSchemaError.Errors[0].Error(),
|
|
Value: fmt.Sprintf("%v", causeJsonSchemaError.Errors[0].Value),
|
|
},
|
|
}
|
|
} else if causeFieldErr, ok := e.Cause.(*errorz.FieldError); ok {
|
|
//authenticator modules and enrollment only
|
|
//todo: see if we can remove this by not using FieldError
|
|
ret.Cause = &rest_model.APIErrorCause{
|
|
APIFieldError: rest_model.APIFieldError{
|
|
Field: causeFieldErr.FieldName,
|
|
Value: fmt.Sprintf("%v", causeFieldErr.FieldValue),
|
|
Reason: causeFieldErr.Reason,
|
|
},
|
|
}
|
|
if ret.Code == errorz.InvalidFieldCode {
|
|
ret.Code = errorz.CouldNotValidateCode
|
|
ret.Message = errorz.CouldNotValidateMessage
|
|
}
|
|
|
|
} else if causeFieldErr, ok := e.Cause.(*openApiErrors.Validation); ok {
|
|
//open api validation errors
|
|
ret.Cause = &rest_model.APIErrorCause{
|
|
APIFieldError: rest_model.APIFieldError{
|
|
Field: causeFieldErr.Name,
|
|
Reason: causeFieldErr.Error(),
|
|
Value: fmt.Sprintf("%v", causeFieldErr.Value),
|
|
},
|
|
}
|
|
ret.Code = errorz.CouldNotValidateCode
|
|
ret.Message = errorz.CouldNotValidateMessage
|
|
|
|
} else if genericErr, ok := e.Cause.(*apierror2.GenericCauseError); ok {
|
|
ret.Cause = &rest_model.APIErrorCause{
|
|
APIError: rest_model.APIError{
|
|
Data: genericErr.DataMap,
|
|
Message: genericErr.Error(),
|
|
},
|
|
}
|
|
} else {
|
|
ret.Cause = &rest_model.APIErrorCause{
|
|
APIError: rest_model.APIError{
|
|
Code: errorz.UnhandledCode,
|
|
Message: e.Cause.Error(),
|
|
},
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return ret
|
|
}
|