From 62287253fe237b8695c6c470acf7894d6b03cb2a Mon Sep 17 00:00:00 2001 From: Daniel Pacak Date: Wed, 21 Aug 2019 11:19:36 +0200 Subject: [PATCH] fix: Bind kube client configuration flags before instantiating a kube client (#42) Resolves: #41 --- pkg/cmd/list.go | 94 ++++++++++++++---------------------- pkg/cmd/list_test.go | 52 +++++++++++--------- pkg/cmd/resource_resolver.go | 3 ++ 3 files changed, 68 insertions(+), 81 deletions(-) diff --git a/pkg/cmd/list.go b/pkg/cmd/list.go index cbf46ec..91cc433 100644 --- a/pkg/cmd/list.go +++ b/pkg/cmd/list.go @@ -68,7 +68,7 @@ type Action struct { nonResourceURL string subResource string resourceName string - gr schema.GroupResource + gr schema.GroupResource namespace string allNamespaces bool @@ -96,60 +96,9 @@ type whoCan struct { clioptions.IOStreams } -func NewWhoCanOptions(configFlags *clioptions.ConfigFlags, - clientConfig clientcmd.ClientConfig, - clientNamespace clientcore.NamespaceInterface, - clientRBAC clientrbac.RbacV1Interface, - namespaceValidator NamespaceValidator, - resourceResolver ResourceResolver, - accessChecker AccessChecker, - policyRuleMatcher PolicyRuleMatcher, - streams clioptions.IOStreams) *whoCan { - return &whoCan{ - configFlags: configFlags, - clientConfig: clientConfig, - clientNamespace: clientNamespace, - clientRBAC: clientRBAC, - namespaceValidator: namespaceValidator, - resourceResolver: resourceResolver, - accessChecker: accessChecker, - policyRuleMatcher: policyRuleMatcher, - IOStreams: streams, - } -} - func NewCmdWhoCan(streams clioptions.IOStreams) (*cobra.Command, error) { - configFlags := clioptions.NewConfigFlags(true) - - clientConfig, err := configFlags.ToRESTConfig() - if err != nil { - return nil, fmt.Errorf("getting config: %v", err) - } - - client, err := kubernetes.NewForConfig(clientConfig) - if err != nil { - return nil, fmt.Errorf("creating client: %v", err) - } - - mapper, err := configFlags.ToRESTMapper() - if err != nil { - return nil, fmt.Errorf("getting mapper: %v", err) - } - - clientNamespace := client.CoreV1().Namespaces() - accessChecker := NewAccessChecker(client.AuthorizationV1().SelfSubjectAccessReviews()) - namespaceValidator := NewNamespaceValidator(clientNamespace) - resourceResolver := NewResourceResolver(client.Discovery(), mapper) - - o := NewWhoCanOptions(configFlags, - configFlags.ToRawKubeConfigLoader(), - clientNamespace, - client.RbacV1(), - namespaceValidator, - resourceResolver, - accessChecker, - NewPolicyRuleMatcher(), - streams) + var configFlags *clioptions.ConfigFlags + var o whoCan cmd := &cobra.Command{ Use: whoCanUsage, @@ -157,6 +106,34 @@ func NewCmdWhoCan(streams clioptions.IOStreams) (*cobra.Command, error) { Example: whoCanExample, SilenceUsage: true, RunE: func(cmd *cobra.Command, args []string) error { + clientConfig, err := configFlags.ToRESTConfig() + if err != nil { + return fmt.Errorf("getting config: %v", err) + } + + client, err := kubernetes.NewForConfig(clientConfig) + if err != nil { + return fmt.Errorf("creating client: %v", err) + } + + mapper, err := configFlags.ToRESTMapper() + if err != nil { + return fmt.Errorf("getting mapper: %v", err) + } + + clientNamespace := client.CoreV1().Namespaces() + namespaceValidator := NewNamespaceValidator(clientNamespace) + + o.configFlags = configFlags + o.clientConfig = configFlags.ToRawKubeConfigLoader() + o.clientNamespace = clientNamespace + o.clientRBAC = client.RbacV1() + o.namespaceValidator = namespaceValidator + o.resourceResolver = NewResourceResolver(client.Discovery(), mapper) + o.accessChecker = NewAccessChecker(client.AuthorizationV1().SelfSubjectAccessReviews()) + o.policyRuleMatcher = NewPolicyRuleMatcher() + o.IOStreams = streams + if err := o.Complete(args); err != nil { return err } @@ -171,14 +148,15 @@ func NewCmdWhoCan(streams clioptions.IOStreams) (*cobra.Command, error) { }, } - cmd.PersistentFlags().StringVar(&o.subResource, "subresource", o.subResource, + cmd.Flags().StringVar(&o.subResource, "subresource", o.subResource, "SubResource such as pod/log or deployment/scale") - cmd.PersistentFlags().BoolVarP(&o.allNamespaces, "all-namespaces", "A", false, + cmd.Flags().BoolVarP(&o.allNamespaces, "all-namespaces", "A", o.allNamespaces, "If true, check the specified action in all namespaces.") - flag.CommandLine.VisitAll(func(goflag *flag.Flag) { - cmd.PersistentFlags().AddGoFlag(goflag) + flag.CommandLine.VisitAll(func(gf *flag.Flag) { + cmd.Flags().AddGoFlag(gf) }) + configFlags = clioptions.NewConfigFlags(true) configFlags.AddFlags(cmd.Flags()) return cmd, nil diff --git a/pkg/cmd/list_test.go b/pkg/cmd/list_test.go index 23944e9..e8ebc0c 100644 --- a/pkg/cmd/list_test.go +++ b/pkg/cmd/list_test.go @@ -219,19 +219,21 @@ func TestComplete(t *testing.T) { } // given - o := NewWhoCanOptions(configFlags, - clientConfig, - kubeClient.CoreV1().Namespaces(), - kubeClient.RbacV1(), - namespaceValidator, - resourceResolver, - accessChecker, - policyRuleMatcher, - clioptions.NewTestIOStreamsDiscard()) - - // and - o.namespace = tt.flags.namespace - o.allNamespaces = tt.flags.allNamespaces + o := whoCan{ + Action: Action{ + namespace: tt.flags.namespace, + allNamespaces: tt.flags.allNamespaces, + }, + configFlags: configFlags, + clientConfig: clientConfig, + clientNamespace: kubeClient.CoreV1().Namespaces(), + clientRBAC: kubeClient.RbacV1(), + namespaceValidator: namespaceValidator, + resourceResolver: resourceResolver, + accessChecker: accessChecker, + policyRuleMatcher: policyRuleMatcher, + IOStreams: clioptions.NewTestIOStreamsDiscard(), + } // when err := o.Complete(tt.args) @@ -398,16 +400,20 @@ func TestWhoCan_checkAPIAccess(t *testing.T) { // given configFlags := &clioptions.ConfigFlags{} - wc := NewWhoCanOptions(configFlags, - configFlags.ToRawKubeConfigLoader(), - client.CoreV1().Namespaces(), - client.RbacV1(), - namespaceValidator, - resourceResolver, - accessChecker, - policyRuleMatcher, - clioptions.NewTestIOStreamsDiscard()) - wc.namespace = tt.namespace + wc := whoCan{ + Action: Action{ + namespace: tt.namespace, + }, + configFlags: configFlags, + clientConfig: configFlags.ToRawKubeConfigLoader(), + clientNamespace: client.CoreV1().Namespaces(), + clientRBAC: client.RbacV1(), + namespaceValidator: namespaceValidator, + resourceResolver: resourceResolver, + accessChecker: accessChecker, + policyRuleMatcher: policyRuleMatcher, + IOStreams: clioptions.NewTestIOStreamsDiscard(), + } // when warnings, err := wc.checkAPIAccess() diff --git a/pkg/cmd/resource_resolver.go b/pkg/cmd/resource_resolver.go index c80c6df..7638fea 100644 --- a/pkg/cmd/resource_resolver.go +++ b/pkg/cmd/resource_resolver.go @@ -2,6 +2,7 @@ package cmd import ( "fmt" + "github.com/golang/glog" rbac "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/meta" apismeta "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -43,11 +44,13 @@ func (rv *resourceResolver) Resolve(verb, resource, subResource string) (schema. gvr, err := rv.resolveGVR(resource) if err != nil { + glog.V(3).Infof("Error while resolving GVR for resource %s: %v", resource, err) return schema.GroupResource{}, fmt.Errorf("the server doesn't have a resource type \"%s\"", name) } apiResource, err := rv.resolveAPIResource(gvr, subResource) if err != nil { + glog.V(3).Infof("Error while resolving APIResource for GVR %v and subResource %s: %v", gvr, subResource, err) return schema.GroupResource{}, fmt.Errorf("the server doesn't have a resource type \"%s\"", name) }