diff --git a/cmd/kops/delete_cluster.go b/cmd/kops/delete_cluster.go index 933f142de5..b8a3451aa4 100644 --- a/cmd/kops/delete_cluster.go +++ b/cmd/kops/delete_cluster.go @@ -71,7 +71,7 @@ func NewCmdDeleteCluster(f *util.Factory, out io.Writer) *cobra.Command { Long: deleteClusterLong, Example: deleteClusterExample, Args: rootCommand.clusterNameArgsNoKubeconfig(&options.ClusterName), - ValidArgsFunction: commandutils.CompleteClusterName(&rootCommand, true), + ValidArgsFunction: commandutils.CompleteClusterName(&rootCommand, true, false), RunE: func(cmd *cobra.Command, args []string) error { return RunDeleteCluster(context.TODO(), f, out, options) }, diff --git a/cmd/kops/edit_cluster.go b/cmd/kops/edit_cluster.go index 576ff20d63..25e56dd411 100644 --- a/cmd/kops/edit_cluster.go +++ b/cmd/kops/edit_cluster.go @@ -79,7 +79,7 @@ func NewCmdEditCluster(f *util.Factory, out io.Writer) *cobra.Command { Long: editClusterLong, Example: editClusterExample, Args: rootCommand.clusterNameArgs(&options.ClusterName), - ValidArgsFunction: commandutils.CompleteClusterName(&rootCommand, true), + ValidArgsFunction: commandutils.CompleteClusterName(&rootCommand, true, false), RunE: func(cmd *cobra.Command, args []string) error { return RunEditCluster(context.TODO(), f, out, options) }, diff --git a/cmd/kops/export_kubeconfig.go b/cmd/kops/export_kubeconfig.go index 7af3272e69..56b1eb4ce8 100644 --- a/cmd/kops/export_kubeconfig.go +++ b/cmd/kops/export_kubeconfig.go @@ -88,7 +88,7 @@ func NewCmdExportKubeconfig(f *util.Factory, out io.Writer) *cobra.Command { return rootCommand.clusterNameArgs(&options.ClusterName)(cmd, args) } }, - ValidArgsFunction: commandutils.CompleteClusterName(&rootCommand, true), + ValidArgsFunction: commandutils.CompleteClusterName(&rootCommand, true, false), RunE: func(cmd *cobra.Command, args []string) error { return RunExportKubeconfig(context.TODO(), f, out, options, args) }, diff --git a/cmd/kops/get.go b/cmd/kops/get.go index 9f2bfd98db..6e32a971dd 100644 --- a/cmd/kops/get.go +++ b/cmd/kops/get.go @@ -75,7 +75,7 @@ func NewCmdGet(f *util.Factory, out io.Writer) *cobra.Command { Long: getLong, Example: getExample, Args: rootCommand.clusterNameArgs(&options.ClusterName), - ValidArgsFunction: commandutils.CompleteClusterName(&rootCommand, true), + ValidArgsFunction: commandutils.CompleteClusterName(&rootCommand, true, false), RunE: func(cmd *cobra.Command, args []string) error { return RunGet(context.TODO(), &rootCommand, out, options) }, diff --git a/cmd/kops/get_assets.go b/cmd/kops/get_assets.go index 4b1c0d1da9..cea529ff30 100644 --- a/cmd/kops/get_assets.go +++ b/cmd/kops/get_assets.go @@ -89,7 +89,7 @@ func NewCmdGetAssets(f *util.Factory, out io.Writer, getOptions *GetOptions) *co Long: getAssetsLong, Example: getAssetsExample, Args: rootCommand.clusterNameArgs(&options.ClusterName), - ValidArgsFunction: commandutils.CompleteClusterName(&rootCommand, true), + ValidArgsFunction: commandutils.CompleteClusterName(&rootCommand, true, false), RunE: func(cmd *cobra.Command, args []string) error { return RunGetAssets(context.TODO(), f, out, &options) }, diff --git a/cmd/kops/get_cluster.go b/cmd/kops/get_cluster.go index 3890152e9e..fc216a2a00 100644 --- a/cmd/kops/get_cluster.go +++ b/cmd/kops/get_cluster.go @@ -90,29 +90,26 @@ func NewCmdGetCluster(f *util.Factory, out io.Writer, getOptions *GetOptions) *c } cmd := &cobra.Command{ - Use: "clusters", + Use: "clusters [CLUSTER]...", Aliases: []string{"cluster"}, Short: getClusterShort, Long: getClusterLong, Example: getClusterExample, - Run: func(cmd *cobra.Command, args []string) { - ctx := context.TODO() + Args: func(cmd *cobra.Command, args []string) error { if len(args) != 0 { - options.ClusterNames = append(options.ClusterNames, args...) - } - - if rootCommand.clusterName != "" { - if len(args) != 0 { - exitWithError(fmt.Errorf("cannot mix --name for cluster with positional arguments")) + if rootCommand.clusterName != "" { + return fmt.Errorf("cannot mix --name for cluster with positional arguments") } - - options.ClusterNames = append(options.ClusterNames, rootCommand.clusterName) + options.ClusterNames = append(options.ClusterNames, args...) + } else { + options.ClusterNames = append(options.ClusterNames, rootCommand.ClusterName(true)) } - err := RunGetClusters(ctx, &rootCommand, os.Stdout, &options) - if err != nil { - exitWithError(err) - } + return nil + }, + ValidArgsFunction: commandutils.CompleteClusterName(&rootCommand, false, true), + RunE: func(cmd *cobra.Command, args []string) error { + return RunGetClusters(context.TODO(), &rootCommand, os.Stdout, &options) }, } diff --git a/cmd/kops/rollingupdate_cluster.go b/cmd/kops/rollingupdate_cluster.go index 0d642f4770..351d60dd13 100644 --- a/cmd/kops/rollingupdate_cluster.go +++ b/cmd/kops/rollingupdate_cluster.go @@ -167,7 +167,7 @@ func NewCmdRollingUpdateCluster(f *util.Factory, out io.Writer) *cobra.Command { Long: rollingupdateLong, Example: rollingupdateExample, Args: rootCommand.clusterNameArgs(&options.ClusterName), - ValidArgsFunction: commandutils.CompleteClusterName(&rootCommand, true), + ValidArgsFunction: commandutils.CompleteClusterName(&rootCommand, true, false), RunE: func(cmd *cobra.Command, args []string) error { return RunRollingUpdateCluster(context.TODO(), f, out, &options) }, diff --git a/cmd/kops/root.go b/cmd/kops/root.go index 40dff9221d..3d99f9e9e3 100644 --- a/cmd/kops/root.go +++ b/cmd/kops/root.go @@ -140,7 +140,7 @@ func NewCmdRoot(f *util.Factory, out io.Writer) *cobra.Command { defaultClusterName := os.Getenv("KOPS_CLUSTER_NAME") cmd.PersistentFlags().StringVarP(&rootCommand.clusterName, "name", "", defaultClusterName, "Name of cluster. Overrides KOPS_CLUSTER_NAME environment variable") - cmd.RegisterFlagCompletionFunc("name", commandutils.CompleteClusterName(&rootCommand, false)) + cmd.RegisterFlagCompletionFunc("name", commandutils.CompleteClusterName(&rootCommand, false, false)) // create subcommands cmd.AddCommand(NewCmdCreate(f, out)) diff --git a/cmd/kops/toolbox_dump.go b/cmd/kops/toolbox_dump.go index 5b1aa64195..171e1b0e46 100644 --- a/cmd/kops/toolbox_dump.go +++ b/cmd/kops/toolbox_dump.go @@ -82,7 +82,7 @@ func NewCmdToolboxDump(f *util.Factory, out io.Writer) *cobra.Command { Long: toolboxDumpLong, Example: toolboxDumpExample, Args: rootCommand.clusterNameArgs(&options.ClusterName), - ValidArgsFunction: commandutils.CompleteClusterName(&rootCommand, true), + ValidArgsFunction: commandutils.CompleteClusterName(&rootCommand, true, false), RunE: func(cmd *cobra.Command, args []string) error { return RunToolboxDump(context.TODO(), f, out, options) }, diff --git a/cmd/kops/toolbox_template.go b/cmd/kops/toolbox_template.go index fafc86c55f..b64682a406 100644 --- a/cmd/kops/toolbox_template.go +++ b/cmd/kops/toolbox_template.go @@ -86,7 +86,7 @@ func NewCmdToolboxTemplate(f *util.Factory, out io.Writer) *cobra.Command { Long: toolboxTemplatingLong, Example: toolboxTemplatingExample, Args: rootCommand.clusterNameArgs(&options.ClusterName), - ValidArgsFunction: commandutils.CompleteClusterName(&rootCommand, true), + ValidArgsFunction: commandutils.CompleteClusterName(&rootCommand, true, false), RunE: func(cmd *cobra.Command, args []string) error { return RunToolBoxTemplate(f, out, options) }, diff --git a/cmd/kops/update_cluster.go b/cmd/kops/update_cluster.go index a8810b1650..e4a8587701 100644 --- a/cmd/kops/update_cluster.go +++ b/cmd/kops/update_cluster.go @@ -106,7 +106,7 @@ func NewCmdUpdateCluster(f *util.Factory, out io.Writer) *cobra.Command { Long: updateClusterLong, Example: updateClusterExample, Args: rootCommand.clusterNameArgs(&options.ClusterName), - ValidArgsFunction: commandutils.CompleteClusterName(&rootCommand, true), + ValidArgsFunction: commandutils.CompleteClusterName(&rootCommand, true, false), RunE: func(cmd *cobra.Command, args []string) error { _, err := RunUpdateCluster(context.TODO(), f, out, options) return err diff --git a/cmd/kops/upgrade_cluster.go b/cmd/kops/upgrade_cluster.go index 31ecbd1346..ef54538e9b 100644 --- a/cmd/kops/upgrade_cluster.go +++ b/cmd/kops/upgrade_cluster.go @@ -70,7 +70,7 @@ func NewCmdUpgradeCluster(f *util.Factory, out io.Writer) *cobra.Command { Long: upgradeClusterLong, Example: upgradeClusterExample, Args: rootCommand.clusterNameArgs(&options.ClusterName), - ValidArgsFunction: commandutils.CompleteClusterName(&rootCommand, true), + ValidArgsFunction: commandutils.CompleteClusterName(&rootCommand, true, false), RunE: func(cmd *cobra.Command, args []string) error { ctx := context.TODO() diff --git a/cmd/kops/validate_cluster.go b/cmd/kops/validate_cluster.go index 37554a30e1..6bdedc2397 100644 --- a/cmd/kops/validate_cluster.go +++ b/cmd/kops/validate_cluster.go @@ -83,7 +83,7 @@ func NewCmdValidateCluster(f *util.Factory, out io.Writer) *cobra.Command { Long: validateClusterLong, Example: validateClusterExample, Args: rootCommand.clusterNameArgs(&options.ClusterName), - ValidArgsFunction: commandutils.CompleteClusterName(&rootCommand, true), + ValidArgsFunction: commandutils.CompleteClusterName(&rootCommand, true, false), RunE: func(cmd *cobra.Command, args []string) error { result, err := RunValidateCluster(context.TODO(), f, out, options) if err != nil { diff --git a/docs/cli/kops_get_clusters.md b/docs/cli/kops_get_clusters.md index a4f8c69895..7bc9b9cc81 100644 --- a/docs/cli/kops_get_clusters.md +++ b/docs/cli/kops_get_clusters.md @@ -10,7 +10,7 @@ Get one or many clusters. Display one or many cluster resources. ``` -kops get clusters [flags] +kops get clusters [CLUSTER]... [flags] ``` ### Examples diff --git a/pkg/commands/commandutils/BUILD.bazel b/pkg/commands/commandutils/BUILD.bazel index 69d91cac2b..895c055a06 100644 --- a/pkg/commands/commandutils/BUILD.bazel +++ b/pkg/commands/commandutils/BUILD.bazel @@ -16,6 +16,7 @@ go_library( "//pkg/client/simple:go_default_library", "//vendor/github.com/spf13/cobra:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library", "//vendor/k8s.io/klog/v2:go_default_library", ], ) diff --git a/pkg/commands/commandutils/cluster.go b/pkg/commands/commandutils/cluster.go index 93652838d1..209f47d546 100644 --- a/pkg/commands/commandutils/cluster.go +++ b/pkg/commands/commandutils/cluster.go @@ -21,10 +21,11 @@ import ( "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/sets" ) // CompleteClusterName returns a Cobra completion function for cluster names. -func CompleteClusterName(f Factory, suppressIfArgs bool) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { +func CompleteClusterName(f Factory, suppressIfArgs bool, suppressArgs bool) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { if suppressIfArgs && len(args) > 0 { return nil, cobra.ShellCompDirectiveNoFileComp @@ -43,8 +44,14 @@ func CompleteClusterName(f Factory, suppressIfArgs bool) func(cmd *cobra.Command } var clusterNames []string + alreadySelected := sets.NewString() + if suppressArgs { + alreadySelected = alreadySelected.Insert(args...) + } for _, cluster := range list.Items { - clusterNames = append(clusterNames, cluster.Name) + if !alreadySelected.Has(cluster.Name) { + clusterNames = append(clusterNames, cluster.Name) + } } return clusterNames, cobra.ShellCompDirectiveNoFileComp