Implement completion for "kops delete instancegroup"

This commit is contained in:
John Gardiner Myers 2021-07-09 11:22:15 -07:00
parent 56b57b5326
commit ea8cd3b758
4 changed files with 74 additions and 47 deletions

View File

@ -19,6 +19,7 @@ package main
import ( import (
"context" "context"
"fmt" "fmt"
"strings"
"io" "io"
"os" "os"
@ -26,6 +27,7 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kops/cmd/kops/util" "k8s.io/kops/cmd/kops/util"
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/instancegroups" "k8s.io/kops/pkg/instancegroups"
"k8s.io/kops/upup/pkg/fi/cloudup" "k8s.io/kops/upup/pkg/fi/cloudup"
"k8s.io/kops/util/pkg/ui" "k8s.io/kops/util/pkg/ui"
@ -34,12 +36,12 @@ import (
) )
var ( var (
deleteIgLong = templates.LongDesc(i18n.T(` deleteInstanceGroupLong = templates.LongDesc(i18n.T(`
Delete an instancegroup configuration. kOps has the concept of "instance groups", Delete an instance group configuration. kOps has the concept of "instance groups",
which are a group of similar virtual machines. On AWS, they map to an which are a group of similar virtual machines. On AWS, they map to an
AutoScalingGroup. An ig work either as a Kubernetes master or a node.`)) AutoScalingGroup.`))
deleteIgExample = templates.Examples(i18n.T(` deleteInstanceGroupExample = templates.Examples(i18n.T(`
# Delete an instancegroup for the k8s-cluster.example.com cluster. # Delete an instancegroup for the k8s-cluster.example.com cluster.
# The --yes option runs the command immediately. # The --yes option runs the command immediately.
@ -47,7 +49,7 @@ var (
kops delete ig --name=k8s-cluster.example.com node-example --yes kops delete ig --name=k8s-cluster.example.com node-example --yes
`)) `))
deleteIgShort = i18n.T(`Delete instancegroup`) deleteInstanceGroupShort = i18n.T(`Delete instance group.`)
) )
type DeleteInstanceGroupOptions struct { type DeleteInstanceGroupOptions struct {
@ -60,28 +62,36 @@ func NewCmdDeleteInstanceGroup(f *util.Factory, out io.Writer) *cobra.Command {
options := &DeleteInstanceGroupOptions{} options := &DeleteInstanceGroupOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "instancegroup", Use: "instancegroup INSTANCE_GROUP",
Aliases: []string{"instancegroups", "ig"}, Aliases: []string{"instancegroups", "ig"},
Short: deleteIgShort, Short: deleteInstanceGroupShort,
Long: deleteIgLong, Long: deleteInstanceGroupLong,
Example: deleteIgExample, Example: deleteInstanceGroupExample,
Run: func(cmd *cobra.Command, args []string) { Args: func(cmd *cobra.Command, args []string) error {
ctx := context.TODO()
if len(args) == 0 {
exitWithError(fmt.Errorf("Specify name of instance group to delete"))
}
if len(args) != 1 {
exitWithError(fmt.Errorf("Can only edit one instance group at a time!"))
}
groupName := args[0]
options.GroupName = groupName
options.ClusterName = rootCommand.ClusterName(true) options.ClusterName = rootCommand.ClusterName(true)
if options.ClusterName == "" {
return fmt.Errorf("--name is required")
}
if len(args) == 0 {
return fmt.Errorf("must specify the name of instance group to delete")
}
options.GroupName = args[0]
if len(args) != 1 {
return fmt.Errorf("can only edit one instance group at a time")
}
return nil
},
ValidArgsFunction: completeInstanceGroup(nil, &[]string{strings.ToLower(string(kops.InstanceGroupRoleMaster))}),
RunE: func(cmd *cobra.Command, args []string) error {
ctx := context.TODO()
if !options.Yes { if !options.Yes {
message := fmt.Sprintf("Do you really want to delete instance group %q? This action cannot be undone.", groupName) message := fmt.Sprintf("Do you really want to delete instance group %q? This action cannot be undone.", options.GroupName)
c := &ui.ConfirmArgs{ c := &ui.ConfirmArgs{
Out: out, Out: out,
@ -92,7 +102,7 @@ func NewCmdDeleteInstanceGroup(f *util.Factory, out io.Writer) *cobra.Command {
confirmed, err := ui.GetConfirm(c) confirmed, err := ui.GetConfirm(c)
if err != nil { if err != nil {
exitWithError(err) return err
} }
if !confirmed { if !confirmed {
os.Exit(1) os.Exit(1)
@ -101,10 +111,7 @@ func NewCmdDeleteInstanceGroup(f *util.Factory, out io.Writer) *cobra.Command {
} }
} }
err := RunDeleteInstanceGroup(ctx, f, out, options) return RunDeleteInstanceGroup(ctx, f, out, options)
if err != nil {
exitWithError(err)
}
}, },
} }
@ -123,12 +130,7 @@ func RunDeleteInstanceGroup(ctx context.Context, f *util.Factory, out io.Writer,
return fmt.Errorf("GroupName is required") return fmt.Errorf("GroupName is required")
} }
clusterName := options.ClusterName cluster, err := GetCluster(ctx, f, options.ClusterName)
if clusterName == "" {
return fmt.Errorf("ClusterName is required")
}
cluster, err := GetCluster(ctx, f, clusterName)
if err != nil { if err != nil {
return err return err
} }
@ -146,18 +148,37 @@ func RunDeleteInstanceGroup(ctx context.Context, f *util.Factory, out io.Writer,
return fmt.Errorf("InstanceGroup %q not found", groupName) return fmt.Errorf("InstanceGroup %q not found", groupName)
} }
cloud, err := cloudup.BuildCloud(cluster)
if err != nil {
return err
}
fmt.Fprintf(out, "InstanceGroup %q found for deletion\n", groupName) fmt.Fprintf(out, "InstanceGroup %q found for deletion\n", groupName)
if group.Spec.Role == kops.InstanceGroupRoleMaster {
groups, err := clientset.InstanceGroupsFor(cluster).List(ctx, metav1.ListOptions{})
if err != nil {
return fmt.Errorf("listing InstanceGroups: %v", err)
}
onlyMaster := true
for _, ig := range groups.Items {
if ig.Name != groupName && ig.Spec.Role == kops.InstanceGroupRoleMaster {
onlyMaster = false
break
}
}
if onlyMaster {
return fmt.Errorf("cannot delete the only control plane instance group")
}
}
if !options.Yes { if !options.Yes {
fmt.Fprintf(out, "\nMust specify --yes to delete instancegroup\n") fmt.Fprintf(out, "\nMust specify --yes to delete instancegroup\n")
return nil return nil
} }
cloud, err := cloudup.BuildCloud(cluster)
if err != nil {
return err
}
d := &instancegroups.DeleteInstanceGroup{} d := &instancegroups.DeleteInstanceGroup{}
d.Cluster = cluster d.Cluster = cluster
d.Cloud = cloud d.Cloud = cloud

View File

@ -190,7 +190,7 @@ func NewCmdRollingUpdateCluster(f *util.Factory, out io.Writer) *cobra.Command {
cmd.Flags().DurationVar(&options.PostDrainDelay, "post-drain-delay", options.PostDrainDelay, "Time to wait after draining each node") cmd.Flags().DurationVar(&options.PostDrainDelay, "post-drain-delay", options.PostDrainDelay, "Time to wait after draining each node")
cmd.Flags().BoolVarP(&options.Interactive, "interactive", "i", options.Interactive, "Prompt to continue after each instance is updated") cmd.Flags().BoolVarP(&options.Interactive, "interactive", "i", options.Interactive, "Prompt to continue after each instance is updated")
cmd.Flags().StringSliceVar(&options.InstanceGroups, "instance-group", options.InstanceGroups, "Instance groups to update (defaults to all if not specified)") cmd.Flags().StringSliceVar(&options.InstanceGroups, "instance-group", options.InstanceGroups, "Instance groups to update (defaults to all if not specified)")
cmd.RegisterFlagCompletionFunc("instance-group", completeInstanceGroup(&options)) cmd.RegisterFlagCompletionFunc("instance-group", completeInstanceGroup(&options.InstanceGroups, &options.InstanceGroupRoles))
cmd.Flags().StringSliceVar(&options.InstanceGroupRoles, "instance-group-roles", options.InstanceGroupRoles, "Instance group roles to update ("+strings.Join(allRoles, ",")+")") cmd.Flags().StringSliceVar(&options.InstanceGroupRoles, "instance-group-roles", options.InstanceGroupRoles, "Instance group roles to update ("+strings.Join(allRoles, ",")+")")
cmd.RegisterFlagCompletionFunc("instance-group-roles", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { cmd.RegisterFlagCompletionFunc("instance-group-roles", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return sets.NewString(allRoles...).Delete(options.InstanceGroupRoles...).List(), cobra.ShellCompDirectiveNoFileComp return sets.NewString(allRoles...).Delete(options.InstanceGroupRoles...).List(), cobra.ShellCompDirectiveNoFileComp
@ -429,7 +429,7 @@ func RunRollingUpdateCluster(ctx context.Context, f *util.Factory, out io.Writer
return d.RollingUpdate(groups, list) return d.RollingUpdate(groups, list)
} }
func completeInstanceGroup(options *RollingUpdateOptions) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { func completeInstanceGroup(selectedInstanceGroups *[]string, selectedInstanceGroupRoles *[]string) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
commandutils.ConfigureKlogForCompletion() commandutils.ConfigureKlogForCompletion()
ctx := context.TODO() ctx := context.TODO()
@ -444,8 +444,14 @@ func completeInstanceGroup(options *RollingUpdateOptions) func(cmd *cobra.Comman
return commandutils.CompletionError("listing instance groups", err) return commandutils.CompletionError("listing instance groups", err)
} }
alreadySelected := sets.NewString(options.InstanceGroups...) alreadySelected := sets.NewString()
alreadySelectedRoles := sets.NewString(options.InstanceGroupRoles...) if selectedInstanceGroups != nil {
alreadySelected = alreadySelected.Insert(*selectedInstanceGroups...)
}
alreadySelectedRoles := sets.NewString()
if selectedInstanceGroupRoles != nil {
alreadySelectedRoles = alreadySelectedRoles.Insert(*selectedInstanceGroupRoles...)
}
var igs []string var igs []string
for _, ig := range list.Items { for _, ig := range list.Items {
if !alreadySelected.Has(ig.Name) && !alreadySelectedRoles.Has(strings.ToLower(string(ig.Spec.Role))) { if !alreadySelected.Has(ig.Name) && !alreadySelectedRoles.Has(strings.ToLower(string(ig.Spec.Role))) {

View File

@ -53,6 +53,6 @@ kops delete {-f FILENAME}... [flags]
* [kops](kops.md) - kOps is Kubernetes Operations. * [kops](kops.md) - kOps is Kubernetes Operations.
* [kops delete cluster](kops_delete_cluster.md) - Delete a cluster. * [kops delete cluster](kops_delete_cluster.md) - Delete a cluster.
* [kops delete instance](kops_delete_instance.md) - Delete an instance. * [kops delete instance](kops_delete_instance.md) - Delete an instance.
* [kops delete instancegroup](kops_delete_instancegroup.md) - Delete instancegroup * [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 a secret

View File

@ -3,14 +3,14 @@
## kops delete instancegroup ## kops delete instancegroup
Delete instancegroup Delete instance group.
### Synopsis ### Synopsis
Delete an instancegroup configuration. kOps has the concept of "instance groups", which are a group of similar virtual machines. On AWS, they map to an AutoScalingGroup. An ig work either as a Kubernetes master or a node. Delete an instance group configuration. kOps has the concept of "instance groups", which are a group of similar virtual machines. On AWS, they map to an AutoScalingGroup.
``` ```
kops delete instancegroup [flags] kops delete instancegroup INSTANCE_GROUP [flags]
``` ```
### Examples ### Examples