Merge pull request #11999 from johngmyers/complete-template

Implement completion for "kops toolbox", part two
This commit is contained in:
Kubernetes Prow Robot 2021-07-17 13:12:51 -07:00 committed by GitHub
commit 8d3b638333
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 99 additions and 79 deletions

View File

@ -304,9 +304,9 @@ func NewCmdCreateCluster(f *util.Factory, out io.Writer) *cobra.Command {
}
cmd.Flags().StringSliceVar(&options.NodeSecurityGroups, "node-security-groups", options.NodeSecurityGroups, "Additional precreated security groups to add to worker nodes.")
cmd.RegisterFlagCompletionFunc("node-security-groups", completeSecurityGroup(options))
cmd.RegisterFlagCompletionFunc("node-security-groups", completeSecurityGroup)
cmd.Flags().StringSliceVar(&options.MasterSecurityGroups, "master-security-groups", options.MasterSecurityGroups, "Additional precreated security groups to add to masters.")
cmd.RegisterFlagCompletionFunc("master-security-groups", completeSecurityGroup(options))
cmd.RegisterFlagCompletionFunc("master-security-groups", completeSecurityGroup)
cmd.Flags().StringVar(&options.Channel, "channel", options.Channel, "Channel for default versions and configuration to use")
cmd.RegisterFlagCompletionFunc("channel", completeChannel)
@ -963,11 +963,9 @@ func completeDNSZone(options *CreateClusterOptions) func(cmd *cobra.Command, arg
}
}
func completeSecurityGroup(options *CreateClusterOptions) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
// TODO call into cloud provider(s) to get list of valid Security groups
return nil, cobra.ShellCompDirectiveNoFileComp
}
func completeSecurityGroup(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
// TODO call into cloud provider(s) to get list of valid Security groups
return nil, cobra.ShellCompDirectiveNoFileComp
}
func completeTenancy(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {

View File

@ -136,7 +136,7 @@ func NewCmdCreateInstanceGroup(f *util.Factory, out io.Writer) *cobra.Command {
return allRoles, cobra.ShellCompDirectiveNoFileComp
})
cmd.Flags().StringSliceVar(&options.Subnets, "subnet", options.Subnets, "Subnet in which to create instance group. One of Availability Zone like eu-west-1a or a comma-separated list of multiple Availability Zones.")
cmd.RegisterFlagCompletionFunc("subnet", completeClusterSubnet(options))
cmd.RegisterFlagCompletionFunc("subnet", completeClusterSubnet(&options.Subnets))
// DryRun mode that will print YAML or JSON
cmd.Flags().BoolVar(&options.DryRun, "dry-run", options.DryRun, "Only print the object that would be created, without created it. This flag can be used to create an instance group YAML or JSON manifest.")
cmd.Flags().StringVarP(&options.Output, "output", "o", options.Output, "Output format. One of json or yaml")
@ -277,7 +277,7 @@ func RunCreateInstanceGroup(ctx context.Context, f *util.Factory, out io.Writer,
return nil
}
func completeClusterSubnet(options *CreateInstanceGroupOptions) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
func completeClusterSubnet(excludeSubnets *[]string) 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()
ctx := context.TODO()
@ -293,7 +293,7 @@ func completeClusterSubnet(options *CreateInstanceGroupOptions) func(cmd *cobra.
var requiredType kopsapi.SubnetType
var subnets []string
alreadySelected := sets.NewString(options.Subnets...)
alreadySelected := sets.NewString(*excludeSubnets...)
for _, subnet := range cluster.Spec.Subnets {
if alreadySelected.Has(subnet.Name) {
requiredType = subnet.Type

View File

@ -170,40 +170,64 @@ func NewCmdToolboxInstanceSelector(f *util.Factory, out io.Writer) *cobra.Comman
// Instance Group Node Configurations
commandline.IntFlag(nodeCountMin, nil, &nodeCountMinDefault, "Set the minimum number of nodes")
commandline.IntFlag(nodeCountMax, nil, &nodeCountMaxDefault, "Set the maximum number of nodes")
commandline.IntFlag(nodeVolumeSize, nil, nil, "Set instance volume size (in GiB) for nodes")
commandline.StringSliceFlag(nodeSecurityGroups, nil, nil, "Add precreated additional security groups to nodes")
commandline.IntFlag(nodeCountMin, nil, &nodeCountMinDefault, "Minimum number of nodes")
commandline.IntFlag(nodeCountMax, nil, &nodeCountMaxDefault, "Maximum number of nodes")
commandline.IntFlag(nodeVolumeSize, nil, nil, "Instance volume size (in GiB) for nodes")
commandline.StringSliceFlag(nodeSecurityGroups, nil, nil, "Pre-created additional security groups for nodes")
commandline.Command.RegisterFlagCompletionFunc(nodeSecurityGroups, completeSecurityGroup)
commandline.BoolFlag(clusterAutoscaler, nil, &clusterAutoscalerDefault, "Add auto-discovery tags for cluster-autoscaler to manage the instance-group")
// Aggregate Filters
commandline.StringFlag(instanceTypeBase, nil, nil, "Base instance type to retrieve similarly spec'd instance types", nil)
commandline.BoolFlag(flexible, nil, nil, "Retrieves a group of instance types spanning multiple generations based on opinionated defaults and user overridden resource filters")
commandline.IntFlag(instanceGroupCount, nil, nil, "Number of instance groups to create w/ different vcpus-to-memory-ratios starting at 1:2 and doubling.")
commandline.StringFlag(instanceTypeBase, nil, nil, "Base instance type to retrieve similarly specified instance types", nil)
commandline.Command.RegisterFlagCompletionFunc(instanceTypeBase, completeMachineType)
commandline.BoolFlag(flexible, nil, nil, "Retrieve a group of instance types spanning multiple generations based on opinionated defaults and user overridden resource filters")
commandline.IntFlag(instanceGroupCount, nil, nil, "Number of instance groups to create with different vcpus-to-memory ratios, starting at 1:2 and doubling")
// Raw Filters
commandline.IntMinMaxRangeFlags(vcpus, nil, nil, "Number of vcpus available to the instance type.")
commandline.IntMinMaxRangeFlags(vcpus, nil, nil, "Number of vcpus available to the instance type")
commandline.ByteQuantityMinMaxRangeFlags(memory, nil, nil, "Amount of memory available (Example: 4gb)")
commandline.RatioFlag(vcpusToMemoryRatio, nil, nil, "The ratio of vcpus to memory in MiB. (Example: 1:2)")
commandline.Command.RegisterFlagCompletionFunc(memory, cobra.NoFileCompletions)
commandline.Command.RegisterFlagCompletionFunc(memory+"-min", cobra.NoFileCompletions)
commandline.Command.RegisterFlagCompletionFunc(memory+"-max", cobra.NoFileCompletions)
commandline.RatioFlag(vcpusToMemoryRatio, nil, nil, "Ratio of vcpus to memory in MiB. (Example: 1:2)")
commandline.Command.RegisterFlagCompletionFunc(vcpusToMemoryRatio, cobra.NoFileCompletions)
commandline.StringOptionsFlag(cpuArchitecture, nil, &cpuArchDefault, fmt.Sprintf("CPU architecture [%s]", strings.Join(cpuArchs, ", ")), append(cpuArchs, cpuArchitectureX8664))
commandline.IntMinMaxRangeFlags(gpus, nil, nil, "Total number of GPUs (Example: 4)")
commandline.ByteQuantityMinMaxRangeFlags(gpuMemory, nil, nil, "Number of GPUs' total memory (Example: 4gb)")
commandline.Command.RegisterFlagCompletionFunc(cpuArchitecture, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return cpuArchs, cobra.ShellCompDirectiveNoFileComp
})
commandline.IntMinMaxRangeFlags(gpus, nil, nil, "Number of GPUs (Example: 4)")
commandline.ByteQuantityMinMaxRangeFlags(gpuMemory, nil, nil, "GPUs' total memory (Example: 4gb)")
commandline.Command.RegisterFlagCompletionFunc(gpuMemory, cobra.NoFileCompletions)
commandline.Command.RegisterFlagCompletionFunc(gpuMemory+"-min", cobra.NoFileCompletions)
commandline.Command.RegisterFlagCompletionFunc(gpuMemory+"-max", cobra.NoFileCompletions)
commandline.StringOptionsFlag(placementGroupStrategy, nil, nil, fmt.Sprintf("Placement group strategy: [%s]", strings.Join(placementGroupStrategies, ", ")), placementGroupStrategies)
commandline.Command.RegisterFlagCompletionFunc(placementGroupStrategy, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return placementGroupStrategies, cobra.ShellCompDirectiveNoFileComp
})
commandline.StringOptionsFlag(usageClass, nil, &usageClassDefault, fmt.Sprintf("Usage class: [%s]", strings.Join(usageClasses, ", ")), usageClasses)
commandline.Command.RegisterFlagCompletionFunc(usageClass, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return usageClasses, cobra.ShellCompDirectiveNoFileComp
})
commandline.BoolFlag(enaSupport, nil, nil, "Instance types where ENA is supported or required")
commandline.BoolFlag(burstSupport, nil, nil, "Burstable instance types")
commandline.StringSliceFlag(subnets, nil, nil, "Subnet(s) in which to create the instance group. One of Availability Zone like eu-west-1a or utility-eu-west-1a,")
commandline.Command.RegisterFlagCompletionFunc(subnets, completeClusterSubnet(commandline.Flags[subnets].(*[]string)))
commandline.IntMinMaxRangeFlags(networkInterfaces, nil, nil, "Number of network interfaces (ENIs) that can be attached to the instance")
commandline.RegexFlag(allowList, nil, nil, "List of allowed instance types to select from w/ regex syntax (Example: m[3-5]\\.*)")
commandline.Command.RegisterFlagCompletionFunc(allowList, cobra.NoFileCompletions)
commandline.RegexFlag(denyList, nil, nil, "List of instance types which should be excluded w/ regex syntax (Example: m[1-2]\\.*)")
commandline.Command.RegisterFlagCompletionFunc(denyList, cobra.NoFileCompletions)
// Output Flags
commandline.IntFlag(maxResults, nil, &maxResultsDefault, "Maximum number of instance types to return back")
commandline.BoolFlag(dryRun, nil, &dryRunDefault, "If true, only print the object that would be sent, without sending it. This flag can be used to create a cluster YAML or JSON manifest.")
commandline.StringFlag(output, commandline.StringMe("o"), &outputDefault, "Output format. One of json|yaml. Used with the --dry-run flag.", nil)
commandline.BoolFlag(dryRun, nil, &dryRunDefault, "Only print the object that would be created, without creating it. This flag can be used to create a cluster YAML or JSON manifest.")
commandline.StringFlag(output, commandline.StringMe("o"), &outputDefault, "Output format. One of json or yaml. Used with the --dry-run flag.", nil)
commandline.Command.RegisterFlagCompletionFunc(output, func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{"json", "yaml"}, cobra.ShellCompDirectiveNoFileComp
})
return commandline.Command
}

View File

@ -28,6 +28,7 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"helm.sh/helm/v3/pkg/strvals"
"k8s.io/kops/pkg/commands/commandutils"
"k8s.io/kubectl/pkg/util/i18n"
"k8s.io/kubectl/pkg/util/templates"
"sigs.k8s.io/yaml"
@ -47,8 +48,7 @@ var (
`))
toolboxTemplatingExample = templates.Examples(i18n.T(`
# generate cluster.yaml from template and input values
# Generate cluster.yaml from template and input values
kops toolbox template \
--values values.yaml --values=another.yaml \
--set var=value --set-string othervar=true \
@ -60,9 +60,8 @@ var (
toolboxTemplatingShort = i18n.T(`Generate cluster.yaml from template`)
)
// the options for the command
type toolboxTemplateOption struct {
clusterName string
type ToolboxTemplateOptions struct {
ClusterName string
configPath []string
configValue string
failOnMissing bool
@ -75,35 +74,40 @@ type toolboxTemplateOption struct {
channel string
}
// NewCmdToolboxTemplate returns a new templating command
// NewCmdToolboxTemplate returns a new templating command.
func NewCmdToolboxTemplate(f *util.Factory, out io.Writer) *cobra.Command {
options := &toolboxTemplateOption{}
options := &ToolboxTemplateOptions{
channel: kopsapi.DefaultChannel,
}
cmd := &cobra.Command{
Use: "template",
Short: toolboxTemplatingShort,
Long: toolboxTemplatingLong,
Example: toolboxTemplatingExample,
Run: func(cmd *cobra.Command, args []string) {
if err := rootCommand.ProcessArgs(args); err != nil {
exitWithError(err)
}
options.clusterName = rootCommand.ClusterName(true)
if err := runToolBoxTemplate(f, out, options); err != nil {
exitWithError(err)
}
Use: "template [CLUSTER]",
Short: toolboxTemplatingShort,
Long: toolboxTemplatingLong,
Example: toolboxTemplatingExample,
Args: rootCommand.clusterNameArgs(&options.ClusterName),
ValidArgsFunction: commandutils.CompleteClusterName(&rootCommand, true),
RunE: func(cmd *cobra.Command, args []string) error {
return RunToolBoxTemplate(f, out, options)
},
}
cmd.Flags().StringSliceVar(&options.configPath, "values", options.configPath, "Path to a configuration file containing values to include in template")
cmd.RegisterFlagCompletionFunc("values", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{"yaml", "json"}, cobra.ShellCompDirectiveFilterFileExt
})
cmd.Flags().StringArrayVar(&options.values, "set", options.values, "Set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
cmd.RegisterFlagCompletionFunc("set", cobra.NoFileCompletions)
cmd.Flags().StringArrayVar(&options.stringValues, "set-string", options.stringValues, "Set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)")
cmd.RegisterFlagCompletionFunc("set", cobra.NoFileCompletions)
cmd.Flags().StringSliceVar(&options.templatePath, "template", options.templatePath, "Path to template file or directory of templates to render")
cmd.Flags().StringSliceVar(&options.snippetsPath, "snippets", options.snippetsPath, "Path to directory containing snippets used for templating")
cmd.MarkFlagDirname("snippets")
cmd.Flags().StringVar(&options.channel, "channel", options.channel, "Channel to use for the channel* functions")
cmd.Flags().StringVar(&options.outputPath, "out", options.outputPath, "Path to output file, otherwise defaults to stdout")
cmd.RegisterFlagCompletionFunc("channel", completeChannel)
cmd.Flags().StringVar(&options.outputPath, "out", options.outputPath, "Path to output file. Defaults to stdout")
cmd.Flags().StringVar(&options.configValue, "config-value", "", "Show the value of a specific configuration value")
cmd.RegisterFlagCompletionFunc("config-value", cobra.NoFileCompletions)
cmd.Flags().BoolVar(&options.failOnMissing, "fail-on-missing", true, "Fail on referencing unset variables in templates")
cmd.Flags().BoolVar(&options.formatYAML, "format-yaml", false, "Attempt to format the generated yaml content before output")
cmd.Flags().SetNormalizeFunc(func(f *pflag.FlagSet, name string) pflag.NormalizedName {
@ -117,8 +121,8 @@ func NewCmdToolboxTemplate(f *util.Factory, out io.Writer) *cobra.Command {
return cmd
}
// runToolBoxTemplate is the action for the command
func runToolBoxTemplate(f *util.Factory, out io.Writer, options *toolboxTemplateOption) error {
// RunToolBoxTemplate is the action for the command
func RunToolBoxTemplate(f *util.Factory, out io.Writer, options *ToolboxTemplateOptions) error {
// @step: read in the configuration if any
context, err := newTemplateContext(options.configPath, options.values, options.stringValues)
if err != nil {
@ -128,9 +132,9 @@ func runToolBoxTemplate(f *util.Factory, out io.Writer, options *toolboxTemplate
// @step: set clusterName from template's values or cli flag
value, ok := context["clusterName"].(string)
if ok {
options.clusterName = value
options.ClusterName = value
} else {
context["clusterName"] = options.clusterName
context["clusterName"] = options.ClusterName
}
// @check if we are just rendering the config value
@ -171,14 +175,9 @@ func runToolBoxTemplate(f *util.Factory, out io.Writer, options *toolboxTemplate
}
}
channelLocation := ""
if channelLocation == "" {
channelLocation = kopsapi.DefaultChannel
}
channel, err := kopsapi.LoadChannel(channelLocation)
channel, err := kopsapi.LoadChannel(options.channel)
if err != nil {
return fmt.Errorf("error loading channel %q: %v", channelLocation, err)
return fmt.Errorf("error loading channel %q: %v", options.channel, err)
}
// @step: render each of the templates, splitting on the documents

View File

@ -28,22 +28,22 @@ kops toolbox instance-selector INSTANCE_GROUP [flags]
```
--allow-list string List of allowed instance types to select from w/ regex syntax (Example: m[3-5]\.*)
--base-instance-type string Base instance type to retrieve similarly spec'd instance types
--base-instance-type string Base instance type to retrieve similarly specified instance types
--burst-support Burstable instance types
--cluster-autoscaler Add auto-discovery tags for cluster-autoscaler to manage the instance-group (default true)
--cpu-architecture string CPU architecture [amd64, arm64] (default "amd64")
--deny-list string List of instance types which should be excluded w/ regex syntax (Example: m[1-2]\.*)
--dry-run If true, only print the object that would be sent, without sending it. This flag can be used to create a cluster YAML or JSON manifest.
--dry-run Only print the object that would be created, without creating it. This flag can be used to create a cluster YAML or JSON manifest.
--ena-support Instance types where ENA is supported or required
--flexible Retrieves a group of instance types spanning multiple generations based on opinionated defaults and user overridden resource filters
--gpu-memory string Number of GPUs' total memory (Example: 4gb) (sets --gpu-memory-min and -max to the same value)
--gpu-memory-max string Maximum Number of GPUs' total memory (Example: 4gb) If --gpu-memory-min is not specified, the lower bound will be 0
--gpu-memory-min string Minimum Number of GPUs' total memory (Example: 4gb) If --gpu-memory-max is not specified, the upper bound will be infinity
--gpus int Total number of GPUs (Example: 4) (sets --gpus-min and -max to the same value)
--gpus-max int Maximum Total number of GPUs (Example: 4) If --gpus-min is not specified, the lower bound will be 0
--gpus-min int Minimum Total number of GPUs (Example: 4) If --gpus-max is not specified, the upper bound will be infinity
--flexible Retrieve a group of instance types spanning multiple generations based on opinionated defaults and user overridden resource filters
--gpu-memory string GPUs' total memory (Example: 4gb) (sets --gpu-memory-min and -max to the same value)
--gpu-memory-max string Maximum GPUs' total memory (Example: 4gb) If --gpu-memory-min is not specified, the lower bound will be 0
--gpu-memory-min string Minimum GPUs' total memory (Example: 4gb) If --gpu-memory-max is not specified, the upper bound will be infinity
--gpus int Number of GPUs (Example: 4) (sets --gpus-min and -max to the same value)
--gpus-max int Maximum Number of GPUs (Example: 4) If --gpus-min is not specified, the lower bound will be 0
--gpus-min int Minimum Number of GPUs (Example: 4) If --gpus-max is not specified, the upper bound will be infinity
-h, --help help for instance-selector
--ig-count int Number of instance groups to create w/ different vcpus-to-memory-ratios starting at 1:2 and doubling.
--ig-count int Number of instance groups to create with different vcpus-to-memory ratios, starting at 1:2 and doubling
--max-results int Maximum number of instance types to return back (default 20)
--memory string Amount of memory available (Example: 4gb) (sets --memory-min and -max to the same value)
--memory-max string Maximum Amount of memory available (Example: 4gb) If --memory-min is not specified, the lower bound will be 0
@ -51,18 +51,18 @@ kops toolbox instance-selector INSTANCE_GROUP [flags]
--network-interfaces int Number of network interfaces (ENIs) that can be attached to the instance (sets --network-interfaces-min and -max to the same value)
--network-interfaces-max int Maximum Number of network interfaces (ENIs) that can be attached to the instance If --network-interfaces-min is not specified, the lower bound will be 0
--network-interfaces-min int Minimum Number of network interfaces (ENIs) that can be attached to the instance If --network-interfaces-max is not specified, the upper bound will be infinity
--node-count-max int Set the maximum number of nodes (default 10)
--node-count-min int Set the minimum number of nodes (default 1)
--node-security-groups strings Add precreated additional security groups to nodes
--node-volume-size int Set instance volume size (in GiB) for nodes
-o, --output string Output format. One of json|yaml. Used with the --dry-run flag. (default "yaml")
--node-count-max int Maximum number of nodes (default 10)
--node-count-min int Minimum number of nodes (default 1)
--node-security-groups strings Pre-created additional security groups for nodes
--node-volume-size int Instance volume size (in GiB) for nodes
-o, --output string Output format. One of json or yaml. Used with the --dry-run flag. (default "yaml")
--placement-group-strategy string Placement group strategy: [cluster, partition, spread]
--subnets strings Subnet(s) in which to create the instance group. One of Availability Zone like eu-west-1a or utility-eu-west-1a,
--usage-class string Usage class: [spot, on-demand] (default "on-demand")
--vcpus int Number of vcpus available to the instance type. (sets --vcpus-min and -max to the same value)
--vcpus-max int Maximum Number of vcpus available to the instance type. If --vcpus-min is not specified, the lower bound will be 0
--vcpus-min int Minimum Number of vcpus available to the instance type. If --vcpus-max is not specified, the upper bound will be infinity
--vcpus-to-memory-ratio string The ratio of vcpus to memory in MiB. (Example: 1:2)
--vcpus int Number of vcpus available to the instance type (sets --vcpus-min and -max to the same value)
--vcpus-max int Maximum Number of vcpus available to the instance type If --vcpus-min is not specified, the lower bound will be 0
--vcpus-min int Minimum Number of vcpus available to the instance type If --vcpus-max is not specified, the upper bound will be infinity
--vcpus-to-memory-ratio string Ratio of vcpus to memory in MiB. (Example: 1:2)
```
### Options inherited from parent commands

View File

@ -10,14 +10,13 @@ Generate cluster.yaml from template
Generate cluster.yaml from values input yaml file and apply template.
```
kops toolbox template [flags]
kops toolbox template [CLUSTER] [flags]
```
### Examples
```
# generate cluster.yaml from template and input values
# Generate cluster.yaml from template and input values
kops toolbox template \
--values values.yaml --values=another.yaml \
--set var=value --set-string othervar=true \
@ -29,12 +28,12 @@ kops toolbox template [flags]
### Options
```
--channel string Channel to use for the channel* functions
--channel string Channel to use for the channel* functions (default "stable")
--config-value string Show the value of a specific configuration value
--fail-on-missing Fail on referencing unset variables in templates (default true)
--format-yaml Attempt to format the generated yaml content before output
-h, --help help for template
--out string Path to output file, otherwise defaults to stdout
--out string Path to output file. Defaults to stdout
--set stringArray Set values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
--set-string stringArray Set STRING values on the command line (can specify multiple or separate values with commas: key1=val1,key2=val2)
--snippets strings Path to directory containing snippets used for templating