diff --git a/api/actions/app_logs.go b/api/actions/app_logs.go index 7abe808c6..753a56cab 100644 --- a/api/actions/app_logs.go +++ b/api/actions/app_logs.go @@ -33,20 +33,17 @@ func (a *AppLogs) Read(ctx context.Context, logger logr.Logger, authInfo authori app, err := a.appRepo.GetApp(ctx, authInfo, appGUID) if err != nil { - logger.Error(err, "Failed to fetch app from Kubernetes", "AppGUID", appGUID) - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "Failed to fetch app from Kubernetes", "AppGUID", appGUID) } build, err := a.buildRepo.GetLatestBuildByAppGUID(ctx, authInfo, app.SpaceGUID, appGUID) if err != nil { - logger.Error(err, "Failed to fetch latest app CFBuild from Kubernetes", "AppGUID", appGUID) - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "Failed to fetch latest app CFBuild from Kubernetes", "AppGUID", appGUID) } buildLogs, err := a.buildRepo.GetBuildLogs(ctx, authInfo, app.SpaceGUID, build.GUID) if err != nil { - logger.Error(err, "Failed to fetch build logs", "AppGUID", appGUID, "BuildGUID", build.GUID) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to fetch build logs", "AppGUID", appGUID, "BuildGUID", build.GUID) } logLimit := int64(defaultLogLimit) @@ -61,8 +58,7 @@ func (a *AppLogs) Read(ctx context.Context, logger logr.Logger, authInfo authori Limit: logLimit, }) if err != nil { - logger.Error(err, "Failed to fetch app runtime logs from Kubernetes", "AppGUID", appGUID) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to fetch app runtime logs from Kubernetes", "AppGUID", appGUID) } logs := append(buildLogs, runtimeLogs...) diff --git a/api/handlers/app_handler.go b/api/handlers/app_handler.go index e0fd00e31..586dc3472 100644 --- a/api/handlers/app_handler.go +++ b/api/handlers/app_handler.go @@ -98,8 +98,7 @@ func (h *AppHandler) appGetHandler(ctx context.Context, logger logr.Logger, auth app, err := h.appRepo.GetApp(ctx, authInfo, appGUID) if err != nil { - logger.Error(err, "Failed to fetch app from Kubernetes", "AppGUID", appGUID) - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "Failed to fetch app from Kubernetes", "AppGUID", appGUID) } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForApp(app, h.serverURL)), nil } @@ -108,20 +107,22 @@ func (h *AppHandler) appGetHandler(ctx context.Context, logger logr.Logger, auth func (h *AppHandler) appCreateHandler(ctx context.Context, logger logr.Logger, authInfo authorization.Info, r *http.Request) (*HandlerResponse, error) { var payload payloads.AppCreate if err := h.decoderValidator.DecodeAndValidateJSONPayload(r, &payload); err != nil { - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "failed to decode json payload") } spaceGUID := payload.Relationships.Space.Data.GUID _, err := h.spaceRepo.GetSpace(ctx, authInfo, spaceGUID) if err != nil { - logger.Error(err, "Failed to fetch space from Kubernetes", "spaceGUID", spaceGUID) - return nil, apierrors.AsUnprocessableEntity(err, "Invalid space. Ensure that the space exists and you have access to it.", apierrors.NotFoundError{}, apierrors.ForbiddenError{}) + return nil, apierrors.LogAndReturn( + logger, + apierrors.AsUnprocessableEntity(err, "Invalid space. Ensure that the space exists and you have access to it.", apierrors.NotFoundError{}, apierrors.ForbiddenError{}), + "spaceGUID", spaceGUID, + ) } appRecord, err := h.appRepo.CreateApp(ctx, authInfo, payload.ToAppCreateMessage()) if err != nil { - logger.Error(err, "Failed to create app", "App Name", payload.Name) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to create app", "App Name", payload.Name) } return NewHandlerResponse(http.StatusCreated).WithBody(presenter.ForApp(appRecord, h.serverURL)), nil @@ -130,21 +131,18 @@ func (h *AppHandler) appCreateHandler(ctx context.Context, logger logr.Logger, a func (h *AppHandler) appListHandler(ctx context.Context, logger logr.Logger, authInfo authorization.Info, r *http.Request) (*HandlerResponse, error) { //nolint:dupl if err := r.ParseForm(); err != nil { - logger.Error(err, "Unable to parse request query parameters") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Unable to parse request query parameters") } appListFilter := new(payloads.AppList) err := payloads.Decode(appListFilter, r.Form) if err != nil { - logger.Error(err, "Unable to decode request query parameters") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Unable to decode request query parameters") } appList, err := h.appRepo.ListApps(ctx, authInfo, appListFilter.ToMessage()) if err != nil { - logger.Error(err, "Failed to fetch app(s) from Kubernetes") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to fetch app(s) from Kubernetes") } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForAppList(appList, h.serverURL, *r.URL)), nil @@ -156,24 +154,30 @@ func (h *AppHandler) appSetCurrentDropletHandler(ctx context.Context, logger log var payload payloads.AppSetCurrentDroplet if err := h.decoderValidator.DecodeAndValidateJSONPayload(r, &payload); err != nil { - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "failed to decode json payload") } app, err := h.appRepo.GetApp(ctx, authInfo, appGUID) if err != nil { - logger.Error(err, "Failed to fetch app from Kubernetes", "AppGUID", appGUID) - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "Failed to fetch app from Kubernetes", "AppGUID", appGUID) } dropletGUID := payload.Data.GUID droplet, err := h.dropletRepo.GetDroplet(ctx, authInfo, dropletGUID) if err != nil { - logger.Error(err, "Error fetching droplet") - return nil, apierrors.AsUnprocessableEntity(err, invalidDropletMsg, apierrors.ForbiddenError{}, apierrors.NotFoundError{}) + return nil, apierrors.LogAndReturn( + logger, + apierrors.AsUnprocessableEntity(err, invalidDropletMsg, apierrors.ForbiddenError{}, apierrors.NotFoundError{}), + "Error fetching droplet", + ) } if droplet.AppGUID != appGUID { - return nil, apierrors.NewUnprocessableEntityError(fmt.Errorf("droplet %s does not belong to app %s", droplet.GUID, appGUID), invalidDropletMsg) + return nil, apierrors.LogAndReturn( + logger, + apierrors.NewUnprocessableEntityError(fmt.Errorf("droplet %s does not belong to app %s", droplet.GUID, appGUID), invalidDropletMsg), + invalidDropletMsg, + ) } currentDroplet, err := h.appRepo.SetCurrentDroplet(ctx, authInfo, repositories.SetCurrentDropletMessage{ @@ -182,8 +186,7 @@ func (h *AppHandler) appSetCurrentDropletHandler(ctx context.Context, logger log SpaceGUID: app.SpaceGUID, }) if err != nil { - logger.Error(err, "Error setting current droplet") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Error setting current droplet") } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForCurrentDroplet(currentDroplet, h.serverURL)), nil @@ -195,19 +198,21 @@ func (h *AppHandler) appGetCurrentDropletHandler(ctx context.Context, logger log app, err := h.appRepo.GetApp(ctx, authInfo, appGUID) if err != nil { - logger.Error(err, "Failed to fetch app from Kubernetes", "AppGUID", appGUID) - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "Failed to fetch app from Kubernetes", "AppGUID", appGUID) } if app.DropletGUID == "" { - logger.Info("App does not have a current droplet assigned", "appGUID", app.GUID) - return nil, apierrors.DropletForbiddenAsNotFound(apierrors.NewNotFoundError(err, repositories.DropletResourceType)) + return nil, apierrors.LogAndReturn( + logger, + apierrors.DropletForbiddenAsNotFound(apierrors.NewNotFoundError(nil, repositories.DropletResourceType)), + "App does not have a current droplet assigned", + "appGUID", app.GUID, + ) } droplet, err := h.dropletRepo.GetDroplet(ctx, authInfo, app.DropletGUID) if err != nil { - logger.Error(err, "Failed to fetch droplet from Kubernetes", "dropletGUID", app.DropletGUID) - return nil, apierrors.DropletForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.DropletForbiddenAsNotFound(err), "Failed to fetch droplet from Kubernetes", "dropletGUID", app.DropletGUID) } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForDroplet(droplet, h.serverURL)), nil @@ -219,12 +224,10 @@ func (h *AppHandler) appStartHandler(ctx context.Context, logger logr.Logger, au app, err := h.appRepo.GetApp(ctx, authInfo, appGUID) if err != nil { - logger.Error(err, "Failed to fetch app from Kubernetes", "AppGUID", appGUID) - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "Failed to fetch app from Kubernetes", "AppGUID", appGUID) } if app.DropletGUID == "" { - logger.Info("App droplet not set before start", "AppGUID", appGUID) - return nil, apierrors.NewUnprocessableEntityError(err, "Assign a droplet before starting this app.") + return nil, apierrors.LogAndReturn(logger, apierrors.NewUnprocessableEntityError(err, "Assign a droplet before starting this app."), "App droplet not set before start", "AppGUID", appGUID) } app, err = h.appRepo.SetAppDesiredState(ctx, authInfo, repositories.SetAppDesiredStateMessage{ @@ -233,8 +236,7 @@ func (h *AppHandler) appStartHandler(ctx context.Context, logger logr.Logger, au DesiredState: AppStartedState, }) if err != nil { - logger.Error(err, "Failed to update app in Kubernetes", "AppGUID", appGUID) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to update app in Kubernetes", "AppGUID", appGUID) } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForApp(app, h.serverURL)), nil @@ -246,8 +248,7 @@ func (h *AppHandler) appStopHandler(ctx context.Context, logger logr.Logger, aut app, err := h.appRepo.GetApp(ctx, authInfo, appGUID) if err != nil { - logger.Error(err, "Failed to fetch app from Kubernetes", "AppGUID", appGUID) - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "Failed to fetch app from Kubernetes", "AppGUID", appGUID) } app, err = h.appRepo.SetAppDesiredState(ctx, authInfo, repositories.SetAppDesiredStateMessage{ @@ -256,8 +257,7 @@ func (h *AppHandler) appStopHandler(ctx context.Context, logger logr.Logger, aut DesiredState: AppStoppedState, }) if err != nil { - logger.Error(err, "Failed to update app in Kubernetes", "AppGUID", appGUID) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to update app in Kubernetes", "AppGUID", appGUID) } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForApp(app, h.serverURL)), nil @@ -269,8 +269,7 @@ func (h *AppHandler) getProcessesForAppHandler(ctx context.Context, logger logr. app, err := h.appRepo.GetApp(ctx, authInfo, appGUID) if err != nil { - logger.Error(err, "Failed to fetch app from Kubernetes", "AppGUID", appGUID) - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "Failed to fetch app from Kubernetes", "AppGUID", appGUID) } fetchProcessesForAppMessage := repositories.ListProcessesMessage{ @@ -280,8 +279,7 @@ func (h *AppHandler) getProcessesForAppHandler(ctx context.Context, logger logr. processList, err := h.processRepo.ListProcesses(ctx, authInfo, fetchProcessesForAppMessage) if err != nil { - logger.Error(err, "Failed to fetch app Process(es) from Kubernetes") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to fetch app Process(es) from Kubernetes") } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForProcessList(processList, h.serverURL, *r.URL)), nil @@ -293,14 +291,12 @@ func (h *AppHandler) getRoutesForAppHandler(ctx context.Context, logger logr.Log app, err := h.appRepo.GetApp(ctx, authInfo, appGUID) if err != nil { - logger.Error(err, "Failed to fetch app from Kubernetes", "AppGUID", appGUID) - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "Failed to fetch app from Kubernetes", "AppGUID", appGUID) } routes, err := h.lookupAppRouteAndDomainList(ctx, authInfo, app.GUID, app.SpaceGUID) if err != nil { - logger.Error(err, "Failed to fetch route or domains from Kubernetes") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to fetch route or domains from Kubernetes") } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForRouteList(routes, h.serverURL, *r.URL)), nil @@ -313,13 +309,12 @@ func (h *AppHandler) appScaleProcessHandler(ctx context.Context, logger logr.Log var payload payloads.ProcessScale if err := h.decoderValidator.DecodeAndValidateJSONPayload(r, &payload); err != nil { - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "failed to decode json payload") } processRecord, err := h.appProcessScaler.ScaleAppProcess(ctx, authInfo, appGUID, processType, payload.ToRecord()) if err != nil { - logger.Error(err, "Failed due to error from Kubernetes", "appGUID", appGUID) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed due to error from Kubernetes", "appGUID", appGUID) } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForProcess(processRecord, h.serverURL)), nil @@ -331,13 +326,16 @@ func (h *AppHandler) appRestartHandler(ctx context.Context, logger logr.Logger, app, err := h.appRepo.GetApp(ctx, authInfo, appGUID) if err != nil { - logger.Error(err, "Failed to fetch app from Kubernetes", "AppGUID", appGUID) - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "Failed to fetch app from Kubernetes", "AppGUID", appGUID) } if app.DropletGUID == "" { - logger.Info("App droplet not set before start", "AppGUID", appGUID) - return nil, apierrors.NewUnprocessableEntityError(fmt.Errorf("app %s has no droplet set", app.GUID), "Assign a droplet before starting this app.") + return nil, apierrors.LogAndReturn( + logger, + apierrors.NewUnprocessableEntityError(fmt.Errorf("app %s has no droplet set", app.GUID), "Assign a droplet before starting this app."), + "App droplet not set before start", + "AppGUID", appGUID, + ) } if app.State == repositories.StartedState { @@ -347,8 +345,7 @@ func (h *AppHandler) appRestartHandler(ctx context.Context, logger logr.Logger, DesiredState: AppStoppedState, }) if err != nil { - logger.Error(err, "Failed to update app in Kubernetes", "AppGUID", appGUID) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to update app in Kubernetes", "AppGUID", appGUID) } } @@ -358,8 +355,7 @@ func (h *AppHandler) appRestartHandler(ctx context.Context, logger logr.Logger, DesiredState: AppStartedState, }) if err != nil { - logger.Error(err, "Failed to update app in Kubernetes", "AppGUID", appGUID) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to update app in Kubernetes", "AppGUID", appGUID) } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForApp(app, h.serverURL)), nil @@ -371,8 +367,7 @@ func (h *AppHandler) appDeleteHandler(ctx context.Context, logger logr.Logger, a app, err := h.appRepo.GetApp(ctx, authInfo, appGUID) if err != nil { - logger.Error(err, "Failed to fetch app from Kubernetes", "AppGUID", appGUID) - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "Failed to fetch app from Kubernetes", "AppGUID", appGUID) } err = h.appRepo.DeleteApp(ctx, authInfo, repositories.DeleteAppMessage{ @@ -380,8 +375,7 @@ func (h *AppHandler) appDeleteHandler(ctx context.Context, logger logr.Logger, a SpaceGUID: app.SpaceGUID, }) if err != nil { - logger.Error(err, "Failed to delete app", "AppGUID", appGUID) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to delete app", "AppGUID", appGUID) } return NewHandlerResponse(http.StatusAccepted).WithHeader("Location", presenter.JobURLForRedirects(appGUID, presenter.AppDeleteOperation, h.serverURL)), nil @@ -422,19 +416,17 @@ func (h *AppHandler) appPatchEnvVarsHandler(ctx context.Context, logger logr.Log var payload payloads.AppPatchEnvVars if err := h.decoderValidator.DecodeAndValidateJSONPayload(r, &payload); err != nil { - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "failed to decode payload") } app, err := h.appRepo.GetApp(ctx, authInfo, appGUID) if err != nil { - logger.Error(err, "Failed to fetch app from Kubernetes", "AppGUID", appGUID) - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "Failed to fetch app from Kubernetes", "AppGUID", appGUID) } envVarsRecord, err := h.appRepo.PatchAppEnvVars(ctx, authInfo, payload.ToMessage(appGUID, app.SpaceGUID)) if err != nil { - logger.Error(err, "Error updating app environment variables") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Error updating app environment variables") } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForAppEnvVars(envVarsRecord, h.serverURL)), nil @@ -446,8 +438,7 @@ func (h *AppHandler) appGetEnvHandler(ctx context.Context, logger logr.Logger, a appEnvRecord, err := h.appRepo.GetAppEnv(ctx, authInfo, appGUID) if err != nil { - logger.Error(err, "Failed to fetch app environment variables", "AppGUID", appGUID) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to fetch app environment variables", "AppGUID", appGUID) } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForAppEnv(appEnvRecord)), nil @@ -460,14 +451,12 @@ func (h *AppHandler) getProcessByTypeForAppHander(ctx context.Context, logger lo app, err := h.appRepo.GetApp(ctx, authInfo, appGUID) if err != nil { - logger.Error(err, "Failed to fetch app from Kubernetes", "AppGUID", appGUID) - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "Failed to fetch app from Kubernetes", "AppGUID", appGUID) } process, err := h.processRepo.GetProcessByAppTypeAndSpace(ctx, authInfo, appGUID, processType, app.SpaceGUID) if err != nil { - logger.Error(err, "Failed to fetch process from Kubernetes", "AppGUID", appGUID) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to fetch process from Kubernetes", "AppGUID", appGUID) } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForProcess(process, h.serverURL)), nil diff --git a/api/handlers/auth_aware_handler.go b/api/handlers/auth_aware_handler.go index 76beef333..d056ed9a8 100644 --- a/api/handlers/auth_aware_handler.go +++ b/api/handlers/auth_aware_handler.go @@ -73,25 +73,27 @@ func (h *AuthAwareHandlerFuncWrapper) Wrap(delegate AuthAwareHandlerFunc) http.H authInfo, ok := h.authInfoProvider(r.Context()) if !ok { logger.Error(nil, "unable to get auth info") - presentError(w, nil) + presentError(h.logger, w, nil) return } handlerResponse, err := delegate(ctx, logger, authInfo, r) if err != nil { logger.Info("handler returned error", "error", err) - presentError(w, err) + presentError(h.logger, w, err) return } - handlerResponse.writeTo(w) + if err := handlerResponse.writeTo(w); err != nil { + _ = apierrors.LogAndReturn(logger, err, "failed to write result to the HTTP response", "handlerResponse", handlerResponse, "method", r.Method, "URL", r.URL) + } } } -func presentError(w http.ResponseWriter, err error) { +func presentError(logger logr.Logger, w http.ResponseWriter, err error) { var apiError apierrors.ApiError if errors.As(err, &apiError) { - NewHandlerResponse(apiError.HttpStatus()). + writeErr := NewHandlerResponse(apiError.HttpStatus()). WithBody(presenter.ErrorsResponse{ Errors: []presenter.PresentedError{ { @@ -102,20 +104,25 @@ func presentError(w http.ResponseWriter, err error) { }, }). writeTo(w) + + if writeErr != nil { + _ = apierrors.LogAndReturn(logger, writeErr, "failed to write error to the HTTP response") + } + return } - presentError(w, apierrors.NewUnknownError(err)) + presentError(logger, w, apierrors.NewUnknownError(err)) } -func (response *HandlerResponse) writeTo(w http.ResponseWriter) { +func (response *HandlerResponse) writeTo(w http.ResponseWriter) error { for k, v := range response.headers { w.Header().Set(k, v) } if response.body == nil { w.WriteHeader(response.httpStatus) - return + return nil } w.Header().Set(headers.ContentType, "application/json") @@ -126,6 +133,8 @@ func (response *HandlerResponse) writeTo(w http.ResponseWriter) { err := encoder.Encode(response.body) if err != nil { - Logger.Error(err, "failed to encode and write response") + return fmt.Errorf("failed to encode and write response: %w", err) } + + return nil } diff --git a/api/handlers/authentication_middleware.go b/api/handlers/authentication_middleware.go index 098cb9951..0ccd6b2b0 100644 --- a/api/handlers/authentication_middleware.go +++ b/api/handlers/authentication_middleware.go @@ -3,6 +3,7 @@ package handlers import ( "net/http" + "code.cloudfoundry.org/korifi/api/apierrors" "code.cloudfoundry.org/korifi/api/authorization" "code.cloudfoundry.org/korifi/api/correlation" ctrl "sigs.k8s.io/controller-runtime" @@ -48,8 +49,8 @@ func (a *AuthenticationMiddleware) Middleware(next http.Handler) http.Handler { authInfo, err := a.authInfoParser.Parse(r.Header.Get(headers.Authorization)) if err != nil { - logger.Error(err, "failed to parse auth info") - presentError(w, err) + logger.Info("failed to parse auth info", "err", err) + presentError(logger, w, err) return } @@ -57,8 +58,7 @@ func (a *AuthenticationMiddleware) Middleware(next http.Handler) http.Handler { _, err = a.identityProvider.GetIdentity(r.Context(), authInfo) if err != nil { - logger.Error(err, "failed to get identity") - presentError(w, err) + presentError(logger, w, apierrors.LogAndReturn(logger, err, "failed to get identity")) return } diff --git a/api/handlers/build_handler.go b/api/handlers/build_handler.go index 2efb02904..b16996645 100644 --- a/api/handlers/build_handler.go +++ b/api/handlers/build_handler.go @@ -57,8 +57,7 @@ func (h *BuildHandler) buildGetHandler(ctx context.Context, logger logr.Logger, build, err := h.buildRepo.GetBuild(ctx, authInfo, buildGUID) if err != nil { - logger.Error(err, fmt.Sprintf("Failed to fetch %s from Kubernetes", repositories.BuildResourceType), "guid", buildGUID) - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), fmt.Sprintf("Failed to fetch %s from Kubernetes", repositories.BuildResourceType), "guid", buildGUID) } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForBuild(build, h.serverURL)), nil @@ -67,16 +66,19 @@ func (h *BuildHandler) buildGetHandler(ctx context.Context, logger logr.Logger, func (h *BuildHandler) buildCreateHandler(ctx context.Context, logger logr.Logger, authInfo authorization.Info, r *http.Request) (*HandlerResponse, error) { var payload payloads.BuildCreate if err := h.decoderValidator.DecodeAndValidateJSONPayload(r, &payload); err != nil { - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "failed to decode payload") } packageRecord, err := h.packageRepo.GetPackage(r.Context(), authInfo, payload.Package.GUID) if err != nil { - logger.Info("Error finding Package", "Package GUID", payload.Package.GUID) - return nil, apierrors.AsUnprocessableEntity(err, - "Unable to use package. Ensure that the package exists and you have access to it.", - apierrors.ForbiddenError{}, - apierrors.NotFoundError{}, + return nil, apierrors.LogAndReturn( + logger, + apierrors.AsUnprocessableEntity(err, + "Unable to use package. Ensure that the package exists and you have access to it.", + apierrors.ForbiddenError{}, + apierrors.NotFoundError{}, + ), + "Error finding Package", "Package GUID", payload.Package.GUID, ) } @@ -84,8 +86,7 @@ func (h *BuildHandler) buildCreateHandler(ctx context.Context, logger logr.Logge record, err := h.buildRepo.CreateBuild(r.Context(), authInfo, buildCreateMessage) if err != nil { - logger.Info("Error creating build with repository", "error", err.Error()) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Error creating build with repository") } return NewHandlerResponse(http.StatusCreated).WithBody(presenter.ForBuild(record, h.serverURL)), nil diff --git a/api/handlers/buildpack_handler.go b/api/handlers/buildpack_handler.go index 3228bc5bb..62d87bdb4 100644 --- a/api/handlers/buildpack_handler.go +++ b/api/handlers/buildpack_handler.go @@ -5,6 +5,7 @@ import ( "net/http" "net/url" + "code.cloudfoundry.org/korifi/api/apierrors" "code.cloudfoundry.org/korifi/api/authorization" "code.cloudfoundry.org/korifi/api/payloads" "code.cloudfoundry.org/korifi/api/presenter" @@ -43,21 +44,18 @@ func NewBuildpackHandler( func (h *BuildpackHandler) buildpackListHandler(ctx context.Context, logger logr.Logger, authInfo authorization.Info, r *http.Request) (*HandlerResponse, error) { if err := r.ParseForm(); err != nil { - logger.Error(err, "Unable to parse request query parameters") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Unable to parse request query parameters") } buildpackListFilter := new(payloads.BuildpackList) err := payloads.Decode(buildpackListFilter, r.Form) if err != nil { - logger.Error(err, "Unable to decode request query parameters") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Unable to decode request query parameters") } buildpacks, err := h.buildpackRepo.ListBuildpacks(ctx, authInfo) if err != nil { - logger.Error(err, "Failed to fetch buildpacks from Kubernetes") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to fetch buildpacks from Kubernetes") } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForBuildpackList(buildpacks, h.serverURL, *r.URL)), nil diff --git a/api/handlers/domain_handler.go b/api/handlers/domain_handler.go index 0417fe9c8..09cdcf5f9 100644 --- a/api/handlers/domain_handler.go +++ b/api/handlers/domain_handler.go @@ -5,6 +5,7 @@ import ( "net/http" "net/url" + "code.cloudfoundry.org/korifi/api/apierrors" "code.cloudfoundry.org/korifi/api/authorization" "code.cloudfoundry.org/korifi/api/payloads" "code.cloudfoundry.org/korifi/api/presenter" @@ -46,21 +47,18 @@ func NewDomainHandler( func (h *DomainHandler) DomainListHandler(ctx context.Context, logger logr.Logger, authInfo authorization.Info, r *http.Request) (*HandlerResponse, error) { //nolint:dupl if err := r.ParseForm(); err != nil { - logger.Error(err, "Unable to parse request query parameters") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Unable to parse request query parameters") } domainListFilter := new(payloads.DomainList) err := payloads.Decode(domainListFilter, r.Form) if err != nil { - logger.Error(err, "Unable to decode request query parameters") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Unable to decode request query parameters") } domainList, err := h.domainRepo.ListDomains(ctx, authInfo, domainListFilter.ToMessage()) if err != nil { - logger.Error(err, "Failed to fetch domain(s) from Kubernetes") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to fetch domain(s) from Kubernetes") } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForDomainList(domainList, h.serverURL, *r.URL)), nil diff --git a/api/handlers/droplet_handler.go b/api/handlers/droplet_handler.go index 66619410e..23cd9a60a 100644 --- a/api/handlers/droplet_handler.go +++ b/api/handlers/droplet_handler.go @@ -49,8 +49,12 @@ func (h *DropletHandler) dropletGetHandler(ctx context.Context, logger logr.Logg droplet, err := h.dropletRepo.GetDroplet(ctx, authInfo, dropletGUID) if err != nil { - logger.Error(err, fmt.Sprintf("Failed to fetch %s from Kubernetes", repositories.DropletResourceType), "guid", dropletGUID) - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn( + logger, + apierrors.ForbiddenAsNotFound(err), + fmt.Sprintf("Failed to fetch %s from Kubernetes", repositories.DropletResourceType), + "guid", dropletGUID, + ) } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForDroplet(droplet, h.serverURL)), nil diff --git a/api/handlers/job_handler.go b/api/handlers/job_handler.go index 45de0a3db..cfc5d328c 100644 --- a/api/handlers/job_handler.go +++ b/api/handlers/job_handler.go @@ -46,8 +46,11 @@ func (h *JobHandler) jobGetHandler(ctx context.Context, logger logr.Logger, auth jobType, resourceGUID, match := parseJobGUID(jobGUID) if !match { - logger.Info("Invalid Job GUID") - return nil, apierrors.NewNotFoundError(fmt.Errorf("invalid job guid: %s", jobGUID), JobResourceType) + return nil, apierrors.LogAndReturn( + logger, + apierrors.NewNotFoundError(fmt.Errorf("invalid job guid: %s", jobGUID), JobResourceType), + "Invalid Job GUID", + ) } var jobResponse presenter.JobResponse @@ -58,8 +61,11 @@ func (h *JobHandler) jobGetHandler(ctx context.Context, logger logr.Logger, auth case appDeletePrefix, orgDeletePrefix, spaceDeletePrefix, routeDeletePrefix: jobResponse = presenter.ForDeleteJob(jobGUID, jobType, h.serverURL) default: - logger.Info(fmt.Sprintf("Invalid Job type: %s", jobType)) - return nil, apierrors.NewNotFoundError(fmt.Errorf("invalid job type: %s", jobType), JobResourceType) + return nil, apierrors.LogAndReturn( + logger, + apierrors.NewNotFoundError(fmt.Errorf("invalid job type: %s", jobType), JobResourceType), + fmt.Sprintf("Invalid Job type: %s", jobType), + ) } return NewHandlerResponse(http.StatusOK).WithBody(jobResponse), nil diff --git a/api/handlers/log_cache_handler.go b/api/handlers/log_cache_handler.go index 44973cf98..f00a99b95 100644 --- a/api/handlers/log_cache_handler.go +++ b/api/handlers/log_cache_handler.go @@ -60,21 +60,22 @@ func (h *LogCacheHandler) logCacheInfoHandler(ctx context.Context, logger logr.L func (h *LogCacheHandler) logCacheReadHandler(ctx context.Context, logger logr.Logger, authInfo authorization.Info, r *http.Request) (*HandlerResponse, error) { if err := r.ParseForm(); err != nil { - logger.Error(err, "Unable to parse request query parameters") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Unable to parse request query parameters") } logReadPayload := new(payloads.LogRead) err := payloads.Decode(logReadPayload, r.Form) if err != nil { - logger.Error(err, "Unable to decode request query parameters") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Unable to decode request query parameters") } v := validator.New() if logReadPayloadErr := v.Struct(logReadPayload); logReadPayloadErr != nil { - logger.Error(logReadPayloadErr, "Error validating log read request query parameters") - return nil, apierrors.NewUnprocessableEntityError(logReadPayloadErr, "error validating log read query parameters") + return nil, apierrors.LogAndReturn( + logger, + apierrors.NewUnprocessableEntityError(logReadPayloadErr, "error validating log read query parameters"), + "Error validating log read request query parameters", + ) } vars := mux.Vars(r) diff --git a/api/handlers/org_handler.go b/api/handlers/org_handler.go index ed1bd5312..f62f66288 100644 --- a/api/handlers/org_handler.go +++ b/api/handlers/org_handler.go @@ -57,15 +57,13 @@ func NewOrgHandler(apiBaseURL url.URL, orgRepo CFOrgRepository, domainRepo CFDom func (h *OrgHandler) orgCreateHandler(ctx context.Context, logger logr.Logger, authInfo authorization.Info, r *http.Request) (*HandlerResponse, error) { var payload payloads.OrgCreate if err := h.decoderValidator.DecodeAndValidateJSONPayload(r, &payload); err != nil { - logger.Info("invalid-payload-for-create-org", "err", err) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "invalid-payload-for-create-org") } org := payload.ToMessage() record, err := h.orgRepo.CreateOrg(ctx, authInfo, org) if err != nil { - logger.Error(err, "Failed to create org", "Org Name", payload.Name) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to create org", "Org Name", payload.Name) } return NewHandlerResponse(http.StatusCreated).WithBody(presenter.ForCreateOrg(record, h.apiBaseURL)), nil @@ -80,8 +78,7 @@ func (h *OrgHandler) orgDeleteHandler(ctx context.Context, logger logr.Logger, a } err := h.orgRepo.DeleteOrg(ctx, authInfo, deleteOrgMessage) if err != nil { - logger.Error(err, "Failed to delete org", "OrgGUID", orgGUID) - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "Failed to delete org", "OrgGUID", orgGUID) } return NewHandlerResponse(http.StatusAccepted).WithHeader("Location", presenter.JobURLForRedirects(orgGUID, presenter.OrgDeleteOperation, h.apiBaseURL)), nil @@ -92,8 +89,7 @@ func (h *OrgHandler) orgListHandler(ctx context.Context, logger logr.Logger, aut orgs, err := h.orgRepo.ListOrgs(ctx, authInfo, repositories.ListOrgsMessage{Names: names}) if err != nil { - logger.Error(err, "failed to fetch orgs") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "failed to fetch orgs") } resp := NewHandlerResponse(http.StatusOK).WithBody(presenter.ForOrgList(orgs, h.apiBaseURL, *r.URL)) @@ -110,26 +106,22 @@ func (h *OrgHandler) orgListDomainHandler(ctx context.Context, logger logr.Logge orgGUID := vars["guid"] if _, err := h.orgRepo.GetOrg(ctx, authInfo, orgGUID); err != nil { - logger.Error(err, "Unable to get organization") - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "Unable to get organization") } if err := r.ParseForm(); err != nil { - logger.Error(err, "Unable to parse request query parameters") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Unable to parse request query parameters") } domainListFilter := new(payloads.DomainList) err := payloads.Decode(domainListFilter, r.Form) if err != nil { - logger.Error(err, "Unable to decode request query parameters") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Unable to decode request query parameters") } domainList, err := h.domainRepo.ListDomains(ctx, authInfo, domainListFilter.ToMessage()) if err != nil { - logger.Error(err, "Failed to fetch domain(s) from Kubernetes") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to fetch domain(s) from Kubernetes") } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForDomainList(domainList, h.apiBaseURL, *r.URL)), nil diff --git a/api/handlers/package_handler.go b/api/handlers/package_handler.go index 2500d87ed..fda77be9e 100644 --- a/api/handlers/package_handler.go +++ b/api/handlers/package_handler.go @@ -78,8 +78,7 @@ func (h PackageHandler) packageGetHandler(ctx context.Context, logger logr.Logge packageGUID := mux.Vars(r)["guid"] record, err := h.packageRepo.GetPackage(ctx, authInfo, packageGUID) if err != nil { - logger.Info("Error fetching package with repository", "error", err.Error()) - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "Error fetching package with repository") } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForPackage(record, h.serverURL)), nil @@ -87,21 +86,18 @@ func (h PackageHandler) packageGetHandler(ctx context.Context, logger logr.Logge func (h PackageHandler) packageListHandler(ctx context.Context, logger logr.Logger, authInfo authorization.Info, r *http.Request) (*HandlerResponse, error) { if err := r.ParseForm(); err != nil { - logger.Error(err, "Unable to parse request query parameters") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Unable to parse request query parameters") } packageListQueryParameters := new(payloads.PackageListQueryParameters) err := payloads.Decode(packageListQueryParameters, r.Form) if err != nil { - logger.Error(err, "Unable to decode request query parameters") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Unable to decode request query parameters") } records, err := h.packageRepo.ListPackages(ctx, authInfo, packageListQueryParameters.ToMessage()) if err != nil { - logger.Error(err, "Error fetching package with repository", "error") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Error fetching package with repository", "error") } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForPackageList(records, h.serverURL, *r.URL)), nil @@ -110,24 +106,27 @@ func (h PackageHandler) packageListHandler(ctx context.Context, logger logr.Logg func (h PackageHandler) packageCreateHandler(ctx context.Context, logger logr.Logger, authInfo authorization.Info, r *http.Request) (*HandlerResponse, error) { var payload payloads.PackageCreate if err := h.decoderValidator.DecodeAndValidateJSONPayload(r, &payload); err != nil { - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "failed to decode payload") } appRecord, err := h.appRepo.GetApp(ctx, authInfo, payload.Relationships.App.Data.GUID) if err != nil { - logger.Info("Error finding App", "App GUID", payload.Relationships.App.Data.GUID) - return nil, apierrors.AsUnprocessableEntity( - err, - "App is invalid. Ensure it exists and you have access to it.", - apierrors.NotFoundError{}, - apierrors.ForbiddenError{}, + return nil, apierrors.LogAndReturn( + logger, + apierrors.AsUnprocessableEntity( + err, + "App is invalid. Ensure it exists and you have access to it.", + apierrors.NotFoundError{}, + apierrors.ForbiddenError{}, + ), + "Error finding App", + "App GUID", payload.Relationships.App.Data.GUID, ) } record, err := h.packageRepo.CreatePackage(r.Context(), authInfo, payload.ToMessage(appRecord)) if err != nil { - logger.Info("Error creating package with repository", "error", err.Error()) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Error creating package with repository") } return NewHandlerResponse(http.StatusCreated).WithBody(presenter.ForPackage(record, h.serverURL)), nil @@ -137,33 +136,28 @@ func (h PackageHandler) packageUploadHandler(ctx context.Context, logger logr.Lo packageGUID := mux.Vars(r)["guid"] err := r.ParseForm() if err != nil { // untested - couldn't find a way to trigger this branch - logger.Info("Error parsing multipart form", "error", err.Error()) - return nil, apierrors.NewInvalidRequestError(err, "Unable to parse body as multipart form") + return nil, apierrors.LogAndReturn(logger, apierrors.NewInvalidRequestError(err, "Unable to parse body as multipart form"), "Error parsing multipart form") } bitsFile, _, err := r.FormFile("bits") if err != nil { - logger.Info("Error reading form file \"bits\"", "error", err.Error()) - return nil, apierrors.NewUnprocessableEntityError(err, "Upload must include bits") + return nil, apierrors.LogAndReturn(logger, apierrors.NewUnprocessableEntityError(err, "Upload must include bits"), "Error reading form file \"bits\"") } defer bitsFile.Close() record, err := h.packageRepo.GetPackage(r.Context(), authInfo, packageGUID) if err != nil { - logger.Info("Error fetching package with repository", "error", err.Error()) - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "Error fetching package with repository") } if record.State != repositories.PackageStateAwaitingUpload { - logger.Info("Error, cannot call package upload state was not AWAITING_UPLOAD", "packageGUID", packageGUID) - return nil, apierrors.NewPackageBitsAlreadyUploadedError(err) + return nil, apierrors.LogAndReturn(logger, apierrors.NewPackageBitsAlreadyUploadedError(err), "Error, cannot call package upload state was not AWAITING_UPLOAD", "packageGUID", packageGUID) } imageRef := path.Join(h.registryBase, packageGUID) uploadedImageRef, err := h.imageRepo.UploadSourceImage(r.Context(), authInfo, imageRef, bitsFile, record.SpaceGUID) if err != nil { - logger.Info("Error calling uploadSourceImage", "error", err.Error()) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Error calling uploadSourceImage") } record, err = h.packageRepo.UpdatePackageSource(r.Context(), authInfo, repositories.UpdatePackageSourceMessage{ @@ -173,8 +167,7 @@ func (h PackageHandler) packageUploadHandler(ctx context.Context, logger logr.Lo RegistrySecretName: h.registrySecretName, }) if err != nil { - logger.Info("Error calling UpdatePackageSource", "error", err.Error()) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Error calling UpdatePackageSource") } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForPackage(record, h.serverURL)), nil @@ -182,30 +175,26 @@ func (h PackageHandler) packageUploadHandler(ctx context.Context, logger logr.Lo func (h PackageHandler) packageListDropletsHandler(ctx context.Context, logger logr.Logger, authInfo authorization.Info, r *http.Request) (*HandlerResponse, error) { if err := r.ParseForm(); err != nil { - logger.Error(err, "Unable to parse request query parameters") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Unable to parse request query parameters") } packageListDropletsQueryParams := new(payloads.PackageListDropletsQueryParameters) err := payloads.Decode(packageListDropletsQueryParams, r.Form) if err != nil { - logger.Error(err, "Unable to decode request query parameters") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Unable to decode request query parameters") } packageGUID := mux.Vars(r)["guid"] _, err = h.packageRepo.GetPackage(r.Context(), authInfo, packageGUID) if err != nil { - logger.Error(err, "Error fetching package with repository") - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "Error fetching package with repository") } dropletListMessage := packageListDropletsQueryParams.ToMessage([]string{packageGUID}) dropletList, err := h.dropletRepo.ListDroplets(r.Context(), authInfo, dropletListMessage) if err != nil { - logger.Error(err, "Error fetching droplet list with repository") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Error fetching droplet list with repository") } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForDropletList(dropletList, h.serverURL, *r.URL)), nil diff --git a/api/handlers/process_handler.go b/api/handlers/process_handler.go index cc14132e0..5dfb7c512 100644 --- a/api/handlers/process_handler.go +++ b/api/handlers/process_handler.go @@ -76,8 +76,7 @@ func (h *ProcessHandler) processGetHandler(ctx context.Context, logger logr.Logg process, err := h.processRepo.GetProcess(ctx, authInfo, processGUID) if err != nil { - logger.Error(err, "Failed to fetch process from Kubernetes", "ProcessGUID", processGUID) - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "Failed to fetch process from Kubernetes", "ProcessGUID", processGUID) } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForProcess(process, h.serverURL)), nil @@ -89,8 +88,7 @@ func (h *ProcessHandler) processGetSidecarsHandler(ctx context.Context, logger l _, err := h.processRepo.GetProcess(ctx, authInfo, processGUID) if err != nil { - logger.Error(err, "Failed to fetch process from Kubernetes", "ProcessGUID", processGUID) - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "Failed to fetch process from Kubernetes", "ProcessGUID", processGUID) } return NewHandlerResponse(http.StatusOK).WithBody(map[string]interface{}{ @@ -116,13 +114,12 @@ func (h *ProcessHandler) processScaleHandler(ctx context.Context, logger logr.Lo var payload payloads.ProcessScale if err := h.decoderValidator.DecodeAndValidateJSONPayload(r, &payload); err != nil { - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "failed to decode payload") } processRecord, err := h.processScaler.ScaleProcess(ctx, authInfo, processGUID, payload.ToRecord()) if err != nil { - logger.Error(err, "Failed due to error from Kubernetes", "processGUID", processGUID) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed due to error from Kubernetes", "processGUID", processGUID) } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForProcess(processRecord, h.serverURL)), nil @@ -134,8 +131,7 @@ func (h *ProcessHandler) processGetStatsHandler(ctx context.Context, logger logr records, err := h.processStatsFetcher.FetchStats(ctx, authInfo, processGUID) if err != nil { - logger.Error(err, "Failed to get process stats from Kubernetes", "ProcessGUID", processGUID) - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "Failed to get process stats from Kubernetes", "ProcessGUID", processGUID) } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForProcessStats(records)), nil @@ -143,21 +139,18 @@ func (h *ProcessHandler) processGetStatsHandler(ctx context.Context, logger logr func (h *ProcessHandler) processListHandler(ctx context.Context, logger logr.Logger, authInfo authorization.Info, r *http.Request) (*HandlerResponse, error) { //nolint:dupl if err := r.ParseForm(); err != nil { - logger.Error(err, "Unable to parse request query parameters") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Unable to parse request query parameters") } processListFilter := new(payloads.ProcessList) err := payloads.Decode(processListFilter, r.Form) if err != nil { - logger.Error(err, "Unable to decode request query parameters") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Unable to decode request query parameters") } processList, err := h.processRepo.ListProcesses(ctx, authInfo, processListFilter.ToMessage()) if err != nil { - logger.Error(err, "Failed to fetch processes(s) from Kubernetes") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to fetch processes(s) from Kubernetes") } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForProcessList(processList, h.serverURL, *r.URL)), nil @@ -169,19 +162,17 @@ func (h *ProcessHandler) processPatchHandler(ctx context.Context, logger logr.Lo var payload payloads.ProcessPatch if err := h.decoderValidator.DecodeAndValidateJSONPayload(r, &payload); err != nil { - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "failed to decode json payload") } process, err := h.processRepo.GetProcess(ctx, authInfo, processGUID) if err != nil { - logger.Error(err, "Failed to get process from Kubernetes", "ProcessGUID", processGUID) - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "Failed to get process from Kubernetes", "ProcessGUID", processGUID) } updatedProcess, err := h.processRepo.PatchProcess(ctx, authInfo, payload.ToProcessPatchMessage(processGUID, process.SpaceGUID)) if err != nil { - logger.Error(err, "Failed to patch process from Kubernetes", "ProcessGUID", processGUID) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to patch process from Kubernetes", "ProcessGUID", processGUID) } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForProcess(updatedProcess, h.serverURL)), nil diff --git a/api/handlers/role_handler.go b/api/handlers/role_handler.go index 214469dc9..8acbf4b3d 100644 --- a/api/handlers/role_handler.go +++ b/api/handlers/role_handler.go @@ -5,6 +5,7 @@ import ( "net/http" "net/url" + "code.cloudfoundry.org/korifi/api/apierrors" "code.cloudfoundry.org/korifi/api/authorization" "code.cloudfoundry.org/korifi/api/payloads" "code.cloudfoundry.org/korifi/api/presenter" @@ -60,7 +61,7 @@ func NewRoleHandler(apiBaseURL url.URL, roleRepo CFRoleRepository, decoderValida func (h *RoleHandler) roleCreateHandler(ctx context.Context, logger logr.Logger, authInfo authorization.Info, r *http.Request) (*HandlerResponse, error) { var payload payloads.RoleCreate if err := h.decoderValidator.DecodeAndValidateJSONPayload(r, &payload); err != nil { - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "failed to decode payload") } role := payload.ToMessage() @@ -68,8 +69,7 @@ func (h *RoleHandler) roleCreateHandler(ctx context.Context, logger logr.Logger, record, err := h.roleRepo.CreateRole(ctx, authInfo, role) if err != nil { - logger.Error(err, "Failed to create role", "Role Type", role.Type, "Space", role.Space, "User", role.User) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to create role", "Role Type", role.Type, "Space", role.Space, "User", role.User) } return NewHandlerResponse(http.StatusCreated).WithBody(presenter.ForCreateRole(record, h.apiBaseURL)), nil diff --git a/api/handlers/route_handler.go b/api/handlers/route_handler.go index 7302cf4c9..b129e43d6 100644 --- a/api/handlers/route_handler.go +++ b/api/handlers/route_handler.go @@ -78,21 +78,18 @@ func (h *RouteHandler) routeGetHandler(ctx context.Context, logger logr.Logger, func (h *RouteHandler) routeGetListHandler(ctx context.Context, logger logr.Logger, authInfo authorization.Info, r *http.Request) (*HandlerResponse, error) { if err := r.ParseForm(); err != nil { - logger.Error(err, "Unable to parse request query parameters") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Unable to parse request query parameters") } routeListFilter := new(payloads.RouteList) err := payloads.Decode(routeListFilter, r.Form) if err != nil { - logger.Error(err, "Unable to decode request query parameters") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Unable to decode request query parameters") } routes, err := h.lookupRouteAndDomainList(ctx, authInfo, routeListFilter.ToMessage()) if err != nil { - logger.Error(err, "Failed to fetch routes from Kubernetes") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to fetch routes from Kubernetes") } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForRouteList(routes, h.serverURL, *r.URL)), nil @@ -113,37 +110,43 @@ func (h *RouteHandler) routeGetDestinationsHandler(ctx context.Context, logger l func (h *RouteHandler) routeCreateHandler(ctx context.Context, logger logr.Logger, authInfo authorization.Info, r *http.Request) (*HandlerResponse, error) { var payload payloads.RouteCreate if err := h.decoderValidator.DecodeAndValidateJSONPayload(r, &payload); err != nil { - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "failed to decode payload") } spaceGUID := payload.Relationships.Space.Data.GUID _, err := h.spaceRepo.GetSpace(ctx, authInfo, spaceGUID) if err != nil { - logger.Error(err, "Failed to fetch space from Kubernetes", "spaceGUID", spaceGUID) - return nil, apierrors.AsUnprocessableEntity( - err, - "Invalid space. Ensure that the space exists and you have access to it.", - apierrors.NotFoundError{}, - apierrors.ForbiddenError{}, + return nil, apierrors.LogAndReturn( + logger, + apierrors.AsUnprocessableEntity( + err, + "Invalid space. Ensure that the space exists and you have access to it.", + apierrors.NotFoundError{}, + apierrors.ForbiddenError{}, + ), + "Failed to fetch space from Kubernetes", + "spaceGUID", spaceGUID, ) } domainGUID := payload.Relationships.Domain.Data.GUID domain, err := h.domainRepo.GetDomain(ctx, authInfo, domainGUID) if err != nil { - logger.Error(err, "Failed to fetch domain from Kubernetes", "Domain GUID", domainGUID) - return nil, apierrors.AsUnprocessableEntity( - err, - "Invalid domain. Ensure that the domain exists and you have access to it.", - apierrors.NotFoundError{}, + return nil, apierrors.LogAndReturn(logger, + apierrors.AsUnprocessableEntity( + err, + "Invalid domain. Ensure that the domain exists and you have access to it.", + apierrors.NotFoundError{}, + ), + "Failed to fetch space from Kubernetes", + "spaceGUID", spaceGUID, ) } createRouteMessage := payload.ToMessage(domain.Namespace, domain.Name) responseRouteRecord, err := h.routeRepo.CreateRoute(ctx, authInfo, createRouteMessage) if err != nil { - logger.Error(err, "Failed to create route", "Route Host", payload.Host) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to create route", "Route Host", payload.Host) } responseRouteRecord = responseRouteRecord.UpdateDomainRef(domain) @@ -154,7 +157,7 @@ func (h *RouteHandler) routeCreateHandler(ctx context.Context, logger logr.Logge func (h *RouteHandler) routeAddDestinationsHandler(ctx context.Context, logger logr.Logger, authInfo authorization.Info, r *http.Request) (*HandlerResponse, error) { var destinationCreatePayload payloads.DestinationListCreate if err := h.decoderValidator.DecodeAndValidateJSONPayload(r, &destinationCreatePayload); err != nil { - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "failed to decode payload") } vars := mux.Vars(r) @@ -169,8 +172,7 @@ func (h *RouteHandler) routeAddDestinationsHandler(ctx context.Context, logger l responseRouteRecord, err := h.routeRepo.AddDestinationsToRoute(ctx, authInfo, destinationListCreateMessage) if err != nil { - logger.Error(err, "Failed to add destination on route", "Route GUID", routeRecord.GUID) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to add destination on route", "Route GUID", routeRecord.GUID) } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForRouteDestinations(responseRouteRecord, h.serverURL)), nil @@ -195,8 +197,7 @@ func (h *RouteHandler) routeDeleteDestinationHandler(ctx context.Context, logger _, err = h.routeRepo.RemoveDestinationFromRoute(r.Context(), authInfo, message) if err != nil { - logger.Error(err, "Failed to remove destination from route", "Route GUID", routeRecord.GUID, "Destination GUID", destinationGUID) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to remove destination from route", "Route GUID", routeRecord.GUID, "Destination GUID", destinationGUID) } return NewHandlerResponse(http.StatusNoContent), nil @@ -216,8 +217,7 @@ func (h *RouteHandler) routeDeleteHandler(ctx context.Context, logger logr.Logge SpaceGUID: routeRecord.SpaceGUID, }) if err != nil { - logger.Error(err, "Failed to delete route", "routeGUID", routeGUID) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to delete route", "routeGUID", routeGUID) } return NewHandlerResponse(http.StatusAccepted).WithHeader("Location", presenter.JobURLForRedirects(routeGUID, presenter.RouteDeleteOperation, h.serverURL)), nil @@ -237,14 +237,12 @@ func (h *RouteHandler) RegisterRoutes(router *mux.Router) { func (h *RouteHandler) lookupRouteAndDomain(ctx context.Context, logger logr.Logger, authInfo authorization.Info, routeGUID string) (repositories.RouteRecord, error) { route, err := h.routeRepo.GetRoute(ctx, authInfo, routeGUID) if err != nil { - logger.Error(err, "Failed to fetch route from Kubernetes", "RouteGUID", routeGUID) - return repositories.RouteRecord{}, apierrors.ForbiddenAsNotFound(err) + return repositories.RouteRecord{}, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "Failed to fetch route from Kubernetes", "RouteGUID", routeGUID) } domain, err := h.domainRepo.GetDomain(ctx, authInfo, route.Domain.GUID) if err != nil { - logger.Error(err, "Failed to fetch domain from Kubernetes", "DomainGUID", route.Domain.GUID) - return repositories.RouteRecord{}, apierrors.ForbiddenAsNotFound(err) + return repositories.RouteRecord{}, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "Failed to fetch domain from Kubernetes", "DomainGUID", route.Domain.GUID) } route = route.UpdateDomainRef(domain) @@ -266,7 +264,6 @@ func (h *RouteHandler) lookupRouteAndDomainList(ctx context.Context, authInfo au if !has { domainRecord, err = h.domainRepo.GetDomain(ctx, authInfo, currentDomainGUID) if err != nil { - // err = errors.New("resource not found for route's specified domain ref") return []repositories.RouteRecord{}, err } domainGUIDToDomainRecord[currentDomainGUID] = domainRecord diff --git a/api/handlers/service_binding_handler.go b/api/handlers/service_binding_handler.go index 84327d133..2569c6fa2 100644 --- a/api/handlers/service_binding_handler.go +++ b/api/handlers/service_binding_handler.go @@ -52,30 +52,31 @@ func NewServiceBindingHandler(serverURL url.URL, serviceBindingRepo CFServiceBin func (h *ServiceBindingHandler) createHandler(ctx context.Context, logger logr.Logger, authInfo authorization.Info, r *http.Request) (*HandlerResponse, error) { var payload payloads.ServiceBindingCreate if err := h.decoderValidator.DecodeAndValidateJSONPayload(r, &payload); err != nil { - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "failed to decode payload") } app, err := h.appRepo.GetApp(ctx, authInfo, payload.Relationships.App.Data.GUID) if err != nil { - logger.Error(err, fmt.Sprintf("failed to get %s", repositories.AppResourceType)) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, fmt.Sprintf("failed to get %s", repositories.AppResourceType)) } serviceInstance, err := h.serviceInstanceRepo.GetServiceInstance(ctx, authInfo, payload.Relationships.ServiceInstance.Data.GUID) if err != nil { - logger.Error(err, fmt.Sprintf("failed to get %s", repositories.ServiceInstanceResourceType)) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, fmt.Sprintf("failed to get %s", repositories.ServiceInstanceResourceType)) } if app.SpaceGUID != serviceInstance.SpaceGUID { - logger.Info("App and ServiceInstance in different spaces", "App GUID", app.GUID, "ServiceInstance GUID", serviceInstance.GUID) - return nil, apierrors.NewUnprocessableEntityError(err, "The service instance and the app are in different spaces") + return nil, apierrors.LogAndReturn( + logger, + apierrors.NewUnprocessableEntityError(nil, "The service instance and the app are in different spaces"), + "App and ServiceInstance in different spaces", "App GUID", app.GUID, + "ServiceInstance GUID", serviceInstance.GUID, + ) } serviceBinding, err := h.serviceBindingRepo.CreateServiceBinding(ctx, authInfo, payload.ToMessage(app.SpaceGUID)) if err != nil { - logger.Error(err, "failed to create ServiceBinding", "App GUID", app.GUID, "ServiceInstance GUID", serviceInstance.GUID) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "failed to create ServiceBinding", "App GUID", app.GUID, "ServiceInstance GUID", serviceInstance.GUID) } return NewHandlerResponse(http.StatusCreated).WithBody(presenter.ForServiceBinding(serviceBinding, h.serverURL)), nil @@ -87,8 +88,7 @@ func (h *ServiceBindingHandler) deleteHandler(ctx context.Context, logger logr.L err := h.serviceBindingRepo.DeleteServiceBinding(ctx, authInfo, serviceBindingGUID) if err != nil { - logger.Error(err, "error when deleting service binding", "guid", serviceBindingGUID) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "error when deleting service binding", "guid", serviceBindingGUID) } return NewHandlerResponse(http.StatusNoContent), nil @@ -96,21 +96,18 @@ func (h *ServiceBindingHandler) deleteHandler(ctx context.Context, logger logr.L func (h *ServiceBindingHandler) listHandler(ctx context.Context, logger logr.Logger, authInfo authorization.Info, r *http.Request) (*HandlerResponse, error) { if err := r.ParseForm(); err != nil { - logger.Error(err, "Unable to parse request query parameters") - return nil, apierrors.NewUnprocessableEntityError(err, "unable to parse query") + return nil, apierrors.LogAndReturn(logger, apierrors.NewUnprocessableEntityError(err, "unable to parse query"), "Unable to parse request query parameters") } listFilter := new(payloads.ServiceBindingList) err := payloads.Decode(listFilter, r.Form) if err != nil { - logger.Error(err, "Unable to decode request query parameters") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Unable to decode request query parameters") } serviceBindingList, err := h.serviceBindingRepo.ListServiceBindings(ctx, authInfo, listFilter.ToMessage()) if err != nil { - logger.Error(err, fmt.Sprintf("failed to list %s", repositories.ServiceBindingResourceType)) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, fmt.Sprintf("failed to list %s", repositories.ServiceBindingResourceType)) } var appRecords []repositories.AppRecord @@ -123,8 +120,7 @@ func (h *ServiceBindingHandler) listHandler(ctx context.Context, logger logr.Log appRecords, err = h.appRepo.ListApps(ctx, authInfo, listAppsMessage) if err != nil { - logger.Error(err, fmt.Sprintf("failed to list %s", repositories.AppResourceType)) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, fmt.Sprintf("failed to list %s", repositories.AppResourceType)) } } diff --git a/api/handlers/service_instance_handler.go b/api/handlers/service_instance_handler.go index 2daacab2f..94ffeaaf9 100644 --- a/api/handlers/service_instance_handler.go +++ b/api/handlers/service_instance_handler.go @@ -62,20 +62,23 @@ func NewServiceInstanceHandler( func (h *ServiceInstanceHandler) serviceInstanceCreateHandler(ctx context.Context, logger logr.Logger, authInfo authorization.Info, r *http.Request) (*HandlerResponse, error) { var payload payloads.ServiceInstanceCreate if err := h.decoderValidator.DecodeAndValidateJSONPayload(r, &payload); err != nil { - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "failed to decode payload") } spaceGUID := payload.Relationships.Space.Data.GUID _, err := h.spaceRepo.GetSpace(ctx, authInfo, spaceGUID) if err != nil { - logger.Error(err, "Failed to fetch namespace from Kubernetes", "spaceGUID", spaceGUID) - return nil, apierrors.AsUnprocessableEntity(err, "Invalid space. Ensure that the space exists and you have access to it.", apierrors.NotFoundError{}, apierrors.ForbiddenError{}) + return nil, apierrors.LogAndReturn( + logger, + apierrors.AsUnprocessableEntity(err, "Invalid space. Ensure that the space exists and you have access to it.", apierrors.NotFoundError{}, apierrors.ForbiddenError{}), + "Failed to fetch namespace from Kubernetes", + "spaceGUID", spaceGUID, + ) } serviceInstanceRecord, err := h.serviceInstanceRepo.CreateServiceInstance(ctx, authInfo, payload.ToServiceInstanceCreateMessage()) if err != nil { - logger.Error(err, "Failed to create service instance", "Service Instance Name", serviceInstanceRecord.Name) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to create service instance", "Service Instance Name", serviceInstanceRecord.Name) } return NewHandlerResponse(http.StatusCreated).WithBody(presenter.ForServiceInstance(serviceInstanceRecord, h.serverURL)), nil @@ -83,8 +86,7 @@ func (h *ServiceInstanceHandler) serviceInstanceCreateHandler(ctx context.Contex func (h *ServiceInstanceHandler) serviceInstanceListHandler(ctx context.Context, logger logr.Logger, authInfo authorization.Info, r *http.Request) (*HandlerResponse, error) { if err := r.ParseForm(); err != nil { - logger.Error(err, "Unable to parse request query parameters") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Unable to parse request query parameters") } for k := range r.Form { @@ -96,14 +98,12 @@ func (h *ServiceInstanceHandler) serviceInstanceListHandler(ctx context.Context, listFilter := new(payloads.ServiceInstanceList) err := payloads.Decode(listFilter, r.Form) if err != nil { - logger.Error(err, "Unable to decode request query parameters") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Unable to decode request query parameters") } serviceInstanceList, err := h.serviceInstanceRepo.ListServiceInstances(ctx, authInfo, listFilter.ToMessage()) if err != nil { - logger.Error(err, "Failed to list service instance") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to list service instance") } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForServiceInstanceList(serviceInstanceList, h.serverURL, *r.URL)), nil @@ -115,8 +115,7 @@ func (h *ServiceInstanceHandler) serviceInstanceDeleteHandler(ctx context.Contex serviceInstance, err := h.serviceInstanceRepo.GetServiceInstance(ctx, authInfo, serviceInstanceGUID) if err != nil { - logger.Error(err, "failed to get service instance") - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "failed to get service instance") } err = h.serviceInstanceRepo.DeleteServiceInstance(ctx, authInfo, repositories.DeleteServiceInstanceMessage{ @@ -124,8 +123,7 @@ func (h *ServiceInstanceHandler) serviceInstanceDeleteHandler(ctx context.Contex SpaceGUID: serviceInstance.SpaceGUID, }) if err != nil { - logger.Error(err, "error when deleting service instance", "guid", serviceInstanceGUID) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "error when deleting service instance", "guid", serviceInstanceGUID) } return NewHandlerResponse(http.StatusNoContent), nil diff --git a/api/handlers/shared.go b/api/handlers/shared.go index 3ef9d1d84..be388dec4 100644 --- a/api/handlers/shared.go +++ b/api/handlers/shared.go @@ -19,13 +19,10 @@ import ( "golang.org/x/text/cases" "golang.org/x/text/language" "gopkg.in/yaml.v3" - ctrl "sigs.k8s.io/controller-runtime" ) //go:generate go run github.com/maxbrunsfeld/counterfeiter/v6 -generate -var Logger = ctrl.Log.WithName("Shared Handler Functions") - type DecoderValidator struct { validator *validator.Validate translator ut.Translator @@ -53,14 +50,11 @@ func (dv *DecoderValidator) DecodeAndValidateJSONPayload(r *http.Request, object switch { case errors.As(err, &unmarshalTypeError): titler := cases.Title(language.AmericanEnglish) - Logger.Error(err, fmt.Sprintf("Request body contains an invalid value for the %q field (should be of type %v)", titler.String(unmarshalTypeError.Field), unmarshalTypeError.Type)) return apierrors.NewUnprocessableEntityError(err, fmt.Sprintf("%v must be a %v", titler.String(unmarshalTypeError.Field), unmarshalTypeError.Type)) case strings.HasPrefix(err.Error(), "json: unknown field"): // check whether the message matches an "unknown field" error. If so, 422. Else, 400 - Logger.Error(err, fmt.Sprintf("Unknown field in JSON body: %T: %q", err, err.Error())) return apierrors.NewUnprocessableEntityError(err, fmt.Sprintf("invalid request body: %s", err.Error())) default: - Logger.Error(err, fmt.Sprintf("Unable to parse the JSON body: %T: %q", err, err.Error())) return apierrors.NewMessageParseError(err) } } @@ -74,7 +68,6 @@ func (dv *DecoderValidator) DecodeAndValidateYAMLPayload(r *http.Request, object decoder.KnownFields(false) // TODO: change this to true once we've added all manifest fields to payloads.Manifest err := decoder.Decode(object) if err != nil { - Logger.Error(err, fmt.Sprintf("Unable to parse the YAML body: %T: %q", err, err.Error())) return apierrors.NewMessageParseError(err) } diff --git a/api/handlers/space_handler.go b/api/handlers/space_handler.go index b0c150f66..24d4e30d7 100644 --- a/api/handlers/space_handler.go +++ b/api/handlers/space_handler.go @@ -52,15 +52,18 @@ func NewSpaceHandler(apiBaseURL url.URL, imageRegistrySecretName string, spaceRe func (h *SpaceHandler) spaceCreateHandler(ctx context.Context, logger logr.Logger, authInfo authorization.Info, r *http.Request) (*HandlerResponse, error) { var payload payloads.SpaceCreate if err := h.decoderValidator.DecodeAndValidateJSONPayload(r, &payload); err != nil { - logger.Error(err, "Failed to decode and validate payload") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to decode and validate payload") } space := payload.ToMessage(h.imageRegistrySecretName) record, err := h.spaceRepo.CreateSpace(ctx, authInfo, space) if err != nil { - logger.Error(err, "Failed to create space", "Space Name", space.Name) - return nil, apierrors.AsUnprocessableEntity(err, "Invalid organization. Ensure the organization exists and you have access to it.", apierrors.NotFoundError{}) + return nil, apierrors.LogAndReturn( + logger, + apierrors.AsUnprocessableEntity(err, "Invalid organization. Ensure the organization exists and you have access to it.", apierrors.NotFoundError{}), + "Failed to create space", + "Space Name", space.Name, + ) } spaceResponse := presenter.ForCreateSpace(record, h.apiBaseURL) @@ -76,8 +79,7 @@ func (h *SpaceHandler) spaceListHandler(ctx context.Context, logger logr.Logger, Names: names, }) if err != nil { - logger.Error(err, "Failed to fetch spaces") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to fetch spaces") } spaceList := presenter.ForSpaceList(spaces, h.apiBaseURL, *r.URL) @@ -90,8 +92,7 @@ func (h *SpaceHandler) spaceDeleteHandler(ctx context.Context, logger logr.Logge spaceRecord, err := h.spaceRepo.GetSpace(ctx, authInfo, spaceGUID) if err != nil { - logger.Error(err, "Failed to fetch space", "SpaceGUID", spaceGUID) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to fetch space", "SpaceGUID", spaceGUID) } deleteSpaceMessage := repositories.DeleteSpaceMessage{ @@ -100,8 +101,7 @@ func (h *SpaceHandler) spaceDeleteHandler(ctx context.Context, logger logr.Logge } err = h.spaceRepo.DeleteSpace(ctx, authInfo, deleteSpaceMessage) if err != nil { - logger.Error(err, "Failed to delete space", "SpaceGUID", spaceGUID) - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Failed to delete space", "SpaceGUID", spaceGUID) } return NewHandlerResponse(http.StatusAccepted).WithHeader("Location", presenter.JobURLForRedirects(spaceGUID, presenter.SpaceDeleteOperation, h.apiBaseURL)), nil diff --git a/api/handlers/space_manifest_handler.go b/api/handlers/space_manifest_handler.go index 13a923f74..91cb81606 100644 --- a/api/handlers/space_manifest_handler.go +++ b/api/handlers/space_manifest_handler.go @@ -69,12 +69,11 @@ func (h *SpaceManifestHandler) applyManifestHandler(ctx context.Context, logger spaceGUID := vars["spaceGUID"] var manifest payloads.Manifest if err := h.decoderValidator.DecodeAndValidateYAMLPayload(r, &manifest); err != nil { - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "failed to decode payload") } if err := h.manifestApplier.Apply(ctx, authInfo, spaceGUID, manifest); err != nil { - logger.Error(err, "Error applying manifest") - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "Error applying manifest") } return NewHandlerResponse(http.StatusAccepted). @@ -86,8 +85,7 @@ func (h *SpaceManifestHandler) diffManifestHandler(ctx context.Context, logger l spaceGUID := vars["spaceGUID"] if _, err := h.spaceRepo.GetSpace(r.Context(), authInfo, spaceGUID); err != nil { - logger.Error(err, "failed to get space", "guid", spaceGUID) - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "failed to get space", "guid", spaceGUID) } return NewHandlerResponse(http.StatusAccepted).WithBody(map[string]interface{}{"diff": []string{}}), nil diff --git a/api/handlers/task_handler.go b/api/handlers/task_handler.go index 84ac07364..c2f37027c 100644 --- a/api/handlers/task_handler.go +++ b/api/handlers/task_handler.go @@ -61,7 +61,7 @@ func (h *TaskHandler) taskGetHandler(ctx context.Context, logger logr.Logger, au taskRecord, err := h.taskRepo.GetTask(ctx, authInfo, taskGUID) if err != nil { - return nil, apierrors.ForbiddenAsNotFound(err) + return nil, apierrors.LogAndReturn(logger, apierrors.ForbiddenAsNotFound(err), "failed to get task", "taskGUID", taskGUID) } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForTask(taskRecord, h.serverURL)), nil @@ -82,7 +82,7 @@ func (h *TaskHandler) taskCreateHandler(ctx context.Context, logger logr.Logger, var payload payloads.TaskCreate if err := h.decoderValidator.DecodeAndValidateJSONPayload(r, &payload); err != nil { - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "failed to decode payload") } appRecord, err := h.appRepo.GetApp(ctx, authInfo, appGUID) diff --git a/api/handlers/whoami_handler.go b/api/handlers/whoami_handler.go index 11611a835..e7689aea2 100644 --- a/api/handlers/whoami_handler.go +++ b/api/handlers/whoami_handler.go @@ -5,6 +5,7 @@ import ( "net/http" "net/url" + "code.cloudfoundry.org/korifi/api/apierrors" "code.cloudfoundry.org/korifi/api/authorization" "code.cloudfoundry.org/korifi/api/presenter" "github.com/go-logr/logr" @@ -39,9 +40,7 @@ func NewWhoAmI(identityProvider IdentityProvider, apiBaseURL url.URL) *WhoAmIHan func (h *WhoAmIHandler) whoAmIHandler(ctx context.Context, logger logr.Logger, authInfo authorization.Info, r *http.Request) (*HandlerResponse, error) { identity, err := h.identityProvider.GetIdentity(r.Context(), authInfo) if err != nil { - logger.Info("failed to get identity", "err", err) - - return nil, err + return nil, apierrors.LogAndReturn(logger, err, "failed to get identity") } return NewHandlerResponse(http.StatusOK).WithBody(presenter.ForWhoAmI(identity)), nil diff --git a/api/repositories/pod_repository.go b/api/repositories/pod_repository.go index da5366512..298de7b0c 100644 --- a/api/repositories/pod_repository.go +++ b/api/repositories/pod_repository.go @@ -365,7 +365,7 @@ func (r *PodRepo) GetRuntimeLogsForApp(ctx context.Context, logger logr.Logger, logReadCloser, err = k8sClient.CoreV1().Pods(message.SpaceGUID).GetLogs(pod.Name, &corev1.PodLogOptions{Timestamps: true, TailLines: &message.Limit}).Stream(ctx) if err != nil { // untested - logger.Error(err, fmt.Sprintf("failed to fetch logs for pod: %s", pod.Name)) + logger.Info(fmt.Sprintf("failed to fetch logs for pod: %s", pod.Name), "err", err) continue }