1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-31 03:45:17 +00:00

1345 use GR lister (#1387)

* improved log message

* added lister for GR

* added label to GR

* added wait for cache is sync
This commit is contained in:
Pooja Singh 2020-12-15 04:22:13 +05:30 committed by GitHub
parent 2ffe9b024b
commit bff7229678
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 78 additions and 25 deletions

View file

@ -220,7 +220,7 @@ func main() {
} }
// GENERATE REQUEST GENERATOR // GENERATE REQUEST GENERATOR
grgen := webhookgenerate.NewGenerator(pclient, stopCh, log.Log.WithName("GenerateRequestGenerator")) grgen := webhookgenerate.NewGenerator(pclient, pInformer.Kyverno().V1().GenerateRequests(), stopCh, log.Log.WithName("GenerateRequestGenerator"))
// GENERATE CONTROLLER // GENERATE CONTROLLER
// - applies generate rules on resources based on generate requests created by webhook // - applies generate rules on resources based on generate requests created by webhook
@ -308,6 +308,7 @@ func main() {
pclient, pclient,
client, client,
tlsPair, tlsPair,
pInformer.Kyverno().V1().GenerateRequests(),
pInformer.Kyverno().V1().ClusterPolicies(), pInformer.Kyverno().V1().ClusterPolicies(),
kubeInformer.Rbac().V1().RoleBindings(), kubeInformer.Rbac().V1().RoleBindings(),
kubeInformer.Rbac().V1().ClusterRoleBindings(), kubeInformer.Rbac().V1().ClusterRoleBindings(),
@ -341,7 +342,7 @@ func main() {
go reportReqGen.Run(2, stopCh) go reportReqGen.Run(2, stopCh)
go prgen.Run(1, stopCh) go prgen.Run(1, stopCh)
go grgen.Run(1) go grgen.Run(1, stopCh)
go configData.Run(stopCh) go configData.Run(stopCh)
go policyCtrl.Run(2, stopCh) go policyCtrl.Run(2, stopCh)
go eventGenerator.Run(3, stopCh) go eventGenerator.Run(3, stopCh)

View file

@ -185,13 +185,13 @@ func (c *Controller) deleteGR(obj interface{}) {
for _, resource := range gr.Status.GeneratedResources { for _, resource := range gr.Status.GeneratedResources {
r, err := c.client.GetResource(resource.APIVersion, resource.Kind, resource.Namespace, resource.Name) r, err := c.client.GetResource(resource.APIVersion, resource.Kind, resource.Namespace, resource.Name)
if err != nil && !apierrors.IsNotFound(err) { if err != nil && !apierrors.IsNotFound(err) {
logger.Error(err, "Generated resource is not deleted", "Resource", resource.Name) logger.Error(err, "failed to fetch generated resource", "resource", resource.Name)
return return
} }
if r != nil && r.GetLabels()["policy.kyverno.io/synchronize"] == "enable" { if r != nil && r.GetLabels()["policy.kyverno.io/synchronize"] == "enable" {
if err := c.client.DeleteResource(r.GetAPIVersion(), r.GetKind(), r.GetNamespace(), r.GetName(), false); err != nil && !apierrors.IsNotFound(err) { if err := c.client.DeleteResource(r.GetAPIVersion(), r.GetKind(), r.GetNamespace(), r.GetName(), false); err != nil && !apierrors.IsNotFound(err) {
logger.Error(err, "Generated resource is not deleted", "Resource", r.GetName()) logger.Error(err, "failed to delete the generated resource", "resource", r.GetName())
return return
} }
} }

View file

@ -20,6 +20,7 @@ import (
apierrors "k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/labels"
) )
func (c *Controller) processGR(gr *kyverno.GenerateRequest) error { func (c *Controller) processGR(gr *kyverno.GenerateRequest) error {
@ -135,15 +136,20 @@ func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyvern
// Removing GR if rule is failed. Used when the generate condition failed but gr exist // Removing GR if rule is failed. Used when the generate condition failed but gr exist
for _, r := range engineResponse.PolicyResponse.Rules { for _, r := range engineResponse.PolicyResponse.Rules {
if !r.Success { if !r.Success {
logger.V(4).Info("querying all generate requests") logger.V(4).Info("querying all generate requests")
grList, err := c.kyvernoClient.KyvernoV1().GenerateRequests(config.KyvernoNamespace).List(contextdefault.TODO(), metav1.ListOptions{}) selector := labels.SelectorFromSet(labels.Set(map[string]string{
"policyName": engineResponse.PolicyResponse.Policy,
"resourceName": engineResponse.PolicyResponse.Resource.Name,
"resourceKind": engineResponse.PolicyResponse.Resource.Kind,
"ResourceNamespace": engineResponse.PolicyResponse.Resource.Namespace,
}))
grList, err := c.grLister.List(selector)
if err != nil { if err != nil {
logger.Error(err, "failed to list generate requests") logger.Error(err, "failed to get generate request for the resource", "kind", engineResponse.PolicyResponse.Resource.Kind, "name", engineResponse.PolicyResponse.Resource.Name, "namespace", engineResponse.PolicyResponse.Resource.Namespace)
continue continue
} }
for _, v := range grList.Items { for _, v := range grList {
if engineResponse.PolicyResponse.Policy == v.Spec.Policy && engineResponse.PolicyResponse.Resource.Name == v.Spec.Resource.Name && engineResponse.PolicyResponse.Resource.Kind == v.Spec.Resource.Kind && engineResponse.PolicyResponse.Resource.Namespace == v.Spec.Resource.Namespace { if engineResponse.PolicyResponse.Policy == v.Spec.Policy && engineResponse.PolicyResponse.Resource.Name == v.Spec.Resource.Name && engineResponse.PolicyResponse.Resource.Kind == v.Spec.Resource.Kind && engineResponse.PolicyResponse.Resource.Namespace == v.Spec.Resource.Namespace {
err := c.kyvernoClient.KyvernoV1().GenerateRequests(config.KyvernoNamespace).Delete(contextdefault.TODO(), v.GetName(), metav1.DeleteOptions{}) err := c.kyvernoClient.KyvernoV1().GenerateRequests(config.KyvernoNamespace).Delete(contextdefault.TODO(), v.GetName(), metav1.DeleteOptions{})
if err != nil { if err != nil {

View file

@ -56,6 +56,7 @@ type Controller struct {
// grSynced returns true if the Generate Request store has been synced at least once // grSynced returns true if the Generate Request store has been synced at least once
grSynced cache.InformerSynced grSynced cache.InformerSynced
// dynamic shared informer factory // dynamic shared informer factory
dynamicInformer dynamicinformer.DynamicSharedInformerFactory dynamicInformer dynamicinformer.DynamicSharedInformerFactory
@ -112,7 +113,7 @@ func NewController(
c.grLister = grInformer.Lister().GenerateRequests(config.KyvernoNamespace) c.grLister = grInformer.Lister().GenerateRequests(config.KyvernoNamespace)
c.policySynced = policyInformer.Informer().HasSynced c.policySynced = policyInformer.Informer().HasSynced
c.grSynced = policyInformer.Informer().HasSynced c.grSynced = grInformer.Informer().HasSynced
//TODO: dynamic registration //TODO: dynamic registration
// Only supported for namespaces // Only supported for namespaces

View file

@ -6,15 +6,20 @@ import (
"time" "time"
backoff "github.com/cenkalti/backoff" backoff "github.com/cenkalti/backoff"
"github.com/gardener/controller-manager-library/pkg/logger"
"github.com/go-logr/logr" "github.com/go-logr/logr"
kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1" kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned" kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
kyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1"
kyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1"
"github.com/kyverno/kyverno/pkg/config" "github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/constant" "github.com/kyverno/kyverno/pkg/constant"
"k8s.io/api/admission/v1beta1" "k8s.io/api/admission/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
utilruntime "k8s.io/apimachinery/pkg/util/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait" "k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/tools/cache"
) )
// GenerateRequests provides interface to manage generate requests // GenerateRequests provides interface to manage generate requests
@ -35,15 +40,20 @@ type Generator struct {
client *kyvernoclient.Clientset client *kyvernoclient.Clientset
stopCh <-chan struct{} stopCh <-chan struct{}
log logr.Logger log logr.Logger
// grLister can list/get generate request from the shared informer's store
grLister kyvernolister.GenerateRequestNamespaceLister
grSynced cache.InformerSynced
} }
// NewGenerator returns a new instance of Generate-Request resource generator // NewGenerator returns a new instance of Generate-Request resource generator
func NewGenerator(client *kyvernoclient.Clientset, stopCh <-chan struct{}, log logr.Logger) *Generator { func NewGenerator(client *kyvernoclient.Clientset, grInformer kyvernoinformer.GenerateRequestInformer, stopCh <-chan struct{}, log logr.Logger) *Generator {
gen := &Generator{ gen := &Generator{
ch: make(chan GeneratorChannel, 1000), ch: make(chan GeneratorChannel, 1000),
client: client, client: client,
stopCh: stopCh, stopCh: stopCh,
log: log, log: log,
grLister: grInformer.Lister().GenerateRequests(config.KyvernoNamespace),
grSynced: grInformer.Informer().HasSynced,
} }
return gen return gen
} }
@ -67,13 +77,19 @@ func (g *Generator) Apply(gr kyverno.GenerateRequestSpec, action v1beta1.Operati
} }
// Run starts the generate request spec // Run starts the generate request spec
func (g *Generator) Run(workers int) { func (g *Generator) Run(workers int, stopCh <-chan struct{}) {
logger := g.log logger := g.log
defer utilruntime.HandleCrash() defer utilruntime.HandleCrash()
logger.V(4).Info("starting") logger.V(4).Info("starting")
defer func() { defer func() {
logger.V(4).Info("shutting down") logger.V(4).Info("shutting down")
}() }()
if !cache.WaitForCacheSync(stopCh, g.grSynced) {
logger.Info("failed to sync informer cache")
return
}
for i := 0; i < workers; i++ { for i := 0; i < workers; i++ {
go wait.Until(g.processApply, constant.GenerateControllerResync, g.stopCh) go wait.Until(g.processApply, constant.GenerateControllerResync, g.stopCh)
} }
@ -93,7 +109,7 @@ func (g *Generator) processApply() {
func (g *Generator) generate(grSpec kyverno.GenerateRequestSpec, action v1beta1.Operation) error { func (g *Generator) generate(grSpec kyverno.GenerateRequestSpec, action v1beta1.Operation) error {
// create/update a generate request // create/update a generate request
if err := retryApplyResource(g.client, grSpec, g.log, action); err != nil { if err := retryApplyResource(g.client, grSpec, g.log, action, g.grLister); err != nil {
return err return err
} }
return nil return nil
@ -106,6 +122,7 @@ func retryApplyResource(client *kyvernoclient.Clientset,
grSpec kyverno.GenerateRequestSpec, grSpec kyverno.GenerateRequestSpec,
log logr.Logger, log logr.Logger,
action v1beta1.Operation, action v1beta1.Operation,
grLister kyvernolister.GenerateRequestNamespaceLister,
) error { ) error {
var i int var i int
var err error var err error
@ -122,14 +139,20 @@ func retryApplyResource(client *kyvernoclient.Clientset,
// generate requests created in kyverno namespace // generate requests created in kyverno namespace
isExist := false isExist := false
if action == v1beta1.Create || action == v1beta1.Update { if action == v1beta1.Create || action == v1beta1.Update {
log.V(4).Info("querying all generate requests") log.V(4).Info("querying all generate requests")
grList, err := client.KyvernoV1().GenerateRequests(config.KyvernoNamespace).List(context.TODO(), metav1.ListOptions{}) selector := labels.SelectorFromSet(labels.Set(map[string]string{
"policyName": grSpec.Policy,
"resourceName": grSpec.Resource.Name,
"resourceKind": grSpec.Resource.Kind,
"ResourceNamespace": grSpec.Resource.Namespace,
}))
grList, err := grLister.List(selector)
if err != nil { if err != nil {
logger.Error(err, "failed to get generate request for the resource", "kind", grSpec.Resource.Kind, "name", grSpec.Resource.Name, "namespace", grSpec.Resource.Namespace)
return err return err
} }
for i, v := range grList.Items { for _, v := range grList {
if grSpec.Policy == v.Spec.Policy && grSpec.Resource.Name == v.Spec.Resource.Name && grSpec.Resource.Kind == v.Spec.Resource.Kind && grSpec.Resource.Namespace == v.Spec.Resource.Namespace { if grSpec.Policy == v.Spec.Policy && grSpec.Resource.Name == v.Spec.Resource.Name && grSpec.Resource.Kind == v.Spec.Resource.Kind && grSpec.Resource.Namespace == v.Spec.Resource.Namespace {
gr.SetLabels(map[string]string{ gr.SetLabels(map[string]string{
"resources-update": "true", "resources-update": "true",
@ -138,7 +161,7 @@ func retryApplyResource(client *kyvernoclient.Clientset,
v.Spec.Context = gr.Spec.Context v.Spec.Context = gr.Spec.Context
v.Spec.Policy = gr.Spec.Policy v.Spec.Policy = gr.Spec.Policy
v.Spec.Resource = gr.Spec.Resource v.Spec.Resource = gr.Spec.Resource
_, err = client.KyvernoV1().GenerateRequests(config.KyvernoNamespace).Update(context.TODO(), &grList.Items[i], metav1.UpdateOptions{}) _, err = client.KyvernoV1().GenerateRequests(config.KyvernoNamespace).Update(context.TODO(), v, metav1.UpdateOptions{})
if err != nil { if err != nil {
return err return err
} }
@ -147,6 +170,12 @@ func retryApplyResource(client *kyvernoclient.Clientset,
} }
if !isExist { if !isExist {
gr.SetGenerateName("gr-") gr.SetGenerateName("gr-")
gr.SetLabels(map[string]string{
"policyName": grSpec.Policy,
"resourceName": grSpec.Resource.Name,
"resourceKind": grSpec.Resource.Kind,
"ResourceNamespace": grSpec.Resource.Namespace,
})
_, err = client.KyvernoV1().GenerateRequests(config.KyvernoNamespace).Create(context.TODO(), &gr, metav1.CreateOptions{}) _, err = client.KyvernoV1().GenerateRequests(config.KyvernoNamespace).Create(context.TODO(), &gr, metav1.CreateOptions{})
if err != nil { if err != nil {
return err return err

View file

@ -20,6 +20,7 @@ import (
v1beta1 "k8s.io/api/admission/v1beta1" v1beta1 "k8s.io/api/admission/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/labels"
) )
//HandleGenerate handles admission-requests for policies with generate rules //HandleGenerate handles admission-requests for policies with generate rules
@ -54,14 +55,20 @@ func (ws *WebhookServer) HandleGenerate(request *v1beta1.AdmissionRequest, polic
engineResponse := engine.Generate(policyContext) engineResponse := engine.Generate(policyContext)
for _, rule := range engineResponse.PolicyResponse.Rules { for _, rule := range engineResponse.PolicyResponse.Rules {
if !rule.Success { if !rule.Success {
ws.log.V(4).Info("querying all generate requests") ws.log.V(4).Info("querying all generate requests")
grList, err := ws.kyvernoClient.KyvernoV1().GenerateRequests(config.KyvernoNamespace).List(contextdefault.TODO(), metav1.ListOptions{}) selector := labels.SelectorFromSet(labels.Set(map[string]string{
"policyName": engineResponse.PolicyResponse.Policy,
"resourceName": engineResponse.PolicyResponse.Resource.Name,
"resourceKind": engineResponse.PolicyResponse.Resource.Kind,
"ResourceNamespace": engineResponse.PolicyResponse.Resource.Namespace,
}))
grList, err := ws.grLister.List(selector)
if err != nil { if err != nil {
logger.Error(err, "failed to list generate request") logger.Error(err, "failed to get generate request for the resource", "kind", engineResponse.PolicyResponse.Resource.Kind, "name", engineResponse.PolicyResponse.Resource.Name, "namespace", engineResponse.PolicyResponse.Resource.Namespace)
continue
} }
for _, v := range grList.Items { for _, v := range grList {
if engineResponse.PolicyResponse.Policy == v.Spec.Policy && engineResponse.PolicyResponse.Resource.Name == v.Spec.Resource.Name && engineResponse.PolicyResponse.Resource.Kind == v.Spec.Resource.Kind && engineResponse.PolicyResponse.Resource.Namespace == v.Spec.Resource.Namespace { if engineResponse.PolicyResponse.Policy == v.Spec.Policy && engineResponse.PolicyResponse.Resource.Name == v.Spec.Resource.Name && engineResponse.PolicyResponse.Resource.Kind == v.Spec.Resource.Kind && engineResponse.PolicyResponse.Resource.Namespace == v.Spec.Resource.Namespace {
err := ws.kyvernoClient.KyvernoV1().GenerateRequests(config.KyvernoNamespace).Delete(contextdefault.TODO(), v.GetName(), metav1.DeleteOptions{}) err := ws.kyvernoClient.KyvernoV1().GenerateRequests(config.KyvernoNamespace).Delete(contextdefault.TODO(), v.GetName(), metav1.DeleteOptions{})
if err != nil { if err != nil {

View file

@ -43,6 +43,12 @@ type WebhookServer struct {
client *client.Client client *client.Client
kyvernoClient *kyvernoclient.Clientset kyvernoClient *kyvernoclient.Clientset
// grLister can list/get generate request from the shared informer's store
grLister kyvernolister.GenerateRequestNamespaceLister
// grSynced returns true if the Generate Request store has been synced at least once
grSynced cache.InformerSynced
// list/get cluster policy resource // list/get cluster policy resource
pLister kyvernolister.ClusterPolicyLister pLister kyvernolister.ClusterPolicyLister
@ -118,6 +124,7 @@ func NewWebhookServer(
kyvernoClient *kyvernoclient.Clientset, kyvernoClient *kyvernoclient.Clientset,
client *client.Client, client *client.Client,
tlsPair *tlsutils.PemPair, tlsPair *tlsutils.PemPair,
grInformer kyvernoinformer.GenerateRequestInformer,
pInformer kyvernoinformer.ClusterPolicyInformer, pInformer kyvernoinformer.ClusterPolicyInformer,
rbInformer rbacinformer.RoleBindingInformer, rbInformer rbacinformer.RoleBindingInformer,
crbInformer rbacinformer.ClusterRoleBindingInformer, crbInformer rbacinformer.ClusterRoleBindingInformer,
@ -153,6 +160,8 @@ func NewWebhookServer(
ws := &WebhookServer{ ws := &WebhookServer{
client: client, client: client,
kyvernoClient: kyvernoClient, kyvernoClient: kyvernoClient,
grLister: grInformer.Lister().GenerateRequests(config.KyvernoNamespace),
grSynced: grInformer.Informer().HasSynced,
pLister: pInformer.Lister(), pLister: pInformer.Lister(),
pSynced: pInformer.Informer().HasSynced, pSynced: pInformer.Informer().HasSynced,
rbLister: rbInformer.Lister(), rbLister: rbInformer.Lister(),
@ -460,7 +469,7 @@ func (ws *WebhookServer) resourceValidation(request *v1beta1.AdmissionRequest) *
// RunAsync TLS server in separate thread and returns control immediately // RunAsync TLS server in separate thread and returns control immediately
func (ws *WebhookServer) RunAsync(stopCh <-chan struct{}) { func (ws *WebhookServer) RunAsync(stopCh <-chan struct{}) {
logger := ws.log logger := ws.log
if !cache.WaitForCacheSync(stopCh, ws.pSynced, ws.rbSynced, ws.crbSynced, ws.rSynced, ws.crSynced) { if !cache.WaitForCacheSync(stopCh, ws.grSynced, ws.pSynced, ws.rbSynced, ws.crbSynced, ws.rSynced, ws.crSynced) {
logger.Info("failed to sync informer cache") logger.Info("failed to sync informer cache")
} }