Improve completion for kops root command

This commit is contained in:
John Gardiner Myers 2021-06-27 21:32:16 -07:00
parent 6514dbf621
commit 26a5aa179b
8 changed files with 159 additions and 9 deletions

View File

@ -28,6 +28,7 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/kops/cmd/kops/util"
api "k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/commands/commandutils"
"k8s.io/kops/pkg/kopscodecs"
"k8s.io/kubectl/pkg/util/i18n"
"k8s.io/kubectl/pkg/util/templates"
@ -116,7 +117,7 @@ func NewCmdGet(f *util.Factory, out io.Writer) *cobra.Command {
return cmd
}
func RunGet(ctx context.Context, f Factory, out io.Writer, options *GetOptions) error {
func RunGet(ctx context.Context, f commandutils.Factory, out io.Writer, options *GetOptions) error {
client, err := f.Clientset()
if err != nil {

View File

@ -31,6 +31,7 @@ import (
"k8s.io/kops/cmd/kops/util"
kopsapi "k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/apis/kops/registry"
"k8s.io/kops/pkg/commands/commandutils"
"k8s.io/kops/pkg/kopscodecs"
"k8s.io/kops/util/pkg/tables"
"k8s.io/kubectl/pkg/util/i18n"
@ -120,7 +121,7 @@ func NewCmdGetCluster(f *util.Factory, out io.Writer, getOptions *GetOptions) *c
return cmd
}
func RunGetClusters(ctx context.Context, f Factory, out io.Writer, options *GetClusterOptions) error {
func RunGetClusters(ctx context.Context, f commandutils.Factory, out io.Writer, options *GetClusterOptions) error {
client, err := f.Clientset()
if err != nil {
return err

View File

@ -36,6 +36,7 @@ import (
kopsapi "k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/client/simple"
"k8s.io/kops/pkg/commands"
"k8s.io/kops/pkg/commands/commandutils"
"k8s.io/kubectl/pkg/util/i18n"
"k8s.io/kubectl/pkg/util/templates"
)
@ -65,10 +66,6 @@ var (
rootShort = i18n.T(`kOps is Kubernetes Operations.`)
)
type Factory interface {
Clientset() (simple.Clientset, error)
}
type RootCmd struct {
util.FactoryOptions
@ -81,7 +78,7 @@ type RootCmd struct {
cobraCommand *cobra.Command
}
var _ Factory = &RootCmd{}
var _ commandutils.Factory = &RootCmd{}
var rootCommand = RootCmd{
cobraCommand: &cobra.Command{
@ -129,13 +126,18 @@ func NewCmdRoot(f *util.Factory, out io.Writer) *cobra.Command {
cmd.PersistentFlags().StringVar(&rootCommand.configFile, "config", "", "yaml config file (default is $HOME/.kops.yaml)")
viper.BindPFlag("config", cmd.PersistentFlags().Lookup("config"))
viper.SetDefault("config", "$HOME/.kops.yaml")
cmd.RegisterFlagCompletionFunc("config", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{"yaml", "json"}, cobra.ShellCompDirectiveFilterFileExt
})
cmd.PersistentFlags().StringVar(&rootCommand.RegistryPath, "state", "", "Location of state storage (kops 'config' file). Overrides KOPS_STATE_STORE environment variable")
viper.BindPFlag("KOPS_STATE_STORE", cmd.PersistentFlags().Lookup("state"))
viper.BindEnv("KOPS_STATE_STORE")
// TODO implement completion against VFS
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))
// create subcommands
cmd.AddCommand(NewCmdCompletion(f, out))
@ -290,7 +292,7 @@ func (c *RootCmd) Cluster(ctx context.Context) (*kopsapi.Cluster, error) {
return GetCluster(ctx, c.factory, clusterName)
}
func GetCluster(ctx context.Context, factory Factory, clusterName string) (*kopsapi.Cluster, error) {
func GetCluster(ctx context.Context, factory commandutils.Factory, clusterName string) (*kopsapi.Cluster, error) {
if clusterName == "" {
return nil, field.Required(field.NewPath("clusterName"), "Cluster name is required")
}

View File

@ -2,7 +2,19 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["exit.go"],
srcs = [
"cluster.go",
"error.go",
"exit.go",
"factory.go",
"klog.go",
],
importpath = "k8s.io/kops/pkg/commands/commandutils",
visibility = ["//visibility:public"],
deps = [
"//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/klog/v2:go_default_library",
],
)

View File

@ -0,0 +1,48 @@
/*
Copyright 2021 The Kubernetes Authors.
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 commandutils
import (
"context"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// CompleteClusterName returns a Cobra completion function for cluster names.
func CompleteClusterName(f Factory) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
ConfigureKlogForCompletion()
client, err := f.Clientset()
if err != nil {
return CompletionError("getting clientset", err)
}
list, err := client.ListClusters(context.TODO(), metav1.ListOptions{})
if err != nil {
return CompletionError("listing clusters", err)
}
var clusterNames []string
for _, cluster := range list.Items {
clusterNames = append(clusterNames, cluster.Name)
}
return clusterNames, cobra.ShellCompDirectiveNoFileComp
}
}

View File

@ -0,0 +1,29 @@
/*
Copyright 2021 The Kubernetes Authors.
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 commandutils
import (
"fmt"
"github.com/spf13/cobra"
)
// CompletionError a helper function to logs and return an error from a Cobra completion function.
func CompletionError(prefix string, err error) ([]string, cobra.ShellCompDirective) {
cobra.CompError(fmt.Sprintf("%s: %v", prefix, err))
return nil, cobra.ShellCompDirectiveError | cobra.ShellCompDirectiveNoFileComp
}

View File

@ -0,0 +1,23 @@
/*
Copyright 2021 The Kubernetes Authors.
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 commandutils
import "k8s.io/kops/pkg/client/simple"
type Factory interface {
Clientset() (simple.Clientset, error)
}

View File

@ -0,0 +1,34 @@
/*
Copyright 2021 The Kubernetes Authors.
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 commandutils
import (
"github.com/spf13/cobra"
"k8s.io/klog/v2"
)
// ConfigureKlogForCompletion configures Klog to not interfere with Cobra completion functions.
func ConfigureKlogForCompletion() {
klog.SetOutput(&toCompDebug{})
}
type toCompDebug struct{}
func (t toCompDebug) Write(p []byte) (n int, err error) {
cobra.CompDebug(string(p), false)
return len(p), nil
}