From ae365f529dbff4eda446b28c3974367b1013e94a Mon Sep 17 00:00:00 2001 From: Andreas Neumann Date: Thu, 20 Aug 2020 14:10:27 +0200 Subject: [PATCH 1/5] Expanded upgrade test Signed-off-by: Andreas Neumann --- .gitignore | 1 + Makefile | 2 +- pkg/kudoctl/kudoinit/setup/setup.go | 2 +- ...-install.yaml => 00-install-old-kudo.yaml} | 0 .../upgrade/upgrade-to-current/01-assert.yaml | 25 +++++++++++------- .../01-install-operator.yaml | 5 ++++ .../upgrade/upgrade-to-current/02-assert.yaml | 13 ++++++++++ .../{01-upgrade.yaml => 02-upgrade-kudo.yaml} | 2 +- .../upgrade/upgrade-to-current/03-assert.yaml | 22 ++++++++++++++++ .../03-upgrade-operator.yaml | 5 ++++ .../upgrade/upgrade-to-current/99-errors.yaml | 26 +++++++++++++++++++ .../upgrade-to-current/99-remove-kudo.yaml | 4 +++ .../simple-op-0.1.0/operator.yaml | 24 +++++++++++++++++ .../simple-op-0.1.0/params.yaml | 5 ++++ .../simple-op-0.1.0/templates/deployment.yaml | 19 ++++++++++++++ .../simple-op-0.2.0/operator.yaml | 24 +++++++++++++++++ .../simple-op-0.2.0/params.yaml | 9 +++++++ .../simple-op-0.2.0/templates/deployment.yaml | 20 ++++++++++++++ 18 files changed, 195 insertions(+), 13 deletions(-) rename test/upgrade/upgrade-to-current/{00-install.yaml => 00-install-old-kudo.yaml} (100%) create mode 100644 test/upgrade/upgrade-to-current/01-install-operator.yaml create mode 100644 test/upgrade/upgrade-to-current/02-assert.yaml rename test/upgrade/upgrade-to-current/{01-upgrade.yaml => 02-upgrade-kudo.yaml} (83%) create mode 100644 test/upgrade/upgrade-to-current/03-assert.yaml create mode 100644 test/upgrade/upgrade-to-current/03-upgrade-operator.yaml create mode 100644 test/upgrade/upgrade-to-current/99-errors.yaml create mode 100644 test/upgrade/upgrade-to-current/99-remove-kudo.yaml create mode 100644 test/upgrade/upgrade-to-current/simple-op-0.1.0/operator.yaml create mode 100644 test/upgrade/upgrade-to-current/simple-op-0.1.0/params.yaml create mode 100644 test/upgrade/upgrade-to-current/simple-op-0.1.0/templates/deployment.yaml create mode 100644 test/upgrade/upgrade-to-current/simple-op-0.2.0/operator.yaml create mode 100644 test/upgrade/upgrade-to-current/simple-op-0.2.0/params.yaml create mode 100644 test/upgrade/upgrade-to-current/simple-op-0.2.0/templates/deployment.yaml diff --git a/.gitignore b/.gitignore index 7606f1ed2..b3ebab6a4 100644 --- a/.gitignore +++ b/.gitignore @@ -68,3 +68,4 @@ tags [._]*.un~ kubeconfig .kube +/test/upgrade/upgrade-to-current/kubectl-kudo diff --git a/Makefile b/Makefile index 3c6b1007a..f648e8e12 100644 --- a/Makefile +++ b/Makefile @@ -80,7 +80,7 @@ lint: ## Run golangci-lint ifneq (${GOLANGCI_LINT_VER}, "$(shell golangci-lint --version 2>/dev/null | cut -b 27-32)") ./hack/install-golangcilint.sh endif - golangci-lint --timeout 3m run + golangci-lint --timeout 3m run --allow-parallel-runners .PHONY: download download: diff --git a/pkg/kudoctl/kudoinit/setup/setup.go b/pkg/kudoctl/kudoinit/setup/setup.go index d49f33e8d..5e99c0295 100644 --- a/pkg/kudoctl/kudoinit/setup/setup.go +++ b/pkg/kudoctl/kudoinit/setup/setup.go @@ -89,7 +89,7 @@ func (i *Installer) PreUpgradeVerify(client *kube.Client, result *verifier.Resul // Step 2 - Verify that any migration is possible migrations := requiredMigrations() - clog.Printf("Verify that %d required migrations can be applied", len(migrations)) + clog.V(1).Printf("Verify that %d required migrations can be applied", len(migrations)) for _, m := range migrations { if err := m.CanMigrate(client); err != nil { result.AddErrors(fmt.Errorf("migration %s failed install check: %v", m, err).Error()) diff --git a/test/upgrade/upgrade-to-current/00-install.yaml b/test/upgrade/upgrade-to-current/00-install-old-kudo.yaml similarity index 100% rename from test/upgrade/upgrade-to-current/00-install.yaml rename to test/upgrade/upgrade-to-current/00-install-old-kudo.yaml diff --git a/test/upgrade/upgrade-to-current/01-assert.yaml b/test/upgrade/upgrade-to-current/01-assert.yaml index 7c0ed7905..8ea0687be 100644 --- a/test/upgrade/upgrade-to-current/01-assert.yaml +++ b/test/upgrade/upgrade-to-current/01-assert.yaml @@ -1,13 +1,18 @@ +apiVersion: kudo.dev/v1beta1 +kind: Instance +metadata: + name: simple-op +spec: + operatorVersion: + name: simple-op-0.1.0 +status: + planStatus: + deploy: + status: COMPLETE +--- apiVersion: apps/v1 -kind: StatefulSet +kind: Deployment metadata: - labels: - app: kudo-manager - control-plane: controller-manager - name: kudo-controller-manager - namespace: kudo-system + name: nginx-deployment spec: - template: - spec: - containers: - - image: kudobuilder/controller:test \ No newline at end of file + replicas: 2 \ No newline at end of file diff --git a/test/upgrade/upgrade-to-current/01-install-operator.yaml b/test/upgrade/upgrade-to-current/01-install-operator.yaml new file mode 100644 index 000000000..8d6f66323 --- /dev/null +++ b/test/upgrade/upgrade-to-current/01-install-operator.yaml @@ -0,0 +1,5 @@ +apiVersion: kudo.dev/v1beta1 +kind: TestStep +commands: + - command: ./kubectl-kudo install --instance simple-op ./simple-op-0.1.0 + namespaced: true \ No newline at end of file diff --git a/test/upgrade/upgrade-to-current/02-assert.yaml b/test/upgrade/upgrade-to-current/02-assert.yaml new file mode 100644 index 000000000..7c0ed7905 --- /dev/null +++ b/test/upgrade/upgrade-to-current/02-assert.yaml @@ -0,0 +1,13 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + labels: + app: kudo-manager + control-plane: controller-manager + name: kudo-controller-manager + namespace: kudo-system +spec: + template: + spec: + containers: + - image: kudobuilder/controller:test \ No newline at end of file diff --git a/test/upgrade/upgrade-to-current/01-upgrade.yaml b/test/upgrade/upgrade-to-current/02-upgrade-kudo.yaml similarity index 83% rename from test/upgrade/upgrade-to-current/01-upgrade.yaml rename to test/upgrade/upgrade-to-current/02-upgrade-kudo.yaml index 20e7efa8a..818701433 100644 --- a/test/upgrade/upgrade-to-current/01-upgrade.yaml +++ b/test/upgrade/upgrade-to-current/02-upgrade-kudo.yaml @@ -1,4 +1,4 @@ apiVersion: kudo.dev/v1beta1 kind: TestStep commands: - - command: kubectl kudo init -v 4 --upgrade --kudo-image kudobuilder/controller:test --kudo-image-pull-policy IfNotPresent --unsafe-self-signed-webhook-ca \ No newline at end of file + - command: kubectl kudo init -v 4 --upgrade --kudo-image kudobuilder/controller:test --kudo-image-pull-policy IfNotPresent --unsafe-self-signed-webhook-ca --wait \ No newline at end of file diff --git a/test/upgrade/upgrade-to-current/03-assert.yaml b/test/upgrade/upgrade-to-current/03-assert.yaml new file mode 100644 index 000000000..8a4628714 --- /dev/null +++ b/test/upgrade/upgrade-to-current/03-assert.yaml @@ -0,0 +1,22 @@ +apiVersion: kudo.dev/v1beta1 +kind: Instance +metadata: + name: simple-op +spec: + operatorVersion: + name: simple-op-0.2.0 +status: + planStatus: + deploy: + status: COMPLETE +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment +spec: + replicas: 1 + template: + metadata: + labels: + fixedLabel: fixedvalue \ No newline at end of file diff --git a/test/upgrade/upgrade-to-current/03-upgrade-operator.yaml b/test/upgrade/upgrade-to-current/03-upgrade-operator.yaml new file mode 100644 index 000000000..77e1041de --- /dev/null +++ b/test/upgrade/upgrade-to-current/03-upgrade-operator.yaml @@ -0,0 +1,5 @@ +apiVersion: kudo.dev/v1beta1 +kind: TestStep +commands: + - command: kubectl kudo upgrade ./simple-op-0.2.0 --instance simple-op -p replicas=1 -p unchangeable=fixedvalue + namespaced: true \ No newline at end of file diff --git a/test/upgrade/upgrade-to-current/99-errors.yaml b/test/upgrade/upgrade-to-current/99-errors.yaml new file mode 100644 index 000000000..fe4051bb3 --- /dev/null +++ b/test/upgrade/upgrade-to-current/99-errors.yaml @@ -0,0 +1,26 @@ +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: instances.kudo.dev +spec: + group: kudo.dev + names: + kind: Instance +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: operators.kudo.dev +spec: + group: kudo.dev + names: + kind: Operator +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: operatorversions.kudo.dev +spec: + group: kudo.dev + names: + kind: OperatorVersion diff --git a/test/upgrade/upgrade-to-current/99-remove-kudo.yaml b/test/upgrade/upgrade-to-current/99-remove-kudo.yaml new file mode 100644 index 000000000..152cf9065 --- /dev/null +++ b/test/upgrade/upgrade-to-current/99-remove-kudo.yaml @@ -0,0 +1,4 @@ +apiVersion: kudo.dev/v1beta1 +kind: TestStep +commands: + - script: kubectl kudo init --upgrade --kudo-image kudobuilder/controller:test --kudo-image-pull-policy IfNotPresent --unsafe-self-signed-webhook-ca --dry-run --output yaml | tee output.log | kubectl delete -f - \ No newline at end of file diff --git a/test/upgrade/upgrade-to-current/simple-op-0.1.0/operator.yaml b/test/upgrade/upgrade-to-current/simple-op-0.1.0/operator.yaml new file mode 100644 index 000000000..a051e02b6 --- /dev/null +++ b/test/upgrade/upgrade-to-current/simple-op-0.1.0/operator.yaml @@ -0,0 +1,24 @@ +apiVersion: kudo.dev/v1beta1 +name: "simple-op" +operatorVersion: "0.1.0" +kubernetesVersion: 1.13.0 +maintainers: + - name: Your name + email: +url: https://kudo.dev +tasks: + - name: app + kind: Apply + spec: + resources: + - deployment.yaml +plans: + deploy: + strategy: serial + phases: + - name: main + strategy: parallel + steps: + - name: everything + tasks: + - app \ No newline at end of file diff --git a/test/upgrade/upgrade-to-current/simple-op-0.1.0/params.yaml b/test/upgrade/upgrade-to-current/simple-op-0.1.0/params.yaml new file mode 100644 index 000000000..853be3213 --- /dev/null +++ b/test/upgrade/upgrade-to-current/simple-op-0.1.0/params.yaml @@ -0,0 +1,5 @@ +apiVersion: kudo.dev/v1beta1 +parameters: + - name: replicas + description: Number of replicas that should be run as part of the deployment + default: 2 \ No newline at end of file diff --git a/test/upgrade/upgrade-to-current/simple-op-0.1.0/templates/deployment.yaml b/test/upgrade/upgrade-to-current/simple-op-0.1.0/templates/deployment.yaml new file mode 100644 index 000000000..73b0ad025 --- /dev/null +++ b/test/upgrade/upgrade-to-current/simple-op-0.1.0/templates/deployment.yaml @@ -0,0 +1,19 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment +spec: + selector: + matchLabels: + app: nginx + replicas: {{ .Params.replicas }} # tells deployment to run 2 pods matching the template + template: + metadata: + labels: + app: nginx + spec: + containers: + - name: nginx + image: nginx:1.7.9 + ports: + - containerPort: 80 \ No newline at end of file diff --git a/test/upgrade/upgrade-to-current/simple-op-0.2.0/operator.yaml b/test/upgrade/upgrade-to-current/simple-op-0.2.0/operator.yaml new file mode 100644 index 000000000..0bbb85956 --- /dev/null +++ b/test/upgrade/upgrade-to-current/simple-op-0.2.0/operator.yaml @@ -0,0 +1,24 @@ +apiVersion: kudo.dev/v1beta1 +name: "simple-op" +operatorVersion: "0.2.0" +kubernetesVersion: 1.15.0 +maintainers: + - name: Your name + email: +url: https://kudo.dev +tasks: + - name: app + kind: Apply + spec: + resources: + - deployment.yaml +plans: + deploy: + strategy: serial + phases: + - name: main + strategy: parallel + steps: + - name: everything + tasks: + - app \ No newline at end of file diff --git a/test/upgrade/upgrade-to-current/simple-op-0.2.0/params.yaml b/test/upgrade/upgrade-to-current/simple-op-0.2.0/params.yaml new file mode 100644 index 000000000..fc30c92e8 --- /dev/null +++ b/test/upgrade/upgrade-to-current/simple-op-0.2.0/params.yaml @@ -0,0 +1,9 @@ +apiVersion: kudo.dev/v1beta1 +parameters: + - name: replicas + description: Number of replicas that should be run as part of the deployment + default: 2 + - name: unchangeable + description: An unchangeable parameter + required: true + immutable: true \ No newline at end of file diff --git a/test/upgrade/upgrade-to-current/simple-op-0.2.0/templates/deployment.yaml b/test/upgrade/upgrade-to-current/simple-op-0.2.0/templates/deployment.yaml new file mode 100644 index 000000000..de9fb3dd1 --- /dev/null +++ b/test/upgrade/upgrade-to-current/simple-op-0.2.0/templates/deployment.yaml @@ -0,0 +1,20 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: nginx-deployment +spec: + selector: + matchLabels: + app: nginx + replicas: {{ .Params.replicas }} # tells deployment to run 2 pods matching the template + template: + metadata: + labels: + app: nginx + fixedLabel: {{ .Params.unchangeable }} + spec: + containers: + - name: nginx + image: nginx:1.7.9 + ports: + - containerPort: 80 \ No newline at end of file From fe4633c74d113496dfe26cbac23454e1b6e7615d Mon Sep 17 00:00:00 2001 From: Andreas Neumann Date: Mon, 24 Aug 2020 14:08:32 +0200 Subject: [PATCH 2/5] Extend get command Signed-off-by: Andreas Neumann --- pkg/kudoctl/cmd/get.go | 20 ++- pkg/kudoctl/cmd/get/get.go | 130 ++++++++++++++---- pkg/kudoctl/cmd/get/get_test.go | 128 ++++++++++++++--- .../cmd/get/testdata/get-all.json.golden | 53 +++++++ .../cmd/get/testdata/get-all.txt.golden | 6 + .../cmd/get/testdata/get-all.yaml.golden | 43 ++++++ .../get/testdata/get-instances.json.golden | 21 +++ .../cmd/get/testdata/get-instances.txt.golden | 4 + .../get/testdata/get-instances.yaml.golden | 16 +++ .../get/testdata/get-operators.json.golden | 16 +++ .../cmd/get/testdata/get-operators.txt.golden | 4 + .../get/testdata/get-operators.yaml.golden | 13 ++ .../testdata/get-operatorversions.json.golden | 20 +++ .../testdata/get-operatorversions.txt.golden | 4 + .../testdata/get-operatorversions.yaml.golden | 16 +++ pkg/kudoctl/cmd/root.go | 2 +- pkg/kudoctl/util/kudo/kudo.go | 41 +++++- 17 files changed, 490 insertions(+), 47 deletions(-) create mode 100644 pkg/kudoctl/cmd/get/testdata/get-all.json.golden create mode 100644 pkg/kudoctl/cmd/get/testdata/get-all.txt.golden create mode 100644 pkg/kudoctl/cmd/get/testdata/get-all.yaml.golden create mode 100644 pkg/kudoctl/cmd/get/testdata/get-instances.json.golden create mode 100644 pkg/kudoctl/cmd/get/testdata/get-instances.txt.golden create mode 100644 pkg/kudoctl/cmd/get/testdata/get-instances.yaml.golden create mode 100644 pkg/kudoctl/cmd/get/testdata/get-operators.json.golden create mode 100644 pkg/kudoctl/cmd/get/testdata/get-operators.txt.golden create mode 100644 pkg/kudoctl/cmd/get/testdata/get-operators.yaml.golden create mode 100644 pkg/kudoctl/cmd/get/testdata/get-operatorversions.json.golden create mode 100644 pkg/kudoctl/cmd/get/testdata/get-operatorversions.txt.golden create mode 100644 pkg/kudoctl/cmd/get/testdata/get-operatorversions.yaml.golden diff --git a/pkg/kudoctl/cmd/get.go b/pkg/kudoctl/cmd/get.go index 6b5746543..29854b2e1 100644 --- a/pkg/kudoctl/cmd/get.go +++ b/pkg/kudoctl/cmd/get.go @@ -1,9 +1,12 @@ package cmd import ( + "io" + "github.com/spf13/cobra" "github.com/kudobuilder/kudo/pkg/kudoctl/cmd/get" + "github.com/kudobuilder/kudo/pkg/kudoctl/env" ) const getExample = ` # Get all available instances @@ -11,15 +14,28 @@ const getExample = ` # Get all available instances ` // newGetCmd creates a command that lists the instances in the cluster -func newGetCmd() *cobra.Command { +func newGetCmd(out io.Writer) *cobra.Command { + opts := get.CmdOpts{ + Out: out, + } + getCmd := &cobra.Command{ Use: "get instances", Short: "Gets all available instances.", Example: getExample, RunE: func(cmd *cobra.Command, args []string) error { - return get.Run(args, &Settings) + client, err := env.GetClient(&Settings) + if err != nil { + return err + } + opts.Client = client + opts.Namespace = Settings.Namespace + + return get.Run(args, opts) }, } + getCmd.Flags().StringVarP(opts.Output.AsStringPtr(), "output", "o", "", "Output format for command results.") + return getCmd } diff --git a/pkg/kudoctl/cmd/get/get.go b/pkg/kudoctl/cmd/get/get.go index 926e38b90..6bfc03389 100644 --- a/pkg/kudoctl/cmd/get/get.go +++ b/pkg/kudoctl/cmd/get/get.go @@ -3,60 +3,144 @@ package get import ( "errors" "fmt" - "log" + "io" "github.com/xlab/treeprint" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" - "github.com/kudobuilder/kudo/pkg/kudoctl/env" + "github.com/kudobuilder/kudo/pkg/apis/kudo/v1beta1" + "github.com/kudobuilder/kudo/pkg/kudoctl/cmd/output" "github.com/kudobuilder/kudo/pkg/kudoctl/util/kudo" ) +type CmdOpts struct { + Out io.Writer + Output output.Type + + Namespace string + Client *kudo.Client +} + // Run returns the errors associated with cmd env -func Run(args []string, settings *env.Settings) error { +func Run(args []string, opts CmdOpts) error { + if err := opts.Output.Validate(); err != nil { + return err + } err := validate(args) if err != nil { return err } - kc, err := env.GetClient(settings) + var objs []runtime.Object + switch args[0] { + case "instances": + objs, err = opts.Client.ListInstances(opts.Namespace) + case "operators": + objs, err = opts.Client.ListOperators(opts.Namespace) + case "operatorversions": + objs, err = opts.Client.ListOperatorVersions(opts.Namespace) + case "all": + return runGetAll(opts) + } if err != nil { - return fmt.Errorf("creating kudo client: %w", err) + return fmt.Errorf("failed to retrieve objects: %v", err) } - p, err := getInstances(kc, settings) - if err != nil { - log.Printf("Error: %v", err) + if opts.Output != "" { + outObj := []interface{}{} + for _, o := range objs { + outObj = append(outObj, o) + } + return output.WriteObjects(outObj, opts.Output, opts.Out) } + tree := treeprint.New() - for _, plan := range p { - tree.AddBranch(plan) + metadataAccessor := meta.NewAccessor() + for _, obj := range objs { + name, err := metadataAccessor.Name(obj) + if err != nil { + return fmt.Errorf("failed to retrieve name from %v: %v", obj, err) + } + tree.AddBranch(name) } - fmt.Printf("List of current installed instances in namespace \"%s\":\n", settings.Namespace) - fmt.Println(tree.String()) + _, _ = fmt.Fprintf(opts.Out, "List of current installed %s in namespace \"%s\":\n", args[0], opts.Namespace) + _, _ = fmt.Fprintln(opts.Out, tree.String()) return err } -func validate(args []string) error { - if len(args) != 1 { - return errors.New(`expecting exactly one argument - "instances"`) +func runGetAll(opts CmdOpts) error { + instances, err := opts.Client.ListInstances(opts.Namespace) + if err != nil { + return fmt.Errorf("failed to get instances") + } + operatorversions, err := opts.Client.ListOperatorVersions(opts.Namespace) + if err != nil { + return fmt.Errorf("failed to get operatorversions") + } + operators, err := opts.Client.ListOperators(opts.Namespace) + if err != nil { + return fmt.Errorf("failed to get operators") } - if args[0] != "instances" { - return fmt.Errorf(`expecting "instances" and not %q`, args[0]) + if opts.Output != "" { + outObj := []interface{}{} + for _, o := range operators { + outObj = append(outObj, o) + } + for _, o := range operatorversions { + outObj = append(outObj, o) + } + for _, o := range instances { + outObj = append(outObj, o) + } + return output.WriteObjects(outObj, opts.Output, opts.Out) } + return printAllTree(opts, operators, operatorversions, instances) +} + +func printAllTree(opts CmdOpts, operators, operatorversions, instances []runtime.Object) error { + + rootTree := treeprint.New() + for _, o := range operators { + op, _ := o.(*v1beta1.Operator) + opTree := rootTree.AddBranch(op.Name) + + for _, ovo := range operatorversions { + ov, _ := ovo.(*v1beta1.OperatorVersion) + if ov.Spec.Operator.Name == op.Name { + ovTree := opTree.AddBranch(ov.Name) + + for _, io := range instances { + i, _ := io.(*v1beta1.Instance) + if i.Spec.OperatorVersion.Name == ov.Name { + ovTree.AddBranch(i.Name) + } + } + } + } + } + + _, _ = fmt.Fprintf(opts.Out, "List of current installed operators including versions and instances in namespace \"%s\":\n", opts.Namespace) + _, _ = fmt.Fprintln(opts.Out, rootTree.String()) return nil } -func getInstances(kc *kudo.Client, settings *env.Settings) ([]string, error) { - - instanceList, err := kc.ListInstances(settings.Namespace) - if err != nil { - return nil, fmt.Errorf("getting instances: %w", err) +func validate(args []string) error { + if len(args) != 1 { + return errors.New(`expecting exactly one argument - "instances, operators, operatorversions or all"`) } - return instanceList, nil + switch args[0] { + case "instances", "operators", "operatorversions": + fallthrough + case "all": + return nil + default: + return fmt.Errorf(`expecting one of "instances, operators, operatorversions or all" and not %q`, args[0]) + } } diff --git a/pkg/kudoctl/cmd/get/get_test.go b/pkg/kudoctl/cmd/get/get_test.go index c8abaff43..b4fa34c4a 100644 --- a/pkg/kudoctl/cmd/get/get_test.go +++ b/pkg/kudoctl/cmd/get/get_test.go @@ -1,6 +1,10 @@ package get import ( + "bytes" + "flag" + "io/ioutil" + "path/filepath" "testing" "github.com/stretchr/testify/assert" @@ -10,19 +14,21 @@ import ( "github.com/kudobuilder/kudo/pkg/apis/kudo/v1beta1" "github.com/kudobuilder/kudo/pkg/client/clientset/versioned/fake" - "github.com/kudobuilder/kudo/pkg/kudoctl/env" + "github.com/kudobuilder/kudo/pkg/kudoctl/cmd/output" "github.com/kudobuilder/kudo/pkg/kudoctl/util/kudo" ) +var updateGolden = flag.Bool("update", false, "update .golden files") + func TestValidate(t *testing.T) { tests := []struct { arg []string err string }{ - {nil, "expecting exactly one argument - \"instances\""}, // 1 - {[]string{"arg", "arg2"}, "expecting exactly one argument - \"instances\""}, // 2 - {[]string{}, "expecting exactly one argument - \"instances\""}, // 3 - {[]string{"somethingelse"}, "expecting \"instances\" and not \"somethingelse\""}, // 4 + {nil, "expecting exactly one argument - \"instances, operators, operatorversions or all\""}, // 1 + {[]string{"arg", "arg2"}, "expecting exactly one argument - \"instances, operators, operatorversions or all\""}, // 2 + {[]string{}, "expecting exactly one argument - \"instances, operators, operatorversions or all\""}, // 3 + {[]string{"somethingelse"}, "expecting one of \"instances, operators, operatorversions or all\" and not \"somethingelse\""}, // 4 } for _, tt := range tests { @@ -45,27 +51,117 @@ func TestGetInstances(t *testing.T) { Labels: map[string]string{ "operator": "test", }, - Name: "test", + Name: "test", + Namespace: "default", }, Spec: v1beta1.InstanceSpec{ OperatorVersion: v1.ObjectReference{ - Name: "test-1.0", + Name: "some-operator-0.1.0", + }, + }, + } + + testOperator := &v1beta1.Operator{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "kudo.dev/v1beta1", + Kind: "Operator", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "some-operator", + Namespace: "default", + }, + Spec: v1beta1.OperatorSpec{ + Description: "A fancy Operator", + KudoVersion: "0.16.0", + }, + } + + testOperatorVersion := &v1beta1.OperatorVersion{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "kudo.dev/v1beta1", + Kind: "OperatorVersion", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: "some-operator-0.1.0", + Namespace: "default", + }, + Spec: v1beta1.OperatorVersionSpec{ + Operator: v1.ObjectReference{ + APIVersion: "kudo.dev/v1beta1", + Kind: "Operator", + Name: "some-operator", }, + Version: "0.1.0", }, } + + kc := newTestClient() + if _, err := kc.InstallInstanceObjToCluster(testInstance, "default"); err != nil { + t.Fatal(err) + } + if _, err := kc.InstallOperatorObjToCluster(testOperator, "default"); err != nil { + t.Fatal(err) + } + if _, err := kc.InstallOperatorVersionObjToCluster(testOperatorVersion, "default"); err != nil { + t.Fatal(err) + } + tests := []struct { - instances []string + name string + arg string + goldenFile string + output output.Type + expectedError string }{ - {[]string{"test"}}, + {name: "human readable instances", arg: "instances", goldenFile: "get-instances.txt", output: ""}, + {name: "yaml instances", arg: "instances", goldenFile: "get-instances.yaml", output: output.TypeYAML}, + {name: "json instances", arg: "instances", goldenFile: "get-instances.json", output: output.TypeJSON}, + {name: "human readable operators", arg: "operators", goldenFile: "get-operators.txt", output: ""}, + {name: "yaml operators", arg: "operators", goldenFile: "get-operators.yaml", output: output.TypeYAML}, + {name: "json operators", arg: "operators", goldenFile: "get-operators.json", output: output.TypeJSON}, + {name: "human readable operatorversions", arg: "operatorversions", goldenFile: "get-operatorversions.txt", output: ""}, + {name: "yaml operatorversions", arg: "operatorversions", goldenFile: "get-operatorversions.yaml", output: output.TypeYAML}, + {name: "json operatorversions", arg: "operatorversions", goldenFile: "get-operatorversions.json", output: output.TypeJSON}, + {name: "human readable all", arg: "all", goldenFile: "get-all.txt", output: ""}, + {name: "yaml all", arg: "all", goldenFile: "get-all.yaml", output: output.TypeYAML}, + {name: "json all", arg: "all", goldenFile: "get-all.json", output: output.TypeJSON}, + + {name: "invalid output", arg: "instances", expectedError: output.InvalidOutputError, output: "invalid"}, } for _, tt := range tests { - kc := newTestClient() - if _, err := kc.InstallInstanceObjToCluster(testInstance, "default"); err != nil { - t.Fatal(err) - } - instanceList, err := getInstances(kc, env.DefaultSettings) - assert.NoError(t, err) - assert.EqualValues(t, tt.instances, instanceList, "missing instances") + tt := tt + + t.Run(tt.name, func(t *testing.T) { + out := &bytes.Buffer{} + cmd := CmdOpts{Out: out, Output: tt.output, Namespace: "default", Client: kc} + + if err := Run([]string{tt.arg}, cmd); err != nil { + if tt.expectedError != "" { + assert.Equal(t, tt.expectedError, err.Error()) + } else { + t.Fatalf("unexpected error: %v", err) + } + } + + if tt.goldenFile != "" { + gp := filepath.Join("testdata", tt.goldenFile+".golden") + + if *updateGolden { + t.Log("update golden file") + + //nolint:gosec + if err := ioutil.WriteFile(gp, out.Bytes(), 0644); err != nil { + t.Fatalf("failed to update golden file: %s", err) + } + } + g, err := ioutil.ReadFile(gp) + if err != nil { + t.Fatalf("failed reading .golden: %s", err) + } + + assert.Equal(t, string(g), out.String(), "output does not match .golden file %s", gp) + } + }) } } diff --git a/pkg/kudoctl/cmd/get/testdata/get-all.json.golden b/pkg/kudoctl/cmd/get/testdata/get-all.json.golden new file mode 100644 index 000000000..f9f682240 --- /dev/null +++ b/pkg/kudoctl/cmd/get/testdata/get-all.json.golden @@ -0,0 +1,53 @@ +[ + { + "kind": "Operator", + "apiVersion": "kudo.dev/v1beta1", + "metadata": { + "name": "some-operator", + "namespace": "default", + "creationTimestamp": null + }, + "spec": { + "description": "A fancy Operator", + "kudoVersion": "0.16.0" + }, + "status": {} + }, + { + "kind": "OperatorVersion", + "apiVersion": "kudo.dev/v1beta1", + "metadata": { + "name": "some-operator-0.1.0", + "namespace": "default", + "creationTimestamp": null + }, + "spec": { + "operator": { + "kind": "Operator", + "name": "some-operator", + "apiVersion": "kudo.dev/v1beta1" + }, + "version": "0.1.0" + }, + "status": {} + }, + { + "kind": "Instance", + "apiVersion": "kudo.dev/v1beta1", + "metadata": { + "name": "test", + "namespace": "default", + "creationTimestamp": null, + "labels": { + "operator": "test" + } + }, + "spec": { + "operatorVersion": { + "name": "some-operator-0.1.0" + }, + "planExecution": {} + }, + "status": {} + } +] diff --git a/pkg/kudoctl/cmd/get/testdata/get-all.txt.golden b/pkg/kudoctl/cmd/get/testdata/get-all.txt.golden new file mode 100644 index 000000000..37a7bb2ca --- /dev/null +++ b/pkg/kudoctl/cmd/get/testdata/get-all.txt.golden @@ -0,0 +1,6 @@ +List of current installed operators including versions and instances in namespace "default": +. +└── some-operator + └── some-operator-0.1.0 + └── test + diff --git a/pkg/kudoctl/cmd/get/testdata/get-all.yaml.golden b/pkg/kudoctl/cmd/get/testdata/get-all.yaml.golden new file mode 100644 index 000000000..e79848e3d --- /dev/null +++ b/pkg/kudoctl/cmd/get/testdata/get-all.yaml.golden @@ -0,0 +1,43 @@ +--- +apiVersion: kudo.dev/v1beta1 +kind: Operator +metadata: + creationTimestamp: null + name: some-operator + namespace: default +spec: + description: A fancy Operator + kudoVersion: 0.16.0 +status: {} + +--- +apiVersion: kudo.dev/v1beta1 +kind: OperatorVersion +metadata: + creationTimestamp: null + name: some-operator-0.1.0 + namespace: default +spec: + operator: + apiVersion: kudo.dev/v1beta1 + kind: Operator + name: some-operator + version: 0.1.0 +status: {} + +--- +apiVersion: kudo.dev/v1beta1 +kind: Instance +metadata: + creationTimestamp: null + labels: + operator: test + name: test + namespace: default +spec: + operatorVersion: + name: some-operator-0.1.0 + planExecution: {} +status: {} + +... diff --git a/pkg/kudoctl/cmd/get/testdata/get-instances.json.golden b/pkg/kudoctl/cmd/get/testdata/get-instances.json.golden new file mode 100644 index 000000000..8fff1b00d --- /dev/null +++ b/pkg/kudoctl/cmd/get/testdata/get-instances.json.golden @@ -0,0 +1,21 @@ +[ + { + "kind": "Instance", + "apiVersion": "kudo.dev/v1beta1", + "metadata": { + "name": "test", + "namespace": "default", + "creationTimestamp": null, + "labels": { + "operator": "test" + } + }, + "spec": { + "operatorVersion": { + "name": "some-operator-0.1.0" + }, + "planExecution": {} + }, + "status": {} + } +] diff --git a/pkg/kudoctl/cmd/get/testdata/get-instances.txt.golden b/pkg/kudoctl/cmd/get/testdata/get-instances.txt.golden new file mode 100644 index 000000000..bd9dcbe0c --- /dev/null +++ b/pkg/kudoctl/cmd/get/testdata/get-instances.txt.golden @@ -0,0 +1,4 @@ +List of current installed instances in namespace "default": +. +└── test + diff --git a/pkg/kudoctl/cmd/get/testdata/get-instances.yaml.golden b/pkg/kudoctl/cmd/get/testdata/get-instances.yaml.golden new file mode 100644 index 000000000..375920c95 --- /dev/null +++ b/pkg/kudoctl/cmd/get/testdata/get-instances.yaml.golden @@ -0,0 +1,16 @@ +--- +apiVersion: kudo.dev/v1beta1 +kind: Instance +metadata: + creationTimestamp: null + labels: + operator: test + name: test + namespace: default +spec: + operatorVersion: + name: some-operator-0.1.0 + planExecution: {} +status: {} + +... diff --git a/pkg/kudoctl/cmd/get/testdata/get-operators.json.golden b/pkg/kudoctl/cmd/get/testdata/get-operators.json.golden new file mode 100644 index 000000000..62d6c7a0e --- /dev/null +++ b/pkg/kudoctl/cmd/get/testdata/get-operators.json.golden @@ -0,0 +1,16 @@ +[ + { + "kind": "Operator", + "apiVersion": "kudo.dev/v1beta1", + "metadata": { + "name": "some-operator", + "namespace": "default", + "creationTimestamp": null + }, + "spec": { + "description": "A fancy Operator", + "kudoVersion": "0.16.0" + }, + "status": {} + } +] diff --git a/pkg/kudoctl/cmd/get/testdata/get-operators.txt.golden b/pkg/kudoctl/cmd/get/testdata/get-operators.txt.golden new file mode 100644 index 000000000..7c8b4fe9a --- /dev/null +++ b/pkg/kudoctl/cmd/get/testdata/get-operators.txt.golden @@ -0,0 +1,4 @@ +List of current installed operators in namespace "default": +. +└── some-operator + diff --git a/pkg/kudoctl/cmd/get/testdata/get-operators.yaml.golden b/pkg/kudoctl/cmd/get/testdata/get-operators.yaml.golden new file mode 100644 index 000000000..f297c5a4f --- /dev/null +++ b/pkg/kudoctl/cmd/get/testdata/get-operators.yaml.golden @@ -0,0 +1,13 @@ +--- +apiVersion: kudo.dev/v1beta1 +kind: Operator +metadata: + creationTimestamp: null + name: some-operator + namespace: default +spec: + description: A fancy Operator + kudoVersion: 0.16.0 +status: {} + +... diff --git a/pkg/kudoctl/cmd/get/testdata/get-operatorversions.json.golden b/pkg/kudoctl/cmd/get/testdata/get-operatorversions.json.golden new file mode 100644 index 000000000..0b9fcd029 --- /dev/null +++ b/pkg/kudoctl/cmd/get/testdata/get-operatorversions.json.golden @@ -0,0 +1,20 @@ +[ + { + "kind": "OperatorVersion", + "apiVersion": "kudo.dev/v1beta1", + "metadata": { + "name": "some-operator-0.1.0", + "namespace": "default", + "creationTimestamp": null + }, + "spec": { + "operator": { + "kind": "Operator", + "name": "some-operator", + "apiVersion": "kudo.dev/v1beta1" + }, + "version": "0.1.0" + }, + "status": {} + } +] diff --git a/pkg/kudoctl/cmd/get/testdata/get-operatorversions.txt.golden b/pkg/kudoctl/cmd/get/testdata/get-operatorversions.txt.golden new file mode 100644 index 000000000..3267b2142 --- /dev/null +++ b/pkg/kudoctl/cmd/get/testdata/get-operatorversions.txt.golden @@ -0,0 +1,4 @@ +List of current installed operatorversions in namespace "default": +. +└── some-operator-0.1.0 + diff --git a/pkg/kudoctl/cmd/get/testdata/get-operatorversions.yaml.golden b/pkg/kudoctl/cmd/get/testdata/get-operatorversions.yaml.golden new file mode 100644 index 000000000..9940c45f5 --- /dev/null +++ b/pkg/kudoctl/cmd/get/testdata/get-operatorversions.yaml.golden @@ -0,0 +1,16 @@ +--- +apiVersion: kudo.dev/v1beta1 +kind: OperatorVersion +metadata: + creationTimestamp: null + name: some-operator-0.1.0 + namespace: default +spec: + operator: + apiVersion: kudo.dev/v1beta1 + kind: Operator + name: some-operator + version: 0.1.0 +status: {} + +... diff --git a/pkg/kudoctl/cmd/root.go b/pkg/kudoctl/cmd/root.go index e30d47c7c..a70dc17d5 100644 --- a/pkg/kudoctl/cmd/root.go +++ b/pkg/kudoctl/cmd/root.go @@ -62,7 +62,7 @@ and serves as an API aggregation layer. cmd.AddCommand(newUpdateCmd()) cmd.AddCommand(newUninstallCmd()) cmd.AddCommand(newPackageCmd(fs, cmd.OutOrStdout())) - cmd.AddCommand(newGetCmd()) + cmd.AddCommand(newGetCmd(cmd.OutOrStdout())) cmd.AddCommand(newPlanCmd(cmd.OutOrStdout())) cmd.AddCommand(newRepoCmd(fs, cmd.OutOrStdout())) cmd.AddCommand(newSearchCmd(fs, cmd.OutOrStdout())) diff --git a/pkg/kudoctl/util/kudo/kudo.go b/pkg/kudoctl/util/kudo/kudo.go index df5a44fb3..72cbc0d79 100644 --- a/pkg/kudoctl/util/kudo/kudo.go +++ b/pkg/kudoctl/util/kudo/kudo.go @@ -337,18 +337,49 @@ func (c *Client) IsInstanceByNameDone(name string, namespace string, oldInstance return c.IsInstanceDone(instance, oldInstance) } -// ListInstances lists all instances of given operator installed in the cluster in a given ns -func (c *Client) ListInstances(namespace string) ([]string, error) { +// ListInstances lists all instances installed in the cluster in a given ns +func (c *Client) ListInstances(namespace string) ([]runtime.Object, error) { instances, err := c.kudoClientset.KudoV1beta1().Instances(namespace).List(context.TODO(), v1.ListOptions{}) if err != nil { return nil, err } - existingInstances := []string{} + existingItems := []runtime.Object{} for _, v := range instances.Items { - existingInstances = append(existingInstances, v.Name) + v := v + existingItems = append(existingItems, &v) } - return existingInstances, nil + return existingItems, nil +} + +// ListOperatorVersions lists all operatorversions installed in the cluster in a given ns +func (c *Client) ListOperatorVersions(namespace string) ([]runtime.Object, error) { + ovs, err := c.kudoClientset.KudoV1beta1().OperatorVersions(namespace).List(context.TODO(), v1.ListOptions{}) + if err != nil { + return nil, err + } + + existingItems := []runtime.Object{} + for _, v := range ovs.Items { + v := v + existingItems = append(existingItems, &v) + } + return existingItems, nil +} + +// ListOperators lists all operators installed in the cluster in a given ns +func (c *Client) ListOperators(namespace string) ([]runtime.Object, error) { + operators, err := c.kudoClientset.KudoV1beta1().Operators(namespace).List(context.TODO(), v1.ListOptions{}) + if err != nil { + return nil, err + } + + existingItems := []runtime.Object{} + for _, v := range operators.Items { + v := v + existingItems = append(existingItems, &v) + } + return existingItems, nil } // OperatorVersionsInstalled lists all the versions of given operator installed in the cluster in given ns From a25a63cd18b3eca714317bb59550e58992c5ce62 Mon Sep 17 00:00:00 2001 From: Andreas Neumann Date: Mon, 24 Aug 2020 14:11:09 +0200 Subject: [PATCH 3/5] Reference slice items directly Signed-off-by: Andreas Neumann --- pkg/kudoctl/util/kudo/kudo.go | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/pkg/kudoctl/util/kudo/kudo.go b/pkg/kudoctl/util/kudo/kudo.go index 72cbc0d79..c42e3ae95 100644 --- a/pkg/kudoctl/util/kudo/kudo.go +++ b/pkg/kudoctl/util/kudo/kudo.go @@ -345,9 +345,8 @@ func (c *Client) ListInstances(namespace string) ([]runtime.Object, error) { } existingItems := []runtime.Object{} - for _, v := range instances.Items { - v := v - existingItems = append(existingItems, &v) + for i := range instances.Items { + existingItems = append(existingItems, &instances.Items[i]) } return existingItems, nil } @@ -360,9 +359,8 @@ func (c *Client) ListOperatorVersions(namespace string) ([]runtime.Object, error } existingItems := []runtime.Object{} - for _, v := range ovs.Items { - v := v - existingItems = append(existingItems, &v) + for i := range ovs.Items { + existingItems = append(existingItems, &ovs.Items[i]) } return existingItems, nil } @@ -375,9 +373,8 @@ func (c *Client) ListOperators(namespace string) ([]runtime.Object, error) { } existingItems := []runtime.Object{} - for _, v := range operators.Items { - v := v - existingItems = append(existingItems, &v) + for i := range operators.Items { + existingItems = append(existingItems, &operators.Items[i]) } return existingItems, nil } From a4e7606c1462449a6aab00b0a341b501636030eb Mon Sep 17 00:00:00 2001 From: Andreas Neumann Date: Mon, 24 Aug 2020 14:48:46 +0200 Subject: [PATCH 4/5] Fixed integration test Signed-off-by: Andreas Neumann --- pkg/kudoctl/util/kudo/kudo_test.go | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/pkg/kudoctl/util/kudo/kudo_test.go b/pkg/kudoctl/util/kudo/kudo_test.go index 918d5c315..960086a8d 100644 --- a/pkg/kudoctl/util/kudo/kudo_test.go +++ b/pkg/kudoctl/util/kudo/kudo_test.go @@ -8,7 +8,9 @@ import ( "github.com/stretchr/testify/assert" v1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" kubefake "k8s.io/client-go/kubernetes/fake" "github.com/kudobuilder/kudo/pkg/apis/kudo/v1beta1" @@ -167,13 +169,13 @@ func TestKudoClient_ListInstances(t *testing.T) { } tests := []struct { - expectedInstances []string + expectedInstances []runtime.Object namespace string obj *v1beta1.Instance }{ - {expectedInstances: []string{}, namespace: installNamespace}, // 1 - {expectedInstances: []string{obj.Name}, namespace: installNamespace, obj: &obj}, // 2 - {expectedInstances: []string{}, namespace: "otherns", obj: &obj}, // 3 + {expectedInstances: []runtime.Object{}, namespace: installNamespace}, // 1 + {expectedInstances: []runtime.Object{&obj}, namespace: installNamespace, obj: &obj}, // 2 + {expectedInstances: []runtime.Object{}, namespace: "otherns", obj: &obj}, // 3 } for i, tt := range tests { @@ -192,8 +194,17 @@ func TestKudoClient_ListInstances(t *testing.T) { // test if OperatorVersion exists in namespace existingInstances, _ := k2o.ListInstances(tt.namespace) - if !reflect.DeepEqual(tt.expectedInstances, existingInstances) { - t.Errorf("%d:\nexpected: %v\n got: %v", i+1, tt.expectedInstances, existingInstances) + + assert.Equal(t, len(tt.expectedInstances), len(existingInstances)) + + metadataAccessor := meta.NewAccessor() + for i := range existingInstances { + expectedName, err := metadataAccessor.Name(tt.expectedInstances[i]) + assert.NoError(t, err) + existingName, err := metadataAccessor.Name(existingInstances[i]) + assert.NoError(t, err) + + assert.Equal(t, expectedName, existingName) } } } From ce8e553283e21e77cc8a46d70b0e06e34864d68c Mon Sep 17 00:00:00 2001 From: Andreas Neumann Date: Tue, 25 Aug 2020 16:26:18 +0200 Subject: [PATCH 5/5] Review comments Signed-off-by: Andreas Neumann --- pkg/kudoctl/cmd/get/get.go | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/pkg/kudoctl/cmd/get/get.go b/pkg/kudoctl/cmd/get/get.go index 6bfc03389..a738e6ec0 100644 --- a/pkg/kudoctl/cmd/get/get.go +++ b/pkg/kudoctl/cmd/get/get.go @@ -16,12 +16,20 @@ import ( type CmdOpts struct { Out io.Writer - Output output.Type + Client *kudo.Client + Output output.Type Namespace string - Client *kudo.Client } +const ( + All = "all" + + Instances = "instances" + Operators = "operators" + OperatorVersions = "operatorversions" +) + // Run returns the errors associated with cmd env func Run(args []string, opts CmdOpts) error { if err := opts.Output.Validate(); err != nil { @@ -35,20 +43,20 @@ func Run(args []string, opts CmdOpts) error { var objs []runtime.Object switch args[0] { - case "instances": + case Instances: objs, err = opts.Client.ListInstances(opts.Namespace) - case "operators": + case Operators: objs, err = opts.Client.ListOperators(opts.Namespace) - case "operatorversions": + case OperatorVersions: objs, err = opts.Client.ListOperatorVersions(opts.Namespace) - case "all": + case All: return runGetAll(opts) } if err != nil { return fmt.Errorf("failed to retrieve objects: %v", err) } - if opts.Output != "" { + if opts.Output.IsFormattedOutput() { outObj := []interface{}{} for _, o := range objs { outObj = append(outObj, o) @@ -66,7 +74,7 @@ func Run(args []string, opts CmdOpts) error { } tree.AddBranch(name) } - _, _ = fmt.Fprintf(opts.Out, "List of current installed %s in namespace \"%s\":\n", args[0], opts.Namespace) + _, _ = fmt.Fprintf(opts.Out, "List of current installed %s in namespace %q:\n", args[0], opts.Namespace) _, _ = fmt.Fprintln(opts.Out, tree.String()) return err } @@ -85,7 +93,7 @@ func runGetAll(opts CmdOpts) error { return fmt.Errorf("failed to get operators") } - if opts.Output != "" { + if opts.Output.IsFormattedOutput() { outObj := []interface{}{} for _, o := range operators { outObj = append(outObj, o) @@ -124,7 +132,7 @@ func printAllTree(opts CmdOpts, operators, operatorversions, instances []runtime } } - _, _ = fmt.Fprintf(opts.Out, "List of current installed operators including versions and instances in namespace \"%s\":\n", opts.Namespace) + _, _ = fmt.Fprintf(opts.Out, "List of current installed operators including versions and instances in namespace %q:\n", opts.Namespace) _, _ = fmt.Fprintln(opts.Out, rootTree.String()) return nil @@ -136,9 +144,9 @@ func validate(args []string) error { } switch args[0] { - case "instances", "operators", "operatorversions": + case Instances, Operators, OperatorVersions: fallthrough - case "all": + case All: return nil default: return fmt.Errorf(`expecting one of "instances, operators, operatorversions or all" and not %q`, args[0])