diff --git a/cmd/kops/delete.go b/cmd/kops/delete.go index c606507282..c6a37b00a0 100644 --- a/cmd/kops/delete.go +++ b/cmd/kops/delete.go @@ -27,7 +27,6 @@ import ( "k8s.io/kops/cmd/kops/util" kopsapi "k8s.io/kops/pkg/apis/kops" "k8s.io/kops/pkg/kopscodecs" - "k8s.io/kops/pkg/sshcredentials" "k8s.io/kops/util/pkg/text" "k8s.io/kops/util/pkg/vfs" "k8s.io/kubectl/pkg/util/i18n" @@ -134,19 +133,11 @@ func RunDelete(ctx context.Context, factory *util.Factory, out io.Writer, d *Del return err } case *kopsapi.SSHCredential: - fingerprint, err := sshcredentials.Fingerprint(v.Spec.PublicKey) - if err != nil { - klog.Error("unable to compute fingerprint for public key") - } - - options := &DeleteSecretOptions{ + options := &DeleteSSHPublicKeyOptions{ ClusterName: v.ObjectMeta.Labels[kopsapi.LabelClusterName], - SecretType: "SSHPublicKey", - SecretName: "admin", - SecretID: fingerprint, } - err = RunDeleteSecret(ctx, factory, out, options) + err = RunDeleteSSHPublicKey(ctx, factory, out, options) if err != nil { return err } diff --git a/cmd/kops/delete_secret.go b/cmd/kops/delete_secret.go index c233b8108a..9a25c128ed 100644 --- a/cmd/kops/delete_secret.go +++ b/cmd/kops/delete_secret.go @@ -22,60 +22,64 @@ import ( "io" "github.com/spf13/cobra" + "k8s.io/apimachinery/pkg/util/sets" "k8s.io/kops/cmd/kops/util" - "k8s.io/kops/upup/pkg/fi" + "k8s.io/kops/pkg/commands/commandutils" "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" ) var ( - deleteSecretLong = templates.LongDesc(i18n.T(` - Delete a secret.`)) - deleteSecretExample = templates.Examples(i18n.T(` - # Syntax: kops delete secret - # or kops delete secret - kops delete secret sshpublickey admin + # Delete the encryptionconfig secret + kops delete secret encryptionconfig `)) - deleteSecretShort = i18n.T(`Delete a secret`) + deleteSecretShort = i18n.T(`Delete one or more secrets.`) ) type DeleteSecretOptions struct { ClusterName string SecretType string - SecretName string - SecretID string + SecretNames []string } func NewCmdDeleteSecret(f *util.Factory, out io.Writer) *cobra.Command { options := &DeleteSecretOptions{} cmd := &cobra.Command{ - Use: "secret", + Use: "secret SECRET_NAME...", Short: deleteSecretShort, - Long: deleteSecretLong, Example: deleteSecretExample, - Run: func(cmd *cobra.Command, args []string) { - ctx := context.TODO() - - if len(args) != 2 && len(args) != 3 { - exitWithError(fmt.Errorf("Syntax: []")) + Args: func(cmd *cobra.Command, args []string) error { + if len(args) > 0 && args[0] == "sshpublickey" { + options.SecretType = args[0] + return nil } - options.SecretType = args[0] - options.SecretName = args[1] - if len(args) == 3 { - options.SecretID = args[2] + if len(args) > 0 && args[0] == "secret" { + args = args[1:] } + if len(args) == 0 { + return fmt.Errorf("secret name is required") + } + if len(args) > 1 { + return fmt.Errorf("too many arguments") + } + options.SecretNames = args options.ClusterName = rootCommand.ClusterName(true) - err := RunDeleteSecret(ctx, f, out, options) - if err != nil { - exitWithError(err) + if options.ClusterName == "" { + return fmt.Errorf("--name is required") } + + return nil + }, + ValidArgsFunction: completeSecretNames, + RunE: func(cmd *cobra.Command, args []string) error { + return RunDeleteSecret(context.TODO(), f, out, options) }, } @@ -83,16 +87,6 @@ func NewCmdDeleteSecret(f *util.Factory, out io.Writer) *cobra.Command { } func RunDeleteSecret(ctx context.Context, f *util.Factory, out io.Writer, options *DeleteSecretOptions) error { - if options.ClusterName == "" { - return fmt.Errorf("ClusterName is required") - } - if options.SecretType == "" { - return fmt.Errorf("SecretType is required") - } - if options.SecretName == "" { - return fmt.Errorf("SecretName is required") - } - if options.SecretType == "sshpublickey" { return RunDeleteSSHPublicKey(ctx, f, out, &DeleteSSHPublicKeyOptions{ ClusterName: options.ClusterName, @@ -114,34 +108,41 @@ func RunDeleteSecret(ctx context.Context, f *util.Factory, out io.Writer, option return err } - secrets, err := listSecrets(secretStore, options.SecretType, []string{options.SecretName}) - if err != nil { - return err - } - - if options.SecretID != "" { - var matches []*fi.KeystoreItem - for _, s := range secrets { - if s.ID == options.SecretID { - matches = append(matches, s) - } + for _, name := range options.SecretNames { + err = secretStore.DeleteSecret(name) + if err != nil { + return fmt.Errorf("deleting secret %q: %v", name, err) } - secrets = matches - } - - if len(secrets) == 0 { - return fmt.Errorf("secret not found") - } - - if len(secrets) != 1 { - // TODO: it would be friendly to print the matching keys - return fmt.Errorf("found multiple matching secrets; specify the id of the key") - } - - err = secretStore.DeleteSecret(secrets[0].Name) - if err != nil { - return fmt.Errorf("error deleting secret: %v", err) } return nil } + +func completeSecretNames(cmd *cobra.Command, args []string, complete string) ([]string, cobra.ShellCompDirective) { + commandutils.ConfigureKlogForCompletion() + ctx := context.TODO() + + cluster, clientSet, completions, directive := GetClusterForCompletion(ctx, &rootCommand, nil) + if cluster == nil { + return completions, directive + } + + secretStore, err := clientSet.SecretStore(cluster) + if err != nil { + return commandutils.CompletionError("constructing secret store", err) + } + + alreadySelected := sets.NewString(args...) + var secrets []string + items, err := listSecrets(secretStore, "secret", nil) + if err != nil { + return commandutils.CompletionError("listing secrets", err) + } + for _, secret := range items { + if !alreadySelected.Has(secret.Name) { + secrets = append(secrets, secret.Name) + } + } + + return secrets, cobra.ShellCompDirectiveNoFileComp +} diff --git a/docs/cli/kops_delete.md b/docs/cli/kops_delete.md index bd4e57c20f..07d50a9333 100644 --- a/docs/cli/kops_delete.md +++ b/docs/cli/kops_delete.md @@ -54,6 +54,6 @@ kops delete {-f FILENAME}... [flags] * [kops delete cluster](kops_delete_cluster.md) - Delete a cluster. * [kops delete instance](kops_delete_instance.md) - Delete an instance. * [kops delete instancegroup](kops_delete_instancegroup.md) - Delete instance group. -* [kops delete secret](kops_delete_secret.md) - Delete a secret +* [kops delete secret](kops_delete_secret.md) - Delete one or more secrets. * [kops delete sshpublickey](kops_delete_sshpublickey.md) - Delete an SSH public key. diff --git a/docs/cli/kops_delete_secret.md b/docs/cli/kops_delete_secret.md index c0d6c4a8e8..13213dfc64 100644 --- a/docs/cli/kops_delete_secret.md +++ b/docs/cli/kops_delete_secret.md @@ -3,22 +3,17 @@ ## kops delete secret -Delete a secret - -### Synopsis - -Delete a secret. +Delete one or more secrets. ``` -kops delete secret [flags] +kops delete secret SECRET_NAME... [flags] ``` ### Examples ``` - # Syntax: kops delete secret - # or kops delete secret - kops delete secret sshpublickey admin + # Delete the encryptionconfig secret + kops delete secret encryptionconfig ``` ### Options