From 59119cf443d0205f4e91bfe73f22677b41c47399 Mon Sep 17 00:00:00 2001 From: Tim Ramlot <42113979+inteon@users.noreply.github.com> Date: Tue, 30 Apr 2024 16:15:27 +0200 Subject: [PATCH 1/3] make the binary dynamically determine whether it is a kubectl plugin Signed-off-by: Tim Ramlot <42113979+inteon@users.noreply.github.com> --- .goreleaser.yml | 1 - cmd/cmd.go | 39 +++----------- main.go | 6 ++- make/00_mod.mk | 12 +---- pkg/approve/approve.go | 33 +++++------- pkg/build/build.go | 52 ++++++++++++++++--- pkg/build/commands/commands.go | 10 +--- pkg/check/api/api.go | 3 +- pkg/completion/bash.go | 6 ++- pkg/completion/completion.go | 14 +++-- pkg/completion/fish.go | 6 ++- pkg/completion/kubectl.go | 45 ++++++++++++++++ pkg/completion/powershell.go | 6 ++- pkg/completion/zsh.go | 6 ++- pkg/convert/convert.go | 43 +++++++-------- .../certificaterequest/certificaterequest.go | 49 ++++++++--------- .../certificatesigningrequest.go | 49 ++++++++--------- pkg/deny/deny.go | 33 +++++------- pkg/inspect/secret/secret.go | 23 +++----- pkg/install/install.go | 6 +-- pkg/renew/renew.go | 33 +++++------- pkg/status/certificate/certificate.go | 23 +++----- pkg/uninstall/uninstall.go | 6 +-- pkg/upgrade/migrateapiversion/command.go | 45 +++++++--------- pkg/version/version.go | 6 +-- 25 files changed, 277 insertions(+), 278 deletions(-) create mode 100644 pkg/completion/kubectl.go diff --git a/.goreleaser.yml b/.goreleaser.yml index e2c6c7f..6dafd50 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -2,7 +2,6 @@ # to this builds array (environment variables, flags, ...) builds: - id: cmctl - - id: kubectl_cert-manager # config the checksum filename # https://goreleaser.com/customization/checksum diff --git a/cmd/cmd.go b/cmd/cmd.go index 619beb8..403bb46 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -18,7 +18,6 @@ package cmd import ( "context" - "fmt" "io" logf "github.com/cert-manager/cert-manager/pkg/logs" @@ -31,14 +30,18 @@ import ( ) func NewCertManagerCtlCommand(ctx context.Context, in io.Reader, out, err io.Writer) *cobra.Command { - ctx = logf.NewContext(ctx, logf.Log) - logOptions := logs.NewOptions() cmds := &cobra.Command{ - Use: build.Name(), + Use: build.Name(ctx), + Annotations: map[string]string{ + // For commands that have a space (eg. kubectl cert-manager), the name + // is not correctly determined based on just the Use field. + cobra.CommandDisplayNameAnnotation: build.Name(ctx), + }, + Short: "cert-manager CLI tool to manage and configure cert-manager resources", - Long: build.WithTemplate(` + Long: build.WithTemplate(ctx, ` {{.BuildName}} is a CLI tool manage and configure cert-manager resources for Kubernetes`), CompletionOptions: cobra.CompletionOptions{ DisableDefaultCmd: true, @@ -49,7 +52,6 @@ func NewCertManagerCtlCommand(ctx context.Context, in io.Reader, out, err io.Wri SilenceErrors: true, // Errors are already logged when calling cmd.Execute() SilenceUsage: true, // Don't print usage when an error occurs } - cmds.SetUsageTemplate(usageTemplate()) logf.AddFlagsNonDeprecated(logOptions, cmds.PersistentFlags()) @@ -60,28 +62,3 @@ func NewCertManagerCtlCommand(ctx context.Context, in io.Reader, out, err io.Wri return cmds } - -func usageTemplate() string { - return fmt.Sprintf(`Usage:{{if .Runnable}} %s {{end}}{{if .HasAvailableSubCommands}} %s [command]{{end}}{{if gt (len .Aliases) 0}} - -Aliases: - {{.NameAndAliases}}{{end}}{{if .HasExample}} - -Examples: -{{.Example}}{{end}}{{if .HasAvailableSubCommands}} - -Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}} - {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} - -Flags: -{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} - -Global Flags: -{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}} - -Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} - {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} - -Use "%s [command] --help" for more information about a command.{{end}} -`, build.Name(), build.Name(), build.Name()) -} diff --git a/main.go b/main.go index 34f9c45..a2a80d7 100644 --- a/main.go +++ b/main.go @@ -29,16 +29,20 @@ import ( ctlcmd "github.com/cert-manager/cmctl/v2/cmd" "github.com/cert-manager/cmctl/v2/internal/util" + "github.com/cert-manager/cmctl/v2/pkg/build" ) func main() { ctx, exit := util.SetupExitHandler(context.Background(), util.AlwaysErrCode) defer exit() // This function might call os.Exit, so defer last + ctlName, isKubectlPlugin := build.DetectCtlInfo(os.Args) + logf.InitLogs() defer logf.FlushLogs() ctrl.SetLogger(logf.Log) - ctx = logf.NewContext(ctx, logf.Log, "cmctl") + ctx = logf.NewContext(ctx, logf.Log, ctlName) + ctx = build.WithCtlInfo(ctx, ctlName, isKubectlPlugin) // In cmctl, we are using cmdutil.CheckErr, a kubectl utility function that creates human readable // error messages from errors. By default, this function will call os.Exit(1) if it receives an error. diff --git a/make/00_mod.mk b/make/00_mod.mk index 911a2bc..485f4f0 100644 --- a/make/00_mod.mk +++ b/make/00_mod.mk @@ -14,23 +14,13 @@ repo_name := github.com/cert-manager/cmctl/v2 -exe_build_names := cmctl kubectl_cert-manager +exe_build_names := cmctl gorelease_file := .goreleaser.yml go_cmctl_main_dir := . go_cmctl_mod_dir := . go_cmctl_ldflags := \ - -X $(repo_name)/pkg/build.name=cmctl \ - -X $(repo_name)/pkg/build/commands.registerCompletion=true \ -X github.com/cert-manager/cert-manager/pkg/util.AppVersion=$(VERSION) \ -X github.com/cert-manager/cert-manager/pkg/util.AppGitCommit=$(GITCOMMIT) -go_kubectl_cert-manager_main_dir := . -go_kubectl_cert-manager_mod_dir := . -go_kubectl_cert-manager_ldflags := \ - -X $(repo_name)/pkg/build.name=kubectl \ - -X $(repo_name)/pkg/build/commands.registerCompletion=false \ - -X github.com/cert-manager/cert-manager/pkg/util/version.AppVersion=$(VERSION) \ - -X github.com/cert-manager/cert-manager/pkg/util/version.AppGitCommit=$(GITCOMMIT) - golangci_lint_config := .golangci.yaml diff --git a/pkg/approve/approve.go b/pkg/approve/approve.go index 8691687..2d1f3e3 100644 --- a/pkg/approve/approve.go +++ b/pkg/approve/approve.go @@ -27,26 +27,12 @@ import ( "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/cli-runtime/pkg/genericclioptions" - "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" "github.com/cert-manager/cmctl/v2/pkg/build" "github.com/cert-manager/cmctl/v2/pkg/factory" ) -var ( - example = templates.Examples(i18n.T(build.WithTemplate(` -# Approve a CertificateRequest with the name 'my-cr' -{{.BuildName}} approve my-cr - -# Approve a CertificateRequest in namespace default -{{.BuildName}} approve my-cr --namespace default - -# Approve a CertificateRequest giving a custom reason and message -{{.BuildName}} approve my-cr --reason "ManualApproval" --reason "Approved by PKI department" -`))) -) - // Options is a struct to support create certificaterequest command type Options struct { // Reason is the string that will be set on the Reason field of the Approved @@ -71,10 +57,19 @@ func NewCmdApprove(setupCtx context.Context, ioStreams genericclioptions.IOStrea o := newOptions(ioStreams) cmd := &cobra.Command{ - Use: "approve", - Short: "Approve a CertificateRequest", - Long: `Mark a CertificateRequest as Approved, so it may be signed by a configured Issuer.`, - Example: example, + Use: "approve", + Short: "Approve a CertificateRequest", + Long: `Mark a CertificateRequest as Approved, so it may be signed by a configured Issuer.`, + Example: templates.Examples(build.WithTemplate(setupCtx, ` +# Approve a CertificateRequest with the name 'my-cr' +{{.BuildName}} approve my-cr + +# Approve a CertificateRequest in namespace default +{{.BuildName}} approve my-cr --namespace default + +# Approve a CertificateRequest giving a custom reason and message +{{.BuildName}} approve my-cr --reason "ManualApproval" --reason "Approved by PKI department" +`)), ValidArgsFunction: factory.ValidArgsListCertificateRequests(&o.Factory), PreRunE: func(cmd *cobra.Command, args []string) error { return o.Validate(args) @@ -87,7 +82,7 @@ func NewCmdApprove(setupCtx context.Context, ioStreams genericclioptions.IOStrea cmd.Flags().StringVar(&o.Reason, "reason", "KubectlCertManager", "The reason to give as to what approved this CertificateRequest.") - cmd.Flags().StringVar(&o.Message, "message", fmt.Sprintf("manually approved by %q", build.Name()), + cmd.Flags().StringVar(&o.Message, "message", fmt.Sprintf("manually approved by %q", build.Name(setupCtx)), "The message to give as to why this CertificateRequest was approved.") o.Factory = factory.New(cmd) diff --git a/pkg/build/build.go b/pkg/build/build.go index 144be39..97c6631 100644 --- a/pkg/build/build.go +++ b/pkg/build/build.go @@ -18,24 +18,62 @@ package build import ( "bytes" + "context" + "os" + "path/filepath" + "strings" "text/template" ) -// name is the build time configurable name of the build (name of the target -// binary name). -var name = "cmctl" +var defaultCtlName string = "cmctl" +var defaultIsKubectlPlugin bool = false + +func DetectCtlInfo(args []string) (name string, isKubectlPlugin bool) { + commandName := filepath.Base(os.Args[0]) + if strings.HasPrefix(commandName, "kubectl-") || strings.HasPrefix(commandName, "kubectl_") { + return "kubectl cert-manager", true + } + + return commandName, false +} + +// contextNameKey is how we find the ctl name in a context.Context. +type contextNameKey struct{} + +// contextIsKubectlPluginKey is how we find if the ctl is a Kubectl plugin in a context.Context. +type contextIsKubectlPluginKey struct{} + +func WithCtlInfo(ctx context.Context, name string, isKubectlPlugin bool) context.Context { + ctx = context.WithValue(ctx, contextNameKey{}, name) + ctx = context.WithValue(ctx, contextIsKubectlPluginKey{}, isKubectlPlugin) + return ctx +} + +func Name(ctx context.Context) string { + name, ok := ctx.Value(contextNameKey{}).(string) + if !ok { + return defaultCtlName + } -// Name returns the build name. -func Name() string { return name } +func IsKubectlPlugin(ctx context.Context) bool { + isKubectlPlugin, ok := ctx.Value(contextIsKubectlPluginKey{}).(bool) + if !ok { + return defaultIsKubectlPlugin + } + + return isKubectlPlugin +} + // WithTemplate returns a string that has the build name templated out with the // configured build name. Build name templates on '{{ .BuildName }}' variable. -func WithTemplate(str string) string { +func WithTemplate(ctx context.Context, str string) string { + buildName := Name(ctx) tmpl := template.Must(template.New("build-name").Parse(str)) var buf bytes.Buffer - if err := tmpl.Execute(&buf, struct{ BuildName string }{name}); err != nil { + if err := tmpl.Execute(&buf, struct{ BuildName string }{buildName}); err != nil { // We panic here as it should never be possible that this template fails. panic(err) } diff --git a/pkg/build/commands/commands.go b/pkg/build/commands/commands.go index 6707c75..fd92298 100644 --- a/pkg/build/commands/commands.go +++ b/pkg/build/commands/commands.go @@ -18,7 +18,6 @@ package commands import ( "context" - "strings" "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" @@ -37,11 +36,6 @@ import ( "github.com/cert-manager/cmctl/v2/pkg/version" ) -// registerCompletion gates whether the completion command is registered. -// Specifically useful when building the CLI as a kubectl plugin which does not -// support completion. -var registerCompletion = "false" - type RegisterCommandFunc func(context.Context, genericclioptions.IOStreams) *cobra.Command // Commands returns the cobra Commands that should be registered for the CLI @@ -61,10 +55,8 @@ func Commands() []RegisterCommandFunc { // Experimental features experimental.NewCmdExperimental, - } - if strings.ToLower(registerCompletion) == "true" { - cmds = append(cmds, completion.NewCmdCompletion) + completion.NewCmdCompletion, } return cmds diff --git a/pkg/check/api/api.go b/pkg/check/api/api.go index 6a977bb..95b1c50 100644 --- a/pkg/check/api/api.go +++ b/pkg/check/api/api.go @@ -28,7 +28,6 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/cli-runtime/pkg/genericclioptions" - "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" cmcmdutil "github.com/cert-manager/cmctl/v2/internal/util" @@ -51,7 +50,7 @@ type Options struct { *factory.Factory } -var checkApiDesc = templates.LongDesc(i18n.T(` +var checkApiDesc = templates.LongDesc((` This check attempts to perform a dry-run create of a cert-manager *v1alpha2* Certificate resource in order to verify that CRDs are installed and all the required webhooks are reachable by the K8S API server. diff --git a/pkg/completion/bash.go b/pkg/completion/bash.go index c7f703d..4a54b23 100644 --- a/pkg/completion/bash.go +++ b/pkg/completion/bash.go @@ -17,17 +17,19 @@ limitations under the License. package completion import ( + "context" + "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" "github.com/cert-manager/cmctl/v2/pkg/build" ) -func newCmdCompletionBash(ioStreams genericclioptions.IOStreams) *cobra.Command { +func newCmdCompletionBash(setupCtx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { return &cobra.Command{ Use: "bash", Short: "Generate cert-manager CLI scripts for a Bash shell", - Long: build.WithTemplate(`To load completions: + Long: build.WithTemplate(setupCtx, `To load completions: Bash: $ source <({{.BuildName}} completion bash) # To load completions for each session, execute once: diff --git a/pkg/completion/completion.go b/pkg/completion/completion.go index 5798460..9ce8d9a 100644 --- a/pkg/completion/completion.go +++ b/pkg/completion/completion.go @@ -21,6 +21,8 @@ import ( "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" + + "github.com/cert-manager/cmctl/v2/pkg/build" ) func NewCmdCompletion(setupCtx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { @@ -30,10 +32,14 @@ func NewCmdCompletion(setupCtx context.Context, ioStreams genericclioptions.IOSt Long: "Generate completion for the cert-manager CLI so arguments and flags can be suggested and auto-completed", } - cmds.AddCommand(newCmdCompletionBash(ioStreams)) - cmds.AddCommand(newCmdCompletionZSH(ioStreams)) - cmds.AddCommand(newCmdCompletionFish(ioStreams)) - cmds.AddCommand(newCmdCompletionPowerShell(ioStreams)) + if build.IsKubectlPlugin(setupCtx) { + cmds.AddCommand(newCmdCompletionKubectl(setupCtx, ioStreams)) + } else { + cmds.AddCommand(newCmdCompletionBash(setupCtx, ioStreams)) + cmds.AddCommand(newCmdCompletionZSH(setupCtx, ioStreams)) + cmds.AddCommand(newCmdCompletionFish(setupCtx, ioStreams)) + cmds.AddCommand(newCmdCompletionPowerShell(setupCtx, ioStreams)) + } return cmds } diff --git a/pkg/completion/fish.go b/pkg/completion/fish.go index d999baa..dd72f2c 100644 --- a/pkg/completion/fish.go +++ b/pkg/completion/fish.go @@ -17,17 +17,19 @@ limitations under the License. package completion import ( + "context" + "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" "github.com/cert-manager/cmctl/v2/pkg/build" ) -func newCmdCompletionFish(ioStreams genericclioptions.IOStreams) *cobra.Command { +func newCmdCompletionFish(setupCtx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { return &cobra.Command{ Use: "fish", Short: "Generate cert-manager CLI scripts for a Fish shell", - Long: build.WithTemplate(`To load completions: + Long: build.WithTemplate(setupCtx, `To load completions: $ {{.BuildName}} completion fish | source # To load completions for each session, execute once: diff --git a/pkg/completion/kubectl.go b/pkg/completion/kubectl.go new file mode 100644 index 0000000..140c28d --- /dev/null +++ b/pkg/completion/kubectl.go @@ -0,0 +1,45 @@ +/* +Copyright 2021 The cert-manager Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package completion + +import ( + "context" + "fmt" + + "github.com/spf13/cobra" + "k8s.io/cli-runtime/pkg/genericclioptions" + + "github.com/cert-manager/cmctl/v2/pkg/build" +) + +func newCmdCompletionKubectl(setupCtx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { + return &cobra.Command{ + Use: "kubectl", + Short: "Generate cert-manager CLI scripts for Kubectl", + Long: build.WithTemplate(setupCtx, `To load completions: +$ {{.BuildName}} completion kubectl > kubectl_complete-cert_manager +$ sudo install kubectl_complete-cert_manager /usr/local/bin +`), + DisableFlagsInUseLine: true, + RunE: func(cmd *cobra.Command, args []string) error { + _, err := fmt.Fprint(ioStreams.Out, `#!/usr/bin/env sh +kubectl cert-manager __complete "$@" +`) + return err + }, + } +} diff --git a/pkg/completion/powershell.go b/pkg/completion/powershell.go index 8ec0931..7ab4429 100644 --- a/pkg/completion/powershell.go +++ b/pkg/completion/powershell.go @@ -17,17 +17,19 @@ limitations under the License. package completion import ( + "context" + "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" "github.com/cert-manager/cmctl/v2/pkg/build" ) -func newCmdCompletionPowerShell(ioStreams genericclioptions.IOStreams) *cobra.Command { +func newCmdCompletionPowerShell(setupCtx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { return &cobra.Command{ Use: "powershell", Short: "Generate cert-manager CLI scripts for a PowerShell shell", - Long: build.WithTemplate(`To load completions: + Long: build.WithTemplate(setupCtx, `To load completions: PS> {{.BuildName}} completion powershell | Out-String | Invoke-Expression # To load completions for every new session, run: diff --git a/pkg/completion/zsh.go b/pkg/completion/zsh.go index b917aca..4f80197 100644 --- a/pkg/completion/zsh.go +++ b/pkg/completion/zsh.go @@ -17,17 +17,19 @@ limitations under the License. package completion import ( + "context" + "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" "github.com/cert-manager/cmctl/v2/pkg/build" ) -func newCmdCompletionZSH(ioStreams genericclioptions.IOStreams) *cobra.Command { +func newCmdCompletionZSH(setupCtx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { return &cobra.Command{ Use: "zsh", Short: "Generation cert-manager CLI scripts for a ZSH shell", - Long: build.WithTemplate(`To load completions: + Long: build.WithTemplate(setupCtx, `To load completions: # If shell completion is not already enabled in your environment, # you will need to enable it. You can execute the following once: $ echo "autoload -U compinit; compinit" >> ~/.zshrc diff --git a/pkg/convert/convert.go b/pkg/convert/convert.go index 68f0989..5fc7989 100644 --- a/pkg/convert/convert.go +++ b/pkg/convert/convert.go @@ -32,32 +32,11 @@ import ( "k8s.io/cli-runtime/pkg/printers" "k8s.io/cli-runtime/pkg/resource" cmdutil "k8s.io/kubectl/pkg/cmd/util" - "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" "github.com/cert-manager/cmctl/v2/pkg/build" ) -var ( - example = templates.Examples(i18n.T(build.WithTemplate(` - # Convert 'cert.yaml' to latest version and print to stdout. - {{.BuildName}} convert -f cert.yaml - - # Convert kustomize overlay under current directory to 'cert-manager.io/v1alpha3' - {{.BuildName}} convert -k . --output-version cert-manager.io/v1alpha3`))) - - longDesc = templates.LongDesc(i18n.T(` -Convert cert-manager config files between different API versions. Both YAML -and JSON formats are accepted. - -The command takes filename, directory, or URL as input, and converts into the -format of the version specified by --output-version flag. If target version is -not specified or not supported, it will convert to the latest version - -The default output will be printed to stdout in YAML format. One can use -o option -to change to output destination.`)) -) - var ( // Use this scheme as it has the internal cert-manager types // and their conversion functions registered. @@ -88,10 +67,24 @@ func NewCmdConvert(setupCtx context.Context, ioStreams genericclioptions.IOStrea o := NewOptions(ioStreams) cmd := &cobra.Command{ - Use: "convert", - Short: "Convert cert-manager config files between different API versions", - Long: longDesc, - Example: example, + Use: "convert", + Short: "Convert cert-manager config files between different API versions", + Long: templates.LongDesc(` +Convert cert-manager config files between different API versions. Both YAML +and JSON formats are accepted. + +The command takes filename, directory, or URL as input, and converts into the +format of the version specified by --output-version flag. If target version is +not specified or not supported, it will convert to the latest version + +The default output will be printed to stdout in YAML format. One can use -o option +to change to output destination.`), + Example: templates.Examples(build.WithTemplate(setupCtx, ` +# Convert 'cert.yaml' to latest version and print to stdout. +{{.BuildName}} convert -f cert.yaml + +# Convert kustomize overlay under current directory to 'cert-manager.io/v1alpha3' +{{.BuildName}} convert -k . --output-version cert-manager.io/v1alpha3`)), DisableFlagsInUseLine: true, PreRunE: func(cmd *cobra.Command, args []string) error { return o.Complete() diff --git a/pkg/create/certificaterequest/certificaterequest.go b/pkg/create/certificaterequest/certificaterequest.go index e8df487..be93934 100644 --- a/pkg/create/certificaterequest/certificaterequest.go +++ b/pkg/create/certificaterequest/certificaterequest.go @@ -36,35 +36,12 @@ import ( "k8s.io/apimachinery/pkg/util/wait" "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/cli-runtime/pkg/resource" - "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" "github.com/cert-manager/cmctl/v2/pkg/build" "github.com/cert-manager/cmctl/v2/pkg/factory" ) -var ( - long = templates.LongDesc(i18n.T(` -Create a new CertificateRequest resource based on a Certificate resource, by generating a private key locally and create a 'certificate signing request' to be submitted to a cert-manager Issuer.`)) - - example = templates.Examples(i18n.T(build.WithTemplate(` -# Create a CertificateRequest with the name 'my-cr', saving the private key in a file named 'my-cr.key'. -{{.BuildName}} create certificaterequest my-cr --from-certificate-file my-certificate.yaml - -# Create a CertificateRequest in namespace default, provided no conflict with namespace defined in file. -{{.BuildName}} create certificaterequest my-cr --namespace default --from-certificate-file my-certificate.yaml - -# Create a CertificateRequest and store private key in file 'new.key'. -{{.BuildName}} create certificaterequest my-cr --from-certificate-file my-certificate.yaml --output-key-file new.key - -# Create a CertificateRequest, wait for it to be signed for up to 5 minutes (default) and store the x509 certificate in file 'new.crt'. -{{.BuildName}} create certificaterequest my-cr --from-certificate-file my-certificate.yaml --fetch-certificate --output-cert-file new.crt - -# Create a CertificateRequest, wait for it to be signed for up to 20 minutes and store the x509 certificate in file 'my-cr.crt'. -{{.BuildName}} create certificaterequest my-cr --from-certificate-file my-certificate.yaml --fetch-certificate --timeout 20m -`))) -) - var ( // Dedicated scheme used by the ctl tool that has the internal cert-manager types, // and their conversion functions registered @@ -106,11 +83,27 @@ func NewCmdCreateCR(setupCtx context.Context, ioStreams genericclioptions.IOStre o := NewOptions(ioStreams) cmd := &cobra.Command{ - Use: "certificaterequest", - Aliases: []string{"cr"}, - Short: "Create a cert-manager CertificateRequest resource, using a Certificate resource as a template", - Long: long, - Example: example, + Use: "certificaterequest", + Aliases: []string{"cr"}, + Short: "Create a cert-manager CertificateRequest resource, using a Certificate resource as a template", + Long: templates.LongDesc(` +Create a new CertificateRequest resource based on a Certificate resource, by generating a private key locally and create a 'certificate signing request' to be submitted to a cert-manager Issuer.`), + Example: templates.Examples(build.WithTemplate(setupCtx, ` +# Create a CertificateRequest with the name 'my-cr', saving the private key in a file named 'my-cr.key'. +{{.BuildName}} create certificaterequest my-cr --from-certificate-file my-certificate.yaml + +# Create a CertificateRequest in namespace default, provided no conflict with namespace defined in file. +{{.BuildName}} create certificaterequest my-cr --namespace default --from-certificate-file my-certificate.yaml + +# Create a CertificateRequest and store private key in file 'new.key'. +{{.BuildName}} create certificaterequest my-cr --from-certificate-file my-certificate.yaml --output-key-file new.key + +# Create a CertificateRequest, wait for it to be signed for up to 5 minutes (default) and store the x509 certificate in file 'new.crt'. +{{.BuildName}} create certificaterequest my-cr --from-certificate-file my-certificate.yaml --fetch-certificate --output-cert-file new.crt + +# Create a CertificateRequest, wait for it to be signed for up to 20 minutes and store the x509 certificate in file 'my-cr.crt'. +{{.BuildName}} create certificaterequest my-cr --from-certificate-file my-certificate.yaml --fetch-certificate --timeout 20m +`)), ValidArgsFunction: factory.ValidArgsListCertificateRequests(&o.Factory), PreRunE: func(cmd *cobra.Command, args []string) error { return o.Validate(args) diff --git a/pkg/create/certificatesigningrequest/certificatesigningrequest.go b/pkg/create/certificatesigningrequest/certificatesigningrequest.go index 4d6e76a..9b14bce 100644 --- a/pkg/create/certificatesigningrequest/certificatesigningrequest.go +++ b/pkg/create/certificatesigningrequest/certificatesigningrequest.go @@ -40,35 +40,12 @@ import ( "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/cli-runtime/pkg/resource" "k8s.io/client-go/discovery" - "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" "github.com/cert-manager/cmctl/v2/pkg/build" "github.com/cert-manager/cmctl/v2/pkg/factory" ) -var ( - long = templates.LongDesc(i18n.T(` -Experimental. Only supported for Kubernetes versions 1.19+. Requires -cert-manager versions 1.4+ with experimental controllers enabled. - -Create a new CertificateSigningRequest resource based on a Certificate resource, by generating a private key locally and create a 'certificate signing request' to be submitted to a cert-manager Issuer.`)) - - example = templates.Examples(i18n.T(build.WithTemplate(` -# Create a CertificateSigningRequest with the name 'my-csr', saving the private key in a file named 'my-cr.key'. -{{.BuildName}} x create certificatesigningrequest my-csr --from-certificate-file my-certificate.yaml - -# Create a CertificateSigningRequest and store private key in file 'new.key'. -{{.BuildName}} x create certificatesigningrequest my-csr --from-certificate-file my-certificate.yaml --output-key-file new.key - -# Create a CertificateSigningRequest, wait for it to be signed for up to 5 minutes (default) and store the x509 certificate in file 'new.crt'. -{{.BuildName}} x create csr my-cr -f my-certificate.yaml -c new.crt -w - -# Create a CertificateSigningRequest, wait for it to be signed for up to 20 minutes and store the x509 certificate in file 'my-cr.crt'. -{{.BuildName}} x create csr my-cr --from-certificate-file my-certificate.yaml --fetch-certificate --timeout 20m -`))) -) - var ( // Dedicated scheme used by the ctl tool that has the internal cert-manager types, // and their conversion functions registered @@ -118,11 +95,27 @@ func NewCmdCreateCSR(setupCtx context.Context, ioStreams genericclioptions.IOStr o := NewOptions(ioStreams) cmd := &cobra.Command{ - Use: "certificatesigningrequest", - Aliases: []string{"csr"}, - Short: "Create a Kubernetes CertificateSigningRequest resource, using a Certificate resource as a template", - Long: long, - Example: example, + Use: "certificatesigningrequest", + Aliases: []string{"csr"}, + Short: "Create a Kubernetes CertificateSigningRequest resource, using a Certificate resource as a template", + Long: templates.LongDesc(` +Experimental. Only supported for Kubernetes versions 1.19+. Requires +cert-manager versions 1.4+ with experimental controllers enabled. + +Create a new CertificateSigningRequest resource based on a Certificate resource, by generating a private key locally and create a 'certificate signing request' to be submitted to a cert-manager Issuer.`), + Example: templates.Examples(build.WithTemplate(setupCtx, ` +# Create a CertificateSigningRequest with the name 'my-csr', saving the private key in a file named 'my-cr.key'. +{{.BuildName}} x create certificatesigningrequest my-csr --from-certificate-file my-certificate.yaml + +# Create a CertificateSigningRequest and store private key in file 'new.key'. +{{.BuildName}} x create certificatesigningrequest my-csr --from-certificate-file my-certificate.yaml --output-key-file new.key + +# Create a CertificateSigningRequest, wait for it to be signed for up to 5 minutes (default) and store the x509 certificate in file 'new.crt'. +{{.BuildName}} x create csr my-cr -f my-certificate.yaml -c new.crt -w + +# Create a CertificateSigningRequest, wait for it to be signed for up to 20 minutes and store the x509 certificate in file 'my-cr.crt'. +{{.BuildName}} x create csr my-cr --from-certificate-file my-certificate.yaml --fetch-certificate --timeout 20m +`)), ValidArgsFunction: factory.ValidArgsListCertificateSigningRequests(&o.Factory), PreRunE: func(cmd *cobra.Command, args []string) error { return o.Validate(args) diff --git a/pkg/deny/deny.go b/pkg/deny/deny.go index 474519c..c6c1d63 100644 --- a/pkg/deny/deny.go +++ b/pkg/deny/deny.go @@ -27,26 +27,12 @@ import ( "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/cli-runtime/pkg/genericclioptions" - "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" "github.com/cert-manager/cmctl/v2/pkg/build" "github.com/cert-manager/cmctl/v2/pkg/factory" ) -var ( - example = templates.Examples(i18n.T(build.WithTemplate(` -# Deny a CertificateRequest with the name 'my-cr' -{{.BuildName}} deny my-cr - -# Deny a CertificateRequest in namespace default -{{.BuildName}} deny my-cr --namespace default - -# Deny a CertificateRequest giving a custom reason and message -{{.BuildName}} deny my-cr --reason "ManualDenial" --reason "Denied by PKI department" -`))) -) - // Options is a struct to support create certificaterequest command type Options struct { // Reason is the string that will be set on the Reason field of the Denied @@ -71,10 +57,19 @@ func NewCmdDeny(setupCtx context.Context, ioStreams genericclioptions.IOStreams) o := NewOptions(ioStreams) cmd := &cobra.Command{ - Use: "deny", - Short: "Deny a CertificateRequest", - Long: `Mark a CertificateRequest as Denied, so it may never be signed by a configured Issuer.`, - Example: example, + Use: "deny", + Short: "Deny a CertificateRequest", + Long: `Mark a CertificateRequest as Denied, so it may never be signed by a configured Issuer.`, + Example: templates.Examples(build.WithTemplate(setupCtx, ` +# Deny a CertificateRequest with the name 'my-cr' +{{.BuildName}} deny my-cr + +# Deny a CertificateRequest in namespace default +{{.BuildName}} deny my-cr --namespace default + +# Deny a CertificateRequest giving a custom reason and message +{{.BuildName}} deny my-cr --reason "ManualDenial" --reason "Denied by PKI department" +`)), ValidArgsFunction: factory.ValidArgsListCertificateRequests(&o.Factory), PreRunE: func(cmd *cobra.Command, args []string) error { return o.Validate(args) @@ -87,7 +82,7 @@ func NewCmdDeny(setupCtx context.Context, ioStreams genericclioptions.IOStreams) cmd.Flags().StringVar(&o.Reason, "reason", "KubectlCertManager", "The reason to give as to what denied this CertificateRequest.") - cmd.Flags().StringVar(&o.Message, "message", fmt.Sprintf("manually denied by %q", build.Name()), + cmd.Flags().StringVar(&o.Message, "message", fmt.Sprintf("manually denied by %q", build.Name(setupCtx)), "The message to give as to why this CertificateRequest was denied.") o.Factory = factory.New(cmd) diff --git a/pkg/inspect/secret/secret.go b/pkg/inspect/secret/secret.go index f430b7d..7db549d 100644 --- a/pkg/inspect/secret/secret.go +++ b/pkg/inspect/secret/secret.go @@ -34,7 +34,6 @@ import ( corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/cli-runtime/pkg/genericclioptions" - "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" k8sclock "k8s.io/utils/clock" @@ -81,16 +80,6 @@ const debuggingTemplate = `Debugging: CRL Status: {{ .CRLStatus }} OCSP Status: {{ .OCSPStatus }}` -var ( - long = templates.LongDesc(i18n.T(` -Get details about a kubernetes.io/tls typed secret`)) - - example = templates.Examples(i18n.T(build.WithTemplate(` -# Query information about a secret with name 'my-crt' in namespace 'my-namespace' -{{.BuildName}} inspect secret my-crt --namespace my-namespace -`))) -) - // Options is a struct to support status certificate command type Options struct { genericclioptions.IOStreams @@ -109,10 +98,14 @@ func NewCmdInspectSecret(setupCtx context.Context, ioStreams genericclioptions.I o := NewOptions(ioStreams) cmd := &cobra.Command{ - Use: "secret", - Short: "Get details about a kubernetes.io/tls typed secret", - Long: long, - Example: example, + Use: "secret", + Short: "Get details about a kubernetes.io/tls typed secret", + Long: templates.LongDesc(` +Get details about a kubernetes.io/tls typed secret`), + Example: templates.Examples(build.WithTemplate(setupCtx, ` +# Query information about a secret with name 'my-crt' in namespace 'my-namespace' +{{.BuildName}} inspect secret my-crt --namespace my-namespace +`)), ValidArgsFunction: factory.ValidArgsListSecrets(&o.Factory), PreRunE: func(cmd *cobra.Command, args []string) error { return o.Validate(args) diff --git a/pkg/install/install.go b/pkg/install/install.go index 510b172..c44caae 100644 --- a/pkg/install/install.go +++ b/pkg/install/install.go @@ -54,8 +54,8 @@ const ( installCRDsFlagName = "installCRDs" ) -func installDesc() string { - return build.WithTemplate(`This command installs cert-manager. It uses the Helm libraries to do so. +func installDesc(ctx context.Context) string { + return build.WithTemplate(ctx, `This command installs cert-manager. It uses the Helm libraries to do so. The latest published cert-manager chart in the "https://charts.jetstack.io" repo is used. Most of the features supported by 'helm install' are also supported by this command. @@ -89,7 +89,7 @@ func NewCmdInstall(setupCtx context.Context, ioStreams genericclioptions.IOStrea cmd := &cobra.Command{ Use: "install", Short: "Install cert-manager", - Long: installDesc(), + Long: installDesc(setupCtx), // nolint:contextcheck // False positive RunE: func(cmd *cobra.Command, args []string) error { options.client.Namespace = settings.Namespace() diff --git a/pkg/renew/renew.go b/pkg/renew/renew.go index 729a34e..ea5c55f 100644 --- a/pkg/renew/renew.go +++ b/pkg/renew/renew.go @@ -32,28 +32,12 @@ import ( "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/client-go/kubernetes" cmdutil "k8s.io/kubectl/pkg/cmd/util" - "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" "github.com/cert-manager/cmctl/v2/pkg/build" "github.com/cert-manager/cmctl/v2/pkg/factory" ) -var ( - long = templates.LongDesc(i18n.T(` -Mark cert-manager Certificate resources for manual renewal.`)) - - example = templates.Examples(i18n.T(build.WithTemplate(` -# Renew the Certificates named 'my-app' and 'vault' in the current context namespace. -{{.BuildName}} renew my-app vault - -# Renew all Certificates in the 'kube-system' namespace. -{{.BuildName}} renew --namespace kube-system --all - -# Renew all Certificates in all namespaces, provided those Certificates have the label 'app=my-service' -{{.BuildName}} renew --all-namespaces -l app=my-service`))) -) - // Options is a struct to support renew command type Options struct { LabelSelector string @@ -75,10 +59,19 @@ func NewOptions(ioStreams genericclioptions.IOStreams) *Options { func NewCmdRenew(setupCtx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { o := NewOptions(ioStreams) cmd := &cobra.Command{ - Use: "renew", - Short: "Mark a Certificate for manual renewal", - Long: long, - Example: example, + Use: "renew", + Short: "Mark a Certificate for manual renewal", + Long: templates.LongDesc(` +Mark cert-manager Certificate resources for manual renewal.`), + Example: templates.Examples(build.WithTemplate(setupCtx, ` +# Renew the Certificates named 'my-app' and 'vault' in the current context namespace. +{{.BuildName}} renew my-app vault + +# Renew all Certificates in the 'kube-system' namespace. +{{.BuildName}} renew --namespace kube-system --all + +# Renew all Certificates in all namespaces, provided those Certificates have the label 'app=my-service' +{{.BuildName}} renew --all-namespaces -l app=my-service`)), ValidArgsFunction: factory.ValidArgsListCertificates(&o.Factory), PreRunE: func(cmd *cobra.Command, args []string) error { return o.Validate(cmd, args) diff --git a/pkg/status/certificate/certificate.go b/pkg/status/certificate/certificate.go index d36a9fe..e690d73 100644 --- a/pkg/status/certificate/certificate.go +++ b/pkg/status/certificate/certificate.go @@ -33,23 +33,12 @@ import ( "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/reference" - "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" "github.com/cert-manager/cmctl/v2/pkg/build" "github.com/cert-manager/cmctl/v2/pkg/factory" ) -var ( - long = templates.LongDesc(i18n.T(` -Get details about the current status of a cert-manager Certificate resource, including information on related resources like CertificateRequest or Order.`)) - - example = templates.Examples(i18n.T(build.WithTemplate(` -# Query status of Certificate with name 'my-crt' in namespace 'my-namespace' -{{.BuildName}} status certificate my-crt --namespace my-namespace -`))) -) - // Options is a struct to support status certificate command type Options struct { genericclioptions.IOStreams @@ -88,10 +77,14 @@ func NewCmdStatusCert(setupCtx context.Context, ioStreams genericclioptions.IOSt o := NewOptions(ioStreams) cmd := &cobra.Command{ - Use: "certificate", - Short: "Get details about the current status of a cert-manager Certificate resource", - Long: long, - Example: example, + Use: "certificate", + Short: "Get details about the current status of a cert-manager Certificate resource", + Long: templates.LongDesc(` +Get details about the current status of a cert-manager Certificate resource, including information on related resources like CertificateRequest or Order.`), + Example: templates.Examples(build.WithTemplate(setupCtx, ` +# Query status of Certificate with name 'my-crt' in namespace 'my-namespace' +{{.BuildName}} status certificate my-crt --namespace my-namespace +`)), ValidArgsFunction: factory.ValidArgsListCertificates(&o.Factory), PreRunE: func(cmd *cobra.Command, args []string) error { return o.Validate(args) diff --git a/pkg/uninstall/uninstall.go b/pkg/uninstall/uninstall.go index d0857b4..4928dc4 100644 --- a/pkg/uninstall/uninstall.go +++ b/pkg/uninstall/uninstall.go @@ -53,8 +53,8 @@ const ( releaseName = "cert-manager" ) -func description() string { - return build.WithTemplate(`This command safely uninstalls any Helm-managed release of cert-manager. +func description(ctx context.Context) string { + return build.WithTemplate(ctx, `This command safely uninstalls any Helm-managed release of cert-manager. This command is safe because it will not delete any of the cert-manager CRDs even if they were installed as part of the Helm release. This is to avoid accidentally deleting CRDs and custom resources. @@ -86,7 +86,7 @@ func NewCmd(setupCtx context.Context, ioStreams genericclioptions.IOStreams) *co cmd := &cobra.Command{ Use: "uninstall", Short: "Uninstall cert-manager", - Long: description(), + Long: description(setupCtx), // nolint:contextcheck // False positive RunE: func(cmd *cobra.Command, args []string) error { res, err := run(cmd.Context(), options) diff --git a/pkg/upgrade/migrateapiversion/command.go b/pkg/upgrade/migrateapiversion/command.go index 7a1d00b..b9b2b53 100644 --- a/pkg/upgrade/migrateapiversion/command.go +++ b/pkg/upgrade/migrateapiversion/command.go @@ -23,7 +23,6 @@ import ( apiextinstall "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/install" "k8s.io/apimachinery/pkg/runtime" "k8s.io/cli-runtime/pkg/genericclioptions" - "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" "sigs.k8s.io/controller-runtime/pkg/client" @@ -31,27 +30,6 @@ import ( "github.com/cert-manager/cmctl/v2/pkg/factory" ) -var ( - long = templates.LongDesc(i18n.T(` -Ensures resources in your Kubernetes cluster are persisted in the v1 API version. - -This must be run prior to upgrading to ensure your cluster is ready to upgrade to cert-manager v1.7 and beyond. - -This command must be run with a cluster running cert-manager v1.0 or greater.`)) - - example = templates.Examples(i18n.T(build.WithTemplate(` -# Check the cert-manager installation is ready to be upgraded to v1.7 and perform necessary migrations -# to ensure that the kube-apiserver has stored only v1 API versions. -{{.BuildName}} upgrade migrate-api-version - -# Force migrations to be run, even if the 'status.storedVersion' field on the CRDs does not contain -# old, deprecated API versions. -# This should only be used if you have manually edited/patched the CRDs already. -# It will force a read and a write of ALL cert-manager resources unconditionally. -{{.BuildName}} upgrade migrate-api-version --skip-stored-version-check -`))) -) - // Options is a struct to support renew command type Options struct { genericclioptions.IOStreams @@ -75,10 +53,25 @@ func NewOptions(ioStreams genericclioptions.IOStreams) *Options { func NewCmdMigrate(setupCtx context.Context, ioStreams genericclioptions.IOStreams) *cobra.Command { o := NewOptions(ioStreams) cmd := &cobra.Command{ - Use: "migrate-api-version", - Short: "Migrate all existing persisted cert-manager resources to the v1 API version", - Long: long, - Example: example, + Use: "migrate-api-version", + Short: "Migrate all existing persisted cert-manager resources to the v1 API version", + Long: templates.LongDesc(` +Ensures resources in your Kubernetes cluster are persisted in the v1 API version. + +This must be run prior to upgrading to ensure your cluster is ready to upgrade to cert-manager v1.7 and beyond. + +This command must be run with a cluster running cert-manager v1.0 or greater.`), + Example: templates.Examples(build.WithTemplate(setupCtx, ` +# Check the cert-manager installation is ready to be upgraded to v1.7 and perform necessary migrations +# to ensure that the kube-apiserver has stored only v1 API versions. +{{.BuildName}} upgrade migrate-api-version + +# Force migrations to be run, even if the 'status.storedVersion' field on the CRDs does not contain +# old, deprecated API versions. +# This should only be used if you have manually edited/patched the CRDs already. +# It will force a read and a write of ALL cert-manager resources unconditionally. +{{.BuildName}} upgrade migrate-api-version --skip-stored-version-check +`)), PreRunE: func(cmd *cobra.Command, args []string) error { if err := o.Validate(args); err != nil { return err diff --git a/pkg/version/version.go b/pkg/version/version.go index e26ccee..8e10e75 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -64,8 +64,8 @@ func NewOptions(ioStreams genericclioptions.IOStreams) *Options { } } -func versionLong() string { - return build.WithTemplate(`Print the cert-manager CLI version and the deployed cert-manager version. +func versionLong(ctx context.Context) string { + return build.WithTemplate(ctx, `Print the cert-manager CLI version and the deployed cert-manager version. The CLI version is embedded in the binary and directly displayed. Determining the deployed cert-manager version is done by querying the cert-manger resources. First, the tool looks at the labels of the cert-manager CRD @@ -97,7 +97,7 @@ func NewCmdVersion(setupCtx context.Context, ioStreams genericclioptions.IOStrea cmd := &cobra.Command{ Use: "version", Short: "Print the cert-manager CLI version and the deployed cert-manager version", - Long: versionLong(), + Long: versionLong(setupCtx), PreRunE: func(cmd *cobra.Command, args []string) error { if err := o.Validate(); err != nil { return err From f074757f491a4504c25dbee43fa4a2d7222f370e Mon Sep 17 00:00:00 2001 From: Tim Ramlot <42113979+inteon@users.noreply.github.com> Date: Thu, 16 May 2024 12:32:10 +0200 Subject: [PATCH 2/3] add installation notes to README.md Signed-off-by: Tim Ramlot <42113979+inteon@users.noreply.github.com> --- README.md | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/README.md b/README.md index c8bc66a..4d2e761 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,68 @@ The documentation for `cmctl` can be found on the [cert-manager website](https://cert-manager.io/docs/usage/cmctl/). +## Installation + +> [!Note] +> These instructions are a copy of the [official installation instructions](https://cert-manager.io/docs/usage/cmctl/#installation). + +### Homebrew + +On Mac or Linux if you have [Homebrew](https://brew.sh/) installed, you can install `cmctl` with: + +```sh +brew install cmctl +``` + +This will also install shell completion. + +### Go install + +If you have Go installed, you can install `cmctl` with: + +```sh +go install github.com/cert-manager/cmctl/v2@latest +``` + +### Manual Installation + +You need the `cmctl` file for the platform you're using, these can be found on our [cmctl GitHub releases page](https://github.com/cert-manager/cmctl/releases). +In order to use `cmctl` you need its binary to be accessible under the name `cmctl` in your `$PATH`. Run the following commands to set up the CLI. Replace OS and ARCH with your systems equivalents: + +```sh +OS=$(uname -s | tr A-Z a-z); ARCH=$(uname -m | sed 's/x86_64/amd64/' | sed 's/aarch64/arm64/'); curl -fsSL -o cmctl https://github.com/cert-manager/cmctl/releases/latest/download/cmctl_${OS}_${ARCH} +chmod +x cmctl +sudo mv cmctl /usr/local/bin +# or `sudo mv cmctl /usr/local/bin/kubectl-cert_manager` to use `kubectl cert-manager` instead. +``` + +### Shell Completion + +`cmctl` supports shell completion for most popular shells. To get help on how to enable shell completion, run the following commands: + +```sh +$ cmctl completion --help +# or `kubectl cert-manager completion --help` +... +Available Commands: + bash Generate cert-manager CLI scripts for a Bash shell + fish Generate cert-manager CLI scripts for a Fish shell + powershell Generate cert-manager CLI scripts for a PowerShell shell + zsh Generation cert-manager CLI scripts for a ZSH shell + +$ cmctl completion bash --help +To load completions: +Bash: + $ source <(cmctl completion bash) + # To load completions for each session, execute once: + # Linux: + $ cmctl completion bash > /etc/bash_completion.d/cmctl + + # macOS: + $ cmctl completion bash > /usr/local/etc/bash_completion.d/cmctl +... +``` + ## Versioning Before v2, `cmctl` was located in the cert-manager repository and versioned together with cert-manager. From eecff2150f8d86f311ad829bd07d4a312711bf35 Mon Sep 17 00:00:00 2001 From: Tim Ramlot <42113979+inteon@users.noreply.github.com> Date: Mon, 10 Jun 2024 12:54:30 +0200 Subject: [PATCH 3/3] remove double bracket Signed-off-by: Tim Ramlot <42113979+inteon@users.noreply.github.com> --- pkg/check/api/api.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/check/api/api.go b/pkg/check/api/api.go index 95b1c50..36cb060 100644 --- a/pkg/check/api/api.go +++ b/pkg/check/api/api.go @@ -50,12 +50,12 @@ type Options struct { *factory.Factory } -var checkApiDesc = templates.LongDesc((` +var checkApiDesc = templates.LongDesc(` This check attempts to perform a dry-run create of a cert-manager *v1alpha2* Certificate resource in order to verify that CRDs are installed and all the required webhooks are reachable by the K8S API server. We use v1alpha2 API to ensure that the API server has also connected to the -cert-manager conversion webhook.`)) +cert-manager conversion webhook.`) // NewOptions returns initialized Options func NewOptions(ioStreams genericclioptions.IOStreams) *Options {