diff --git a/cmd/kyverno/main.go b/cmd/kyverno/main.go index dd015ae43b..581d3f76ba 100755 --- a/cmd/kyverno/main.go +++ b/cmd/kyverno/main.go @@ -138,6 +138,7 @@ func main() { webhookCfg := webhookconfig.NewRegister( clientConfig, client, + rCache, serverIP, int32(webhookTimeout), log.Log) @@ -171,6 +172,7 @@ func main() { eventGenerator := event.NewEventGenerator( client, pInformer.Kyverno().V1().ClusterPolicies(), + rCache, log.Log.WithName("EventGenerator")) // Policy Status Handler - deals with all logic related to policy status diff --git a/pkg/dclient/client.go b/pkg/dclient/client.go index 255b6a53ca..7574759915 100644 --- a/pkg/dclient/client.go +++ b/pkg/dclient/client.go @@ -8,8 +8,6 @@ import ( "github.com/go-logr/logr" openapi_v2 "github.com/googleapis/gnostic/OpenAPIv2" - "github.com/kyverno/kyverno/pkg/config" - apps "k8s.io/api/apps/v1" certificates "k8s.io/api/certificates/v1beta1" v1 "k8s.io/api/core/v1" helperv1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -78,19 +76,6 @@ func (c *Client) NewDynamicSharedInformerFactory(defaultResync time.Duration) dy return dynamicinformer.NewDynamicSharedInformerFactory(c.client, defaultResync) } -//GetKubePolicyDeployment returns kube policy depoyment value -func (c *Client) GetKubePolicyDeployment() (*apps.Deployment, error) { - kubePolicyDeployment, err := c.GetResource("", "Deployment", config.KyvernoNamespace, config.KyvernoDeploymentName) - if err != nil { - return nil, err - } - deploy := apps.Deployment{} - if err = runtime.DefaultUnstructuredConverter.FromUnstructured(kubePolicyDeployment.UnstructuredContent(), &deploy); err != nil { - return nil, err - } - return &deploy, nil -} - //GetEventsInterface provides typed interface for events //TODO: can we use dynamic client to fetch the typed interface // or generate a kube client value to access the interface diff --git a/pkg/dclient/client_test.go b/pkg/dclient/client_test.go index 9689d1d8af..2ab750f291 100644 --- a/pkg/dclient/client_test.go +++ b/pkg/dclient/client_test.go @@ -117,11 +117,3 @@ func TestCSRInterface(t *testing.T) { t.Errorf("Testing CSR interface not working: %s", err) } } - -func TestKubePolicyDeployment(t *testing.T) { - f := newFixture(t) - _, err := f.client.GetKubePolicyDeployment() - if err != nil { - t.Fatal(err) - } -} diff --git a/pkg/event/controller.go b/pkg/event/controller.go index 7925a2845d..bf1f5c1cb9 100644 --- a/pkg/event/controller.go +++ b/pkg/event/controller.go @@ -8,8 +8,10 @@ import ( kyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1" kyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1" client "github.com/kyverno/kyverno/pkg/dclient" + "github.com/kyverno/kyverno/pkg/resourcecache" v1 "k8s.io/api/core/v1" errors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/wait" @@ -35,6 +37,7 @@ type Generator struct { admissionCtrRecorder record.EventRecorder // events generated at namespaced policy controller to process 'generate' rule genPolicyRecorder record.EventRecorder + resCache resourcecache.ResourceCache log logr.Logger } @@ -44,7 +47,7 @@ type Interface interface { } //NewEventGenerator to generate a new event controller -func NewEventGenerator(client *client.Client, pInformer kyvernoinformer.ClusterPolicyInformer, log logr.Logger) *Generator { +func NewEventGenerator(client *client.Client, pInformer kyvernoinformer.ClusterPolicyInformer, resCache resourcecache.ResourceCache, log logr.Logger) *Generator { gen := Generator{ client: client, @@ -54,6 +57,7 @@ func NewEventGenerator(client *client.Client, pInformer kyvernoinformer.ClusterP policyCtrRecorder: initRecorder(client, PolicyController, log), admissionCtrRecorder: initRecorder(client, AdmissionController, log), genPolicyRecorder: initRecorder(client, GeneratePolicyController, log), + resCache: resCache, log: log, } return &gen @@ -185,7 +189,7 @@ func (gen *Generator) syncHandler(key Info) error { return err } default: - robj, err = gen.client.GetResource("", key.Kind, key.Namespace, key.Name) + robj, err = gen.getResource(key) if err != nil { if !errors.IsNotFound(err) { logger.Error(err, "failed to get resource", "kind", key.Kind, "name", key.Name, "namespace", key.Namespace) @@ -211,6 +215,21 @@ func (gen *Generator) syncHandler(key Info) error { return nil } +func (gen *Generator) getResource(key Info) (obj *unstructured.Unstructured, err error) { + lister, ok := gen.resCache.GetGVRCache(key.Kind) + if !ok { + if lister, err = gen.resCache.CreateResourceInformer(key.Kind); err != nil { + return nil, err + } + } + + if key.Namespace == "" { + return lister.Lister().Get(key.Name) + } + + return lister.Lister().Namespace(key.Namespace).Get(key.Name) +} + //NewEvent builds a event creation request func NewEvent( log logr.Logger, diff --git a/pkg/resourcecache/main.go b/pkg/resourcecache/main.go index dfc15a3529..096549ae20 100644 --- a/pkg/resourcecache/main.go +++ b/pkg/resourcecache/main.go @@ -1,6 +1,8 @@ package resourcecache import ( + "fmt" + "github.com/go-logr/logr" dclient "github.com/kyverno/kyverno/pkg/dclient" cmap "github.com/orcaman/concurrent-map" @@ -27,6 +29,8 @@ type resourceCache struct { log logr.Logger } +var KyvernoDefaultInformer = []string{"ConfigMap", "Secret", "Deployment", "MutatingWebhookConfiguration", "ValidatingWebhookConfiguration"} + // NewResourceCache - initializes the ResourceCache func NewResourceCache(dclient *dclient.Client, dInformer dynamicinformer.DynamicSharedInformerFactory, logger logr.Logger) (ResourceCache, error) { rCache := &resourceCache{ @@ -36,8 +40,9 @@ func NewResourceCache(dclient *dclient.Client, dInformer dynamicinformer.Dynamic log: logger, } - if _, err := rCache.CreateResourceInformer("ConfigMap"); err != nil { - return nil, err + errs := rCache.CreateInformers(KyvernoDefaultInformer...) + if len(errs) != 0 { + return rCache, fmt.Errorf("failed to register default informers %v", errs) } return rCache, nil diff --git a/pkg/webhookconfig/common.go b/pkg/webhookconfig/common.go index bebc8c4beb..059c0db52b 100644 --- a/pkg/webhookconfig/common.go +++ b/pkg/webhookconfig/common.go @@ -5,7 +5,9 @@ import ( "github.com/kyverno/kyverno/pkg/config" admregapi "k8s.io/api/admissionregistration/v1beta1" + apps "k8s.io/api/apps/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" rest "k8s.io/client-go/rest" ) @@ -47,7 +49,7 @@ func extractCA(config *rest.Config) (result []byte) { func (wrc *Register) constructOwner() v1.OwnerReference { logger := wrc.log - kubePolicyDeployment, err := wrc.client.GetKubePolicyDeployment() + kubePolicyDeployment, err := wrc.getKubePolicyDeployment() if err != nil { logger.Error(err, "failed to construct OwnerReference") @@ -62,6 +64,19 @@ func (wrc *Register) constructOwner() v1.OwnerReference { } } +func (wrc *Register) getKubePolicyDeployment() (*apps.Deployment, error) { + lister, _ := wrc.resCache.GetGVRCache("Deployment") + kubePolicyDeployment, err := lister.NamespacedLister(config.KyvernoNamespace).Get(config.KyvernoDeploymentName) + if err != nil { + return nil, err + } + deploy := apps.Deployment{} + if err = runtime.DefaultUnstructuredConverter.FromUnstructured(kubePolicyDeployment.UnstructuredContent(), &deploy); err != nil { + return nil, err + } + return &deploy, nil +} + // debug mutating webhook func generateDebugMutatingWebhook(name, url string, caData []byte, validate bool, timeoutSeconds int32, resources []string, apiGroups, apiVersions string, operationTypes []admregapi.OperationType) admregapi.MutatingWebhook { sideEffect := admregapi.SideEffectClassNoneOnDryRun diff --git a/pkg/webhookconfig/registration.go b/pkg/webhookconfig/registration.go index cc3b3b5e6f..64ace56bf5 100644 --- a/pkg/webhookconfig/registration.go +++ b/pkg/webhookconfig/registration.go @@ -7,13 +7,13 @@ import ( "sync" "time" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "github.com/go-logr/logr" "github.com/kyverno/kyverno/pkg/config" client "github.com/kyverno/kyverno/pkg/dclient" + "github.com/kyverno/kyverno/pkg/resourcecache" admregapi "k8s.io/api/admissionregistration/v1beta1" errorsapi "k8s.io/apimachinery/pkg/api/errors" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" rest "k8s.io/client-go/rest" ) @@ -31,6 +31,7 @@ const ( type Register struct { client *client.Client clientConfig *rest.Config + resCache resourcecache.ResourceCache serverIP string // when running outside a cluster timeoutSeconds int32 log logr.Logger @@ -40,12 +41,14 @@ type Register struct { func NewRegister( clientConfig *rest.Config, client *client.Client, + resCache resourcecache.ResourceCache, serverIP string, webhookTimeout int32, log logr.Logger) *Register { return &Register{ clientConfig: clientConfig, client: client, + resCache: resCache, serverIP: serverIP, timeoutSeconds: webhookTimeout, log: log.WithName("Register"), @@ -89,26 +92,28 @@ func (wrc *Register) Register() error { return nil } -// CheckWebhooks returns an error if any of the webhooks are not configured +// Check returns an error if any of the webhooks are not configured func (wrc *Register) Check() error { + mutatingCache, _ := wrc.resCache.GetGVRCache(kindMutating) + validatingCache, _ := wrc.resCache.GetGVRCache(kindValidating) - if _, err := wrc.client.GetResource("", kindMutating, "", wrc.getVerifyWebhookMutatingWebhookName()); err != nil { + if _, err := mutatingCache.Lister().Get(wrc.getVerifyWebhookMutatingWebhookName()); err != nil { return err } - if _, err := wrc.client.GetResource("", kindMutating, "", wrc.getResourceMutatingWebhookConfigName()); err != nil { + if _, err := mutatingCache.Lister().Get(wrc.getResourceMutatingWebhookConfigName()); err != nil { return err } - if _, err := wrc.client.GetResource("", kindValidating, "", wrc.getResourceValidatingWebhookConfigName()); err != nil { + if _, err := validatingCache.Lister().Get(wrc.getResourceValidatingWebhookConfigName()); err != nil { return err } - if _, err := wrc.client.GetResource("", kindMutating, "", wrc.getPolicyMutatingWebhookConfigurationName()); err != nil { + if _, err := mutatingCache.Lister().Get(wrc.getPolicyMutatingWebhookConfigurationName()); err != nil { return err } - if _, err := wrc.client.GetResource("", kindValidating, "", wrc.getPolicyValidatingWebhookConfigurationName()); err != nil { + if _, err := validatingCache.Lister().Get(wrc.getPolicyValidatingWebhookConfigurationName()); err != nil { return err }