diff --git a/commands/install.go b/commands/install.go index 8404b565..4b57c412 100644 --- a/commands/install.go +++ b/commands/install.go @@ -66,6 +66,7 @@ func initInstallFlags(cmd *cobra.Command) { cmd.Flags().StringP("kubeconfig", "k", "~/.kube/config", "Path to a kubeconfig") cmd.Flags().String("namespaces", "", "Comma-separated namespaces list Percona Everest can manage") cmd.Flags().Bool("skip-wizard", false, "Skip installation wizard") + cmd.Flags().String("version-metadata-url", "https://check.percona.com", "URL to retrieve version metadata information from") cmd.Flags().Bool("operator.mongodb", true, "Install MongoDB operator") cmd.Flags().Bool("operator.postgresql", true, "Install PostgreSQL operator") @@ -75,9 +76,10 @@ func initInstallFlags(cmd *cobra.Command) { func initInstallViperFlags(cmd *cobra.Command) { viper.BindPFlag("skip-wizard", cmd.Flags().Lookup("skip-wizard")) //nolint:errcheck,gosec - viper.BindEnv("kubeconfig") //nolint:errcheck,gosec - viper.BindPFlag("kubeconfig", cmd.Flags().Lookup("kubeconfig")) //nolint:errcheck,gosec - viper.BindPFlag("namespaces", cmd.Flags().Lookup("namespaces")) //nolint:errcheck,gosec + viper.BindEnv("kubeconfig") //nolint:errcheck,gosec + viper.BindPFlag("kubeconfig", cmd.Flags().Lookup("kubeconfig")) //nolint:errcheck,gosec + viper.BindPFlag("namespaces", cmd.Flags().Lookup("namespaces")) //nolint:errcheck,gosec + viper.BindPFlag("version-metadata-url", cmd.Flags().Lookup("version-metadata-url")) //nolint:errcheck,gosec viper.BindPFlag("operator.mongodb", cmd.Flags().Lookup("operator.mongodb")) //nolint:errcheck,gosec viper.BindPFlag("operator.postgresql", cmd.Flags().Lookup("operator.postgresql")) //nolint:errcheck,gosec diff --git a/commands/upgrade.go b/commands/upgrade.go index 1864efc4..4aecfaf8 100644 --- a/commands/upgrade.go +++ b/commands/upgrade.go @@ -23,11 +23,11 @@ import ( "github.com/spf13/viper" "go.uber.org/zap" + everestClient "github.com/percona/percona-everest-cli/pkg/everest/client" "github.com/percona/percona-everest-cli/pkg/output" "github.com/percona/percona-everest-cli/pkg/upgrade" ) -// newUpgradeCmd returns a new operators command. func newUpgradeCmd(l *zap.SugaredLogger) *cobra.Command { cmd := &cobra.Command{ Use: "upgrade", @@ -40,12 +40,17 @@ func newUpgradeCmd(l *zap.SugaredLogger) *cobra.Command { Run: func(cmd *cobra.Command, args []string) { initUpgradeViperFlags(cmd) - c, err := parseConfig() + c, err := parseUpgradeConfig() if err != nil { os.Exit(1) } - op, err := upgrade.NewUpgrade(*c, l) + everestClConnector, err := everestClient.NewEverestFromURL(c.Everest.Endpoint, c.Everest.Token) + if err != nil { + l.Error(err) + os.Exit(1) + } + op, err := upgrade.NewUpgrade(c, everestClConnector, l) if err != nil { l.Error(err) os.Exit(1) @@ -64,22 +69,22 @@ func newUpgradeCmd(l *zap.SugaredLogger) *cobra.Command { } func initUpgradeFlags(cmd *cobra.Command) { + cmd.Flags().String("everest.endpoint", "http://127.0.0.1:8080", "Everest endpoint URL") + cmd.Flags().String("everest.token", "", "Everest token to authenticate against Everest") cmd.Flags().StringP("kubeconfig", "k", "~/.kube/config", "Path to a kubeconfig") - cmd.Flags().String("namespaces", "", "Comma-separated namespaces list Percona Everest can manage") - cmd.Flags().Bool("upgrade-olm", false, "Upgrade OLM distribution") - cmd.Flags().Bool("skip-wizard", false, "Skip installation wizard") + cmd.Flags().String("version-metadata-url", "https://check.percona.com", "URL to retrieve version metadata information from") } func initUpgradeViperFlags(cmd *cobra.Command) { - viper.BindEnv("kubeconfig") //nolint:errcheck,gosec - viper.BindPFlag("kubeconfig", cmd.Flags().Lookup("kubeconfig")) //nolint:errcheck,gosec - viper.BindPFlag("namespaces", cmd.Flags().Lookup("namespaces")) //nolint:errcheck,gosec - viper.BindPFlag("upgrade-olm", cmd.Flags().Lookup("upgrade-olm")) //nolint:errcheck,gosec - viper.BindPFlag("skip-wizard", cmd.Flags().Lookup("skip-wizard")) //nolint:errcheck,gosec + viper.BindPFlag("everest.endpoint", cmd.Flags().Lookup("everest.endpoint")) //nolint:errcheck,gosec + viper.BindPFlag("everest.token", cmd.Flags().Lookup("everest.token")) //nolint:errcheck,gosec + viper.BindEnv("kubeconfig") //nolint:errcheck,gosec + viper.BindPFlag("kubeconfig", cmd.Flags().Lookup("kubeconfig")) //nolint:errcheck,gosec + viper.BindPFlag("version-metadata-url", cmd.Flags().Lookup("version-metadata-url")) //nolint:errcheck,gosec } -func parseConfig() (*upgrade.Config, error) { - c := &upgrade.Config{} +func parseUpgradeConfig() (*upgrade.UpgradeConfig, error) { + c := &upgrade.UpgradeConfig{} err := viper.Unmarshal(c) return c, err } diff --git a/data/gen.go b/data/gen.go index f981f215..15da418d 100644 --- a/data/gen.go +++ b/data/gen.go @@ -22,6 +22,3 @@ import "embed" // //go:embed crds/* var OLMCRDs embed.FS - -// OLMVersion indicates the OLM version shipped with the CLI. -const OLMVersion = "0.25.0" diff --git a/go.mod b/go.mod index 7fe0fe11..3e4614b0 100644 --- a/go.mod +++ b/go.mod @@ -2,14 +2,18 @@ module github.com/percona/percona-everest-cli go 1.21 +replace github.com/Percona-Lab/percona-version-service => ../percona-version-service + require ( github.com/AlecAivazis/survey/v2 v2.3.7 + github.com/Percona-Lab/percona-version-service v0.0.0-20230404081016-ea25e30cdcbc github.com/dchest/uniuri v1.2.0 github.com/go-logr/zapr v1.3.0 github.com/hashicorp/go-version v1.6.0 github.com/operator-framework/api v0.22.0 github.com/operator-framework/operator-lifecycle-manager v0.26.0 github.com/percona/everest-operator v0.6.0-dev1.0.20240220114053-fae6111d9818 + github.com/percona/percona-everest-backend v0.7.0 github.com/spf13/cobra v1.8.0 github.com/spf13/viper v1.18.2 github.com/stretchr/testify v1.8.4 @@ -17,7 +21,6 @@ require ( golang.org/x/crypto v0.19.0 golang.org/x/sync v0.6.0 gopkg.in/yaml.v3 v3.0.1 - gotest.tools v2.2.0+incompatible k8s.io/api v0.29.1 k8s.io/apiextensions-apiserver v0.29.1 k8s.io/apimachinery v0.29.1 @@ -31,7 +34,8 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.1 // indirect - github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect + github.com/antlr4-go/antlr/v4 v4.13.0 // indirect + github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect github.com/aws/aws-sdk-go v1.50.9 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/bshuster-repo/logrus-logstash-hook v1.0.0 // indirect @@ -43,31 +47,33 @@ require ( github.com/evanphx/json-patch/v5 v5.8.0 // indirect github.com/flosch/pongo2/v6 v6.0.0 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/getkin/kin-openapi v0.122.0 // indirect github.com/go-errors/errors v1.5.0 // indirect github.com/go-ini/ini v1.67.0 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-openapi/jsonpointer v0.20.2 // indirect - github.com/go-openapi/jsonreference v0.20.2 // indirect - github.com/go-openapi/swag v0.22.8 // indirect + github.com/go-openapi/jsonreference v0.20.4 // indirect + github.com/go-openapi/swag v0.22.9 // indirect github.com/go-sql-driver/mysql v1.7.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/golang/snappy v0.0.4 // indirect - github.com/google/cel-go v0.17.7 // indirect + github.com/google/cel-go v0.19.0 // indirect github.com/google/gnostic-models v0.6.8 // indirect - github.com/google/go-cmp v0.6.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/handlers v1.5.1 // indirect github.com/gorilla/mux v1.8.1 // indirect github.com/gorilla/websocket v1.5.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 // indirect github.com/h2non/filetype v1.1.1 // indirect github.com/h2non/go-is-svg v0.0.0-20160927212452-35e8c4b0612c // indirect github.com/hashicorp/hcl v1.0.1-vault-5 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/invopop/yaml v0.2.0 // indirect github.com/jessevdk/go-flags v1.5.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect @@ -86,11 +92,13 @@ require ( github.com/moby/spdystream v0.2.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/mongodb/mongo-tools v0.0.0-20230720205640-fb74684da15f // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/montanaflynn/stats v0.6.6 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect + github.com/oapi-codegen/runtime v1.1.0 // indirect github.com/onsi/gomega v1.30.0 // indirect github.com/operator-framework/operator-registry v1.30.1 // indirect github.com/pelletier/go-toml/v2 v2.1.0 // indirect @@ -98,6 +106,7 @@ require ( github.com/percona/percona-postgresql-operator v0.0.0-20231220140959-ad5eef722609 // indirect github.com/percona/percona-server-mongodb-operator v1.15.0 // indirect github.com/percona/percona-xtradb-cluster-operator v1.13.0 // indirect + github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 // indirect github.com/pierrec/lz4 v2.6.1+incompatible // indirect github.com/pkg/errors v0.9.1 // indirect @@ -110,32 +119,34 @@ require ( github.com/spf13/afero v1.11.0 // indirect github.com/spf13/cast v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/stoewer/go-strcase v1.2.0 // indirect + github.com/stoewer/go-strcase v1.3.0 // indirect github.com/stretchr/objx v0.5.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect + github.com/ugorji/go/codec v1.2.12 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect github.com/xlab/treeprint v1.2.0 // indirect github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect - go.mongodb.org/mongo-driver v1.12.1 // indirect - go.opentelemetry.io/otel v1.20.0 // indirect - go.opentelemetry.io/otel/trace v1.20.0 // indirect + go.mongodb.org/mongo-driver v1.13.1 // indirect + go.opentelemetry.io/otel v1.22.0 // indirect + go.opentelemetry.io/otel/trace v1.22.0 // indirect go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 // indirect golang.org/x/mod v0.14.0 // indirect - golang.org/x/net v0.19.0 // indirect - golang.org/x/oauth2 v0.15.0 // indirect + golang.org/x/net v0.20.0 // indirect + golang.org/x/oauth2 v0.16.0 // indirect golang.org/x/sys v0.17.0 // indirect golang.org/x/term v0.17.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect google.golang.org/appengine v1.6.8 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f // indirect - google.golang.org/grpc v1.59.0 // indirect - google.golang.org/protobuf v1.31.0 // indirect + google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014 // indirect + google.golang.org/grpc v1.61.0 // indirect + google.golang.org/protobuf v1.32.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 8b2e5446..87a71546 100644 --- a/go.sum +++ b/go.sum @@ -42,6 +42,7 @@ github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= +github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/adrg/xdg v0.4.0 h1:RzRqFcjH4nE5C6oTAxhBtoE2IRyjBSa62SCbyPidvls= @@ -51,8 +52,10 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alessio/shellescape v1.2.2/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df h1:7RFfzj4SSt6nnvCPbCqijJi1nWCd+TqAT3bYCStRC18= -github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM= +github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI= +github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g= +github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ= +github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= @@ -70,6 +73,7 @@ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kB github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w= github.com/bshuster-repo/logrus-logstash-hook v1.0.0 h1:e+C0SB5R1pu//O4MQ3f9cFuPGoOVeF2fE4Og9otCc70= github.com/bshuster-repo/logrus-logstash-hook v1.0.0/go.mod h1:zsTqEiSzDgAa/8GZR7E1qaXrhYNDKBYy5/dWPTIflbk= github.com/bugsnag/bugsnag-go v1.5.3 h1:yeRUT3mUE13jL1tGwvoQsKdVbAsQx9AJ+fqahKveP04= @@ -115,7 +119,6 @@ github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwc github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= @@ -182,6 +185,8 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/garyburd/redigo v1.6.0 h1:0VruCpn7yAIIu7pWVClQC8wxCJEcG3nyzpMSHKi1PQc= github.com/garyburd/redigo v1.6.0/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY= +github.com/getkin/kin-openapi v0.122.0 h1:WB9Jbl0Hp/T79/JF9xlSW5Kl9uYdk/AWD0yAd9HOM10= +github.com/getkin/kin-openapi v0.122.0/go.mod h1:PCWw/lfBrJY4HcdqE3jj+QFkaFK8ABoqo7PvqVhXXqw= github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -216,7 +221,6 @@ github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwds github.com/go-openapi/jsonpointer v0.18.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= @@ -224,8 +228,8 @@ github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3Hfo github.com/go-openapi/jsonreference v0.18.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= -github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= +github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4= github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.18.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU= @@ -248,9 +252,8 @@ github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/ github.com/go-openapi/swag v0.18.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/swag v0.22.8 h1:/9RjDSQ0vbFR+NyjGMkFTsA1IA0fmhKSThmfGZjicbw= -github.com/go-openapi/swag v0.22.8/go.mod h1:6QT22icPLEqAM/z/TChgb4WAveCHF92+2gF0CNjHpPI= +github.com/go-openapi/swag v0.22.9 h1:XX2DssF+mQKM2DHsbgZK74y/zj4mo9I99+89xUmuZCE= +github.com/go-openapi/swag v0.22.9/go.mod h1:3/OXnFfnMAwBD099SwYRk7GD3xOrr1iL7d/XNLXVVwE= github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4= github.com/go-openapi/validate v0.19.2/go.mod h1:1tRCw7m3jtI8eNWEEliiAqUIcBztB2KDnRCRMUi7GTA= github.com/go-openapi/validate v0.19.5/go.mod h1:8DJv2CVJQ6kGNpFW6eV9N3JviE1C85nY1c2z52x1Gk4= @@ -259,6 +262,8 @@ github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= +github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= github.com/gofrs/uuid v3.3.0+incompatible h1:8K4tyRfvU1CYPgJsveYFQMhpFd/wXNM7iK6rR7UHz84= github.com/gofrs/uuid v3.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= @@ -267,6 +272,7 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE= github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang-migrate/migrate/v4 v4.16.1 h1:O+0C55RbMN66pWm5MjO6mw0px6usGpY0+bkSGW9zCo0= @@ -298,8 +304,8 @@ github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/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= -github.com/google/cel-go v0.17.7 h1:6ebJFzu1xO2n7TLtN+UBqShGBhlD85bhvglh5DpcfqQ= -github.com/google/cel-go v0.17.7/go.mod h1:HXZKzB0LXqer5lHHgfWAnlYwJaQBDKMjxjulNQzhwhY= +github.com/google/cel-go v0.19.0 h1:vVgaZoHPBDd1lXCYGQOh5A06L4EtuIfmqQ/qnSXSKiU= +github.com/google/cel-go v0.19.0/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -319,8 +325,8 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20211214055906-6f57359322fd h1:1FjCyPC+syAzJ5/2S8fqdZK1R22vvA0J7JZKcuOIQ7Y= -github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -349,9 +355,8 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0 h1:RtRsiaGvWxcwd8y3BiRZxsylPT8hLWZ5SPcfI+3IDNk= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.0/go.mod h1:TzP6duP4Py2pHLVPPQp42aoYI92+PCrVotyR5e8Vqlk= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 h1:/c3QmbOGMGTOumP2iT/rCwB7b0QDGLKzqOmktBjT+Is= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1/go.mod h1:5SN9VR2LTsRFsrEC6FHgRbTWrTHu6tqPeKxEQv15giM= github.com/h2non/filetype v1.1.1 h1:xvOwnXKAckvtLWsN398qS9QhlxlnVXBjXBydK2/UFB4= github.com/h2non/filetype v1.1.1/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY= github.com/h2non/go-is-svg v0.0.0-20160927212452-35e8c4b0612c h1:fEE5/5VNnYUoBOj2I9TP8Jc+a7lge3QWn9DKE7NCwfc= @@ -374,6 +379,8 @@ github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+h github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY= +github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= @@ -393,6 +400,7 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= @@ -410,7 +418,6 @@ github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 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.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -475,6 +482,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= +github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/mongodb/mongo-tools v0.0.0-20230720205640-fb74684da15f h1:vrP8tGvlgFyelOah/ndZgZfia5fXbNVIb37ldYYg+OM= github.com/mongodb/mongo-tools v0.0.0-20230720205640-fb74684da15f/go.mod h1:FjrtGjfqHbUZEkbw0lZ+GB/3rqQsZM9KCFYnO8xx2cU= github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0= @@ -491,6 +500,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/oapi-codegen/runtime v1.1.0 h1:rJpoNUawn5XTvekgfkvSZr0RqEnoYpFkyvrzfWeFKWM= +github.com/oapi-codegen/runtime v1.1.0/go.mod h1:BeSfBkWWWnAnGdyS+S/GnlbmHKzf8/hwkvelJZDeKA8= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -529,12 +540,16 @@ github.com/percona/everest-operator v0.6.0-dev1.0.20240220114053-fae6111d9818 h1 github.com/percona/everest-operator v0.6.0-dev1.0.20240220114053-fae6111d9818/go.mod h1:45pGpvWrPy495qiQqxNuOJor4wif+vTTTJP4Qee8qZk= github.com/percona/percona-backup-mongodb v1.8.1-0.20230920143330-3b1c2e263901 h1:BDgsZRCjEuxl2/z4yWBqB0s8d20shuIDks7/RVdZiLs= github.com/percona/percona-backup-mongodb v1.8.1-0.20230920143330-3b1c2e263901/go.mod h1:fZRCMpUqkWlLVdRKqqaj001LoVP2eo6F0ZhoMPeXDng= +github.com/percona/percona-everest-backend v0.7.0 h1:ku03G3p1sttWL9rfzeOhUcSarREnszmeWScTqGMynzk= +github.com/percona/percona-everest-backend v0.7.0/go.mod h1:10coAH1cUBk0Z3tHbYNTtN362I0i5VsHQxkwacZBaQA= github.com/percona/percona-postgresql-operator v0.0.0-20231220140959-ad5eef722609 h1:+UOK4gcHrRgqjo4smgfwT7/0apF6PhAJdQIdAV4ub/M= github.com/percona/percona-postgresql-operator v0.0.0-20231220140959-ad5eef722609/go.mod h1:znzhtSTF6moUOGNPzVpgfFEMaqIe/ijTSHY8BNDkiEA= github.com/percona/percona-server-mongodb-operator v1.15.0 h1:pcP9GMi9f05VFi8e/TQifBrR+cvOkYMiv1xAftkESBs= github.com/percona/percona-server-mongodb-operator v1.15.0/go.mod h1:D4HOWd6TXRg3kfJ3sgm1LkbMe0QheueGtGCyiUflwlE= github.com/percona/percona-xtradb-cluster-operator v1.13.0 h1:KhXkjK3hRCLdEtbcuc9ynKiY7fJ1IxRqZTLgd6R6xz0= github.com/percona/percona-xtradb-cluster-operator v1.13.0/go.mod h1:EuEh2c3STNlMTvuEMGeAkM6eDhKiIT5wtfcxBZLSjiA= +github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= +github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= @@ -621,8 +636,9 @@ github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DM github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= -github.com/stoewer/go-strcase v1.2.0 h1:Z2iHWqGXH00XYgqDmNgQbIBxf3wrNq0F3feEy0ainaU= -github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8= +github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0= +github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= +github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= @@ -632,7 +648,6 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -647,6 +662,8 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= +github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/vektah/gqlparser v1.1.2/go.mod h1:1ycwN7Ij5njmMkPPAOaRFY4rET2Enx7IkVv3vaXspKw= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= @@ -679,25 +696,25 @@ go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mI go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.1/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= go.mongodb.org/mongo-driver v1.1.2/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM= -go.mongodb.org/mongo-driver v1.12.1 h1:nLkghSU8fQNaK7oUmDhQFsnrtcoNy7Z6LVFKsEecqgE= -go.mongodb.org/mongo-driver v1.12.1/go.mod h1:/rGBTebI3XYboVmgz+Wv3Bcbl3aD0QF9zl6kDDw18rQ= +go.mongodb.org/mongo-driver v1.13.1 h1:YIc7HTYsKndGK4RFzJ3covLz1byri52x0IoMB0Pt/vk= +go.mongodb.org/mongo-driver v1.13.1/go.mod h1:wcDf1JBCXy2mOW0bWHwO/IOYqdca1MPCwDtFu/Z9+eo= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= 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/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0/go.mod h1:62CPTSry9QZtOaSsE3tOzhx6LzDhHnXJ6xHeMNNiM6Q= -go.opentelemetry.io/otel v1.20.0 h1:vsb/ggIY+hUjD/zCAQHpzTmndPqv/ml2ArbsbfBYTAc= -go.opentelemetry.io/otel v1.20.0/go.mod h1:oUIGj3D77RwJdM6PPZImDpSZGDvkD9fhesHny69JFrs= +go.opentelemetry.io/otel v1.22.0 h1:xS7Ku+7yTFvDfDraDIJVpw7XPyuHlB9MCiqqX5mcJ6Y= +go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0 h1:DeFD0VgTZ+Cj6hxravYYZE2W4GlneVH81iAOPjZkzk8= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.20.0/go.mod h1:GijYcYmNpX1KazD5JmWGsi4P7dDTTTnfv1UbGn84MnU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0 h1:gvmNvqrPYovvyRmCSygkUDyL8lC5Tl845MLEwqpxhEU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.20.0/go.mod h1:vNUq47TGFioo+ffTSnKNdob241vePmtNZnAODKapKd0= -go.opentelemetry.io/otel/metric v1.20.0 h1:ZlrO8Hu9+GAhnepmRGhSU7/VkpjrNowxRN9GyKR4wzA= -go.opentelemetry.io/otel/metric v1.20.0/go.mod h1:90DRw3nfK4D7Sm/75yQ00gTJxtkBxX+wu6YaNymbpVM= +go.opentelemetry.io/otel/metric v1.22.0 h1:lypMQnGyJYeuYPhOM/bgjbFM6WE44W1/T45er4d8Hhg= +go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= go.opentelemetry.io/otel/sdk v1.20.0 h1:5Jf6imeFZlZtKv9Qbo6qt2ZkmWtdWx/wzcCbNUlAWGM= go.opentelemetry.io/otel/sdk v1.20.0/go.mod h1:rmkSx1cZCm/tn16iWDn1GQbLtsW/LvsdEEFzCSRM6V0= -go.opentelemetry.io/otel/trace v1.20.0 h1:+yxVAPZPbQhbC3OfAkeIVTky6iTFpcr4SiY9om7mXSQ= -go.opentelemetry.io/otel/trace v1.20.0/go.mod h1:HJSK7F/hA5RlzpZ0zKDCHCDHm556LCDtKaAo6JmBFUU= +go.opentelemetry.io/otel/trace v1.22.0 h1:Hg6pPujv0XG9QaVbGOBVHunyuLcCC3jN7WEhPx83XD0= +go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY= @@ -728,8 +745,8 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 h1:/RIbNt/Zr7rVhIkQhooTxCxFcdWLGIKnZA4IXNFSrvo= +golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -763,13 +780,13 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= 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= -golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= -golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= +golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= +golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= 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= @@ -854,8 +871,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA= -golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0= +golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -874,20 +891,20 @@ google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20231127180814-3a041ad873d4 h1:W12Pwm4urIbRdGhMEg2NM9O3TWKjNcxQhs46V0ypf/k= -google.golang.org/genproto v0.0.0-20231127180814-3a041ad873d4/go.mod h1:5RBcpGRxr25RbDzY5w+dmaqpSEvl8Gwl1x2CICf60ic= -google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f h1:2yNACc1O40tTnrsbk9Cv6oxiW8pxI/pXj0wRtdlYmgY= -google.golang.org/genproto/googleapis/api v0.0.0-20231120223509-83a465c0220f/go.mod h1:Uy9bTZJqmfrw2rIBxgGLnamc78euZULUBrLZ9XTITKI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f h1:ultW7fxlIvee4HYrtnaRPon9HpEgFk5zYpmfMgtKB5I= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231120223509-83a465c0220f/go.mod h1:L9KNLi232K1/xB6f7AlSX692koaRnKaWSR0stBki0Yc= +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-20240205150955-31a09d347014 h1:x9PwdEgd11LgK+orcck69WVRo7DezSO4VUMPI4xpc8A= +google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014/go.mod h1:rbHMSEDyoYX62nRVLOCc4Qt1HbsdytAYoVwgjiOhF3I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014 h1:FSL3lRCkhaPFxqi0s9o+V4UI2WTzAVOvkgbd4kVV4Wg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014/go.mod h1:SaPjaZGWb0lPqs6Ittu0spdfrOArqji4ZdeP5IC/9N4= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0= +google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs= 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= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -899,8 +916,8 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= +google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 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= @@ -928,6 +945,7 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20190905181640-827449938966/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200121175148-a6ecf24a6d71/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= diff --git a/pkg/everest/client/client.go b/pkg/everest/client/client.go new file mode 100644 index 00000000..d77a9bee --- /dev/null +++ b/pkg/everest/client/client.go @@ -0,0 +1,110 @@ +// percona-everest-cli +// Copyright (C) 2023 Percona LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package client provides helpers to communicate with Everest API +package client + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "net/url" + + "github.com/percona/percona-everest-backend/client" +) + +// Everest is a connector to the Everest API. +type Everest struct { + cl *client.Client +} + +// ErrEverest is an error coming from Everest where Everest provided an error message. +var ErrEverest = errors.New("") + +// NewEverest returns new Everest. +func NewEverest(everestClient *client.Client) *Everest { + return &Everest{ + cl: everestClient, + } +} + +// NewEverestFromURL returns a new Everest from a provided URL. +func NewEverestFromURL(rawURL, everestPwd string) (*Everest, error) { + u, err := url.Parse(rawURL) + if err != nil { + return nil, errors.Join(err, errors.New("could not parse Everest URL")) + } + everestCl, err := client.NewClient( + u.JoinPath("v1").String(), + client.WithRequestEditorFn(func(ctx context.Context, req *http.Request) error { + req.Header.Set("Cookie", fmt.Sprintf("everest_token=%s", everestPwd)) + return nil + }), + ) + if err != nil { + return nil, errors.Join(err, errors.New("could not initialize Everest client")) + } + return NewEverest(everestCl), nil +} + +// makeRequest calls arbitrary *client.Client method for API call and applies common logic for response handling. +// See methods in Everest struct for examples how to call. +func makeRequest[B interface{}, R interface{}]( + ctx context.Context, + fn func(context.Context, B, ...client.RequestEditorFn) (*http.Response, error), + body B, + ret R, + errorStatus error, +) error { + res, err := fn(ctx, body) + if err != nil { + return err + } + defer res.Body.Close() //nolint:errcheck + + if res.StatusCode < http.StatusOK || res.StatusCode >= http.StatusMultipleChoices { + return processErrorResponse(res, errorStatus) + } + err = json.NewDecoder(res.Body).Decode(ret) + if errors.Is(err, io.EOF) { + // In case the server returns no content, such as with the DELETE method, + // don't return an error. + return nil + } + + return err +} + +func processErrorResponse(res *http.Response, err error) error { + errMsg := client.Error{} + if err := json.NewDecoder(res.Body).Decode(&errMsg); err != nil { + return errors.Join(err, fmt.Errorf("could not decode Everest error response (status %d)", res.StatusCode)) + } + + msg := fmt.Sprintf("unknown error (status %d)", res.StatusCode) + if errMsg.Message != nil { + msg = fmt.Sprintf("%s (status %d)", *errMsg.Message, res.StatusCode) + return fmt.Errorf("%w%s: %w", ErrEverest, msg, err) + } + + if err != nil { + return errors.Join(err, errors.New(msg)) + } + + return errors.New("generic response error") +} diff --git a/pkg/everest/client/everest.go b/pkg/everest/client/everest.go new file mode 100644 index 00000000..98faa514 --- /dev/null +++ b/pkg/everest/client/everest.go @@ -0,0 +1,45 @@ +// percona-everest-cli +// Copyright (C) 2023 Percona LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package client ... +package client + +import ( + "context" + "errors" + "net/http" + + "github.com/percona/percona-everest-backend/client" +) + +// Version retrieves Everest version informatoin. +func (e *Everest) Version(ctx context.Context) (*client.Version, error) { + res := &client.Version{} + err := makeRequest( + ctx, func( + ctx context.Context, + _ struct{}, + r ...client.RequestEditorFn, + ) (*http.Response, error) { + return e.cl.VersionInfo(ctx, r...) + }, + struct{}{}, &res, errors.New("cannot get version due to Everest error"), + ) + if err != nil { + return nil, err + } + + return res, nil +} diff --git a/pkg/install/install.go b/pkg/install/install.go index 1b0125df..60612db7 100644 --- a/pkg/install/install.go +++ b/pkg/install/install.go @@ -27,6 +27,7 @@ import ( "strings" "github.com/AlecAivazis/survey/v2" + goversion "github.com/hashicorp/go-version" "github.com/operator-framework/api/pkg/operators/v1alpha1" "go.uber.org/zap" "golang.org/x/sync/errgroup" @@ -34,8 +35,10 @@ import ( rbacv1 "k8s.io/api/rbac/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" + versionpb "github.com/Percona-Lab/percona-version-service/versionpb" "github.com/percona/percona-everest-cli/pkg/kubernetes" "github.com/percona/percona-everest-cli/pkg/token" + "github.com/percona/percona-everest-cli/pkg/version" ) // Install implements the main logic for commands. @@ -113,6 +116,8 @@ type ( SkipWizard bool `mapstructure:"skip-wizard"` // KubeconfigPath is a path to a kubeconfig KubeconfigPath string `mapstructure:"kubeconfig"` + // VersionMetadataURL stores hostname to retrieve version metadata information from. + VersionMetadataURL string `mapstructure:"version-metadata-url"` Operator OperatorConfig } @@ -150,11 +155,25 @@ func NewInstall(c Config, l *zap.SugaredLogger) (*Install, error) { // Run runs the operators installation process. func (o *Install) Run(ctx context.Context) error { + // TODO: we shall probably split this into "install" and "add namespaces" + // Otherwise the logic is hard to maintain - we need to make sure not to, + // for example, install a different version of operators per namespace, if + // we are always installing the "latest" version. if err := o.populateConfig(); err != nil { return err } - if err := o.provisionOLM(ctx); err != nil { + meta, err := version.Metadata(ctx, o.config.VersionMetadataURL) + if err != nil { + return err + } + + latest, latestMeta, err := o.latestVersion(meta) + if err != nil { + return err + } + + if err := o.provisionOLM(ctx, latest); err != nil { return err } @@ -162,18 +181,23 @@ func (o *Install) Run(ctx context.Context) error { return err } - if err := o.provisionDBNamespaces(ctx); err != nil { + recVer, err := version.RecommendedVersions(latestMeta) + if err != nil { return err } - if err := o.provisionEverestOperator(ctx); err != nil { + if err := o.provisionDBNamespaces(ctx, recVer); err != nil { return err } - if err := o.provisionEverest(ctx); err != nil { + if err := o.provisionEverestOperator(ctx, recVer); err != nil { return err } - _, err := o.kubeClient.GetSecret(ctx, token.SecretName, SystemNamespace) + + if err := o.provisionEverest(ctx, latest); err != nil { + return err + } + _, err = o.kubeClient.GetSecret(ctx, token.SecretName, SystemNamespace) if err != nil && !k8serrors.IsNotFound(err) { return errors.Join(err, errors.New("could not get the everest token secret")) } @@ -204,6 +228,33 @@ func (o *Install) populateConfig() error { return nil } +func (o *Install) latestVersion(meta *versionpb.MetadataResponse) (*goversion.Version, *versionpb.MetadataVersion, error) { + var ( + latest *goversion.Version + latestMeta *versionpb.MetadataVersion + ) + + for _, v := range meta.Versions { + ver, err := goversion.NewSemver(v.Version) + if err != nil { + o.l.Debugf("Could not parse version %s. Error: %s", v.Version, err) + continue + } + + if latest == nil || latest.GreaterThan(ver) { + latest = ver + latestMeta = v + continue + } + } + + if latest == nil { + return nil, nil, errors.New("could not determine the latest Everest version") + } + + return latest, latestMeta, nil +} + func (o *Install) installVMOperator(ctx context.Context) error { o.l.Info("Creating operator group for everest") if err := o.kubeClient.CreateOperatorGroup(ctx, monitoringOperatorGroup, MonitoringNamespace, []string{}); err != nil { @@ -236,6 +287,7 @@ func (o *Install) provisionMonitoringStack(ctx context.Context) error { } l.Info("Preparing k8s cluster for monitoring") + // TODO: shall we grab VM operator version from metadata? if err := o.installVMOperator(ctx); err != nil { return err } @@ -247,7 +299,7 @@ func (o *Install) provisionMonitoringStack(ctx context.Context) error { return nil } -func (o *Install) provisionEverestOperator(ctx context.Context) error { +func (o *Install) provisionEverestOperator(ctx context.Context, recVer *version.RecommendedVersion) error { if err := o.createNamespace(SystemNamespace); err != nil { return err } @@ -257,14 +309,19 @@ func (o *Install) provisionEverestOperator(ctx context.Context) error { return err } - if err := o.installOperator(ctx, everestOperatorChannel, everestOperatorName, SystemNamespace)(); err != nil { + v := "" + if recVer.EverestOperator != nil { + v = recVer.EverestOperator.String() + } + + if err := o.installOperator(ctx, everestOperatorChannel, everestOperatorName, SystemNamespace, v)(); err != nil { return err } return nil } -func (o *Install) provisionEverest(ctx context.Context) error { +func (o *Install) provisionEverest(ctx context.Context, v *goversion.Version) error { d, err := o.kubeClient.GetDeployment(ctx, kubernetes.PerconaEverestDeploymentName, SystemNamespace) var everestExists bool if err != nil && !k8serrors.IsNotFound(err) { @@ -276,8 +333,7 @@ func (o *Install) provisionEverest(ctx context.Context) error { if !everestExists { o.l.Info(fmt.Sprintf("Deploying Everest to %s", SystemNamespace)) - err = o.kubeClient.InstallEverest(ctx, SystemNamespace) - if err != nil { + if err = o.kubeClient.InstallEverest(ctx, SystemNamespace, v); err != nil { return err } } else { @@ -298,7 +354,7 @@ func (o *Install) provisionEverest(ctx context.Context) error { return nil } -func (o *Install) provisionDBNamespaces(ctx context.Context) error { +func (o *Install) provisionDBNamespaces(ctx context.Context, recVer *version.RecommendedVersion) error { for _, namespace := range o.config.NamespacesList { namespace := namespace if err := o.createNamespace(namespace); err != nil { @@ -309,10 +365,11 @@ func (o *Install) provisionDBNamespaces(ctx context.Context) error { } o.l.Infof("Installing operators into %s namespace", namespace) - if err := o.provisionOperators(ctx, namespace); err != nil { + if err := o.provisionOperators(ctx, namespace, recVer); err != nil { return err } o.l.Info("Creating role for the Everest service account") + // TODO: this shall come from Everest, not cli. err := o.kubeClient.CreateRole(namespace, everestServiceAccountRole, o.serviceAccountRolePolicyRules()) if err != nil { return errors.Join(err, errors.New("could not create role")) @@ -426,15 +483,17 @@ func (o *Install) createNamespace(namespace string) error { return nil } -func (o *Install) provisionOLM(ctx context.Context) error { +func (o *Install) provisionOLM(ctx context.Context, v *goversion.Version) error { o.l.Info("Installing Operator Lifecycle Manager") + // TODO: do we upgrade OLM if the version is too old? if err := o.kubeClient.InstallOLMOperator(ctx, false); err != nil { o.l.Error("failed installing OLM") return err } o.l.Info("OLM has been installed") o.l.Info("Installing Percona OLM Catalog") - if err := o.kubeClient.InstallPerconaCatalog(ctx); err != nil { + + if err := o.kubeClient.InstallPerconaCatalog(ctx, v); err != nil { o.l.Errorf("failed installing OLM catalog: %v", err) return err } @@ -443,7 +502,7 @@ func (o *Install) provisionOLM(ctx context.Context) error { return nil } -func (o *Install) provisionOperators(ctx context.Context, namespace string) error { +func (o *Install) provisionOperators(ctx context.Context, namespace string, recVer *version.RecommendedVersion) error { g, gCtx := errgroup.WithContext(ctx) // We set the limit to 1 since operator installation // requires an update to the same installation plan which @@ -452,13 +511,25 @@ func (o *Install) provisionOperators(ctx context.Context, namespace string) erro g.SetLimit(operatorInstallThreads) if o.config.Operator.PXC { - g.Go(o.installOperator(gCtx, pxcOperatorChannel, pxcOperatorName, namespace)) + v := "" + if recVer.PXC != nil { + v = recVer.PXC.String() + } + g.Go(o.installOperator(gCtx, pxcOperatorChannel, pxcOperatorName, namespace, v)) } if o.config.Operator.PSMDB { - g.Go(o.installOperator(gCtx, psmdbOperatorChannel, psmdbOperatorName, namespace)) + v := "" + if recVer.PSMDB != nil { + v = recVer.PSMDB.String() + } + g.Go(o.installOperator(gCtx, psmdbOperatorChannel, psmdbOperatorName, namespace, v)) } if o.config.Operator.PG { - g.Go(o.installOperator(gCtx, pgOperatorChannel, pgOperatorName, namespace)) + v := "" + if recVer.PG != nil { + v = recVer.PG.String() + } + g.Go(o.installOperator(gCtx, pgOperatorChannel, pgOperatorName, namespace, v)) } if err := g.Wait(); err != nil { return err @@ -467,7 +538,7 @@ func (o *Install) provisionOperators(ctx context.Context, namespace string) erro return nil } -func (o *Install) installOperator(ctx context.Context, channel, operatorName, namespace string) func() error { +func (o *Install) installOperator(ctx context.Context, channel, operatorName, namespace string, version string) func() error { return func() error { // We check if the context has not been cancelled yet to return early if err := ctx.Err(); err != nil { @@ -490,6 +561,7 @@ func (o *Install) installOperator(ctx context.Context, channel, operatorName, na CatalogSourceNamespace: kubernetes.OLMNamespace, Channel: channel, InstallPlanApproval: v1alpha1.ApprovalManual, + StartingCSV: version, SubscriptionConfig: &v1alpha1.SubscriptionConfig{ Env: []corev1.EnvVar{ { diff --git a/pkg/kubernetes/kubernetes.go b/pkg/kubernetes/kubernetes.go index 3b50730f..1e302811 100644 --- a/pkg/kubernetes/kubernetes.go +++ b/pkg/kubernetes/kubernetes.go @@ -50,6 +50,7 @@ import ( "k8s.io/apimachinery/pkg/version" "k8s.io/client-go/rest" + goversion "github.com/hashicorp/go-version" "github.com/percona/percona-everest-cli/data" "github.com/percona/percona-everest-cli/pkg/kubernetes/client" everestVersion "github.com/percona/percona-everest-cli/pkg/version" @@ -449,7 +450,7 @@ func (k *Kubernetes) applyCSVs(ctx context.Context, resources []unstructured.Uns } // InstallPerconaCatalog installs percona catalog and ensures that packages are available. -func (k *Kubernetes) InstallPerconaCatalog(ctx context.Context) error { +func (k *Kubernetes) InstallPerconaCatalog(ctx context.Context, version *goversion.Version) error { data, err := fs.ReadFile(data.OLMCRDs, "crds/olm/everest-catalog.yaml") if err != nil { return errors.Join(err, errors.New("failed to read percona catalog file")) @@ -459,7 +460,7 @@ func (k *Kubernetes) InstallPerconaCatalog(ctx context.Context) error { return err } - if err := unstructured.SetNestedField(o, everestVersion.CatalogImage(), "spec", "image"); err != nil { + if err := unstructured.SetNestedField(o, everestVersion.CatalogImage(version), "spec", "image"); err != nil { return err } data, err = yamlv3.Marshal(o) @@ -979,24 +980,30 @@ func (k *Kubernetes) ApplyObject(obj runtime.Object) error { } // InstallEverest downloads the manifest file and applies it against provisioned k8s cluster. -func (k *Kubernetes) InstallEverest(ctx context.Context, namespace string) error { - data, err := k.getManifestData(ctx) +func (k *Kubernetes) InstallEverest(ctx context.Context, namespace string, version *goversion.Version) error { + data, err := k.getManifestData(ctx, version) if err != nil { return errors.Join(err, errors.New("failed downloading everest monitoring file")) } + k.l.Debug("Applying manifest file") err = k.client.ApplyManifestFile(data, namespace) if err != nil { return errors.Join(err, errors.New("failed applying manifest file")) } + + k.l.Debug("Waiting for manifest rollout") if err := k.client.DoRolloutWait(ctx, types.NamespacedName{Name: PerconaEverestDeploymentName, Namespace: namespace}); err != nil { return errors.Join(err, errors.New("failed waiting for the Everest deployment to be ready")) } return nil } -func (k *Kubernetes) getManifestData(ctx context.Context) ([]byte, error) { - req, err := http.NewRequestWithContext(ctx, http.MethodGet, everestVersion.ManifestURL(), nil) +func (k *Kubernetes) getManifestData(ctx context.Context, version *goversion.Version) ([]byte, error) { + m := everestVersion.ManifestURL(version) + k.l.Debugf("Downloading manifest file %s", m) + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, m, nil) if err != nil { return nil, err } @@ -1009,15 +1016,15 @@ func (k *Kubernetes) getManifestData(ctx context.Context) ([]byte, error) { } // DeleteEverest downloads the manifest file and deletes it from provisioned k8s cluster. -func (k *Kubernetes) DeleteEverest(ctx context.Context, namespace string) error { - data, err := k.getManifestData(ctx) +func (k *Kubernetes) DeleteEverest(ctx context.Context, namespace string, version *goversion.Version) error { + data, err := k.getManifestData(ctx, version) if err != nil { - return errors.Join(err, errors.New("failed downloading everest monitoring file")) + return errors.Join(err, errors.New("failed downloading Everest manifest file")) } err = k.client.DeleteManifestFile(data, namespace) if err != nil { - return errors.Join(err, errors.New("failed deleting manifest file")) + return errors.Join(err, errors.New("failed deleting Everest based on a manifest file")) } return nil } diff --git a/pkg/output/command.go b/pkg/output/command.go index 41ad646f..9183b7d6 100644 --- a/pkg/output/command.go +++ b/pkg/output/command.go @@ -26,6 +26,7 @@ import ( "go.uber.org/zap" "github.com/percona/percona-everest-cli/commands/common" + everestClient "github.com/percona/percona-everest-cli/pkg/everest/client" ) // PrintOutput prints output as a string or json. @@ -51,6 +52,12 @@ func PrintOutput(cmd *cobra.Command, l *zap.SugaredLogger, output interface{}) { // PrintError formats and prints an error to logger. func PrintError(err error, l *zap.SugaredLogger) { + if errors.Is(err, everestClient.ErrEverest) { + l := l.WithOptions(zap.AddStacktrace(zap.DPanicLevel)) + l.Error(err) + return + } + if errors.Is(err, common.ErrExitWithError) { return } diff --git a/pkg/uninstall/uninstall.go b/pkg/uninstall/uninstall.go index 2329df1f..11f47bb5 100644 --- a/pkg/uninstall/uninstall.go +++ b/pkg/uninstall/uninstall.go @@ -23,6 +23,7 @@ import ( "time" "github.com/AlecAivazis/survey/v2" + goversion "github.com/hashicorp/go-version" everestv1alpha1 "github.com/percona/everest-operator/api/v1alpha1" "go.uber.org/zap" k8serrors "k8s.io/apimachinery/pkg/api/errors" @@ -31,6 +32,7 @@ import ( "github.com/percona/percona-everest-cli/pkg/install" "github.com/percona/percona-everest-cli/pkg/kubernetes" + "github.com/percona/percona-everest-cli/pkg/version" ) // Uninstall implements logic for the cluster command. @@ -110,6 +112,14 @@ This will uninstall Everest and all its components from the cluster.` return err } + v, err := goversion.NewVersion(version.Version) + if err != nil { + return err + } + // TODO: How do we ensure we delete all resources based on the correct Everest version? + if err := u.kubeClient.DeleteEverest(ctx, install.SystemNamespace, v); err != nil { + return err + } if err := u.deleteDBNamespaces(ctx); err != nil { return err } diff --git a/pkg/upgrade/deps.go b/pkg/upgrade/deps.go new file mode 100644 index 00000000..3b7784aa --- /dev/null +++ b/pkg/upgrade/deps.go @@ -0,0 +1,27 @@ +// percona-everest-cli +// Copyright (C) 2023 Percona LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package upgrade + +import ( + "context" + + "github.com/percona/percona-everest-backend/client" +) + +//go:generate ../../bin/mockery --name=everestClientConnector --case=snake --inpackage +type everestClientConnector interface { + Version(ctx context.Context) (*client.Version, error) +} diff --git a/pkg/upgrade/mock_everest_client_connector.go b/pkg/upgrade/mock_everest_client_connector.go new file mode 100644 index 00000000..73eca0d8 --- /dev/null +++ b/pkg/upgrade/mock_everest_client_connector.go @@ -0,0 +1,56 @@ +// Code generated by mockery v2.32.4. DO NOT EDIT. + +package upgrade + +import ( + context "context" + + client "github.com/percona/percona-everest-backend/client" + + mock "github.com/stretchr/testify/mock" +) + +// mockEverestClientConnector is an autogenerated mock type for the everestClientConnector type +type mockEverestClientConnector struct { + mock.Mock +} + +// Version provides a mock function with given fields: ctx +func (_m *mockEverestClientConnector) Version(ctx context.Context) (*client.Version, error) { + ret := _m.Called(ctx) + + var r0 *client.Version + var r1 error + if rf, ok := ret.Get(0).(func(context.Context) (*client.Version, error)); ok { + return rf(ctx) + } + if rf, ok := ret.Get(0).(func(context.Context) *client.Version); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*client.Version) + } + } + + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// newMockEverestClientConnector creates a new instance of mockEverestClientConnector. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func newMockEverestClientConnector(t interface { + mock.TestingT + Cleanup(func()) +}) *mockEverestClientConnector { + mock := &mockEverestClientConnector{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/pkg/upgrade/upgrade.go b/pkg/upgrade/upgrade.go index 2a9f3b21..6323d925 100644 --- a/pkg/upgrade/upgrade.go +++ b/pkg/upgrade/upgrade.go @@ -21,50 +21,60 @@ import ( "errors" "fmt" "net/url" - "os" - "strings" - "github.com/AlecAivazis/survey/v2" + version "github.com/Percona-Lab/percona-version-service/versionpb" goversion "github.com/hashicorp/go-version" "go.uber.org/zap" "k8s.io/apimachinery/pkg/types" - "github.com/percona/percona-everest-cli/data" "github.com/percona/percona-everest-cli/pkg/install" "github.com/percona/percona-everest-cli/pkg/kubernetes" + cliVersion "github.com/percona/percona-everest-cli/pkg/version" ) type ( - // Config defines configuration required for upgrade command. - Config struct { - // Namespaces is a user-defined string represents raw non-validated comma-separated list of namespaces for everest to operate in. - Namespaces string `mapstructure:"namespaces"` - // NamespacesList validated list of namespaces that everest can operate in. - NamespacesList []string `mapstructure:"namespaces-map"` + // UpgradeConfig defines configuration required for upgrade command. + UpgradeConfig struct { + Everest struct { + // Endpoint stores URL to Everest. + Endpoint string + // Token stores Everest token. + Token string + } + // KubeconfigPath is a path to a kubeconfig KubeconfigPath string `mapstructure:"kubeconfig"` - // UpgradeOLM defines do we need to upgrade OLM or not. - UpgradeOLM bool `mapstructure:"upgrade-olm"` - // SkipWizard skips wizard during installation. - SkipWizard bool `mapstructure:"skip-wizard"` + // VersionMetadataURL stores hostname to retrieve version metadata information from. + VersionMetadataURL string `mapstructure:"version-metadata-url"` } + // Upgrade struct implements upgrade command. Upgrade struct { l *zap.SugaredLogger - config Config - kubeClient *kubernetes.Kubernetes + config *UpgradeConfig + everestClient everestClientConnector + kubeClient *kubernetes.Kubernetes + } + + supportedVersion struct { + catalog goversion.Constraints + cli goversion.Constraints + olm goversion.Constraints } ) +var ErrNoUpdateAvailable = errors.New("no update available") + // NewUpgrade returns a new Upgrade struct. -func NewUpgrade(c Config, l *zap.SugaredLogger) (*Upgrade, error) { +func NewUpgrade(cfg *UpgradeConfig, everestClient everestClientConnector, l *zap.SugaredLogger) (*Upgrade, error) { cli := &Upgrade{ - config: c, - l: l.With("component", "upgrade"), + config: cfg, + everestClient: everestClient, + l: l.With("component", "upgrade"), } - k, err := kubernetes.New(c.KubeconfigPath, cli.l) + k, err := kubernetes.New(cfg.KubeconfigPath, cli.l) if err != nil { var u *url.Error if errors.As(err, &u) { @@ -79,138 +89,198 @@ func NewUpgrade(c Config, l *zap.SugaredLogger) (*Upgrade, error) { // Run runs the operators installation process. func (u *Upgrade) Run(ctx context.Context) error { - if err := u.runEverestWizard(ctx); err != nil { - return err - } - l, err := install.ValidateNamespaces(u.config.Namespaces) + // Check prerequisites + upgradeEverestTo, recVer, err := u.canUpgrade(ctx) if err != nil { + if errors.Is(err, ErrNoUpdateAvailable) { + u.l.Info("You're running the latest version of Everest") + return nil + } return err } - u.config.NamespacesList = l - if err := u.upgradeOLM(ctx); err != nil { - return err - } - u.l.Info("Upgrading Percona Catalog") - if err := u.kubeClient.InstallPerconaCatalog(ctx); err != nil { + + // Start upgrade. + if err := u.upgradeOLM(ctx, recVer.OLM); err != nil { return err } - u.l.Info("Percona Catalog has been upgraded") - u.l.Info("Patching subscriptions") - if err := u.patchSubscriptions(ctx); err != nil { + + // We cannot use the latest version of catalog yet since + // at the time of writing, each catalog version supports only one Everest version. + u.l.Infof("Upgrading Percona Catalog to %s", recVer.Catalog) + if err := u.kubeClient.InstallPerconaCatalog(ctx, recVer.Catalog); err != nil { return err } - u.l.Info("Subscriptions have been patched") - u.l.Info("Upgrading Everest") - if err := u.kubeClient.InstallEverest(ctx, install.SystemNamespace); err != nil { + + u.l.Infof("Upgrading Everest to %s in namespace %s", upgradeEverestTo, install.SystemNamespace) + if err := u.kubeClient.InstallEverest(ctx, install.SystemNamespace, upgradeEverestTo); err != nil { return err } - u.l.Info("Everest has been upgraded") + + u.l.Infof("Everest has been upgraded to version %s", upgradeEverestTo) + return nil } -func (u *Upgrade) runEverestWizard(ctx context.Context) error { - if !u.config.SkipWizard { - namespaces, err := u.kubeClient.GetDBNamespaces(ctx, install.SystemNamespace) +// canUpgrade checks if there's a new Everest version available and if we can upgrade to it +// based on minimum requirements. +func (u *Upgrade) canUpgrade(ctx context.Context) (*goversion.Version, *cliVersion.RecommendedVersion, error) { + // Get Everest version. + eVer, err := u.everestClient.Version(ctx) + if err != nil { + return nil, nil, errors.Join(err, errors.New("could not retrieve Everest version")) + } + everestVersion, err := goversion.NewSemver(eVer.Version) + if err != nil { + return nil, nil, errors.Join(err, fmt.Errorf("invalid Everest version %s", eVer.Version)) + } + + u.l.Infof("Current Everest version is %s", everestVersion) + + // Determine version to upgrade to. + upgradeEverestTo, meta, err := u.versionToUpgradeTo(ctx, everestVersion) + if err != nil { + return nil, nil, err + } + + // Check requirements. + if err := u.verifyRequirements(ctx, meta); err != nil { + return nil, nil, err + } + + recVer, err := cliVersion.RecommendedVersions(meta) + if err != nil { + return nil, nil, err + } + + return upgradeEverestTo, recVer, nil +} + +// versionToUpgradeTo returns version to which the current Everest version can be upgraded to. +func (u *Upgrade) versionToUpgradeTo( + ctx context.Context, currentEverestVersion *goversion.Version, +) (*goversion.Version, *version.MetadataVersion, error) { + req, err := cliVersion.Metadata(ctx, u.config.VersionMetadataURL) + if err != nil { + return nil, nil, err + } + + var ( + upgradeTo *goversion.Version + meta *version.MetadataVersion + ) + for _, v := range req.Versions { + ver, err := goversion.NewVersion(v.Version) if err != nil { - return err + u.l.Debugf("Could not parse version %s. Error: %s", v.Version, err) + continue + } + + if currentEverestVersion.GreaterThanOrEqual(ver) { + continue + } + + if upgradeTo == nil { + upgradeTo = ver + meta = v + continue } - pNamespace := &survey.MultiSelect{ - Message: "Please select namespaces", - Options: namespaces, + + // Select the latest patch version for the same major and minor version. + verSeg := ver.Segments() + uSeg := upgradeTo.Segments() + if len(verSeg) >= 3 && len(uSeg) >= 3 && verSeg[0] == uSeg[0] && verSeg[1] == uSeg[1] && verSeg[2] > uSeg[2] { + upgradeTo = ver + meta = v + continue } - var input []string - if err := survey.AskOne( - pNamespace, - &input, - survey.WithValidator(survey.MinItems(1)), - ); err != nil { - return err + if upgradeTo.GreaterThan(ver) { + upgradeTo = ver + meta = v + continue } - u.config.Namespaces = strings.Join(input, ",") + } + + if upgradeTo == nil { + return nil, nil, ErrNoUpdateAvailable + } + + return upgradeTo, meta, nil +} + +func (u *Upgrade) verifyRequirements(ctx context.Context, meta *version.MetadataVersion) error { + supVer, err := u.supportedVersion(meta) + if err != nil { + return err + } + + if err := u.checkRequirements(supVer); err != nil { + return err } return nil } -func (u *Upgrade) patchSubscriptions(ctx context.Context) error { - for _, namespace := range u.config.NamespacesList { - namespace := namespace - subList, err := u.kubeClient.ListSubscriptions(ctx, namespace) +func (u *Upgrade) supportedVersion(meta *version.MetadataVersion) (*supportedVersion, error) { + supVer := &supportedVersion{} + + if cli, ok := meta.Supported["cli"]; ok { + c, err := goversion.NewConstraint(cli) if err != nil { - return err + return nil, errors.Join(err, fmt.Errorf("invalid cli constraint %s", cli)) } - if len(subList.Items) == 0 { - u.l.Warn(fmt.Sprintf("No subscriptions found in '%s' namespace", namespace)) - continue - } - disableTelemetryEnvVar := "DISABLE_TELEMETRY" - disableTelemetry, ok := os.LookupEnv(disableTelemetryEnvVar) - if !ok || disableTelemetry != "true" { - disableTelemetry = "false" + supVer.cli = c + } + + if olm, ok := meta.Supported["olm"]; ok { + c, err := goversion.NewConstraint(olm) + if err != nil { + return nil, errors.Join(err, fmt.Errorf("invalid OLM constraint %s", olm)) } - for _, subscription := range subList.Items { - u.l.Info(fmt.Sprintf("Patching %s subscription in '%s' namespace", subscription.Name, subscription.Namespace)) - subscription := subscription - for i := range subscription.Spec.Config.Env { - env := subscription.Spec.Config.Env[i] - if env.Name == disableTelemetryEnvVar { - env.Value = disableTelemetry - subscription.Spec.Config.Env[i] = env - } - } - if err := u.kubeClient.ApplyObject(&subscription); err != nil { - return err - } + supVer.olm = c + } + + if catalog, ok := meta.Supported["catalog"]; ok { + c, err := goversion.NewConstraint(catalog) + if err != nil { + return nil, errors.Join(err, fmt.Errorf("invalid catalog constraint %s", catalog)) } + supVer.catalog = c } + + return supVer, nil +} + +func (u *Upgrade) checkRequirements(minVer *supportedVersion) error { + // TODO: to be implemented. return nil } -func (u *Upgrade) upgradeOLM(ctx context.Context) error { +func (u *Upgrade) upgradeOLM(ctx context.Context, minimumVersion *goversion.Version) error { + u.l.Info("Checking OLM version") csv, err := u.kubeClient.GetClusterServiceVersion(ctx, types.NamespacedName{ Name: "packageserver", Namespace: kubernetes.OLMNamespace, }) if err != nil { - return err + return errors.Join(err, errors.New("could not retrieve Cluster Service Version")) } foundVersion, err := goversion.NewSemver(csv.Spec.Version.String()) if err != nil { return err } - shippedVersion, err := goversion.NewSemver(data.OLMVersion) - if err != nil { - return err - } - if foundVersion.GreaterThan(shippedVersion) { - // Nothing to do here. Installed OLM is greater that we ship with the CLI. + u.l.Infof("OLM version is %s. Minimum version is %s", foundVersion, minimumVersion) + if !foundVersion.LessThan(minimumVersion) { + u.l.Info("OLM version is supported. No action is required.") return nil } - if foundVersion.Equal(shippedVersion) { - // Nothing to do here. OLM is upgraded. - return nil - } - if !u.config.SkipWizard { - if err := u.runWizard(); err != nil { - return err - } - } - if u.config.UpgradeOLM { - u.l.Info("Upgrading OLM") - if err := u.kubeClient.InstallOLMOperator(ctx, true); err != nil { - return err - } - u.l.Info("OLM has been upgraded") - } - return nil -} -// runWizard runs installation wizard. -func (u *Upgrade) runWizard() error { - pOLM := &survey.Confirm{ - Message: "Do you want to upgrade OLM?", - Default: u.config.UpgradeOLM, + u.l.Info("Upgrading OLM to version %s", minimumVersion) + // TODO: shall we actually upgrade OLM operator instead of installation/skip? + if err := u.kubeClient.InstallOLMOperator(ctx, true); err != nil { + return errors.Join(err, errors.New("could not upgrade OLM")) } - return survey.AskOne(pOLM, &u.config.UpgradeOLM) + u.l.Info("OLM has been upgraded") + + return nil } diff --git a/pkg/upgrade/upgrade_test.go b/pkg/upgrade/upgrade_test.go new file mode 100644 index 00000000..370e063e --- /dev/null +++ b/pkg/upgrade/upgrade_test.go @@ -0,0 +1,162 @@ +// percona-everest-cli +// Copyright (C) 2023 Percona LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package upgrade + +import ( + "context" + "encoding/json" + "errors" + "net/http" + "net/http/httptest" + "testing" + + version "github.com/Percona-Lab/percona-version-service/versionpb" + "github.com/percona/percona-everest-backend/client" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "go.uber.org/zap" +) + +func TestUpgrade_canUpgrade(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + everestVersion string + versionMeta *version.MetadataResponse + wantErrIs error + wantUpgradeTo string + }{ + { + name: "upgrade by only one minor version", + everestVersion: "0.6.0", + versionMeta: &version.MetadataResponse{ + Versions: []*version.MetadataVersion{ + {Version: "0.5.0"}, + {Version: "0.6.0"}, + {Version: "0.7.0"}, + {Version: "0.8.0"}, + }, + }, + wantUpgradeTo: "0.7.0", + }, + { + name: "upgrade by one version to the latest", + everestVersion: "0.6.0", + versionMeta: &version.MetadataResponse{ + Versions: []*version.MetadataVersion{ + {Version: "0.5.0"}, + {Version: "0.6.0"}, + {Version: "0.7.0"}, + }, + }, + wantUpgradeTo: "0.7.0", + }, + { + name: "no update is available", + everestVersion: "0.7.0", + versionMeta: &version.MetadataResponse{ + Versions: []*version.MetadataVersion{ + {Version: "0.5.0"}, + {Version: "0.6.0"}, + {Version: "0.7.0"}, + }, + }, + wantErrIs: ErrNoUpdateAvailable, + }, + { + name: "select latest patch version", + everestVersion: "0.6.0", + versionMeta: &version.MetadataResponse{ + Versions: []*version.MetadataVersion{ + {Version: "0.5.0"}, + {Version: "0.6.0"}, + {Version: "0.7.0"}, + {Version: "0.7.1"}, + {Version: "0.7.2"}, + {Version: "0.8.0"}, + }, + }, + wantUpgradeTo: "0.7.2", + }, + { + name: "ignore invalid version", + everestVersion: "0.6.0", + versionMeta: &version.MetadataResponse{ + Versions: []*version.MetadataVersion{ + {Version: "0.5.0"}, + {Version: "0.6.0"}, + {Version: "invalid version"}, + {Version: "0.7.0"}, + }, + }, + wantUpgradeTo: "0.7.0", + }, + { + name: "descending version order shall work", + everestVersion: "0.6.0", + versionMeta: &version.MetadataResponse{ + Versions: []*version.MetadataVersion{ + {Version: "0.8.0"}, + {Version: "0.7.0"}, + {Version: "0.6.0"}, + {Version: "0.5.0"}, + }, + }, + wantUpgradeTo: "0.7.0", + }, + } + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + b, err := json.Marshal(tt.versionMeta) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + + w.Header().Add("content-type", "application/json") + w.Write(b) + })) + defer ts.Close() + + ecl := newMockEverestClientConnector(t) + ecl.On("Version", mock.Anything).Return(&client.Version{Version: tt.everestVersion}, nil) + + u := &Upgrade{ + l: zap.L().Sugar(), + config: &UpgradeConfig{ + VersionMetadataURL: ts.URL, + }, + everestClient: ecl, + } + upgradeTo, _, err := u.canUpgrade(context.Background()) + if err != nil && !errors.Is(err, tt.wantErrIs) { + t.Errorf("error = %v, wantErrIs %v", err, tt.wantErrIs) + return + } + + if err != nil { + return + } + + assert.Equal(t, tt.wantUpgradeTo, upgradeTo.String()) + }) + } +} diff --git a/pkg/version/metadata.go b/pkg/version/metadata.go new file mode 100644 index 00000000..a9e6ac84 --- /dev/null +++ b/pkg/version/metadata.go @@ -0,0 +1,88 @@ +// percona-everest-cli +// Copyright (C) 2023 Percona LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// Package install holds the main logic for installation commands. +package version + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "net/http" + "net/url" + + version "github.com/Percona-Lab/percona-version-service/versionpb" + goversion "github.com/hashicorp/go-version" +) + +// RecommendedVersion holds recommended versions per component. +type RecommendedVersion struct { + Catalog *goversion.Version + EverestOperator *goversion.Version + OLM *goversion.Version + PG *goversion.Version + PSMDB *goversion.Version + PXC *goversion.Version +} + +// Metadata returns metadata from a given metadata URL. +func Metadata(ctx context.Context, versionMetadataURL string) (*version.MetadataResponse, error) { + p, err := url.Parse(versionMetadataURL) + if err != nil { + return nil, errors.Join(err, errors.New("could not parse version metadata URL")) + } + req, err := http.NewRequestWithContext(ctx, http.MethodGet, p.JoinPath("metadata/v1/everest").String(), nil) + if err != nil { + return nil, errors.Join(err, errors.New("could not create requirements request")) + } + res, err := http.DefaultClient.Do(req) + if err != nil { + return nil, errors.Join(err, errors.New("could not retrieve requirements")) + } + defer res.Body.Close() + + if res.StatusCode != http.StatusOK { + return nil, fmt.Errorf("invalid response from requirements endpoint http %d", res.StatusCode) + } + requirements := &version.MetadataResponse{} + if err = json.NewDecoder(res.Body).Decode(requirements); err != nil { + return nil, errors.Join(err, errors.New("could not decode from requirements")) + } + + return requirements, nil +} + +// RecommendedVersions returns recommended version information based on metadata. +func RecommendedVersions(meta *version.MetadataVersion) (*RecommendedVersion, error) { + recVer := &RecommendedVersion{} + + if olm, ok := meta.Recommended["olm"]; ok { + v, err := goversion.NewSemver(olm) + if err != nil { + return nil, errors.Join(err, fmt.Errorf("invalid OLM version %s", olm)) + } + recVer.OLM = v + } + + if catalog, ok := meta.Recommended["catalog"]; ok { + v, err := goversion.NewSemver(catalog) + if err != nil { + return nil, errors.Join(err, fmt.Errorf("invalid catalog version %s", catalog)) + } + recVer.Catalog = v + } + + return recVer, nil +} diff --git a/pkg/version/version.go b/pkg/version/version.go index 7713f668..da3ba27d 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -39,34 +39,39 @@ var ( Version string //nolint:gochecknoglobals // FullCommit is a git commit hash. FullCommit string //nolint:gochecknoglobals - // CatalogImage is a image path for OLM catalog. - catalogImage string //nolint:gochecknoglobals ) -// CatalogImage returns a catalog image needed for the build of everestctl -// -// for dev builds it returns https://raw.githubusercontent.com/percona/percona-everest-backend/main/deploy/quickstart-k8s.yaml -// for the release builds it returns https://raw.githubusercontent.com/percona/percona-everest-backend/vX.Y.Z/deploy/quickstart-k8s.yaml -func CatalogImage() string { - catalogImage = devCatalogImage - v, err := goversion.NewSemver(Version) - if Version != "" && err == nil && v.Prerelease() == "" { - catalogImage = fmt.Sprintf(releaseCatalogImage, Version) +// CatalogImage returns a catalog image name. +func CatalogImage(v *goversion.Version) string { + if isDevVersion() { + return devCatalogImage } - return catalogImage + return fmt.Sprintf(releaseCatalogImage, v) } -// ManifestURL returns a manifest URL to install everest -// -// for dev builds it returns everest-catalog:latest -// for the release it returns everest-catalog:X.Y.Z. -func ManifestURL() string { - url := devManifestURL +// ManifestURL returns a manifest URL to install Everest. +func ManifestURL(v *goversion.Version) string { + if isDevVersion() { + return devManifestURL + } + return fmt.Sprintf(releaseManifestURL, v) +} + +func isDevVersion() bool { + if Version == "" { + return true + } + v, err := goversion.NewSemver(Version) - if Version != "" && err == nil && v.Prerelease() == "" { - url = fmt.Sprintf(releaseManifestURL, Version) + if err != nil { + panic(err) } - return url + + if v.Prerelease() != "" && !strings.HasSuffix(v.Prerelease(), "-upgrade-test") { + return true + } + + return false } // FullVersionInfo returns full version report. diff --git a/pkg/version/version_test.go b/pkg/version/version_test.go index 80522237..c768fec9 100644 --- a/pkg/version/version_test.go +++ b/pkg/version/version_test.go @@ -4,17 +4,24 @@ import ( "fmt" "testing" - "gotest.tools/assert" + goversion "github.com/hashicorp/go-version" + "github.com/stretchr/testify/assert" ) func TestCatalogImage(t *testing.T) { t.Parallel() Version = "v0.3.0" - assert.Equal(t, CatalogImage(), fmt.Sprintf(releaseCatalogImage, Version)) + v, err := goversion.NewVersion(Version) + assert.NoError(t, err) + assert.Equal(t, fmt.Sprintf(releaseCatalogImage, v.String()), CatalogImage(v)) + Version = "v0.3.0-1-asd-dirty" - assert.Equal(t, CatalogImage(), devCatalogImage) - Version = "c09550" - assert.Equal(t, CatalogImage(), devCatalogImage) + v, err = goversion.NewVersion(Version) + assert.NoError(t, err) + assert.Equal(t, devCatalogImage, CatalogImage(v)) + Version = "0.3.0-37-gf1f07f6" - assert.Equal(t, CatalogImage(), devCatalogImage) + v, err = goversion.NewVersion(Version) + assert.NoError(t, err) + assert.Equal(t, devCatalogImage, CatalogImage(v)) }