From cfb044c2730fa30f6cb953ae5945f3c276057be1 Mon Sep 17 00:00:00 2001 From: Michal Kralik Date: Fri, 9 Feb 2024 16:53:51 +0100 Subject: [PATCH 1/8] EVEREST-793: upgrade --- commands/upgrade.go | 31 +- data/gen.go | 3 - go.mod | 47 +-- go.sum | 113 +++++--- pkg/everest/client/client.go | 110 +++++++ pkg/everest/client/everest.go | 45 +++ pkg/install/install.go | 16 +- pkg/kubernetes/kubernetes.go | 17 +- pkg/output/command.go | 7 + pkg/uninstall/uninstall.go | 8 +- pkg/upgrade/deps.go | 27 ++ pkg/upgrade/mock_everest_client_connector.go | 56 ++++ pkg/upgrade/upgrade.go | 289 +++++++++++++------ pkg/upgrade/upgrade_test.go | 168 +++++++++++ pkg/version/version.go | 18 +- pkg/version/version_test.go | 26 +- 16 files changed, 784 insertions(+), 197 deletions(-) create mode 100644 pkg/everest/client/client.go create mode 100644 pkg/everest/client/everest.go create mode 100644 pkg/upgrade/deps.go create mode 100644 pkg/upgrade/mock_everest_client_connector.go create mode 100644 pkg/upgrade/upgrade_test.go diff --git a/commands/upgrade.go b/commands/upgrade.go index 3c6f5f54..4e271e57 100644 --- a/commands/upgrade.go +++ b/commands/upgrade.go @@ -23,23 +23,28 @@ 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", 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) @@ -58,22 +63,24 @@ 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().StringArray("namespace", []string{}, "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("namespace", cmd.Flags().Lookup("namespace")) //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("skip-wizard", cmd.Flags().Lookup("skip-wizard")) //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 43a6db9e..0060f28d 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.20240207193854-cdd70b8eb1e6 + 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.18.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.0 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.7.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.3.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 @@ -111,32 +120,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.16.0 // indirect golang.org/x/term v0.16.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 d581fe5c..c864beac 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= @@ -195,8 +200,9 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 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-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= +github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= @@ -215,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= @@ -223,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= @@ -247,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= @@ -258,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= @@ -266,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= @@ -297,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= @@ -318,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= @@ -348,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= @@ -373,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= @@ -392,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= @@ -409,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= @@ -473,6 +481,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= @@ -489,6 +499,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= @@ -527,12 +539,16 @@ github.com/percona/everest-operator v0.6.0-dev1.0.20240207193854-cdd70b8eb1e6 h1 github.com/percona/everest-operator v0.6.0-dev1.0.20240207193854-cdd70b8eb1e6/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= @@ -619,8 +635,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= @@ -630,7 +647,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= @@ -645,6 +661,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= @@ -677,25 +695,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= @@ -726,8 +744,8 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= 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= @@ -761,13 +779,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= @@ -852,8 +870,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= @@ -872,20 +890,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= @@ -897,8 +915,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= @@ -926,6 +944,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 d6ac1b2f..dc492437 100644 --- a/pkg/install/install.go +++ b/pkg/install/install.go @@ -25,6 +25,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,6 +35,7 @@ import ( "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. @@ -259,10 +261,14 @@ 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) + v, err := goversion.NewVersion(version.Version) if err != nil { return err } + + if err = o.kubeClient.InstallEverest(ctx, SystemNamespace, v); err != nil { + return err + } } else { o.l.Info("Restarting Everest") if err := o.kubeClient.RestartEverest(ctx, everestOperatorName, SystemNamespace); err != nil { @@ -428,7 +434,13 @@ func (o *Install) provisionOLM(ctx context.Context) error { } o.l.Info("OLM has been installed") o.l.Info("Installing Percona OLM Catalog") - if err := o.kubeClient.InstallPerconaCatalog(ctx); err != nil { + + v, err := goversion.NewVersion(version.Version) + if err != nil { + return err + } + + if err := o.kubeClient.InstallPerconaCatalog(ctx, v); err != nil { o.l.Errorf("failed installing OLM catalog: %v", err) return err } diff --git a/pkg/kubernetes/kubernetes.go b/pkg/kubernetes/kubernetes.go index b09b7792..8625544e 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" @@ -498,7 +499,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")) @@ -508,7 +509,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) @@ -955,8 +956,8 @@ 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")) } @@ -971,8 +972,8 @@ func (k *Kubernetes) InstallEverest(ctx context.Context, namespace string) error 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) { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, everestVersion.ManifestURL(version), nil) if err != nil { return nil, err } @@ -985,8 +986,8 @@ 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")) } 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 d0e4e2fe..47e52c18 100644 --- a/pkg/uninstall/uninstall.go +++ b/pkg/uninstall/uninstall.go @@ -22,11 +22,13 @@ import ( "fmt" "github.com/AlecAivazis/survey/v2" + goversion "github.com/hashicorp/go-version" "go.uber.org/zap" k8serrors "k8s.io/apimachinery/pkg/api/errors" "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. @@ -87,7 +89,11 @@ This will uninstall Everest and all monitoring resources deployed by it. All oth if err := u.uninstallK8sResources(ctx); err != nil { return err } - if err := u.kubeClient.DeleteEverest(ctx, install.SystemNamespace); err != nil { + v, err := goversion.NewVersion(version.Version) + if err != nil { + return err + } + if err := u.kubeClient.DeleteEverest(ctx, install.SystemNamespace, v); 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 2c94f6f6..20950e86 100644 --- a/pkg/upgrade/upgrade.go +++ b/pkg/upgrade/upgrade.go @@ -18,50 +18,68 @@ package upgrade import ( "context" + "encoding/json" "errors" "fmt" + "net/http" "net/url" - "os" "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" ) type ( - // Config defines configuration required for upgrade command. - Config struct { + // UpgradeConfig defines configuration required for upgrade command. + UpgradeConfig struct { + Everest struct { + // Endpoint stores URL to Everest. + Endpoint string + // Token stores Everest token. + Token string + } + // Namespaces defines namespaces that everest can operate in. Namespaces []string `mapstructure:"namespace"` // 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 + } + + minimumVersion struct { + catalog *goversion.Version + olm *goversion.Version } ) +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) { @@ -82,27 +100,113 @@ func (u *Upgrade) Run(ctx context.Context) error { if len(u.config.Namespaces) == 0 { return errors.New("namespace list is empty. Specify at least one namespace") } - if err := u.upgradeOLM(ctx); err != nil { + + upgradeEverestTo, minVer, err := u.canUpgrade(ctx) + if 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, minVer.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 { + + u.l.Infof("Upgrading Percona Catalog to %s", minVer.catalog) + if err := u.kubeClient.InstallPerconaCatalog(ctx, minVer.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", upgradeEverestTo) + if err := u.kubeClient.InstallEverest(ctx, install.SystemNamespace, upgradeEverestTo); err != nil { return err } - u.l.Info("Everest has been upgraded") + + u.l.Info("Everest has been upgraded to version %s", upgradeEverestTo) + return nil } +// 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, *minimumVersion, 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)) + } + + // Determine version to upgrade to. + upgradeEverestTo, meta, err := u.versionToUpgradeTo(ctx, everestVersion) + if err != nil { + return nil, nil, err + } + + // Check minimum requirements. + minVer, err := u.verifyMinimumRequirements(ctx, meta) + if err != nil { + return nil, nil, err + } + + return upgradeEverestTo, minVer, 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 := u.versionMetadata(ctx) + 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 { + 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 + } + + // 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 + } + + if upgradeTo.GreaterThan(ver) { + upgradeTo = ver + meta = v + continue + } + } + + if upgradeTo == nil { + return nil, nil, ErrNoUpdateAvailable + } + + return upgradeTo, meta, nil +} + func (u *Upgrade) runEverestWizard(ctx context.Context) error { if !u.config.SkipWizard { namespaces, err := u.kubeClient.GetDBNamespaces(ctx, install.SystemNamespace) @@ -125,84 +229,101 @@ func (u *Upgrade) runEverestWizard(ctx context.Context) error { return nil } -func (u *Upgrade) patchSubscriptions(ctx context.Context) error { - for _, namespace := range u.config.Namespaces { - namespace := namespace - subList, err := u.kubeClient.ListSubscriptions(ctx, namespace) - if err != nil { - return err - } - 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" - } - 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 - } - } +func (u *Upgrade) versionMetadata(ctx context.Context) (*version.MetadataResponse, error) { + p, err := url.Parse(u.config.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 +} + +func (u *Upgrade) verifyMinimumRequirements(ctx context.Context, meta *version.MetadataVersion) (*minimumVersion, error) { + minVer, err := u.minimumVersion(meta) + if err != nil { + return nil, err + } + + if err := u.checkRequirements(minVer); err != nil { + return nil, err + } + + return minVer, nil +} + +func (u *Upgrade) minimumVersion(meta *version.MetadataVersion) (*minimumVersion, error) { + olm, ok := meta.Requirements["olm"] + if !ok { + olm = "0.0.0" + } + catalog, ok := meta.Requirements["catalog"] + if !ok { + catalog = "0.0.0" } + + vOLM, err := goversion.NewSemver(olm) + if err != nil { + return nil, errors.Join(err, fmt.Errorf("invalid OLM version %s", olm)) + } + + vCatalog, err := goversion.NewSemver(catalog) + if err != nil { + return nil, errors.Join(err, fmt.Errorf("invalid catalog version %s", catalog)) + } + + return &minimumVersion{ + olm: vOLM, + catalog: vCatalog, + }, nil +} + +func (u *Upgrade) checkRequirements(minVer *minimumVersion) 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: "olm", }) 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: 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..6e3268a1 --- /dev/null +++ b/pkg/upgrade/upgrade_test.go @@ -0,0 +1,168 @@ +// 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 + wantErr bool + 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"}, + }, + }, + wantErr: true, + 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) != tt.wantErr { + t.Errorf("Upgrade.canUpgrade() error = %v, wantErr %v", err, tt.wantErr) + return + } + if err != nil && !errors.Is(err, tt.wantErrIs) { + t.Errorf("error = %v, wantErrIs %v", err, tt.wantErrIs) + return + } + + if tt.wantErr { + return + } + + assert.Equal(t, tt.wantUpgradeTo, upgradeTo.String()) + }) + } +} diff --git a/pkg/version/version.go b/pkg/version/version.go index 7713f668..51702e09 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -44,26 +44,18 @@ var ( ) // 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 { +func CatalogImage(v *goversion.Version) string { catalogImage = devCatalogImage - v, err := goversion.NewSemver(Version) - if Version != "" && err == nil && v.Prerelease() == "" { - catalogImage = fmt.Sprintf(releaseCatalogImage, Version) + if Version != "" && v.Prerelease() == "" { + catalogImage = fmt.Sprintf(releaseCatalogImage, v) } return catalogImage } // 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 { +func ManifestURL(v *goversion.Version) string { url := devManifestURL - v, err := goversion.NewSemver(Version) - if Version != "" && err == nil && v.Prerelease() == "" { + if Version != "" && v.Prerelease() == "" { url = fmt.Sprintf(releaseManifestURL, Version) } return url diff --git a/pkg/version/version_test.go b/pkg/version/version_test.go index 80522237..45b8d402 100644 --- a/pkg/version/version_test.go +++ b/pkg/version/version_test.go @@ -4,17 +4,25 @@ 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)) - Version = "v0.3.0-1-asd-dirty" - assert.Equal(t, CatalogImage(), devCatalogImage) - Version = "c09550" - assert.Equal(t, CatalogImage(), devCatalogImage) - Version = "0.3.0-37-gf1f07f6" - assert.Equal(t, CatalogImage(), devCatalogImage) + v, err := goversion.NewVersion("v0.3.0") + assert.NoError(t, err) + assert.Equal(t, fmt.Sprintf(releaseCatalogImage, v.String()), CatalogImage(v)) + + v, err = goversion.NewVersion("v0.3.0-1-asd-dirty") + assert.NoError(t, err) + assert.Equal(t, devCatalogImage, CatalogImage(v)) + + v, err = goversion.NewVersion("c09550") + assert.NoError(t, err) + assert.Equal(t, devCatalogImage, CatalogImage(v)) + + v, err = goversion.NewVersion("0.3.0-37-gf1f07f6") + assert.NoError(t, err) + assert.Equal(t, devCatalogImage, CatalogImage(v)) } From 70bbf2801667ec1a3bf86f87141d807987dcddd8 Mon Sep 17 00:00:00 2001 From: Michal Kralik Date: Mon, 12 Feb 2024 16:26:34 +0100 Subject: [PATCH 2/8] Progress --- commands/install.go | 8 ++-- commands/upgrade.go | 4 +- pkg/install/install.go | 62 +++++++++++++++++++------- pkg/kubernetes/kubernetes.go | 9 +++- pkg/upgrade/upgrade.go | 86 +++++++----------------------------- pkg/version/metadata.go | 54 ++++++++++++++++++++++ pkg/version/version.go | 37 +++++++++++----- pkg/version/version_test.go | 13 +++--- 8 files changed, 164 insertions(+), 109 deletions(-) create mode 100644 pkg/version/metadata.go diff --git a/commands/install.go b/commands/install.go index cdc59bba..24576b98 100644 --- a/commands/install.go +++ b/commands/install.go @@ -60,6 +60,7 @@ func initInstallFlags(cmd *cobra.Command) { cmd.Flags().StringP("kubeconfig", "k", "~/.kube/config", "Path to a kubeconfig") cmd.Flags().StringArray("namespace", []string{}, "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") @@ -69,9 +70,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("namespace", cmd.Flags().Lookup("namespace")) //nolint:errcheck,gosec + viper.BindEnv("kubeconfig") //nolint:errcheck,gosec + viper.BindPFlag("kubeconfig", cmd.Flags().Lookup("kubeconfig")) //nolint:errcheck,gosec + viper.BindPFlag("namespace", cmd.Flags().Lookup("namespace")) //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 4e271e57..bbc4472a 100644 --- a/commands/upgrade.go +++ b/commands/upgrade.go @@ -66,7 +66,7 @@ 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().Bool("skip-wizard", false, "Skip installation wizard") + cmd.Flags().String("namespace", "everest-system", "Namespace where Everest is installed") cmd.Flags().String("version-metadata-url", "https://check.percona.com", "URL to retrieve version metadata information from") } @@ -75,7 +75,7 @@ func initUpgradeViperFlags(cmd *cobra.Command) { 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("skip-wizard", cmd.Flags().Lookup("skip-wizard")) //nolint:errcheck,gosec + viper.BindPFlag("namespace", cmd.Flags().Lookup("namespace")) //nolint:errcheck,gosec viper.BindPFlag("version-metadata-url", cmd.Flags().Lookup("version-metadata-url")) //nolint:errcheck,gosec } diff --git a/pkg/install/install.go b/pkg/install/install.go index dfddec53..0ae15d45 100644 --- a/pkg/install/install.go +++ b/pkg/install/install.go @@ -34,6 +34,7 @@ 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" @@ -98,6 +99,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 } @@ -139,7 +142,17 @@ func (o *Install) Run(ctx context.Context) error { return err } - if err := o.provisionOLM(ctx); err != nil { + meta, err := version.Metadata(ctx, o.config.VersionMetadataURL) + if err != nil { + return err + } + + latest, err := o.latestVersion(meta) + if err != nil { + return err + } + + if err := o.provisionOLM(ctx, latest); err != nil { return err } @@ -147,18 +160,20 @@ func (o *Install) Run(ctx context.Context) error { return err } + // TODO: revisit - we need to install correct version based on metadata. if err := o.provisionDBNamespaces(ctx); err != nil { return err } + // TODO: install correct version based on metadata. if err := o.provisionEverestOperator(ctx); err != nil { return err } - if err := o.provisionEverest(ctx); err != nil { + if err := o.provisionEverest(ctx, latest); err != nil { return err } - _, err := o.kubeClient.GetSecret(ctx, token.SecretName, SystemNamespace) + _, 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")) } @@ -192,6 +207,28 @@ func (o *Install) populateConfig() error { return nil } +func (o *Install) latestVersion(meta *versionpb.MetadataResponse) (*goversion.Version, error) { + var latest *goversion.Version + 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 + continue + } + } + + if latest == nil { + return nil, errors.New("could not determine the latest Everest version") + } + + return latest, 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 { @@ -224,6 +261,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 } @@ -252,7 +290,7 @@ func (o *Install) provisionEverestOperator(ctx context.Context) error { 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) { @@ -264,15 +302,11 @@ func (o *Install) provisionEverest(ctx context.Context) error { if !everestExists { o.l.Info(fmt.Sprintf("Deploying Everest to %s", SystemNamespace)) - v, err := goversion.NewVersion(version.Version) - if err != nil { - return err - } - if err = o.kubeClient.InstallEverest(ctx, SystemNamespace, v); err != nil { return err } } else { + // TODO: revisit - we shall probably not restart but offer upgrade. o.l.Info("Restarting Everest") if err := o.kubeClient.RestartEverest(ctx, everestOperatorName, SystemNamespace); err != nil { return err @@ -282,6 +316,7 @@ func (o *Install) provisionEverest(ctx context.Context) error { } } + // TODO: get from Everest, not cli. o.l.Info("Updating cluster role bindings for everest-admin") if err := o.kubeClient.UpdateClusterRoleBinding(ctx, everestServiceAccountClusterRoleBinding, o.config.Namespaces); err != nil { return err @@ -305,6 +340,7 @@ func (o *Install) provisionDBNamespaces(ctx context.Context) error { 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")) @@ -429,8 +465,9 @@ 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 @@ -438,11 +475,6 @@ func (o *Install) provisionOLM(ctx context.Context) error { o.l.Info("OLM has been installed") o.l.Info("Installing Percona OLM Catalog") - v, err := goversion.NewVersion(version.Version) - if err != nil { - return err - } - if err := o.kubeClient.InstallPerconaCatalog(ctx, v); err != nil { o.l.Errorf("failed installing OLM catalog: %v", err) return err diff --git a/pkg/kubernetes/kubernetes.go b/pkg/kubernetes/kubernetes.go index 9accf3de..a8a7f80e 100644 --- a/pkg/kubernetes/kubernetes.go +++ b/pkg/kubernetes/kubernetes.go @@ -1026,10 +1026,13 @@ func (k *Kubernetes) InstallEverest(ctx context.Context, namespace string, versi 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")) } @@ -1037,7 +1040,10 @@ func (k *Kubernetes) InstallEverest(ctx context.Context, namespace string, versi } func (k *Kubernetes) getManifestData(ctx context.Context, version *goversion.Version) ([]byte, error) { - req, err := http.NewRequestWithContext(ctx, http.MethodGet, everestVersion.ManifestURL(version), nil) + 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 } @@ -1050,6 +1056,7 @@ func (k *Kubernetes) getManifestData(ctx context.Context, version *goversion.Ver } // DeleteEverest downloads the manifest file and deletes it from provisioned k8s cluster. +// TODO: how do we need to change this after upgrade changes. func (k *Kubernetes) DeleteEverest(ctx context.Context, namespace string, version *goversion.Version) error { data, err := k.getManifestData(ctx, version) if err != nil { diff --git a/pkg/upgrade/upgrade.go b/pkg/upgrade/upgrade.go index 20950e86..fbf24a65 100644 --- a/pkg/upgrade/upgrade.go +++ b/pkg/upgrade/upgrade.go @@ -18,20 +18,17 @@ package upgrade import ( "context" - "encoding/json" "errors" "fmt" - "net/http" "net/url" - "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/pkg/install" "github.com/percona/percona-everest-cli/pkg/kubernetes" + cliVersion "github.com/percona/percona-everest-cli/pkg/version" ) type ( @@ -44,12 +41,10 @@ type ( Token string } - // Namespaces defines namespaces that everest can operate in. - Namespaces []string `mapstructure:"namespace"` // KubeconfigPath is a path to a kubeconfig KubeconfigPath string `mapstructure:"kubeconfig"` - // SkipWizard skips wizard during installation. - SkipWizard bool `mapstructure:"skip-wizard"` + // Namespace holds namespace where Everest is installed. + Namespace string // VersionMetadataURL stores hostname to retrieve version metadata information from. VersionMetadataURL string `mapstructure:"version-metadata-url"` } @@ -94,15 +89,13 @@ func NewUpgrade(cfg *UpgradeConfig, everestClient everestClientConnector, l *zap // Run runs the operators installation process. func (u *Upgrade) Run(ctx context.Context) error { - if err := u.runEverestWizard(ctx); err != nil { - return err - } - if len(u.config.Namespaces) == 0 { - return errors.New("namespace list is empty. Specify at least one namespace") - } - + // Check prerequisites upgradeEverestTo, minVer, 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 } @@ -111,17 +104,18 @@ func (u *Upgrade) Run(ctx context.Context) error { return err } - u.l.Infof("Upgrading Percona Catalog to %s", minVer.catalog) - if err := u.kubeClient.InstallPerconaCatalog(ctx, minVer.catalog); err != nil { + // TODO: figure out catalog version + u.l.Infof("Upgrading Percona Catalog to %s", upgradeEverestTo) + if err := u.kubeClient.InstallPerconaCatalog(ctx, upgradeEverestTo); err != nil { return err } - u.l.Infof("Upgrading Everest to %s", upgradeEverestTo) - if err := u.kubeClient.InstallEverest(ctx, install.SystemNamespace, upgradeEverestTo); err != nil { + u.l.Infof("Upgrading Everest to %s in namespace %s", upgradeEverestTo, u.config.Namespace) + if err := u.kubeClient.InstallEverest(ctx, u.config.Namespace, upgradeEverestTo); err != nil { return err } - u.l.Info("Everest has been upgraded to version %s", upgradeEverestTo) + u.l.Infof("Everest has been upgraded to version %s", upgradeEverestTo) return nil } @@ -139,6 +133,8 @@ func (u *Upgrade) canUpgrade(ctx context.Context) (*goversion.Version, *minimumV 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 { @@ -158,7 +154,7 @@ func (u *Upgrade) canUpgrade(ctx context.Context) (*goversion.Version, *minimumV func (u *Upgrade) versionToUpgradeTo( ctx context.Context, currentEverestVersion *goversion.Version, ) (*goversion.Version, *version.MetadataVersion, error) { - req, err := u.versionMetadata(ctx) + req, err := cliVersion.Metadata(ctx, u.config.VersionMetadataURL) if err != nil { return nil, nil, err } @@ -207,54 +203,6 @@ func (u *Upgrade) versionToUpgradeTo( return upgradeTo, meta, nil } -func (u *Upgrade) runEverestWizard(ctx context.Context) error { - if !u.config.SkipWizard { - namespaces, err := u.kubeClient.GetDBNamespaces(ctx, install.SystemNamespace) - if err != nil { - return err - } - pNamespace := &survey.MultiSelect{ - Message: "Please select namespaces", - Options: namespaces, - } - if err := survey.AskOne( - pNamespace, - &u.config.Namespaces, - survey.WithValidator(survey.MinItems(1)), - ); err != nil { - return err - } - } - - return nil -} - -func (u *Upgrade) versionMetadata(ctx context.Context) (*version.MetadataResponse, error) { - p, err := url.Parse(u.config.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 -} - func (u *Upgrade) verifyMinimumRequirements(ctx context.Context, meta *version.MetadataVersion) (*minimumVersion, error) { minVer, err := u.minimumVersion(meta) if err != nil { diff --git a/pkg/version/metadata.go b/pkg/version/metadata.go new file mode 100644 index 00000000..f151e402 --- /dev/null +++ b/pkg/version/metadata.go @@ -0,0 +1,54 @@ +// 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" +) + +// 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 +} diff --git a/pkg/version/version.go b/pkg/version/version.go index 51702e09..da3ba27d 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -39,26 +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 +// CatalogImage returns a catalog image name. func CatalogImage(v *goversion.Version) string { - catalogImage = devCatalogImage - if Version != "" && v.Prerelease() == "" { - catalogImage = fmt.Sprintf(releaseCatalogImage, v) + if isDevVersion() { + return devCatalogImage } - return catalogImage + return fmt.Sprintf(releaseCatalogImage, v) } -// ManifestURL returns a manifest URL to install everest +// ManifestURL returns a manifest URL to install Everest. func ManifestURL(v *goversion.Version) string { - url := devManifestURL - if Version != "" && v.Prerelease() == "" { - url = fmt.Sprintf(releaseManifestURL, Version) + if isDevVersion() { + return devManifestURL } - return url + return fmt.Sprintf(releaseManifestURL, v) +} + +func isDevVersion() bool { + if Version == "" { + return true + } + + v, err := goversion.NewSemver(Version) + if err != nil { + panic(err) + } + + 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 45b8d402..c768fec9 100644 --- a/pkg/version/version_test.go +++ b/pkg/version/version_test.go @@ -10,19 +10,18 @@ import ( func TestCatalogImage(t *testing.T) { t.Parallel() - v, err := goversion.NewVersion("v0.3.0") + Version = "v0.3.0" + v, err := goversion.NewVersion(Version) assert.NoError(t, err) assert.Equal(t, fmt.Sprintf(releaseCatalogImage, v.String()), CatalogImage(v)) - v, err = goversion.NewVersion("v0.3.0-1-asd-dirty") + Version = "v0.3.0-1-asd-dirty" + v, err = goversion.NewVersion(Version) assert.NoError(t, err) assert.Equal(t, devCatalogImage, CatalogImage(v)) - v, err = goversion.NewVersion("c09550") - assert.NoError(t, err) - assert.Equal(t, devCatalogImage, CatalogImage(v)) - - v, err = goversion.NewVersion("0.3.0-37-gf1f07f6") + Version = "0.3.0-37-gf1f07f6" + v, err = goversion.NewVersion(Version) assert.NoError(t, err) assert.Equal(t, devCatalogImage, CatalogImage(v)) } From 134b47af9a2681c20e55418ec2ec058499122de9 Mon Sep 17 00:00:00 2001 From: Michal Kralik Date: Wed, 14 Feb 2024 18:29:16 +0100 Subject: [PATCH 3/8] go mod tidy --- go.mod | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 38c26b25..201988af 100644 --- a/go.mod +++ b/go.mod @@ -12,8 +12,8 @@ require ( 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/percona-everest-backend v0.7.0 github.com/percona/everest-operator v0.6.0-dev1.0.20240214112044-8f2dea595284 + 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 @@ -137,10 +137,6 @@ require ( golang.org/x/mod v0.14.0 // indirect golang.org/x/net v0.20.0 // indirect golang.org/x/oauth2 v0.16.0 // indirect - golang.org/x/sys v0.16.0 // indirect - golang.org/x/term v0.16.0 // indirect - golang.org/x/net v0.19.0 // indirect - golang.org/x/oauth2 v0.15.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 From 8db3369d9e1f321013aa55597ef61b2f6e509a20 Mon Sep 17 00:00:00 2001 From: Michal Kralik Date: Wed, 14 Feb 2024 18:32:45 +0100 Subject: [PATCH 4/8] cleanup --- pkg/uninstall/uninstall.go | 3 --- pkg/upgrade/upgrade.go | 2 -- 2 files changed, 5 deletions(-) diff --git a/pkg/uninstall/uninstall.go b/pkg/uninstall/uninstall.go index 6415565a..8811e079 100644 --- a/pkg/uninstall/uninstall.go +++ b/pkg/uninstall/uninstall.go @@ -112,9 +112,6 @@ This will uninstall Everest and all its components from the cluster.` return err } - if err := u.uninstallK8sResources(ctx); err != nil { - return err - } v, err := goversion.NewVersion(version.Version) if err != nil { return err diff --git a/pkg/upgrade/upgrade.go b/pkg/upgrade/upgrade.go index f005583d..db06810e 100644 --- a/pkg/upgrade/upgrade.go +++ b/pkg/upgrade/upgrade.go @@ -21,8 +21,6 @@ import ( "errors" "fmt" "net/url" - "os" - "strings" version "github.com/Percona-Lab/percona-version-service/versionpb" goversion "github.com/hashicorp/go-version" From c6529851c60f559a6634d89d72257482cee78474 Mon Sep 17 00:00:00 2001 From: Michal Kralik Date: Wed, 21 Feb 2024 08:53:07 +0100 Subject: [PATCH 5/8] Install proper versions --- pkg/install/install.go | 62 +++++++++++++++++++++++---------- pkg/upgrade/upgrade.go | 77 +++++++++++++++++++++++------------------ pkg/version/metadata.go | 34 ++++++++++++++++++ 3 files changed, 121 insertions(+), 52 deletions(-) diff --git a/pkg/install/install.go b/pkg/install/install.go index 32ce145d..9d7afc28 100644 --- a/pkg/install/install.go +++ b/pkg/install/install.go @@ -150,7 +150,7 @@ func (o *Install) Run(ctx context.Context) error { return err } - latest, err := o.latestVersion(meta) + latest, latestMeta, err := o.latestVersion(meta) if err != nil { return err } @@ -163,13 +163,16 @@ func (o *Install) Run(ctx context.Context) error { return err } - // TODO: revisit - we need to install correct version based on metadata. - if err := o.provisionDBNamespaces(ctx); err != nil { + recVer, err := version.RecommendedVersions(latestMeta) + if err != nil { + return err + } + + if err := o.provisionDBNamespaces(ctx, recVer); err != nil { return err } - // TODO: install correct version based on metadata. - if err := o.provisionEverestOperator(ctx); err != nil { + if err := o.provisionEverestOperator(ctx, recVer); err != nil { return err } @@ -211,8 +214,12 @@ func (o *Install) populateConfig() error { return nil } -func (o *Install) latestVersion(meta *versionpb.MetadataResponse) (*goversion.Version, error) { - var latest *goversion.Version +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 { @@ -222,15 +229,16 @@ func (o *Install) latestVersion(meta *versionpb.MetadataResponse) (*goversion.Ve if latest == nil || latest.GreaterThan(ver) { latest = ver + latestMeta = v continue } } if latest == nil { - return nil, errors.New("could not determine the latest Everest version") + return nil, nil, errors.New("could not determine the latest Everest version") } - return latest, nil + return latest, latestMeta, nil } func (o *Install) installVMOperator(ctx context.Context) error { @@ -277,7 +285,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 } @@ -287,7 +295,12 @@ 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 } @@ -329,7 +342,7 @@ func (o *Install) provisionEverest(ctx context.Context, v *goversion.Version) er 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 { @@ -340,7 +353,7 @@ 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") @@ -492,7 +505,7 @@ func (o *Install) provisionOLM(ctx context.Context, v *goversion.Version) 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 @@ -501,13 +514,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 @@ -516,7 +541,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 { @@ -539,6 +564,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/upgrade/upgrade.go b/pkg/upgrade/upgrade.go index db06810e..c722288b 100644 --- a/pkg/upgrade/upgrade.go +++ b/pkg/upgrade/upgrade.go @@ -58,9 +58,10 @@ type ( kubeClient *kubernetes.Kubernetes } - minimumVersion struct { - catalog *goversion.Version - olm *goversion.Version + supportedVersion struct { + catalog goversion.Constraints + cli goversion.Constraints + olm goversion.Constraints } ) @@ -90,7 +91,7 @@ func NewUpgrade(cfg *UpgradeConfig, everestClient everestClientConnector, l *zap // Run runs the operators installation process. func (u *Upgrade) Run(ctx context.Context) error { // Check prerequisites - upgradeEverestTo, minVer, err := u.canUpgrade(ctx) + 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") @@ -100,7 +101,7 @@ func (u *Upgrade) Run(ctx context.Context) error { } // Start upgrade. - if err := u.upgradeOLM(ctx, minVer.olm); err != nil { + if err := u.upgradeOLM(ctx, recVer.OLM); err != nil { return err } @@ -122,7 +123,7 @@ func (u *Upgrade) Run(ctx context.Context) error { // 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, *minimumVersion, error) { +func (u *Upgrade) canUpgrade(ctx context.Context) (*goversion.Version, *cliVersion.RecommendedVersion, error) { // Get Everest version. eVer, err := u.everestClient.Version(ctx) if err != nil { @@ -141,13 +142,17 @@ func (u *Upgrade) canUpgrade(ctx context.Context) (*goversion.Version, *minimumV return nil, nil, err } - // Check minimum requirements. - minVer, err := u.verifyMinimumRequirements(ctx, meta) + // 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, minVer, nil + return upgradeEverestTo, recVer, nil } // versionToUpgradeTo returns version to which the current Everest version can be upgraded to. @@ -203,46 +208,50 @@ func (u *Upgrade) versionToUpgradeTo( return upgradeTo, meta, nil } -func (u *Upgrade) verifyMinimumRequirements(ctx context.Context, meta *version.MetadataVersion) (*minimumVersion, error) { - minVer, err := u.minimumVersion(meta) +func (u *Upgrade) verifyRequirements(ctx context.Context, meta *version.MetadataVersion) error { + supVer, err := u.supportedVersion(meta) if err != nil { - return nil, err + return err } - if err := u.checkRequirements(minVer); err != nil { - return nil, err + if err := u.checkRequirements(supVer); err != nil { + return err } - return minVer, nil + return nil } -func (u *Upgrade) minimumVersion(meta *version.MetadataVersion) (*minimumVersion, error) { - olm, ok := meta.Requirements["olm"] - if !ok { - olm = "0.0.0" - } - catalog, ok := meta.Requirements["catalog"] - if !ok { - catalog = "0.0.0" +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 nil, errors.Join(err, fmt.Errorf("invalid cli constraint %s", cli)) + } + supVer.cli = c } - vOLM, err := goversion.NewSemver(olm) - if err != nil { - return nil, errors.Join(err, fmt.Errorf("invalid OLM version %s", olm)) + 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)) + } + supVer.olm = c } - vCatalog, err := goversion.NewSemver(catalog) - if err != nil { - return nil, errors.Join(err, fmt.Errorf("invalid catalog version %s", catalog)) + 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 &minimumVersion{ - olm: vOLM, - catalog: vCatalog, - }, nil + return supVer, nil } -func (u *Upgrade) checkRequirements(minVer *minimumVersion) error { +func (u *Upgrade) checkRequirements(minVer *supportedVersion) error { // TODO: to be implemented. return nil } diff --git a/pkg/version/metadata.go b/pkg/version/metadata.go index f151e402..a9e6ac84 100644 --- a/pkg/version/metadata.go +++ b/pkg/version/metadata.go @@ -24,8 +24,19 @@ import ( "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) @@ -52,3 +63,26 @@ func Metadata(ctx context.Context, versionMetadataURL string) (*version.Metadata 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 +} From 52a804419b6f7ee9850f7b30c4844917e4d9272b Mon Sep 17 00:00:00 2001 From: Michal Kralik Date: Thu, 22 Feb 2024 16:31:37 +0100 Subject: [PATCH 6/8] Resolve a couple TODOs --- pkg/install/install.go | 6 ++++-- pkg/kubernetes/kubernetes.go | 5 ++--- pkg/uninstall/uninstall.go | 1 + pkg/upgrade/upgrade.go | 9 +++++---- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/pkg/install/install.go b/pkg/install/install.go index 9d7afc28..45c3cfcc 100644 --- a/pkg/install/install.go +++ b/pkg/install/install.go @@ -141,6 +141,10 @@ 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 } @@ -323,7 +327,6 @@ func (o *Install) provisionEverest(ctx context.Context, v *goversion.Version) er return err } } else { - // TODO: revisit - we shall probably not restart but offer upgrade. o.l.Info("Restarting Everest") if err := o.kubeClient.RestartEverest(ctx, everestOperatorName, SystemNamespace); err != nil { return err @@ -333,7 +336,6 @@ func (o *Install) provisionEverest(ctx context.Context, v *goversion.Version) er } } - // TODO: get from Everest, not cli. o.l.Info("Updating cluster role bindings for everest-admin") if err := o.kubeClient.UpdateClusterRoleBinding(ctx, everestServiceAccountClusterRoleBinding, o.config.NamespacesList()); err != nil { return err diff --git a/pkg/kubernetes/kubernetes.go b/pkg/kubernetes/kubernetes.go index d213c825..1e302811 100644 --- a/pkg/kubernetes/kubernetes.go +++ b/pkg/kubernetes/kubernetes.go @@ -1016,16 +1016,15 @@ func (k *Kubernetes) getManifestData(ctx context.Context, version *goversion.Ver } // DeleteEverest downloads the manifest file and deletes it from provisioned k8s cluster. -// TODO: how do we need to change this after upgrade changes. 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/uninstall/uninstall.go b/pkg/uninstall/uninstall.go index 8811e079..6f68a2b9 100644 --- a/pkg/uninstall/uninstall.go +++ b/pkg/uninstall/uninstall.go @@ -116,6 +116,7 @@ This will uninstall Everest and all its components from the cluster.` 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 } diff --git a/pkg/upgrade/upgrade.go b/pkg/upgrade/upgrade.go index c722288b..dd895aa3 100644 --- a/pkg/upgrade/upgrade.go +++ b/pkg/upgrade/upgrade.go @@ -105,9 +105,10 @@ func (u *Upgrade) Run(ctx context.Context) error { return err } - // TODO: figure out catalog version - u.l.Infof("Upgrading Percona Catalog to %s", upgradeEverestTo) - if err := u.kubeClient.InstallPerconaCatalog(ctx, upgradeEverestTo); 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 } @@ -276,7 +277,7 @@ func (u *Upgrade) upgradeOLM(ctx context.Context, minimumVersion *goversion.Vers } u.l.Info("Upgrading OLM to version %s", minimumVersion) - // TODO: actually upgrade OLM operator instead of installation/skip. + // 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")) } From 9eeb4b91f492cfd4823622aa7bd25f82bd5fc080 Mon Sep 17 00:00:00 2001 From: Michal Kralik Date: Wed, 28 Feb 2024 08:40:34 +0100 Subject: [PATCH 7/8] Refactore test --- pkg/upgrade/upgrade_test.go | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/pkg/upgrade/upgrade_test.go b/pkg/upgrade/upgrade_test.go index 6e3268a1..370e063e 100644 --- a/pkg/upgrade/upgrade_test.go +++ b/pkg/upgrade/upgrade_test.go @@ -37,7 +37,6 @@ func TestUpgrade_canUpgrade(t *testing.T) { name string everestVersion string versionMeta *version.MetadataResponse - wantErr bool wantErrIs error wantUpgradeTo string }{ @@ -76,7 +75,6 @@ func TestUpgrade_canUpgrade(t *testing.T) { {Version: "0.7.0"}, }, }, - wantErr: true, wantErrIs: ErrNoUpdateAvailable, }, { @@ -149,16 +147,12 @@ func TestUpgrade_canUpgrade(t *testing.T) { everestClient: ecl, } upgradeTo, _, err := u.canUpgrade(context.Background()) - if (err != nil) != tt.wantErr { - t.Errorf("Upgrade.canUpgrade() error = %v, wantErr %v", err, tt.wantErr) - return - } if err != nil && !errors.Is(err, tt.wantErrIs) { t.Errorf("error = %v, wantErrIs %v", err, tt.wantErrIs) return } - if tt.wantErr { + if err != nil { return } From 66ce00b87a5c1ced6294362cc15d2c93d58b00a2 Mon Sep 17 00:00:00 2001 From: Michal Kralik Date: Wed, 28 Feb 2024 08:49:50 +0100 Subject: [PATCH 8/8] Remove namespace flag --- commands/upgrade.go | 2 -- pkg/upgrade/upgrade.go | 7 +++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/commands/upgrade.go b/commands/upgrade.go index 8341f783..4aecfaf8 100644 --- a/commands/upgrade.go +++ b/commands/upgrade.go @@ -72,7 +72,6 @@ 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("namespace", "everest-system", "Namespace where Everest is installed") cmd.Flags().String("version-metadata-url", "https://check.percona.com", "URL to retrieve version metadata information from") } @@ -81,7 +80,6 @@ func initUpgradeViperFlags(cmd *cobra.Command) { 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("namespace", cmd.Flags().Lookup("namespace")) //nolint:errcheck,gosec viper.BindPFlag("version-metadata-url", cmd.Flags().Lookup("version-metadata-url")) //nolint:errcheck,gosec } diff --git a/pkg/upgrade/upgrade.go b/pkg/upgrade/upgrade.go index dd895aa3..6323d925 100644 --- a/pkg/upgrade/upgrade.go +++ b/pkg/upgrade/upgrade.go @@ -27,6 +27,7 @@ import ( "go.uber.org/zap" "k8s.io/apimachinery/pkg/types" + "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" ) @@ -43,8 +44,6 @@ type ( // KubeconfigPath is a path to a kubeconfig KubeconfigPath string `mapstructure:"kubeconfig"` - // Namespace holds namespace where Everest is installed. - Namespace string // VersionMetadataURL stores hostname to retrieve version metadata information from. VersionMetadataURL string `mapstructure:"version-metadata-url"` } @@ -112,8 +111,8 @@ func (u *Upgrade) Run(ctx context.Context) error { return err } - u.l.Infof("Upgrading Everest to %s in namespace %s", upgradeEverestTo, u.config.Namespace) - if err := u.kubeClient.InstallEverest(ctx, u.config.Namespace, upgradeEverestTo); 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 }