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

1319 fix throttling ()

* fix policy status and generate controller issues

* shorten ACTION column name

* update logs

* improve naming

* add temp logs for troubleshooting

* cleanup logs

* apply generate policy to old & new resource in webhook

* cleanup log messages

* cleanup log messages

* cleanup log messages

* fix clean up of policy report in init container

Co-authored-by: Jim Bugwadia <jim@nirmata.com>
This commit is contained in:
shuting 2020-12-01 12:30:08 -08:00 committed by GitHub
parent 1c73dd9107
commit 2ec5a0fa42
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 119 additions and 97 deletions

View file

@ -259,6 +259,8 @@ func removeClusterPolicyReport(client *client.Client, kind string) error {
for _, cpolr := range cpolrs.Items { for _, cpolr := range cpolrs.Items {
if err := client.DeleteResource(cpolr.GetAPIVersion(), cpolr.GetKind(), "", cpolr.GetName(), false); err != nil { if err := client.DeleteResource(cpolr.GetAPIVersion(), cpolr.GetKind(), "", cpolr.GetName(), false); err != nil {
logger.Error(err, "failed to delete clusterPolicyReport", "name", cpolr.GetName()) logger.Error(err, "failed to delete clusterPolicyReport", "name", cpolr.GetName())
} else {
logger.Info("successfully cleaned up ClusterPolicyReport")
} }
} }
return nil return nil
@ -276,10 +278,12 @@ func removePolicyReport(client *client.Client, kind string) error {
// name of namespace policy report follows the name convention // name of namespace policy report follows the name convention
// policyreport-ns-<namespace name> // policyreport-ns-<namespace name>
for _, ns := range namespaces.Items { for _, ns := range namespaces.Items {
reportName := fmt.Sprintf("policyreport-ns-%s", ns.GetName()) reportName := fmt.Sprintf("pr-ns-%s", ns.GetName())
err := client.DeleteResource("", kind, ns.GetName(), reportName, false) err := client.DeleteResource("", kind, ns.GetName(), reportName, false)
if err != nil && !errors.IsNotFound(err) { if err != nil && !errors.IsNotFound(err) {
logger.Error(err, "failed to delete policyReport", "name", reportName) logger.Error(err, "failed to delete policyReport", "name", reportName)
} else {
logger.Info("successfully cleaned up PolicyReport", "name", reportName)
} }
} }

View file

@ -276,6 +276,10 @@ func (c ServerPreferredResources) OpenAPISchema() (*openapi_v2.Document, error)
// GetGVRFromKind get the Group Version Resource from kind // GetGVRFromKind get the Group Version Resource from kind
func (c ServerPreferredResources) GetGVRFromKind(kind string) schema.GroupVersionResource { func (c ServerPreferredResources) GetGVRFromKind(kind string) schema.GroupVersionResource {
if kind == "" {
return schema.GroupVersionResource{}
}
_, gvr, err := c.FindResource("", kind) _, gvr, err := c.FindResource("", kind)
if err != nil { if err != nil {
c.log.Info("schema not found", "kind", kind) c.log.Info("schema not found", "kind", kind)
@ -289,7 +293,7 @@ func (c ServerPreferredResources) GetGVRFromKind(kind string) schema.GroupVersio
func (c ServerPreferredResources) GetGVRFromAPIVersionKind(apiVersion string, kind string) schema.GroupVersionResource { func (c ServerPreferredResources) GetGVRFromAPIVersionKind(apiVersion string, kind string) schema.GroupVersionResource {
_, gvr, err := c.FindResource(apiVersion, kind) _, gvr, err := c.FindResource(apiVersion, kind)
if err != nil { if err != nil {
c.log.Info("schema not found", "kind", kind, "apiVersion", apiVersion, "Error : ", err) c.log.Info("schema not found", "kind", kind, "apiVersion", apiVersion, "error : ", err)
return schema.GroupVersionResource{} return schema.GroupVersionResource{}
} }

View file

@ -20,33 +20,37 @@ import (
// 2. returns the list of rules that are applicable on this policy and resource, if 1 succeed // 2. returns the list of rules that are applicable on this policy and resource, if 1 succeed
func Generate(policyContext PolicyContext) (resp response.EngineResponse) { func Generate(policyContext PolicyContext) (resp response.EngineResponse) {
policy := policyContext.Policy policy := policyContext.Policy
resource := policyContext.NewResource new := policyContext.NewResource
old := policyContext.OldResource
admissionInfo := policyContext.AdmissionInfo admissionInfo := policyContext.AdmissionInfo
ctx := policyContext.Context ctx := policyContext.Context
resCache := policyContext.ResourceCache resCache := policyContext.ResourceCache
jsonContext := policyContext.JSONContext jsonContext := policyContext.JSONContext
logger := log.Log.WithName("Generate").WithValues("policy", policy.Name, "kind", resource.GetKind(), "namespace", resource.GetNamespace(), "name", resource.GetName()) logger := log.Log.WithName("Generate").WithValues("policy", policy.Name, "kind", new.GetKind(), "namespace", new.GetNamespace(), "name", new.GetName())
return filterRules(policy, resource, admissionInfo, ctx, logger, policyContext.ExcludeGroupRole, resCache, jsonContext) return filterRules(policy, new, old, admissionInfo, ctx, logger, policyContext.ExcludeGroupRole, resCache, jsonContext)
} }
func filterRule(rule kyverno.Rule, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo, ctx context.EvalInterface, log logr.Logger, excludeGroupRole []string, resCache resourcecache.ResourceCacheIface, jsonContext *context.Context) *response.RuleResponse { func filterRule(rule kyverno.Rule, new, old unstructured.Unstructured, admissionInfo kyverno.RequestInfo, ctx context.EvalInterface, log logr.Logger, excludeGroupRole []string, resCache resourcecache.ResourceCacheIface, jsonContext *context.Context) *response.RuleResponse {
if !rule.HasGenerate() { if !rule.HasGenerate() {
return nil return nil
} }
startTime := time.Now() startTime := time.Now()
if err := MatchesResourceDescription(resource, rule, admissionInfo, excludeGroupRole); err != nil { if err := MatchesResourceDescription(new, rule, admissionInfo, excludeGroupRole); err != nil {
return &response.RuleResponse{ if err := MatchesResourceDescription(old, rule, admissionInfo, excludeGroupRole); err == nil {
Name: rule.Name, return &response.RuleResponse{
Type: "Generation", Name: rule.Name,
Success: false, Type: "Generation",
RuleStats: response.RuleStats{ Success: false,
ProcessingTime: time.Since(startTime), RuleStats: response.RuleStats{
}, ProcessingTime: time.Since(startTime),
},
}
} }
return nil
} }
// add configmap json data to context // add configmap json data to context
@ -74,19 +78,19 @@ func filterRule(rule kyverno.Rule, resource unstructured.Unstructured, admission
} }
} }
func filterRules(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, admissionInfo kyverno.RequestInfo, ctx context.EvalInterface, log logr.Logger, excludeGroupRole []string, resCache resourcecache.ResourceCacheIface, jsonContext *context.Context) response.EngineResponse { func filterRules(policy kyverno.ClusterPolicy, new, old unstructured.Unstructured, admissionInfo kyverno.RequestInfo, ctx context.EvalInterface, log logr.Logger, excludeGroupRole []string, resCache resourcecache.ResourceCacheIface, jsonContext *context.Context) response.EngineResponse {
resp := response.EngineResponse{ resp := response.EngineResponse{
PolicyResponse: response.PolicyResponse{ PolicyResponse: response.PolicyResponse{
Policy: policy.Name, Policy: policy.Name,
Resource: response.ResourceSpec{ Resource: response.ResourceSpec{
Kind: resource.GetKind(), Kind: new.GetKind(),
Name: resource.GetName(), Name: new.GetName(),
Namespace: resource.GetNamespace(), Namespace: new.GetNamespace(),
}, },
}, },
} }
for _, rule := range policy.Spec.Rules { for _, rule := range policy.Spec.Rules {
if ruleResp := filterRule(rule, resource, admissionInfo, ctx, log, excludeGroupRole, resCache, jsonContext); ruleResp != nil { if ruleResp := filterRule(rule, new, old, admissionInfo, ctx, log, excludeGroupRole, resCache, jsonContext); ruleResp != nil {
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, *ruleResp) resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, *ruleResp)
} }
} }

View file

@ -23,7 +23,7 @@ import (
) )
const ( const (
maxRetries = 5 maxRetries = 10
) )
//Controller manages life-cycle of generate-requests //Controller manages life-cycle of generate-requests
@ -204,7 +204,8 @@ func (c *Controller) enqueue(gr *kyverno.GenerateRequest) {
logger.Error(err, "failed to extract key") logger.Error(err, "failed to extract key")
return return
} }
logger.V(4).Info("eneque generate request", "name", gr.Name)
logger.V(5).Info("enqueue generate request", "name", gr.Name)
c.queue.Add(key) c.queue.Add(key)
} }
@ -253,18 +254,18 @@ func (c *Controller) handleErr(err error, key interface{}) {
} }
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
logger.V(4).Info("dropping generate request", "key", key, "error", err.Error())
c.queue.Forget(key) c.queue.Forget(key)
logger.V(4).Info("Dropping generate request from the queue", "key", key, "error", err.Error())
return return
} }
if c.queue.NumRequeues(key) < maxRetries { if c.queue.NumRequeues(key) < maxRetries {
logger.Error(err, "failed to sync generate request", "key", key) logger.V(3).Info("retrying generate request", "key", key, "error", err.Error())
c.queue.AddRateLimited(key) c.queue.AddRateLimited(key)
return return
} }
utilruntime.HandleError(err)
logger.Error(err, "dropping generate request out of the queue", "key", key) logger.Error(err, "failed to cleanup generate request", "key", key)
c.queue.Forget(key) c.queue.Forget(key)
} }

View file

@ -57,7 +57,9 @@ func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyvern
// build context // build context
ctx := context.NewContext() ctx := context.NewContext()
policyObj, err := c.pLister.Get(gr.Spec.Policy) logger.V(3).Info("applying generate policy rule")
policyObj, err := c.policyLister.Get(gr.Spec.Policy)
if err != nil { if err != nil {
if apierrors.IsNotFound(err) { if apierrors.IsNotFound(err) {
for _, e := range gr.Status.GeneratedResources { for _, e := range gr.Status.GeneratedResources {
@ -69,7 +71,7 @@ func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyvern
if resp != nil && resp.GetLabels()["policy.kyverno.io/synchronize"] == "enable" { if resp != nil && resp.GetLabels()["policy.kyverno.io/synchronize"] == "enable" {
if err := c.client.DeleteResource(resp.GetAPIVersion(), resp.GetKind(), resp.GetNamespace(), resp.GetName(), false); err != nil { if err := c.client.DeleteResource(resp.GetAPIVersion(), resp.GetKind(), resp.GetNamespace(), resp.GetName(), false); err != nil {
logger.Error(err, "Generated resource is not deleted", "Resource", e.Name) logger.Error(err, "generated resource is not deleted", "Resource", e.Name)
} }
} }
} }
@ -86,16 +88,19 @@ func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyvern
logger.Error(err, "failed to marshal resource") logger.Error(err, "failed to marshal resource")
return nil, err return nil, err
} }
err = ctx.AddResource(resourceRaw) err = ctx.AddResource(resourceRaw)
if err != nil { if err != nil {
logger.Error(err, "failed to load resource in context") logger.Error(err, "failed to load resource in context")
return nil, err return nil, err
} }
err = ctx.AddUserInfo(gr.Spec.Context.UserRequestInfo) err = ctx.AddUserInfo(gr.Spec.Context.UserRequestInfo)
if err != nil { if err != nil {
logger.Error(err, "failed to load SA in context") logger.Error(err, "failed to load SA in context")
return nil, err return nil, err
} }
err = ctx.AddSA(gr.Spec.Context.UserRequestInfo.AdmissionUserInfo.Username) err = ctx.AddSA(gr.Spec.Context.UserRequestInfo.AdmissionUserInfo.Username)
if err != nil { if err != nil {
logger.Error(err, "failed to load UserInfo in context") logger.Error(err, "failed to load UserInfo in context")
@ -116,12 +121,14 @@ func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyvern
engineResponse := engine.Generate(policyContext) engineResponse := engine.Generate(policyContext)
if len(engineResponse.PolicyResponse.Rules) == 0 { if len(engineResponse.PolicyResponse.Rules) == 0 {
logger.V(4).Info("policy does not apply to resource") logger.V(4).Info("policy does not apply to resource")
return nil, fmt.Errorf("policy %s, dont not apply to resource %v", gr.Spec.Policy, gr.Spec.Resource) return nil, fmt.Errorf("policy %s, does not apply to resource %v", gr.Spec.Policy, gr.Spec.Resource)
} }
// 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")
grList, err := c.kyvernoClient.KyvernoV1().GenerateRequests(config.KyvernoNamespace).List(contextdefault.TODO(), metav1.ListOptions{}) grList, err := c.kyvernoClient.KyvernoV1().GenerateRequests(config.KyvernoNamespace).List(contextdefault.TODO(), metav1.ListOptions{})
if err != nil { if err != nil {
logger.Error(err, "failed to list generate requests") logger.Error(err, "failed to list generate requests")
@ -350,12 +357,12 @@ func applyRule(log logr.Logger, client *dclient.Client, rule kyverno.Rule, resou
// Reset resource version // Reset resource version
newResource.SetResourceVersion("") newResource.SetResourceVersion("")
// Create the resource // Create the resource
logger.V(4).Info("creating new resource")
_, err = client.CreateResource(genAPIVersion, genKind, genNamespace, newResource, false) _, err = client.CreateResource(genAPIVersion, genKind, genNamespace, newResource, false)
if err != nil { if err != nil {
return noGenResource, err return noGenResource, err
} }
logger.V(2).Info("created generated resource")
logger.V(2).Info("created resource")
} else if mode == Update { } else if mode == Update {
var isUpdate bool var isUpdate bool

View file

@ -26,8 +26,7 @@ import (
) )
const ( const (
maxRetries = 5 maxRetries = 10
resyncPeriod = 15 * time.Minute
) )
// Controller manages the life-cycle for Generate-Requests and applies generate rule // Controller manages the life-cycle for Generate-Requests and applies generate rule
@ -36,27 +35,30 @@ type Controller struct {
client *dclient.Client client *dclient.Client
// typed client for Kyverno CRDs // typed client for Kyverno CRDs
kyvernoClient *kyvernoclient.Clientset kyvernoClient *kyvernoclient.Clientset
// event generator interface // event generator interface
eventGen event.Interface eventGen event.Interface
// handler for GR CR
syncHandler func(grKey string) error
// handler to enqueue GR
enqueueGR func(gr *kyverno.GenerateRequest)
// grStatusControl is used to update GR status // grStatusControl is used to update GR status
statusControl StatusControlInterface statusControl StatusControlInterface
// Gr that need to be synced
// GR that need to be synced
queue workqueue.RateLimitingInterface queue workqueue.RateLimitingInterface
// pLister can list/get cluster policy from the shared informer's store
pLister kyvernolister.ClusterPolicyLister // policyLister can list/get cluster policy from the shared informer's store
policyLister kyvernolister.ClusterPolicyLister
// grLister can list/get generate request from the shared informer's store // grLister can list/get generate request from the shared informer's store
grLister kyvernolister.GenerateRequestNamespaceLister grLister kyvernolister.GenerateRequestNamespaceLister
// pSynced returns true if the Cluster policy store has been synced at least once
pSynced cache.InformerSynced // policySynced returns true if the Cluster policy store has been synced at least once
policySynced cache.InformerSynced
// 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
//TODO: list of generic informers //TODO: list of generic informers
// only support Namespaces for re-evalutation on resource updates // only support Namespaces for re-evalutation on resource updates
nsInformer informers.GenericInformer nsInformer informers.GenericInformer
@ -69,31 +71,33 @@ type Controller struct {
//NewController returns an instance of the Generate-Request Controller //NewController returns an instance of the Generate-Request Controller
func NewController( func NewController(
kyvernoclient *kyvernoclient.Clientset, kyvernoClient *kyvernoclient.Clientset,
client *dclient.Client, client *dclient.Client,
pInformer kyvernoinformer.ClusterPolicyInformer, policyInformer kyvernoinformer.ClusterPolicyInformer,
grInformer kyvernoinformer.GenerateRequestInformer, grInformer kyvernoinformer.GenerateRequestInformer,
eventGen event.Interface, eventGen event.Interface,
dynamicInformer dynamicinformer.DynamicSharedInformerFactory, dynamicInformer dynamicinformer.DynamicSharedInformerFactory,
policyStatus policystatus.Listener, policyStatus policystatus.Listener,
log logr.Logger, log logr.Logger,
dynamicConfig config.Interface, dynamicConfig config.Interface,
resCache resourcecache.ResourceCacheIface, resourceCache resourcecache.ResourceCacheIface,
) *Controller { ) *Controller {
c := Controller{ c := Controller{
client: client, client: client,
kyvernoClient: kyvernoclient, kyvernoClient: kyvernoClient,
eventGen: eventGen, eventGen: eventGen,
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "generate-request"), queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "generate-request"),
dynamicInformer: dynamicInformer, dynamicInformer: dynamicInformer,
log: log, log: log,
policyStatusListener: policyStatus, policyStatusListener: policyStatus,
Config: dynamicConfig, Config: dynamicConfig,
resCache: resCache, resCache: resourceCache,
} }
c.statusControl = StatusControl{client: kyvernoclient}
pInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ c.statusControl = StatusControl{client: kyvernoClient}
policyInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
UpdateFunc: c.updatePolicy, // We only handle updates to policy UpdateFunc: c.updatePolicy, // We only handle updates to policy
// Deletion of policy will be handled by cleanup controller // Deletion of policy will be handled by cleanup controller
}) })
@ -104,14 +108,11 @@ func NewController(
DeleteFunc: c.deleteGR, DeleteFunc: c.deleteGR,
}) })
c.enqueueGR = c.enqueue c.policyLister = policyInformer.Lister()
c.syncHandler = c.syncGenerateRequest
c.pLister = pInformer.Lister()
c.grLister = grInformer.Lister().GenerateRequests(config.KyvernoNamespace) c.grLister = grInformer.Lister().GenerateRequests(config.KyvernoNamespace)
c.pSynced = pInformer.Informer().HasSynced c.policySynced = policyInformer.Informer().HasSynced
c.grSynced = pInformer.Informer().HasSynced c.grSynced = policyInformer.Informer().HasSynced
//TODO: dynamic registration //TODO: dynamic registration
// Only supported for namespaces // Only supported for namespaces
@ -130,22 +131,24 @@ func (c *Controller) updateGenericResource(old, cur interface{}) {
grs, err := c.grLister.GetGenerateRequestsForResource(curR.GetKind(), curR.GetNamespace(), curR.GetName()) grs, err := c.grLister.GetGenerateRequestsForResource(curR.GetKind(), curR.GetNamespace(), curR.GetName())
if err != nil { if err != nil {
logger.Error(err, "failed to get generate request CR for the resoource", "kind", curR.GetKind(), "name", curR.GetName(), "namespace", curR.GetNamespace()) logger.Error(err, "failed to get generate request CR for the resource", "kind", curR.GetKind(), "name", curR.GetName(), "namespace", curR.GetNamespace())
return return
} }
// re-evaluate the GR as the resource was updated // re-evaluate the GR as the resource was updated
for _, gr := range grs { for _, gr := range grs {
c.enqueueGR(gr) c.enqueueGenerateRequest(gr)
} }
} }
func (c *Controller) enqueue(gr *kyverno.GenerateRequest) { func (c *Controller) enqueueGenerateRequest(gr *kyverno.GenerateRequest) {
c.log.V(5).Info("enqueuing generate request", "gr", gr.Name)
key, err := cache.MetaNamespaceKeyFunc(gr) key, err := cache.MetaNamespaceKeyFunc(gr)
if err != nil { if err != nil {
c.log.Error(err, "failed to extract name") c.log.Error(err, "failed to extract name")
return return
} }
c.queue.Add(key) c.queue.Add(key)
} }
@ -171,21 +174,23 @@ func (c *Controller) updatePolicy(old, cur interface{}) {
} }
logger.V(4).Info("updating policy", "name", oldP.Name) logger.V(4).Info("updating policy", "name", oldP.Name)
// get the list of GR for the current Policy version // get the list of GR for the current Policy version
grs, err := c.grLister.GetGenerateRequestsForClusterPolicy(curP.Name) grs, err := c.grLister.GetGenerateRequestsForClusterPolicy(curP.Name)
if err != nil { if err != nil {
logger.Error(err, "failed to generate request for policy", "name", curP.Name) logger.Error(err, "failed to generate request for policy", "name", curP.Name)
return return
} }
// re-evaluate the GR as the policy was updated // re-evaluate the GR as the policy was updated
for _, gr := range grs { for _, gr := range grs {
c.enqueueGR(gr) c.enqueueGenerateRequest(gr)
} }
} }
func (c *Controller) addGR(obj interface{}) { func (c *Controller) addGR(obj interface{}) {
gr := obj.(*kyverno.GenerateRequest) gr := obj.(*kyverno.GenerateRequest)
c.enqueueGR(gr) c.enqueueGenerateRequest(gr)
} }
func (c *Controller) updateGR(old, cur interface{}) { func (c *Controller) updateGR(old, cur interface{}) {
@ -201,7 +206,7 @@ func (c *Controller) updateGR(old, cur interface{}) {
if curGr.Status.State == kyverno.Failed { if curGr.Status.State == kyverno.Failed {
return return
} }
c.enqueueGR(curGr) c.enqueueGenerateRequest(curGr)
} }
func (c *Controller) deleteGR(obj interface{}) { func (c *Controller) deleteGR(obj interface{}) {
@ -232,9 +237,11 @@ func (c *Controller) deleteGR(obj interface{}) {
} }
} }
} }
logger.V(3).Info("deleting generate request", "name", gr.Name) logger.V(3).Info("deleting generate request", "name", gr.Name)
// sync Handler will remove it from the queue // sync Handler will remove it from the queue
c.enqueueGR(gr) c.enqueueGenerateRequest(gr)
} }
//Run ... //Run ...
@ -246,7 +253,7 @@ func (c *Controller) Run(workers int, stopCh <-chan struct{}) {
logger.Info("starting") logger.Info("starting")
defer logger.Info("shutting down") defer logger.Info("shutting down")
if !cache.WaitForCacheSync(stopCh, c.pSynced, c.grSynced) { if !cache.WaitForCacheSync(stopCh, c.policySynced, c.grSynced) {
logger.Info("failed to sync informer cache") logger.Info("failed to sync informer cache")
return return
} }
@ -269,7 +276,7 @@ func (c *Controller) processNextWorkItem() bool {
return false return false
} }
defer c.queue.Done(key) defer c.queue.Done(key)
err := c.syncHandler(key.(string)) err := c.syncGenerateRequest(key.(string))
c.handleErr(err, key) c.handleErr(err, key)
return true return true
@ -289,12 +296,12 @@ func (c *Controller) handleErr(err error, key interface{}) {
} }
if c.queue.NumRequeues(key) < maxRetries { if c.queue.NumRequeues(key) < maxRetries {
logger.Error(err, "failed to sync generate request", "key", key) logger.V(3).Info("retrying generate request", "key", key, "error", err.Error())
c.queue.AddRateLimited(key) c.queue.AddRateLimited(key)
return return
} }
utilruntime.HandleError(err)
logger.Error(err, "Dropping generate request from the queue", "key", key) logger.Error(err, "failed to process generate request", "key", key)
c.queue.Forget(key) c.queue.Forget(key)
} }
@ -304,7 +311,7 @@ func (c *Controller) syncGenerateRequest(key string) error {
startTime := time.Now() startTime := time.Now()
logger.V(4).Info("started sync", "key", key, "startTime", startTime) logger.V(4).Info("started sync", "key", key, "startTime", startTime)
defer func() { defer func() {
logger.V(4).Info("finished sync", "key", key, "processingTime", time.Since(startTime).String()) logger.V(4).Info("completed sync generate request", "key", key, "processingTime", time.Since(startTime).String())
}() }()
_, grName, err := cache.SplitMetaNamespaceKey(key) _, grName, err := cache.SplitMetaNamespaceKey(key)

View file

@ -49,6 +49,7 @@ func (sc StatusControl) Success(gr kyverno.GenerateRequest, genResources []kyver
log.Log.Error(err, "failed to update generate request status", "name", gr.Name) log.Log.Error(err, "failed to update generate request status", "name", gr.Name)
return err return err
} }
log.Log.V(3).Info("updated generate request status", "name", gr.Name, "status", string(kyverno.Completed)) log.Log.V(3).Info("updated generate request status", "name", gr.Name, "status", string(kyverno.Completed))
return nil return nil
} }

View file

@ -220,14 +220,13 @@ func (g *ReportGenerator) handleErr(err error, key interface{}) {
// retires requests if there is error // retires requests if there is error
if g.queue.NumRequeues(key) < workQueueRetryLimit { if g.queue.NumRequeues(key) < workQueueRetryLimit {
logger.Error(err, "failed to sync policy report", "key", key) logger.V(3).Info("retrying policy report", "key", key, "error", err.Error())
// Re-enqueue the key rate limited. Based on the rate limiter on the
// queue and the re-enqueue history, the key will be processed later again.
g.queue.AddRateLimited(key) g.queue.AddRateLimited(key)
return return
} }
logger.Error(err, "failed to process policy report", "key", key)
g.queue.Forget(key) g.queue.Forget(key)
logger.Error(err, "dropping key out of the queue", "key", key)
} }
// syncHandler reconciles clusterPolicyReport if namespace == "" // syncHandler reconciles clusterPolicyReport if namespace == ""

View file

@ -31,7 +31,7 @@ import (
) )
const workQueueName = "report-request-controller" const workQueueName = "report-request-controller"
const workQueueRetryLimit = 3 const workQueueRetryLimit = 10
// Generator creates report request // Generator creates report request
type Generator struct { type Generator struct {
@ -197,18 +197,16 @@ func (gen *Generator) handleErr(err error, key interface{}) {
// retires requests if there is error // retires requests if there is error
if gen.queue.NumRequeues(key) < workQueueRetryLimit { if gen.queue.NumRequeues(key) < workQueueRetryLimit {
logger.Error(err, "failed to sync report request", "key", key) logger.V(3).Info("retrying report request", "key", key, "error", err)
// Re-enqueue the key rate limited. Based on the rate limiter on the
// queue and the re-enqueue history, the key will be processed later again.
gen.queue.AddRateLimited(key) gen.queue.AddRateLimited(key)
return return
} }
logger.Error(err, "failed to process report request", "key", key)
gen.queue.Forget(key) gen.queue.Forget(key)
// remove from data store
if keyHash, ok := key.(string); ok { if keyHash, ok := key.(string); ok {
gen.dataStore.delete(keyHash) gen.dataStore.delete(keyHash)
} }
logger.Error(err, "dropping key out of the queue", "key", key)
} }
func (gen *Generator) processNextWorkItem() bool { func (gen *Generator) processNextWorkItem() bool {

View file

@ -3,11 +3,12 @@ package policystatus
import ( import (
"context" "context"
"encoding/json" "encoding/json"
"github.com/go-logr/logr"
"strings" "strings"
"sync" "sync"
"time" "time"
"github.com/go-logr/logr"
v1 "github.com/kyverno/kyverno/pkg/api/kyverno/v1" v1 "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
"github.com/kyverno/kyverno/pkg/client/clientset/versioned" "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
kyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1" kyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1"
@ -133,7 +134,7 @@ func (s *Sync) updateStatusCache(stopCh <-chan struct{}) {
// from the status cache, syncing them // from the status cache, syncing them
func (s *Sync) updatePolicyStatus() { func (s *Sync) updatePolicyStatus() {
for key, status := range s.getCachedStatus() { for key, status := range s.getCachedStatus() {
s.log.V(2).Info("updating policy status", "policy", key) s.log.V(3).Info("updating policy status", "policy", key)
namespace, policyName := s.parseStatusKey(key) namespace, policyName := s.parseStatusKey(key)
if namespace == "" { if namespace == "" {
s.updateClusterPolicy(policyName, key, status) s.updateClusterPolicy(policyName, key, status)

View file

@ -118,7 +118,6 @@ func ConvertResource(raw []byte, group, version, kind, namespace string) (unstru
} }
obj.SetGroupVersionKind(schema.GroupVersionKind{Group: group, Version: version, Kind: kind}) obj.SetGroupVersionKind(schema.GroupVersionKind{Group: group, Version: version, Kind: kind})
obj.SetNamespace(namespace)
return *obj, nil return *obj, nil
} }

View file

@ -122,10 +122,13 @@ 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")
grList, err := client.KyvernoV1().GenerateRequests(config.KyvernoNamespace).List(context.TODO(), metav1.ListOptions{}) grList, err := client.KyvernoV1().GenerateRequests(config.KyvernoNamespace).List(context.TODO(), metav1.ListOptions{})
if err != nil { if err != nil {
return err return err
} }
for i, v := range grList.Items { for i, v := range grList.Items {
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{

View file

@ -14,8 +14,8 @@ import (
"github.com/kyverno/kyverno/pkg/engine" "github.com/kyverno/kyverno/pkg/engine"
"github.com/kyverno/kyverno/pkg/engine/context" "github.com/kyverno/kyverno/pkg/engine/context"
"github.com/kyverno/kyverno/pkg/engine/response" "github.com/kyverno/kyverno/pkg/engine/response"
"github.com/kyverno/kyverno/pkg/engine/utils"
"github.com/kyverno/kyverno/pkg/event" "github.com/kyverno/kyverno/pkg/event"
kyvernoutils "github.com/kyverno/kyverno/pkg/utils"
"github.com/kyverno/kyverno/pkg/webhooks/generate" "github.com/kyverno/kyverno/pkg/webhooks/generate"
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"
@ -32,16 +32,14 @@ func (ws *WebhookServer) HandleGenerate(request *v1beta1.AdmissionRequest, polic
return return
} }
// convert RAW to unstructured // convert RAW to unstructured
resource, err := utils.ConvertToUnstructured(request.Object.Raw) new, old, err := kyvernoutils.ExtractResources(nil, request)
if err != nil { if err != nil {
//TODO: skip applying the admission control ? logger.Error(err, "failed to extract resource")
logger.Error(err, "failed to convert RAR resource to unstructured format")
return
} }
// CREATE resources, do not have name, assigned in admission-request
policyContext := engine.PolicyContext{ policyContext := engine.PolicyContext{
NewResource: *resource, NewResource: new,
OldResource: old,
AdmissionInfo: userRequestInfo, AdmissionInfo: userRequestInfo,
Context: ctx, Context: ctx,
ExcludeGroupRole: dynamicConfig.GetExcludeGroupRole(), ExcludeGroupRole: dynamicConfig.GetExcludeGroupRole(),
@ -56,10 +54,13 @@ 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")
grList, err := ws.kyvernoClient.KyvernoV1().GenerateRequests(config.KyvernoNamespace).List(contextdefault.TODO(), metav1.ListOptions{}) grList, err := ws.kyvernoClient.KyvernoV1().GenerateRequests(config.KyvernoNamespace).List(contextdefault.TODO(), metav1.ListOptions{})
if err != nil { if err != nil {
logger.Error(err, "failed to list generate request") logger.Error(err, "failed to list generate request")
} }
for _, v := range grList.Items { for _, v := range grList.Items {
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{})
@ -88,19 +89,11 @@ func (ws *WebhookServer) HandleGenerate(request *v1beta1.AdmissionRequest, polic
if failedResponse := applyGenerateRequest(ws.grGenerator, userRequestInfo, request.Operation, engineResponses...); err != nil { if failedResponse := applyGenerateRequest(ws.grGenerator, userRequestInfo, request.Operation, engineResponses...); err != nil {
// report failure event // report failure event
for _, failedGR := range failedResponse { for _, failedGR := range failedResponse {
events := failedEvents(fmt.Errorf("failed to create Generate Request: %v", failedGR.err), failedGR.gr, *resource) events := failedEvents(fmt.Errorf("failed to create Generate Request: %v", failedGR.err), failedGR.gr, new)
ws.eventGen.Add(events...) ws.eventGen.Add(events...)
} }
} }
// Generate Stats wont be used here, as we delegate the generate rule
// - Filter policies that apply on this resource
// - - build CR context(userInfo+roles+clusterRoles)
// - Create CR
// - send Success
// HandleGeneration always returns success
// Filter Policies
return return
} }
@ -113,6 +106,7 @@ func applyGenerateRequest(gnGenerator generate.GenerateRequests, userRequestInfo
failedGenerateRequest = append(failedGenerateRequest, generateRequestResponse{gr: gr, err: err}) failedGenerateRequest = append(failedGenerateRequest, generateRequestResponse{gr: gr, err: err})
} }
} }
return return
} }