From 2e38df5ba07a7b8a5c9245462f1872aae4cef82a Mon Sep 17 00:00:00 2001 From: Jake Schuurmans Date: Mon, 23 Sep 2024 15:49:16 -0400 Subject: [PATCH] Clean up --- .github/PULL_REQUEST_TEMPLATE.md | 2 + .github/workflows/codeql-analysis.yml | 77 +++++ .github/workflows/push-pr-lint.yaml | 61 ++++ .github/workflows/release.yml | 47 +++ .golangci.yml | 17 +- Makefile | 46 +-- cmd/bioscfg.go | 27 ++ cmd/root.go | 30 +- cmd/run.go | 92 ------ config.yaml | 20 ++ go.mod | 128 +++++---- go.sum | 363 +++++++++++++----------- internal/config/config.go | 140 +++++++++ internal/configuration/configuration.go | 271 ------------------ internal/controllers/bioscfg/bioscfg.go | 113 ++++++++ internal/controllers/bioscfg/errors.go | 9 + internal/controllers/bioscfg/handler.go | 154 ++++++++++ internal/controllers/bioscfg/publish.go | 113 ++++++++ internal/controllers/bioscfg/task.go | 89 ++++++ internal/controllers/controller.go | 73 +++++ internal/controllers/kind/controller.go | 38 +++ internal/handlers/handlers.go | 88 ------ internal/log/log.go | 84 ------ internal/model/errors.go | 10 - internal/model/model.go | 23 -- internal/store/bmc/bmc.go | 248 ++++++++++++++++ internal/store/bmc/dryRun.go | 184 ++++++++++++ internal/store/bmc/interface.go | 18 ++ internal/store/fleetdb/client.go | 57 ++-- internal/store/fleetdb/config.go | 56 ++++ internal/store/fleetdb/errors.go | 15 + internal/store/fleetdb/fleetdb.go | 22 +- internal/store/fleetdb/fleetdb_test.go | 1 + internal/store/store.go | 19 -- internal/tasks/steps.go | 140 --------- internal/tasks/tasks.go | 226 --------------- internal/tasks/tasks_test.go | 64 ----- internal/version/version.go | 17 ++ main.go | 2 - 39 files changed, 1838 insertions(+), 1346 deletions(-) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/workflows/codeql-analysis.yml create mode 100644 .github/workflows/push-pr-lint.yaml create mode 100644 .github/workflows/release.yml create mode 100644 cmd/bioscfg.go delete mode 100644 cmd/run.go create mode 100644 config.yaml create mode 100644 internal/config/config.go delete mode 100644 internal/configuration/configuration.go create mode 100644 internal/controllers/bioscfg/bioscfg.go create mode 100644 internal/controllers/bioscfg/errors.go create mode 100644 internal/controllers/bioscfg/handler.go create mode 100644 internal/controllers/bioscfg/publish.go create mode 100644 internal/controllers/bioscfg/task.go create mode 100644 internal/controllers/controller.go create mode 100644 internal/controllers/kind/controller.go delete mode 100644 internal/handlers/handlers.go delete mode 100644 internal/log/log.go delete mode 100644 internal/model/errors.go create mode 100644 internal/store/bmc/bmc.go create mode 100644 internal/store/bmc/dryRun.go create mode 100644 internal/store/bmc/interface.go create mode 100644 internal/store/fleetdb/config.go create mode 100644 internal/store/fleetdb/errors.go delete mode 100644 internal/store/store.go delete mode 100644 internal/tasks/steps.go delete mode 100644 internal/tasks/tasks.go delete mode 100644 internal/tasks/tasks_test.go diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..69467dd --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,2 @@ +#### What does this PR do + diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 0000000..1c193de --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,77 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL" + +on: + push: + branches: [ main ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ main ] + schedule: + - cron: '34 3 * * 0' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'go' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v3 + + # ℹī¸ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 diff --git a/.github/workflows/push-pr-lint.yaml b/.github/workflows/push-pr-lint.yaml new file mode 100644 index 0000000..e426c07 --- /dev/null +++ b/.github/workflows/push-pr-lint.yaml @@ -0,0 +1,61 @@ +name: lint, test and build image +on: [pull_request, push] + +jobs: + lint-test: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: golangci-lint + uses: golangci/golangci-lint-action@v6 + with: + args: --config .golangci.yml --timeout 2m + version: v1.61.0 + + - name: Test + run: go test ./... + + build: + runs-on: ubuntu-latest + needs: [lint-test] + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: build binary + run: make build-linux + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build bioscfg Docker image - no push + id: dockerbuild-bioscfg + uses: docker/build-push-action@v5 + with: + context: . + push: false + file: Dockerfile + + - name: Scan image - bioscfg + id: scan-bioscfg-image + uses: anchore/scan-action@v3 + with: + image: ghcr.io/metal-toolbox/bioscfg:latest + acs-report-enable: true + fail-build: false + + - name: Inspect action SARIF report + run: cat ${{ steps.scan.outputs.sarif }} + if: always() diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..3808552 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,47 @@ +name: release + +on: + push: + tags: + - 'v*.*.*' + +jobs: + goreleaser: + runs-on: ubuntu-latest + permissions: + contents: write + id-token: write + packages: write + steps: + - + name: Login to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - + name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - + name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + - + name: install cosign + uses: sigstore/cosign-installer@main + - + uses: anchore/sbom-action/download-syft@v0.17.2 + - + name: Run GoReleaser + uses: goreleaser/goreleaser-action@v6 + with: + version: latest + args: release --clean + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COSIGN_EXPERIMENTAL: 1 + GOVERSION: "1.20" diff --git a/.golangci.yml b/.golangci.yml index 77aa173..e8552c0 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,14 +1,13 @@ # golangci.com configuration # https://github.com/golangci/golangci/wiki/Configuration service: - golangci-lint-version: 1.57.2 + golangci-lint-version: 1.61.0 linters-settings: govet: enable: - fieldalignment auto-fix: true - check-shadowing: true settings: printf: funcs: @@ -47,6 +46,7 @@ linters-settings: - wrapperFunc gofumpt: extra-rules: true +shadow: true linters: enable: @@ -65,7 +65,7 @@ linters: # additional linters - bodyclose - gocritic - - goerr113 + - err113 - goimports - revive - misspell @@ -76,14 +76,11 @@ linters: enable-all: false disable-all: true -run: -# build-tags: - skip-dirs: +issues: + exclude-dirs: - internal/fixtures - skip-files: + exclude-files: - "(.*/)*.*_test.go" - -issues: exclude-rules: - linters: - gosec @@ -119,5 +116,3 @@ issues: # EXC0010 gosec: False positive is triggered by 'src, err := ioutil.ReadFile(filename)' - Potential file inclusion via variable exclude-use-default: false - - diff --git a/Makefile b/Makefile index 96599b1..60ae5d1 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ GIT_SUMMARY := $(shell git describe --tags --dirty --always) VERSION := $(shell git describe --tags 2> /dev/null) BUILD_DATE := $(shell date +%s) GIT_COMMIT_FULL := $(shell git rev-parse HEAD) -GO_VERSION := $(shell expr `go version |cut -d ' ' -f3 |cut -d. -f2` \>= 16) +GO_VERSION := $(shell expr `go version |cut -d ' ' -f3 |cut -d. -f2` \>= 23) DOCKER_IMAGE := "ghcr.io/metal-toolbox/bioscfg" REPO := "https://github.com/metal-toolbox/bioscfg.git" @@ -14,7 +14,7 @@ REPO := "https://github.com/metal-toolbox/bioscfg.git" ## lint lint: gen-mock - golangci-lint run --config .golangci.yml + golangci-lint run --config .golangci.yml --fix ## Go test test: lint @@ -30,38 +30,36 @@ gen-mock: ## build-osx build-osx: ifeq ($(GO_VERSION), 0) - $(error build requies go version 1.22.1 or higher) + $(error build requies go version 1.23 or higher) endif - go build -o bioscfg \ - -ldflags \ + go build -o bioscfg \ + -ldflags \ "-X $(LDFLAG_LOCATION).GitCommit=$(GIT_COMMIT) \ - -X $(LDFLAG_LOCATION).GitBranch=$(GIT_BRANCH) \ - -X $(LDFLAG_LOCATION).GitSummary=$(GIT_SUMMARY) \ - -X $(LDFLAG_LOCATION).AppVersion=$(VERSION) \ - -X $(LDFLAG_LOCATION).BuildDate=$(BUILD_DATE)" - + -X $(LDFLAG_LOCATION).GitBranch=$(GIT_BRANCH) \ + -X $(LDFLAG_LOCATION).GitSummary=$(GIT_SUMMARY) \ + -X $(LDFLAG_LOCATION).AppVersion=$(VERSION) \ + -X $(LDFLAG_LOCATION).BuildDate=$(BUILD_DATE)" ## Build linux bin build-linux: ifeq ($(GO_VERSION), 0) - $(error build requies go version 1.22.1 or higher) + $(error build requies go version 1.23 or higher) endif GOOS=linux GOARCH=amd64 go build -o bioscfg \ - -ldflags \ + -ldflags \ "-X $(LDFLAG_LOCATION).GitCommit=$(GIT_COMMIT) \ - -X $(LDFLAG_LOCATION).GitBranch=$(GIT_BRANCH) \ - -X $(LDFLAG_LOCATION).GitSummary=$(GIT_SUMMARY) \ - -X $(LDFLAG_LOCATION).AppVersion=$(VERSION) \ - -X $(LDFLAG_LOCATION).BuildDate=$(BUILD_DATE)" - + -X $(LDFLAG_LOCATION).GitBranch=$(GIT_BRANCH) \ + -X $(LDFLAG_LOCATION).GitSummary=$(GIT_SUMMARY) \ + -X $(LDFLAG_LOCATION).AppVersion=$(VERSION) \ + -X $(LDFLAG_LOCATION).BuildDate=$(BUILD_DATE)" ## build docker image and tag as ghcr.io/metal-toolbox/bioscfg:latest build-image: build-linux @echo ">>>> NOTE: You may want to execute 'make build-image-nocache' depending on the Docker stages changed" - docker build --rm=true -f Dockerfile -t ${DOCKER_IMAGE}:latest . \ - --label org.label-schema.schema-version=1.0 \ - --label org.label-schema.vcs-ref=$(GIT_COMMIT_FULL) \ - --label org.label-schema.vcs-url=$(REPO) + docker build --rm=true -f Dockerfile -t ${DOCKER_IMAGE}:latest . \ + --label org.label-schema.schema-version=1.0 \ + --label org.label-schema.vcs-ref=$(GIT_COMMIT_FULL) \ + --label org.label-schema.vcs-url=$(REPO) ## tag and push devel docker image to local registry push-image-devel: build-image @@ -73,6 +71,11 @@ push-image-devel: build-image push-image: docker push ${DOCKER_IMAGE}:latest +## Clean all caches +clean-all: + golangci-lint cache clean + go clean -modcache -testcache -cache -fuzzcache + # https://gist.github.com/prwhite/8168133 # COLORS GREEN := $(shell tput -Txterm setaf 2) @@ -80,7 +83,6 @@ YELLOW := $(shell tput -Txterm setaf 3) WHITE := $(shell tput -Txterm setaf 7) RESET := $(shell tput -Txterm sgr0) - TARGET_MAX_CHAR_NUM=20 ## Show help help: diff --git a/cmd/bioscfg.go b/cmd/bioscfg.go new file mode 100644 index 0000000..ab293d1 --- /dev/null +++ b/cmd/bioscfg.go @@ -0,0 +1,27 @@ +package cmd + +import ( + "fmt" + "os" + + "github.com/metal-toolbox/bioscfg/internal/controllers" + "github.com/metal-toolbox/bioscfg/internal/controllers/kind" + "github.com/spf13/cobra" +) + +// bioscfgCmd represents the bioscfg command +var bioscfgCmd = &cobra.Command{ + Use: "bioscfg", + Short: "Run the BiosCfg Controller", + Run: func(cmd *cobra.Command, _ []string) { + err := controllers.Run(cmd.Context(), kind.BiosCfg) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + }, +} + +func init() { + rootCmd.AddCommand(bioscfgCmd) +} diff --git a/cmd/root.go b/cmd/root.go index 0b9f446..c0350e6 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -18,26 +18,16 @@ package cmd import ( "fmt" - "log/slog" "os" - "github.com/metal-toolbox/bioscfg/internal/model" + "github.com/metal-toolbox/bioscfg/internal/controllers" "github.com/spf13/cobra" ) -var ( - args = &model.Args{} -) - // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ - Use: "bioscfg", - Short: "bioscfg remotely manages BIOS settings", - Run: func(cmd *cobra.Command, _ []string) { - if err := runWorker(cmd.Context(), args); err != nil { - os.Exit(1) - } - }, + Use: "controller", + Short: "Fleet Services Controllers", } // Execute adds all child commands to the root command and sets flags appropriately. @@ -51,19 +41,11 @@ func Execute() { func init() { rootCmd.PersistentFlags(). - StringVar(&args.ConfigFile, "config", "", "configuration file (default is $HOME/.bioscfg.yml)") - - rootCmd.PersistentFlags(). - StringVar(&args.LogLevel, "log-level", "info", "set logging level - debug, trace") + StringVar(&controllers.ConfigFile, "config", "", "configuration file (default is $HOME/.bioscfg.yml)") rootCmd.PersistentFlags(). - BoolVarP(&args.EnableProfiling, "enable-pprof", "", false, "Enable profiling endpoint at: http://localhost:9091") + StringVar(&controllers.LogLevel, "log-level", "info", "set logging level - debug, trace") rootCmd.PersistentFlags(). - StringVarP(&args.FacilityCode, "facility-code", "f", "", "The facility code this bioscfg instance is associated with") - - if err := rootCmd.MarkPersistentFlagRequired("facility-code"); err != nil { - slog.Error("failed to mark required flag", "error", err) - os.Exit(1) - } + BoolVarP(&controllers.EnableProfiling, "enable-pprof", "", false, "Enable profiling endpoint at: http://localhost:9091") } diff --git a/cmd/run.go b/cmd/run.go deleted file mode 100644 index 0840b32..0000000 --- a/cmd/run.go +++ /dev/null @@ -1,92 +0,0 @@ -package cmd - -import ( - "context" - "log/slog" - _ "net/http/pprof" // nolint:gosec // profiling endpoint listens on localhost. - "os" - "os/signal" - "syscall" - - "github.com/equinix-labs/otel-init-go/otelinit" - "github.com/metal-toolbox/bioscfg/internal/configuration" - "github.com/metal-toolbox/bioscfg/internal/handlers" - "github.com/metal-toolbox/bioscfg/internal/log" - "github.com/metal-toolbox/bioscfg/internal/metrics" - "github.com/metal-toolbox/bioscfg/internal/model" - "github.com/metal-toolbox/bioscfg/internal/profiling" - "github.com/metal-toolbox/bioscfg/internal/store" - "github.com/metal-toolbox/bioscfg/internal/version" - "github.com/metal-toolbox/rivets/events/controller" -) - -func runWorker(ctx context.Context, args *model.Args) error { - config, err := configuration.Load(args) - if err != nil { - slog.Error("Failed to load configuration", "error", err) - return err - } - - slog.Info("Configuration loaded", config.AsLogFields()...) - - log.SetLevel(config.LogLevel) - - // serve metrics endpoint - metrics.ListenAndServe() - version.ExportBuildInfoMetric() - - if config.EnableProfiling { - profiling.Enable() - } - - ctx, otelShutdown := otelinit.InitOpenTelemetry(ctx, model.AppName) - defer otelShutdown(ctx) - - repository, err := store.NewRepository(ctx, config) - if err != nil { - slog.Error("Failed to create repository", "error", err) - return err - } - - termChan := make(chan os.Signal, 1) - signal.Notify(termChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT) - - ctx, cancel := context.WithCancel(ctx) - - // Cancel the context when we receive a termination signal. - go func() { - s := <-termChan - slog.Info("Received signal for termination, exiting...", "signal", s.String()) - cancel() - }() - - nc := controller.NewNatsController( - model.AppName, - config.FacilityCode, - model.AppSubject, - config.NatsConfig.NatsURL, - config.NatsConfig.CredsFile, - model.AppSubject, - controller.WithConcurrency(config.Concurrency), - controller.WithKVReplicas(config.NatsConfig.KVReplicas), - controller.WithConnectionTimeout(config.NatsConfig.ConnectTimeout), - controller.WithLogger(log.NewLogrusLogger(config.LogLevel)), - ) - - if err = nc.Connect(ctx); err != nil { - slog.Error("Failed to connect to NATS", "error", err) - return err - } - - slog.With(version.Current().AsLogFields()...).Info("bioscfg worker running") - - err = nc.ListenEvents(ctx, func() controller.ConditionHandler { - return handlers.NewHandlerFactory(repository) - }) - if err != nil { - slog.Error("Failed to listen for events", "error", err) - return err - } - - return nil -} diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..2e1d997 --- /dev/null +++ b/config.yaml @@ -0,0 +1,20 @@ +facility: sandbox +log_level: trace +concurrency: 1 +dryrun: false +endpoints: + fleetdb: + authenticate: false + oidc_audience_url: + oidc_client_id: + oidc_issuer_url: + oidc_client_scopes: + url: http://fleetdb:8000 + nats: + connect_timeout: 60s + kv_replication: 1 + creds_file: /etc/nats/nats.creds + url: nats://nats:4222 + otel: + authenticate: false + url: jaeger:4317 \ No newline at end of file diff --git a/go.mod b/go.mod index f56baa4..07d3654 100644 --- a/go.mod +++ b/go.mod @@ -3,102 +3,111 @@ module github.com/metal-toolbox/bioscfg go 1.22.1 require ( - github.com/banzaicloud/logrus-runtime-formatter v0.0.0-20190729070250-5ae5475bae5e github.com/bmc-toolbox/bmclib/v2 v2.2.4 + github.com/bombsimon/logrusr/v2 v2.0.1 github.com/coreos/go-oidc v2.2.1+incompatible github.com/equinix-labs/otel-init-go v0.0.9 github.com/google/uuid v1.6.0 - github.com/hashicorp/go-retryablehttp v0.7.5 + github.com/hashicorp/go-retryablehttp v0.7.7 github.com/jeremywohl/flatten v1.0.1 - github.com/metal-toolbox/fleetdb v0.16.9 - github.com/metal-toolbox/rivets v1.0.4 + github.com/metal-toolbox/ctrl v0.2.9 + github.com/metal-toolbox/fleetdb v1.19.5 + github.com/metal-toolbox/rivets v1.3.8-0.20240923144748-4fa59d630b50 + github.com/mitchellh/copystructure v1.2.0 github.com/mitchellh/mapstructure v1.5.0 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.19.0 + github.com/prometheus/client_golang v1.20.1 github.com/sirupsen/logrus v1.9.3 - github.com/spf13/cobra v1.8.0 - github.com/spf13/viper v1.18.2 + github.com/spf13/cobra v1.8.1 + github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 - go.opentelemetry.io/otel v1.24.0 - go.opentelemetry.io/otel/trace v1.24.0 - golang.org/x/oauth2 v0.17.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 + go.opentelemetry.io/otel v1.28.0 + go.opentelemetry.io/otel/trace v1.28.0 + golang.org/x/net v0.28.0 + golang.org/x/oauth2 v0.22.0 ) -replace google.golang.org/protobuf v1.32.0 => google.golang.org/protobuf v1.33.0 // Fix CVE-2024-24786 - require ( + cloud.google.com/go/kms v1.17.1 // indirect dario.cat/mergo v1.0.0 // indirect github.com/Jeffail/gabs/v2 v2.7.0 // indirect github.com/VictorLowther/simplexml v0.0.0-20180716164440-0bff93621230 // indirect github.com/VictorLowther/soap v0.0.0-20150314151524-8e36fca84b22 // indirect + github.com/banzaicloud/logrus-runtime-formatter v0.0.0-20190729070250-5ae5475bae5e // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bmc-toolbox/common v0.0.0-20231204194243-7bcbccab7116 // indirect - github.com/bytedance/sonic v1.11.2 // indirect - github.com/cenkalti/backoff/v4 v4.2.1 // 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/cockroachdb/cockroach-go/v2 v2.3.6 // indirect + github.com/bmc-toolbox/common v0.0.0-20240723142833-87832458b53b // indirect + github.com/bytedance/sonic v1.12.1 // indirect + github.com/bytedance/sonic/loader v0.2.0 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cloudwego/base64x v0.1.4 // indirect + github.com/cloudwego/iasm v0.2.0 // indirect + github.com/cockroachdb/cockroach-go/v2 v2.3.8 // 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/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/friendsofgo/errors v0.9.2 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect - github.com/gabriel-vasile/mimetype v1.4.3 // indirect + github.com/gabriel-vasile/mimetype v1.4.5 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect - github.com/gin-gonic/gin v1.9.1 // indirect - github.com/go-logr/logr v1.4.1 // indirect + github.com/gin-gonic/gin v1.10.0 // indirect + github.com/go-logr/logr v1.4.2 // 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 - github.com/go-playground/validator/v10 v10.19.0 // indirect - github.com/goccy/go-json v0.10.2 // indirect + github.com/go-playground/validator/v10 v10.22.0 // indirect + github.com/goccy/go-json v0.10.3 // 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.2 // indirect + github.com/googleapis/gax-go/v2 v2.13.0 // indirect + github.com/gorilla/websocket v1.5.3 // indirect github.com/gosimple/slug v1.14.0 // indirect github.com/gosimple/unidecode v1.0.1 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.21.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect + github.com/hetiansu5/urlquery v1.2.7 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jackc/chunkreader/v2 v2.0.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.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/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgtype v1.14.3 // indirect + github.com/jackc/pgx/v4 v4.18.3 // indirect github.com/jacobweinstock/iamt v0.0.0-20230502042727-d7cdbe67d9ef // indirect github.com/jacobweinstock/registrar v0.4.7 // indirect - github.com/jmoiron/sqlx v1.3.5 // indirect + github.com/jmoiron/sqlx v1.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/klauspost/compress v1.17.7 // indirect - github.com/klauspost/cpuid/v2 v2.2.7 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/cpuid/v2 v2.2.8 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/lib/pq v1.10.9 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-isatty v0.0.20 // indirect + github.com/metal-toolbox/conditionorc v1.1.8 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // 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.33.1 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/nats-io/nats.go v1.36.0 // 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.1.1 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/pquerna/cachecontrol v0.2.0 // 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/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect + github.com/sagikazarmark/locafero v0.6.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/satori/go.uuid v1.2.0 // indirect + github.com/slack-go/slack v0.13.1 // 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 @@ -115,29 +124,26 @@ require ( github.com/volatiletech/sqlboiler v3.7.1+incompatible // indirect github.com/volatiletech/sqlboiler/v4 v4.16.2 // indirect github.com/volatiletech/strmangle v0.0.6 // indirect - go.hollow.sh/toolbox v0.6.3 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 // indirect - go.opentelemetry.io/otel/metric v1.24.0 // indirect - go.opentelemetry.io/otel/sdk v1.24.0 // indirect - go.opentelemetry.io/proto/otlp v1.1.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 // indirect + go.opentelemetry.io/otel/metric v1.28.0 // indirect + go.opentelemetry.io/otel/sdk v1.28.0 // indirect + go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - gocloud.dev v0.36.0 // indirect - golang.org/x/arch v0.7.0 // indirect - golang.org/x/crypto v0.22.0 // indirect - golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8 // 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.168.0 // indirect - google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240304212257-790db918fca8 // indirect - google.golang.org/grpc v1.62.0 // indirect - google.golang.org/protobuf v1.32.0 // indirect + gocloud.dev v0.38.0 // indirect + golang.org/x/arch v0.9.0 // indirect + golang.org/x/crypto v0.26.0 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect + golang.org/x/sys v0.24.0 // indirect + golang.org/x/text v0.17.0 // indirect + golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 // indirect + google.golang.org/api v0.189.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240730163845-b1a4ccb954bf // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240730163845-b1a4ccb954bf // indirect + google.golang.org/grpc v1.65.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index bfa0fda..238950d 100644 --- a/go.sum +++ b/go.sum @@ -29,7 +29,12 @@ 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.10 h1:LXy9GEO+timppncPIAZoOj3l58LIU9k+kn48AN7IO3Y= +cloud.google.com/go v0.115.0 h1:CnFSK6Xo3lDYRoBKEcAtia6VSC837/ZkJuRduSFnr14= +cloud.google.com/go v0.115.0/go.mod h1:8jIM5vVgoAEoiVxQ/O4BFTfHqulPZgs/ufEzMcFMdWU= +cloud.google.com/go/auth v0.7.2 h1:uiha352VrCDMXg+yoBtaD0tUF4Kv9vrtrWPYXwutnDE= +cloud.google.com/go/auth v0.7.2/go.mod h1:VEc4p5NNxycWQTMQEDQF0bd6aTMb6VgYDXEwiJJQAbs= +cloud.google.com/go/auth/oauth2adapt v0.2.3 h1:MlxF+Pd3OmSudg/b1yZ5lJwoXCEaeedAguodky1PcKI= +cloud.google.com/go/auth/oauth2adapt v0.2.3/go.mod h1:tMQXOfZzFuNuUxOypHlQEXgdfX5cuhwU+ffUuXRJE8I= 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,17 +46,18 @@ 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.4 h1:EBT9Nw4q3zyE7G45Wvv3MzolIrCJEuHys5muLY0wvAw= -cloud.google.com/go/compute v1.23.4/go.mod h1:/EJMj55asU6kAFnuZET8zqgwgJ9FvXWXOkkfQZa4ioI= -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/compute v1.24.0 h1:phWcR2eWzRJaL/kOiJwfFsPs4BaKq1j6vnpZrc1YlVg= +cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= +cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= 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.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI= -cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= -cloud.google.com/go/kms v1.15.5 h1:pj1sRfut2eRbD9pFRjNnPNg/CzJPuQAzUujMIM1vVeM= -cloud.google.com/go/kms v1.15.5/go.mod h1:cU2H5jnp6G2TDpUGZyqTCoy1n16fbubHZjmVXSMtwDI= +cloud.google.com/go/iam v1.1.8 h1:r7umDwhj+BQyz0ScZMp4QrGXjSTI3ZINnpgU2nlB/K0= +cloud.google.com/go/iam v1.1.8/go.mod h1:GvE6lyMmfxXauzNq8NbgJbeVQNspG+tcdL/W8QO1+zE= +cloud.google.com/go/kms v1.17.1 h1:5k0wXqkxL+YcXd4viQzTqCgzzVKKxzgrK+rCZJytEQs= +cloud.google.com/go/kms v1.17.1/go.mod h1:DCMnCF/apA6fZk5Cj4XsD979OyHAqFasPuA5Sd0kGlQ= +cloud.google.com/go/longrunning v0.5.7 h1:WLbHekDbjK1fVFD3ibpFFVoyizlLRl73I7YKuAKilhU= +cloud.google.com/go/longrunning v0.5.7/go.mod h1:8GClkudohy1Fxm3owmBGid8W0pSgodEMwEAztp38Xng= 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= @@ -65,6 +71,8 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.0.0/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.0.0/go.mod h1:+6sju8gk8FRmSajX3Oz4G5Gm7P+mbqE9FVaXXFYTkCM= github.com/Azure/azure-sdk-for-go/sdk/internal v1.0.0/go.mod h1:eWRD7oawr1Mu1sLCawqVc0CUiF43ia3qQMxLscsKQ9w= @@ -105,34 +113,32 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bmc-toolbox/bmclib/v2 v2.2.4 h1:agAQuDLI/NNpKkxU+c+NfPZAu8ENBDE+kcTfz7WTCrw= github.com/bmc-toolbox/bmclib/v2 v2.2.4/go.mod h1:V2XVg0Scpm16+0gE7WnI+5bU/M0c/o/nPZKHKzyVjAo= -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/bmc-toolbox/common v0.0.0-20240723142833-87832458b53b h1:0LHjikaGWlqEMczrCEZ6w1N/ZqcYlx6WRHkhabRUQEk= +github.com/bmc-toolbox/common v0.0.0-20240723142833-87832458b53b/go.mod h1:Cdnkm+edb6C0pVkyCrwh3JTXAe0iUF9diDG/DztPI9I= github.com/bombsimon/logrusr/v2 v2.0.1 h1:1VgxVNQMCvjirZIYaT9JYn6sAVGVEcNtRE0y4mvaOAM= github.com/bombsimon/logrusr/v2 v2.0.1/go.mod h1:ByVAX+vHdLGAfdroiMg6q0zgq2FODY2lc5YJvzmOJio= -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.2 h1:ywfwo0a/3j9HR8wsYGWsIWl2mvRsI950HyoxiBERw5A= -github.com/bytedance/sonic v1.11.2/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/bytedance/sonic v1.12.1 h1:jWl5Qz1fy7X1ioY74WqO0KjAMtAGQs4sYnjiEBiyX24= +github.com/bytedance/sonic v1.12.1/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk= +github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM= +github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= +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= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= -github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= -github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= -github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= -github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= -github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0= -github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= +github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= +github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= +github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -144,8 +150,8 @@ 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.6 h1:Wlv9TzkrG9V7i6u8dEtmXPrBzvfFp+CgJNs696rAajM= -github.com/cockroachdb/cockroach-go/v2 v2.3.6/go.mod h1:1wNJ45eSXW9AnOc3skntW9ZUZz6gxrQK3cOj3rK+BC8= +github.com/cockroachdb/cockroach-go/v2 v2.3.8 h1:53yoUo4+EtrC1NrAEgnnad4AS3ntNvGup1PAXZ7UmpE= +github.com/cockroachdb/cockroach-go/v2 v2.3.8/go.mod h1:9uH5jK4yQ3ZQUT9IXe4I2fHzMIF5+JC/oOdzTRgJYJk= github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk= github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= @@ -153,7 +159,7 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7 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/cpuguy83/go-md2man/v2 v2.0.4/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= @@ -176,13 +182,13 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/equinix-labs/otel-init-go v0.0.9 h1:hdh0Qifs1vzFnaN6UpJz0pO6A6ZejXjvkEFi8OGTfpE= github.com/equinix-labs/otel-init-go v0.0.9/go.mod h1:5h8apPuPWz/KaMvAb3d0HoPEisQrUnqPmkc2T5SSpX4= github.com/ericlagergren/decimal v0.0.0-20190420051523-6335edbaa640/go.mod h1:mdYyfAkzn9kyJ/kMk/7WE9ufl9lflh+2NvecQ5mAghs= -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/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731 h1:R/ZjJpjQKsZ6L/+Gf9WHbt31GG8NMVcpRqUE+1mMIyo= +github.com/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731/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/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= -github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= +github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= +github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= 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= @@ -193,18 +199,18 @@ github.com/friendsofgo/errors v0.9.2/go.mod h1:yCvFW5AkDIL9qn7suHVLiI/gH228n7PC4 github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= 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/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4= +github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -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/cors v1.7.2 h1:oLDHxdg8W/XDoN/8zamqk/Drgt4oVZDvaV0YmvVICQw= +github.com/gin-contrib/cors v1.7.2/go.mod h1:SUJVARKgQ40dmrzgXEVxj2m7Ig1v1qIboQkPDTQ9t2E= 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.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= -github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= +github.com/gin-contrib/zap v1.1.4 h1:xvxTybg6XBdNtcQLH3Tf0lFr4vhDkwzgLLrIGlNTqIo= +github.com/gin-contrib/zap v1.1.4/go.mod h1:7lgEpe91kLbeJkwBTPgtVBy4zMa6oSBEcvj662diqKQ= +github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= +github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -214,9 +220,10 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 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.0.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.2.2/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/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/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-logr/zerologr v1.2.3 h1:up5N9vcH9Xck3jJkXzgyOxozT14R47IyDODz8LM1KSs= @@ -227,14 +234,16 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= 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.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-playground/validator/v10 v10.22.0 h1:k6HsTZ0sTnROkhS//R0O+55JgM8C4Bx7ia+JlgcnOao= +github.com/go-playground/validator/v10 v10.22.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-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -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/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= +github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= 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= @@ -283,8 +292,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= @@ -332,8 +341,8 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+ github.com/google/uuid v1.3.0/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/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= +github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI= +github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA= 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= @@ -343,17 +352,20 @@ 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.2 h1:mhN09QQW1jEWeMF74zGR81R30z4VJzjZsfkUhuHF+DA= -github.com/googleapis/gax-go/v2 v2.12.2/go.mod h1:61M8vcyyXR2kqKFxKrfA22jaA8JGF7Dc8App1U3H6jc= +github.com/googleapis/gax-go/v2 v2.13.0 h1:yitjD5f7jQHhyDsnhKEBU52NdvvdSeGzlAnDPT0hH1s= +github.com/googleapis/gax-go/v2 v2.13.0/go.mod h1:Z/fvTZXF8/uw7Xu5GuslPw+bplx6SS338j1Is2S+B7A= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 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.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.21.0 h1:CWyXh/jylQWp2dtiV33mY4iSSp6yf4lmn+c7/tN+ObI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.21.0/go.mod h1:nCLIt0w3Ept2NwF8ThLmrppXsfT07oC8k0XNDxd8sVU= 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= @@ -363,11 +375,10 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c= -github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= @@ -376,8 +387,8 @@ github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-retryablehttp v0.7.5 h1:bJj+Pj19UZMIweq/iie+1u5YCdGrnxCT9yvm0e+Nd5M= -github.com/hashicorp/go-retryablehttp v0.7.5/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8= +github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= +github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= @@ -393,6 +404,8 @@ github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/ github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= +github.com/hetiansu5/urlquery v1.2.7 h1:jn0h+9pIRqUziSPnRdK/gJK8S5TCnk+HZZx5fRHf8K0= +github.com/hetiansu5/urlquery v1.2.7/go.mod h1:wFpZdTHRdwt7mk0EM/DdZEWtEN4xf8HJoH/BLXm/PG0= github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= @@ -433,20 +446,23 @@ github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwX 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-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA= -github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/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.2 h1:QBdZQTKpPdBlw2AdKwHEyqUcm/lrl2cwWAHjCMyln/o= -github.com/jackc/pgtype v1.14.2/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgtype v1.14.3 h1:h6W9cPuHsRWQFTWUZMAKMgG5jSwQI0Zurzdvlx3Plus= +github.com/jackc/pgtype v1.14.3/go.mod h1:aKeozOde08iifGosdJpz9MBZonJOUJxqNpPBcMJTlVA= 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.2 h1:xVpYkNR5pk5bMCZGfClbO962UIqVABcAGt7ha1s/FeU= github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= +github.com/jackc/pgx/v4 v4.18.3 h1:dE2/TrEsGX3RBprb3qryqSV9Y60iZN1C6i8IrmW9/BA= +github.com/jackc/pgx/v4 v4.18.3/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= @@ -458,8 +474,8 @@ github.com/jacobweinstock/registrar v0.4.7 h1:s4dOExccgD+Pc7rJC+f3Mc3D+NXHcXUaOi github.com/jacobweinstock/registrar v0.4.7/go.mod h1:PWmkdGFG5/ZdCqgMo7pvB3pXABOLHc5l8oQ0sgmBNDU= github.com/jeremywohl/flatten v1.0.1 h1:LrsxmB3hfwJuE+ptGOijix1PIfOoKLJ3Uee/mzbgtrs= github.com/jeremywohl/flatten v1.0.1/go.mod h1:4AmD/VxjWcI5SRB0n6szE2A6s2fsNHDLO0nAlMHgfLQ= -github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= -github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= +github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= +github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -475,11 +491,11 @@ github.com/kat-co/vala v0.0.0-20170210184112-42e1d8b61f12/go.mod h1:u9MdXq/QageO 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.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= -github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/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= +github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM= +github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -488,6 +504,7 @@ 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= @@ -496,6 +513,7 @@ 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 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= 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= @@ -528,14 +546,18 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.14 h1:qZgc/Rwetq+MtyE18WhzjokPD93dNqLGNT3QJuLvBGw= github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/metal-toolbox/fleetdb v0.16.9 h1:cU8izN7tTi4dnGisP43MgK2ddtbrJJ4zLLwIS3wRABw= -github.com/metal-toolbox/fleetdb v0.16.9/go.mod h1:L2FavoKCdpewj759/MepRmbInSE0JpuSOMnXJho9u3o= -github.com/metal-toolbox/rivets v1.0.4 h1:BFvlYWsN+5Zb2JS+oJJBDtaQ94M5x2Llf6kmwi+Byjo= -github.com/metal-toolbox/rivets v1.0.4/go.mod h1:EMQJRT1mjIyFRXxvKNaBlz7Z4Sp88rTaGO8W18olN2I= +github.com/metal-toolbox/conditionorc v1.1.8 h1:5wjIdPLdLY2RkIeGZ73tTFEnKJxBzBM5ZJMopDqFgSg= +github.com/metal-toolbox/conditionorc v1.1.8/go.mod h1:eXlXZoOJBmihR4/+xA2o1dj1sQTXkU63Ekma7Ouc+o0= +github.com/metal-toolbox/ctrl v0.2.9 h1:Q1Hqpqyb71/gg2PcX/qrfoDE8FlydJt4rPQb7/Z8LhI= +github.com/metal-toolbox/ctrl v0.2.9/go.mod h1:QVATUIWFx3dbjOoEX0EnJHtRvypRlXZ9HUGaPLRyTG8= +github.com/metal-toolbox/fleetdb v1.19.5 h1:ERgdFAUtWnT/AeVhCGclsENmwPhU88JUcgOZAdxWKYI= +github.com/metal-toolbox/fleetdb v1.19.5/go.mod h1:k9MZXQsJX4NfBoANst6g1468papSs0tzsSyzN3gGWuQ= +github.com/metal-toolbox/rivets v1.3.8-0.20240923144748-4fa59d630b50 h1:v5aGsD3WnCOD6IB8o9F4XqR9kB/Vr/+LUQTmaG+aQYI= +github.com/metal-toolbox/rivets v1.3.8-0.20240923144748-4fa59d630b50/go.mod h1:8irU6eXgOa3QkjdcGi/aY4vqoMqCkbwVz7iVTYYPCX8= 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= @@ -543,6 +565,7 @@ github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA 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 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= @@ -552,6 +575,7 @@ github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= @@ -562,14 +586,16 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= github.com/montanaflynn/stats v0.6.6/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= 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.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/nats-server/v2 v2.10.12 h1:G6u+RDrHkw4bkwn7I911O5jqys7jJVRY6MwgndyUsnE= +github.com/nats-io/nats-server/v2 v2.10.12/go.mod h1:H1n6zXtYLFCgXcf/SF8QNTSIFuS8tyZQMN9NguUHdEs= +github.com/nats-io/nats.go v1.36.0 h1:suEUPuWzTSse/XhESwqLxXGuj8vGRuPRoG7MoRN/qyU= +github.com/nats-io/nats.go v1.36.0/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= @@ -579,8 +605,8 @@ github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144T github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= -github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= -github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/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/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -600,33 +626,33 @@ 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.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_golang v1.20.1 h1:IMJXHOD6eARkQpxo8KkhgEVFlBNm+nkrFUyGlIu7Na8= +github.com/prometheus/client_golang v1.20.1/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= 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.6.0 h1:k1v3CzpSRUTrKMppY35TLwPvxHqBu0bYgxZzqGIgaos= -github.com/prometheus/client_model v0.6.0/go.mod h1:NTQHnmxFpouOD0DpvP4XujX3CdOAGQPoaGhyTchlyt8= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= 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.49.0 h1:ToNTdK4zSnPVJmh698mGFkDor9wBI/iGaJy5dbH1EgI= -github.com/prometheus/common v0.49.0/go.mod h1:Kxm+EULxRbUkjGU6WFsQqo3ORzB4tyKvlWFOE9mB2sE= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= 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.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/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.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= 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= @@ -635,8 +661,8 @@ github.com/rs/zerolog v1.31.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWR 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/locafero v0.6.0 h1:ON7AQg37yzcRPU69mt7gwhFEBwxI6P9T4Qu3N51bwOk= +github.com/sagikazarmark/locafero v0.6.0/go.mod h1:77OmuIc6VTraTXKXIs/uvUxKGUXjE1GbemJYHqdNjX0= 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 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= @@ -650,8 +676,11 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/slack-go/slack v0.13.1 h1:6UkM3U1OnbhPsYeb1IMkQ6HSNOSikWluwOncJt4Tz/o= +github.com/slack-go/slack v0.13.1/go.mod h1:hlGi5oXA+Gt+yWTPP0plCdRKmjsDxecdHxYQdlMQKOw= 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= @@ -664,14 +693,14 @@ github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155 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.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= -github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= 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.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= -github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= +github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI= +github.com/spf13/viper v1.19.0/go.mod h1:GQUN9bilAbhU/jgc1bKs99f/suXKeUMct8Adx5+Ntkg= github.com/stmcginnis/gofish v0.15.1-0.20231121142100-22a60a77be91 h1:WmABtU8y6kTgzoVUn3FWCQGAfyodve3uz3xno28BrRs= github.com/stmcginnis/gofish v0.15.1-0.20231121142100-22a60a77be91/go.mod h1:BLDSFTp8pDlf/xDbLZa+F7f7eW0E/CHCboggsu8CznI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -725,16 +754,12 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -github.com/zsais/go-gin-prometheus v0.1.0 h1:bkLv1XCdzqVgQ36ScgRi09MA2UC1t3tAB6nsfErsGO4= -github.com/zsais/go-gin-prometheus v0.1.0/go.mod h1:Slirjzuz8uM8Cw0jmPNqbneoqcUtY2GGjn2bEd4NRLY= go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= go.etcd.io/etcd/client/v2 v2.305.4/go.mod h1:Ud+VUwIi9/uQHOMA+4ekToJ12lTxlv0zB/+DHwTGEbU= 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.9 h1:fsfF/w5zHgiNAHvYmvsWlICNha2X53WNLVSKOkyPnWo= -go.infratographer.com/x v0.3.9/go.mod h1:n/61MZRKFbGlS8xUwAhTyDhqcL2Wk6uPsXADC2n5t1I= +go.infratographer.com/x v0.5.3 h1:Ul50kwszNWPSf9Tds7RKmSQx+QHZbE8Jy9J38cEztP8= +go.infratographer.com/x v0.5.3/go.mod h1:IyZALpwaaviUIN8bGp9cU0hnn1mn0A/6zi70XES4+iE= 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= @@ -744,27 +769,27 @@ 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.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/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo= -go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0 h1:t6wl9SPayj+c7lEIFgm4ooDBZVb01IhLB4InpomhRw8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0/go.mod h1:iSDOcsnSA5INXzZtwaBPrKp/lWu/V14Dd+llD0oI2EA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0 h1:Mw5xcxMwlqoJd97vwPxA8isEaIoxsta9/Q51+TTJLGE= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0/go.mod h1:CQNu9bj7o7mC6U7+CA/schKEYakYXWr79ucDHTMGhCM= -go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI= -go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco= -go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw= -go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg= -go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI= -go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.53.0 h1:ktt8061VV/UU5pdPF6AcEFyuPxMizf/vU6eD1l+13LI= +go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.53.0/go.mod h1:JSRiHPV7E3dbOAP0N6SRPg2nC/cugJnVXRqP018ejtY= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.51.0 h1:A3SayB3rNyt+1S6qpI9mHPkeHTZbD7XILEqWnYZb2l0= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.51.0/go.mod h1:27iA5uvhuRNmalO+iEUdVn5ZMj2qy10Mm+XRIpRmyuU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= +go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= +go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw= +go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= +go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= +go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= +go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= +go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v1.1.0 h1:2Di21piLrCqJ3U3eXGCTPHE9R8Nh+0uglSnOyxikMeI= -go.opentelemetry.io/proto/otlp v1.1.0/go.mod h1:GpBHCBWiqvVLDqmHZsoMM3C5ySeKTC7ej/RNTae6MdY= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= 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= @@ -785,11 +810,10 @@ 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.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= +gocloud.dev v0.38.0 h1:SpxfaOc/Fp4PeO8ui7wRcCZV0EgXZ+IWcVSLn6ZMSw0= +gocloud.dev v0.38.0/go.mod h1:3XjKvd2E5iVNu/xFImRzjN0d/fkNHe4s0RiKidpEUMQ= +golang.org/x/arch v0.9.0 h1:ub9TgUInamJ8mrZIGlBG6/4TqWeMszd4N8lNorbrr6k= +golang.org/x/arch v0.9.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= @@ -809,8 +833,10 @@ golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5y 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-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -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/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= 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= @@ -821,8 +847,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-20240409090435-93d18d7e34b8 h1:ESSUROHIBHg7USnszlcdmjBEwdMj9VUvU+OPk4yl2mc= -golang.org/x/exp v0.0.0-20240409090435-93d18d7e34b8/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= 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= @@ -849,6 +875,7 @@ 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.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 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= @@ -899,8 +926,11 @@ 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.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= 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= @@ -921,8 +951,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.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= -golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= +golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= +golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= 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= @@ -936,8 +966,9 @@ 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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.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= @@ -1000,6 +1031,7 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210608053332-aa57babbf139/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1026,11 +1058,16 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/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.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= +golang.org/x/sys v0.24.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/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= 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= @@ -1040,9 +1077,11 @@ 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.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 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= @@ -1110,6 +1149,7 @@ 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.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= 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= @@ -1119,8 +1159,8 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9 h1:LLhsEBxRTBLuKlQxFBYUOU8xyFgXv6cOTp2HASDlsDk= +golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -1160,8 +1200,8 @@ 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.168.0 h1:MBRe+Ki4mMN93jhDDbpuRLjRddooArz4FeSObvUMmjY= -google.golang.org/api v0.168.0/go.mod h1:gpNOiMA2tZ4mf5R9Iwf4rK/Dcz0fbdIgWYWVoxmsyLg= +google.golang.org/api v0.189.0 h1:equMo30LypAkdkLMBqfeIqtyAnlyig1JSZArl4XPwdI= +google.golang.org/api v0.189.0/go.mod h1:FLWGJKb0hb+pU2j+rJqwbnsF+ym+fQs73rbJ+KAUgy8= 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= @@ -1169,8 +1209,6 @@ google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww 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/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= @@ -1249,12 +1287,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-20240205150955-31a09d347014 h1:g/4bk7P6TPMkAUbUhquq98xey1slwvuVJPosdBqYJlU= -google.golang.org/genproto v0.0.0-20240205150955-31a09d347014/go.mod h1:xEgQu1e4stdSSsxPDK8Azkrk/ECl5HvdPf6nbZrTS5M= -google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8 h1:8eadJkXbwDEMNwcB5O0s5Y5eCfyuCLdvaiOIaGTrWmQ= -google.golang.org/genproto/googleapis/api v0.0.0-20240304212257-790db918fca8/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240304212257-790db918fca8 h1:IR+hp6ypxjH24bkMfEJ0yHR21+gwPWdV+/IBrPQyn3k= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240304212257-790db918fca8/go.mod h1:UCOku4NytXMJuLQE5VuqA5lX3PcHCBo8pxNyvkf4xBs= +google.golang.org/genproto v0.0.0-20240722135656-d784300faade h1:lKFsS7wpngDgSCeFn7MoLy+wBDQZ1UQIJD4UNM1Qvkg= +google.golang.org/genproto v0.0.0-20240722135656-d784300faade/go.mod h1:FfBgJBJg9GcpPvKIuHSZ/aE1g2ecGL74upMzGZjiGEY= +google.golang.org/genproto/googleapis/api v0.0.0-20240730163845-b1a4ccb954bf h1:GillM0Ef0pkZPIB+5iO6SDK+4T9pf6TpaYR6ICD5rVE= +google.golang.org/genproto/googleapis/api v0.0.0-20240730163845-b1a4ccb954bf/go.mod h1:OFMYQFHJ4TM3JRlWDZhJbZfra2uqc3WLBZiaaqP4DtU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240730163845-b1a4ccb954bf h1:liao9UHurZLtiEwBgT9LMOnKYsHze6eA6w1KQCMVN2Q= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240730163845-b1a4ccb954bf/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= 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= @@ -1285,8 +1323,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.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk= -google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= 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= @@ -1302,8 +1340,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -1378,7 +1416,6 @@ modernc.org/token v1.0.1/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= -rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= diff --git a/internal/config/config.go b/internal/config/config.go new file mode 100644 index 0000000..dcfd66f --- /dev/null +++ b/internal/config/config.go @@ -0,0 +1,140 @@ +package config + +import ( + "os" + "strings" + + "github.com/jeremywohl/flatten" + "github.com/metal-toolbox/bioscfg/internal/controllers/kind" + "github.com/metal-toolbox/bioscfg/internal/store/fleetdb" + "github.com/metal-toolbox/rivets/events" + "github.com/mitchellh/mapstructure" + "github.com/pkg/errors" + "github.com/spf13/viper" +) + +var ( + ErrConfig = errors.New("configuration error") +) + +type Configuration struct { + FacilityCode string + LogLevel string + Endpoints Endpoints + Controller kind.Controller + Dryrun bool + Concurrency int +} + +type Endpoints struct { + // NatsOptions defines the NATs events broker configuration parameters. + Nats events.NatsOptions `mapstructure:"nats"` + + // FleetDBConfig defines the fleetdb client configuration parameters + FleetDB fleetdb.Config `mapstructure:"fleetdb"` +} + +func Load(cfgFilePath, loglevel string) (*Configuration, error) { + v := viper.New() + cfg := &Configuration{} + + err := cfg.envBindVars(v) + if err != nil { + return nil, err + } + + v.SetConfigType("yaml") + v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) + v.AutomaticEnv() + + err = readInFile(v, cfg, cfgFilePath) + if err != nil { + return nil, err + } + + if loglevel != "" { + cfg.LogLevel = loglevel + } + + err = cfg.validate() + return cfg, err +} + +// Reads in the cfgFile when available and overrides from environment variables. +func readInFile(v *viper.Viper, cfg *Configuration, path string) error { + if cfg == nil { + return ErrConfig + } + + if path != "" { + fh, err := os.Open(path) + if err != nil { + return errors.Wrap(ErrConfig, err.Error()) + } + + if err = v.ReadConfig(fh); err != nil { + return errors.Wrap(ErrConfig, "ReadConfig error:"+err.Error()) + } + } else { + v.AddConfigPath(".") + v.SetConfigName("config") + err := v.ReadInConfig() + if err != nil { + return err + } + } + + err := v.Unmarshal(cfg) + if err != nil { + return err + } + + return nil +} + +func (cfg *Configuration) validate() error { + if cfg == nil { + return ErrConfig + } + + if cfg.FacilityCode == "" { + return errors.Wrap(ErrConfig, "no facility code") + } + + if cfg.LogLevel == "" { + cfg.LogLevel = "info" + } + + if cfg.Concurrency == 0 { + cfg.Concurrency = 1 + } + + return nil +} + +// envBindVars binds environment variables to the struct +// without a configuration file being unmarshalled, +// this is a workaround for a viper bug, +// +// This can be replaced by the solution in https://github.com/spf13/viper/pull/1429 +// once that PR is merged. +func (cfg *Configuration) envBindVars(v *viper.Viper) error { + envKeysMap := map[string]interface{}{} + if err := mapstructure.Decode(cfg, &envKeysMap); err != nil { + return err + } + + // Flatten nested conf map + flat, err := flatten.Flatten(envKeysMap, "", flatten.DotStyle) + if err != nil { + return errors.Wrap(err, "Unable to flatten config") + } + + for k := range flat { + if err := v.BindEnv(k); err != nil { + return errors.Wrap(ErrConfig, "env var bind error: "+err.Error()) + } + } + + return nil +} diff --git a/internal/configuration/configuration.go b/internal/configuration/configuration.go deleted file mode 100644 index fe7425d..0000000 --- a/internal/configuration/configuration.go +++ /dev/null @@ -1,271 +0,0 @@ -package configuration - -import ( - "net/url" - "os" - "strings" - "time" - - "github.com/jeremywohl/flatten" - "github.com/metal-toolbox/bioscfg/internal/model" - "github.com/mitchellh/mapstructure" - "github.com/pkg/errors" - "github.com/spf13/viper" -) - -var ( - // NATs streaming configuration - defaultNatsConnectTimeout = 100 * time.Millisecond -) - -// NatsConfig holds NATS specific configuration -type NatsConfig struct { - NatsURL string - CredsFile string - KVReplicas int - ConnectTimeout time.Duration -} - -func newNatsConfig() *NatsConfig { - return &NatsConfig{ - ConnectTimeout: defaultNatsConnectTimeout, - } -} - -// Configuration holds application configuration read from a YAML or set by env variables. -// nolint:govet // prefer readability over field alignment optimization for this case. -type Configuration struct { - // LogLevel is the app verbose logging level. - // one of - info, debug, trace - LogLevel string `mapstructure:"log_level"` - - // Concurrency is the number of concurrent tasks that can be running at once. - Concurrency int `mapstructure:"concurrency"` - - // FacilityCode limits this service to events in a facility. - FacilityCode string `mapstructure:"facility_code"` - - // FleetDBOptions defines the fleetdb client configuration parameters - FleetDBOptions *FleetDBOptions `mapstructure:"fleetdb"` - - // NatsConfig defines the NATs events broker configuration parameters. - NatsConfig *NatsConfig `mapstructure:"nats"` - - EnableProfiling bool `mapstructure:"enable_profiling"` -} - -// New creates an empty configuration struct. -func New() *Configuration { - config := &Configuration{} - - // these are initialized here so viper can read in configuration from env vars - // once https://github.com/spf13/viper/pull/1429 is merged, this can go. - config.FleetDBOptions = &FleetDBOptions{} - config.NatsConfig = newNatsConfig() - - return config -} - -func (c *Configuration) AsLogFields() []any { - return []any{ - "logLevel", c.LogLevel, - "concurrency", c.Concurrency, - "facilityCode", c.FacilityCode, - "disableOAuth", c.FleetDBOptions.DisableOAuth, - "fleetDBUrl", c.FleetDBOptions.Endpoint, - "natsURL", c.NatsConfig.NatsURL, - "enableProfiling", c.EnableProfiling, - } -} - -func (c *Configuration) LoadArgs(args *model.Args) { - c.LogLevel = args.LogLevel - c.EnableProfiling = args.EnableProfiling - c.FacilityCode = args.FacilityCode -} - -// FleetDBOptions defines configuration for the fleetdb client. -// https://github.com/metal-toolbox/fleetdb -type FleetDBOptions struct { - Endpoint string `mapstructure:"endpoint"` - OidcIssuerEndpoint string `mapstructure:"oidc_issuer_endpoint"` - OidcAudienceEndpoint string `mapstructure:"oidc_audience_endpoint"` - OidcClientSecret string `mapstructure:"oidc_client_secret"` - OidcClientID string `mapstructure:"oidc_client_id"` - OidcClientScopes []string `mapstructure:"oidc_client_scopes"` - DisableOAuth bool `mapstructure:"disable_oauth"` -} - -// Load the application configuration -// Reads in the configFile when available and overrides from environment variables. -func Load(args *model.Args) (*Configuration, error) { - viperConfig := viper.New() - viperConfig.SetConfigType("yaml") - viperConfig.SetEnvPrefix(model.AppName) - viperConfig.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) - viperConfig.AutomaticEnv() - - if args.ConfigFile != "" { - fh, err := os.Open(args.ConfigFile) - if err != nil { - return nil, errors.Wrap(model.ErrConfig, err.Error()) - } - - if err = viperConfig.ReadConfig(fh); err != nil { - return nil, errors.Wrap(model.ErrConfig, "ReadConfig error: "+err.Error()) - } - } - - config := New() - config.LoadArgs(args) - - if err := config.envBindVars(viperConfig); err != nil { - return nil, errors.Wrap(model.ErrConfig, "env var bind error: "+err.Error()) - } - - if err := viperConfig.Unmarshal(config); err != nil { - return nil, errors.Wrap(model.ErrConfig, "Unmarshal error: "+err.Error()) - } - - config.envVarAppOverrides(viperConfig) - - if err := config.envVarNatsOverrides(viperConfig); err != nil { - return nil, errors.Wrap(model.ErrConfig, "nats env overrides error: "+err.Error()) - } - - if err := config.envVarFleetDBOverrides(viperConfig); err != nil { - return nil, errors.Wrap(model.ErrConfig, "fleetdb env overrides error: "+err.Error()) - } - - return config, nil -} - -func (c *Configuration) envVarAppOverrides(viperConfig *viper.Viper) { - logLevel := viperConfig.GetString("log.level") - if logLevel != "" { - c.LogLevel = logLevel - } -} - -// envBindVars binds environment variables to the struct -// without a configuration file being unmarshalled, -// this is a workaround for a viper bug, -// -// This can be replaced by the solution in https://github.com/spf13/viper/pull/1429 -// once that PR is merged. -func (c *Configuration) envBindVars(viperConfig *viper.Viper) error { - envKeysMap := map[string]interface{}{} - if err := mapstructure.Decode(c, &envKeysMap); err != nil { - return err - } - - // Flatten nested conf map - flat, err := flatten.Flatten(envKeysMap, "", flatten.DotStyle) - if err != nil { - return errors.Wrap(err, "Unable to flatten configuration") - } - - for k := range flat { - if err := viperConfig.BindEnv(k); err != nil { - return errors.Wrap(model.ErrConfig, "env var bind error: "+err.Error()) - } - } - - return nil -} - -// nolint:gocyclo // nats env configuration load is cyclomatic -func (c *Configuration) envVarNatsOverrides(viperConfig *viper.Viper) error { - if c.NatsConfig == nil { - c.NatsConfig = newNatsConfig() - } - - if viperConfig.GetString("nats.url") != "" { - c.NatsConfig.NatsURL = viperConfig.GetString("nats.url") - } - - if c.NatsConfig.NatsURL == "" { - return errors.New("missing parameter: nats.url") - } - - if viperConfig.GetString("nats.creds.file") != "" { - c.NatsConfig.CredsFile = viperConfig.GetString("nats.creds.file") - } - - if viperConfig.GetDuration("nats.connect.timeout") != 0 { - c.NatsConfig.ConnectTimeout = viperConfig.GetDuration("nats.connect.timeout") - } - - if viperConfig.GetInt("nats.kv.replicas") != 0 { - c.NatsConfig.KVReplicas = viperConfig.GetInt("nats.kv.replicas") - } - - return nil -} - -// nolint:gocyclo // parameter validation is cyclomatic -func (c *Configuration) envVarFleetDBOverrides(viperConfig *viper.Viper) error { - if c.FleetDBOptions == nil { - c.FleetDBOptions = &FleetDBOptions{} - } - - if viperConfig.GetString("fleetdb.endpoint") != "" { - c.FleetDBOptions.Endpoint = viperConfig.GetString("fleetdb.endpoint") - } - - // Validate endpoint - _, err := url.Parse(c.FleetDBOptions.Endpoint) - if err != nil { - return errors.New("fleetdb endpoint URL error: " + err.Error()) - } - - if viperConfig.GetString("fleetdb.disable.oauth") != "" { - c.FleetDBOptions.DisableOAuth = viperConfig.GetBool("fleetdb.disable.oauth") - } - - if c.FleetDBOptions.DisableOAuth { - return nil - } - - if viperConfig.GetString("fleetdb.oidc.issuer.endpoint") != "" { - c.FleetDBOptions.OidcIssuerEndpoint = viperConfig.GetString("fleetdb.oidc.issuer.endpoint") - } - - if c.FleetDBOptions.OidcIssuerEndpoint == "" { - return errors.New("fleetdb oidc.issuer.endpoint not defined") - } - - if viperConfig.GetString("fleetdb.oidc.audience.endpoint") != "" { - c.FleetDBOptions.OidcAudienceEndpoint = viperConfig.GetString("fleetdb.oidc.audience.endpoint") - } - - if c.FleetDBOptions.OidcAudienceEndpoint == "" { - return errors.New("fleetdb oidc.audience.endpoint not defined") - } - - if viperConfig.GetString("fleetdb.oidc.client.secret") != "" { - c.FleetDBOptions.OidcClientSecret = viperConfig.GetString("fleetdb.oidc.client.secret") - } - - if c.FleetDBOptions.OidcClientSecret == "" { - return errors.New("fleetdb.oidc.client.secret not defined") - } - - if viperConfig.GetString("fleetdb.oidc.client.id") != "" { - c.FleetDBOptions.OidcClientID = viperConfig.GetString("fleetdb.oidc.client.id") - } - - if c.FleetDBOptions.OidcClientID == "" { - return errors.New("fleetdb.oidc.client.id not defined") - } - - if viperConfig.GetString("fleetdb.oidc.client.scopes") != "" { - c.FleetDBOptions.OidcClientScopes = viperConfig.GetStringSlice("fleetdb.oidc.client.scopes") - } - - if len(c.FleetDBOptions.OidcClientScopes) == 0 { - return errors.New("fleetdb oidc.client.scopes not defined") - } - - return nil -} diff --git a/internal/controllers/bioscfg/bioscfg.go b/internal/controllers/bioscfg/bioscfg.go new file mode 100644 index 0000000..15ede94 --- /dev/null +++ b/internal/controllers/bioscfg/bioscfg.go @@ -0,0 +1,113 @@ +package bioscfg + +import ( + "context" + + "github.com/metal-toolbox/bioscfg/internal/config" + "github.com/metal-toolbox/bioscfg/internal/store/fleetdb" + "github.com/metal-toolbox/ctrl" + rctypes "github.com/metal-toolbox/rivets/condition" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +var ( + pkgName = "internal/bioscfg" +) + +// BiosCfg BiosCfg Controller Struct +type BiosCfg struct { + cfg *config.Configuration + logger *logrus.Entry + ctx context.Context + fleetdb *fleetdb.Store + nc *ctrl.NatsController +} + +// New create a new BiosCfg Controller +func New(ctx context.Context, cfg *config.Configuration, logger *logrus.Entry) (*BiosCfg, error) { + bc := &BiosCfg{ + cfg: cfg, + logger: logger, + ctx: ctx, + } + + err := bc.initDependences() + if err != nil { + return nil, err + } + + return bc, nil +} + +// Listen listen to Nats for tasks +func (bc *BiosCfg) Listen() error { + handleFactory := func() ctrl.TaskHandler { + return &TaskHandler{ + cfg: bc.cfg, + logger: bc.logger, + controllerID: bc.nc.ID(), + fleetdb: bc.fleetdb, + } + } + + err := bc.nc.ListenEvents(bc.ctx, handleFactory) + if err != nil { + return err + } + + return nil +} + +// initDependences Initialize network dependencies +func (bc *BiosCfg) initDependences() error { + err := bc.initNats() + if err != nil { + return errors.Wrap(err, "failed to initialize connection to nats") + } + + err = bc.initFleetDB() + if err != nil { + return errors.Wrap(err, "failed to initialize connection to fleetdb") + } + + return nil +} + +func (bc *BiosCfg) initNats() error { + bc.nc = ctrl.NewNatsController( + string(rctypes.BiosControl), + bc.cfg.FacilityCode, + string(rctypes.BiosControl), + bc.cfg.Endpoints.Nats.URL, + bc.cfg.Endpoints.Nats.CredsFile, + rctypes.BiosControl, + ctrl.WithConcurrency(bc.cfg.Concurrency), + ctrl.WithKVReplicas(bc.cfg.Endpoints.Nats.KVReplicationFactor), + ctrl.WithLogger(bc.logger.Logger), + ctrl.WithConnectionTimeout(bc.cfg.Endpoints.Nats.ConnectTimeout), + ) + + err := bc.nc.Connect(bc.ctx) + if err != nil { + bc.logger.Error(err) + return err + } + + return nil +} + +func (bc *BiosCfg) initFleetDB() error { + store, err := fleetdb.New( + bc.ctx, + &bc.cfg.Endpoints.FleetDB, + bc.logger.Logger, + ) + if err != nil { + return err + } + + bc.fleetdb = store + + return nil +} diff --git a/internal/controllers/bioscfg/errors.go b/internal/controllers/bioscfg/errors.go new file mode 100644 index 0000000..1d32181 --- /dev/null +++ b/internal/controllers/bioscfg/errors.go @@ -0,0 +1,9 @@ +package bioscfg + +import "errors" + +var ( + errInvalidConditionParams = errors.New("invalid condition parameters") + errTaskConv = errors.New("error in generic Task conversion") + errUnsupportedAction = errors.New("unsupported action") +) diff --git a/internal/controllers/bioscfg/handler.go b/internal/controllers/bioscfg/handler.go new file mode 100644 index 0000000..25d911f --- /dev/null +++ b/internal/controllers/bioscfg/handler.go @@ -0,0 +1,154 @@ +package bioscfg + +import ( + "context" + "time" + + "github.com/metal-toolbox/bioscfg/internal/config" + "github.com/metal-toolbox/bioscfg/internal/model" + "github.com/metal-toolbox/bioscfg/internal/store/bmc" + "github.com/metal-toolbox/bioscfg/internal/store/fleetdb" + "github.com/metal-toolbox/ctrl" + rctypes "github.com/metal-toolbox/rivets/condition" + "github.com/sirupsen/logrus" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/trace" +) + +type TaskHandler struct { + logger *logrus.Entry + cfg *config.Configuration + fleetdb *fleetdb.Store + bmcClient bmc.BMC + publisher ctrl.Publisher + server *model.Asset + task *Task + startTS time.Time + controllerID string +} + +func (th *TaskHandler) HandleTask(ctx context.Context, genTask *rctypes.Task[any, any], publisher ctrl.Publisher) error { + ctx, span := otel.Tracer(pkgName).Start( + ctx, + "bioscfg.HandleTask", + ) + defer span.End() + + var err error + th.publisher = publisher + + // Ungeneric the task + th.task, err = NewTask(genTask) + if err != nil { + th.logger.WithFields(logrus.Fields{ + "conditionID": genTask.ID, + "controllerID": th.controllerID, + "err": err.Error(), + }).Error("asset lookup error") + return err + } + + // Get Server + th.server, err = th.fleetdb.AssetByID(ctx, th.task.Parameters.AssetID) + if err != nil { + th.logger.WithFields(logrus.Fields{ + "assetID": th.task.Parameters.AssetID.String(), + "conditionID": th.task.ID, + "controllerID": th.controllerID, + "err": err.Error(), + }).Error("asset lookup error") + + return ctrl.ErrRetryHandler + } + + // New log entry for this condition + th.logger = th.logger.WithFields( + logrus.Fields{ + "controllerID": th.controllerID, + "conditionID": th.task.ID.String(), + "serverID": th.server.ID.String(), + "bmc": th.server.BmcAddress.String(), + "action": th.task.Parameters.Action, + }, + ) + + // Get BMC Client + if th.cfg.Dryrun { // Fake BMC + th.bmcClient = bmc.NewDryRunBMCClient(th.server) + th.logger.Warn("Running BMC in Dryrun mode") + } else { + th.bmcClient = bmc.NewBMCClient(th.server, th.logger) + } + + err = th.bmcClient.Open(ctx) + if err != nil { + th.logger.WithError(err).Error("bmc connection failed to connect") + return err + } + defer func() { + if err := th.bmcClient.Close(ctx); err != nil { + th.logger.WithError(err).Error("bmc connection close error") + } + }() + + return th.Run(ctx) +} + +func (th *TaskHandler) Run(ctx context.Context) error { + ctx, span := otel.Tracer(pkgName).Start( + ctx, + "TaskHandler.Run", + trace.WithSpanKind(trace.SpanKindConsumer), + ) + defer span.End() + + th.logger.Info("running condition action") + err := th.publishActive(ctx, "running condition action") + if err != nil { + return err + } + + switch th.task.Parameters.Action { + case rctypes.ResetSettings: + return th.ResetBios(ctx) + default: + return th.failedWithError(ctx, string(th.task.Parameters.Action), errUnsupportedAction) + } +} + +// ResetBios reset the bios of the server +func (th *TaskHandler) ResetBios(ctx context.Context) error { + // Get Power State + state, err := th.bmcClient.GetPowerState(ctx) + if err != nil { + return th.failedWithError(ctx, "error getting power state", err) + } + + err = th.publishActivef(ctx, "current power state: %s", state) + if err != nil { + return err + } + + // Reset Bios + err = th.bmcClient.ResetBios(ctx) + if err != nil { + return th.failedWithError(ctx, "error reseting bios", err) + } + + err = th.publishActive(ctx, "BIOS settings reset") + if err != nil { + return err + } + + // Reboot (if ON) + if state == model.PowerStateOn { + err = th.bmcClient.SetPowerState(ctx, model.PowerStateReset) + if err != nil { + return th.failedWithError(ctx, "failed to reboot server", err) + } + + return th.successful(ctx, "rebooting server") + } + + return th.successful(ctx, "skipping server reboot, not on") +} diff --git a/internal/controllers/bioscfg/publish.go b/internal/controllers/bioscfg/publish.go new file mode 100644 index 0000000..551ea3a --- /dev/null +++ b/internal/controllers/bioscfg/publish.go @@ -0,0 +1,113 @@ +package bioscfg + +import ( + "context" + "fmt" + "time" + + "github.com/metal-toolbox/bioscfg/internal/metrics" + rctypes "github.com/metal-toolbox/rivets/condition" + "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus" +) + +func (th *TaskHandler) publish(ctx context.Context, status string, state rctypes.State) error { + th.task.State = state + th.task.Status.Append(status) + + genTask, err := th.task.ToGeneric() + if err != nil { + th.logger.WithError(errTaskConv).Error() + return err + } + + if errDelay := sleepInContext(ctx, 10*time.Second); errDelay != nil { + return context.Canceled + } + + return th.publisher.Publish(ctx, + genTask, + false, + ) +} + +func (th *TaskHandler) publishActive(ctx context.Context, status string) error { + err := th.publish(ctx, status, rctypes.Active) + if err != nil { + th.logger.Infof("failed to publish condition status: %s", status) + return err + } + + th.logger.Infof("condition active: %s", status) + return nil +} + +func (th *TaskHandler) publishActivef(ctx context.Context, status string, args ...interface{}) error { + if len(args) > 0 { + status = fmt.Sprintf(status, args) + } + + return th.publishActive(ctx, status) +} + +// failed condition helper method +func (th *TaskHandler) failed(ctx context.Context, status string) error { + err := th.publish(ctx, status, rctypes.Failed) + + th.registerConditionMetrics(string(rctypes.Failed)) + + if err != nil { + th.logger.Infof("failed to publish condition status: %s", status) + return err + } + + th.logger.Warnf("condition failed: %s", status) + return nil +} + +func (th *TaskHandler) failedWithError(ctx context.Context, status string, err error) error { + newError := th.failed(ctx, errors.Wrap(err, status).Error()) + if newError != nil { + if err != nil { + return errors.Wrap(newError, err.Error()) + } + + return newError + } + + return err +} + +// successful condition helper method +func (th *TaskHandler) successful(ctx context.Context, status string) error { + err := th.publish(ctx, status, rctypes.Succeeded) + + th.registerConditionMetrics(string(rctypes.Succeeded)) + + if err != nil { + th.logger.Warnf("failed to publish condition status: %s", status) + return err + } + + th.logger.Infof("condition complete: %s", status) + return nil +} + +func (th *TaskHandler) registerConditionMetrics(status string) { + metrics.ConditionRunTimeSummary.With( + prometheus.Labels{ + "condition": string(rctypes.ServerControl), + "state": status, + }, + ).Observe(time.Since(th.startTS).Seconds()) +} + +// sleepInContext +func sleepInContext(ctx context.Context, t time.Duration) error { + select { + case <-time.After(t): + return nil + case <-ctx.Done(): + return context.Canceled + } +} diff --git a/internal/controllers/bioscfg/task.go b/internal/controllers/bioscfg/task.go new file mode 100644 index 0000000..8f74604 --- /dev/null +++ b/internal/controllers/bioscfg/task.go @@ -0,0 +1,89 @@ +package bioscfg + +import ( + "encoding/json" + + rctypes "github.com/metal-toolbox/rivets/condition" + rtypes "github.com/metal-toolbox/rivets/types" + "github.com/mitchellh/copystructure" + "github.com/pkg/errors" +) + +type Task rctypes.Task[*rctypes.BiosControlTaskParameters, json.RawMessage] + +func NewTask(task *rctypes.Task[any, any]) (*Task, error) { + paramsJSON, ok := task.Parameters.(json.RawMessage) + if !ok { + return nil, errInvalidConditionParams + } + + params := rctypes.BiosControlTaskParameters{} + if err := json.Unmarshal(paramsJSON, ¶ms); err != nil { + return nil, err + } + + // deep copy fields referenced by pointer + asset, err := copystructure.Copy(task.Server) + if err != nil { + return nil, errors.Wrap(errTaskConv, err.Error()+": Task.Server") + } + + fault, err := copystructure.Copy(task.Fault) + if err != nil { + return nil, errors.Wrap(errTaskConv, err.Error()+": Task.Fault") + } + + return &Task{ + StructVersion: task.StructVersion, + ID: task.ID, + Kind: task.Kind, + State: task.State, + Status: task.Status, + Parameters: ¶ms, + Fault: fault.(*rctypes.Fault), + FacilityCode: task.FacilityCode, + Server: asset.(*rtypes.Server), + WorkerID: task.WorkerID, + TraceID: task.TraceID, + SpanID: task.SpanID, + CreatedAt: task.CreatedAt, + UpdatedAt: task.UpdatedAt, + CompletedAt: task.CompletedAt, + }, nil +} + +func (task *Task) ToGeneric() (*rctypes.Task[any, any], error) { + paramsJSON, err := task.Parameters.Marshal() + if err != nil { + return nil, errors.Wrap(errTaskConv, err.Error()+": Task.Parameters") + } + + // deep copy fields referenced by pointer + asset, err := copystructure.Copy(task.Server) + if err != nil { + return nil, errors.Wrap(errTaskConv, err.Error()+": Task.Server") + } + + fault, err := copystructure.Copy(task.Fault) + if err != nil { + return nil, errors.Wrap(errTaskConv, err.Error()+": Task.Fault") + } + + return &rctypes.Task[any, any]{ + StructVersion: task.StructVersion, + ID: task.ID, + Kind: task.Kind, + State: task.State, + Status: task.Status, + Parameters: paramsJSON, + Fault: fault.(*rctypes.Fault), + FacilityCode: task.FacilityCode, + Server: asset.(*rtypes.Server), + WorkerID: task.WorkerID, + TraceID: task.TraceID, + SpanID: task.SpanID, + CreatedAt: task.CreatedAt, + UpdatedAt: task.UpdatedAt, + CompletedAt: task.CompletedAt, + }, nil +} diff --git a/internal/controllers/controller.go b/internal/controllers/controller.go new file mode 100644 index 0000000..70e1e06 --- /dev/null +++ b/internal/controllers/controller.go @@ -0,0 +1,73 @@ +package controllers + +import ( + "context" + + "github.com/equinix-labs/otel-init-go/otelinit" + "github.com/metal-toolbox/bioscfg/internal/config" + "github.com/metal-toolbox/bioscfg/internal/controllers/bioscfg" + "github.com/metal-toolbox/bioscfg/internal/controllers/kind" + "github.com/metal-toolbox/bioscfg/internal/metrics" + "github.com/metal-toolbox/bioscfg/internal/profiling" + "github.com/metal-toolbox/bioscfg/internal/version" + "github.com/sirupsen/logrus" +) + +var ( + LogLevel string + ConfigFile string + EnableProfiling bool +) + +type Controller interface { + Listen() error +} + +func newController(ctx context.Context, cfg *config.Configuration, logger *logrus.Entry) (Controller, error) { + switch cfg.Controller { + case kind.BiosCfg: + return bioscfg.New(ctx, cfg, logger) + default: + return nil, kind.ErrUnknownControllerKind + } +} + +func Run(ctx context.Context, controllerKind kind.Controller) error { + cfg, err := config.Load(ConfigFile, LogLevel) + if err != nil { + return err + } + cfg.Controller = controllerKind + + logger := logrus.New() + // TODO; Replace cfg.LogLevel with logrus.LogLevel, it should marshall/unmarshall? + logger.Level, err = logrus.ParseLevel(cfg.LogLevel) + if err != nil { + return err + } + + metrics.ListenAndServe() + version.ExportBuildInfoMetric() + if EnableProfiling { + profiling.Enable() + } + + ctx, otelShutdown := otelinit.InitOpenTelemetry(ctx, cfg.Controller.String()) + defer otelShutdown(ctx) + + v, err := version.Current().AsMap() + if err != nil { + return err + } + loggerEntry := logger.WithFields(v) + loggerEntry.Infof("Initializing %s", cfg.Controller.String()) + + controller, err := newController(ctx, cfg, loggerEntry) + if err != nil { + return err + } + + loggerEntry.Infof("Success! %s is starting to listen for conditions", cfg.Controller.String()) + + return controller.Listen() +} diff --git a/internal/controllers/kind/controller.go b/internal/controllers/kind/controller.go new file mode 100644 index 0000000..02e0f2f --- /dev/null +++ b/internal/controllers/kind/controller.go @@ -0,0 +1,38 @@ +package kind + +import ( + "errors" + "strings" +) + +type Controller uint8 + +const ( + BiosCfg Controller = iota +) + +const ( + BiosCfgStr = "bioscfg" +) + +var ( + ErrUnknownControllerKind = errors.New("unknown controller kind") +) + +func (c Controller) String() string { + switch c { + case BiosCfg: + return BiosCfgStr + default: + return "unknown" + } +} + +func FromString(str string) (Controller, error) { + switch strings.ToLower(str) { + case BiosCfgStr: + return BiosCfg, nil + default: + return 0, ErrUnknownControllerKind + } +} diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go deleted file mode 100644 index 6c01978..0000000 --- a/internal/handlers/handlers.go +++ /dev/null @@ -1,88 +0,0 @@ -package handlers - -import ( - "context" - "log/slog" - _ "net/http/pprof" // nolint:gosec // pprof path is only exposed over localhost - - "github.com/bmc-toolbox/bmclib/v2" - "github.com/metal-toolbox/bioscfg/internal/model" - "github.com/metal-toolbox/bioscfg/internal/store" - "github.com/metal-toolbox/bioscfg/internal/tasks" - rctypes "github.com/metal-toolbox/rivets/condition" - "github.com/metal-toolbox/rivets/events/controller" - "github.com/pkg/errors" -) - -// HandlerFactory has the data and business logic for the application -type HandlerFactory struct { - repository store.Repository -} - -// NewHandlerFactory returns a new instance of the Handler -func NewHandlerFactory(repository store.Repository) *HandlerFactory { - return &HandlerFactory{ - repository: repository, - } -} - -func (h *HandlerFactory) parseParams(condition *rctypes.Condition) (*rctypes.BiosControlTaskParameters, error) { - params, err := rctypes.NewBiosControlParametersFromCondition(condition) - if err != nil { - return nil, errors.Wrap(err, "failed to parse condition parameters") - } - - slog.Debug("Parsed condition parameters", "params", params) - - return params, nil -} - -func (h *HandlerFactory) getAsset(ctx context.Context, params *rctypes.BiosControlTaskParameters) (*model.Asset, error) { - asset, err := h.repository.AssetByID(ctx, params.AssetID) - if err != nil { - // TODO: Check error type - return nil, controller.ErrRetryHandler - } - - slog.Debug("Found asset", asset.AsLogFields()...) - - return asset, nil -} - -// Handle will handle the received condition -func (h *HandlerFactory) Handle( - ctx context.Context, - condition *rctypes.Condition, - publisher controller.ConditionStatusPublisher, -) error { - slog.Debug("Handling condition", "condition", condition) - - params, err := h.parseParams(condition) - if err != nil { - return err - } - - asset, err := h.getAsset(ctx, params) - if err != nil { - return err - } - - var task tasks.Task - - switch params.Action { - case rctypes.ResetSettings: - task = tasks.NewBiosResetTask(asset) - default: - slog.With(asset.AsLogFields()...).Error("Invalid action", "action", params.Action) - return model.ErrInvalidAction - } - - runner := tasks.NewTaskRunner(publisher, task) - client := bmclib.NewClient(asset.BmcAddress.String(), asset.BmcUsername, asset.BmcPassword) - - if err := runner.Run(ctx, client); err != nil { - slog.Error("Failed running task", "error", err, "task", task.Name()) - } - - return nil -} diff --git a/internal/log/log.go b/internal/log/log.go deleted file mode 100644 index 872c8bc..0000000 --- a/internal/log/log.go +++ /dev/null @@ -1,84 +0,0 @@ -package log - -import ( - "log/slog" - "os" - - runtime "github.com/banzaicloud/logrus-runtime-formatter" - "github.com/sirupsen/logrus" -) - -type Level string - -const ( - LevelTrace Level = "trace" - LevelDebug Level = "debug" - LevelInfo Level = "info" - LevelWarn Level = "warn" - LevelError Level = "error" -) - -var levelVar *slog.LevelVar - -// InitLogger will initialize the default logger instance. -func InitLogger() { - levelVar = &slog.LevelVar{} - levelVar.Set(slog.LevelInfo) - - logger := slog.New(slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: levelVar})) - - slog.SetDefault(logger) -} - -// SetLevel will set the logging level of the default logger at runtime. -func SetLevel(loglevel string) { - switch Level(loglevel) { - case LevelDebug: - levelVar.Set(slog.LevelDebug) - case LevelInfo, "": - levelVar.Set(slog.LevelInfo) - case LevelWarn: - levelVar.Set(slog.LevelWarn) - case LevelError: - levelVar.Set(slog.LevelError) - default: - levelVar.Set(slog.LevelInfo) - slog.Warn("Unknown log level, defaulting to info", "loglevel", loglevel) - } -} - -// NewLogrusLogger will generate a new logrus logger instance -func NewLogrusLogger(logLevel string) *logrus.Logger { - logger := logrus.New() - - logger.SetOutput(os.Stdout) - - switch Level(logLevel) { - case LevelDebug: - logger.Level = logrus.DebugLevel - case LevelTrace: - logger.Level = logrus.TraceLevel - case LevelInfo, "": - logger.Level = logrus.InfoLevel - case LevelWarn: - logger.Level = logrus.WarnLevel - case LevelError: - logger.Level = logrus.ErrorLevel - default: - logger.Level = logrus.InfoLevel - logger.WithField("logLevel", logLevel).Warn("Unknown log level, defaulting to info") - } - - logger.Level = logrus.InfoLevel - - runtimeFormatter := &runtime.Formatter{ - ChildFormatter: &logrus.JSONFormatter{}, - File: true, - Line: true, - BaseNameOnly: true, - } - - logger.SetFormatter(runtimeFormatter) - - return logger -} diff --git a/internal/model/errors.go b/internal/model/errors.go deleted file mode 100644 index 0b60877..0000000 --- a/internal/model/errors.go +++ /dev/null @@ -1,10 +0,0 @@ -package model - -import ( - "github.com/pkg/errors" -) - -var ( - ErrConfig = errors.New("configuration error") - ErrInvalidAction = errors.New("invalid action") -) diff --git a/internal/model/model.go b/internal/model/model.go index b393758..ee37c6e 100644 --- a/internal/model/model.go +++ b/internal/model/model.go @@ -10,11 +10,6 @@ type ( StoreKind string ) -const ( - AppName = "bioscfg" - AppSubject = "biosControl" -) - // nolint:govet // prefer to keep field ordering as is type Asset struct { ID uuid.UUID @@ -32,21 +27,3 @@ type Asset struct { // Facility this Asset is hosted in. FacilityCode string } - -func (a *Asset) AsLogFields() []any { - return []any{ - "asset_id", a.ID.String(), - "address", a.BmcAddress.String(), - "vendor", a.Vendor, - "model", a.Model, - "serial", a.Serial, - "facility", a.FacilityCode, - } -} - -type Args struct { - LogLevel string - ConfigFile string - FacilityCode string - EnableProfiling bool -} diff --git a/internal/store/bmc/bmc.go b/internal/store/bmc/bmc.go new file mode 100644 index 0000000..c441513 --- /dev/null +++ b/internal/store/bmc/bmc.go @@ -0,0 +1,248 @@ +package bmc + +import ( + "context" + "crypto/tls" + "net" + "net/http" + "net/http/cookiejar" + "path" + "runtime" + "strings" + "time" + + "github.com/bmc-toolbox/bmclib/v2" + "github.com/bmc-toolbox/bmclib/v2/constants" + "github.com/bmc-toolbox/bmclib/v2/providers" + logrusrv2 "github.com/bombsimon/logrusr/v2" + "github.com/metal-toolbox/bioscfg/internal/model" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" + "go.opentelemetry.io/otel" + "golang.org/x/net/publicsuffix" +) + +const ( + logoutTimeout = 1 * time.Minute + loginTimeout = 1 * time.Minute +) + +var ( + errBMCLogin = errors.New("bmc login error") + errBMCLogout = errors.New("bmc logout error") + errBMCNotImplemented = errors.New("method not implemented") +) + +// Bmc is an implementation of the Queryor interface +type Client struct { + client *bmclib.Client + asset *model.Asset + logger *logrus.Entry +} + +// NewBMCClient creates a new Queryor interface for a BMC +func NewBMCClient(asset *model.Asset, logger *logrus.Entry) *Client { + client := newBmclibClient(asset, logger) + + return &Client{ + client, + asset, + logger, + } +} + +// Open creates a BMC session +func (b *Client) Open(ctx context.Context) error { + if b.client == nil { + return errors.Wrap(errBMCLogin, "client not initialized") + } + defer b.tracelog() + + return b.client.Open(ctx) +} + +// Close logs out of the BMC +func (b *Client) Close(traceCtx context.Context) error { + if b.client == nil { + return nil + } + + ctxClose, cancel := context.WithTimeout(traceCtx, logoutTimeout) + defer cancel() + + defer b.tracelog() + + if err := b.client.Close(ctxClose); err != nil { + return errors.Wrap(errBMCLogout, err.Error()) + } + + return nil +} + +// GetPowerState returns the device power status +func (b *Client) GetPowerState(ctx context.Context) (string, error) { + defer b.tracelog() + return b.client.GetPowerState(ctx) +} + +// SetPowerState sets the given power state on the device +func (b *Client) SetPowerState(ctx context.Context, state string) error { + defer b.tracelog() + _, err := b.client.SetPowerState(ctx, state) + return err +} + +// SetBootDevice sets the boot device of the remote device, and validates it was set +// +//nolint:gocritic // its a TODO +func (b *Client) SetBootDevice(ctx context.Context, device string, persistent, efiBoot bool) error { + ok, err := b.client.SetBootDevice(ctx, device, persistent, efiBoot) + if err != nil { + return err + } + + if !ok { + return errors.New("setting boot device failed") + } + + // Now lets validate the boot device order + // TODO; This is a WIP. We do not know yet if This is the right bmc call to get boot device + // override, err := b.client.GetBootDeviceOverride(ctx) + // if err != nil { + // return err + // } + + // if device != string(override.Device) { + // return errors.New("setting boot device failed to propagate") + // } + + // if efiBoot != override.IsEFIBoot { + // return errors.New("setting boot device EFI boot failed to propagate") + // } + + // if persistent != override.IsPersistent { + // return errors.New("setting boot device Persistent boot failed to propagate") + // } + + return nil +} + +// GetBootDevice gets the boot device information of the remote device +func (b *Client) GetBootDevice(_ context.Context) (device string, persistent, efiBoot bool, err error) { + return "", false, false, errors.Wrap(errBMCNotImplemented, "GetBootDevice") +} + +// PowerCycleBMC sets a power cycle action on the BMC of the remote device +func (b *Client) PowerCycleBMC(ctx context.Context) error { + defer b.tracelog() + _, err := b.client.ResetBMC(ctx, "GracefulRestart") + return err +} + +func (b *Client) HostBooted(ctx context.Context) (bool, error) { + defer b.tracelog() + status, _, err := b.client.PostCode(ctx) + if err != nil { + return false, err + } + return status == constants.POSTStateOS, nil +} + +func (b *Client) ResetBios(ctx context.Context) error { + defer b.tracelog() + return b.client.ResetBiosConfiguration(ctx) +} + +func (b *Client) tracelog() { + pc, _, _, _ := runtime.Caller(1) + funcName := path.Base(runtime.FuncForPC(pc).Name()) + + mapstr := func(m map[string]string) string { + if m == nil { + return "" + } + + var s []string + for k, v := range m { + s = append(s, k+": "+v) + } + + return strings.Join(s, ", ") + } + + b.logger.WithFields( + logrus.Fields{ + "attemptedProviders": strings.Join(b.client.GetMetadata().ProvidersAttempted, ","), + "successfulProvider": b.client.GetMetadata().SuccessfulProvider, + "successfulOpens": strings.Join(b.client.GetMetadata().SuccessfulOpenConns, ","), + "successfulCloses": strings.Join(b.client.GetMetadata().SuccessfulCloseConns, ","), + "failedProviderDetail": mapstr(b.client.GetMetadata().FailedProviderDetail), + }).Trace(funcName + ": connection metadata") +} + +func newHTTPClient() *http.Client { + jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List}) + if err != nil { + panic(err) + } + + // nolint:gomnd // time duration declarations are clear as is. + return &http.Client{ + Timeout: time.Second * 600, + Jar: jar, + Transport: &http.Transport{ + // nolint:gosec // BMCs don't have valid certs. + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + DisableKeepAlives: true, + Dial: (&net.Dialer{ + Timeout: 180 * time.Second, + KeepAlive: 180 * time.Second, + }).Dial, + TLSHandshakeTimeout: 180 * time.Second, + ResponseHeaderTimeout: 600 * time.Second, + IdleConnTimeout: 180 * time.Second, + }, + } +} + +// newBmclibClient initializes a bmclib client with the given credentials +func newBmclibClient(asset *model.Asset, l *logrus.Entry) *bmclib.Client { + logger := logrus.New() + logger.Formatter = l.Logger.Formatter + + // setup a logr logger for bmclib + // bmclib uses logr, for which the trace logs are logged with log.V(3), + // this is a hax so the logrusr lib will enable trace logging + // since any value that is less than (logrus.LogLevel - 4) >= log.V(3) is ignored + // https://github.com/bombsimon/logrusr/blob/master/logrusr.go#L64 + switch l.Logger.GetLevel() { + case logrus.TraceLevel: + logger.Level = 7 + case logrus.DebugLevel: + logger.Level = 5 + } + + logruslogr := logrusrv2.New(logger) + + bmcClient := bmclib.NewClient( + asset.BmcAddress.String(), + asset.BmcUsername, + asset.BmcPassword, + bmclib.WithLogger(logruslogr), + bmclib.WithHTTPClient(newHTTPClient()), + bmclib.WithPerProviderTimeout(loginTimeout), + bmclib.WithRedfishEtagMatchDisabled(true), + bmclib.WithTracerProvider(otel.GetTracerProvider()), + ) + + bmcClient.Registry.Drivers = bmcClient.Registry.Supports( + providers.FeatureBmcReset, + providers.FeatureBootDeviceSet, + providers.FeaturePowerSet, + providers.FeaturePowerState, + ) + + // NOTE: remove the .Using("redfish") before this ends up in prod + // this is kept here since ipmitool doesn't work well in the docker sandbox env. + return bmcClient.Using("redfish") +} diff --git a/internal/store/bmc/dryRun.go b/internal/store/bmc/dryRun.go new file mode 100644 index 0000000..d4d27db --- /dev/null +++ b/internal/store/bmc/dryRun.go @@ -0,0 +1,184 @@ +package bmc + +import ( + "context" + "errors" + "time" + + "github.com/metal-toolbox/bioscfg/internal/model" +) + +type server struct { + powerStatus string + bootTime time.Time + bootDevice string + previousBootDevice string + persistent bool + efiBoot bool +} + +var ( + errBmcCantFindServer = errors.New("dryrun BMC couldnt find server to set state") + errBmcServerOffline = errors.New("dryrun BMC couldnt set boot device, server is off") + serverStates = make(map[string]server) +) + +// DryRunBMC is an simulated implementation of the Queryor interface +type DryRunBMCClient struct { + id string +} + +// NewDryRunBMCClient creates a new Queryor interface for a simulated BMC +func NewDryRunBMCClient(asset *model.Asset) *DryRunBMCClient { + _, ok := serverStates[asset.ID.String()] + if !ok { + serverStates[asset.ID.String()] = getDefaultSettings() + } + + return &DryRunBMCClient{ + asset.ID.String(), + } +} + +// Open simulates creating a BMC session +func (b *DryRunBMCClient) Open(_ context.Context) error { + return nil +} + +// Close simulates logging out of the BMC +func (b *DryRunBMCClient) Close(_ context.Context) error { + return nil +} + +// GetPowerState simulates returning the device power status +func (b *DryRunBMCClient) GetPowerState(_ context.Context) (string, error) { + server, err := b.getServer() + if err != nil { + return "", err + } + + return server.powerStatus, nil +} + +// SetPowerState simulates setting the given power state on the device +func (b *DryRunBMCClient) SetPowerState(_ context.Context, state string) error { + server, err := b.getServer() + if err != nil { + return err + } + + if isRestarting(state) { + server.bootTime = getRestartTime(state) + } + + server.powerStatus = state + serverStates[b.id] = *server + return nil +} + +// SetBootDevice simulates setting the boot device of the remote device +func (b *DryRunBMCClient) SetBootDevice(_ context.Context, device string, persistent, efiBoot bool) error { + server, err := b.getServer() + if err != nil { + return err + } + + if server.powerStatus != "on" { + return errBmcServerOffline + } + + server.previousBootDevice = server.bootDevice + server.bootDevice = device + server.persistent = persistent + server.efiBoot = efiBoot + + return nil +} + +// GetBootDevice simulates getting the boot device information of the remote device +func (b *DryRunBMCClient) GetBootDevice(_ context.Context) (device string, persistent, efiBoot bool, err error) { + server, err := b.getServer() + if err != nil { + return "", false, false, err + } + + if server.powerStatus != "on" { + return "", false, false, errBmcServerOffline + } + + return server.bootDevice, server.persistent, server.efiBoot, nil +} + +// PowerCycleBMC simulates a power cycle action on the BMC of the remote device +func (b *DryRunBMCClient) PowerCycleBMC(_ context.Context) error { + return nil +} + +// HostBooted reports whether or not the device has booted the host OS +func (b *DryRunBMCClient) HostBooted(_ context.Context) (bool, error) { + return true, nil +} + +func (b *DryRunBMCClient) ResetBios(ctx context.Context) error { + _, ok := serverStates[b.id] + if !ok { + return errBmcCantFindServer + } + + serverStates[b.id] = getDefaultSettings() + + return b.SetPowerState(ctx, "cycle") +} + +// getServer gets a simulateed server state, and update power status and boot device if required +func (b *DryRunBMCClient) getServer() (*server, error) { + server, ok := serverStates[b.id] + if !ok { + return nil, errBmcCantFindServer + } + + if isRestarting(server.powerStatus) { + if time.Now().After(server.bootTime) { + server.powerStatus = "on" + + if !server.persistent { + server.bootDevice = server.previousBootDevice + } + } + } + + return &server, nil +} + +func isRestarting(state string) bool { + switch state { + case "reset", "cycle": + return true + default: + return false + } +} + +func getRestartTime(state string) time.Time { + switch state { + case "reset": + return time.Now().Add(time.Second * 30) // Soft reboot should take longer than a hard reboot + case "cycle": + return time.Now().Add(time.Second * 20) + default: + return time.Now() // No reboot necessary + } +} + +func getDefaultSettings() server { + server := server{} + + server.powerStatus = "on" + server.bootDevice = "disk" + server.previousBootDevice = "disk" + server.persistent = true + server.efiBoot = false + server.bootTime = time.Now() + + return server +} diff --git a/internal/store/bmc/interface.go b/internal/store/bmc/interface.go new file mode 100644 index 0000000..20f3953 --- /dev/null +++ b/internal/store/bmc/interface.go @@ -0,0 +1,18 @@ +package bmc + +import ( + "context" +) + +// Queryor interface abstracts calls to remote devices +type BMC interface { + Open(ctx context.Context) error + Close(ctx context.Context) error + GetPowerState(ctx context.Context) (state string, err error) + SetPowerState(ctx context.Context, state string) error + SetBootDevice(ctx context.Context, device string, persistent, efiBoot bool) error + GetBootDevice(ctx context.Context) (device string, persistent, efiBoot bool, err error) + PowerCycleBMC(ctx context.Context) error + HostBooted(ctx context.Context) (bool, error) + ResetBios(ctx context.Context) error +} diff --git a/internal/store/fleetdb/client.go b/internal/store/fleetdb/client.go index 0a11d30..3e15ffd 100644 --- a/internal/store/fleetdb/client.go +++ b/internal/store/fleetdb/client.go @@ -3,58 +3,53 @@ package fleetdb import ( "context" "io" - "log/slog" "net/http" "net/url" "time" "github.com/coreos/go-oidc" "github.com/hashicorp/go-retryablehttp" - "github.com/metal-toolbox/bioscfg/internal/configuration" - fleetdbapi "github.com/metal-toolbox/fleetdb/pkg/api/v1" - "github.com/pkg/errors" + "github.com/sirupsen/logrus" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "golang.org/x/oauth2/clientcredentials" + + fleetdbapi "github.com/metal-toolbox/fleetdb/pkg/api/v1" ) var ( // timeout for requests made by this client. - timeout = 30 * time.Second - ErrConfig = errors.New("error in fleetdb client configuration") + timeout = 30 * time.Second ) // NewFleetDBClient instantiates and returns a serverService client -func NewFleetDBClient(ctx context.Context, cfg *configuration.FleetDBOptions) (*fleetdbapi.Client, error) { - if cfg == nil { - return nil, errors.Wrap(ErrConfig, "configuration is nil") +func NewFleetDBClient(ctx context.Context, cfg *Config, logger *logrus.Logger) (*fleetdbapi.Client, error) { + err := cfg.validate() + if err != nil { + return nil, err } - if cfg.DisableOAuth { - return newFleetDBClientWithOtel(cfg, cfg.Endpoint) + if cfg.Authenticate { + return newFleetDBClientWithOAuthOtel(ctx, cfg, logger) } - return newFleetDBClientWithOAuthOtel(ctx, cfg, cfg.Endpoint) + return newFleetDBClientWithOtel(cfg, logger) } // returns a fleetdb retryable client with Otel -func newFleetDBClientWithOtel(cfg *configuration.FleetDBOptions, endpoint string) (*fleetdbapi.Client, error) { - if cfg == nil { - return nil, errors.Wrap(ErrConfig, "configuration is nil") - } - +func newFleetDBClientWithOtel(cfg *Config, logger *logrus.Logger) (*fleetdbapi.Client, error) { // init retryable http client retryableClient := retryablehttp.NewClient() - // log hook fo 500 errors since the retryablehttp client masks them - logHookFunc := func(l retryablehttp.Logger, r *http.Response) { + // log hook fo 500 errors since the the retryablehttp client masks them + logHookFunc := func(_ retryablehttp.Logger, r *http.Response) { if r.StatusCode == http.StatusInternalServerError { b, err := io.ReadAll(r.Body) if err != nil { - slog.Warn("fleetdb query returned 500 status code; error reading body", "error", err) + logger.Warn("fleetdb query returned 500 error, got error reading body: ", err.Error()) return } - slog.Warn("fleetdb query returned 500 status code", "body", string(b)) + logger.Warn("fleetdb query returned 500 error, body: ", string(b)) } } @@ -69,18 +64,14 @@ func newFleetDBClientWithOtel(cfg *configuration.FleetDBOptions, endpoint string return fleetdbapi.NewClientWithToken( "dummy", - endpoint, + cfg.URL, client, ) } // returns a fleetdb retryable http client with Otel and Oauth wrapped in -func newFleetDBClientWithOAuthOtel(ctx context.Context, cfg *configuration.FleetDBOptions, endpoint string) (*fleetdbapi.Client, error) { - if cfg == nil { - return nil, errors.Wrap(ErrConfig, "configuration is nil") - } - - slog.Info("fleetdb client ctor") +func newFleetDBClientWithOAuthOtel(ctx context.Context, cfg *Config, logger *logrus.Logger) (*fleetdbapi.Client, error) { + logger.Info("fleetdb client ctor") // init retryable http client retryableClient := retryablehttp.NewClient() @@ -89,13 +80,13 @@ func newFleetDBClientWithOAuthOtel(ctx context.Context, cfg *configuration.Fleet retryableClient.HTTPClient = otelhttp.DefaultClient // setup oidc provider - provider, err := oidc.NewProvider(ctx, cfg.OidcIssuerEndpoint) + provider, err := oidc.NewProvider(ctx, cfg.OidcIssuerURL) if err != nil { return nil, err } - // clientID defaults to 'bioscfg' - clientID := "bioscfg" + // clientID defaults to 'flipflop' + clientID := "flipflop" if cfg.OidcClientID != "" { clientID = cfg.OidcClientID @@ -107,7 +98,7 @@ func newFleetDBClientWithOAuthOtel(ctx context.Context, cfg *configuration.Fleet ClientSecret: cfg.OidcClientSecret, TokenURL: provider.Endpoint().TokenURL, Scopes: cfg.OidcClientScopes, - EndpointParams: url.Values{"audience": []string{cfg.OidcAudienceEndpoint}}, + EndpointParams: url.Values{"audience": []string{cfg.OidcAudienceURL}}, } // wrap OAuth transport, cookie jar in the retryable client @@ -122,7 +113,7 @@ func newFleetDBClientWithOAuthOtel(ctx context.Context, cfg *configuration.Fleet return fleetdbapi.NewClientWithToken( cfg.OidcClientSecret, - endpoint, + cfg.URL, client, ) } diff --git a/internal/store/fleetdb/config.go b/internal/store/fleetdb/config.go new file mode 100644 index 0000000..d45e640 --- /dev/null +++ b/internal/store/fleetdb/config.go @@ -0,0 +1,56 @@ +package fleetdb + +import ( + "net/url" + + "github.com/pkg/errors" +) + +// FleetDBConfig defines configuration for the Serverservice client. +// https://github.com/metal-toolbox/fleetdb +type Config struct { + URL string `mapstructure:"url"` + OidcIssuerURL string `mapstructure:"oidc_issuer_url"` + OidcAudienceURL string `mapstructure:"oidc_audience_url"` + OidcClientSecret string `mapstructure:"oidc_client_secret"` + OidcClientID string `mapstructure:"oidc_client_id"` + OidcClientScopes []string `mapstructure:"oidc_client_scopes"` + Authenticate bool `mapstructure:"authenticate"` +} + +func (cfg *Config) validate() error { + if cfg == nil { + return errors.Wrap(ErrFleetDBConfig, "config was nil") + } + + if cfg.URL == "" { + return errors.Wrap(ErrFleetDBConfig, "url was empty") + } + + _, err := url.Parse(cfg.URL) + if err != nil { + return errors.Wrap(ErrFleetDBConfig, "url failed to parse, isnt a valid url") + } + + if !cfg.Authenticate { + return nil + } + + if cfg.OidcIssuerURL == "" { + return errors.Wrap(ErrFleetDBConfig, "oidc issuer url was empty") + } + + if cfg.OidcClientSecret == "" { + return errors.Wrap(ErrFleetDBConfig, "oidc secret was empty") + } + + if cfg.OidcClientID == "" { + return errors.Wrap(ErrFleetDBConfig, "oidc client id was empty") + } + + if len(cfg.OidcClientScopes) == 0 { + return errors.Wrap(ErrFleetDBConfig, "oidc scopes was empty") + } + + return nil +} diff --git a/internal/store/fleetdb/errors.go b/internal/store/fleetdb/errors.go new file mode 100644 index 0000000..016031b --- /dev/null +++ b/internal/store/fleetdb/errors.go @@ -0,0 +1,15 @@ +package fleetdb + +import "github.com/pkg/errors" + +var ( + ErrSlugs = errors.New("slugs error") + ErrServerServiceRegisterChanges = errors.New("error in server service API register changes") + ErrAssetObject = errors.New("asset object error") + ErrAssetObjectConversion = errors.New("error converting asset object") + ErrFleetDBObject = errors.New("serverService object error") + ErrChangeList = errors.New("error building change list") + ErrServerServiceAttrObject = errors.New("error in server service attribute object") + ErrFleetDBConfig = errors.New("fleetdb configuration error") + ErrInventoryQuery = errors.New("fleetdb query returned error") +) diff --git a/internal/store/fleetdb/fleetdb.go b/internal/store/fleetdb/fleetdb.go index 97d75f7..2ff86dc 100644 --- a/internal/store/fleetdb/fleetdb.go +++ b/internal/store/fleetdb/fleetdb.go @@ -3,43 +3,40 @@ package fleetdb import ( "context" "encoding/json" - "log/slog" "net" "github.com/google/uuid" - "github.com/metal-toolbox/bioscfg/internal/configuration" "github.com/metal-toolbox/bioscfg/internal/model" - fleetdbapi "github.com/metal-toolbox/fleetdb/pkg/api/v1" "github.com/metal-toolbox/rivets/fleetdb" "github.com/pkg/errors" + "github.com/sirupsen/logrus" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/codes" + + fleetdbapi "github.com/metal-toolbox/fleetdb/pkg/api/v1" ) const ( pkgName = "internal/store" ) -var ( - ErrInventoryQuery = errors.New("fleetdb query returned error") - ErrFleetDBObject = errors.New("fleetdb object error") -) - // Store is an asset inventory store type Store struct { api *fleetdbapi.Client - config *configuration.FleetDBOptions + logger *logrus.Logger + config *Config } // New returns a fleetdb store queryor to lookup and publish assets to, from the store. -func New(ctx context.Context, cfg *configuration.FleetDBOptions) (*Store, error) { - apiclient, err := NewFleetDBClient(ctx, cfg) +func New(ctx context.Context, cfg *Config, logger *logrus.Logger) (*Store, error) { + apiclient, err := NewFleetDBClient(ctx, cfg, logger) if err != nil { return nil, err } s := &Store{ api: apiclient, + logger: logger, config: cfg, } @@ -79,8 +76,7 @@ func toAsset(server *fleetdbapi.Server, credential *fleetdbapi.ServerCredential) serverAttributes, err := serverAttributes(server.Attributes) if err != nil { - slog.Error("error getting server attributes", "error", err) - return nil, errors.Wrap(ErrFleetDBObject, err.Error()) + return nil, errors.Wrap(err, "error getting server attributes") } asset := &model.Asset{ diff --git a/internal/store/fleetdb/fleetdb_test.go b/internal/store/fleetdb/fleetdb_test.go index 9bc76f5..a2243e9 100644 --- a/internal/store/fleetdb/fleetdb_test.go +++ b/internal/store/fleetdb/fleetdb_test.go @@ -2,6 +2,7 @@ package fleetdb import ( "net" + "testing" "github.com/google/uuid" diff --git a/internal/store/store.go b/internal/store/store.go deleted file mode 100644 index 36f2a2b..0000000 --- a/internal/store/store.go +++ /dev/null @@ -1,19 +0,0 @@ -package store - -import ( - "context" - - "github.com/google/uuid" - "github.com/metal-toolbox/bioscfg/internal/configuration" - "github.com/metal-toolbox/bioscfg/internal/model" - "github.com/metal-toolbox/bioscfg/internal/store/fleetdb" -) - -type Repository interface { - // AssetByID returns asset based on the identifier. - AssetByID(ctx context.Context, assetID uuid.UUID) (*model.Asset, error) -} - -func NewRepository(ctx context.Context, config *configuration.Configuration) (Repository, error) { - return fleetdb.New(ctx, config.FleetDBOptions) -} diff --git a/internal/tasks/steps.go b/internal/tasks/steps.go deleted file mode 100644 index 5763d41..0000000 --- a/internal/tasks/steps.go +++ /dev/null @@ -1,140 +0,0 @@ -package tasks - -import ( - "context" - "log/slog" - - "github.com/bmc-toolbox/bmclib/v2" - "github.com/metal-toolbox/bioscfg/internal/model" - rctypes "github.com/metal-toolbox/rivets/condition" - "github.com/pkg/errors" -) - -// StepStatus has status about a step, to be reported as part of the overall task. -type StepStatus struct { - Step string `json:"step"` - Status string `json:"status"` - Details string `json:"details,omitempty"` - Error string `json:"error,omitempty"` -} - -// NewStepStatus will create a new step status struct -func NewStepStatus(stepName string, state rctypes.State, details string, err error) *StepStatus { - status := &StepStatus{ - Step: stepName, - Status: string(state), - Details: details, - } - - if err != nil { - status.Error = err.Error() - } - - return status -} - -func (s *StepStatus) AsLogFields() []any { - return []any{ - "task", s.Step, - "status", s.Status, - "details", s.Details, - "error", s.Error, - } -} - -// Step is a unit of work. Multiple steps accomplish a task. -type Step interface { - // Name of this step - Name() string - // Run will execute the code to accomplish this step - Run(ctx context.Context, client *bmclib.Client, data sharedData) (string, error) -} - -type getServerPowerStateStep struct { - name string -} - -// GetServerPowerStateStep will get the current power state of a server, -// and store it in sharedData. -func GetServerPowerStateStep() Step { - return &getServerPowerStateStep{ - name: "GetServerPowerState", - } -} - -func (t *getServerPowerStateStep) Name() string { - return t.name -} - -func (t *getServerPowerStateStep) Run(ctx context.Context, client *bmclib.Client, data sharedData) (string, error) { - state, err := client.GetPowerState(ctx) - if err != nil { - return "Failed to get current power state", err - } - - data[currentPowerStateKey] = state - - return "Current power state: " + state, nil -} - -type biosResetStep struct { - name string -} - -// BiosResetStep will use the client to reset the BIOS settings. -func BiosResetStep() Step { - return &biosResetStep{ - name: "BiosReset", - } -} - -func (t *biosResetStep) Name() string { - return t.name -} - -func (t *biosResetStep) Run(ctx context.Context, client *bmclib.Client, _ sharedData) (string, error) { - err := client.ResetBiosConfiguration(ctx) - if err != nil { - return "Failed to reset bios settings", err - } - - return "BIOS settings reset", nil -} - -type serverRebootStep struct { - name string -} - -// ServerRebootStep will reboot the server, if necessary, per the information in sharedData -func ServerRebootStep() Step { - return &serverRebootStep{ - name: "ServerReboot", - } -} - -func (t *serverRebootStep) Name() string { - return t.name -} - -func (t *serverRebootStep) Run(ctx context.Context, client *bmclib.Client, data sharedData) (string, error) { - powerState, ok := data[currentPowerStateKey].(string) - if !ok { - return "Reboot requirement unknown", errors.New("missing power state") - } - - var details string - - if powerState == model.PowerStateOn { - slog.Info("Rebooting server", "powerState", powerState) - _, err := client.SetPowerState(ctx, model.PowerStateReset) - if err != nil { - return "Failed to reset power state", err - } - details = "Rebooting server" - } else { - slog.Info("Skipping server reboot", "ok", ok, "powerState", powerState) - details = "Reboot not required" - } - - return details, nil -} diff --git a/internal/tasks/tasks.go b/internal/tasks/tasks.go deleted file mode 100644 index d2f1680..0000000 --- a/internal/tasks/tasks.go +++ /dev/null @@ -1,226 +0,0 @@ -package tasks - -import ( - "context" - "encoding/json" - "log/slog" - "runtime/debug" - - "github.com/bmc-toolbox/bmclib/v2" - "github.com/metal-toolbox/bioscfg/internal/model" - rctypes "github.com/metal-toolbox/rivets/condition" - "github.com/metal-toolbox/rivets/events/controller" - "github.com/pkg/errors" -) - -var ( - currentPowerStateKey = "currentPowerState" -) - -// Miscellaneous -type sharedData map[string]interface{} - -// TaskStatus has status about a task, and it's steps. -type TaskStatus struct { - Task string `json:"task"` - Status string `json:"status"` - Details string `json:"details,omitempty"` - Error string `json:"error,omitempty"` - ActiveStep string `json:"active_step,omitempty"` - Steps []*StepStatus `json:"steps"` -} - -// NewTaskStatus will generate a new task status struct -func NewTaskStatus(taskName string, state rctypes.State) *TaskStatus { - return &TaskStatus{ - Task: taskName, - Status: string(state), - } -} - -func (r *TaskStatus) AsLogFields() []string { - return []string{ - "task", r.Task, - "status", r.Status, - "details", r.Details, - "error", r.Error, - } -} - -func (r *TaskStatus) Marshal() ([]byte, error) { - respBytes, err := json.Marshal(r) - if err != nil { - return nil, errors.Wrap(err, "failed to marshal response to json") - } - - return respBytes, nil -} - -// Task is a unit of work to address a condition from condition orchestrator. -// The task multiple steps to accomplish the task. -type Task interface { - // Name of the task - Name() string - // Asset is the server that will be affected by this task - Asset() *model.Asset - // Steps is the multiple units of work that will accomplish this task - Steps() []Step -} - -type biosResetTask struct { - name string - asset *model.Asset - steps []Step -} - -// NewBiosResetTask creates the task for resetting the BIOS of a server to default settings. -func NewBiosResetTask(asset *model.Asset) Task { - return &biosResetTask{ - name: "BiosResetSettings", - asset: asset, - steps: []Step{ - GetServerPowerStateStep(), - BiosResetStep(), - ServerRebootStep(), - }, - } -} - -func (j *biosResetTask) Name() string { - return j.name -} - -func (j *biosResetTask) Steps() []Step { - return j.steps -} - -func (j *biosResetTask) Asset() *model.Asset { - return j.asset -} - -// TaskRunner Will run the task by executing the individual steps in the task, -// and reports task status using the publisher. -type TaskRunner struct { - publisher controller.ConditionStatusPublisher - task Task - taskStatus *TaskStatus -} - -// NewTaskRunner creates a TaskRunner to run a specific Task -func NewTaskRunner(publisher controller.ConditionStatusPublisher, task Task) *TaskRunner { - return &TaskRunner{ - publisher: publisher, - task: task, - taskStatus: NewTaskStatus(task.Name(), rctypes.Pending), - } -} - -func (r *TaskRunner) Run(ctx context.Context, client *bmclib.Client) (err error) { - slog.With(r.task.Asset().AsLogFields()...).Info("Running task", "task", r.task.Name()) - - data := sharedData{} - r.initTaskLog() - - defer func() { - if rec := recover(); rec != nil { - err = r.handlePanic(ctx, rec) - } - }() - - r.publishTaskUpdate(ctx, rctypes.Active, "Opening client", nil) - - if err = client.Open(ctx); err != nil { - r.publishFailed(ctx, 0, "Failed to open client", err) - return errors.Wrap(err, "failed to open client") - } - defer client.Close(ctx) - - for stepID, step := range r.task.Steps() { - r.publishStepUpdate(ctx, stepID, "Running step") - - details, err := step.Run(ctx, client, data) - if err != nil { - r.publishFailed(ctx, stepID, "Step failure", err) - return err - } - - r.publishStepSuccess(ctx, stepID, details) - } - - r.publishTaskSuccess(ctx) - - return nil -} - -func (r *TaskRunner) initTaskLog() { - steps := r.task.Steps() - r.taskStatus.Steps = make([]*StepStatus, len(steps)) - - for i, step := range steps { - r.taskStatus.Steps[i] = NewStepStatus(step.Name(), rctypes.Pending, "", nil) - } -} - -func (r *TaskRunner) handlePanic(ctx context.Context, rec any) error { - msg := "Panic occurred while running task" - slog.Error("!!panic occurred", "rec", rec, "stack", string(debug.Stack())) - slog.Error(msg) - err := errors.New("Task fatal error, check logs for details") - - r.publishTaskUpdate(ctx, rctypes.Failed, msg, err) - - return err -} - -func (r *TaskRunner) publishStepUpdate(ctx context.Context, stepID int, details string) { - r.publish(ctx, stepID, rctypes.Active, rctypes.Active, details, nil) -} - -func (r *TaskRunner) publishStepSuccess(ctx context.Context, stepID int, details string) { - r.publish(ctx, stepID, rctypes.Succeeded, rctypes.Active, details, nil) -} - -func (r *TaskRunner) publishFailed(ctx context.Context, stepID int, details string, err error) { - slog.With(r.task.Asset().AsLogFields()...).Error("Task failed", "task", r.task.Name()) - r.publish(ctx, stepID, rctypes.Failed, rctypes.Failed, details, err) -} - -func (r *TaskRunner) publishTaskSuccess(ctx context.Context) { - slog.With(r.task.Asset().AsLogFields()...).Info("Task completed successfully", "task", r.task.Name()) - r.publishTaskUpdate(ctx, rctypes.Succeeded, "Task completed successfully", nil) -} - -func (r *TaskRunner) publish(ctx context.Context, stepID int, stepState, taskState rctypes.State, details string, err error) { - step := r.task.Steps()[stepID] - stepStatus := NewStepStatus(step.Name(), stepState, details, err) - - slog.With(r.task.Asset().AsLogFields()...).With(stepStatus.AsLogFields()...).Info(details, "step", step.Name()) - - r.taskStatus.Steps[stepID] = stepStatus - - var taskDetails string - if err != nil { - taskDetails = "Task failed at step " + step.Name() - } - - r.publishTaskUpdate(ctx, taskState, taskDetails, err) -} - -func (r *TaskRunner) publishTaskUpdate(ctx context.Context, state rctypes.State, details string, err error) { - r.taskStatus.Status = string(state) - r.taskStatus.Details = details - - if err != nil { - r.taskStatus.Error = err.Error() - } - - slog.With(r.task.Asset().AsLogFields()...).Info("Task update", "task", r.task.Name()) - - respBytes, err := json.Marshal(r.taskStatus) - if err != nil { - slog.Error("Failed to marshal condition update", "error", err) - return - } - - r.publisher.Publish(ctx, r.task.Asset().ID.String(), state, respBytes) -} diff --git a/internal/tasks/tasks_test.go b/internal/tasks/tasks_test.go deleted file mode 100644 index 4ce68d3..0000000 --- a/internal/tasks/tasks_test.go +++ /dev/null @@ -1,64 +0,0 @@ -package tasks - -import ( - "context" - "encoding/json" - "testing" - - "github.com/bmc-toolbox/bmclib/v2" - "github.com/metal-toolbox/bioscfg/internal/model" - "github.com/metal-toolbox/rivets/condition" - "github.com/stretchr/testify/assert" -) - -type fakeStep struct{} - -func (s *fakeStep) Name() string { - return "fake step" -} - -func (s *fakeStep) Run(_ context.Context, _ *bmclib.Client, _ sharedData) (string, error) { - return "", nil -} - -type fakeTask struct { - asset *model.Asset - steps []Step -} - -func newFakeTask() *fakeTask { - return &fakeTask{ - asset: &model.Asset{}, - steps: []Step{&fakeStep{}}, - } -} - -func (t *fakeTask) Name() string { - return "fake task" -} - -func (t *fakeTask) Asset() *model.Asset { - return t.asset -} - -func (t *fakeTask) Steps() []Step { - return t.steps -} - -type fakePublisher struct { - t *testing.T -} - -func (m *fakePublisher) Publish(_ context.Context, _ string, _ condition.State, _ json.RawMessage) { -} - -func TestTaskRunnerHandlePanic(t *testing.T) { - task := newFakeTask() - runner := NewTaskRunner(&fakePublisher{t: t}, task) - - err := runner.Run(context.Background(), nil) - - if assert.NotNil(t, err) { - assert.Equal(t, "Task fatal error, check logs for details", err.Error()) - } -} diff --git a/internal/version/version.go b/internal/version/version.go index b5100d5..361d561 100644 --- a/internal/version/version.go +++ b/internal/version/version.go @@ -1,6 +1,7 @@ package version import ( + "encoding/json" "runtime" rdebug "runtime/debug" "strings" @@ -49,6 +50,22 @@ func Current() *Version { } } +func (v *Version) AsMap() (map[string]any, error) { + var asMap map[string]interface{} + + bytes, err := json.Marshal(v) + if err != nil { + return nil, err + } + + err = json.Unmarshal(bytes, &asMap) + if err != nil { + return nil, err + } + + return asMap, nil +} + func ExportBuildInfoMetric() { buildInfo := promauto.NewGaugeVec( prometheus.GaugeOpts{ diff --git a/main.go b/main.go index d899e73..30b0781 100644 --- a/main.go +++ b/main.go @@ -17,10 +17,8 @@ package main import ( "github.com/metal-toolbox/bioscfg/cmd" - "github.com/metal-toolbox/bioscfg/internal/log" ) func main() { - log.InitLogger() cmd.Execute() }