From 28f7e7bc78c9156e13615efa9ed7f07dcddd8ff4 Mon Sep 17 00:00:00 2001 From: JoshVanL Date: Mon, 27 Apr 2020 14:49:08 +0100 Subject: [PATCH] Cleans up renew kube flags and adds --namespace validation Signed-off-by: JoshVanL --- cmd/ctl/BUILD.bazel | 5 +++ cmd/ctl/cmd/cmd.go | 18 ++++++++-- cmd/ctl/main.go | 19 +++------- cmd/ctl/pkg/renew/BUILD.bazel | 3 ++ cmd/ctl/pkg/renew/renew.go | 63 ++++++++++++++++++++++----------- cmd/ctl/pkg/renew/renew_test.go | 33 ++++++++++++++--- 6 files changed, 100 insertions(+), 41 deletions(-) diff --git a/cmd/ctl/BUILD.bazel b/cmd/ctl/BUILD.bazel index 1612b048c..f88c743a0 100644 --- a/cmd/ctl/BUILD.bazel +++ b/cmd/ctl/BUILD.bazel @@ -8,7 +8,12 @@ go_library( deps = [ "//cmd/ctl/cmd:go_default_library", "//pkg/util/cmd:go_default_library", +<<<<<<< HEAD "@io_k8s_klog//:go_default_library", +======= + "@com_github_spf13_cobra//:go_default_library", + "@io_k8s_cli_runtime//pkg/genericclioptions:go_default_library", +>>>>>>> 65e8ff5db... Cleans up renew kube flags and adds --namespace validation ], ) diff --git a/cmd/ctl/cmd/cmd.go b/cmd/ctl/cmd/cmd.go index 176033e5d..ebaf09e34 100644 --- a/cmd/ctl/cmd/cmd.go +++ b/cmd/ctl/cmd/cmd.go @@ -17,13 +17,18 @@ limitations under the License. package cmd import ( + "flag" + "fmt" "io" + "os" "github.com/spf13/cobra" "k8s.io/cli-runtime/pkg/genericclioptions" - cmdutil "k8s.io/kubectl/pkg/cmd/util" + // Load all auth plugins _ "k8s.io/client-go/plugin/pkg/client/auth" + "k8s.io/klog" + cmdutil "k8s.io/kubectl/pkg/cmd/util" "github.com/jetstack/cert-manager/cmd/ctl/pkg/convert" "github.com/jetstack/cert-manager/cmd/ctl/pkg/renew" @@ -45,10 +50,19 @@ cert-manager-ctl is a CLI tool manage and configure cert-manager resources for K matchVersionKubeConfigFlags.AddFlags(cmds.PersistentFlags()) factory := cmdutil.NewFactory(matchVersionKubeConfigFlags) + cmds.Flags().AddGoFlagSet(flag.CommandLine) + flag.CommandLine.Parse([]string{}) + fakefs := flag.NewFlagSet("fake", flag.ExitOnError) + klog.InitFlags(fakefs) + if err := fakefs.Parse([]string{"-logtostderr=false"}); err != nil { + fmt.Fprintf(os.Stderr, "%s\n", err) + os.Exit(1) + } + ioStreams := genericclioptions.IOStreams{In: in, Out: out, ErrOut: err} cmds.AddCommand(version.NewCmdVersion(ioStreams)) cmds.AddCommand(convert.NewCmdConvert(ioStreams)) - cmds.AddCommand(renew.NewCmdRenew(ioStreams, factory)) + cmds.AddCommand(renew.NewCmdRenew(ioStreams)) return cmds } diff --git a/cmd/ctl/main.go b/cmd/ctl/main.go index 02aff910e..a9f9c4d54 100644 --- a/cmd/ctl/main.go +++ b/cmd/ctl/main.go @@ -17,27 +17,16 @@ limitations under the License. package main import ( - "flag" "fmt" "os" - "k8s.io/klog" - - ctlcmd "github.com/jetstack/cert-manager/cmd/ctl/cmd" - utilcmd "github.com/jetstack/cert-manager/pkg/util/cmd" + "github.com/jetstack/cert-manager/pkg/util/cmd" ) func main() { - stopCh := utilcmd.SetupSignalHandler() - cmd := ctlcmd.NewCertManagerCtlCommand(os.Stdin, os.Stdout, os.Stderr, stopCh) - cmd.Flags().AddGoFlagSet(flag.CommandLine) - flag.CommandLine.Parse([]string{}) - fakefs := flag.NewFlagSet("fake", flag.ExitOnError) - klog.InitFlags(fakefs) - if err := fakefs.Parse([]string{"-logtostderr=false"}); err != nil { - fmt.Fprintf(os.Stderr, "%s\n", err) - os.Exit(1) - } + stopCh := cmd.SetupSignalHandler() + cmd := NewCertManagerCtlCommand(os.Stdin, os.Stdout, os.Stderr, stopCh) + if err := cmd.Execute(); err != nil { fmt.Fprintf(os.Stderr, "%s\n", err) } diff --git a/cmd/ctl/pkg/renew/BUILD.bazel b/cmd/ctl/pkg/renew/BUILD.bazel index ed09b54a0..8932c07e3 100644 --- a/cmd/ctl/pkg/renew/BUILD.bazel +++ b/cmd/ctl/pkg/renew/BUILD.bazel @@ -15,7 +15,9 @@ go_library( "@io_k8s_apimachinery//pkg/apis/meta/v1:go_default_library", "@io_k8s_cli_runtime//pkg/genericclioptions:go_default_library", "@io_k8s_client_go//kubernetes:go_default_library", + "@io_k8s_client_go//plugin/pkg/client/auth:go_default_library", "@io_k8s_client_go//rest:go_default_library", + "@io_k8s_klog//:go_default_library", "@io_k8s_kubectl//pkg/cmd/util:go_default_library", "@io_k8s_kubectl//pkg/util/i18n:go_default_library", "@io_k8s_kubectl//pkg/util/templates:go_default_library", @@ -40,4 +42,5 @@ go_test( name = "go_default_test", srcs = ["renew_test.go"], embed = [":go_default_library"], + deps = ["@io_k8s_cli_runtime//pkg/genericclioptions:go_default_library"], ) diff --git a/cmd/ctl/pkg/renew/renew.go b/cmd/ctl/pkg/renew/renew.go index 069de9667..53d92bf1d 100644 --- a/cmd/ctl/pkg/renew/renew.go +++ b/cmd/ctl/pkg/renew/renew.go @@ -19,14 +19,19 @@ package renew import ( "context" "errors" + "flag" "fmt" + "os" "github.com/spf13/cobra" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/client-go/kubernetes" + // Load all auth plugins + _ "k8s.io/client-go/plugin/pkg/client/auth" restclient "k8s.io/client-go/rest" + "k8s.io/klog" cmdutil "k8s.io/kubectl/pkg/cmd/util" "k8s.io/kubectl/pkg/util/i18n" "k8s.io/kubectl/pkg/util/templates" @@ -39,27 +44,27 @@ import ( var ( long = templates.LongDesc(i18n.T(` - Mark cert-manager Certificate resources for manual renewal. -`)) +Mark cert-manager Certificate resources for manual renewal.`)) example = templates.Examples(i18n.T(` - # Renew the Certificates named 'my-app' and 'vault' in the current context namespace. - ctl renew my-app vault +# Renew the Certificates named 'my-app' and 'vault' in the current context namespace. +ctl renew my-app vault - # Renew all Certificates in the 'kube-system' namespace. - ctl renew --namespace kube-system --all +# Renew all Certificates in the 'kube-system' namespace. +ctl renew --namespace kube-system --all - # Renew all Certificates in all namespaces that have the label 'app=my-service'. - ctl renew --all-namespaces -l app=my-service`)) +# Renew all Certificates in all namespaces, provided those Certificates have the label 'app=my-service +ctl renew --all-namespaces -l app=my-service`)) ) // Options is a struct to support renew command type Options struct { - // The Namespace that the Certificate to be renewed resided in - Namespace string CMClient cmclient.Interface - RestConfig *restclient.Config + RESTConfig *restclient.Config + // The Namespace that the Certificate to be renewed resided in. + // This flag registration is handled by cmdutil.Factory + Namespace string LabelSelector string All bool AllNamespaces bool @@ -75,17 +80,18 @@ func NewOptions(ioStreams genericclioptions.IOStreams) *Options { } // NewCmdRenew returns a cobra command for renewing Certificates -func NewCmdRenew(ioStreams genericclioptions.IOStreams, factory cmdutil.Factory) *cobra.Command { +func NewCmdRenew(ioStreams genericclioptions.IOStreams) *cobra.Command { o := NewOptions(ioStreams) + var factory cmdutil.Factory cmd := &cobra.Command{ Use: "renew", Short: "Mark a Certificate for manual renewal", - Long: "Mark a Certificate for manual renewal", + Long: long, Example: example, Run: func(cmd *cobra.Command, args []string) { cmdutil.CheckErr(o.Complete(factory)) - cmdutil.CheckErr(o.Validate(args)) + cmdutil.CheckErr(o.Validate(cmd, args)) cmdutil.CheckErr(o.Run(args)) }, } @@ -94,11 +100,26 @@ func NewCmdRenew(ioStreams genericclioptions.IOStreams, factory cmdutil.Factory) cmd.Flags().BoolVarP(&o.AllNamespaces, "all-namespaces", "A", o.AllNamespaces, "If present, mark Certificates across namespaces for manual renewal. Namespace in current context is ignored even if specified with --namespace.") cmd.Flags().BoolVar(&o.All, "all", o.All, "Renew all Certificates in the given Namespace, or all namespaces with --all-namespaces enabled.") + kubeConfigFlags := genericclioptions.NewConfigFlags(true) + kubeConfigFlags.AddFlags(cmd.PersistentFlags()) + matchVersionKubeConfigFlags := cmdutil.NewMatchVersionFlags(kubeConfigFlags) + matchVersionKubeConfigFlags.AddFlags(cmd.PersistentFlags()) + factory = cmdutil.NewFactory(matchVersionKubeConfigFlags) + + cmd.Flags().AddGoFlagSet(flag.CommandLine) + flag.CommandLine.Parse([]string{}) + fakefs := flag.NewFlagSet("fake", flag.ExitOnError) + klog.InitFlags(fakefs) + if err := fakefs.Parse([]string{"-logtostderr=false"}); err != nil { + fmt.Fprintf(os.Stderr, "%s\n", err) + os.Exit(1) + } + return cmd } // Validate validates the provided options -func (o *Options) Validate(args []string) error { +func (o *Options) Validate(cmd *cobra.Command, args []string) error { if len(o.LabelSelector) > 0 && len(args) > 0 { return errors.New("cannot specify Certificate names in conjunction with label selectors") } @@ -111,6 +132,10 @@ func (o *Options) Validate(args []string) error { return errors.New("cannot specify Certificate names in conjunction with --all flag") } + if o.All && cmd.PersistentFlags().Changed("namespace") { + return errors.New("cannot specify --namespace flag in conjunction with --all flag") + } + return nil } @@ -122,12 +147,12 @@ func (o *Options) Complete(f cmdutil.Factory) error { return err } - o.RestConfig, err = f.ToRESTConfig() + o.RESTConfig, err = f.ToRESTConfig() if err != nil { return err } - o.CMClient, err = cmclient.NewForConfig(o.RestConfig) + o.CMClient, err = cmclient.NewForConfig(o.RESTConfig) if err != nil { return err } @@ -141,10 +166,8 @@ func (o *Options) Run(args []string) error { nss := []corev1.Namespace{{ObjectMeta: metav1.ObjectMeta{Name: o.Namespace}}} - // TODO: handle network context - if o.AllNamespaces { - kubeClient, err := kubernetes.NewForConfig(o.RestConfig) + kubeClient, err := kubernetes.NewForConfig(o.RESTConfig) if err != nil { return err } diff --git a/cmd/ctl/pkg/renew/renew_test.go b/cmd/ctl/pkg/renew/renew_test.go index 0076c3660..7817ac043 100644 --- a/cmd/ctl/pkg/renew/renew_test.go +++ b/cmd/ctl/pkg/renew/renew_test.go @@ -18,13 +18,20 @@ package renew import ( "testing" + + "k8s.io/cli-runtime/pkg/genericclioptions" ) +type stringFlag struct { + name, value string +} + func TestValidate(t *testing.T) { tests := map[string]struct { - options *Options - args []string - expErr bool + options *Options + args []string + setStringFlags []stringFlag + expErr bool }{ "If there are arguments, as well as label selector, error": { options: &Options{ @@ -55,12 +62,30 @@ func TestValidate(t *testing.T) { }, expErr: false, }, + "If --namespace and --all namespace specified, error": { + options: &Options{ + All: true, + }, + setStringFlags: []stringFlag{ + {name: "namespace", value: "foo"}, + }, + expErr: true, + }, } for name, test := range tests { t.Run(name, func(t *testing.T) { - err := test.options.Validate(test.args) + cmd := NewCmdRenew(genericclioptions.IOStreams{}) + if test.setStringFlags != nil { + for _, s := range test.setStringFlags { + if err := cmd.PersistentFlags().Set(s.name, s.value); err != nil { + t.Fatal(err) + } + } + } + + err := test.options.Validate(cmd, test.args) if test.expErr != (err != nil) { t.Errorf("expected error=%t got=%v", test.expErr, err)