diff --git a/cli-tests/tests/flow/all-operators.spec.ts b/cli-tests/tests/flow/all-operators.spec.ts index 54ef12d4..b0cc5de8 100644 --- a/cli-tests/tests/flow/all-operators.spec.ts +++ b/cli-tests/tests/flow/all-operators.spec.ts @@ -46,7 +46,7 @@ test.describe('Everest CLI install', async () => { await test.step('run everest install command', async () => { const out = await cli.everestExecSkipWizard( - `install --namespace=everest-all`, + `install --namespaces=everest-all`, ); await out.assertSuccess(); @@ -73,7 +73,7 @@ test.describe('Everest CLI install', async () => { await out.assertSuccess(); - out = await cli.everestExecSkipWizardWithEnv('upgrade --namespace=everest-all', 'DISABLE_TELEMETRY=true'); + out = await cli.everestExecSkipWizardWithEnv('upgrade --namespaces=everest-all', 'DISABLE_TELEMETRY=true'); await out.assertSuccess(); await out.outErrContainsNormalizedMany([ 'Subscriptions have been patched\t{"component": "upgrade"}', diff --git a/commands/install.go b/commands/install.go index cdc59bba..7c15ca0e 100644 --- a/commands/install.go +++ b/commands/install.go @@ -30,7 +30,7 @@ import ( func newInstallCmd(l *zap.SugaredLogger) *cobra.Command { cmd := &cobra.Command{ Use: "install", - Example: "everestctl install --namespace dev --namespace staging --namespace prod --operator.mongodb=true --operator.postgresql=true --operator.xtradb-cluster=true --skip-wizard", + Example: "everestctl install --namespaces dev,staging,prod --operator.mongodb=true --operator.postgresql=true --operator.xtradb-cluster=true --skip-wizard", Run: func(cmd *cobra.Command, args []string) { initInstallViperFlags(cmd) c := &install.Config{} @@ -58,7 +58,7 @@ func newInstallCmd(l *zap.SugaredLogger) *cobra.Command { 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().String("namespaces", "", "Comma-separated namespaces list Percona Everest can manage") cmd.Flags().Bool("skip-wizard", false, "Skip installation wizard") cmd.Flags().Bool("operator.mongodb", true, "Install MongoDB operator") @@ -71,7 +71,7 @@ func initInstallViperFlags(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("namespaces", cmd.Flags().Lookup("namespaces")) //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 3c6f5f54..7380ddb1 100644 --- a/commands/upgrade.go +++ b/commands/upgrade.go @@ -59,7 +59,7 @@ func newUpgradeCmd(l *zap.SugaredLogger) *cobra.Command { func initUpgradeFlags(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().String("namespaces", "", "Comma-separated namespaces list Percona Everest can manage") cmd.Flags().Bool("upgrade-olm", false, "Upgrade OLM distribution") cmd.Flags().Bool("skip-wizard", false, "Skip installation wizard") } @@ -67,7 +67,7 @@ func initUpgradeFlags(cmd *cobra.Command) { 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("namespaces", cmd.Flags().Lookup("namespaces")) //nolint:errcheck,gosec viper.BindPFlag("upgrade-olm", cmd.Flags().Lookup("upgrade-olm")) //nolint:errcheck,gosec viper.BindPFlag("skip-wizard", cmd.Flags().Lookup("skip-wizard")) //nolint:errcheck,gosec } diff --git a/install.sh b/install.sh index 9e5b24c8..cab215c4 100755 --- a/install.sh +++ b/install.sh @@ -35,7 +35,7 @@ fi echo "Provisioning Everest with monitoring disabled" echo "If you want to enable monitoring please refer to the everest installation documentation." echo "" -./everestctl install --namespace everest --operator.mongodb=true --operator.postgresql=true --operator.xtradb-cluster=true --skip-wizard +./everestctl install --namespaces everest --operator.mongodb=true --operator.postgresql=true --operator.xtradb-cluster=true --skip-wizard echo "Your provisioned Everest instance will be available at http://127.0.0.1:8080" echo "Exposing Everest using kubectl port-forwarding. You can expose it manually" diff --git a/pkg/install/install.go b/pkg/install/install.go index 850e291e..df2d42e1 100644 --- a/pkg/install/install.go +++ b/pkg/install/install.go @@ -91,7 +91,7 @@ type ( // Config stores configuration for the operators. Config struct { // Namespaces defines namespaces that everest can operate in. - Namespaces []string `mapstructure:"namespace"` + Namespaces string `mapstructure:"namespaces"` // SkipWizard skips wizard during installation. SkipWizard bool `mapstructure:"skip-wizard"` // KubeconfigPath is a path to a kubeconfig @@ -111,6 +111,10 @@ type ( } ) +func (c Config) NamespacesList() []string { + return strings.Split(c.Namespaces, ",") +} + // NewInstall returns a new Install struct. func NewInstall(c Config, l *zap.SugaredLogger) (*Install, error) { cli := &Install{ @@ -179,9 +183,10 @@ func (o *Install) populateConfig() error { } if len(o.config.Namespaces) == 0 { - return errors.New("namespace list is empty. Specify at least one namespace using the --namespace flag") + return errors.New("namespace list is empty. Specify the comma-separated list of namespaces using the --namespaces flag, at least one namespace is required") } - for _, ns := range o.config.Namespaces { + + for _, ns := range o.config.NamespacesList() { if ns == SystemNamespace || ns == monitoringNamespace { return fmt.Errorf("'%s' namespace is reserved for Everest internals. Please specify another namespace", ns) } @@ -239,7 +244,7 @@ func (o *Install) provisionEverestOperator(ctx context.Context) error { } o.l.Info("Creating operator group for everest") - if err := o.kubeClient.CreateOperatorGroup(ctx, systemOperatorGroup, SystemNamespace, o.config.Namespaces); err != nil { + if err := o.kubeClient.CreateOperatorGroup(ctx, systemOperatorGroup, SystemNamespace, o.config.NamespacesList()); err != nil { return err } @@ -277,7 +282,7 @@ func (o *Install) provisionEverest(ctx context.Context) error { } o.l.Info("Updating cluster role bindings for everest-admin") - if err := o.kubeClient.UpdateClusterRoleBinding(ctx, everestServiceAccountClusterRoleBinding, o.config.Namespaces); err != nil { + if err := o.kubeClient.UpdateClusterRoleBinding(ctx, everestServiceAccountClusterRoleBinding, o.config.NamespacesList()); err != nil { return err } @@ -285,7 +290,7 @@ func (o *Install) provisionEverest(ctx context.Context) error { } func (o *Install) provisionDBNamespaces(ctx context.Context) error { - for _, namespace := range o.config.Namespaces { + for _, namespace := range o.config.NamespacesList() { namespace := namespace if err := o.createNamespace(namespace); err != nil { return err @@ -349,7 +354,7 @@ func (o *Install) runEverestWizard() error { return fmt.Errorf("'%s' namespace is reserved for Everest internals. Please specify another namespace", ns) } - o.config.Namespaces = append(o.config.Namespaces, ns) + o.config.Namespaces += "," + ns } if len(o.config.Namespaces) == 0 { @@ -497,7 +502,7 @@ func (o *Install) installOperator(ctx context.Context, channel, operatorName, na }, } if operatorName == everestOperatorName { - params.TargetNamespaces = o.config.Namespaces + params.TargetNamespaces = o.config.NamespacesList() params.SubscriptionConfig.Env = append(params.SubscriptionConfig.Env, []corev1.EnvVar{ { Name: EverestMonitoringNamespaceEnvVar, @@ -505,7 +510,7 @@ func (o *Install) installOperator(ctx context.Context, channel, operatorName, na }, { Name: kubernetes.EverestDBNamespacesEnvVar, - Value: strings.Join(o.config.Namespaces, ","), + Value: o.config.Namespaces, }, }...) } diff --git a/pkg/kubernetes/kubernetes.go b/pkg/kubernetes/kubernetes.go index 081f60d2..f51d1917 100644 --- a/pkg/kubernetes/kubernetes.go +++ b/pkg/kubernetes/kubernetes.go @@ -631,7 +631,7 @@ type InstallOperatorRequest struct { func mergeNamespacesEnvVar(str1, str2 string) string { ns1 := strings.Split(str1, ",") ns2 := strings.Split(str2, ",") - nsMap := map[string]struct{}{} + nsMap := make(map[string]struct{}) for _, ns := range ns1 { if ns == "" { diff --git a/pkg/upgrade/upgrade.go b/pkg/upgrade/upgrade.go index 2c94f6f6..6007533d 100644 --- a/pkg/upgrade/upgrade.go +++ b/pkg/upgrade/upgrade.go @@ -22,6 +22,7 @@ import ( "fmt" "net/url" "os" + "strings" "github.com/AlecAivazis/survey/v2" goversion "github.com/hashicorp/go-version" @@ -37,7 +38,7 @@ type ( // Config defines configuration required for upgrade command. Config struct { // Namespaces defines namespaces that everest can operate in. - Namespaces []string `mapstructure:"namespace"` + Namespaces string `mapstructure:"namespaces"` // KubeconfigPath is a path to a kubeconfig KubeconfigPath string `mapstructure:"kubeconfig"` // UpgradeOLM defines do we need to upgrade OLM or not. @@ -54,6 +55,10 @@ type ( } ) +func (c Config) NamespacesList() []string { + return strings.Split(c.Namespaces, ",") +} + // NewUpgrade returns a new Upgrade struct. func NewUpgrade(c Config, l *zap.SugaredLogger) (*Upgrade, error) { cli := &Upgrade{ @@ -126,7 +131,7 @@ func (u *Upgrade) runEverestWizard(ctx context.Context) error { } func (u *Upgrade) patchSubscriptions(ctx context.Context) error { - for _, namespace := range u.config.Namespaces { + for _, namespace := range u.config.NamespacesList() { namespace := namespace subList, err := u.kubeClient.ListSubscriptions(ctx, namespace) if err != nil {