From a9b8cd2db55fb405e323991cebed54f7074f678d Mon Sep 17 00:00:00 2001 From: Doctor Vince Date: Thu, 25 Apr 2024 09:47:40 -0400 Subject: [PATCH] Vc/incoming device api (#38) * update golang and golangci-lint * add a skeleton for incoming CIS data * implement attribute upsert for incoming inventory * WIP: inventory updates * move component type initialization to FleetDB Currently alloy creates the server component types on startup if they haven't been populated previously. This change imports bmc-toolbox's component slugs and uses them to populate the server_component_types table using an upsert. This should be able to capture changes to known component types on an upgrade too. * refactor updateAnyAttribute so we can do component attributes too * add real component initialization to setup and fix test fallout * flesh out the incoming inventory API a bit * parallel tests are problematic with a big global database * generalize the routines for upserting attributes and versioned attributes * implement bios and dimms * implement bmc and mainboard * refactor the common parts out of the update functions * change the namespacing and fimware/status handling for vattr * implement generic deserialization routines * update deps * convert to rivets.Server * enforce a test timeout to catch hangs * update linter config and fix linting issues in code * finish API and tests for inventory * fix up some overly brittle tests --- .github/workflows/lint-test.yml | 6 +- .golangci.yml | 4 +- Makefile | 4 +- cmd/serve.go | 7 + go.mod | 109 +++--- go.sum | 309 ++++++++++-------- internal/dbtools/component_types.go | 85 +++++ internal/dbtools/component_types_test.go | 26 ++ internal/dbtools/fixtures.go | 49 ++- internal/inventory/attribute_utils.go | 87 +++++ internal/inventory/component_attributes.go | 76 +++++ internal/inventory/device_components.go | 244 ++++++++++++++ internal/inventory/device_components_test.go | 280 ++++++++++++++++ internal/inventory/device_view.go | 204 ++++++++++++ internal/inventory/device_view_test.go | 105 ++++++ pkg/api/v1/router.go | 8 + pkg/api/v1/router_inventory.go | 112 +++++++ pkg/api/v1/router_inventory_test.go | 64 ++++ .../v1/router_server_component_type_test.go | 5 +- pkg/api/v1/router_server_components_test.go | 20 +- pkg/api/v1/router_server_test.go | 23 +- pkg/api/v1/server_service.go | 34 ++ pkg/api/v1/server_service_test.go | 40 +++ 23 files changed, 1679 insertions(+), 222 deletions(-) create mode 100644 internal/dbtools/component_types.go create mode 100644 internal/dbtools/component_types_test.go create mode 100644 internal/inventory/attribute_utils.go create mode 100644 internal/inventory/component_attributes.go create mode 100644 internal/inventory/device_components.go create mode 100644 internal/inventory/device_components_test.go create mode 100644 internal/inventory/device_view.go create mode 100644 internal/inventory/device_view_test.go create mode 100644 pkg/api/v1/router_inventory.go create mode 100644 pkg/api/v1/router_inventory_test.go diff --git a/.github/workflows/lint-test.yml b/.github/workflows/lint-test.yml index 7914ae1..c7b82c6 100644 --- a/.github/workflows/lint-test.yml +++ b/.github/workflows/lint-test.yml @@ -18,7 +18,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v4 with: - go-version: '1.21.0' + go-version: '1.22.1' - name: Install cockroach binary run: curl https://binaries.cockroachdb.com/cockroach-v23.1.11.linux-amd64.tgz | tar -xz && sudo cp -i cockroach-v23.1.11.linux-amd64/cockroach /usr/local/bin/ @@ -32,12 +32,12 @@ jobs: - name: Run golangci-lint uses: golangci/golangci-lint-action@v3 with: - version: v1.52.2 + version: v1.57.1 args: --timeout=5m - name: Run go tests and generate coverage report run: FLEETDB_CRDB_URI="host=localhost port=26257 user=root sslmode=disable dbname=fleetdb_test" go test -race -coverprofile=coverage.txt -covermode=atomic -tags testtools -p 1 ./... - + - name: Stop test database run: cockroach node drain --insecure --host=localhost:26257 diff --git a/.golangci.yml b/.golangci.yml index ff1fc7a..1ca9442 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -7,6 +7,8 @@ linters-settings: local-prefixes: github.com/metal-toolbox/fleetdb gofumpt: extra-rules: true + stylecheck: + checks: ["all", "-ST1000"] linters: enable: @@ -31,7 +33,7 @@ linters: - govet - misspell - noctx - - revive + # - revive XXX: fix up old code caught here - stylecheck - whitespace diff --git a/Makefile b/Makefile index d5a2ebe..ae261f4 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ test: | unit-test integration-test ## run integration tests integration-test: test-database @echo Running integration tests... - @FLEETDB_CRDB_URI="${TEST_DB}" go test -cover -tags testtools,integration -p 1 ./... + @FLEETDB_CRDB_URI="${TEST_DB}" go test -cover -tags testtools,integration -p 1 -timeout 1m ./... ## run lint and unit tests unit-test: | lint @@ -24,7 +24,7 @@ unit-test: | lint ## check test coverage coverage: | test-database @echo Generating coverage report... - @FLEETDB_CRDB_URI="${TEST_DB}" go test ./... -race -coverprofile=coverage.out -covermode=atomic -tags testtools -p 1 + @FLEETDB_CRDB_URI="${TEST_DB}" go test ./... -race -coverprofile=coverage.out -covermode=atomic -tags testtools,integration -p 1 @go tool cover -func=coverage.out @go tool cover -html=coverage.out diff --git a/cmd/serve.go b/cmd/serve.go index 94b6600..beb5e1f 100644 --- a/cmd/serve.go +++ b/cmd/serve.go @@ -13,6 +13,7 @@ import ( "go.infratographer.com/x/crdbx" "go.infratographer.com/x/otelx" "go.infratographer.com/x/viperx" + "go.uber.org/zap" "gocloud.dev/secrets" // import gocdk secret drivers @@ -92,6 +93,12 @@ func serve(ctx context.Context) { dbtools.RegisterHooks() + if err := dbtools.SetupComponentTypes(ctx, db); err != nil { + logger.With( + zap.Error(err), + ).Fatal("set up component types") + } + keeper, err := secrets.OpenKeeper(ctx, viper.GetString("db.encryption_driver")) if err != nil { logger.Fatalw("failed to open secrets keeper", "error", err) diff --git a/go.mod b/go.mod index 4b8fd55..7b373e6 100644 --- a/go.mod +++ b/go.mod @@ -1,59 +1,62 @@ module github.com/metal-toolbox/fleetdb -go 1.19 +go 1.22 require ( github.com/XSAM/otelsql v0.23.0 // indirect - github.com/cockroachdb/cockroach-go/v2 v2.3.5 + github.com/cockroachdb/cockroach-go/v2 v2.3.6 github.com/friendsofgo/errors v0.9.2 - github.com/gin-contrib/cors v1.4.0 + github.com/gin-contrib/cors v1.5.0 github.com/gin-contrib/zap v1.1.0 github.com/gin-gonic/gin v1.9.1 - github.com/google/uuid v1.3.1 - github.com/gosimple/slug v1.13.1 + github.com/google/uuid v1.6.0 + github.com/gosimple/slug v1.14.0 github.com/jmoiron/sqlx v1.3.5 github.com/lib/pq v1.10.9 github.com/pkg/errors v0.9.1 github.com/pressly/goose/v3 v3.15.0 // indirect - github.com/prometheus/client_golang v1.16.0 // indirect - github.com/spf13/cobra v1.7.0 + github.com/prometheus/client_golang v1.19.0 // indirect + github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 // indirect - github.com/spf13/viper v1.16.0 + github.com/spf13/viper v1.18.2 github.com/stretchr/testify v1.9.0 github.com/volatiletech/null/v8 v8.1.2 github.com/volatiletech/randomize v0.0.1 - github.com/volatiletech/sqlboiler/v4 v4.15.0 - github.com/volatiletech/strmangle v0.0.5 + github.com/volatiletech/sqlboiler/v4 v4.16.2 + github.com/volatiletech/strmangle v0.0.6 github.com/zsais/go-gin-prometheus v0.1.0 - go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.42.0 - go.opentelemetry.io/otel v1.16.0 + go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.49.0 + go.opentelemetry.io/otel v1.25.0 go.opentelemetry.io/otel/exporters/jaeger v1.16.0 // indirect - go.opentelemetry.io/otel/sdk v1.16.0 // indirect + go.opentelemetry.io/otel/sdk v1.25.0 // indirect go.uber.org/zap v1.27.0 gopkg.in/square/go-jose.v2 v2.6.0 ) require ( + github.com/bmc-toolbox/common v0.0.0-20231204194243-7bcbccab7116 + github.com/metal-toolbox/rivets v1.0.3 github.com/volatiletech/sqlboiler v3.7.1+incompatible go.hollow.sh/toolbox v0.6.3 - go.infratographer.com/x v0.3.7 - gocloud.dev v0.33.0 - golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 + go.infratographer.com/x v0.3.9 + gocloud.dev v0.36.0 + golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 ) require ( + cloud.google.com/go/kms v1.15.7 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bytedance/sonic v1.11.3 // indirect - github.com/cenkalti/backoff/v4 v4.2.1 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect github.com/chenzhuoyu/iasm v0.9.1 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/ericlagergren/decimal v0.0.0-20221120152707-495c53812d05 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/ericlagergren/decimal v0.0.0-20240305081647-93d586550569 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gabriel-vasile/mimetype v1.4.3 // indirect github.com/gin-contrib/sse v0.1.0 // indirect - github.com/go-logr/logr v1.2.4 // indirect + github.com/go-logr/logr v1.4.1 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect @@ -61,70 +64,68 @@ require ( github.com/goccy/go-json v0.10.2 // indirect github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/googleapis/gax-go/v2 v2.12.0 // indirect + github.com/googleapis/gax-go/v2 v2.12.2 // indirect github.com/gosimple/unidecode v1.0.1 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.14.1 // indirect + github.com/jackc/pgconn v1.14.3 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.2 // indirect - github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect - github.com/jackc/pgtype v1.14.0 // indirect - github.com/jackc/pgx/v4 v4.18.1 // indirect + github.com/jackc/pgproto3/v2 v2.3.3 // indirect + github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect + github.com/jackc/pgtype v1.14.2 // indirect + github.com/jackc/pgx/v4 v4.18.2 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.16.7 // indirect + github.com/klauspost/compress v1.17.7 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect - github.com/nats-io/nats.go v1.28.0 // indirect - github.com/nats-io/nkeys v0.4.4 // indirect + github.com/nats-io/nats.go v1.33.1 // indirect + github.com/nats-io/nkeys v0.4.7 // indirect github.com/nats-io/nuid v1.0.1 // indirect github.com/pelletier/go-toml/v2 v2.2.0 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_model v0.4.0 // indirect - github.com/prometheus/common v0.44.0 // indirect - github.com/prometheus/procfs v0.11.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus/client_model v0.6.0 // indirect + github.com/prometheus/common v0.49.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/spf13/afero v1.9.5 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect - github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/ugorji/go/codec v1.2.12 // indirect github.com/volatiletech/inflect v0.0.1 // indirect github.com/volatiletech/null v8.0.0+incompatible // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.16.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.25.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.25.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 // indirect - go.opentelemetry.io/otel/metric v1.16.0 // indirect - go.opentelemetry.io/otel/trace v1.16.0 // indirect - go.opentelemetry.io/proto/otlp v1.0.0 // indirect + go.opentelemetry.io/otel/metric v1.25.0 // indirect + go.opentelemetry.io/otel/trace v1.25.0 // indirect + go.opentelemetry.io/proto/otlp v1.2.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/arch v0.7.0 // indirect - golang.org/x/crypto v0.21.0 // indirect - golang.org/x/net v0.22.0 // indirect - golang.org/x/sys v0.18.0 // indirect + golang.org/x/crypto v0.22.0 // indirect + golang.org/x/net v0.24.0 // indirect + golang.org/x/sys v0.19.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect - google.golang.org/api v0.137.0 // indirect - google.golang.org/genproto v0.0.0-20230815205213-6bfd019c3878 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20230815205213-6bfd019c3878 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20230815205213-6bfd019c3878 // indirect - google.golang.org/grpc v1.57.0 // indirect + google.golang.org/api v0.168.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be // indirect + google.golang.org/grpc v1.63.2 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 371cedb..712fcf2 100644 --- a/go.sum +++ b/go.sum @@ -29,7 +29,7 @@ cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= -cloud.google.com/go v0.110.7 h1:rJyC7nWRg2jWGZ4wSJ5nY65GTdYJkg0cd/uXb+ACI6o= +cloud.google.com/go v0.110.10 h1:LXy9GEO+timppncPIAZoOj3l58LIU9k+kn48AN7IO3Y= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= @@ -41,13 +41,17 @@ cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJW cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= -cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY= +cloud.google.com/go/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg= +cloud.google.com/go/compute v1.24.0/go.mod h1:kw1/T+h/+tK2LJK0wiPPx1intgdAM3j/g3hFDlscY40= cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= +cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= cloud.google.com/go/firestore v1.6.1/go.mod h1:asNXNOzBdyVQmEU+ggO8UPodTkEVFW5Qx+rwHnAz+EY= -cloud.google.com/go/iam v1.1.1 h1:lW7fzj15aVIXYHREOqjRBV9PsH0Z6u8Y46a1YGvQP4Y= -cloud.google.com/go/kms v1.15.0 h1:xYl5WEaSekKYN5gGRyhjvZKM22GVBBCzegGNVPy+aIs= +cloud.google.com/go/iam v1.1.6 h1:bEa06k05IO4f4uJonbB5iAgKTPpABy1ayxaIZV/GHVc= +cloud.google.com/go/iam v1.1.6/go.mod h1:O0zxdPeGBoFdWW3HWmBxJsk0pfvNM/p/qa82rWOGTwI= +cloud.google.com/go/kms v1.15.7 h1:7caV9K3yIxvlQPAcaFffhlT7d1qpxjB1wHBtjWa13SM= +cloud.google.com/go/kms v1.15.7/go.mod h1:ub54lbsa6tDkUwnu4W7Yt1aAIFLnspgh0kPGToDukeI= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= @@ -91,12 +95,14 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= +github.com/bmc-toolbox/common v0.0.0-20231204194243-7bcbccab7116 h1:gqWn/cMjryKoUfITx2vRHrRHTvd9fQ+zKPwWsmMIrK4= +github.com/bmc-toolbox/common v0.0.0-20231204194243-7bcbccab7116/go.mod h1:SY//n1PJjZfbFbmAsB6GvEKbc7UXz3d30s3kWxfJQ/c= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= github.com/bytedance/sonic v1.11.3 h1:jRN+yEjakWh8aK5FzrciUHG8OFXK+4/KrAX/ysEtHAA= github.com/bytedance/sonic v1.11.3/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= @@ -126,22 +132,25 @@ github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/cockroachdb/cockroach-go/v2 v2.3.5 h1:Khtm8K6fTTz/ZCWPzU9Ne3aOW9VyAnj4qIPCJgKtwK0= -github.com/cockroachdb/cockroach-go/v2 v2.3.5/go.mod h1:1wNJ45eSXW9AnOc3skntW9ZUZz6gxrQK3cOj3rK+BC8= +github.com/cockroachdb/cockroach-go/v2 v2.3.6 h1:Wlv9TzkrG9V7i6u8dEtmXPrBzvfFp+CgJNs696rAajM= +github.com/cockroachdb/cockroach-go/v2 v2.3.6/go.mod h1:1wNJ45eSXW9AnOc3skntW9ZUZz6gxrQK3cOj3rK+BC8= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko= github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -153,28 +162,30 @@ github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go. github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/ericlagergren/decimal v0.0.0-20190420051523-6335edbaa640/go.mod h1:mdYyfAkzn9kyJ/kMk/7WE9ufl9lflh+2NvecQ5mAghs= -github.com/ericlagergren/decimal v0.0.0-20221120152707-495c53812d05 h1:S92OBrGuLLZsyM5ybUzgc/mPjIYk2AZqufieooe98uw= -github.com/ericlagergren/decimal v0.0.0-20221120152707-495c53812d05/go.mod h1:M9R1FoZ3y//hwwnJtO51ypFGwm8ZfpxPT/ZLtO1mcgQ= +github.com/ericlagergren/decimal v0.0.0-20240305081647-93d586550569 h1:PNe5U6Gc0FAVbptp1BXy1ZYi8MyBoeIBWLU2DBH9YnA= +github.com/ericlagergren/decimal v0.0.0-20240305081647-93d586550569/go.mod h1:M9R1FoZ3y//hwwnJtO51ypFGwm8ZfpxPT/ZLtO1mcgQ= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/friendsofgo/errors v0.9.2 h1:X6NYxef4efCBdwI7BgS820zFaN7Cphrmb+Pljdzjtgk= github.com/friendsofgo/errors v0.9.2/go.mod h1:yCvFW5AkDIL9qn7suHVLiI/gH228n7PC4Pn44IGoTOI= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g= -github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs= +github.com/gin-contrib/cors v1.5.0 h1:DgGKV7DDoOn36DFkNtbHrjoRiT5ExCe+PC9/xp7aKvk= +github.com/gin-contrib/cors v1.5.0/go.mod h1:TvU7MAZ3EwrPLI2ztzTt3tqgvBCq+wn8WpZmfADjupI= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-contrib/zap v1.1.0 h1:GWzL9+zmK8OJdiycaK2SK1/D3SZIYpieJDD0QCNAU1o= github.com/gin-contrib/zap v1.1.0/go.mod h1:KzROP9rAL7ofFd1P8lx7Oo2lerwPWNL5vv4f6U/mAk8= -github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -187,29 +198,27 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= -github.com/go-logr/logr v1.2.4/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +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-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= -github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= -github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= -github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos= github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4= github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= +github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= +github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= @@ -224,7 +233,6 @@ github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2V github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -256,8 +264,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -275,7 +283,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= @@ -297,14 +306,17 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/google/s2a-go v0.1.5 h1:8IYp3w9nysqv3JH+NJgXJzGbDHzLOTj43BmSkp+O7qg= +github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= +github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8= -github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM= +github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= +github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= +github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= @@ -312,17 +324,17 @@ github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0 github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= -github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= -github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= +github.com/googleapis/gax-go/v2 v2.12.2 h1:mhN09QQW1jEWeMF74zGR81R30z4VJzjZsfkUhuHF+DA= +github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gosimple/slug v1.13.1 h1:bQ+kpX9Qa6tHRaK+fZR0A0M2Kd7Pa5eHPPsb1JpHD+Q= -github.com/gosimple/slug v1.13.1/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ= +github.com/gosimple/slug v1.14.0 h1:RtTL/71mJNDfpUbCOmnf/XFkzKRtD6wL6Uy+3akm4Es= +github.com/gosimple/slug v1.14.0/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ= github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o= github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 h1:dygLcbEBA+t/P7ck6a8AkXv6juQ4cK0RHBoh32jxhHM= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2/go.mod h1:Ap9RLCIJVtgQg1/BBgVEfypOAySvvlcpcVQkSzJCH4Y= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 h1:/c3QmbOGMGTOumP2iT/rCwB7b0QDGLKzqOmktBjT+Is= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM= github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -376,9 +388,8 @@ github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsU github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.14.0/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= -github.com/jackc/pgconn v1.14.1 h1:smbxIaZA08n6YuxEX1sDyjV/qkbtUtkH20qLkR9MUR4= -github.com/jackc/pgconn v1.14.1/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= +github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w= +github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= @@ -394,23 +405,23 @@ github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvW github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.2 h1:7eY55bdBeCz1F2fTzSz69QC+pG46jYq9/jtSPiJ5nn0= -github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag= +github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA= +github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw= -github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.14.2 h1:QBdZQTKpPdBlw2AdKwHEyqUcm/lrl2cwWAHjCMyln/o= +github.com/jackc/pgtype v1.14.2/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.18.1 h1:YP7G1KABtKpB5IHrO9vYwSrCOhs7p3uqhvhhQBptya0= -github.com/jackc/pgx/v4 v4.18.1/go.mod h1:FydWkUyadDmdNH/mHnGob881GawxeEm7TcMCzkb+qQE= +github.com/jackc/pgx/v4 v4.18.2 h1:xVpYkNR5pk5bMCZGfClbO962UIqVABcAGt7ha1s/FeU= +github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= @@ -429,12 +440,13 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kat-co/vala v0.0.0-20170210184112-42e1d8b61f12/go.mod h1:u9MdXq/QageOOSGp7qG4XAQsYUMP+V5zEel/Vrl6OOc= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= 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.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= -github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= +github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= @@ -446,16 +458,15 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -489,12 +500,13 @@ github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A github.com/mattn/go-sqlite3 v1.14.14 h1:qZgc/Rwetq+MtyE18WhzjokPD93dNqLGNT3QJuLvBGw= github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/metal-toolbox/rivets v1.0.3 h1:ZW9q8V3vz6VxAczC4eR1YJdl+kapHF3ebVc+4r3NmR8= +github.com/metal-toolbox/rivets v1.0.3/go.mod h1:EMQJRT1mjIyFRXxvKNaBlz7Z4Sp88rTaGO8W18olN2I= github.com/microsoft/go-mssqldb v0.17.0/go.mod h1:OkoNGhGEs8EZqchVTtochlXruEhEOaO4S0d2sB5aeGQ= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g= +github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= @@ -518,12 +530,14 @@ github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3P github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= 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/jwt/v2 v2.4.1 h1:Y35W1dgbbz2SQUYDPCaclXcuqleVmpbRa7646Jf2EX4= -github.com/nats-io/nats-server/v2 v2.9.17 h1:gFpUQ3hqIDJrnqog+Bl5vaXg+RhhYEZIElasEuRn2tw= -github.com/nats-io/nats.go v1.28.0 h1:Th4G6zdsz2d0OqXdfzKLClo6bOfoI/b1kInhRtFIy5c= -github.com/nats-io/nats.go v1.28.0/go.mod h1:XpbWUlOElGwTYbMR7imivs7jJj9GtK7ypv321Wp6pjc= -github.com/nats-io/nkeys v0.4.4 h1:xvBJ8d69TznjcQl9t6//Q5xXuVhyYiSos6RPtvQNTwA= -github.com/nats-io/nkeys v0.4.4/go.mod h1:XUkxdLPTufzlihbamfzQ7mw/VGx6ObUs+0bN5sNvt64= +github.com/nats-io/jwt/v2 v2.5.5 h1:ROfXb50elFq5c9+1ztaUbdlrArNFl2+fQWP6B8HGEq4= +github.com/nats-io/jwt/v2 v2.5.5/go.mod h1:ZdWS1nZa6WMZfFwwgpEaqBV8EPGVgOTDHN/wTbz0Y5A= +github.com/nats-io/nats-server/v2 v2.10.11 h1:yKUiLVincZISpo3A4YljJQ+HfLltGAgoNNJl99KL8I0= +github.com/nats-io/nats-server/v2 v2.10.11/go.mod h1:dXtOqVWzbMTEj+tUyC/itXjJhW37xh0tUBrTAlqAfx8= +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/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI= +github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= @@ -535,14 +549,14 @@ github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeB github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4/go.mod h1:N6UoU20jOqggOuDwUaBQpluzLNDqif3kq9z2wpdYEfQ= github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/pressly/goose/v3 v3.15.0 h1:6tY5aDqFknY6VZkorFGgZtWygodZQxfmmEF4rqyJW9k= @@ -552,40 +566,45 @@ github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5Fsn github.com/prometheus/client_golang v1.4.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8= -github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc= +github.com/prometheus/client_golang v1.19.0 h1:ygXvpU1AoN1MhdzckN+PyD9QJOSD4x7kmXYlnfbA6JU= +github.com/prometheus/client_golang v1.19.0/go.mod h1:ZRM9uEAypZakd+q/x7+gmsvXdURP+DABIEIjnmDdp+k= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY= -github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU= +github.com/prometheus/client_model v0.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= +github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY= -github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY= +github.com/prometheus/common v0.49.0 h1:ToNTdK4zSnPVJmh698mGFkDor9wBI/iGaJy5dbH1EgI= +github.com/prometheus/common v0.49.0/go.mod h1:Kxm+EULxRbUkjGU6WFsQqo3ORzB4tyKvlWFOE9mB2sE= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.11.1 h1:xRC8Iq1yyca5ypa9n1EZnWZkt7dwcoRPQwX/5gwaUuI= -github.com/prometheus/procfs v0.11.1/go.mod h1:eesXgaPo1q7lBpVMoMy0ZOFTth9hBn4W/y0/p/ScXhY= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= +github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.6.0/go.mod h1:U8+INwJo3nBv1m6A/8OBXAq7Jnpspk5AxSgDyEQcea8= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= @@ -598,25 +617,26 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= -github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= -github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= -github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= -github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= -github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc= -github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg= +github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= +github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= @@ -644,8 +664,6 @@ github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSW github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= -github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= -github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/volatiletech/inflect v0.0.1 h1:2a6FcMQyhmPZcLa+uet3VJ8gLn/9svWhJxJYwvE8KsU= @@ -658,11 +676,11 @@ github.com/volatiletech/randomize v0.0.1 h1:eE5yajattWqTB2/eN8df4dw+8jwAzBtbdo5s github.com/volatiletech/randomize v0.0.1/go.mod h1:GN3U0QYqfZ9FOJ67bzax1cqZ5q2xuj2mXrXBjWaRTlY= github.com/volatiletech/sqlboiler v3.7.1+incompatible h1:dm9/NjDskQVwAarmpeZ2UqLn1NKE8M3WHSHBS4jw2x8= github.com/volatiletech/sqlboiler v3.7.1+incompatible/go.mod h1:jLfDkkHWPbS2cWRLkyC20vQWaIQsASEY7gM7zSo11Yw= -github.com/volatiletech/sqlboiler/v4 v4.15.0 h1:+twm3mA34SaUF6wB9U6QkXxkK8AKkV5EfgMSvcKWeY4= -github.com/volatiletech/sqlboiler/v4 v4.15.0/go.mod h1:s643wqYyCQ7Ak2hMVxH7kTS0+lFPNlj+gHKUIukJ0YA= +github.com/volatiletech/sqlboiler/v4 v4.16.2 h1:PcV2bxjE+S+GwPKCyX7/AjlY3aiTKsOEjciLhpWQImc= +github.com/volatiletech/sqlboiler/v4 v4.16.2/go.mod h1:B14BPBGTrJ2X6l7lwnvV/iXgYR48+ozGSlzHI3frl6U= github.com/volatiletech/strmangle v0.0.1/go.mod h1:F6RA6IkB5vq0yTG4GQ0UsbbRcl3ni9P76i+JrTBKFFg= -github.com/volatiletech/strmangle v0.0.5 h1:CompJPy+lAi9h+YU/IzBR4X2RDRuAuEIP+kjFdyZXcU= -github.com/volatiletech/strmangle v0.0.5/go.mod h1:ycDvbDkjDvhC0NUU8w3fWwl5JEMTV56vTKXzR3GeR+0= +github.com/volatiletech/strmangle v0.0.6 h1:AdOYE3B2ygRDq4rXDij/MMwq6KVK/pWAYxpC7CLrkKQ= +github.com/volatiletech/strmangle v0.0.6/go.mod h1:ycDvbDkjDvhC0NUU8w3fWwl5JEMTV56vTKXzR3GeR+0= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -678,8 +696,8 @@ go.etcd.io/etcd/client/v2 v2.305.4/go.mod h1:Ud+VUwIi9/uQHOMA+4ekToJ12lTxlv0zB/+ go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= go.hollow.sh/toolbox v0.6.3 h1:IJOjiGdiwWwXJ2QfOkJuSucSIqrdXJbUBFst3u6T6z4= go.hollow.sh/toolbox v0.6.3/go.mod h1:nl+5RDDyYY/+wukOUzHHX2mOyWKRjlTOXUcGxny+tns= -go.infratographer.com/x v0.3.7 h1:kkykoVtC8XrmvC4oZwHWa/15+dv9RhQHgSm8KoEb/Nc= -go.infratographer.com/x v0.3.7/go.mod h1:/zbDM9njbWzUDCA9pkbi1z/v4VZjGsVHx+SPycSgIhg= +go.infratographer.com/x v0.3.9 h1:fsfF/w5zHgiNAHvYmvsWlICNha2X53WNLVSKOkyPnWo= +go.infratographer.com/x v0.3.9/go.mod h1:n/61MZRKFbGlS8xUwAhTyDhqcL2Wk6uPsXADC2n5t1I= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -689,39 +707,44 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.42.0 h1:l7AmwSVqozWKKXeZHycpdmpycQECRpoGwJ1FW2sWfTo= -go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.42.0/go.mod h1:Ep4uoO2ijR0f49Pr7jAqyTjSCyS1SRL18wwttKfwqXA= -go.opentelemetry.io/contrib/propagators/b3 v1.17.0 h1:ImOVvHnku8jijXqkwCSyYKRDt2YrnGXD4BbhcpfbfJo= -go.opentelemetry.io/otel v1.16.0 h1:Z7GVAX/UkAXPKsy94IU+i6thsQS4nb7LviLpnaNeW8s= -go.opentelemetry.io/otel v1.16.0/go.mod h1:vl0h9NUa1D5s1nv3A5vZOYWn8av4K8Ml6JDeHrT/bx4= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.49.0 h1:1f31+6grJmV3X4lxcEvUy13i5/kfDw1nJZwhd8mA4tg= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.49.0/go.mod h1:1P/02zM3OwkX9uki+Wmxw3a5GVb6KUXRsa7m7bOC9Fg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= +go.opentelemetry.io/contrib/propagators/b3 v1.24.0 h1:n4xwCdTx3pZqZs2CjS/CUZAs03y3dZcGhC/FepKtEUY= +go.opentelemetry.io/contrib/propagators/b3 v1.24.0/go.mod h1:k5wRxKRU2uXx2F8uNJ4TaonuEO/V7/5xoz7kdsDACT8= +go.opentelemetry.io/otel v1.25.0 h1:gldB5FfhRl7OJQbUHt/8s0a7cE8fbsPAtdpRaApKy4k= +go.opentelemetry.io/otel v1.25.0/go.mod h1:Wa2ds5NOXEMkCmUou1WA7ZBfLTHWIsp034OVD7AO+Vg= go.opentelemetry.io/otel/exporters/jaeger v1.16.0 h1:YhxxmXZ011C0aDZKoNw+juVWAmEfv/0W2XBOv9aHTaA= go.opentelemetry.io/otel/exporters/jaeger v1.16.0/go.mod h1:grYbBo/5afWlPpdPZYhyn78Bk04hnvxn2+hvxQhKIQM= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0 h1:t4ZwRPU+emrcvM2e9DHd0Fsf0JTPVcbfa/BhTDF03d0= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.16.0/go.mod h1:vLarbg68dH2Wa77g71zmKQqlQ8+8Rq3GRG31uc0WcWI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0 h1:cbsD4cUcviQGXdw8+bo5x2wazq10SKz8hEbtCRPcU78= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.16.0/go.mod h1:JgXSGah17croqhJfhByOLVY719k1emAXC8MVhCIJlRs= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0 h1:TVQp/bboR4mhZSav+MdgXB8FaRho1RC8UwVn3T0vjVc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.16.0/go.mod h1:I33vtIe0sR96wfrUcilIzLoA3mLHhRmz9S9Te0S3gDo= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.16.0 h1:iqjq9LAB8aK++sKVcELezzn655JnBNdsDhghU4G/So8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.16.0/go.mod h1:hGXzO5bhhSHZnKvrDaXB82Y9DRFour0Nz/KrBh7reWw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0 h1:dT33yIHtmsqpixFsSQPwNeY5drM9wTcoL8h0FWF4oGM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.25.0/go.mod h1:h95q0LBGh7hlAC08X2DhSeyIG02YQ0UyioTCVAqRPmc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.25.0 h1:vOL89uRfOCCNIjkisd0r7SEdJF3ZJFyCNY34fdZs8eU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.25.0/go.mod h1:8GlBGcDk8KKi7n+2S4BT/CPZQYH3erLu0/k64r1MYgo= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.25.0 h1:Mbi5PKN7u322woPa85d7ebZ+SOvEoPvoiBu+ryHWgfA= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.25.0/go.mod h1:e7ciERRhZaOZXVjx5MiL8TK5+Xv7G5Gv5PA2ZDEJdL8= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0 h1:+XWJd3jf75RXJq29mxbuXhCXFDG3S3R4vBUeSI2P7tE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.16.0/go.mod h1:hqgzBPTf4yONMFgdZvL/bK42R/iinTyVQtiWihs3SZc= -go.opentelemetry.io/otel/metric v1.16.0 h1:RbrpwVG1Hfv85LgnZ7+txXioPDoh6EdbZHo26Q3hqOo= -go.opentelemetry.io/otel/metric v1.16.0/go.mod h1:QE47cpOmkwipPiefDwo2wDzwJrlfxxNYodqc4xnGCo4= -go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE= -go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4= +go.opentelemetry.io/otel/metric v1.25.0 h1:LUKbS7ArpFL/I2jJHdJcqMGxkRdxpPHE0VU/D4NuEwA= +go.opentelemetry.io/otel/metric v1.25.0/go.mod h1:rkDLUSd2lC5lq2dFNrX9LGAbINP5B7WBkC78RXCpH5s= +go.opentelemetry.io/otel/sdk v1.25.0 h1:PDryEJPC8YJZQSyLY5eqLeafHtG+X7FWnf3aXMtxbqo= +go.opentelemetry.io/otel/sdk v1.25.0/go.mod h1:oFgzCM2zdsxKzz6zwpTZYLLQsFwc+K0daArPdIhuxkw= go.opentelemetry.io/otel/sdk/metric v0.39.0 h1:Kun8i1eYf48kHH83RucG93ffz0zGV1sh46FAScOTuDI= -go.opentelemetry.io/otel/trace v1.16.0 h1:8JRpaObFoW0pxuVPapkgH8UhHQj+bJW8jJsCZEu5MQs= -go.opentelemetry.io/otel/trace v1.16.0/go.mod h1:Yt9vYq1SdNz3xdjZZK7wcXv1qv2pwLkqr2QVwea0ef0= +go.opentelemetry.io/otel/sdk/metric v0.39.0/go.mod h1:piDIRgjcK7u0HCL5pCA4e74qpK/jk3NiUoAHATVAmiI= +go.opentelemetry.io/otel/trace v1.25.0 h1:tqukZGLwQYRIFtSQM2u2+yfMVTgGVeqRLPUYx1Dq6RM= +go.opentelemetry.io/otel/trace v1.25.0/go.mod h1:hCCs70XM/ljO+BeQkyFnbK28SBIJ/Emuha+ccrCRT7I= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= -go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= +go.opentelemetry.io/proto/otlp v1.2.0 h1:pVeZGk7nXDC9O2hncA6nHldxEjm6LByfA2aN8IOkz94= +go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naRm/KDsgaHD8A= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= @@ -735,8 +758,8 @@ go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -gocloud.dev v0.33.0 h1:ET5z49jm1+eUhY5BkuGk2d7czfgGeXKd4vtg1Jcg9OQ= -gocloud.dev v0.33.0/go.mod h1:z6W8qorjrfM09H8t1MDk8KLPj3Xi26aFBzDKAHWIgLU= +gocloud.dev v0.36.0 h1:q5zoXux4xkOZP473e1EZbG8Gq9f0vlg1VNH5Du/ybus= +gocloud.dev v0.36.0/go.mod h1:bLxah6JQVKBaIxzsr5BQLYB4IYdWHkMZdzCXlo6F0gg= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc= golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= @@ -758,11 +781,9 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220511200225-c6db032c6c88/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -773,8 +794,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63 h1:m64FZMko/V45gv0bNmrNYoDEq8U5YUhetc9cBWKS1TQ= -golang.org/x/exp v0.0.0-20230817173708-d852ddb80c63/go.mod h1:0v4NqG35kSWCMzLaMeX+IQrlSnVE/bqGSyC2cz/9Le8= +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/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -801,7 +822,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= +golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -852,9 +874,8 @@ golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +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-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -875,7 +896,8 @@ golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.11.0 h1:vPL4xzxBM4niKCW6g9whtaWVXTJf1U5e4aZxxFx/gbU= +golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= +golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -889,7 +911,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -976,15 +999,13 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -994,13 +1015,13 @@ golang.org/x/text v0.3.4/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.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= 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= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -1063,7 +1084,8 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.12.1-0.20230815132531-74c255bcf846 h1:Vve/L0v7CXXuxUmaMGIEK/dEeq7uiqb5qBgQrZzIE7E= +golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ= +golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1114,16 +1136,17 @@ google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRR google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= google.golang.org/api v0.81.0/go.mod h1:FA6Mb/bZxj706H2j+j2d6mHEEaHBmbbWnkfvmorOCko= -google.golang.org/api v0.137.0 h1:QrKX6uNvzJLr0Fd3vWVqcyrcmFoYi036VUAsZbiF4+s= -google.golang.org/api v0.137.0/go.mod h1:4xyob8CxC+0GChNBvEUAk8VBKNvYOTWM9T3v3UfRxuY= +google.golang.org/api v0.168.0 h1:MBRe+Ki4mMN93jhDDbpuRLjRddooArz4FeSObvUMmjY= +google.golang.org/api v0.168.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1202,12 +1225,12 @@ google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= -google.golang.org/genproto v0.0.0-20230815205213-6bfd019c3878 h1:Iveh6tGCJkHAjJgEqUQYGDGgbwmhjoAOz8kO/ajxefY= -google.golang.org/genproto v0.0.0-20230815205213-6bfd019c3878/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4= -google.golang.org/genproto/googleapis/api v0.0.0-20230815205213-6bfd019c3878 h1:WGq4lvB/mlicysM/dUT3SBvijH4D3sm/Ny1A4wmt2CI= -google.golang.org/genproto/googleapis/api v0.0.0-20230815205213-6bfd019c3878/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230815205213-6bfd019c3878 h1:lv6/DhyiFFGsmzxbsUUTOkN29II+zeWHxvT8Lpdxsv0= -google.golang.org/genproto/googleapis/rpc v0.0.0-20230815205213-6bfd019c3878/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de h1:F6qOa9AZTYJXOUEr4jDysRDLrm4PHePlge4v4TGAlxY= +google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:VUhTRKeHn9wwcdrk73nvdC9gF178Tzhmt/qyaFcPLSo= +google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be h1:Zz7rLWqp0ApfsR/l7+zSHhY3PMiH2xqgxlfYfAfNpoU= +google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be/go.mod h1:dvdCTIoAGbkWbcIKBniID56/7XHTt6WfxXNMxuziJ+w= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be h1:LG9vZxsWGOmUKieR8wPAUR3u3MpnYFQZROPIMaXh7/A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1238,8 +1261,8 @@ google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ5 google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= -google.golang.org/grpc v1.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw= -google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo= +google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= +google.golang.org/grpc v1.63.2/go.mod h1:WAX/8DgncnokcFUldAxq7GeB5DXHDbMF+lLvDomNkRA= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -1294,10 +1317,12 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo= +lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= modernc.org/cc/v3 v3.36.2/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= modernc.org/cc/v3 v3.36.3/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI= modernc.org/cc/v3 v3.41.0 h1:QoR1Sn3YWlmA1T4vLaKZfawdVtSiGx8H+cEojbC7v1Q= +modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y= modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc= modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw= modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ= @@ -1305,6 +1330,7 @@ modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWs modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws= modernc.org/ccgo/v3 v3.16.9/go.mod h1:zNMzC9A9xeNUepy6KuZBbugn3c0Mc9TeiJO4lgvkJDo= modernc.org/ccgo/v3 v3.16.14 h1:af6KNtFgsVmnDYrWk3PQCS9XT6BXe7o3ZFJKkIKvXNQ= +modernc.org/ccgo/v3 v3.16.14/go.mod h1:mPDSujUIaTNWQSG4eqKw+atqLOEbma6Ncsa94WbC9zo= modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= @@ -1315,19 +1341,23 @@ modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA= modernc.org/libc v1.17.0/go.mod h1:XsgLldpP4aWlPlsjqKRdHPqCxCjISdHfM/yeWC5GyW0= modernc.org/libc v1.17.1/go.mod h1:FZ23b+8LjxZs7XtFMbSzL/EhPxNbfZbErxEHc7cbD9s= modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM= +modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak= modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4= +modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo= modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= modernc.org/memory v1.2.0/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw= modernc.org/memory v1.2.1/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= modernc.org/memory v1.6.0 h1:i6mzavxrE9a30whzMfwf7XWVODx2r5OYXvU46cirX7o= +modernc.org/memory v1.6.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU= modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4= modernc.org/sqlite v1.25.0 h1:AFweiwPNd/b3BoKnBOfFm+Y260guGMF+0UFk0savqeA= +modernc.org/sqlite v1.25.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU= modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY= modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw= @@ -1335,6 +1365,7 @@ modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw= modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= +modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/internal/dbtools/component_types.go b/internal/dbtools/component_types.go new file mode 100644 index 0000000..d886988 --- /dev/null +++ b/internal/dbtools/component_types.go @@ -0,0 +1,85 @@ +package dbtools + +import ( + "context" + "database/sql" + + "github.com/bmc-toolbox/common" + "github.com/gosimple/slug" + "github.com/jmoiron/sqlx" + "github.com/pkg/errors" + "github.com/volatiletech/sqlboiler/v4/boil" + + "github.com/metal-toolbox/fleetdb/internal/models" +) + +var ( + errAddTypes = errors.New("unable to add component types") + errBadName = errors.New("unknown component name") +) + +// XXX: if bmc-toolbox exported this as a list, we could just import it. +var knownComponentTypes = []string{ + common.SlugBackplaneExpander, + common.SlugChassis, + common.SlugTPM, + common.SlugGPU, + common.SlugCPU, + common.SlugPhysicalMem, + common.SlugStorageController, + common.SlugBMC, + common.SlugBIOS, + common.SlugDrive, + common.SlugDriveTypePCIeNVMEeSSD, + common.SlugDriveTypeSATASSD, + common.SlugDriveTypeSATAHDD, + common.SlugNIC, + common.SlugPSU, + common.SlugCPLD, + common.SlugEnclosure, + common.SlugUnknown, + common.SlugMainboard, +} + +var componentTypeIDCache = map[string]string{} + +// SetupComponentTypes upserts all known component types to the database. +// Despite the descriptor, in the database the Name field of the component type +// is the verbatim value of the string, and the Slug is computed as a lower-case +// english-localized variant. +func SetupComponentTypes(ctx context.Context, db *sqlx.DB) error { + txn := db.MustBeginTx(ctx, &sql.TxOptions{}) + for _, typ := range knownComponentTypes { + existing, err := models.ServerComponentTypes( + models.ServerComponentTypeWhere.Name.EQ(typ), + ).One(ctx, txn) + + switch err { + case nil: + componentTypeIDCache[typ] = existing.ID + case sql.ErrNoRows: + sct := &models.ServerComponentType{ + Name: typ, + Slug: slug.Make(typ), + } + if err := sct.Insert(ctx, txn, boil.Infer()); err != nil { + _ = txn.Rollback() + return errors.Wrap(errAddTypes, err.Error()) + } + componentTypeIDCache[typ] = sct.ID + default: + return errors.Wrap(errAddTypes, err.Error()) + } + } + return txn.Commit() +} + +// ComponentTypeIDFromName expects the name of the component (as defined in +// bmc-toolbox) and will return the internal database ID for that name. +func ComponentTypeIDFromName(name string) (string, error) { + id, ok := componentTypeIDCache[name] + if !ok { + return "", errors.Wrap(errBadName, name) + } + return id, nil +} diff --git a/internal/dbtools/component_types_test.go b/internal/dbtools/component_types_test.go new file mode 100644 index 0000000..8985f87 --- /dev/null +++ b/internal/dbtools/component_types_test.go @@ -0,0 +1,26 @@ +//go:build testtools && integration + +package dbtools + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestServerComponentTypes(t *testing.T) { + db := DatabaseTest(t) + ctx := context.TODO() + + err := SetupComponentTypes(ctx, db) + require.NoError(t, err) + + for _, typ := range knownComponentTypes { + _, err := ComponentTypeIDFromName(typ) + require.NoError(t, err, "couldn't find %s", typ) + } + + _, err = ComponentTypeIDFromName("bogus") + require.Error(t, err, "no error on bogus") +} diff --git a/internal/dbtools/fixtures.go b/internal/dbtools/fixtures.go index d599a2b..525c5df 100644 --- a/internal/dbtools/fixtures.go +++ b/internal/dbtools/fixtures.go @@ -5,9 +5,11 @@ package dbtools import ( "context" + "encoding/json" "testing" "time" + "github.com/google/uuid" "github.com/jmoiron/sqlx" "github.com/volatiletech/null/v8" "github.com/volatiletech/sqlboiler/v4/boil" @@ -27,6 +29,7 @@ var ( // Server Component Types FixtureFinType *models.ServerComponentType + NemoID uuid.UUID FixtureNemo *models.Server FixtureNemoMetadata *models.Attribute FixtureNemoOtherdata *models.Attribute @@ -83,6 +86,9 @@ var ( FixtureFirmwareUUIDsR640 []string FixtureFirmwareSetR640 *models.ComponentFirmwareSet FixtureFirmwareSetR640Attribute *models.AttributesFirmwareSet + + // Inventory fixtures + FixtureInventoryServer *models.Server ) func addFixtures(t *testing.T) error { @@ -137,6 +143,14 @@ func addFixtures(t *testing.T) error { return err } + if err := SetupComponentTypes(ctx, testDB); err != nil { + return err + } + + if err := setupInventoryFixture(ctx, testDB); err != nil { + return err + } + // excluding Chuckles here since that server is deleted FixtureServers = models.ServerSlice{FixtureNemo, FixtureDory, FixtureMarlin} FixtureDeletedServers = models.ServerSlice{FixtureChuckles} @@ -255,7 +269,11 @@ func setupNemo(ctx context.Context, db *sqlx.DB, t *testing.T) error { return err } - return FixtureNemo.AddVersionedAttributes(ctx, db, true, FixtureNemoVersionedNew) + if err := FixtureNemo.AddVersionedAttributes(ctx, db, true, FixtureNemoVersionedNew); err != nil { + return err + } + NemoID = uuid.MustParse(FixtureNemo.ID) + return nil } func setupDory(ctx context.Context, db *sqlx.DB) error { @@ -602,3 +620,32 @@ func setupFirmwareSetR640(ctx context.Context, db *sqlx.DB) error { return nil } + +func setupInventoryFixture(ctx context.Context, db *sqlx.DB) error { + FixtureInventoryServer = &models.Server{ + Name: null.StringFrom("inventory"), + FacilityCode: null.StringFrom("tf2"), + } + + if err := FixtureInventoryServer.Insert(ctx, db, boil.Infer()); err != nil { + return err + } + + vendorAttrs := map[string]string{ + "model": "myModel", + "vendor": "Awesome Computer, Inc.", + "serial": "1234xyz", + } + vaData, _ := json.Marshal(vendorAttrs) + + vendorAttrRecord := &models.Attribute{ + ServerID: null.StringFrom(FixtureInventoryServer.ID), + Namespace: "sh.hollow.alloy.server_vendor_attributes", // alloyVendorNamespace + Data: types.JSON(vaData), + } + if err := vendorAttrRecord.Insert(ctx, db, boil.Infer()); err != nil { + return err + } + + return nil +} diff --git a/internal/inventory/attribute_utils.go b/internal/inventory/attribute_utils.go new file mode 100644 index 0000000..489942c --- /dev/null +++ b/internal/inventory/attribute_utils.go @@ -0,0 +1,87 @@ +package inventory + +import ( + "context" + "database/sql" + "encoding/json" + + "github.com/volatiletech/null/v8" + "github.com/volatiletech/sqlboiler/v4/boil" + "github.com/volatiletech/sqlboiler/v4/queries/qm" + "github.com/volatiletech/sqlboiler/v4/types" + + "github.com/metal-toolbox/fleetdb/internal/models" +) + +// the "either server or server-component" facet of attributes makes this function a +// little complicated +func updateAnyAttribute(ctx context.Context, exec boil.ContextExecutor, + isServerAttr bool, id, namespace string, data json.RawMessage) error { + var mods []qm.QueryMod + + idStr := null.StringFrom(id) + attrData := types.JSON(data) + + // create an attribute in the event we need to make an insert + attr := models.Attribute{ + Namespace: namespace, + Data: attrData, + } + + if isServerAttr { + attr.ServerID = idStr + mods = append(mods, models.AttributeWhere.ServerID.EQ(idStr)) + } else { + attr.ServerComponentID = idStr + mods = append(mods, models.AttributeWhere.ServerComponentID.EQ(idStr)) + } + mods = append(mods, models.AttributeWhere.Namespace.EQ(namespace)) + + existing, err := models.Attributes(mods...).One(ctx, exec) + switch err { + case nil: + attr.ID = existing.ID + _, updErr := attr.Update(ctx, exec, boil.Infer()) + return updErr + case sql.ErrNoRows: + return attr.Insert(ctx, exec, boil.Infer()) + default: + return err + } +} + +// insert a new versioned attribute record with the provided data. if this is not the first +// time we've seen a id/namespace tuple, increment the tally +func updateAnyVersionedAttribute(ctx context.Context, exec boil.ContextExecutor, + isServerAttr bool, id, namespace string, data json.RawMessage) error { + var mods []qm.QueryMod + + idStr := null.StringFrom(id) + attrData := types.JSON(data) + + // we will always insert a new versioned attribute, just incrementing the tally + vattr := models.VersionedAttribute{ + Namespace: namespace, + Data: attrData, + } + + if isServerAttr { + vattr.ServerID = idStr + mods = append(mods, models.VersionedAttributeWhere.ServerID.EQ(idStr)) + } else { + vattr.ServerComponentID = idStr + mods = append(mods, models.VersionedAttributeWhere.ServerComponentID.EQ(idStr)) + } + mods = append(mods, models.VersionedAttributeWhere.Namespace.EQ(namespace), qm.OrderBy("tally DESC")) + + lastVA, err := models.VersionedAttributes(mods...).One(ctx, exec) + switch err { + case nil: + vattr.Tally = lastVA.Tally + 1 + case sql.ErrNoRows: + // first time we've seen this vattr + default: + return err + } + return vattr.Insert(ctx, exec, boil.Infer()) +} diff --git a/internal/inventory/component_attributes.go b/internal/inventory/component_attributes.go new file mode 100644 index 0000000..4992d4b --- /dev/null +++ b/internal/inventory/component_attributes.go @@ -0,0 +1,76 @@ +package inventory + +import ( + "encoding/json" + + "github.com/bmc-toolbox/common" + rivets "github.com/metal-toolbox/rivets/types" +) + +func mustAttributesJSON(ca *rivets.ComponentAttributes) []byte { + if ca == nil { + return nil + } + byt, err := json.Marshal(ca) + if err != nil { + panic("bad component attributes payload") + } + return byt +} + +func componentAttributesFromJSON(byt []byte) (*rivets.ComponentAttributes, error) { + if byt == nil { + return nil, nil + } + ca := &rivets.ComponentAttributes{} + if err := json.Unmarshal(byt, ca); err != nil { + return nil, err + } + return ca, nil +} + +func mustFirmwareJSON(fw *common.Firmware) []byte { + if fw == nil { + return nil + } + byt, err := json.Marshal(fw) + if err != nil { + panic("bad firmware payload") + } + return byt +} + +func firmwareFromJSON(byt []byte) (*common.Firmware, error) { + if byt == nil { + return nil, nil + } + fw := &common.Firmware{} + err := json.Unmarshal(byt, fw) + if err != nil { + return nil, err + } + return fw, nil +} + +func mustStatusJSON(st *common.Status) []byte { + if st == nil { + return nil + } + byt, err := json.Marshal(st) + if err != nil { + panic("bad status payload") + } + return byt +} + +func statusFromJSON(byt []byte) (*common.Status, error) { + if byt == nil { + return nil, nil + } + st := &common.Status{} + err := json.Unmarshal(byt, st) + if err != nil { + return nil, err + } + return st, nil +} diff --git a/internal/inventory/device_components.go b/internal/inventory/device_components.go new file mode 100644 index 0000000..4779dca --- /dev/null +++ b/internal/inventory/device_components.go @@ -0,0 +1,244 @@ +package inventory + +import ( + "context" + "database/sql" + + "github.com/bmc-toolbox/common" + rivets "github.com/metal-toolbox/rivets/types" + "github.com/pkg/errors" + "github.com/volatiletech/null/v8" + "github.com/volatiletech/sqlboiler/v4/boil" + "github.com/volatiletech/sqlboiler/v4/queries/qm" + + "github.com/metal-toolbox/fleetdb/internal/dbtools" + "github.com/metal-toolbox/fleetdb/internal/models" +) + +var ( + errComponentType = errors.New("component type error") + errComponent = errors.New("component error") + errAttribute = errors.New("attribute error") + errVersionedAttr = errors.New("versioned attribute error") + + inbandNSTag = "sh.hollow.alloy.inband" + outofbandNSTag = "sh.hollow.alloy.outofband" +) + +func getNamespace(inband bool) string { + ns := outofbandNSTag + if inband { + ns = inbandNSTag + } + return ns +} + +func getAttributeNamespace(inband bool) string { + return getNamespace(inband) + ".metadata" +} + +func getFirmwareNamespace(inband bool) string { + return getNamespace(inband) + ".firmware" +} + +func getStatusNamespace(inband bool) string { + return getNamespace(inband) + ".status" +} + +func createOrUpdateComponent(ctx context.Context, exec boil.ContextExecutor, sc *models.ServerComponent) error { + existing, err := models.ServerComponents( + models.ServerComponentWhere.Name.EQ(sc.Name), + models.ServerComponentWhere.ServerID.EQ(sc.ServerID), + models.ServerComponentWhere.Serial.EQ(sc.Serial), + models.ServerComponentWhere.ServerComponentTypeID.EQ(sc.ServerComponentTypeID), + ).One(ctx, exec) + + switch err { + case nil: + sc.ID = existing.ID + _, updErr := sc.Update(ctx, exec, boil.Infer()) + return updErr + case sql.ErrNoRows: + return sc.Insert(ctx, exec, boil.Infer()) + default: + return err + } +} + +// This encapsulates much of the repetitive work of getting a component to the database layer. +func composeRecords(ctx context.Context, exec boil.ContextExecutor, cmp *rivets.Component, + inband bool, deviceID string) error { + name := cmp.Name + typeID, err := dbtools.ComponentTypeIDFromName(name) + if err != nil { + return errors.Wrap(errComponentType, name+" not found") + } + + sc := &models.ServerComponent{ + Name: null.StringFrom(name), + Vendor: null.NewString(cmp.Vendor, cmp.Vendor != ""), + Model: null.NewString(cmp.Model, cmp.Model != ""), + Serial: null.NewString(cmp.Serial, cmp.Serial != ""), + ServerID: deviceID, + ServerComponentTypeID: typeID, + } + + if err := createOrUpdateComponent(ctx, exec, sc); err != nil { + return errors.Wrap(errComponent, name+": "+err.Error()) + } + + if cmp.Attributes != nil { + attrData := mustAttributesJSON(cmp.Attributes) + + // update the component attribute + if err := updateAnyAttribute(ctx, exec, false, sc.ID, getAttributeNamespace(inband), attrData); err != nil { + return errors.Wrap(errAttribute, name+": "+err.Error()) + } + } + + // every component with firmware gets a firmware versioned attribute + if cmp.Firmware != nil { + payload := mustFirmwareJSON(cmp.Firmware) + + if err := updateAnyVersionedAttribute(ctx, exec, false, sc.ID, getFirmwareNamespace(inband), payload); err != nil { + return errors.Wrap(errVersionedAttr, name+"-firmware: "+err.Error()) + } + } + + // every component with status gets a status versioned attribute + if cmp.Status != nil { + payload := mustStatusJSON(cmp.Status) + + if err := updateAnyVersionedAttribute(ctx, exec, false, sc.ID, getStatusNamespace(inband), payload); err != nil { + return errors.Wrap(errVersionedAttr, name+"-status: "+err.Error()) + } + } + + return nil +} + +func retrieveComponentAttributes(ctx context.Context, exec boil.ContextExecutor, + componentID, namespace string) (*rivets.ComponentAttributes, error) { + ar, err := models.Attributes( + models.AttributeWhere.ServerComponentID.EQ(null.StringFrom(componentID)), + models.AttributeWhere.Namespace.EQ(namespace), + ).One(ctx, exec) + + switch err { + case sql.ErrNoRows: + return nil, nil + case nil: + default: + return nil, err + } + + return componentAttributesFromJSON(ar.Data) +} + +// we rely on the caller to know what v-attributes to retrieve and how to deserialize that data +func retrieveVersionedAttribute(ctx context.Context, exec boil.ContextExecutor, + parentID, namespace string, isServer bool) ([]byte, error) { + var mods []qm.QueryMod + if isServer { + mods = append(mods, models.VersionedAttributeWhere.ServerID.EQ(null.StringFrom(parentID))) + } else { + mods = append(mods, models.VersionedAttributeWhere.ServerComponentID.EQ(null.StringFrom(parentID))) + } + mods = append(mods, + models.VersionedAttributeWhere.Namespace.EQ(namespace), + qm.OrderBy("tally DESC"), // get the most recent record + ) + + fwr, err := models.VersionedAttributes(mods...).One(ctx, exec) + if err != nil { + return nil, err + } + return fwr.Data, nil +} + +func retrieveComponentFirmwareVA(ctx context.Context, exec boil.ContextExecutor, + parentID, namespace string) (*common.Firmware, error) { + data, err := retrieveVersionedAttribute(ctx, exec, parentID, namespace, false) + switch err { + case sql.ErrNoRows: + return nil, nil + case nil: + default: + return nil, err + } + + fw, err := firmwareFromJSON(data) + if err != nil { + return nil, err + } + return fw, nil +} + +func retrieveComponentStatusVA(ctx context.Context, exec boil.ContextExecutor, parentID, + namespace string) (*common.Status, error) { + data, err := retrieveVersionedAttribute(ctx, exec, parentID, namespace, false) + switch err { + case sql.ErrNoRows: + return nil, nil + case nil: + default: + return nil, err + } + + st, err := statusFromJSON(data) + if err != nil { + return nil, err + } + return st, nil +} + +// As generically as possible, retrieve this component from the database. Status and Firmware +// are composed into the *Common. We return the attributes so that the caller can reconsitute +// the specific device type. This is basically the reverse of composeRecords. +func componentsFromDatabase(ctx context.Context, exec boil.ContextExecutor, + inband bool, deviceID string) ([]*rivets.Component, error) { + records, err := models.ServerComponents( + models.ServerComponentWhere.ServerID.EQ(deviceID), + qm.OrderBy(models.ServerComponentColumns.CreatedAt+" DESC"), + ).All(ctx, exec) + + if err != nil { + return nil, err + } + + var comps []*rivets.Component + + for _, rec := range records { + // attributes/firmware/status might not be stored because it was missing in the original data. + attr, err := retrieveComponentAttributes(ctx, exec, rec.ID, getAttributeNamespace(inband)) + if err != nil { + return nil, errors.Wrap(err, "retrieving "+rec.Name.String+"-"+rec.ID+" attributes"+":"+err.Error()) + } + + fw, err := retrieveComponentFirmwareVA(ctx, exec, rec.ID, getFirmwareNamespace(inband)) + switch err { + case nil, sql.ErrNoRows: + default: + return nil, errors.Wrap(err, "retrieving "+rec.Name.String+"-"+rec.ID+" firmware"+":"+err.Error()) + } + + st, err := retrieveComponentStatusVA(ctx, exec, rec.ID, getStatusNamespace(inband)) + switch err { + case nil, sql.ErrNoRows: + default: + return nil, errors.Wrap(err, "retrieving "+rec.Name.String+"-"+rec.ID+" status"+":"+err.Error()) + } + comp := &rivets.Component{ + Name: rec.Name.String, + Vendor: rec.Vendor.String, + Model: rec.Model.String, + Serial: rec.Serial.String, + Firmware: fw, + Status: st, + Attributes: attr, + } + comps = append(comps, comp) + } + + return comps, nil +} diff --git a/internal/inventory/device_components_test.go b/internal/inventory/device_components_test.go new file mode 100644 index 0000000..d97a7b9 --- /dev/null +++ b/internal/inventory/device_components_test.go @@ -0,0 +1,280 @@ +//go:build integration + +package inventory + +import ( + "context" + "testing" + + "github.com/bmc-toolbox/common" + "github.com/google/uuid" + "github.com/jmoiron/sqlx" + "github.com/stretchr/testify/require" + "github.com/volatiletech/null/v8" + "github.com/volatiletech/sqlboiler/v4/boil" + "github.com/volatiletech/sqlboiler/v4/queries/qm" + + "github.com/metal-toolbox/fleetdb/internal/dbtools" + "github.com/metal-toolbox/fleetdb/internal/models" + rivets "github.com/metal-toolbox/rivets/types" +) + +func mustCreateServerRecord(t *testing.T, db *sqlx.DB, name string) uuid.UUID { + t.Helper() + // we need to create a server in order to fulfill the foreign-key requirement + // for server-components + srv := models.Server{ + Name: null.StringFrom(name), + FacilityCode: null.StringFrom("tf2"), + } + + err := srv.Insert(context.TODO(), db, boil.Infer()) + require.NoError(t, err, "server setup") + srvUUID := uuid.MustParse(srv.ID) + return srvUUID +} + +func TestComposeComponentRecords(t *testing.T) { + db := dbtools.DatabaseTest(t) + t.Run("nil attr/vattr", func(t *testing.T) { + srvUUID := mustCreateServerRecord(t, db, "nil-attr-case") + + var inband bool + slug := common.SlugBIOS + + orig := &rivets.Component{ + Name: slug, + Vendor: "the-vendor", + } + + attributeNS := getAttributeNamespace(inband) + fwns := getFirmwareNamespace(inband) + sns := getStatusNamespace(inband) + + tx := db.MustBegin() + err := composeRecords(context.TODO(), tx, orig, inband, srvUUID.String()) + require.NoError(t, err) + _ = tx.Commit() + + scc, err := models.ServerComponents( + models.ServerComponentWhere.Name.EQ(null.StringFrom(slug)), + models.ServerComponentWhere.ServerID.EQ(srvUUID.String()), + ).Count(context.TODO(), db) + require.NoError(t, err) + require.Equal(t, int64(1), scc) + + scr, err := models.ServerComponents( + models.ServerComponentWhere.Name.EQ(null.StringFrom(slug)), + models.ServerComponentWhere.ServerID.EQ(srvUUID.String()), + ).One(context.TODO(), db) + require.NoError(t, err) + require.True(t, scr.Model.IsZero()) + + rc, err := models.Attributes( + models.AttributeWhere.ServerComponentID.EQ(null.StringFrom(scr.ID)), + models.AttributeWhere.Namespace.EQ(attributeNS), + ).Count(context.TODO(), db) + require.NoError(t, err) + require.Equal(t, int64(0), rc) + + rc, err = models.VersionedAttributes( + models.VersionedAttributeWhere.ServerComponentID.EQ(null.StringFrom(scr.ID)), + models.VersionedAttributeWhere.Namespace.EQ(fwns), + ).Count(context.TODO(), db) + require.NoError(t, err) + require.Equal(t, int64(0), rc) + + rc, err = models.VersionedAttributes( + models.VersionedAttributeWhere.ServerComponentID.EQ(null.StringFrom(scr.ID)), + models.VersionedAttributeWhere.Namespace.EQ(sns), + ).Count(context.TODO(), db) + require.NoError(t, err) + require.Equal(t, int64(0), rc) + }) + t.Run("common case", func(t *testing.T) { + srvUUID := mustCreateServerRecord(t, db, "common-case") + + var inband bool + attributeNS := getAttributeNamespace(inband) + fwns := getFirmwareNamespace(inband) + sns := getStatusNamespace(inband) + + slug := common.SlugBIOS + + orig := &rivets.Component{ + // this can be any real slug, but *must* be a real slug, otherwise + // we will panic on the slug -> type-id lookup. + Name: slug, + Vendor: "the-vendor", + Serial: "some-serial-number", + Firmware: &common.Firmware{ + Installed: "old-version", + }, + Status: &common.Status{ + State: "OK", + Health: "decent", + }, + Attributes: &rivets.ComponentAttributes{ + PhysicalID: "my-id", + }, + } + + tx := db.MustBegin() + err := composeRecords(context.TODO(), tx, orig, inband, srvUUID.String()) + require.NoError(t, err) + _ = tx.Commit() + + // interrogate the DB for our records + scc, err := models.ServerComponents( + models.ServerComponentWhere.Name.EQ(null.StringFrom(slug)), + models.ServerComponentWhere.ServerID.EQ(srvUUID.String()), + ).Count(context.TODO(), db) + require.NoError(t, err) + require.Equal(t, int64(1), scc) + + scr, err := models.ServerComponents( + models.ServerComponentWhere.Name.EQ(null.StringFrom(slug)), + models.ServerComponentWhere.ServerID.EQ(srvUUID.String()), + ).One(context.TODO(), db) + require.NoError(t, err) + require.True(t, scr.Model.IsZero()) + + // validate the record counts of the attributes/versioned-attributes + ac, err := models.Attributes( + models.AttributeWhere.ServerComponentID.EQ(null.StringFrom(scr.ID)), + models.AttributeWhere.Namespace.EQ(attributeNS), + ).Count(context.TODO(), db) + require.NoError(t, err) + require.Equal(t, int64(1), ac, "attribute record") + + ar, err := models.Attributes( + models.AttributeWhere.ServerComponentID.EQ(null.StringFrom(scr.ID)), + models.AttributeWhere.Namespace.EQ(attributeNS), + ).One(context.TODO(), db) + require.NoError(t, err) + + vac, err := models.VersionedAttributes( + models.VersionedAttributeWhere.ServerComponentID.EQ(null.StringFrom(scr.ID)), + models.VersionedAttributeWhere.Namespace.EQ(fwns), + ).Count(context.TODO(), db) + require.NoError(t, err) + require.Equal(t, int64(1), vac, "firmware record") + + fwr, err := models.VersionedAttributes( + models.VersionedAttributeWhere.ServerComponentID.EQ(null.StringFrom(scr.ID)), + models.VersionedAttributeWhere.Namespace.EQ(fwns), + ).One(context.TODO(), db) + require.NoError(t, err) + fwData, err := firmwareFromJSON(fwr.Data) + require.NoError(t, err) + require.Equal(t, orig.Firmware, fwData) + + vac, err = models.VersionedAttributes( + models.VersionedAttributeWhere.ServerComponentID.EQ(null.StringFrom(scr.ID)), + models.VersionedAttributeWhere.Namespace.EQ(sns), + ).Count(context.TODO(), db) + require.NoError(t, err) + require.Equal(t, int64(1), vac, "status record") + + sr, err := models.VersionedAttributes( + models.VersionedAttributeWhere.ServerComponentID.EQ(null.StringFrom(scr.ID)), + models.VersionedAttributeWhere.Namespace.EQ(sns), + ).One(context.TODO(), db) + require.NoError(t, err) + srData, err := statusFromJSON(sr.Data) + require.NoError(t, err) + require.Equal(t, orig.Status, srData) + + // now do the update + update := &rivets.Component{ + Name: common.SlugBIOS, + Vendor: "the-vendor", + Serial: "some-serial-number", + Firmware: &common.Firmware{ + Installed: "new-version", + }, + Status: &common.Status{ + State: "happy", + Health: "content", + }, + Attributes: &rivets.ComponentAttributes{ + PhysicalID: "my-id", + }, + } + + tx = db.MustBegin() + err = composeRecords(context.TODO(), tx, update, inband, srvUUID.String()) + require.NoError(t, err) + _ = tx.Commit() + + scc, err = models.ServerComponents( + models.ServerComponentWhere.Name.EQ(null.StringFrom(slug)), + models.ServerComponentWhere.ServerID.EQ(srvUUID.String()), + ).Count(context.TODO(), db) + require.NoError(t, err) + require.Equal(t, int64(1), scc) + + scr, err = models.ServerComponents( + models.ServerComponentWhere.Name.EQ(null.StringFrom(slug)), + models.ServerComponentWhere.ServerID.EQ(srvUUID.String()), + ).One(context.TODO(), db) + require.NoError(t, err) + + // validate the record counts of the attributes/versioned-attributes + ac, err = models.Attributes( + models.AttributeWhere.ServerComponentID.EQ(null.StringFrom(scr.ID)), + models.AttributeWhere.Namespace.EQ(attributeNS), + ).Count(context.TODO(), db) + require.NoError(t, err) + require.Equal(t, int64(1), ac, "attribute record") + + ar, err = models.Attributes( + models.AttributeWhere.ServerComponentID.EQ(null.StringFrom(scr.ID)), + models.AttributeWhere.Namespace.EQ(attributeNS), + ).One(context.TODO(), db) + require.NoError(t, err) + require.NotNil(t, ar.Data) + attr, err := componentAttributesFromJSON(ar.Data) + require.NoError(t, err) + require.Equal(t, update.Attributes, attr) + + vac, err = models.VersionedAttributes( + models.VersionedAttributeWhere.ServerComponentID.EQ(null.StringFrom(scr.ID)), + models.VersionedAttributeWhere.Namespace.EQ(fwns), + ).Count(context.TODO(), db) + require.NoError(t, err) + require.Equal(t, int64(2), vac, "firmware record") + + fwr, err = models.VersionedAttributes( + models.VersionedAttributeWhere.ServerComponentID.EQ(null.StringFrom(scr.ID)), + models.VersionedAttributeWhere.Namespace.EQ(fwns), + qm.OrderBy("tally DESC"), + ).One(context.TODO(), db) + require.NoError(t, err) + fwData, err = firmwareFromJSON(fwr.Data) + require.NoError(t, err) + require.Equal(t, update.Firmware, fwData) + + vac, err = models.VersionedAttributes( + models.VersionedAttributeWhere.ServerComponentID.EQ(null.StringFrom(scr.ID)), + models.VersionedAttributeWhere.Namespace.EQ(sns), + ).Count(context.TODO(), db) + require.NoError(t, err) + require.Equal(t, int64(2), vac, "status record") + + sr, err = models.VersionedAttributes( + models.VersionedAttributeWhere.ServerComponentID.EQ(null.StringFrom(scr.ID)), + models.VersionedAttributeWhere.Namespace.EQ(sns), + qm.OrderBy("tally DESC"), + ).One(context.TODO(), db) + require.NoError(t, err) + srData, err = statusFromJSON(sr.Data) + require.NoError(t, err) + require.Equal(t, update.Status, srData) + + // validate that we can get all the component data we expect + comps, err := componentsFromDatabase(context.TODO(), db, inband, srvUUID.String()) + require.NoError(t, err) + require.Len(t, comps, 1) + }) +} diff --git a/internal/inventory/device_view.go b/internal/inventory/device_view.go new file mode 100644 index 0000000..f226304 --- /dev/null +++ b/internal/inventory/device_view.go @@ -0,0 +1,204 @@ +package inventory + +import ( + "context" + "database/sql" + "encoding/json" + + "github.com/google/uuid" + rivets "github.com/metal-toolbox/rivets/types" + "github.com/pkg/errors" + "github.com/volatiletech/null/v8" + "github.com/volatiletech/sqlboiler/v4/boil" + "github.com/volatiletech/sqlboiler/v4/queries/qm" + + "github.com/metal-toolbox/fleetdb/internal/dbtools" + "github.com/metal-toolbox/fleetdb/internal/models" +) + +/* + XXX From the "this is why we can't have nice things" dept.: + SQLBoiler does in-fact generate Upsert methods for the objects in its ORM. However, because many of our tables + have partial constraints on them, Postgres (and by extension CRDB) requires a WHERE clause when you specify + ON CONFLICT (columns). That is the query looks like: INSERT INTO table (col1, col2) VALUES (foo, bar) ON CONFLICT + (col1, col2) WHERE col1 DO UPDATE ... + + SQLBoiler doesn't have a provision for that WHERE clause in the ON CONFLICT and they probably won't add it: cf. + https://github.com/volatiletech/sqlboiler/issues/856 + + That means we do the upserts the hard way until we change change the tables that have only partial constraints. +*/ + +var ( + // historically these values were determined/set by alloy, even though they are + // internal to the data storage layer, hence the names + alloyVendorNamespace = "sh.hollow.alloy.server_vendor_attributes" + // XXX: enable this when Server supports UEFI variables + // alloyUefiVarsNamespace = "sh.hollow.alloy.server_uefi_variables" // this is a versioned attribute, we expect it to change + serverStatusNamespace = "sh.hollow.alloy.server_status" // versioned + + // metadata keys + modelKey = "model" + vendorKey = "vendor" + serialKey = "serial" + // XXX: again, enable after UEFI Variables are a thing. uefiVarsKey = "uefi-variables" + + errBadServer = errors.New("data is missing required field") + errBadComponent = errors.New("component data") + + ErrNoInventory = errors.New("no inventory stored") +) + +// DeviceView encapsulates everything we need to get and set inventory data for servers +// A reminder for maintenance: this type needs to be able to contain all the +// relevant fields from Component-Inventory or Alloy. +type DeviceView struct { + Inv *rivets.Server + Inband bool // the method of inventory collection + DeviceID uuid.UUID +} + +// ServerSanityCheck handles verifying that all the details in the incoming data +// structure have been set so we maintain database invariants. +func ServerSanityCheck(srv *rivets.Server) error { + srvReq := map[string]string{ + "model": srv.Model, + "vendor": srv.Vendor, + "serial": srv.Serial, + } + for k, v := range srvReq { + if v == "" { + return errors.Wrap(errBadServer, k) + } + } + + for _, cmp := range srv.Components { + if _, err := dbtools.ComponentTypeIDFromName(cmp.Name); err != nil { + return errors.Wrap(errBadComponent, err.Error()) + } + if cmp.Serial == "" { + return errors.Wrap(errBadComponent, cmp.Name+" missing serial") + } + } + return nil +} + +func (dv *DeviceView) vendorAttributes() json.RawMessage { + m := map[string]string{ + modelKey: dv.Inv.Model, + serialKey: dv.Inv.Serial, + vendorKey: dv.Inv.Vendor, + } + byt, _ := json.Marshal(m) + + return byt +} + +/* XXX: return this when rivet's Server datatype has a facility to store UEFI vars. +func (dv *DeviceView) uefiVariables() (json.RawMessage, error) { + var varString string + + varString, ok := dv.Inv.Metadata[uefiVarsKey] + if !ok { + return nil, nil + } + + // sanity check the data coming in from the caller + m := map[string]any{} + if err := json.Unmarshal([]byte(varString), &m); err != nil { + return nil, errors.Wrap(err, "unmarshaling uefi-variables") + } + + return []byte(varString), nil +}*/ + +func (dv *DeviceView) updateVendorAttributes(ctx context.Context, exec boil.ContextExecutor) error { + return updateAnyAttribute(ctx, exec, true, dv.DeviceID.String(), alloyVendorNamespace, dv.vendorAttributes()) +} + +// write all the versioned-attributes from this server +func (dv *DeviceView) updateServerVAs(ctx context.Context, exec boil.ContextExecutor) error { + statusData, _ := json.Marshal(dv.Inv.Status) + // XXX: more VAs here + return updateAnyVersionedAttribute(ctx, exec, true, + dv.DeviceID.String(), serverStatusNamespace, statusData) +} + +func (dv *DeviceView) UpsertInventory(ctx context.Context, exec boil.ContextExecutor) error { + // yes, this is a dopey, repetitive style that should be easy for folks to extend or modify + if err := dv.updateVendorAttributes(ctx, exec); err != nil { + return errors.Wrap(err, "server vendor attributes update") + } + + if err := dv.updateServerVAs(ctx, exec); err != nil { + return errors.Wrap(err, "server versioned attribute update") + } + for _, cmp := range dv.Inv.Components { + if err := composeRecords(ctx, exec, cmp, dv.Inband, dv.DeviceID.String()); err != nil { + return err // we already wrapped some contextual data around the error + } + } + return nil +} + +func (dv *DeviceView) FromDatastore(ctx context.Context, exec boil.ContextExecutor) error { + dv.Inv = &rivets.Server{ + ID: dv.DeviceID.String(), // XXX: remove later? + Name: dv.DeviceID.String(), + } + + attrs, err := models.Attributes( + models.AttributeWhere.ServerID.EQ(null.StringFrom(dv.DeviceID.String())), + ).All(ctx, exec) + switch err { + case nil: + default: + return errors.Wrap(err, "fetching attributes") + } + + if len(attrs) == 0 { + return ErrNoInventory + } + + for _, a := range attrs { + switch a.Namespace { + case alloyVendorNamespace: + m := map[string]string{} + if err := a.Data.Unmarshal(&m); err != nil { + return errors.Wrap(err, "unmarshaling vendor attributes") + } + dv.Inv.Vendor = m[vendorKey] + dv.Inv.Model = m[modelKey] + dv.Inv.Serial = m[serialKey] + default: + } + } + + statusVAttr, err := models.VersionedAttributes( + models.VersionedAttributeWhere.ServerID.EQ(null.StringFrom(dv.DeviceID.String())), + models.VersionedAttributeWhere.Namespace.EQ(serverStatusNamespace), + qm.OrderBy("tally DESC"), + ).One(ctx, exec) + + switch err { + case nil: + var status string + if err = json.Unmarshal(statusVAttr.Data, &status); err != nil { + return errors.Wrap(err, "unmarshaling status attribute") + } + dv.Inv.Status = status + case sql.ErrNoRows: + // just skip it, status is optional + default: + return errors.Wrap(err, "fetching versioned attibutes") + } + + comps, err := componentsFromDatabase(ctx, exec, dv.Inband, dv.DeviceID.String()) + if err != nil { + return errors.Wrap(err, "fetching components") + } + + dv.Inv.Components = comps + + return nil +} diff --git a/internal/inventory/device_view_test.go b/internal/inventory/device_view_test.go new file mode 100644 index 0000000..935a1b1 --- /dev/null +++ b/internal/inventory/device_view_test.go @@ -0,0 +1,105 @@ +//go:build integration + +package inventory + +import ( + "context" + "testing" + + "github.com/bmc-toolbox/common" + "github.com/google/uuid" + "github.com/metal-toolbox/fleetdb/internal/dbtools" + "github.com/metal-toolbox/fleetdb/internal/models" + rivets "github.com/metal-toolbox/rivets/types" + "github.com/volatiletech/null/v8" + "github.com/volatiletech/sqlboiler/v4/boil" + + "github.com/stretchr/testify/require" +) + +func Test_ServerSanityCheck(t *testing.T) { + srv := &rivets.Server{} + + require.Error(t, ServerSanityCheck(srv), "zero value") + srv.Model = "some model" + require.Error(t, ServerSanityCheck(srv), "model only") + srv.Vendor = "some vendor" + require.Error(t, ServerSanityCheck(srv), "model+vendor") + srv.Serial = "some-serial" + // theoretically a server could have no components, from the FleetDB perspective + require.NoError(t, ServerSanityCheck(srv)) + srv.Components = []*rivets.Component{ + &rivets.Component{}, + } + require.Error(t, ServerSanityCheck(srv), "zero value component") + srv.Components = []*rivets.Component{ + &rivets.Component{Name: common.SlugPhysicalMem}, + } + require.Error(t, ServerSanityCheck(srv), "component name only") + srv.Components = []*rivets.Component{ + &rivets.Component{ + Name: common.SlugPhysicalMem, + Serial: "some-serial-number", + }, + } + require.NoError(t, ServerSanityCheck(srv)) +} + +func Test_DeviceViewUpdate(t *testing.T) { + t.Run("insert and update device attributes", func(t *testing.T) { + db := dbtools.DatabaseTest(t) + srvID := uuid.New() + dv := DeviceView{ + Inv: &rivets.Server{ + Vendor: "CoolVendor", + Model: "BestModel 420", + Serial: "0xdeadbeef", + Status: "some status string", + Components: []*rivets.Component{ + &rivets.Component{ + Name: common.SlugBIOS, + Serial: "some-serial", + Firmware: &common.Firmware{ + Installed: "version", + }, + Status: &common.Status{ + State: "great", + Health: "very yes", + }, + }, + }, + }, + DeviceID: srvID, + } + // make a server for out attributes + server := models.Server{ + ID: srvID.String(), + Name: null.StringFrom("dvtest-server"), + FacilityCode: null.StringFrom("test1"), + } + + srvErr := server.Insert(context.TODO(), db, boil.Infer()) + require.NoError(t, srvErr, "server setup failed") + + err := dv.UpsertInventory(context.TODO(), db) + require.NoError(t, err) + + // do it again to test the update + dv.Inv.Status = "different status" + err = dv.UpsertInventory(context.TODO(), db) + require.NoError(t, err) + + // validate the contents + read := DeviceView{ + DeviceID: srvID, + } + err = read.FromDatastore(context.TODO(), db) + require.NoError(t, err) + require.Equal(t, "different status", read.Inv.Status) + + require.Len(t, read.Inv.Components, 1) + bios := read.Inv.Components[0] + require.NotNil(t, bios.Firmware) + require.NotNil(t, bios.Status) + }) +} diff --git a/pkg/api/v1/router.go b/pkg/api/v1/router.go index 4a9439b..ce03a5e 100644 --- a/pkg/api/v1/router.go +++ b/pkg/api/v1/router.go @@ -140,6 +140,14 @@ func (r *Router) Routes(rg *gin.RouterGroup) { srvBomByBmcMacAddress.GET("/:bmc_mac_address", amw.AuthRequired(readScopes("bmc-mac-address")), r.getBomFromBmcMacAddress) } } + + // inventory endpoints + srvInventory := rg.Group("/inventory") + { + // uuid is the server id + srvInventory.GET("/:uuid", amw.AuthRequired(readScopes("server")), r.getInventory) + srvInventory.PUT("/:uuid", amw.AuthRequired(updateScopes("server")), r.setInventory) + } } func createScopes(items ...string) []string { diff --git a/pkg/api/v1/router_inventory.go b/pkg/api/v1/router_inventory.go new file mode 100644 index 0000000..49d3583 --- /dev/null +++ b/pkg/api/v1/router_inventory.go @@ -0,0 +1,112 @@ +//nolint:unused +package fleetdbapi + +import ( + "fmt" + + "github.com/gin-gonic/gin" + rivets "github.com/metal-toolbox/rivets/types" + "go.uber.org/zap" + + "github.com/metal-toolbox/fleetdb/internal/inventory" +) + +func (r *Router) getInventory(c *gin.Context) { + srvID, err := r.parseUUID(c) + if err != nil { + badRequestResponse(c, "invalid server id", err) + return + } + + var doInband bool + switch c.Query("mode") { + case "inband": + doInband = true + case "outofband": + default: + badRequestResponse(c, "invalid inventory mode", nil) + return + } + + dv := inventory.DeviceView{ + DeviceID: srvID, + Inband: doInband, + } + + err = dv.FromDatastore(c.Request.Context(), r.DB) + switch err { + case nil: + case inventory.ErrNoInventory: + msg := fmt.Sprintf("no inventory for %s", srvID) + notFoundResponse(c, msg) + return + default: + dbErrorResponse(c, err) + return + } + itemResponse(c, dv.Inv) +} + +func (r *Router) setInventory(c *gin.Context) { + srvID, err := r.parseUUID(c) + if err != nil { + badRequestResponse(c, "invalid server id", err) + return + } + + var doInband bool + param := c.Query("mode") + + switch param { + case "inband": + doInband = true + case "outofband": + case "": + badRequestResponse(c, "missing inventory specifier", nil) + return + default: + badRequestResponse(c, fmt.Sprintf("invalid inventory mode: %s", param), nil) + return + } + + srv := &rivets.Server{} + if err := c.ShouldBindJSON(srv); err != nil { + badRequestResponse(c, "invalid inventory payload", err) + return + } + + if err := inventory.ServerSanityCheck(srv); err != nil { + badRequestResponse(c, "invalid inventory payload", err) + return + } + + view := &inventory.DeviceView{ + DeviceID: srvID, + Inband: doInband, + Inv: srv, + } + + txn := r.DB.MustBegin() + + if err := view.UpsertInventory(c.Request.Context(), txn); err != nil { + if err := txn.Rollback(); err != nil { + r.Logger.With( + zap.Error(err), + zap.String("device_id", srvID.String()), + zap.Bool("inband", doInband), + ).Warn("rollback error") + // increment error metrics + } + dbErrorResponse(c, err) + } + if err := txn.Commit(); err != nil { + r.Logger.With( + zap.Error(err), + zap.String("device_id", srvID.String()), + zap.Bool("inband", doInband), + ).Warn("commit error") + // increment error metrics + dbErrorResponse(c, err) + } + updatedResponse(c, "") +} diff --git a/pkg/api/v1/router_inventory_test.go b/pkg/api/v1/router_inventory_test.go new file mode 100644 index 0000000..043cc1a --- /dev/null +++ b/pkg/api/v1/router_inventory_test.go @@ -0,0 +1,64 @@ +package fleetdbapi_test + +import ( + "context" + "testing" + + "github.com/bmc-toolbox/common" + "github.com/google/uuid" + rivets "github.com/metal-toolbox/rivets/types" + "github.com/stretchr/testify/require" + + "github.com/metal-toolbox/fleetdb/internal/dbtools" +) + +func TestIntegrationGetInventory(t *testing.T) { + s := serverTest(t) + realClientTests(t, func(ctx context.Context, authToken string, respCode int, expectError bool) error { + s.Client.SetToken(authToken) + + srvID := uuid.MustParse(dbtools.FixtureInventoryServer.ID) + srv, _, err := s.Client.GetServerInventory(ctx, srvID, true) + if !expectError { + // we should get back the fixture data for the inventory server + // we don't care about the name of the server + require.NoError(t, err) + require.NotNil(t, srv) + require.Equal(t, "myModel", srv.Model) + require.Equal(t, "Awesome Computer, Inc.", srv.Vendor) + require.Equal(t, "1234xyz", srv.Serial) + } + return err + }) +} + +func TestIntegrationSetInventory(t *testing.T) { + s := serverTest(t) + realClientTests(t, func(ctx context.Context, authToken string, respCode int, expectError bool) error { + s.Client.SetToken(authToken) + + srv := &rivets.Server{ + Model: "myModel", + Vendor: "AwesomeCo", + Serial: "1234xyz", + Components: []*rivets.Component{ + &rivets.Component{ + Name: common.SlugBIOS, + Serial: "0", + Firmware: &common.Firmware{ + Installed: "best version", + }, + }, + }, + } + srvID := uuid.MustParse(dbtools.FixtureInventoryServer.ID) + r, err := s.Client.SetServerInventory(ctx, srvID, srv, true) + if !expectError { + // we should get back the fixture data for the inventory server + // we don't care about the name of the server + require.NoError(t, err) + require.NotNil(t, r) + } + return err + }) +} diff --git a/pkg/api/v1/router_server_component_type_test.go b/pkg/api/v1/router_server_component_type_test.go index 167d6de..bab1cb0 100644 --- a/pkg/api/v1/router_server_component_type_test.go +++ b/pkg/api/v1/router_server_component_type_test.go @@ -42,9 +42,8 @@ func TestIntegrationListServerComponentTypes(t *testing.T) { r, resp, err := s.Client.ListServerComponentTypes(ctx, nil) if !expectError { require.NoError(t, err) - assert.Len(t, r, 1) - assert.Equal(t, dbtools.FixtureFinType.Slug, r[0].Slug) - assert.Equal(t, dbtools.FixtureFinType.Name, r[0].Name) + assert.GreaterOrEqual(t, len(r), 1) + assert.NotNil(t, r.ByName(dbtools.FixtureFinType.Name)) assert.NotNil(t, resp) assert.NotNil(t, resp.Links.Self) } diff --git a/pkg/api/v1/router_server_components_test.go b/pkg/api/v1/router_server_components_test.go index 842dd30..b5c74b6 100644 --- a/pkg/api/v1/router_server_components_test.go +++ b/pkg/api/v1/router_server_components_test.go @@ -199,12 +199,12 @@ func TestIntegrationServerGetComponents(t *testing.T) { } // expect atleast 1 component type to proceed - assert.Len(t, componentTypeSlice, 1) + assert.GreaterOrEqual(t, len(componentTypeSlice), 1) // fixture to create a server components csFixtureCreate := fleetdbapi.ServerComponentSlice{ { - ServerUUID: servers[0].UUID, + ServerUUID: servers[1].UUID, Name: "My Lucky Fin", Vendor: "barracuda", Model: "a lucky fin", @@ -226,7 +226,7 @@ func TestIntegrationServerGetComponents(t *testing.T) { } // create server component - _, err = s.Client.CreateComponents(context.TODO(), servers[0].UUID, csFixtureCreate) + _, err = s.Client.CreateComponents(context.TODO(), servers[1].UUID, csFixtureCreate) if err != nil { t.Fatal(err) } @@ -247,10 +247,10 @@ func TestIntegrationServerGetComponents(t *testing.T) { }, { "component Versioned Attributes is returned as expected", - servers[0].UUID, + servers[1].UUID, 3, fleetdbapi.ServerComponent{ - ServerUUID: servers[0].UUID, + ServerUUID: servers[1].UUID, Name: "My Lucky Fin", Vendor: "barracuda", Model: "a lucky fin", @@ -504,8 +504,16 @@ func TestIntegrationServerUpdateComponents(t *testing.T) { t.Fatal(err) } + var nemo *fleetdbapi.Server + for _, s := range servers { + if s.Name == dbtools.FixtureNemo.Name.String { + nemo = &s + } + } + require.NotNil(t, nemo, "couldn't find nemo") + // update serial attribute for update to work - sc = fleetdbapi.ServerComponentSlice{servers[0].Components[0]} + sc = fleetdbapi.ServerComponentSlice{nemo.Components[0]} sc[0].Serial = "lala" } diff --git a/pkg/api/v1/router_server_test.go b/pkg/api/v1/router_server_test.go index 94793f1..78dcfed 100644 --- a/pkg/api/v1/router_server_test.go +++ b/pkg/api/v1/router_server_test.go @@ -24,11 +24,11 @@ func TestIntegrationServerList(t *testing.T) { r, resp, err := s.Client.List(ctx, nil) if !expectError { require.NoError(t, err) - assert.Len(t, r, 3) + assert.Len(t, r, 4) - assert.EqualValues(t, 3, resp.PageCount) + assert.EqualValues(t, 4, resp.PageCount) assert.EqualValues(t, 1, resp.TotalPages) - assert.EqualValues(t, 3, resp.TotalRecordCount) + assert.EqualValues(t, 4, resp.TotalRecordCount) // We returned everything, so we shouldnt have a next page info assert.Nil(t, resp.Links.Next) assert.Nil(t, resp.Links.Previous) @@ -144,7 +144,7 @@ func TestIntegrationServerList(t *testing.T) { { "empty search filter", nil, - []string{dbtools.FixtureNemo.ID, dbtools.FixtureDory.ID, dbtools.FixtureMarlin.ID}, + []string{dbtools.FixtureInventoryServer.ID, dbtools.FixtureNemo.ID, dbtools.FixtureDory.ID, dbtools.FixtureMarlin.ID}, false, "", }, @@ -436,14 +436,14 @@ func TestIntegrationServerList(t *testing.T) { { "search for server without IncludeDeleted defined", &fleetdbapi.ServerListParams{}, - []string{dbtools.FixtureNemo.ID, dbtools.FixtureDory.ID, dbtools.FixtureMarlin.ID}, + []string{dbtools.FixtureInventoryServer.ID, dbtools.FixtureNemo.ID, dbtools.FixtureDory.ID, dbtools.FixtureMarlin.ID}, false, "", }, { "search for server with IncludeDeleted defined", &fleetdbapi.ServerListParams{IncludeDeleted: true}, - []string{dbtools.FixtureNemo.ID, dbtools.FixtureDory.ID, dbtools.FixtureMarlin.ID, dbtools.FixtureChuckles.ID}, + []string{dbtools.FixtureInventoryServer.ID, dbtools.FixtureNemo.ID, dbtools.FixtureDory.ID, dbtools.FixtureMarlin.ID, dbtools.FixtureChuckles.ID}, false, "", }, @@ -511,12 +511,10 @@ func TestIntegrationServerListPagination(t *testing.T) { assert.NoError(t, err) assert.Len(t, r, 2) - assert.Equal(t, dbtools.FixtureServers[2].ID, r[0].UUID.String()) - assert.Equal(t, dbtools.FixtureServers[1].ID, r[1].UUID.String()) assert.EqualValues(t, 2, resp.PageCount) assert.EqualValues(t, 2, resp.TotalPages) - assert.EqualValues(t, 3, resp.TotalRecordCount) + assert.EqualValues(t, 4, resp.TotalRecordCount) // Since we have a next page let's make sure all the links are set assert.NotNil(t, resp.Links.Next) assert.Nil(t, resp.Links.Previous) @@ -528,16 +526,15 @@ func TestIntegrationServerListPagination(t *testing.T) { resp, err = s.Client.NextPage(context.TODO(), *resp, &r) assert.NoError(t, err) - assert.Len(t, r, 1) - assert.Equal(t, dbtools.FixtureServers[0].ID, r[0].UUID.String()) + assert.Len(t, r, 2) - assert.EqualValues(t, 1, resp.PageCount) + assert.EqualValues(t, 2, resp.PageCount) // we should have followed the cursor so first/previous/next/last links shouldn't be set // but there is another page so we should have a next cursor link. Total counts are not includes // cursor pages assert.EqualValues(t, 2, resp.TotalPages) - assert.EqualValues(t, 3, resp.TotalRecordCount) + assert.EqualValues(t, 4, resp.TotalRecordCount) assert.NotNil(t, resp.Links.First) assert.NotNil(t, resp.Links.Previous) assert.Nil(t, resp.Links.Next) diff --git a/pkg/api/v1/server_service.go b/pkg/api/v1/server_service.go index e9facb9..790b390 100644 --- a/pkg/api/v1/server_service.go +++ b/pkg/api/v1/server_service.go @@ -7,6 +7,7 @@ import ( "path" "github.com/google/uuid" + rivets "github.com/metal-toolbox/rivets/types" ) const ( @@ -22,6 +23,7 @@ const ( uploadFileEndpoint = "batch-upload" bomByMacAOCAddressEndpoint = "aoc-mac-address" bomByMacBMCAddressEndpoint = "bmc-mac-address" + inventoryEndpoint = "inventory" ) // ClientInterface provides an interface for the expected calls to interact with a fleetdb api @@ -61,6 +63,8 @@ type ClientInterface interface { BillOfMaterialsBatchUpload(context.Context, []Bom) (*ServerResponse, error) GetBomInfoByAOCMacAddr(context.Context, string) (*Bom, *ServerResponse, error) GetBomInfoByBMCMacAddr(context.Context, string) (*Bom, *ServerResponse, error) + GetServerInventory(context.Context, uuid.UUID, bool) (*rivets.Server, *ServerResponse, error) + SetServerInventory(context.Context, uuid.UUID, *rivets.Server, bool) (*ServerResponse, error) } // Create will attempt to create a server in Hollow and return the new server's UUID @@ -427,3 +431,33 @@ func (c *Client) GetBomInfoByBMCMacAddr(ctx context.Context, bmcMacAddr string) return bom, &r, nil } + +// GetServerInventory returns the last reported server state of the kind specified by the inband parameter +func (c *Client) GetServerInventory(ctx context.Context, srvID uuid.UUID, inband bool) (*rivets.Server, *ServerResponse, error) { + mode := "outofband" + if inband { + mode = "inband" + } + + path := fmt.Sprintf("%s/%s?mode=%s", inventoryEndpoint, srvID.String(), mode) + srv := &rivets.Server{} + r := &ServerResponse{Record: srv} + + if err := c.get(ctx, path, r); err != nil { + return nil, nil, err + } + + return srv, r, nil +} + +// SetServerInventory writes the given server structure back to the database +func (c *Client) SetServerInventory(ctx context.Context, srvID uuid.UUID, + srv *rivets.Server, inband bool) (*ServerResponse, error) { + mode := "outofband" + if inband { + mode = "inband" + } + + path := fmt.Sprintf("%s/%s?mode=%s", inventoryEndpoint, srvID.String(), mode) + return c.put(ctx, path, srv) +} diff --git a/pkg/api/v1/server_service_test.go b/pkg/api/v1/server_service_test.go index da8f4f8..44f7b25 100644 --- a/pkg/api/v1/server_service_test.go +++ b/pkg/api/v1/server_service_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" fleetdbapi "github.com/metal-toolbox/fleetdb/pkg/api/v1" + rivets "github.com/metal-toolbox/rivets/types" ) func TestFleetdbCreate(t *testing.T) { @@ -397,3 +398,42 @@ func TestGetBomInfoByBMCMacAddr(t *testing.T) { return err }) } + +func TestGetInventory(t *testing.T) { + mockClientTests(t, func(ctx context.Context, respCode int, expectError bool) error { + srvID := uuid.New() + srv := &rivets.Server{ + Name: srvID.String(), + } + jsonResponse, err := json.Marshal(fleetdbapi.ServerResponse{Record: srv}) + require.NoError(t, err) + + c := mockClient(string(jsonResponse), respCode) + respInv, _, err := c.GetServerInventory(ctx, srvID, true) + if !expectError { + require.Equal(t, srv, respInv) + } + + return err + }) +} + +func TestSetInventory(t *testing.T) { + mockClientTests(t, func(ctx context.Context, respCode int, expectError bool) error { + srvID := uuid.New() + srv := &rivets.Server{ + Name: srvID.String(), + } + exp := &fleetdbapi.ServerResponse{Message: "resource updated"} + jsonResponse, err := json.Marshal(exp) + require.NoError(t, err) + + c := mockClient(string(jsonResponse), respCode) + got, err := c.SetServerInventory(ctx, srvID, srv, true) + if !expectError { + require.Equal(t, exp, got) + } + + return err + }) +}