From e793d591e8b4e8d81a26a825642a84e0d83d49b2 Mon Sep 17 00:00:00 2001 From: John Wregglesworth Date: Thu, 23 May 2024 14:33:52 -0700 Subject: [PATCH 01/14] Begin adding http support to subscriptions --- app/app.go | 37 ++++++++++++++++++++++- common/main.go | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 8 +++++ go.sum | 19 ++++++++++++ main.go | 6 ++-- 5 files changed, 147 insertions(+), 4 deletions(-) create mode 100644 common/main.go diff --git a/app/app.go b/app/app.go index cbb1148..9fc5ef3 100644 --- a/app/app.go +++ b/app/app.go @@ -3,15 +3,18 @@ package app import ( "context" "fmt" + "net/http" "strings" "github.com/cyverse-de/go-mod/logging" "github.com/cyverse-de/go-mod/pbinit" "github.com/cyverse-de/p/go/qms" + "github.com/cyverse-de/subscriptions/common" "github.com/cyverse-de/subscriptions/db" "github.com/cyverse-de/subscriptions/errors" "github.com/cyverse-de/subscriptions/natscl" "github.com/jmoiron/sqlx" + "github.com/labstack/echo/v4" "github.com/samber/lo" "github.com/sirupsen/logrus" "google.golang.org/protobuf/types/known/timestamppb" @@ -22,17 +25,45 @@ var log = logging.Log.WithFields(logrus.Fields{"package": "apps"}) type App struct { client *natscl.Client db *sqlx.DB + Router *echo.Echo userSuffix string ReportOverages bool } func New(client *natscl.Client, db *sqlx.DB, userSuffix string) *App { - return &App{ + app := &App{ client: client, db: db, userSuffix: userSuffix, + Router: echo.New(), ReportOverages: true, } + + app.Router.HTTPErrorHandler = func(err error, c echo.Context) { + code := http.StatusInternalServerError + var body interface{} + + switch err := err.(type) { + case common.ErrorResponse: + code = http.StatusBadRequest + body = err + case *common.ErrorResponse: + code = http.StatusBadRequest + body = err + case *echo.HTTPError: + echoErr := err + code = echoErr.Code + body = common.NewErrorResponse(err) + default: + body = common.NewErrorResponse(err) + } + + c.JSON(code, body) // nolint:errcheck + } + + app.Router.GET("/", app.GreetingHTTPHandler).Name = "greeting" + + return app } func (a *App) FixUsername(username string) (string, error) { @@ -84,6 +115,10 @@ func (a *App) validateUpdate(request *qms.AddUpdateRequest) (string, error) { return username, nil } +func (a *App) GreetingHTTPHandler(ctx echo.Context) error { + return ctx.String(http.StatusOK, "Hello from subscriptions.") +} + func (a *App) GetUserUpdatesHandler(subject, reply string, request *qms.UpdateListRequest) { var err error diff --git a/common/main.go b/common/main.go new file mode 100644 index 0000000..9e2f38e --- /dev/null +++ b/common/main.go @@ -0,0 +1,81 @@ +package common + +import ( + "encoding/json" + "net/http" + + "github.com/sirupsen/logrus" +) + +// Log contains the default logger to use. +var Log = logrus.WithFields(logrus.Fields{ + "service": "subscriptions", + "art-id": "subscriptions", + "group": "org.cyverse", +}) + +// ErrorResponse represents an HTTP response body containing error information. This type implements +// the error interface so that it can be returned as an error from from existing functions. +// +// swagger:response errorResponse +type ErrorResponse struct { + Message string `json:"message"` + ErrorCode string `json:"error_code,omitempty"` + Details *map[string]interface{} `json:"details,omitempty"` +} + +// ErrorBytes returns a byte-array representation of an ErrorResponse. +func (e ErrorResponse) ErrorBytes() []byte { + bytes, err := json.Marshal(e) + if err != nil { + Log.Errorf("unable to marshal %+v as JSON", e) + return make([]byte, 0) + } + return bytes +} + +// Error returns a string representation of an ErrorResponse. +func (e ErrorResponse) Error() string { + return string(e.ErrorBytes()) +} + +// DetailedError responds to an HTTP request with a JSON response body indicating that an error +// occurred and providing some extra details about the error if additional details are available. +func DetailedError(writer http.ResponseWriter, cause error, code int) { + writer.Header().Set("Content-Type", "application/json") + + // Handle both instances of ErrorResponse and generic errors. + var errorResponse ErrorResponse + switch val := cause.(type) { + case ErrorResponse: + errorResponse = val + case error: + errorResponse = ErrorResponse{Message: val.Error()} + } + + // Return the response. + writer.WriteHeader(code) + _, err := writer.Write(errorResponse.ErrorBytes()) + if err != nil { + Log.Errorf("unable to write response body for error: %+v", cause) + return + } +} + +// Error responds to an HTTP request with a JSON response body indicating that an error occurred. +func Error(writer http.ResponseWriter, message string, code int) { + DetailedError(writer, ErrorResponse{Message: message}, code) +} + +// NewErrorResponse constructs an ErrorResponse based on the message passed in, but does not send +// it over the wire. This is to aid in converting to labstack/echo. +func NewErrorResponse(err error) ErrorResponse { + var errorResponse ErrorResponse + switch val := err.(type) { + case ErrorResponse: + errorResponse = val + case error: + errorResponse = ErrorResponse{Message: val.Error()} + } + return errorResponse +} diff --git a/go.mod b/go.mod index e5d8e62..abb4974 100644 --- a/go.mod +++ b/go.mod @@ -40,18 +40,26 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/joho/godotenv v1.5.1 // indirect github.com/klauspost/compress v1.17.8 // indirect + github.com/labstack/echo/v4 v4.12.0 // indirect + github.com/labstack/gommon v0.4.2 // indirect github.com/magiconair/properties v1.8.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/nats-io/nkeys v0.4.7 // indirect github.com/nats-io/nuid v1.0.1 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasttemplate v1.2.2 // indirect go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect go.opentelemetry.io/otel/metric v1.26.0 // indirect go.opentelemetry.io/otel/sdk v1.26.0 // indirect go.opentelemetry.io/otel/trace v1.26.0 // indirect golang.org/x/crypto v0.23.0 // indirect golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect + golang.org/x/net v0.24.0 // indirect golang.org/x/sys v0.20.0 // indirect + golang.org/x/text v0.15.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index fb65007..dfdd2f0 100644 --- a/go.sum +++ b/go.sum @@ -211,6 +211,10 @@ github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfn github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0= +github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM= +github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= +github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.1/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= @@ -220,11 +224,16 @@ github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3v github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.7 h1:fxWBnXkxfM6sRiuH3bqJ4CfzZojMOLVc0UTsTglEghA= github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= @@ -327,6 +336,10 @@ github.com/uptrace/opentelemetry-go-extra/otelsqlx v0.2.3 h1:KEX51LW1+n8bjRoTl4k github.com/uptrace/opentelemetry-go-extra/otelsqlx v0.2.3/go.mod h1:0sguCDru7+Ik9OFJYIgAS8NpUFOoGOCsdU4r311ZrlY= github.com/uptrace/opentelemetry-go-extra/otelsqlx v0.2.4 h1:Pt/+CUTRusJb471SBXwkRCz+9pbOjNr80M6LlwqV07w= github.com/uptrace/opentelemetry-go-extra/otelsqlx v0.2.4/go.mod h1:kQgNoghy4K/wguxbOd/u0OJw/Y0maNPc7PF4JpEGeUc= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo= +github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= @@ -395,6 +408,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -438,6 +453,8 @@ golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= @@ -449,6 +466,8 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/main.go b/main.go index 6497a60..5260e0c 100644 --- a/main.go +++ b/main.go @@ -143,7 +143,7 @@ func main() { a := app.New(natsClient, dbconn, userSuffix) - handlers := map[string]nats.Handler{ + natsHandlers := map[string]nats.Handler{ qmssubs.GetUserUpdates: a.GetUserUpdatesHandler, qmssubs.AddUserUpdate: a.AddUserUpdateHandler, @@ -175,12 +175,12 @@ func main() { qmssubs.GetSubscriptionAddon: a.GetSubscriptionAddonHandler, } - for subject, handler := range handlers { + for subject, handler := range natsHandlers { if err = natsClient.Subscribe(subject, handler); err != nil { log.Fatal(err) } } srv := fmt.Sprintf(":%s", strconv.Itoa(*listenPort)) - log.Fatal(http.ListenAndServe(srv, nil)) + log.Fatal(http.ListenAndServe(srv, a.Router)) } From 995ad07f4c149d34994123b2a84b43b522502148 Mon Sep 17 00:00:00 2001 From: John Wregglesworth Date: Fri, 24 May 2024 09:59:11 -0700 Subject: [PATCH 02/14] Add handler for getting the user summary via HTTP --- app/app.go | 1 + 1 file changed, 1 insertion(+) diff --git a/app/app.go b/app/app.go index 9fc5ef3..0be89be 100644 --- a/app/app.go +++ b/app/app.go @@ -62,6 +62,7 @@ func New(client *natscl.Client, db *sqlx.DB, userSuffix string) *App { } app.Router.GET("/", app.GreetingHTTPHandler).Name = "greeting" + app.Router.GET("/summary/:user", app.GetUserSummaryHTTPHandler) return app } From 0d09316806667e51e0498c0c59765eb032430eea Mon Sep 17 00:00:00 2001 From: John Wregglesworth Date: Tue, 28 May 2024 13:17:26 -0700 Subject: [PATCH 03/14] Add user summary HTTP handler --- app/summary.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/app/summary.go b/app/summary.go index 64080ae..471e4d9 100644 --- a/app/summary.go +++ b/app/summary.go @@ -3,11 +3,13 @@ package app import ( "context" "fmt" + "net/http" "github.com/cyverse-de/go-mod/pbinit" "github.com/cyverse-de/p/go/qms" "github.com/cyverse-de/subscriptions/db" "github.com/cyverse-de/subscriptions/errors" + "github.com/labstack/echo/v4" "github.com/sirupsen/logrus" ) @@ -124,3 +126,28 @@ func (a *App) GetUserSummaryHandler(subject, reply string, request *qms.RequestB log.Error(err) } } + +func (a *App) GetUserSummaryHTTPHandler(c echo.Context) error { + var err error + + log := log.WithFields(logrus.Fields{"context": "user summary http"}) + ctx := c.Request().Context() + response := pbinit.NewSubscriptionResponse() + + username := c.Param("user") + + username, err = a.FixUsername(username) + if err != nil { + return err + } + + log = log.WithFields(logrus.Fields{"user": username}) + + subscription, err := a.GetUserSummary(ctx, username) + if err != nil { + return err + } + + response.Subscription = subscription + return c.JSON(http.StatusOK, response) +} From 3299b4813e30b7833ecdee4d77dbcfec870d5707 Mon Sep 17 00:00:00 2001 From: John Wregglesworth Date: Tue, 28 May 2024 13:18:09 -0700 Subject: [PATCH 04/14] Split out application logic from the handlers. Makes the logic reusable in HTTP handlers --- app/addons.go | 392 +++++++++++++++++++++++++++++--------------------- 1 file changed, 232 insertions(+), 160 deletions(-) diff --git a/app/addons.go b/app/addons.go index 7bc3b1e..21af5f1 100644 --- a/app/addons.go +++ b/app/addons.go @@ -55,45 +55,38 @@ func (a *App) sendSubscriptionAddonResponseError(reply string, log *logrus.Entry } } -func (a *App) AddAddonHandler(subject, reply string, request *qms.AddAddonRequest) { - var err error - - ctx, span := qmsinit.InitAddAddonRequest(request, subject) - defer span.End() - - log := log.WithField("context", "adding new available addon") - response := qmsinit.NewAddonResponse() - sendError := a.sendAddonResponseError(reply, log) +func (a *App) addAddon(ctx context.Context, request *qms.AddAddonRequest) *qms.AddonResponse { d := db.New(a.db) reqAddon := request.Addon + response := qmsinit.NewAddonResponse() if reqAddon.Name == "" { - sendError(ctx, response, errors.New("name must be set")) - return + response.Error = serrors.NatsError(ctx, errors.New("name must be set")) + return response } if reqAddon.Description == "" { - sendError(ctx, response, errors.New("descriptions must be set")) - return + response.Error = serrors.NatsError(ctx, errors.New("descriptions must be set")) + return response } if reqAddon.DefaultAmount <= 0.0 { - sendError(ctx, response, errors.New("default_amount must be greater than 0.0")) - return + response.Error = serrors.NatsError(ctx, errors.New("default_amount must be greater than 0.0")) + return response } if reqAddon.ResourceType.Name == "" && reqAddon.ResourceType.Uuid == "" { - sendError(ctx, response, errors.New("resource_type.name or resource_type.uuid must be set")) - return + response.Error = serrors.NatsError(ctx, errors.New("resource_type.name or resource_type.uuid must be set")) + return response } var lookupRT *db.ResourceType tx, err := d.Begin() if err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } defer func() { _ = tx.Rollback() @@ -102,14 +95,14 @@ func (a *App) AddAddonHandler(subject, reply string, request *qms.AddAddonReques if reqAddon.ResourceType.Name != "" && reqAddon.ResourceType.Uuid == "" { lookupRT, err = d.GetResourceTypeByName(ctx, reqAddon.ResourceType.Name, db.WithTX(tx)) if err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } } else { lookupRT, err = d.GetResourceType(ctx, reqAddon.ResourceType.Uuid, db.WithTX(tx)) if err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } } @@ -118,23 +111,55 @@ func (a *App) AddAddonHandler(subject, reply string, request *qms.AddAddonReques newID, err := d.AddAddon(ctx, newAddon, db.WithTX(tx)) if err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } if err = tx.Commit(); err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } response.Addon = newAddon.ToQMSType() response.Addon.Uuid = newID + return response +} + +func (a *App) AddAddonHandler(subject, reply string, request *qms.AddAddonRequest) { + var err error + + ctx, span := qmsinit.InitAddAddonRequest(request, subject) + defer span.End() + + log := log.WithField("context", "adding new available addon") + + response := a.addAddon(ctx, request) + + if response.Error != nil { + log.Error(response.Error.Message) + } if err = a.client.Respond(ctx, reply, response); err != nil { log.Error(err) } } +func (a *App) listAddons(ctx context.Context, request *qms.NoParamsRequest) *qms.AddonListResponse { + response := qmsinit.NewAddonListResponse() + d := db.New(a.db) + + results, err := d.ListAddons(ctx) + if err != nil { + response.Error = serrors.NatsError(ctx, err) + return response + } + + for _, addon := range results { + response.Addons = append(response.Addons, addon.ToQMSType()) + } + return response +} + // ListAddonsHandler lists all of the available add-ons in the system. These are // the ones that can be applied to a subscription, not the ones that have been // applied already. @@ -145,18 +170,11 @@ func (a *App) ListAddonsHandler(subject, reply string, request *qms.NoParamsRequ defer span.End() log := log.WithField("context", "list addons") - sendError := a.sendAddonListResponseError(reply, log) - response := qmsinit.NewAddonListResponse() - d := db.New(a.db) - results, err := d.ListAddons(ctx) - if err != nil { - sendError(ctx, response, err) - return - } + response := a.listAddons(ctx, request) - for _, addon := range results { - response.Addons = append(response.Addons, addon.ToQMSType()) + if response.Error != nil { + log.Error(response.Error.Message) } if err = a.client.Respond(ctx, reply, response); err != nil { @@ -164,171 +182,188 @@ func (a *App) ListAddonsHandler(subject, reply string, request *qms.NoParamsRequ } } -func (a *App) UpdateAddonHandler(subject, reply string, request *qms.UpdateAddonRequest) { - var err error - - log := log.WithField("context", "update addon") - +func (a *App) updateAddon(ctx context.Context, request *qms.UpdateAddonRequest) *qms.AddonResponse { response := qmsinit.NewAddonResponse() - - sendError := func(ctx context.Context, response *qms.AddonResponse, err error) { - log.Error(err) - response.Error = serrors.NatsError(ctx, err) - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } - } - - ctx, span := qmsinit.InitUpdateAddonRequest(request, subject) - defer span.End() - d := db.New(a.db) if request.Addon.Uuid == "" { - sendError(ctx, response, errors.New("uuid must be set in the request")) - return + response.Error = serrors.NatsError(ctx, errors.New("uuid must be set in the request")) + return response } updateAddon := db.NewUpdateAddonFromQMS(request) result, err := d.UpdateAddon(ctx, updateAddon) if err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } response.Addon = result.ToQMSType() - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } + return response } -func (a *App) DeleteAddonHandler(subject, reply string, request *requests.ByUUID) { +func (a *App) UpdateAddonHandler(subject, reply string, request *qms.UpdateAddonRequest) { var err error - log := log.WithField("context", "delete addon") + log := log.WithField("context", "update addon") - response := qmsinit.NewAddonResponse() + ctx, span := qmsinit.InitUpdateAddonRequest(request, subject) + defer span.End() + + response := a.updateAddon(ctx, request) - sendError := func(ctx context.Context, response *qms.AddonResponse, err error) { + if response.Error != nil { + log.Error(response.Error.Message) + } + + if err = a.client.Respond(ctx, reply, response); err != nil { log.Error(err) - response.Error = serrors.NatsError(ctx, err) - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } } +} - ctx, span := reqinit.InitByUUID(request, subject) - defer span.End() +func (a *App) deleteAddon(ctx context.Context, request *requests.ByUUID) *qms.AddonResponse { + response := qmsinit.NewAddonResponse() d := db.New(a.db) subAddons, err := d.ListSubscriptionAddonsByAddonID(ctx, request.Uuid) if err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } if len(subAddons) > 0 { - sendError(ctx, response, serrors.ErrSubscriptionAddonsExist) - return + response.Error = serrors.NatsError(ctx, serrors.ErrSubscriptionAddonsExist) + return response } if err = d.DeleteAddon(ctx, request.Uuid); err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } response.Addon = &qms.Addon{ Uuid: request.Uuid, } - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } + return response } -// ListSubscriptionAddonsHandler lists the add-ons that have been applied to the -// indicated subscription. -func (a *App) ListSubscriptionAddonsHandler(subject, reply string, request *requests.ByUUID) { +func (a *App) DeleteAddonHandler(subject, reply string, request *requests.ByUUID) { var err error + log := log.WithField("context", "delete addon") + ctx, span := reqinit.InitByUUID(request, subject) defer span.End() - log := log.WithField("context", "listing subscription add-ons") + response := a.deleteAddon(ctx, request) + + if response.Error != nil { + log.Error(response.Error.Message) + } + + if err = a.client.Respond(ctx, reply, response); err != nil { + log.Error(err) + } +} + +func (a *App) listSubscriptionAddons(ctx context.Context, request *requests.ByUUID) *qms.SubscriptionAddonListResponse { response := qmsinit.NewSubscriptionAddonListResponse() - sendError := a.sendSubscriptionAddonListResponseError(reply, log) + d := db.New(a.db) results, err := d.ListSubscriptionAddons(ctx, request.Uuid) if err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } for _, addon := range results { response.SubscriptionAddons = append(response.SubscriptionAddons, addon.ToQMSType()) } - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } + return response } -// GetSubscriptionAddonHandler gets a single addon based on it's UUID. -func (a *App) GetSubscriptionAddonHandler(subject, reply string, request *requests.ByUUID) { +// ListSubscriptionAddonsHandler lists the add-ons that have been applied to the +// indicated subscription. +func (a *App) ListSubscriptionAddonsHandler(subject, reply string, request *requests.ByUUID) { var err error ctx, span := reqinit.InitByUUID(request, subject) defer span.End() - log := log.WithField("context", "getting subscription add-on") + log := log.WithField("context", "listing subscription add-ons") + + response := a.listSubscriptionAddons(ctx, request) + if response.Error != nil { + log.Error(response.Error.Message) + } + + if err = a.client.Respond(ctx, reply, response); err != nil { + log.Error(err) + } +} + +func (a *App) getSubscription(ctx context.Context, request *requests.ByUUID) *qms.SubscriptionAddonResponse { response := qmsinit.NewSubscriptionAddonResponse() - sendError := a.sendSubscriptionAddonResponseError(reply, log) + d := db.New(a.db) subAddon, err := d.GetSubscriptionAddonByID(ctx, request.Uuid) if err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } response.SubscriptionAddon = subAddon.ToQMSType() - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } + return response } -func (a *App) AddSubscriptionAddonHandler(subject, reply string, request *requests.AssociateByUUIDs) { +// GetSubscriptionAddonHandler gets a single addon based on it's UUID. +func (a *App) GetSubscriptionAddonHandler(subject, reply string, request *requests.ByUUID) { var err error - ctx, span := reqinit.InitAssociateByUUIDs(request, subject) + ctx, span := reqinit.InitByUUID(request, subject) defer span.End() - log := log.WithField("context", "adding subscription add-on") + log := log.WithField("context", "getting subscription add-on") + + response := a.getSubscription(ctx, request) + + if response.Error != nil { + log.Error(response.Error.Message) + } + + if err = a.client.Respond(ctx, reply, response); err != nil { + log.Error(err) + } +} + +func (a *App) addSubscription(ctx context.Context, request *requests.AssociateByUUIDs) *qms.SubscriptionAddonResponse { response := qmsinit.NewSubscriptionAddonResponse() - sendError := a.sendSubscriptionAddonResponseError(reply, log) d := db.New(a.db) subscriptionID := request.ParentUuid if subscriptionID == "" { - sendError(ctx, response, errors.New("parent_uuid must be set to the subscription UUID")) - return + response.Error = serrors.NatsError(ctx, errors.New("parent_uuid must be set to the subscription UUID")) + return response } addonID := request.ChildUuid if addonID == "" { - sendError(ctx, response, errors.New("child_id must be set to the add-on UUID")) - return + response.Error = serrors.NatsError(ctx, errors.New("child_id must be set to the add-on UUID")) + return response } tx, err := d.Begin() if err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } defer func() { _ = tx.Rollback() @@ -336,8 +371,8 @@ func (a *App) AddSubscriptionAddonHandler(subject, reply string, request *reques subAddon, err := d.AddSubscriptionAddon(ctx, subscriptionID, addonID, db.WithTXRollbackCommit(tx, false, false)) if err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } quotaValue, _, err := d.GetCurrentQuota( @@ -347,8 +382,8 @@ func (a *App) AddSubscriptionAddonHandler(subject, reply string, request *reques db.WithTXRollbackCommit(tx, false, false), ) if err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } quotaValue = quotaValue + subAddon.Amount @@ -359,45 +394,54 @@ func (a *App) AddSubscriptionAddonHandler(subject, reply string, request *reques subscriptionID, db.WithTXRollbackCommit(tx, false, false), ); err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } if err = tx.Commit(); err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } response.SubscriptionAddon = subAddon.ToQMSType() - - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } + return response } -func (a *App) DeleteSubscriptionAddonHandler(subject, reply string, request *requests.ByUUID) { +func (a *App) AddSubscriptionAddonHandler(subject, reply string, request *requests.AssociateByUUIDs) { var err error - ctx, span := reqinit.InitByUUID(request, subject) + ctx, span := reqinit.InitAssociateByUUIDs(request, subject) defer span.End() - log := log.WithField("context", "deleting subscription add-ons") + log := log.WithField("context", "adding subscription add-on") + + response := a.addSubscription(ctx, request) + + if response.Error != nil { + log.Error(response.Error.Message) + } + + if err = a.client.Respond(ctx, reply, response); err != nil { + log.Error(err) + } +} + +func (a *App) deleteSubscriptionAddon(ctx context.Context, request *requests.ByUUID) *qms.SubscriptionAddonResponse { response := qmsinit.NewSubscriptionAddonResponse() - sendError := a.sendSubscriptionAddonResponseError(reply, log) d := db.New(a.db) // Get the subscription add-on ID out of the request. subAddonID := request.Uuid if subAddonID == "" { - sendError(ctx, response, errors.New("subscription add-on UUID must be set")) - return + response.Error = serrors.NatsError(ctx, errors.New("subscription addon-on UUID must be set")) + return response } /// Start the database transaction. tx, err := d.Begin() if err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } defer func() { _ = tx.Rollback() @@ -407,8 +451,8 @@ func (a *App) DeleteSubscriptionAddonHandler(subject, reply string, request *req // the quota value. subAddon, err := d.GetSubscriptionAddonByID(ctx, subAddonID, db.WithTX(tx)) if err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } // Get the current quota value. @@ -419,8 +463,8 @@ func (a *App) DeleteSubscriptionAddonHandler(subject, reply string, request *req db.WithTXRollbackCommit(tx, false, false), ) if err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } // Update the quota value by subtracting the amount configured in the @@ -435,44 +479,55 @@ func (a *App) DeleteSubscriptionAddonHandler(subject, reply string, request *req subAddon.Subscription.ID, db.WithTXRollbackCommit(tx, false, false), ); err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } // Delete the subscription add-on. if err = d.DeleteSubscriptionAddon(ctx, subAddonID, db.WithTX(tx)); err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } // Commit all of the changes. if err = tx.Commit(); err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } // Return the response. response.SubscriptionAddon = subAddon.ToQMSType() - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } + return response } -func (a *App) UpdateSubscriptionAddonHandler(subject, reply string, request *qms.UpdateSubscriptionAddonRequest) { +func (a *App) DeleteSubscriptionAddonHandler(subject, reply string, request *requests.ByUUID) { var err error - ctx, span := qmsinit.InitUpdateSubscriptionAddonRequest(request, subject) + ctx, span := reqinit.InitByUUID(request, subject) defer span.End() - log := log.WithField("context", "update subscription addon") + log := log.WithField("context", "deleting subscription add-ons") + + response := a.deleteSubscriptionAddon(ctx, request) + + if response.Error != nil { + log.Error(response.Error.Message) + } + + if err = a.client.Respond(ctx, reply, response); err != nil { + log.Error(err) + } +} + +func (a *App) updateSubscriptionAddon(ctx context.Context, request *qms.UpdateSubscriptionAddonRequest) *qms.SubscriptionAddonResponse { response := qmsinit.NewSubscriptionAddonResponse() - sendError := a.sendSubscriptionAddonResponseError(reply, log) + d := db.New(a.db) if request.SubscriptionAddon.Uuid == "" { - sendError(ctx, response, errors.New("uuid must be set in the request")) - return + response.Error = serrors.NatsError(ctx, errors.New("uuid must be set in the request")) + return response } subAddonID := request.SubscriptionAddon.Uuid @@ -481,8 +536,8 @@ func (a *App) UpdateSubscriptionAddonHandler(subject, reply string, request *qms /// Start the database transaction. tx, err := d.Begin() if err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } defer func() { _ = tx.Rollback() @@ -493,8 +548,8 @@ func (a *App) UpdateSubscriptionAddonHandler(subject, reply string, request *qms // to modify the quota value. preUpdateSubAddon, err := d.GetSubscriptionAddonByID(ctx, subAddonID, db.WithTX(tx)) if err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } // Get the current quota value. @@ -505,8 +560,8 @@ func (a *App) UpdateSubscriptionAddonHandler(subject, reply string, request *qms db.WithTXRollbackCommit(tx, false, false), ) if err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } // First, remove the pre-update subscription add-on value from the quota @@ -524,24 +579,41 @@ func (a *App) UpdateSubscriptionAddonHandler(subject, reply string, request *qms preUpdateSubAddon.Subscription.ID, db.WithTXRollbackCommit(tx, false, false), ); err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } } result, err := d.UpdateSubscriptionAddon(ctx, updateSubAddon, db.WithTXRollbackCommit(tx, false, false)) if err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } if err = tx.Commit(); err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } response.SubscriptionAddon = result.ToQMSType() + return response +} + +func (a *App) UpdateSubscriptionAddonHandler(subject, reply string, request *qms.UpdateSubscriptionAddonRequest) { + var err error + + ctx, span := qmsinit.InitUpdateSubscriptionAddonRequest(request, subject) + defer span.End() + + log := log.WithField("context", "update subscription addon") + + response := a.updateSubscriptionAddon(ctx, request) + + if response.Error != nil { + log.Debug(response.Error.Message) + } + if err = a.client.Respond(ctx, reply, response); err != nil { log.Error(err) } From 3165e971a8373b876d0d9f44e4ea243fc578ee3e Mon Sep 17 00:00:00 2001 From: John Wregglesworth Date: Wed, 29 May 2024 10:18:25 -0700 Subject: [PATCH 05/14] Split out app logic from handlers in app/app.go --- app/app.go | 111 ++++++++++++++++++++++++++++------------------------- 1 file changed, 59 insertions(+), 52 deletions(-) diff --git a/app/app.go b/app/app.go index 0be89be..2d1a175 100644 --- a/app/app.go +++ b/app/app.go @@ -120,28 +120,13 @@ func (a *App) GreetingHTTPHandler(ctx echo.Context) error { return ctx.String(http.StatusOK, "Hello from subscriptions.") } -func (a *App) GetUserUpdatesHandler(subject, reply string, request *qms.UpdateListRequest) { - var err error - - log := log.WithFields(logrus.Fields{"context": "get all user updates over nats"}) +func (a *App) getUserUpdates(ctx context.Context, request *qms.UpdateListRequest) *qms.UpdateListResponse { response := pbinit.NewQMSUpdateListResponse() - ctx, span := pbinit.InitQMSUpdateListRequest(request, subject) - defer span.End() - - // Avoid duplicating a lot of error reporting code. - sendError := func(ctx context.Context, response *qms.UpdateListResponse, err error) { - log.Error(err) - response.Error = errors.NatsError(ctx, err) - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } - } username, err := a.FixUsername(request.User.Username) if err != nil { - sendError(ctx, response, err) - return - + response.Error = errors.NatsError(ctx, err) + return response } log = log.WithFields(logrus.Fields{"user": username}) @@ -150,8 +135,8 @@ func (a *App) GetUserUpdatesHandler(subject, reply string, request *qms.UpdateLi mUpdates, err := d.UserUpdates(ctx, username) if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } for _, mu := range mUpdates { @@ -176,39 +161,43 @@ func (a *App) GetUserUpdatesHandler(subject, reply string, request *qms.UpdateLi }) } + return response +} + +func (a *App) GetUserUpdatesHandler(subject, reply string, request *qms.UpdateListRequest) { + var err error + + log := log.WithFields(logrus.Fields{"context": "get all user updates over nats"}) + + ctx, span := pbinit.InitQMSUpdateListRequest(request, subject) + defer span.End() + + response := a.getUserUpdates(ctx, request) + + if response.Error != nil { + log.Error(response.Error.Message) + } + if err = a.client.Respond(ctx, reply, response); err != nil { log.Error(err) } } -func (a *App) AddUserUpdateHandler(subject, reply string, request *qms.AddUpdateRequest) { +func (a *App) addUserUpdate(ctx context.Context, request *qms.AddUpdateRequest) *qms.AddUpdateResponse { var ( err error userID, resourceTypeID, operationID string update *db.Update ) - // Initialize the response. - log := log.WithFields(logrus.Fields{"context": "add a user update over nats"}) response := pbinit.NewQMSAddUpdateResponse() - ctx, span := pbinit.InitQMSAddUpdateRequest(request, subject) - defer span.End() - - // Avoid duplicating a lot of error reporting code. - sendError := func(ctx context.Context, response *qms.AddUpdateResponse, err error) { - log.Error(err) - response.Error = errors.NatsError(ctx, err) - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } - } d := db.New(a.db) username, err := a.validateUpdate(request) if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } log = log.WithFields(logrus.Fields{"user": username}) @@ -218,8 +207,8 @@ func (a *App) AddUserUpdateHandler(subject, reply string, request *qms.AddUpdate log.Infof("getting user ID for %s", username) user, err := d.EnsureUser(ctx, username) if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } userID = user.ID log.Infof("user ID for %s is %s", username, userID) @@ -237,8 +226,8 @@ func (a *App) AddUserUpdateHandler(subject, reply string, request *qms.AddUpdate request.Update.ResourceType.Unit, ) if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } log.Infof("resource type id for resource %s is '%s'", request.Update.ResourceType.Name, resourceTypeID) } else { @@ -254,8 +243,8 @@ func (a *App) AddUserUpdateHandler(subject, reply string, request *qms.AddUpdate request.Update.Operation.Name, ) if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } log.Infof("operation ID for %s is %s", request.Update.Operation.Name, operationID) } else { @@ -287,32 +276,32 @@ func (a *App) AddUserUpdateHandler(subject, reply string, request *qms.AddUpdate log.Info("adding update to the database") _, err = d.AddUserUpdate(ctx, update) if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } log.Info("done adding update to the database") switch update.ValueType { case db.UsagesTrackedMetric: log.Info("processing update for usage") - if err = d.ProcessUpdateForUsage(ctx, update); err != nil { - sendError(ctx, response, err) - return + if err != nil { + response.Error = errors.NatsError(ctx, err) + return response } log.Info("after processing update for usage") case db.QuotasTrackedMetric: log.Info("processing update for quota") - if err = d.ProcessUpdateForQuota(ctx, update); err != nil { - sendError(ctx, response, err) - return + if err != nil { + response.Error = errors.NatsError(ctx, err) + return response } log.Info("after processing update for quota") default: err = fmt.Errorf("unknown value type in update: %s", update.ValueType) - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } // Set up the object for the response. @@ -337,6 +326,24 @@ func (a *App) AddUserUpdateHandler(subject, reply string, request *qms.AddUpdate } } + return response +} + +func (a *App) AddUserUpdateHandler(subject, reply string, request *qms.AddUpdateRequest) { + var err error + + // Initialize the response. + log := log.WithFields(logrus.Fields{"context": "add a user update over nats"}) + + ctx, span := pbinit.InitQMSAddUpdateRequest(request, subject) + defer span.End() + + response := a.addUserUpdate(ctx, request) + + if response.Error != nil { + log.Error(response.Error.Message) + } + // Send the response to the caller if err = a.client.Respond(ctx, reply, response); err != nil { log.Error(err) From 2a62b22198b3e67fca3667c835cb6cd60e5db084 Mon Sep 17 00:00:00 2001 From: John Wregglesworth Date: Wed, 29 May 2024 11:15:53 -0700 Subject: [PATCH 06/14] Split out app logic from handlers in app/overages.go and app/plans.go --- app/overages.go | 94 ++++++++++++++++++------------------- app/plans.go | 121 ++++++++++++++++++++++++++++++------------------ 2 files changed, 121 insertions(+), 94 deletions(-) diff --git a/app/overages.go b/app/overages.go index 5475cea..0d0819b 100644 --- a/app/overages.go +++ b/app/overages.go @@ -6,51 +6,31 @@ import ( "github.com/cyverse-de/go-mod/pbinit" "github.com/cyverse-de/p/go/qms" "github.com/cyverse-de/subscriptions/db" - "github.com/cyverse-de/subscriptions/errors" + serrors "github.com/cyverse-de/subscriptions/errors" "github.com/sirupsen/logrus" ) -func (a *App) GetUserOverages(subject, reply string, request *qms.AllUserOveragesRequest) { - var err error - - log := log.WithFields(logrus.Fields{"context": "list overages"}) - +func (a *App) getUserOverages(ctx context.Context, request *qms.AllUserOveragesRequest) *qms.OverageList { response := pbinit.NewOverageList() - ctx, span := pbinit.InitAllUserOveragesRequest(request, subject) - defer span.End() - - sendError := func(ctx context.Context, response *qms.OverageList, err error) { - log.Error(err) - response.Error = errors.NatsError(ctx, err) - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } - } username, err := a.FixUsername(request.Username) if err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } - log = log.WithFields(logrus.Fields{"user": username}) - // If s.ReportOverages is false, then return the empty list of overages that was just created. if !a.ReportOverages { - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } - return + return response } d := db.New(a.db) results, err := d.GetUserOverages(ctx, username) if err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } - log.Debug("after calling db.GetUserOverages()") for _, r := range results { quota := r.QuotaValue @@ -65,42 +45,40 @@ func (a *App) GetUserOverages(subject, reply string, request *qms.AllUserOverage } } - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } + return response } -func (a *App) CheckUserOverages(subject, reply string, request *qms.IsOverageRequest) { +func (a *App) GetUserOverages(subject, reply string, request *qms.AllUserOveragesRequest) { var err error - log := log.WithFields(logrus.Fields{"context": "check if in overage"}) + log := log.WithFields(logrus.Fields{"context": "list overages"}) + + ctx, span := pbinit.InitAllUserOveragesRequest(request, subject) + defer span.End() + + response := a.getUserOverages(ctx, request) - sendError := func(ctx context.Context, response *qms.IsOverage, err error) { + if response.Error != nil { + log.Error(response.Error.Message) + } + + if err = a.client.Respond(ctx, reply, response); err != nil { log.Error(err) - response.Error = errors.NatsError(ctx, err) - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } } +} +func (a *App) checkUserOverages(ctx context.Context, request *qms.IsOverageRequest) *qms.IsOverage { response := pbinit.NewIsOverage() - ctx, span := pbinit.InitIsOverageRequest(request, subject) - defer span.End() if !a.ReportOverages { response.IsOverage = false - - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } - - return + return response } username, err := a.FixUsername(request.Username) if err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } log = log.WithFields(logrus.Fields{"user": username}) @@ -109,10 +87,9 @@ func (a *App) CheckUserOverages(subject, reply string, request *qms.IsOverageReq overages, err := d.GetUserOverages(ctx, username) if err != nil { - sendError(ctx, response, err) - return + response.Error = serrors.NatsError(ctx, err) + return response } - if len(overages) > 0 { for _, overage := range overages { if overage.ResourceType.Name == request.GetResourceName() { @@ -123,6 +100,23 @@ func (a *App) CheckUserOverages(subject, reply string, request *qms.IsOverageReq response.IsOverage = false } + return response +} + +func (a *App) CheckUserOverages(subject, reply string, request *qms.IsOverageRequest) { + var err error + + log := log.WithFields(logrus.Fields{"context": "check if in overage"}) + + ctx, span := pbinit.InitIsOverageRequest(request, subject) + defer span.End() + + response := a.checkUserOverages(ctx, request) + + if response.Error != nil { + log.Error(response.Error.Message) + } + if err = a.client.Respond(ctx, reply, response); err != nil { log.Error(err) } diff --git a/app/plans.go b/app/plans.go index d2032d3..2603174 100644 --- a/app/plans.go +++ b/app/plans.go @@ -21,26 +21,14 @@ func (a *App) sendPlanResponseError(reply string, log *logrus.Entry) func(contex } } -func (a *App) ListPlansHandler(subject, reply string, request *qms.NoParamsRequest) { - log := log.WithField("context", "list plans") - - sendError := func(ctx context.Context, response *qms.PlanList, err error) { - log.Error(err) - response.Error = errors.NatsError(ctx, err) - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } - } - +func (a *App) listPlans(ctx context.Context, request *qms.NoParamsRequest) *qms.PlanList { response := pbinit.NewPlanList() - ctx, span := pbinit.InitQMSNoParamsRequest(request, subject) - defer span.End() d := db.New(a.db) plans, err := d.ListPlans(ctx) if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } for _, p := range plans { @@ -66,19 +54,29 @@ func (a *App) ListPlansHandler(subject, reply string, request *qms.NoParamsReque response.Plans = append(response.Plans, newP) } - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } + return response } -func (a *App) AddPlanHandler(subject, reply string, request *qms.AddPlanRequest) { +func (a *App) ListPlansHandler(subject, reply string, request *qms.NoParamsRequest) { + var err error log := log.WithField("context", "list plans") - sendError := a.sendPlanResponseError(reply, log) + ctx, span := pbinit.InitQMSNoParamsRequest(request, subject) + defer span.End() + + response := a.listPlans(ctx, request) + + if response.Error != nil { + log.Error(response.Error.Message) + } + + if err = a.client.Respond(ctx, reply, response); err != nil { + log.Error(err) + } +} +func (a *App) addPlan(ctx context.Context, request *qms.AddPlanRequest) *qms.PlanResponse { response := pbinit.NewPlanResponse() - ctx, span := pbinit.InitQMSAddPlanRequest(request, subject) - defer span.End() d := db.New(a.db) @@ -86,8 +84,8 @@ func (a *App) AddPlanHandler(subject, reply string, request *qms.AddPlanRequest) var newPlanID string tx, err := d.Begin() if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } err = tx.Wrap(func() error { var err error @@ -111,34 +109,45 @@ func (a *App) AddPlanHandler(subject, reply string, request *qms.AddPlanRequest) return err }) + if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } response.Plan = request.Plan response.Plan.Uuid = newPlanID + return response +} + +func (a *App) AddPlanHandler(subject, reply string, request *qms.AddPlanRequest) { + var err error + log := log.WithField("context", "list plans") + + ctx, span := pbinit.InitQMSAddPlanRequest(request, subject) + defer span.End() + + response := a.addPlan(ctx, request) + + if response.Error != nil { + log.Error(response.Error.Message) + } + if err = a.client.Respond(ctx, reply, response); err != nil { log.Error(err) } } -func (a *App) GetPlanHandler(subject, reply string, request *qms.PlanRequest) { - log := log.WithField("context", "get plan") - - sendError := a.sendPlanResponseError(reply, log) - +func (a *App) getPlan(ctx context.Context, request *qms.PlanRequest) *qms.PlanResponse { response := pbinit.NewPlanResponse() - ctx, span := pbinit.InitQMSPlanRequest(request, subject) - defer span.End() d := db.New(a.db) plan, err := d.GetPlanByID(ctx, request.PlanId) if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } response.Plan = &qms.Plan{ @@ -162,21 +171,45 @@ func (a *App) GetPlanHandler(subject, reply string, request *qms.PlanRequest) { }) } + return response +} + +func (a *App) GetPlanHandler(subject, reply string, request *qms.PlanRequest) { + var err error + log := log.WithField("context", "get plan") + + ctx, span := pbinit.InitQMSPlanRequest(request, subject) + defer span.End() + + response := a.getPlan(ctx, request) + + if response.Error != nil { + log.Error(response.Error.Message) + } + if err = a.client.Respond(ctx, reply, response); err != nil { log.Error(err) } } -func (a *App) UpsertQuotaDefaultsHandler(subject, reply string, request *qms.AddPlanQuotaDefaultRequest) { - sendError := func(ctx context.Context, response *qms.QuotaDefaultResponse, err error) { - log.Error(err) - response.Error = errors.NatsError(ctx, err) - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } - } +func (a *App) upsertQuotaDefault(ctx context.Context, _ *qms.AddPlanQuotaDefaultRequest) *qms.QuotaDefaultResponse { response := pbinit.NewQuotaDefaultResponse() + response.Error = errors.NatsError(ctx, fmt.Errorf("not implemented")) + return response +} + +func (a *App) UpsertQuotaDefaultsHandler(subject, reply string, request *qms.AddPlanQuotaDefaultRequest) { + var err error + ctx, span := pbinit.InitQMSAddPlanQuotaDefaultRequest(request, subject) defer span.End() - sendError(ctx, response, fmt.Errorf("not implemented")) + + response := a.upsertQuotaDefault(ctx, request) + if response.Error != nil { + log.Error(response.Error.Message) + } + + if err = a.client.Respond(ctx, reply, response); err != nil { + log.Error(err) + } } From 38157e7d78e78bfbc36b1e9a3a0fc2700bffb83e Mon Sep 17 00:00:00 2001 From: John Wregglesworth Date: Wed, 29 May 2024 11:23:12 -0700 Subject: [PATCH 07/14] Re-add usage and quota update function calls that were accidentally removed during refactoring --- app/app.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/app.go b/app/app.go index 2d1a175..1363f19 100644 --- a/app/app.go +++ b/app/app.go @@ -284,7 +284,7 @@ func (a *App) addUserUpdate(ctx context.Context, request *qms.AddUpdateRequest) switch update.ValueType { case db.UsagesTrackedMetric: log.Info("processing update for usage") - if err != nil { + if err = d.ProcessUpdateForUsage(ctx, update); err != nil { response.Error = errors.NatsError(ctx, err) return response } @@ -292,7 +292,7 @@ func (a *App) addUserUpdate(ctx context.Context, request *qms.AddUpdateRequest) case db.QuotasTrackedMetric: log.Info("processing update for quota") - if err != nil { + if err = d.ProcessUpdateForQuota(ctx, update); err != nil { response.Error = errors.NatsError(ctx, err) return response } From 1eaf0b198a08c9910ecca976b20d89ea658cfdc9 Mon Sep 17 00:00:00 2001 From: John Wregglesworth Date: Wed, 29 May 2024 11:24:34 -0700 Subject: [PATCH 08/14] Remove unused, uneeded parameters --- app/addons.go | 4 ++-- app/plans.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/addons.go b/app/addons.go index 21af5f1..12e899f 100644 --- a/app/addons.go +++ b/app/addons.go @@ -144,7 +144,7 @@ func (a *App) AddAddonHandler(subject, reply string, request *qms.AddAddonReques } } -func (a *App) listAddons(ctx context.Context, request *qms.NoParamsRequest) *qms.AddonListResponse { +func (a *App) listAddons(ctx context.Context) *qms.AddonListResponse { response := qmsinit.NewAddonListResponse() d := db.New(a.db) @@ -171,7 +171,7 @@ func (a *App) ListAddonsHandler(subject, reply string, request *qms.NoParamsRequ log := log.WithField("context", "list addons") - response := a.listAddons(ctx, request) + response := a.listAddons(ctx) if response.Error != nil { log.Error(response.Error.Message) diff --git a/app/plans.go b/app/plans.go index 2603174..5d700e4 100644 --- a/app/plans.go +++ b/app/plans.go @@ -21,7 +21,7 @@ func (a *App) sendPlanResponseError(reply string, log *logrus.Entry) func(contex } } -func (a *App) listPlans(ctx context.Context, request *qms.NoParamsRequest) *qms.PlanList { +func (a *App) listPlans(ctx context.Context) *qms.PlanList { response := pbinit.NewPlanList() d := db.New(a.db) @@ -64,7 +64,7 @@ func (a *App) ListPlansHandler(subject, reply string, request *qms.NoParamsReque ctx, span := pbinit.InitQMSNoParamsRequest(request, subject) defer span.End() - response := a.listPlans(ctx, request) + response := a.listPlans(ctx) if response.Error != nil { log.Error(response.Error.Message) From e5cdb92eb5b8cce91541ae6ede18181fe01411f6 Mon Sep 17 00:00:00 2001 From: John Wregglesworth Date: Wed, 29 May 2024 14:20:57 -0700 Subject: [PATCH 09/14] Split out the rest of the app logic from the existing handlers --- app/quotas.go | 41 +++++++++-------- app/summary.go | 62 ++++++++++---------------- app/usages.go | 118 +++++++++++++++++++++++++++++-------------------- app/users.go | 81 +++++++++++++++++---------------- 4 files changed, 155 insertions(+), 147 deletions(-) diff --git a/app/quotas.go b/app/quotas.go index 607d2fc..3d222d7 100644 --- a/app/quotas.go +++ b/app/quotas.go @@ -9,37 +9,23 @@ import ( "github.com/cyverse-de/subscriptions/errors" ) -func (a *App) AddQuotaHandler(subject, reply string, request *qms.AddQuotaRequest) { +func (a *App) addQuota(ctx context.Context, request *qms.AddQuotaRequest) *qms.QuotaResponse { var err error - - log := log.WithField("context", "add quota") - - sendError := func(ctx context.Context, response *qms.QuotaResponse, err error) { - log.Error(err) - response.Error = errors.NatsError(ctx, err) - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } - } - response := pbinit.NewQuotaResponse() - ctx, span := pbinit.InitQMSAddQuotaRequest(request, subject) - defer span.End() - subscriptionID := request.Quota.SubscriptionId d := db.New(a.db) if err = d.UpsertQuota(ctx, float64(request.Quota.Quota), request.Quota.ResourceType.Uuid, subscriptionID); err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } value, _, err := d.GetCurrentQuota(ctx, request.Quota.ResourceType.Uuid, subscriptionID) if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } response.Quota = &qms.Quota{ @@ -48,6 +34,23 @@ func (a *App) AddQuotaHandler(subject, reply string, request *qms.AddQuotaReques SubscriptionId: subscriptionID, } + return response +} + +func (a *App) AddQuotaHandler(subject, reply string, request *qms.AddQuotaRequest) { + var err error + + log := log.WithField("context", "add quota") + + ctx, span := pbinit.InitQMSAddQuotaRequest(request, subject) + defer span.End() + + response := a.addQuota(ctx, request) + + if response.Error != nil { + log.Error(response.Error.Message) + } + if err = a.client.Respond(ctx, reply, response); err != nil { log.Error(err) } diff --git a/app/summary.go b/app/summary.go index 471e4d9..30ad09a 100644 --- a/app/summary.go +++ b/app/summary.go @@ -87,67 +87,53 @@ func (a *App) GetUserSummary(ctx context.Context, username string) (*qms.Subscri return subscription.ToQMSSubscription(), nil } -func (a *App) GetUserSummaryHandler(subject, reply string, request *qms.RequestByUsername) { - var err error - - log := log.WithFields(logrus.Fields{"context": "user summary"}) - +func (a *App) getUserSummary(ctx context.Context, request *qms.RequestByUsername) *qms.SubscriptionResponse { response := pbinit.NewSubscriptionResponse() - ctx, span := pbinit.InitQMSRequestByUsername(request, subject) - defer span.End() - - sendError := func(ctx context.Context, response *qms.SubscriptionResponse, err error) { - log.Error(err) - response.Error = errors.NatsError(ctx, err) - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } - } - username, err := a.FixUsername(request.Username) if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } - log = log.WithFields(logrus.Fields{"user": username}) - subscription, err := a.GetUserSummary(ctx, username) if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } - log.Warnf("Reply: %s", reply) - response.Subscription = subscription + + return response +} + +func (a *App) GetUserSummaryHandler(subject, reply string, request *qms.RequestByUsername) { + var err error + + log := log.WithFields(logrus.Fields{"context": "user summary"}) + + ctx, span := pbinit.InitQMSRequestByUsername(request, subject) + defer span.End() + + response := a.getUserSummary(ctx, request) + if err = a.client.Respond(ctx, reply, response); err != nil { log.Error(err) } } func (a *App) GetUserSummaryHTTPHandler(c echo.Context) error { - var err error - - log := log.WithFields(logrus.Fields{"context": "user summary http"}) ctx := c.Request().Context() - response := pbinit.NewSubscriptionResponse() - - username := c.Param("user") - username, err = a.FixUsername(username) - if err != nil { - return err + request := &qms.RequestByUsername{ + Username: c.Param("user"), } - log = log.WithFields(logrus.Fields{"user": username}) + response := a.getUserSummary(ctx, request) - subscription, err := a.GetUserSummary(ctx, username) - if err != nil { - return err + if response.Error != nil { + return c.JSON(int(response.Error.StatusCode), response) } - response.Subscription = subscription return c.JSON(http.StatusOK, response) } diff --git a/app/usages.go b/app/usages.go index 745ec00..5fd7339 100644 --- a/app/usages.go +++ b/app/usages.go @@ -11,42 +11,27 @@ import ( "google.golang.org/protobuf/types/known/timestamppb" ) -func (a *App) GetUsagesHandler(subject, reply string, request *qms.GetUsages) { - var err error - - log := log.WithFields(logrus.Fields{"context": "getting usages"}) +func (a *App) getUsages(ctx context.Context, request *qms.GetUsages) *qms.UsageList { response := pbinit.NewUsageList() - ctx, span := pbinit.InitGetUsages(request, subject) - defer span.End() - - sendError := func(ctx context.Context, response *qms.UsageList, err error) { - log.Error(err) - response.Error = errors.NatsError(ctx, err) - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } - } username, err := a.FixUsername(request.Username) if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } - log = log.WithFields(logrus.Fields{"user": username}) - d := db.New(a.db) subscription, err := d.GetActiveSubscription(ctx, username) if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } usages, err := d.SubscriptionUsages(ctx, subscription.ID) if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } for _, usage := range usages { @@ -66,59 +51,59 @@ func (a *App) GetUsagesHandler(subject, reply string, request *qms.GetUsages) { }) } - log.Info("successfully found usages") + return response +} + +func (a *App) GetUsagesHandler(subject, reply string, request *qms.GetUsages) { + var err error + + log := log.WithFields(logrus.Fields{"context": "getting usages"}) + + ctx, span := pbinit.InitGetUsages(request, subject) + defer span.End() + + response := a.getUsages(ctx, request) + + if response.Error != nil { + log.Error(response.Error.Message) + } if err = a.client.Respond(ctx, reply, response); err != nil { log.Error(err) } } -func (a *App) AddUsageHandler(subject, reply string, request *qms.AddUsage) { +func (a *App) addUsage(ctx context.Context, request *qms.AddUsage) *qms.UsageResponse { var ( err error usage db.Usage ) - log := log.WithFields(logrus.Fields{"context": "adding usage information"}) - - log.Debugf("subject: %s; reply: %s", subject, reply) - response := pbinit.NewUsageResponse() - ctx, span := pbinit.InitAddUsage(request, subject) - defer span.End() - - sendError := func(ctx context.Context, response *qms.UsageResponse, err error) { - log.Error(err) - response.Error = errors.NatsError(ctx, err) - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } - } - username, err := a.FixUsername(request.Username) if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } d := db.New(a.db) subscription, err := d.GetActiveSubscription(ctx, username) if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } // Validate update type. if _, err = d.GetOperationID(ctx, request.UpdateType); err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } resourceID, err := d.GetResourceTypeID(ctx, request.ResourceName, request.ResourceUnit) if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } usage = db.Usage{ @@ -132,7 +117,42 @@ func (a *App) AddUsageHandler(subject, reply string, request *qms.AddUsage) { } if err = d.CalculateUsage(ctx, request.UpdateType, &usage); err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response + } + + u, _, err := d.GetCurrentUsage(ctx, resourceID, subscription.ID) + if err != nil { + response.Error = errors.NatsError(ctx, err) + return response + } + + response.Usage = &qms.Usage{ + Usage: u, + SubscriptionId: subscription.ID, + ResourceType: &qms.ResourceType{ + Uuid: resourceID, + Name: request.ResourceName, + Unit: request.ResourceUnit, + }, + } + + return response +} + +func (a *App) AddUsageHandler(subject, reply string, request *qms.AddUsage) { + var err error + + ctx, span := pbinit.InitAddUsage(request, subject) + defer span.End() + + response := a.addUsage(ctx, request) + + if response.Error != nil { + log.Error(response.Error.Message) + } + + if err = a.client.Respond(ctx, reply, response); err != nil { + log.Error(err) } } diff --git a/app/users.go b/app/users.go index 9e17a24..ae23811 100644 --- a/app/users.go +++ b/app/users.go @@ -11,38 +11,20 @@ import ( "github.com/sirupsen/logrus" ) -func (a *App) AddUserHandler(subject, reply string, request *qms.AddUserRequest) { - var ( - err error - ) - - log := log.WithField("context", "add user") - - ctx, span := pbinit.InitQMSAddUserRequest(request, subject) - defer span.End() - +func (a *App) addUser(ctx context.Context, request *qms.AddUserRequest) *qms.AddUserResponse { response := pbinit.NewQMSAddUserResponse() - - sendError := func(ctx context.Context, response *qms.AddUserResponse, err error) { - log.Error(err) - response.Error = errors.NatsError(ctx, err) - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } - } - username, err := a.FixUsername(request.Username) if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } d := db.New(a.db) opts, err := utils.OptsForValues(request.Paid, request.Periods, request.EndDate) if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } log = log.WithFields( logrus.Fields{ @@ -56,8 +38,8 @@ func (a *App) AddUserHandler(subject, reply string, request *qms.AddUserRequest) tx, err := d.Begin() if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } defer func() { _ = tx.Rollback() @@ -68,15 +50,15 @@ func (a *App) AddUserHandler(subject, reply string, request *qms.AddUserRequest) plan, err := d.GetPlanByName(ctx, planName, db.WithTX(tx)) if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } // look for an existing user. userExists, err := d.UserExists(ctx, username, db.WithTX(tx)) if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } var userID string @@ -85,14 +67,14 @@ func (a *App) AddUserHandler(subject, reply string, request *qms.AddUserRequest) if !userExists { userID, err = d.AddUser(ctx, username, db.WithTX(tx)) if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } } else { userID, err = d.GetUserID(ctx, username, db.WithTX(tx)) if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } } @@ -103,8 +85,8 @@ func (a *App) AddUserHandler(subject, reply string, request *qms.AddUserRequest) if !createSubscription { hasPlan, err := d.UserHasActivePlan(ctx, username, db.WithTX(tx)) if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } createSubscription = !hasPlan } @@ -113,8 +95,8 @@ func (a *App) AddUserHandler(subject, reply string, request *qms.AddUserRequest) if !createSubscription { onPlan, err := d.UserOnPlan(ctx, username, plan.Name, db.WithTX(tx)) if err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } createSubscription = !onPlan } @@ -122,15 +104,15 @@ func (a *App) AddUserHandler(subject, reply string, request *qms.AddUserRequest) // Create the subscription if we're supposed to. if createSubscription { if _, err = d.SetActiveSubscription(ctx, userID, plan, opts, db.WithTX(tx)); err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } } // Commit all of the changes if err = tx.Commit(); err != nil { - sendError(ctx, response, err) - return + response.Error = errors.NatsError(ctx, err) + return response } response.PlanName = plan.Name @@ -138,6 +120,23 @@ func (a *App) AddUserHandler(subject, reply string, request *qms.AddUserRequest) response.Username = username response.Uuid = userID + return response +} + +func (a *App) AddUserHandler(subject, reply string, request *qms.AddUserRequest) { + var err error + + log := log.WithField("context", "add user") + + ctx, span := pbinit.InitQMSAddUserRequest(request, subject) + defer span.End() + + response := a.addUser(ctx, request) + + if response.Error != nil { + log.Error(response.Error.Message) + } + if err = a.client.Respond(ctx, reply, response); err != nil { log.Error(err) } From 3b41e4b281d92881b178d695a535d225e4608736 Mon Sep 17 00:00:00 2001 From: John Wregglesworth Date: Wed, 29 May 2024 15:28:12 -0700 Subject: [PATCH 10/14] Add first pass at http handlers for the addons requests --- app/addons.go | 218 +++++++++++++++++++++++++++++++++++++++----------- app/app.go | 9 +++ 2 files changed, 182 insertions(+), 45 deletions(-) diff --git a/app/addons.go b/app/addons.go index 12e899f..711c992 100644 --- a/app/addons.go +++ b/app/addons.go @@ -2,11 +2,12 @@ package app import ( "context" + "net/http" "errors" serrors "github.com/cyverse-de/subscriptions/errors" - "github.com/sirupsen/logrus" + "github.com/labstack/echo/v4" qmsinit "github.com/cyverse-de/go-mod/pbinit/qms" reqinit "github.com/cyverse-de/go-mod/pbinit/requests" @@ -15,46 +16,6 @@ import ( "github.com/cyverse-de/subscriptions/db" ) -func (a *App) sendAddonResponseError(reply string, log *logrus.Entry) func(context.Context, *qms.AddonResponse, error) { - return func(ctx context.Context, response *qms.AddonResponse, err error) { - log.Error(err) - response.Error = serrors.NatsError(ctx, err) - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } - } -} - -func (a *App) sendAddonListResponseError(reply string, log *logrus.Entry) func(context.Context, *qms.AddonListResponse, error) { - return func(ctx context.Context, response *qms.AddonListResponse, err error) { - log.Error(err) - response.Error = serrors.NatsError(ctx, err) - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } - } -} - -func (a *App) sendSubscriptionAddonListResponseError(reply string, log *logrus.Entry) func(context.Context, *qms.SubscriptionAddonListResponse, error) { - return func(ctx context.Context, response *qms.SubscriptionAddonListResponse, err error) { - log.Error(err) - response.Error = serrors.NatsError(ctx, err) - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } - } -} - -func (a *App) sendSubscriptionAddonResponseError(reply string, log *logrus.Entry) func(context.Context, *qms.SubscriptionAddonResponse, error) { - return func(ctx context.Context, response *qms.SubscriptionAddonResponse, err error) { - log.Error(err) - response.Error = serrors.NatsError(ctx, err) - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } - } -} - func (a *App) addAddon(ctx context.Context, request *qms.AddAddonRequest) *qms.AddonResponse { d := db.New(a.db) @@ -144,6 +105,30 @@ func (a *App) AddAddonHandler(subject, reply string, request *qms.AddAddonReques } } +func (a *App) AddAddonHTTPHandler(c echo.Context) error { + var ( + err error + request qms.AddAddonRequest + ) + + ctx := c.Request().Context() + + if err = c.Bind(&request); err != nil { + return c.JSON(http.StatusBadRequest, map[string]string{ + "message": "invalid body format", + }) + } + + response := a.addAddon(ctx, &request) + + if response.Error != nil { + return c.JSON(int(response.Error.StatusCode), response) + } + + return c.JSON(http.StatusOK, response) + +} + func (a *App) listAddons(ctx context.Context) *qms.AddonListResponse { response := qmsinit.NewAddonListResponse() d := db.New(a.db) @@ -182,6 +167,19 @@ func (a *App) ListAddonsHandler(subject, reply string, request *qms.NoParamsRequ } } +func (a *App) ListAddonsHTTPHandler(c echo.Context) error { + ctx := c.Request().Context() + + response := a.listAddons(ctx) + + if response.Error != nil { + return c.JSON(int(response.Error.StatusCode), response) + } + + return c.JSON(http.StatusOK, response) + +} + func (a *App) updateAddon(ctx context.Context, request *qms.UpdateAddonRequest) *qms.AddonResponse { response := qmsinit.NewAddonResponse() d := db.New(a.db) @@ -223,6 +221,32 @@ func (a *App) UpdateAddonHandler(subject, reply string, request *qms.UpdateAddon } } +func (a *App) UpdateAddonHTTPHandler(c echo.Context) error { + var ( + err error + request qms.UpdateAddonRequest + ) + + ctx := c.Request().Context() + + if err = c.Bind(&request); err != nil { + return c.JSON(http.StatusBadRequest, map[string]string{ + "message": "bad request", + }) + } + + request.Addon.Uuid = c.Param("uuid") + + response := a.updateAddon(ctx, &request) + + if response.Error != nil { + return c.JSON(int(response.Error.StatusCode), response) + } + + return c.JSON(http.StatusOK, response) + +} + func (a *App) deleteAddon(ctx context.Context, request *requests.ByUUID) *qms.AddonResponse { response := qmsinit.NewAddonResponse() @@ -270,6 +294,22 @@ func (a *App) DeleteAddonHandler(subject, reply string, request *requests.ByUUID } } +func (a *App) DeleteAddonHTTPHandler(c echo.Context) error { + ctx := c.Request().Context() + + request := requests.ByUUID{ + Uuid: c.Param("uuid"), + } + + response := a.deleteAddon(ctx, &request) + + if response.Error != nil { + return c.JSON(int(response.Error.StatusCode), response) + } + + return c.JSON(http.StatusOK, response) +} + func (a *App) listSubscriptionAddons(ctx context.Context, request *requests.ByUUID) *qms.SubscriptionAddonListResponse { response := qmsinit.NewSubscriptionAddonListResponse() @@ -308,7 +348,23 @@ func (a *App) ListSubscriptionAddonsHandler(subject, reply string, request *requ } } -func (a *App) getSubscription(ctx context.Context, request *requests.ByUUID) *qms.SubscriptionAddonResponse { +func (a *App) ListSubscriptionAddonsHTTPHandler(c echo.Context) error { + ctx := c.Request().Context() + + request := &requests.ByUUID{ + Uuid: c.Param("uuid"), + } + + response := a.listSubscriptionAddons(ctx, request) + + if response.Error != nil { + return c.JSON(int(response.Error.StatusCode), response) + } + + return c.JSON(http.StatusOK, response) +} + +func (a *App) getSubscriptionAddon(ctx context.Context, request *requests.ByUUID) *qms.SubscriptionAddonResponse { response := qmsinit.NewSubscriptionAddonResponse() d := db.New(a.db) @@ -333,7 +389,7 @@ func (a *App) GetSubscriptionAddonHandler(subject, reply string, request *reques log := log.WithField("context", "getting subscription add-on") - response := a.getSubscription(ctx, request) + response := a.getSubscriptionAddon(ctx, request) if response.Error != nil { log.Error(response.Error.Message) @@ -344,7 +400,23 @@ func (a *App) GetSubscriptionAddonHandler(subject, reply string, request *reques } } -func (a *App) addSubscription(ctx context.Context, request *requests.AssociateByUUIDs) *qms.SubscriptionAddonResponse { +func (a *App) GetSubscriptionAddonHTTPHandler(c echo.Context) error { + ctx := c.Request().Context() + + request := &requests.ByUUID{ + Uuid: c.Param("addon_uuid"), + } + + response := a.getSubscriptionAddon(ctx, request) + + if response.Error != nil { + return c.JSON(int(response.Error.StatusCode), response) + } + + return c.JSON(http.StatusOK, response) +} + +func (a *App) addSubscriptionAddon(ctx context.Context, request *requests.AssociateByUUIDs) *qms.SubscriptionAddonResponse { response := qmsinit.NewSubscriptionAddonResponse() d := db.New(a.db) @@ -415,7 +487,7 @@ func (a *App) AddSubscriptionAddonHandler(subject, reply string, request *reques log := log.WithField("context", "adding subscription add-on") - response := a.addSubscription(ctx, request) + response := a.addSubscriptionAddon(ctx, request) if response.Error != nil { log.Error(response.Error.Message) @@ -426,6 +498,23 @@ func (a *App) AddSubscriptionAddonHandler(subject, reply string, request *reques } } +func (a *App) AddSubscriptionAddonHTTPHandler(c echo.Context) error { + ctx := c.Request().Context() + + request := &requests.AssociateByUUIDs{ + ParentUuid: c.Param("sub_uuid"), + ChildUuid: c.Param("addon_uuid"), + } + + response := a.addSubscriptionAddon(ctx, request) + + if response.Error != nil { + return c.JSON(int(response.Error.StatusCode), response) + } + + return c.JSON(http.StatusOK, response) +} + func (a *App) deleteSubscriptionAddon(ctx context.Context, request *requests.ByUUID) *qms.SubscriptionAddonResponse { response := qmsinit.NewSubscriptionAddonResponse() d := db.New(a.db) @@ -520,6 +609,22 @@ func (a *App) DeleteSubscriptionAddonHandler(subject, reply string, request *req } } +func (a *App) DeleteSubscriptionAddonHTTPHandler(c echo.Context) error { + ctx := c.Request().Context() + + request := &requests.ByUUID{ + Uuid: c.Param("addon_uuid"), + } + + response := a.deleteSubscriptionAddon(ctx, request) + + if response.Error != nil { + return c.JSON(int(response.Error.StatusCode), response) + } + + return c.JSON(http.StatusOK, response) +} + func (a *App) updateSubscriptionAddon(ctx context.Context, request *qms.UpdateSubscriptionAddonRequest) *qms.SubscriptionAddonResponse { response := qmsinit.NewSubscriptionAddonResponse() @@ -618,3 +723,26 @@ func (a *App) UpdateSubscriptionAddonHandler(subject, reply string, request *qms log.Error(err) } } + +func (a *App) UpdateSubscriptionAddonHTTPHandler(c echo.Context) error { + var ( + err error + request qms.UpdateSubscriptionAddonRequest + ) + + ctx := c.Request().Context() + + if err = c.Bind(&request); err != nil { + return c.JSON(http.StatusBadRequest, map[string]string{ + "message": "bad request", + }) + } + + response := a.updateSubscriptionAddon(ctx, &request) + + if response.Error != nil { + return c.JSON(int(response.Error.StatusCode), response) + } + + return c.JSON(http.StatusOK, response) +} diff --git a/app/app.go b/app/app.go index 1363f19..6ffe88d 100644 --- a/app/app.go +++ b/app/app.go @@ -63,6 +63,15 @@ func New(client *natscl.Client, db *sqlx.DB, userSuffix string) *App { app.Router.GET("/", app.GreetingHTTPHandler).Name = "greeting" app.Router.GET("/summary/:user", app.GetUserSummaryHTTPHandler) + app.Router.PUT("/addons", app.AddAddonHTTPHandler) + app.Router.GET("/addons", app.ListAddonsHTTPHandler) + app.Router.POST("/addons/:uuid", app.UpdateAddonHTTPHandler) + app.Router.DELETE("/addons/:uuid", app.DeleteAddonHTTPHandler) + app.Router.GET("/subscriptions/:uuid/addons", app.ListSubscriptionAddonsHTTPHandler) + app.Router.GET("/subscriptions/:sub_uuid/addons/:addon_uuid", app.GetSubscriptionAddonHTTPHandler) + app.Router.PUT("/subscriptions/:sub_uuid/addons/:addon_uuid", app.AddSubscriptionAddonHTTPHandler) + app.Router.DELETE("/subscriptions/:sub_uuid/addons/:addon_uuid", app.DeleteSubscriptionAddonHTTPHandler) + app.Router.POST("/subscriptions/:sub_uuid/addons/:addon_uuid", app.UpdateSubscriptionAddonHTTPHandler) return app } From a420cfdb4325e9c8b65be2da3e8e9d98f685e5ff Mon Sep 17 00:00:00 2001 From: John Wregglesworth Date: Thu, 30 May 2024 10:32:59 -0700 Subject: [PATCH 11/14] Add HTTP handlers for user updates and overages --- app/app.go | 47 +++++++++++++++++++++++++++++++++++++++++++++++ app/overages.go | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/app/app.go b/app/app.go index 6ffe88d..3acb0b3 100644 --- a/app/app.go +++ b/app/app.go @@ -72,6 +72,10 @@ func New(client *natscl.Client, db *sqlx.DB, userSuffix string) *App { app.Router.PUT("/subscriptions/:sub_uuid/addons/:addon_uuid", app.AddSubscriptionAddonHTTPHandler) app.Router.DELETE("/subscriptions/:sub_uuid/addons/:addon_uuid", app.DeleteSubscriptionAddonHTTPHandler) app.Router.POST("/subscriptions/:sub_uuid/addons/:addon_uuid", app.UpdateSubscriptionAddonHTTPHandler) + app.Router.GET("/users/:username/updates", app.GetUserUpdatesHTTPHandler) + app.Router.PUT("/user/:username/updates", app.AddUserUpdateHTTPHandler) + app.Router.GET("/users/:username/overages", app.GetUserOveragesHTTPHandler) + app.Router.GET("/users/:username/overages/:resource_name", app.CheckUserOveragesHTTPHandler) return app } @@ -192,6 +196,24 @@ func (a *App) GetUserUpdatesHandler(subject, reply string, request *qms.UpdateLi } } +func (a *App) GetUserUpdatesHTTPHandler(c echo.Context) error { + ctx := c.Request().Context() + + request := &qms.UpdateListRequest{ + User: &qms.QMSUser{ + Username: c.Param("username"), + }, + } + + response := a.getUserUpdates(ctx, request) + + if response.Error != nil { + return c.JSON(int(response.Error.StatusCode), response) + } + + return c.JSON(http.StatusOK, response) +} + func (a *App) addUserUpdate(ctx context.Context, request *qms.AddUpdateRequest) *qms.AddUpdateResponse { var ( err error @@ -358,3 +380,28 @@ func (a *App) AddUserUpdateHandler(subject, reply string, request *qms.AddUpdate log.Error(err) } } + +func (a *App) AddUserUpdateHTTPHandler(c echo.Context) error { + var ( + err error + request qms.AddUpdateRequest + ) + + ctx := c.Request().Context() + + if err = c.Bind(&request); err != nil { + return c.JSON(http.StatusBadRequest, map[string]string{ + "message": "bad request", + }) + } + + request.Update.User.Username = c.Param("username") + + response := a.addUserUpdate(ctx, &request) + + if response.Error != nil { + return c.JSON(int(response.Error.StatusCode), response) + } + + return c.JSON(http.StatusOK, response) +} diff --git a/app/overages.go b/app/overages.go index 0d0819b..4a9e8bd 100644 --- a/app/overages.go +++ b/app/overages.go @@ -2,11 +2,13 @@ package app import ( "context" + "net/http" "github.com/cyverse-de/go-mod/pbinit" "github.com/cyverse-de/p/go/qms" "github.com/cyverse-de/subscriptions/db" serrors "github.com/cyverse-de/subscriptions/errors" + "github.com/labstack/echo/v4" "github.com/sirupsen/logrus" ) @@ -67,6 +69,22 @@ func (a *App) GetUserOverages(subject, reply string, request *qms.AllUserOverage } } +func (a *App) GetUserOveragesHTTPHandler(c echo.Context) error { + ctx := c.Request().Context() + + request := &qms.AllUserOveragesRequest{ + Username: c.Param("username"), + } + + response := a.getUserOverages(ctx, request) + + if response.Error != nil { + return c.JSON(int(response.Error.StatusCode), response) + } + + return c.JSON(http.StatusOK, response) +} + func (a *App) checkUserOverages(ctx context.Context, request *qms.IsOverageRequest) *qms.IsOverage { response := pbinit.NewIsOverage() @@ -121,3 +139,22 @@ func (a *App) CheckUserOverages(subject, reply string, request *qms.IsOverageReq log.Error(err) } } + +func (a *App) CheckUserOveragesHTTPHandler(c echo.Context) error { + var request qms.IsOverageRequest + + ctx := c.Request().Context() + + request = qms.IsOverageRequest{ + Username: c.Param("username"), + ResourceName: c.Param("resource_name"), + } + + response := a.checkUserOverages(ctx, &request) + + if response.Error != nil { + return c.JSON(int(response.Error.StatusCode), response) + } + + return c.JSON(http.StatusOK, response) +} From 5e634b519294e5eacd39d5271c3603313b706e5f Mon Sep 17 00:00:00 2001 From: John Wregglesworth Date: Thu, 30 May 2024 11:43:47 -0700 Subject: [PATCH 12/14] Add HTTP handlers for plans, quotas, usages, and users --- app/app.go | 8 +++++ app/plans.go | 87 ++++++++++++++++++++++++++++++++++++++++++++------- app/quotas.go | 25 +++++++++++++++ app/usages.go | 43 +++++++++++++++++++++++++ app/users.go | 27 ++++++++++++++++ 5 files changed, 179 insertions(+), 11 deletions(-) diff --git a/app/app.go b/app/app.go index 3acb0b3..f2e9757 100644 --- a/app/app.go +++ b/app/app.go @@ -72,10 +72,18 @@ func New(client *natscl.Client, db *sqlx.DB, userSuffix string) *App { app.Router.PUT("/subscriptions/:sub_uuid/addons/:addon_uuid", app.AddSubscriptionAddonHTTPHandler) app.Router.DELETE("/subscriptions/:sub_uuid/addons/:addon_uuid", app.DeleteSubscriptionAddonHTTPHandler) app.Router.POST("/subscriptions/:sub_uuid/addons/:addon_uuid", app.UpdateSubscriptionAddonHTTPHandler) + app.Router.PUT("/users", app.AddUserHTTPHandler) app.Router.GET("/users/:username/updates", app.GetUserUpdatesHTTPHandler) app.Router.PUT("/user/:username/updates", app.AddUserUpdateHTTPHandler) app.Router.GET("/users/:username/overages", app.GetUserOveragesHTTPHandler) app.Router.GET("/users/:username/overages/:resource_name", app.CheckUserOveragesHTTPHandler) + app.Router.GET("/users/:username/usages", app.GetUsagesHTTPHandler) + app.Router.PUT("/users/:username/usages", app.AddUsageHTTPHandler) + app.Router.GET("/plans", app.ListPlansHTTPHandler) + app.Router.PUT("/plans", app.AddPlanHTTPHandler) + app.Router.GET("/plans/:plan_id", app.GetPlanHTTPHandler) + app.Router.POST("/quotas/defaults", app.UpsertQuotaDefaultsHTTPHandler) + app.Router.PUT("/quotas", app.AddQuotaHTTPHandler) return app } diff --git a/app/plans.go b/app/plans.go index 5d700e4..8fa81bb 100644 --- a/app/plans.go +++ b/app/plans.go @@ -3,24 +3,15 @@ package app import ( "context" "fmt" + "net/http" "github.com/cyverse-de/go-mod/pbinit" "github.com/cyverse-de/p/go/qms" "github.com/cyverse-de/subscriptions/db" "github.com/cyverse-de/subscriptions/errors" - "github.com/sirupsen/logrus" + "github.com/labstack/echo/v4" ) -func (a *App) sendPlanResponseError(reply string, log *logrus.Entry) func(context.Context, *qms.PlanResponse, error) { - return func(ctx context.Context, response *qms.PlanResponse, err error) { - log.Error(err) - response.Error = errors.NatsError(ctx, err) - if err = a.client.Respond(ctx, reply, response); err != nil { - log.Error(err) - } - } -} - func (a *App) listPlans(ctx context.Context) *qms.PlanList { response := pbinit.NewPlanList() @@ -75,6 +66,18 @@ func (a *App) ListPlansHandler(subject, reply string, request *qms.NoParamsReque } } +func (a *App) ListPlansHTTPHandler(c echo.Context) error { + ctx := c.Request().Context() + + response := a.listPlans(ctx) + + if response.Error != nil { + return c.JSON(int(response.Error.StatusCode), response) + } + + return c.JSON(http.StatusOK, response) +} + func (a *App) addPlan(ctx context.Context, request *qms.AddPlanRequest) *qms.PlanResponse { response := pbinit.NewPlanResponse() @@ -139,6 +142,29 @@ func (a *App) AddPlanHandler(subject, reply string, request *qms.AddPlanRequest) } } +func (a *App) AddPlanHTTPHandler(c echo.Context) error { + var ( + err error + request qms.AddPlanRequest + ) + + ctx := c.Request().Context() + + if err = c.Bind(&request); err != nil { + return c.JSON(http.StatusBadRequest, map[string]string{ + "message": "bad request", + }) + } + + response := a.addPlan(ctx, &request) + + if response.Error != nil { + return c.JSON(int(response.Error.StatusCode), response) + } + + return c.JSON(http.StatusOK, response) +} + func (a *App) getPlan(ctx context.Context, request *qms.PlanRequest) *qms.PlanResponse { response := pbinit.NewPlanResponse() @@ -192,6 +218,22 @@ func (a *App) GetPlanHandler(subject, reply string, request *qms.PlanRequest) { } } +func (a *App) GetPlanHTTPHandler(c echo.Context) error { + ctx := c.Request().Context() + + request := &qms.PlanRequest{ + PlanId: c.Param("plan_id"), + } + + response := a.getPlan(ctx, request) + + if response.Error != nil { + return c.JSON(int(response.Error.StatusCode), response) + } + + return c.JSON(http.StatusOK, response) +} + func (a *App) upsertQuotaDefault(ctx context.Context, _ *qms.AddPlanQuotaDefaultRequest) *qms.QuotaDefaultResponse { response := pbinit.NewQuotaDefaultResponse() response.Error = errors.NatsError(ctx, fmt.Errorf("not implemented")) @@ -213,3 +255,26 @@ func (a *App) UpsertQuotaDefaultsHandler(subject, reply string, request *qms.Add log.Error(err) } } + +func (a *App) UpsertQuotaDefaultsHTTPHandler(c echo.Context) error { + var ( + err error + request qms.AddPlanQuotaDefaultRequest + ) + + ctx := c.Request().Context() + + if err = c.Bind(&request); err != nil { + return c.JSON(http.StatusBadRequest, map[string]string{ + "message": "bad request", + }) + } + + response := a.upsertQuotaDefault(ctx, &request) + + if response.Error != nil { + return c.JSON(int(response.Error.StatusCode), response) + } + + return c.JSON(http.StatusOK, response) +} diff --git a/app/quotas.go b/app/quotas.go index 3d222d7..ee38251 100644 --- a/app/quotas.go +++ b/app/quotas.go @@ -2,11 +2,13 @@ package app import ( "context" + "net/http" "github.com/cyverse-de/go-mod/pbinit" "github.com/cyverse-de/p/go/qms" "github.com/cyverse-de/subscriptions/db" "github.com/cyverse-de/subscriptions/errors" + "github.com/labstack/echo/v4" ) func (a *App) addQuota(ctx context.Context, request *qms.AddQuotaRequest) *qms.QuotaResponse { @@ -55,3 +57,26 @@ func (a *App) AddQuotaHandler(subject, reply string, request *qms.AddQuotaReques log.Error(err) } } + +func (a *App) AddQuotaHTTPHandler(c echo.Context) error { + var ( + err error + request qms.AddQuotaRequest + ) + + ctx := c.Request().Context() + + if err = c.Bind(&request); err != nil { + return c.JSON(http.StatusBadRequest, map[string]string{ + "message": "bad request", + }) + } + + response := a.addQuota(ctx, &request) + + if response.Error != nil { + return c.JSON(int(response.Error.StatusCode), response) + } + + return c.JSON(http.StatusOK, response) +} diff --git a/app/usages.go b/app/usages.go index 5fd7339..e47b0e7 100644 --- a/app/usages.go +++ b/app/usages.go @@ -2,11 +2,13 @@ package app import ( "context" + "net/http" "github.com/cyverse-de/go-mod/pbinit" "github.com/cyverse-de/p/go/qms" "github.com/cyverse-de/subscriptions/db" "github.com/cyverse-de/subscriptions/errors" + "github.com/labstack/echo/v4" "github.com/sirupsen/logrus" "google.golang.org/protobuf/types/known/timestamppb" ) @@ -73,6 +75,22 @@ func (a *App) GetUsagesHandler(subject, reply string, request *qms.GetUsages) { } } +func (a *App) GetUsagesHTTPHandler(c echo.Context) error { + ctx := c.Request().Context() + + request := &qms.GetUsages{ + Username: c.Param("username"), + } + + response := a.getUsages(ctx, request) + + if response.Error != nil { + return c.JSON(int(response.Error.StatusCode), response) + } + + return c.JSON(http.StatusOK, response) +} + func (a *App) addUsage(ctx context.Context, request *qms.AddUsage) *qms.UsageResponse { var ( err error @@ -156,3 +174,28 @@ func (a *App) AddUsageHandler(subject, reply string, request *qms.AddUsage) { log.Error(err) } } + +func (a *App) AddUsageHTTPHandler(c echo.Context) error { + var ( + err error + request qms.AddUsage + ) + + ctx := c.Request().Context() + + if err = c.Bind(&request); err != nil { + return c.JSON(http.StatusBadRequest, map[string]string{ + "message": "bad request", + }) + } + + request.Username = c.Param("username") + + response := a.addUsage(ctx, &request) + + if response.Error != nil { + return c.JSON(int(response.Error.StatusCode), response) + } + + return c.JSON(http.StatusOK, response) +} diff --git a/app/users.go b/app/users.go index ae23811..b1542af 100644 --- a/app/users.go +++ b/app/users.go @@ -2,12 +2,14 @@ package app import ( "context" + "net/http" "github.com/cyverse-de/go-mod/pbinit" "github.com/cyverse-de/p/go/qms" "github.com/cyverse-de/subscriptions/db" "github.com/cyverse-de/subscriptions/errors" "github.com/cyverse-de/subscriptions/utils" + "github.com/labstack/echo/v4" "github.com/sirupsen/logrus" ) @@ -141,3 +143,28 @@ func (a *App) AddUserHandler(subject, reply string, request *qms.AddUserRequest) log.Error(err) } } + +func (a *App) AddUserHTTPHandler(c echo.Context) error { + var ( + err error + request qms.AddUserRequest + ) + + ctx := c.Request().Context() + + if err = c.Bind(&request); err != nil { + return c.JSON(http.StatusBadRequest, map[string]string{ + "message": "bad request", + }) + } + + request.Username = c.Param("username") + + response := a.addUser(ctx, &request) + + if response.Error != nil { + return c.JSON(int(response.Error.StatusCode), response) + } + + return c.JSON(http.StatusOK, response) +} From 5187e38c62e148a2c92b7bcfcd2d2edd5f1a4fff Mon Sep 17 00:00:00 2001 From: John Wregglesworth Date: Wed, 5 Jun 2024 12:05:28 -0700 Subject: [PATCH 13/14] Change username.suffix to users.domain --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index 5260e0c..485cab4 100644 --- a/main.go +++ b/main.go @@ -95,7 +95,7 @@ func main() { log.Fatal(errors.Wrap(err, "Can't parse database.uri in the config file")) } - userSuffix := config.String("username.suffix") + userSuffix := config.String("users.domain") if userSuffix == "" { log.Fatal("users.domain must be set in the configuration file") } From 9b4b4668f6cd7f9a02e96acf91ba9bb0cad7c141 Mon Sep 17 00:00:00 2001 From: John Wregglesworth Date: Wed, 5 Jun 2024 13:35:25 -0700 Subject: [PATCH 14/14] Updated go dependencies --- go.mod | 4 ++-- go.sum | 39 +++++---------------------------------- 2 files changed, 7 insertions(+), 36 deletions(-) diff --git a/go.mod b/go.mod index abb4974..9fa7ed4 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/cyverse-de/subscriptions go 1.22 require ( - github.com/cyverse-de/go-mod/cfg v0.0.1 + github.com/cyverse-de/go-mod/cfg v0.0.2 github.com/cyverse-de/go-mod/gotelnats v0.0.11 github.com/cyverse-de/go-mod/logging v0.0.2 github.com/cyverse-de/go-mod/otelutils v0.0.3 @@ -16,6 +16,7 @@ require ( github.com/doug-martin/goqu/v9 v9.19.0 github.com/jmoiron/sqlx v1.4.0 github.com/knadh/koanf v1.5.0 + github.com/labstack/echo/v4 v4.12.0 github.com/lib/pq v1.10.9 github.com/nats-io/nats.go v1.34.1 github.com/pkg/errors v0.9.1 @@ -40,7 +41,6 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/joho/godotenv v1.5.1 // indirect github.com/klauspost/compress v1.17.8 // indirect - github.com/labstack/echo/v4 v4.12.0 // indirect github.com/labstack/gommon v0.4.2 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect diff --git a/go.sum b/go.sum index dfdd2f0..8480946 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= @@ -35,8 +36,8 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cyverse-de/go-mod/cfg v0.0.1 h1:rCNNrGSTHYbnygepgDplBRPZhHQ8SR1zSRCkN0o/mOc= -github.com/cyverse-de/go-mod/cfg v0.0.1/go.mod h1:9yHgS328eyTam8Ji//3oOb4ckOT/o5Qp0iSXZk5cVeM= +github.com/cyverse-de/go-mod/cfg v0.0.2 h1:evHNKqLwOPWHhxxzF498/Rtac7LZb1zxnHAjZSuqiEo= +github.com/cyverse-de/go-mod/cfg v0.0.2/go.mod h1:jjn1fZJRwqKiYgiS5AcXg9Dzxp2QOiLyrWVWCcq9Dw0= github.com/cyverse-de/go-mod/gotelnats v0.0.11 h1:jpnnGrCUnBq1oUow6vujXaW3oiqusViqFUGpJD4njB0= github.com/cyverse-de/go-mod/gotelnats v0.0.11/go.mod h1:UDIqvtSCeOKvjV+gZ+DrcPoTHPYkQjIuFxw7IlcbAI0= github.com/cyverse-de/go-mod/logging v0.0.2 h1:MhmyAXl1UgxwXUgP2C5/jl7QAsF+Bs+r7Cs0SSZYLlI= @@ -98,7 +99,6 @@ github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= @@ -181,8 +181,6 @@ github.com/hjson/hjson-go/v4 v4.0.0 h1:wlm6IYYqHjOdXH1gHev4VoXCaW20HdQAGCxdOEEg2 github.com/hjson/hjson-go/v4 v4.0.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= -github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= @@ -196,8 +194,6 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= -github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/knadh/koanf v1.5.0 h1:q2TSd/3Pyc/5yP9ldIrSdIz26MCcyNQzW0pEAugLPNs= @@ -215,7 +211,6 @@ github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+k github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM= github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.1/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= @@ -234,8 +229,6 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.7 h1:fxWBnXkxfM6sRiuH3bqJ4CfzZojMOLVc0UTsTglEghA= github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= @@ -264,8 +257,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nats-io/nats.go v1.33.1 h1:8TxLZZ/seeEfR97qV0/Bl939tpDnt2Z2fK3HkPypj70= -github.com/nats-io/nats.go v1.33.1/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= github.com/nats-io/nats.go v1.34.1 h1:syWey5xaNHZgicYBemv0nohUPPmaLteiBEUT6Q5+F/4= github.com/nats-io/nats.go v1.34.1/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8= github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI= @@ -326,14 +317,10 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.3 h1:LNi0Qa7869/loPjz2kmMvp/jwZZnMZ9scMJKhDJ1DIo= -github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.3/go.mod h1:jyigonKik3C5V895QNiAGpKYKEvFuqjw9qAEZks1mUg= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.4 h1:x3omFAG2XkvWFg1hvXRinY2ExAL1Aacl7W9ZlYjo6gc= github.com/uptrace/opentelemetry-go-extra/otelsql v0.2.4/go.mod h1:qMKJr5fTnY0p7hqCQMNrAk62bCARWR5rAbTrGUFRuh4= -github.com/uptrace/opentelemetry-go-extra/otelsqlx v0.2.3 h1:KEX51LW1+n8bjRoTl4kP6klKjcptYDJXJ/TxzV8IRDk= -github.com/uptrace/opentelemetry-go-extra/otelsqlx v0.2.3/go.mod h1:0sguCDru7+Ik9OFJYIgAS8NpUFOoGOCsdU4r311ZrlY= github.com/uptrace/opentelemetry-go-extra/otelsqlx v0.2.4 h1:Pt/+CUTRusJb471SBXwkRCz+9pbOjNr80M6LlwqV07w= github.com/uptrace/opentelemetry-go-extra/otelsqlx v0.2.4/go.mod h1:kQgNoghy4K/wguxbOd/u0OJw/Y0maNPc7PF4JpEGeUc= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= @@ -346,22 +333,14 @@ github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1 go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= -go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= go.opentelemetry.io/otel v1.26.0 h1:LQwgL5s/1W7YiiRwxf03QGnWLb2HW4pLiAhaA5cZXBs= go.opentelemetry.io/otel v1.26.0/go.mod h1:UmLkJHUAidDval2EICqBMbnAd0/m2vmpf/dAM+fvFs4= go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4= go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= go.opentelemetry.io/otel/metric v1.26.0 h1:7S39CLuY5Jgg9CrnA9HHiEjGMF/X2VHvoXGgSllRz30= go.opentelemetry.io/otel/metric v1.26.0/go.mod h1:SY+rHOI4cEawI9a7N1A4nIg/nTQXe1ccCNWYOJUrpX4= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= go.opentelemetry.io/otel/sdk v1.26.0 h1:Y7bumHf5tAiDlRYFmGqetNcLaVUZmh4iYfmGxtmz7F8= go.opentelemetry.io/otel/sdk v1.26.0/go.mod h1:0p8MXpqLeJ0pzcszQQN4F0S5FVjBLgypeGSngLsmirs= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= go.opentelemetry.io/otel/trace v1.26.0 h1:1ieeAUb4y0TE26jUFrCIXKpTuVK7uJGN9/Z/2LP5sQA= go.opentelemetry.io/otel/trace v1.26.0/go.mod h1:4iDxvGDQuUkHve82hJJ8UqrwswHYsZuWCBllGV2U2y0= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= @@ -374,13 +353,9 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.20.0 h1:jmAMJJZXr5KiCw05dfYK9QnqaqKLYXijU23lsEdcQqg= -golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ= -golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -455,8 +430,6 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -511,8 +484,6 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= -google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=