Implement completion for "kops promote keypair"

This commit is contained in:
John Gardiner Myers 2021-06-29 19:47:05 -07:00
parent db4c5dc178
commit d8e592c421
6 changed files with 124 additions and 70 deletions

View File

@ -28,6 +28,8 @@ import (
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/klog/v2"
kopsapi "k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/client/simple"
"k8s.io/kops/pkg/commands/commandutils"
"k8s.io/kops/cmd/kops/util"
@ -82,6 +84,10 @@ var rotatableKeysets = sets.NewString(
"service-account",
)
func rotatableKeysetFilter(name string, _ *fi.Keyset) bool {
return rotatableKeysets.Has(name)
}
// NewCmdCreateKeypair returns a create keypair command.
func NewCmdCreateKeypair(f *util.Factory, out io.Writer) *cobra.Command {
options := &CreateKeypairOptions{}
@ -226,45 +232,51 @@ func RunCreateKeypair(ctx context.Context, f *util.Factory, out io.Writer, optio
return nil
}
func completeCreateKeyset(options *CreateKeypairOptions, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
commandutils.ConfigureKlogForCompletion()
options.ClusterName = rootCommand.ClusterName(false)
if options.ClusterName == "" {
return []string{"--name"}, cobra.ShellCompDirectiveNoFileComp
}
ctx := context.TODO()
cluster, err := GetCluster(ctx, &rootCommand, options.ClusterName)
if err != nil {
return commandutils.CompletionError("getting cluster", err)
}
clientSet, err := rootCommand.Clientset()
if err != nil {
return commandutils.CompletionError("getting clientset", err)
}
func completeKeyset(cluster *kopsapi.Cluster, clientSet simple.Clientset, args []string, filter func(name string, keyset *fi.Keyset) bool) (keyset *fi.Keyset, keyStore fi.CAStore, completions []string, directive cobra.ShellCompDirective) {
keyStore, err := clientSet.KeyStore(cluster)
if err != nil {
return commandutils.CompletionError("getting keystore", err)
completions, directive := commandutils.CompletionError("getting keystore", err)
return nil, nil, completions, directive
}
if len(args) == 0 {
list, err := keyStore.ListKeysets()
if err != nil {
return commandutils.CompletionError("listing keysets", err)
completions, directive := commandutils.CompletionError("listing keystore", err)
return nil, nil, completions, directive
}
var keysets []string
for name := range list {
if rotatableKeysets.Has(name) {
for name, keyset := range list {
if filter(name, keyset) {
keysets = append(keysets, name)
}
}
return keysets, cobra.ShellCompDirectiveNoFileComp
return nil, nil, keysets, cobra.ShellCompDirectiveNoFileComp
}
keyset, err = keyStore.FindKeyset(args[0])
if err != nil {
completions, directive := commandutils.CompletionError("finding keyset", err)
return nil, nil, completions, directive
}
return keyset, keyStore, nil, 0
}
func completeCreateKeyset(options *CreateKeypairOptions, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
commandutils.ConfigureKlogForCompletion()
ctx := context.TODO()
cluster, clientSet, completions, directive := GetClusterForCompletion(ctx, &rootCommand)
if cluster == nil {
return completions, directive
}
keyset, _, completions, directive := completeKeyset(cluster, clientSet, args, rotatableKeysetFilter)
if keyset == nil {
return completions, directive
}
if len(args) > 1 {

View File

@ -22,27 +22,16 @@ import (
"github.com/spf13/cobra"
"k8s.io/kops/cmd/kops/util"
"k8s.io/kubectl/pkg/util/i18n"
"k8s.io/kubectl/pkg/util/templates"
)
var (
promoteLong = templates.LongDesc(i18n.T(`
Promote a resource.`))
promoteExample = templates.Examples(i18n.T(`
# Promote the newest ca keypair to be the primary.
kops promote keypair ca
`))
promoteShort = i18n.T(`Promote a resource.`)
)
func NewCmdPromote(f *util.Factory, out io.Writer) *cobra.Command {
cmd := &cobra.Command{
Use: "promote",
Short: promoteShort,
Long: promoteLong,
Example: promoteExample,
Use: "promote",
Short: promoteShort,
}
// create subcommands

View File

@ -23,8 +23,9 @@ import (
"math/big"
"github.com/spf13/cobra"
"k8s.io/klog/v2"
"k8s.io/kops/cmd/kops/util"
"k8s.io/kops/pkg/commands/commandutils"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kubectl/pkg/util/i18n"
"k8s.io/kubectl/pkg/util/templates"
)
@ -58,35 +59,39 @@ func NewCmdPromoteKeypair(f *util.Factory, out io.Writer) *cobra.Command {
options := &PromoteKeypairOptions{}
cmd := &cobra.Command{
Use: "keypair KEYSET [ID]",
Use: "keypair keyset [id]",
Short: promoteKeypairShort,
Long: promoteKeypairLong,
Example: promoteKeypairExample,
Run: func(cmd *cobra.Command, args []string) {
ctx := context.TODO()
Args: func(cmd *cobra.Command, args []string) error {
options.ClusterName = rootCommand.ClusterName(true)
if options.ClusterName == "" {
exitWithError(fmt.Errorf("--name is required"))
return
return fmt.Errorf("--name is required")
}
if len(args) == 0 {
exitWithError(fmt.Errorf("must specify name of keyset promote keypair in"))
}
if len(args) > 2 {
exitWithError(fmt.Errorf("can only promote to one keyset at a time"))
return fmt.Errorf("must specify name of keyset promote keypair in")
}
options.Keyset = args[0]
if len(args) > 2 {
return fmt.Errorf("can only promote to one keyset at a time")
}
if len(args) > 1 {
options.KeypairID = args[1]
}
err := RunPromoteKeypair(ctx, f, out, options)
if err != nil {
exitWithError(err)
}
return nil
},
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return completePromoteKeyset(options, args, toComplete)
},
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.TODO()
return RunPromoteKeypair(ctx, f, out, options)
},
}
@ -101,17 +106,17 @@ func RunPromoteKeypair(ctx context.Context, f *util.Factory, out io.Writer, opti
cluster, err := GetCluster(ctx, f, options.ClusterName)
if err != nil {
return fmt.Errorf("error getting cluster: %q: %v", options.ClusterName, err)
return fmt.Errorf("getting cluster: %q: %v", options.ClusterName, err)
}
clientSet, err := f.Clientset()
if err != nil {
return fmt.Errorf("error getting clientset: %v", err)
return fmt.Errorf("getting clientset: %v", err)
}
keyStore, err := clientSet.KeyStore(cluster)
if err != nil {
return fmt.Errorf("error getting keystore: %v", err)
return fmt.Errorf("getting keystore: %v", err)
}
keyset, err := keyStore.FindKeyset(options.Keyset)
@ -151,9 +156,46 @@ func RunPromoteKeypair(ctx context.Context, f *util.Factory, out io.Writer, opti
keyset.Primary = keyset.Items[keypairID]
err = keyStore.StoreKeyset(options.Keyset, keyset)
if err != nil {
return fmt.Errorf("error writing keyset: %v", err)
return fmt.Errorf("writing keyset: %v", err)
}
klog.Infof("promoted keypair %s", keypairID)
fmt.Fprintf(out, "promoted keypair %s", keypairID)
return nil
}
func completePromoteKeyset(options *PromoteKeypairOptions, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
commandutils.ConfigureKlogForCompletion()
ctx := context.TODO()
cluster, clientSet, completions, directive := GetClusterForCompletion(ctx, &rootCommand)
if cluster == nil {
return completions, directive
}
keyset, _, completions, directive := completeKeyset(cluster, clientSet, args, rotatableKeysetFilter)
if keyset == nil {
return completions, directive
}
if len(args) == 1 {
return completeKeypairID(keyset, func(keyset *fi.Keyset, item *fi.KeysetItem) bool {
return item.DistrustTimestamp == nil && item.Id != keyset.Primary.Id
})
}
if len(args) > 2 {
return commandutils.CompletionError("too many arguments", nil)
}
return nil, cobra.ShellCompDirectiveNoFileComp
}
func completeKeypairID(keyset *fi.Keyset, filter func(keyset *fi.Keyset, item *fi.KeysetItem) bool) (completions []string, directive cobra.ShellCompDirective) {
for _, item := range keyset.Items {
if filter(keyset, item) {
completions = append(completions, item.Id)
}
}
return completions, cobra.ShellCompDirectiveNoFileComp
}

View File

@ -302,6 +302,28 @@ func GetCluster(ctx context.Context, factory commandutils.Factory, clusterName s
return cluster, nil
}
func GetClusterForCompletion(ctx context.Context, factory commandutils.Factory) (cluster *kopsapi.Cluster, clientSet simple.Clientset, completions []string, directive cobra.ShellCompDirective) {
clusterName := rootCommand.ClusterName(false)
if clusterName == "" {
return nil, nil, []string{"--name"}, cobra.ShellCompDirectiveNoFileComp
}
cluster, err := GetCluster(ctx, &rootCommand, clusterName)
if err != nil {
completions, directive := commandutils.CompletionError("getting cluster", err)
return nil, nil, completions, directive
}
clientSet, err = rootCommand.Clientset()
if err != nil {
completions, directive := commandutils.CompletionError("getting clientset", err)
return nil, nil, completions, directive
}
return cluster, clientSet, nil, 0
}
// ConsumeStdin reads all the bytes available from stdin
func ConsumeStdin() ([]byte, error) {
file := os.Stdin

View File

@ -5,17 +5,6 @@
Promote a resource.
### Synopsis
Promote a resource.
### Examples
```
# Promote the newest ca keypair to be the primary.
kops promote keypair ca
```
### Options
```

View File

@ -10,7 +10,7 @@ Promote a keypair to be the primary, used for signing.
Promote a keypair to be the primary, used for signing.
```
kops promote keypair KEYSET [ID] [flags]
kops promote keypair keyset [id] [flags]
```
### Examples