From 17b0702cbc3fbde00076363daf9839f411528ea6 Mon Sep 17 00:00:00 2001 From: Ilya Dmitrichenko Date: Fri, 7 Dec 2018 20:21:08 +0000 Subject: [PATCH] Add abstraction for grouping flags --- cmd/eksctl/main.go | 39 ++++++---- pkg/ctl/cmdutils/cmdutils.go | 26 ++++--- pkg/ctl/cmdutils/group.go | 106 ++++++++++++++++++++++++++ pkg/ctl/create/cluster.go | 120 ++++++++++-------------------- pkg/ctl/create/create.go | 5 +- pkg/ctl/delete/cluster.go | 13 ++-- pkg/ctl/utils/describe_stacks.go | 15 ++-- pkg/ctl/utils/write_kubeconfig.go | 15 +++- 8 files changed, 216 insertions(+), 123 deletions(-) create mode 100644 pkg/ctl/cmdutils/group.go diff --git a/cmd/eksctl/main.go b/cmd/eksctl/main.go index d8f152e82a..850b8dea40 100644 --- a/cmd/eksctl/main.go +++ b/cmd/eksctl/main.go @@ -6,6 +6,7 @@ import ( "github.com/kris-nova/logger" "github.com/spf13/cobra" + "github.com/weaveworks/eksctl/pkg/ctl/cmdutils" "github.com/weaveworks/eksctl/pkg/ctl/completion" "github.com/weaveworks/eksctl/pkg/ctl/create" "github.com/weaveworks/eksctl/pkg/ctl/delete" @@ -14,23 +15,27 @@ import ( "github.com/weaveworks/eksctl/pkg/ctl/utils" ) -var ( - rootCmd = &cobra.Command{ - Use: "eksctl", - Short: "a CLI for Amazon EKS", - Run: func(c *cobra.Command, _ []string) { - if err := c.Help(); err != nil { - logger.Debug("ignoring error %q", err.Error()) - } - }, - } - colorValue string -) +var rootCmd = &cobra.Command{ + Use: "eksctl [command]", + Short: "a CLI for Amazon EKS", + Run: func(c *cobra.Command, _ []string) { + if err := c.Help(); err != nil { + logger.Debug("ignoring error %q", err.Error()) + } + }, +} func init() { - addCommands() - rootCmd.PersistentFlags().IntVarP(&logger.Level, "verbose", "v", 3, "set log level, use 0 to silence, 4 for debugging and 5 for debugging with AWS debug logging") + + var colorValue string + + g := cmdutils.NewGrouping() + + addCommands(g) + + rootCmd.PersistentFlags().BoolP("help", "h", false, "help for this command") rootCmd.PersistentFlags().StringVarP(&colorValue, "color", "C", "true", "toggle colorized logs (true,false,fabulous)") + rootCmd.PersistentFlags().IntVarP(&logger.Level, "verbose", "v", 3, "set log level, use 0 to silence, 4 for debugging and 5 for debugging with AWS debug logging") cobra.OnInitialize(func() { // Control colored output @@ -52,6 +57,8 @@ func init() { logger.Timestamps = true } }) + + rootCmd.SetUsageFunc(g.Usage) } func main() { @@ -61,9 +68,9 @@ func main() { } } -func addCommands() { +func addCommands(g *cmdutils.Grouping) { rootCmd.AddCommand(versionCmd()) - rootCmd.AddCommand(create.Command()) + rootCmd.AddCommand(create.Command(g)) rootCmd.AddCommand(delete.Command()) rootCmd.AddCommand(get.Command()) rootCmd.AddCommand(scale.Command()) diff --git a/pkg/ctl/cmdutils/cmdutils.go b/pkg/ctl/cmdutils/cmdutils.go index b8c1561215..e1c92db723 100644 --- a/pkg/ctl/cmdutils/cmdutils.go +++ b/pkg/ctl/cmdutils/cmdutils.go @@ -27,16 +27,22 @@ func GetNameArg(args []string) string { } // AddCommonFlagsForAWS adds common flags for api.ProviderConfig -func AddCommonFlagsForAWS(fs *pflag.FlagSet, p *api.ProviderConfig) { - fs.StringVarP(&p.Region, "region", "r", "", "AWS region") - fs.StringVarP(&p.Profile, "profile", "p", "", "AWS credentials profile to use (overrides the AWS_PROFILE environment variable)") - - fs.DurationVar(&p.WaitTimeout, "aws-api-timeout", api.DefaultWaitTimeout, "") - // TODO deprecate in 0.2.0 - if err := fs.MarkHidden("aws-api-timeout"); err != nil { - logger.Debug("ignoring error %q", err.Error()) - } - fs.DurationVar(&p.WaitTimeout, "timeout", api.DefaultWaitTimeout, "max wait time in any polling operations") +func AddCommonFlagsForAWS(group *NamedFlagSetGroup, p *api.ProviderConfig) { + group.InFlagSet("AWS client", func(fs *pflag.FlagSet) { + fs.StringVarP(&p.Profile, "profile", "p", "", "AWS credentials profile to use (overrides the AWS_PROFILE environment variable)") + + fs.DurationVar(&p.WaitTimeout, "aws-api-timeout", api.DefaultWaitTimeout, "") + // TODO deprecate in 0.2.0 + if err := fs.MarkHidden("aws-api-timeout"); err != nil { + logger.Debug("ignoring error %q", err.Error()) + } + fs.DurationVar(&p.WaitTimeout, "timeout", api.DefaultWaitTimeout, "max wait time in any polling operations") + }) + + group.InFlagSet("General", func(fs *pflag.FlagSet) { + fs.StringVarP(&p.Region, "region", "r", "", "AWS region") + }) + } // AddCommonFlagsForKubeconfig adds common flags for controlling how output kubeconfig is written diff --git a/pkg/ctl/cmdutils/group.go b/pkg/ctl/cmdutils/group.go new file mode 100644 index 0000000000..8735e8ff43 --- /dev/null +++ b/pkg/ctl/cmdutils/group.go @@ -0,0 +1,106 @@ +package cmdutils + +import ( + "fmt" + "strings" + "unicode" + + "github.com/spf13/cobra" + "github.com/spf13/pflag" +) + +// Grouping holds a superset of all flagsets for all commands +type Grouping struct { + groups map[*cobra.Command]*NamedFlagSetGroup +} + +type namedFlagSet struct { + name string + fs *pflag.FlagSet +} + +// NamedFlagSetGroup holds a single group of flagsets +type NamedFlagSetGroup struct { + list []namedFlagSet +} + +// NewGrouping creates an instance of Grouping +func NewGrouping() *Grouping { + return &Grouping{ + make(map[*cobra.Command]*NamedFlagSetGroup), + } +} + +// New creates a new group of flagsets for use with a subcommand +func (g *Grouping) New(cmd *cobra.Command) *NamedFlagSetGroup { + n := &NamedFlagSetGroup{} + g.groups[cmd] = n + return n +} + +// InFlagSet returs new or existing named GlagSet in a group +func (n *NamedFlagSetGroup) InFlagSet(name string, cb func(*pflag.FlagSet)) { + for _, nfs := range n.list { + if nfs.name == name { + cb(nfs.fs) + return + } + } + + nfs := namedFlagSet{ + name: name, + fs: &pflag.FlagSet{}, + } + cb(nfs.fs) + n.list = append(n.list, nfs) +} + +// AddTo mixes all flagsets in the given group into another flagset +func (n *NamedFlagSetGroup) AddTo(cmd *cobra.Command) { + for _, nfs := range n.list { + cmd.Flags().AddFlagSet(nfs.fs) + } +} + +// Usage is for use with (*cobra.Command).SetUsageFunc +func (g *Grouping) Usage(cmd *cobra.Command) error { + if cmd == nil { + return fmt.Errorf("nil command") + } + + group := g.groups[cmd] + + usage := []string{fmt.Sprintf("Usage: %s", cmd.UseLine())} + + if cmd.HasAvailableSubCommands() { + usage = append(usage, "\nCommands:") + for _, subCommand := range cmd.Commands() { + usage = append(usage, fmt.Sprintf(" %s %-10s %s", cmd.CommandPath(), subCommand.Name(), subCommand.Short)) + } + } + + if len(cmd.Aliases) > 0 { + usage = append(usage, "\nAliases: "+cmd.NameAndAliases()) + } + + if group != nil { + for _, nfs := range group.list { + usage = append(usage, fmt.Sprintf("\n%s flags:", nfs.name)) + usage = append(usage, strings.TrimRightFunc(nfs.fs.FlagUsages(), unicode.IsSpace)) + } + } + + usage = append(usage, "\nCommon flags:") + if len(cmd.PersistentFlags().FlagUsages()) != 0 { + usage = append(usage, strings.TrimRightFunc(cmd.PersistentFlags().FlagUsages(), unicode.IsSpace)) + } + if len(cmd.InheritedFlags().FlagUsages()) != 0 { + usage = append(usage, strings.TrimRightFunc(cmd.InheritedFlags().FlagUsages(), unicode.IsSpace)) + } + + usage = append(usage, fmt.Sprintf("\nUse '%s [command] --help' for more information about a command.\n", cmd.CommandPath())) + + cmd.Println(strings.Join(usage, "\n")) + + return nil +} diff --git a/pkg/ctl/create/cluster.go b/pkg/ctl/create/cluster.go index 646b540ca5..88a20d745e 100644 --- a/pkg/ctl/create/cluster.go +++ b/pkg/ctl/create/cluster.go @@ -3,8 +3,6 @@ package create import ( "fmt" "os" - "strings" - "unicode" "github.com/kris-nova/logger" "github.com/pkg/errors" @@ -36,7 +34,7 @@ var ( subnets map[api.SubnetTopology]*[]string ) -func createClusterCmd() *cobra.Command { +func createClusterCmd(g *cmdutils.Grouping) *cobra.Command { p := &api.ProviderConfig{} cfg := api.NewClusterConfig() ng := cfg.NewNodeGroup() @@ -52,101 +50,61 @@ func createClusterCmd() *cobra.Command { }, } - fs := cmd.Flags() - - cmdutils.AddCommonFlagsForAWS(fs, p) + group := g.New(cmd) exampleClusterName := utils.ClusterName("", "") - fs.StringVarP(&cfg.Metadata.Name, "name", "n", "", fmt.Sprintf("EKS cluster name (generated if unspecified, e.g. %q)", exampleClusterName)) - - fs.StringToStringVarP(&cfg.Metadata.Tags, "tags", "", map[string]string{}, `A list of KV pairs used to tag the AWS resources (e.g. "Owner=John Doe,Team=Some Team")`) - - fs.StringVarP(&ng.InstanceType, "node-type", "t", defaultNodeType, "node instance type") - fs.IntVarP(&ng.DesiredCapacity, "nodes", "N", api.DefaultNodeCount, "total number of nodes (desired capacity of ASG)") - - // TODO: https://github.com/weaveworks/eksctl/issues/28 - fs.IntVarP(&ng.MinSize, "nodes-min", "m", 0, "minimum nodes in ASG (leave unset for a static nodegroup)") - fs.IntVarP(&ng.MaxSize, "nodes-max", "M", 0, "maximum nodes in ASG (leave unset for a static nodegroup)") - - fs.IntVarP(&ng.VolumeSize, "node-volume-size", "", 0, "Node volume size (in GB)") - fs.IntVar(&ng.MaxPodsPerNode, "max-pods-per-node", 0, "maximum number of pods per node (set automatically if unspecified)") - fs.StringSliceVar(&availabilityZones, "zones", nil, "(auto-select if unspecified)") - - fs.BoolVar(&ng.AllowSSH, "ssh-access", false, "control SSH access for nodes") - fs.StringVar(&ng.SSHPublicKeyPath, "ssh-public-key", defaultSSHPublicKey, "SSH public key to use for nodes (import from local path, or use existing EC2 key pair)") - - fs.BoolVar(&writeKubeconfig, "write-kubeconfig", true, "toggle writing of kubeconfig") - cmdutils.AddCommonFlagsForKubeconfig(fs, &kubeconfigPath, &setContext, &autoKubeconfigPath, exampleClusterName) + group.InFlagSet("General", func(fs *pflag.FlagSet) { + fs.StringVarP(&cfg.Metadata.Name, "name", "n", "", fmt.Sprintf("EKS cluster name (generated if unspecified, e.g. %q)", exampleClusterName)) + fs.StringToStringVarP(&cfg.Metadata.Tags, "tags", "", map[string]string{}, `A list of KV pairs used to tag the AWS resources (e.g. "Owner=John Doe,Team=Some Team")`) + fs.StringSliceVar(&availabilityZones, "zones", nil, "(auto-select if unspecified)") + }) - fs.BoolVar(&cfg.Addons.WithIAM.PolicyAmazonEC2ContainerRegistryPowerUser, "full-ecr-access", false, "enable full access to ECR") - fs.BoolVar(&cfg.Addons.WithIAM.PolicyAutoScaling, "asg-access", false, "enable iam policy dependency for cluster-autoscaler") - fs.BoolVar(&cfg.Addons.Storage, "storage-class", true, "if true (default) then a default StorageClass of type gp2 provisioned by EBS will be created") + group.InFlagSet("Initial nodegroup", func(fs *pflag.FlagSet) { + fs.StringVarP(&ng.InstanceType, "node-type", "t", defaultNodeType, "node instance type") + fs.IntVarP(&ng.DesiredCapacity, "nodes", "N", api.DefaultNodeCount, "total number of nodes (desired capacity of ASG)") - fs.StringVar(&ng.AMI, "node-ami", ami.ResolverStatic, "Advanced use cases only. If 'static' is supplied (default) then eksctl will use static AMIs; if 'auto' is supplied then eksctl will automatically set the AMI based on region/instance type; if any other value is supplied it will override the AMI to use for the nodes. Use with extreme care.") - fs.StringVar(&ng.AMIFamily, "node-ami-family", ami.ImageFamilyAmazonLinux2, "Advanced use cases only. If 'AmazonLinux2' is supplied (default), then eksctl will use the offical AWS EKS AMIs (Amazon Linux 2); if 'Ubuntu1804' is supplied, then eksctl will use the offical Canonical EKS AMIs (Ubuntu 18.04).") + // TODO: https://github.com/weaveworks/eksctl/issues/28 + fs.IntVarP(&ng.MinSize, "nodes-min", "m", 0, "minimum nodes in ASG (leave unset for a static nodegroup)") + fs.IntVarP(&ng.MaxSize, "nodes-max", "M", 0, "maximum nodes in ASG (leave unset for a static nodegroup)") - fs.StringVar(&kopsClusterNameForVPC, "vpc-from-kops-cluster", "", "re-use VPC from a given kops cluster") + fs.IntVarP(&ng.VolumeSize, "node-volume-size", "", 0, "Node volume size (in GB)") + fs.IntVar(&ng.MaxPodsPerNode, "max-pods-per-node", 0, "maximum number of pods per node (set automatically if unspecified)") - fs.IPNetVar(cfg.VPC.CIDR, "vpc-cidr", api.DefaultCIDR(), "global CIDR to use for VPC") + fs.BoolVar(&ng.AllowSSH, "ssh-access", false, "control SSH access for nodes") + fs.StringVar(&ng.SSHPublicKeyPath, "ssh-public-key", defaultSSHPublicKey, "SSH public key to use for nodes (import from local path, or use existing EC2 key pair)") - subnets = map[api.SubnetTopology]*[]string{ - api.SubnetTopologyPrivate: fs.StringSlice("vpc-private-subnets", nil, "re-use private subnets of an existing VPC"), - api.SubnetTopologyPublic: fs.StringSlice("vpc-public-subnets", nil, "re-use public subnets of an existing VPC"), - } + fs.StringVar(&ng.AMI, "node-ami", ami.ResolverStatic, "Advanced use cases only. If 'static' is supplied (default) then eksctl will use static AMIs; if 'auto' is supplied then eksctl will automatically set the AMI based on region/instance type; if any other value is supplied it will override the AMI to use for the nodes. Use with extreme care.") + fs.StringVar(&ng.AMIFamily, "node-ami-family", ami.ImageFamilyAmazonLinux2, "Advanced use cases only. If 'AmazonLinux2' is supplied (default), then eksctl will use the offical AWS EKS AMIs (Amazon Linux 2); if 'Ubuntu1804' is supplied, then eksctl will use the offical Canonical EKS AMIs (Ubuntu 18.04).") - fs.BoolVarP(&ng.PrivateNetworking, "node-private-networking", "P", false, "whether to make initial nodegroup networking private") - - groupFlagsInUsage(cmd) + fs.BoolVarP(&ng.PrivateNetworking, "node-private-networking", "P", false, "whether to make initial nodegroup networking private") + }) - return cmd -} + group.InFlagSet("Cluster add-ons", func(fs *pflag.FlagSet) { + fs.BoolVar(&cfg.Addons.WithIAM.PolicyAmazonEC2ContainerRegistryPowerUser, "full-ecr-access", false, "enable full access to ECR") + fs.BoolVar(&cfg.Addons.WithIAM.PolicyAutoScaling, "asg-access", false, "enable iam policy dependency for cluster-autoscaler") + fs.BoolVar(&cfg.Addons.Storage, "storage-class", true, "if true (default) then a default StorageClass of type gp2 provisioned by EBS will be created") + }) -func groupFlagsInUsage(cmd *cobra.Command) { - // Group flags by their categories determined by name prefixes - groupToPatterns := map[string][]string{ - "Node": {"node", "storage-class", "ssh", "max-pods-per-node", "full-ecr-access", "asg-access"}, - "Networking": {"vpc", "zones",}, - "Stack": {"region", "tags"}, - "Other": {}, - } - groups := []string{} - for k := range groupToPatterns { - groups = append(groups, k) - } - groupToFlagSet := make(map[string]*pflag.FlagSet) - for _, g := range groups { - groupToFlagSet[g] = pflag.NewFlagSet(g, /* Unused. Can be anythng. */ pflag.ContinueOnError) - } - cmd.LocalFlags().VisitAll(func(f *pflag.Flag) { - for _, g := range groups { - for _, p := range groupToPatterns[g] { - if strings.HasPrefix(f.Name, p) { - groupToFlagSet[g].AddFlag(f) - return - } - } + group.InFlagSet("VPC networking", func(fs *pflag.FlagSet) { + fs.StringVar(&kopsClusterNameForVPC, "vpc-from-kops-cluster", "", "re-use VPC from a given kops cluster") + fs.IPNetVar(cfg.VPC.CIDR, "vpc-cidr", api.DefaultCIDR(), "global CIDR to use for VPC") + subnets = map[api.SubnetTopology]*[]string{ + api.SubnetTopologyPrivate: fs.StringSlice("vpc-private-subnets", nil, "re-use private subnets of an existing VPC"), + api.SubnetTopologyPublic: fs.StringSlice("vpc-public-subnets", nil, "re-use public subnets of an existing VPC"), } - groupToFlagSet["Other"].AddFlag(f) }) - // The usage template is based on the one bundled into cobra - // https://github.com/spf13/cobra/blob/1e58aa3361fd650121dceeedc399e7189c05674a/command.go#L397 - origFlagUsages := ` + cmdutils.AddCommonFlagsForAWS(group, p) -Flags: -{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}` + group.InFlagSet("Output kubeconfig", func(fs *pflag.FlagSet) { + fs.BoolVar(&writeKubeconfig, "write-kubeconfig", true, "toggle writing of kubeconfig") + cmdutils.AddCommonFlagsForKubeconfig(fs, &kubeconfigPath, &setContext, &autoKubeconfigPath, exampleClusterName) + }) - altFlagUsages := `` - for _, g := range groups { - set := groupToFlagSet[g] - altFlagUsages += fmt.Sprintf(` + group.AddTo(cmd) -%s Flags: -%s`, g, strings.TrimRightFunc(set.FlagUsages(), unicode.IsSpace)) - } - - cmd.SetUsageTemplate(strings.Replace(cmd.UsageTemplate(), origFlagUsages, altFlagUsages, 1)) + return cmd } func doCreateCluster(p *api.ProviderConfig, cfg *api.ClusterConfig, ng *api.NodeGroup, nameArg string) error { diff --git a/pkg/ctl/create/create.go b/pkg/ctl/create/create.go index 1e1ede9469..1e93045669 100644 --- a/pkg/ctl/create/create.go +++ b/pkg/ctl/create/create.go @@ -3,10 +3,11 @@ package create import ( "github.com/kris-nova/logger" "github.com/spf13/cobra" + "github.com/weaveworks/eksctl/pkg/ctl/cmdutils" ) // Command will create the `create` commands -func Command() *cobra.Command { +func Command(g *cmdutils.Grouping) *cobra.Command { cmd := &cobra.Command{ Use: "create", Short: "Create resource(s)", @@ -17,7 +18,7 @@ func Command() *cobra.Command { }, } - cmd.AddCommand(createClusterCmd()) + cmd.AddCommand(createClusterCmd(g)) return cmd } diff --git a/pkg/ctl/delete/cluster.go b/pkg/ctl/delete/cluster.go index 763cb34a0d..8e4e4e1329 100644 --- a/pkg/ctl/delete/cluster.go +++ b/pkg/ctl/delete/cluster.go @@ -7,6 +7,7 @@ import ( "github.com/kris-nova/logger" "github.com/spf13/cobra" + "github.com/spf13/pflag" "github.com/weaveworks/eksctl/pkg/ctl/cmdutils" "github.com/weaveworks/eksctl/pkg/eks" "github.com/weaveworks/eksctl/pkg/eks/api" @@ -28,14 +29,16 @@ func deleteClusterCmd() *cobra.Command { }, } - fs := cmd.Flags() + group := &cmdutils.NamedFlagSetGroup{} - fs.StringVarP(&cfg.Metadata.Name, "name", "n", "", "EKS cluster name (required)") + group.InFlagSet("General", func(fs *pflag.FlagSet) { + fs.StringVarP(&cfg.Metadata.Name, "name", "n", "", "EKS cluster name (required)") + fs.BoolVarP(&waitDelete, "wait", "w", false, "Wait for deletion of all resources before exiting") + }) - cmdutils.AddCommonFlagsForAWS(fs, p) - - fs.BoolVarP(&waitDelete, "wait", "w", false, "Wait for deletion of all resources before exiting") + cmdutils.AddCommonFlagsForAWS(group, p) + group.AddTo(cmd) return cmd } diff --git a/pkg/ctl/utils/describe_stacks.go b/pkg/ctl/utils/describe_stacks.go index 21720a7f09..8e9ae40cad 100644 --- a/pkg/ctl/utils/describe_stacks.go +++ b/pkg/ctl/utils/describe_stacks.go @@ -7,6 +7,8 @@ import ( "github.com/aws/aws-sdk-go/service/cloudformation" "github.com/kris-nova/logger" "github.com/spf13/cobra" + "github.com/spf13/pflag" + "github.com/weaveworks/eksctl/pkg/ctl/cmdutils" "github.com/weaveworks/eksctl/pkg/eks" "github.com/weaveworks/eksctl/pkg/eks/api" @@ -32,15 +34,18 @@ func describeStacksCmd() *cobra.Command { }, } - fs := cmd.Flags() + group := &cmdutils.NamedFlagSetGroup{} - cmdutils.AddCommonFlagsForAWS(fs, p) + group.InFlagSet("General", func(fs *pflag.FlagSet) { + fs.StringVarP(&cfg.Metadata.Name, "name", "n", "", "EKS cluster name (required)") - fs.StringVarP(&cfg.Metadata.Name, "name", "n", "", "EKS cluster name (required)") + fs.BoolVar(&describeStacksAll, "all", false, "include deleted stacks") + fs.BoolVar(&describeStacksEvents, "events", false, "include stack events") + }) - fs.BoolVar(&describeStacksAll, "all", false, "include deleted stacks") - fs.BoolVar(&describeStacksEvents, "events", false, "include stack events") + cmdutils.AddCommonFlagsForAWS(group, p) + group.AddTo(cmd) return cmd } diff --git a/pkg/ctl/utils/write_kubeconfig.go b/pkg/ctl/utils/write_kubeconfig.go index baf52c6729..9a3dc340a0 100644 --- a/pkg/ctl/utils/write_kubeconfig.go +++ b/pkg/ctl/utils/write_kubeconfig.go @@ -7,6 +7,8 @@ import ( "github.com/kris-nova/logger" "github.com/pkg/errors" "github.com/spf13/cobra" + "github.com/spf13/pflag" + "github.com/weaveworks/eksctl/pkg/ctl/cmdutils" "github.com/weaveworks/eksctl/pkg/eks" "github.com/weaveworks/eksctl/pkg/eks/api" @@ -34,14 +36,19 @@ func writeKubeconfigCmd() *cobra.Command { }, } - fs := cmd.Flags() + group := &cmdutils.NamedFlagSetGroup{} - fs.StringVarP(&cfg.Metadata.Name, "name", "n", "", "EKS cluster name (required)") + group.InFlagSet("General", func(fs *pflag.FlagSet) { + fs.StringVarP(&cfg.Metadata.Name, "name", "n", "", "EKS cluster name (required)") + }) - cmdutils.AddCommonFlagsForAWS(fs, p) + group.InFlagSet("Output kubeconfig", func(fs *pflag.FlagSet) { + cmdutils.AddCommonFlagsForKubeconfig(fs, &writeKubeconfigOutputPath, &writeKubeconfigSetContext, &writeKubeconfigAutoPath, "") + }) - cmdutils.AddCommonFlagsForKubeconfig(fs, &writeKubeconfigOutputPath, &writeKubeconfigSetContext, &writeKubeconfigAutoPath, "") + cmdutils.AddCommonFlagsForAWS(group, p) + group.AddTo(cmd) return cmd }