From 621c04a6ecfab039b17ebd2c883c04e4a04224de Mon Sep 17 00:00:00 2001 From: Julien Perrochet Date: Thu, 21 Mar 2024 10:54:47 +0100 Subject: [PATCH] [scd] minimal implementation for the dss report handler (#1012) * [scd] minimal implementation for the dss report handler * PR comments --- cmds/core-service/main.go | 7 ++-- pkg/scd/dss_report_handler.go | 77 +++++++++++++++++++++++++++++++++++ pkg/scd/server.go | 25 ++---------- 3 files changed, 85 insertions(+), 24 deletions(-) create mode 100644 pkg/scd/dss_report_handler.go diff --git a/cmds/core-service/main.go b/cmds/core-service/main.go index ad138887c..2b3b129b0 100644 --- a/cmds/core-service/main.go +++ b/cmds/core-service/main.go @@ -197,9 +197,10 @@ func createSCDServer(ctx context.Context, logger *zap.Logger) (*scd.Server, erro scdCron.Start() return &scd.Server{ - Store: scdStore, - Timeout: *timeout, - EnableHTTP: *enableHTTP, + Store: scdStore, + DSSReportHandler: &scd.JSONLoggingReceivedReportHandler{ReportLogger: logger}, + Timeout: *timeout, + EnableHTTP: *enableHTTP, }, nil } diff --git a/pkg/scd/dss_report_handler.go b/pkg/scd/dss_report_handler.go new file mode 100644 index 000000000..ffd2aa2f2 --- /dev/null +++ b/pkg/scd/dss_report_handler.go @@ -0,0 +1,77 @@ +package scd + +import ( + "context" + "encoding/json" + "github.com/google/uuid" + "github.com/interuss/dss/pkg/api" + restapi "github.com/interuss/dss/pkg/api/scdv1" + dsserr "github.com/interuss/dss/pkg/errors" + "github.com/interuss/dss/pkg/logging" + "github.com/interuss/stacktrace" + "go.uber.org/zap" +) + +// ReceivedReportHandler takes care of handling a DSS report received through the MakeDssReport REST handler. +type ReceivedReportHandler interface { + // Handle a DSS report request. Returns the error report passed in 'req' after having set its identifier. + Handle(ctx context.Context, req *restapi.MakeDssReportRequest) (*restapi.ErrorReport, error) +} + +// JSONLoggingReceivedReportHandler a DSSReportHandler that simply logs the received report as JSON. +type JSONLoggingReceivedReportHandler struct { + // ReportLogger is the logger to which the received reports will be logged. + ReportLogger *zap.Logger +} + +// HandleDssReport logs the received report as a JSON string to a logger. +func (h *JSONLoggingReceivedReportHandler) Handle(ctx context.Context, req *restapi.MakeDssReportRequest) (*restapi.ErrorReport, error) { + reportID, err := uuid.NewRandom() + if err != nil { + return nil, stacktrace.Propagate(err, "Failed to generate report ID") + } + rVal := req.Body + reportIDStr := reportID.String() + rVal.ReportId = &reportIDStr + // Serialize the report to a JSON string: + jsonReport, err := json.Marshal(req.Body) + if err != nil { + logging.WithValuesFromContext(ctx, logging.Logger).Error("Failed to serialize DSS Report", zap.Error(err)) + return nil, stacktrace.PropagateWithCode(err, dsserr.BadRequest, "Failed to serialize DSS Report") + } + h.ReportLogger.Info("Received DSS Report", zap.String("reportID", reportIDStr), zap.String("report", string(jsonReport))) + return rVal, nil +} + +// MakeDssReport creates an error report about a DSS. +func (a *Server) MakeDssReport(ctx context.Context, req *restapi.MakeDssReportRequest, +) restapi.MakeDssReportResponseSet { + if req.Auth.Error != nil { + resp := restapi.MakeDssReportResponseSet{} + setAuthError(ctx, stacktrace.Propagate(req.Auth.Error, "Auth failed"), &resp.Response401, &resp.Response403, &resp.Response500) + return resp + } + + if req.BodyParseError != nil { + return restapi.MakeDssReportResponseSet{Response400: &restapi.ErrorResponse{ + Message: dsserr.Handle(ctx, stacktrace.PropagateWithCode(req.BodyParseError, dsserr.BadRequest, "Malformed params"))}} + } + + report, err := a.DSSReportHandler.Handle(ctx, req) + + if err != nil { + err = stacktrace.Propagate(err, "Could not delete operational intent") + errResp := &restapi.ErrorResponse{Message: dsserr.Handle(ctx, err)} + switch stacktrace.GetCode(err) { + case dsserr.BadRequest: + return restapi.MakeDssReportResponseSet{Response400: errResp} + case dsserr.PermissionDenied: + return restapi.MakeDssReportResponseSet{Response403: errResp} + default: + return restapi.MakeDssReportResponseSet{Response500: &api.InternalServerErrorBody{ + ErrorMessage: *dsserr.Handle(ctx, err)}} + } + } + + return restapi.MakeDssReportResponseSet{Response201: report} +} diff --git a/pkg/scd/server.go b/pkg/scd/server.go index 6b88fcd83..8254a5681 100644 --- a/pkg/scd/server.go +++ b/pkg/scd/server.go @@ -35,27 +35,10 @@ func makeSubscribersToNotify(subscriptions []*scdmodels.Subscription) []restapi. // Server implements scdv1.Implementation. type Server struct { - Store scdstore.Store - Timeout time.Duration - EnableHTTP bool -} - -// MakeDssReport creates an error report about a DSS. -func (a *Server) MakeDssReport(ctx context.Context, req *restapi.MakeDssReportRequest, -) restapi.MakeDssReportResponseSet { - if req.Auth.Error != nil { - resp := restapi.MakeDssReportResponseSet{} - setAuthError(ctx, stacktrace.Propagate(req.Auth.Error, "Auth failed"), &resp.Response401, &resp.Response403, &resp.Response500) - return resp - } - - if req.BodyParseError != nil { - return restapi.MakeDssReportResponseSet{Response400: &restapi.ErrorResponse{ - Message: dsserr.Handle(ctx, stacktrace.PropagateWithCode(req.BodyParseError, dsserr.BadRequest, "Malformed params"))}} - } - - return restapi.MakeDssReportResponseSet{Response400: &restapi.ErrorResponse{ - Message: dsserr.Handle(ctx, stacktrace.NewErrorWithCode(dsserr.BadRequest, "Not yet implemented"))}} + Store scdstore.Store + DSSReportHandler ReceivedReportHandler + Timeout time.Duration + EnableHTTP bool } func setAuthError(ctx context.Context, authErr error, resp401, resp403 **restapi.ErrorResponse, resp500 **api.InternalServerErrorBody) {