Skip to content

Commit

Permalink
Merge pull request #11926 from johngmyers/complete-update
Browse files Browse the repository at this point in the history
Implement completion for "kops update cluster"
  • Loading branch information
k8s-ci-robot authored Jul 5, 2021
2 parents 0e351ed + 1cf3cb2 commit a5533a0
Show file tree
Hide file tree
Showing 12 changed files with 98 additions and 75 deletions.
3 changes: 2 additions & 1 deletion cmd/kops/create_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -662,12 +662,13 @@ func RunCreateCluster(ctx context.Context, f *util.Factory, out io.Writer, c *Cr
updateClusterOptions.Target = c.Target
updateClusterOptions.OutDir = c.OutDir
updateClusterOptions.admin = kubeconfig.DefaultKubecfgAdminLifetime
updateClusterOptions.ClusterName = cluster.Name
updateClusterOptions.CreateKubecfg = true

// SSHPublicKey has already been mapped
updateClusterOptions.SSHPublicKey = ""

_, err := RunUpdateCluster(ctx, f, cluster.Name, out, updateClusterOptions)
_, err := RunUpdateCluster(ctx, f, out, updateClusterOptions)
if err != nil {
return err
}
Expand Down
17 changes: 17 additions & 0 deletions cmd/kops/export_kubecfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"k8s.io/client-go/tools/clientcmd"
"k8s.io/kops/cmd/kops/util"
kopsapi "k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/commands/commandutils"
"k8s.io/kops/pkg/kubeconfig"
"k8s.io/kops/upup/pkg/fi/cloudup"
"k8s.io/kubectl/pkg/util/i18n"
Expand Down Expand Up @@ -176,3 +177,19 @@ func buildPathOptions(options *ExportKubecfgOptions) *clientcmd.PathOptions {

return pathOptions
}

func completeKubecfgUser(cmd *cobra.Command, args []string, complete string) ([]string, cobra.ShellCompDirective) {
pathOptions := clientcmd.NewDefaultPathOptions()

config, err := pathOptions.GetStartingConfig()
if err != nil {
return commandutils.CompletionError("reading kubeconfig", err)
}

var users []string
for user := range config.AuthInfos {
users = append(users, user)
}

return users, cobra.ShellCompDirectiveNoFileComp
}
7 changes: 4 additions & 3 deletions cmd/kops/get_assets.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,10 @@ func RunGetAssets(ctx context.Context, f *util.Factory, out io.Writer, options *
return fmt.Errorf("--name is required")
}

updateClusterResults, err := RunUpdateCluster(ctx, f, clusterName, out, &UpdateClusterOptions{
Target: cloudup.TargetDryRun,
GetAssets: true,
updateClusterResults, err := RunUpdateCluster(ctx, f, out, &UpdateClusterOptions{
Target: cloudup.TargetDryRun,
GetAssets: true,
ClusterName: clusterName,
})
if err != nil {
return err
Expand Down
7 changes: 4 additions & 3 deletions cmd/kops/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -599,10 +599,10 @@ func (i *integrationTest) runTest(t *testing.T, h *testutils.IntegrationTestHarn

// We don't test it here, and it adds a dependency on kubectl
options.CreateKubecfg = false

options.ClusterName = i.clusterName
options.LifecycleOverrides = i.lifecycleOverrides

_, err := RunUpdateCluster(ctx, factory, i.clusterName, &stdout, options)
_, err := RunUpdateCluster(ctx, factory, &stdout, options)
if err != nil {
t.Fatalf("error running update cluster %q: %v", i.clusterName, err)
}
Expand Down Expand Up @@ -1008,9 +1008,10 @@ func (i *integrationTest) runTestCloudformation(t *testing.T) {

// We don't test it here, and it adds a dependency on kubectl
options.CreateKubecfg = false
options.ClusterName = i.clusterName
options.LifecycleOverrides = i.lifecycleOverrides

_, err := RunUpdateCluster(ctx, factory, i.clusterName, &stdout, options)
_, err := RunUpdateCluster(ctx, factory, &stdout, options)
if err != nil {
t.Fatalf("error running update cluster %q: %v", i.clusterName, err)
}
Expand Down
6 changes: 4 additions & 2 deletions cmd/kops/lifecycle_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -502,8 +502,9 @@ func updateEnsureNoChanges(ctx context.Context, t *testing.T, factory *util.Fact

// We don't test it here, and it adds a dependency on kubectl
options.CreateKubecfg = false
options.ClusterName = clusterName

_, err := RunUpdateCluster(ctx, factory, clusterName, &stdout, options)
_, err := RunUpdateCluster(ctx, factory, &stdout, options)
if err != nil {
t.Fatalf("error running update cluster %q: %v", clusterName, err)
}
Expand All @@ -517,8 +518,9 @@ func updateEnsureNoChanges(ctx context.Context, t *testing.T, factory *util.Fact

// We don't test it here, and it adds a dependency on kubectl
options.CreateKubecfg = false
options.ClusterName = clusterName

results, err := RunUpdateCluster(ctx, factory, clusterName, &stdout, options)
results, err := RunUpdateCluster(ctx, factory, &stdout, options)
if err != nil {
t.Fatalf("error running update cluster %q: %v", clusterName, err)
}
Expand Down
16 changes: 2 additions & 14 deletions cmd/kops/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +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 (
updateLong = templates.LongDesc(i18n.T(`
Creates or updates cloud resources to match cluster desired configuration.
`))

updateExample = templates.Examples(i18n.T(`
# After cluster has been created, configure it with:
kops update cluster k8s-cluster.example.com --yes --state=s3://my-state-store
`))

updateShort = i18n.T("Update a cluster.")
)

func NewCmdUpdate(f *util.Factory, out io.Writer) *cobra.Command {
cmd := &cobra.Command{
Use: "update",
Short: updateShort,
Long: updateLong,
Example: updateExample,
Use: "update",
Short: updateShort,
}

// subcommands
Expand Down
74 changes: 48 additions & 26 deletions cmd/kops/update_cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"k8s.io/kops/cmd/kops/util"
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/assets"
"k8s.io/kops/pkg/commands/commandutils"
"k8s.io/kops/pkg/kubeconfig"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/cloudup"
Expand All @@ -44,16 +45,16 @@ import (

var (
updateClusterLong = templates.LongDesc(i18n.T(`
Create or update cloud or cluster resources to match current cluster state. If the cluster or cloud resources already
exist this command may modify those resources.
Create or update cloud or cluster resources to match the current cluster and instance group definitions.
If the cluster or cloud resources already exist this command may modify those resources.
If nodes need updating such as during a Kubernetes upgrade, a rolling-update may
be required as well.
If, such as during a Kubernetes upgrade, nodes need updating, a rolling-update may
be subsequently required.
`))

updateClusterExample = templates.Examples(i18n.T(`
# After cluster has been edited or upgraded, configure it with:
kops update cluster k8s-cluster.example.com --yes --state=s3://my-state-store --yes --admin
# After the cluster has been edited or upgraded, update the cloud resources with:
kops update cluster k8s-cluster.example.com --yes --state=s3://my-state-store --yes
`))

updateClusterShort = i18n.T("Update a cluster.")
Expand All @@ -69,6 +70,8 @@ type UpdateClusterOptions struct {
// GetAssets is whether this is invoked from the CmdGetAssets.
GetAssets bool

ClusterName string

CreateKubecfg bool
admin time.Duration
user string
Expand Down Expand Up @@ -98,40 +101,41 @@ func NewCmdUpdateCluster(f *util.Factory, out io.Writer) *cobra.Command {
options.InitDefaults()

cmd := &cobra.Command{
Use: "cluster",
Short: updateClusterShort,
Long: updateClusterLong,
Example: updateClusterExample,
Run: func(cmd *cobra.Command, args []string) {
ctx := context.TODO()

err := rootCommand.ProcessArgs(args)
if err != nil {
exitWithError(err)
}

clusterName := rootCommand.ClusterName(true)

if _, err := RunUpdateCluster(ctx, f, clusterName, out, options); err != nil {
exitWithError(err)
}
Use: "cluster [CLUSTER]",
Short: updateClusterShort,
Long: updateClusterLong,
Example: updateClusterExample,
Args: rootCommand.clusterNameArgs(&options.ClusterName),
ValidArgsFunction: commandutils.CompleteClusterName(&rootCommand, true),
RunE: func(cmd *cobra.Command, args []string) error {
_, err := RunUpdateCluster(context.TODO(), f, out, options)
return err
},
}

cmd.Flags().BoolVarP(&options.Yes, "yes", "y", options.Yes, "Create cloud resources, without --yes update is in dry run mode")
cmd.Flags().StringVar(&options.Target, "target", options.Target, "Target - direct, terraform, cloudformation")
cmd.RegisterFlagCompletionFunc("target", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{cloudup.TargetDirect, cloudup.TargetDryRun, cloudup.TargetTerraform, cloudup.TargetCloudformation}, cobra.ShellCompDirectiveNoFileComp
})
cmd.Flags().StringVar(&options.SSHPublicKey, "ssh-public-key", options.SSHPublicKey, "SSH public key to use (deprecated: use kops create secret instead)")
cmd.Flags().StringVar(&options.OutDir, "out", options.OutDir, "Path to write any local output")
cmd.MarkFlagDirname("out")
cmd.Flags().BoolVar(&options.CreateKubecfg, "create-kube-config", options.CreateKubecfg, "Will control automatically creating the kube config file on your local filesystem")
cmd.Flags().DurationVar(&options.admin, "admin", options.admin, "Also export a cluster admin user credential with the specified lifetime and add it to the cluster context")
cmd.Flags().Lookup("admin").NoOptDefVal = kubeconfig.DefaultKubecfgAdminLifetime.String()
cmd.Flags().StringVar(&options.user, "user", options.user, "Re-use an existing user in kubeconfig. Value must specify an existing user block in your kubeconfig file. Implies --create-kube-config")
cmd.RegisterFlagCompletionFunc("user", completeKubecfgUser)
cmd.Flags().BoolVar(&options.internal, "internal", options.internal, "Use the cluster's internal DNS name. Implies --create-kube-config")
cmd.Flags().BoolVar(&options.AllowKopsDowngrade, "allow-kops-downgrade", options.AllowKopsDowngrade, "Allow an older version of kOps to update the cluster than last used")
cmd.Flags().StringVar(&options.Phase, "phase", options.Phase, "Subset of tasks to run: "+strings.Join(cloudup.Phases.List(), ", "))
cmd.RegisterFlagCompletionFunc("phase", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return cloudup.Phases.List(), cobra.ShellCompDirectiveNoFileComp
})
cmd.Flags().StringSliceVar(&options.LifecycleOverrides, "lifecycle-overrides", options.LifecycleOverrides, "comma separated list of phase overrides, example: SecurityGroups=Ignore,InternetGateway=ExistsAndWarnIfChanges")
viper.BindPFlag("lifecycle-overrides", cmd.Flags().Lookup("lifecycle-overrides"))
viper.BindEnv("lifecycle-overrides", "KOPS_LIFECYCLE_OVERRIDES")
cmd.RegisterFlagCompletionFunc("lifecycle-overrides", completeLifecycleOverrides)

return cmd
}
Expand All @@ -151,7 +155,7 @@ type UpdateClusterResults struct {
Cluster *kops.Cluster
}

func RunUpdateCluster(ctx context.Context, f *util.Factory, clusterName string, out io.Writer, c *UpdateClusterOptions) (*UpdateClusterResults, error) {
func RunUpdateCluster(ctx context.Context, f *util.Factory, out io.Writer, c *UpdateClusterOptions) (*UpdateClusterResults, error) {
results := &UpdateClusterResults{}

isDryrun := false
Expand Down Expand Up @@ -198,7 +202,7 @@ func RunUpdateCluster(ctx context.Context, f *util.Factory, clusterName string,
}
}

cluster, err := GetCluster(ctx, f, clusterName)
cluster, err := GetCluster(ctx, f, c.ClusterName)
if err != nil {
return results, err
}
Expand Down Expand Up @@ -368,7 +372,7 @@ func RunUpdateCluster(ctx context.Context, f *util.Factory, clusterName string,
fmt.Fprintf(sb, "Cloudformation output has been placed into %s\n", c.OutDir)

if firstRun {
cfName := "kubernetes-" + strings.Replace(clusterName, ".", "-", -1)
cfName := "kubernetes-" + strings.Replace(c.ClusterName, ".", "-", -1)
cfPath := filepath.Join(c.OutDir, "kubernetes.json")
fmt.Fprintf(sb, "Run this command to apply the configuration:\n")
fmt.Fprintf(sb, " aws cloudformation create-stack --capabilities CAPABILITY_NAMED_IAM --stack-name %s --template-body file://%s\n", cfName, cfPath)
Expand Down Expand Up @@ -465,3 +469,21 @@ func hasKubecfg(contextName string) (bool, error) {
}
return false, nil
}

func completeLifecycleOverrides(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
split := strings.SplitAfter(toComplete, "=")

if len(split) < 2 {
// providing completion for task names is too complicated
return nil, cobra.ShellCompDirectiveNoFileComp | cobra.ShellCompDirectiveNoSpace
}
if len(split) > 2 {
return commandutils.CompletionError("too many = characters", nil)
}

var completions []string
for lifecycle := range fi.LifecycleNameMap {
completions = append(completions, split[0]+lifecycle)
}
return completions, cobra.ShellCompDirectiveNoFileComp
}
16 changes: 8 additions & 8 deletions cmd/kops/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,16 @@ func NewCmdVersion(f *util.Factory, out io.Writer) *cobra.Command {
Short: versionShort,
Long: versionLong,
Example: versionExample,
Args: cobra.NoArgs,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return nil, cobra.ShellCompDirectiveNoFileComp
},
RunE: func(cmd *cobra.Command, args []string) error {
return commands.RunVersion(f, out, options)
},
}

cmd.Run = func(cmd *cobra.Command, args []string) {
err := commands.RunVersion(f, out, options)
if err != nil {
exitWithError(err)
}
}

cmd.Flags().BoolVar(&options.Short, "short", options.Short, "only print the main kOps version, useful for scripting")
cmd.Flags().BoolVar(&options.Short, "short", options.Short, "only print the main kOps version. Useful for scripting.")

return cmd
}
11 changes: 0 additions & 11 deletions docs/cli/kops_update.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions docs/cli/kops_update_cluster.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion docs/cli/kops_version.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,16 @@ nav:
- kops create: "cli/kops_create.md"
- kops delete: "cli/kops_delete.md"
- kops describe: "cli/kops_describe.md"
- kops distrust: "cli/kops_distrust.md"
- kops edit: "cli/kops_edit.md"
- kops export: "cli/kops_export.md"
- kops get: "cli/kops_get.md"
- kops import: "cli/kops_import.md"
- kops promote: "cli/kops_promote.md"
- kops replace: "cli/kops_replace.md"
- kops rolling-update: "cli/kops_rolling-update.md"
- kops set: "cli/kops_set.md"
- kops toolbox: "cli/kops_toolbox.md"
- kops unset: "cli/kops_unset.md"
- kops update: "cli/kops_update.md"
- kops upgrade: "cli/kops_upgrade.md"
- kops validate: "cli/kops_validate.md"
Expand Down

0 comments on commit a5533a0

Please sign in to comment.