1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-10 01:46:55 +00:00
kyverno/pkg/policy/report.go
Charles-Edouard Brétéché e0ab72bb9a
feat: reports v2 implementation (#4608)
This PR refactors the reports generation code.
It removes RCR and CRCR crds and replaces them with AdmissionReport, ClusterAdmissionReport, BackgroundScanReport and ClusterBackgroundScanReport crds.

The new reports system is based on 4 controllers:

Admission reports controller is responsible for cleaning up admission reports and attaching admission reports to their corresponding resource in case of a creation
Background scan reports controller is responsible for creating background scan reports when a resource and/or policy changes
Aggregation controller takes care of aggregation per resource reports into higher level reports (per namespace)
Resources controller is responsible for watching reports that need background scan reports
I added two new flags to disable admission reports and/or background scan reports, the whole reporting system can be disabled if something goes wrong.

I also added a flag to split reports in chunks to avoid creating too large resources.

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>

Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com>

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>
Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com>
Co-authored-by: prateekpandey14 <prateek.pandey@nirmata.com>
2022-09-28 17:15:16 +05:30

110 lines
3.5 KiB
Go

package policy
import (
"time"
"github.com/go-logr/logr"
"github.com/kyverno/kyverno/pkg/engine/response"
"github.com/kyverno/kyverno/pkg/event"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
)
func (pc *PolicyController) report(engineResponses []*response.EngineResponse, logger logr.Logger) {
eventInfos := generateFailEvents(logger, engineResponses)
pc.eventGen.Add(eventInfos...)
if pc.configHandler.GetGenerateSuccessEvents() {
successEventInfos := generateSuccessEvents(logger, engineResponses)
pc.eventGen.Add(successEventInfos...)
}
}
// forceReconciliation forces a background scan by adding all policies to the workqueue
func (pc *PolicyController) forceReconciliation(stopCh <-chan struct{}) {
logger := pc.log.WithName("forceReconciliation")
ticker := time.NewTicker(pc.reconcilePeriod)
for {
select {
case <-ticker.C:
logger.Info("performing the background scan", "scan interval", pc.reconcilePeriod.String())
pc.requeuePolicies()
case <-stopCh:
return
}
}
}
func (pc *PolicyController) requeuePolicies() {
logger := pc.log.WithName("requeuePolicies")
if cpols, err := pc.pLister.List(labels.Everything()); err == nil {
for _, cpol := range cpols {
if !pc.canBackgroundProcess(cpol) {
continue
}
pc.enqueuePolicy(cpol)
}
} else {
logger.Error(err, "unable to list ClusterPolicies")
}
if pols, err := pc.npLister.Policies(metav1.NamespaceAll).List(labels.Everything()); err == nil {
for _, p := range pols {
if !pc.canBackgroundProcess(p) {
continue
}
pc.enqueuePolicy(p)
}
} else {
logger.Error(err, "unable to list Policies")
}
}
func generateSuccessEvents(log logr.Logger, ers []*response.EngineResponse) (eventInfos []event.Info) {
for _, er := range ers {
logger := log.WithValues("policy", er.PolicyResponse.Policy, "kind", er.PolicyResponse.Resource.Kind, "namespace", er.PolicyResponse.Resource.Namespace, "name", er.PolicyResponse.Resource.Name)
if !er.IsFailed() {
logger.V(4).Info("generating event on policy for success rules")
e := event.NewPolicyAppliedEvent(event.PolicyController, er)
eventInfos = append(eventInfos, e)
}
}
return eventInfos
}
func generateFailEvents(log logr.Logger, ers []*response.EngineResponse) (eventInfos []event.Info) {
for _, er := range ers {
eventInfos = append(eventInfos, generateFailEventsPerEr(log, er)...)
}
return eventInfos
}
func generateFailEventsPerEr(log logr.Logger, er *response.EngineResponse) []event.Info {
var eventInfos []event.Info
logger := log.WithValues("policy", er.PolicyResponse.Policy.Name,
"kind", er.PolicyResponse.Resource.Kind, "namespace", er.PolicyResponse.Resource.Namespace,
"name", er.PolicyResponse.Resource.Name)
for i, rule := range er.PolicyResponse.Rules {
if rule.Status == response.RuleStatusPass {
continue
} else if rule.Status == response.RuleStatusSkip {
eventResource := event.NewPolicySkippedEvent(event.PolicyController, event.PolicySkipped, er, &er.PolicyResponse.Rules[i])
eventInfos = append(eventInfos, eventResource)
} else {
eventResource := event.NewResourceViolationEvent(event.PolicyController, event.PolicyViolation, er, &er.PolicyResponse.Rules[i])
eventInfos = append(eventInfos, eventResource)
eventPolicy := event.NewPolicyFailEvent(event.PolicyController, event.PolicyViolation, er, &er.PolicyResponse.Rules[i], false)
eventInfos = append(eventInfos, eventPolicy)
}
}
if len(eventInfos) > 0 {
logger.V(4).Info("generating events for policy", "events", eventInfos)
}
return eventInfos
}