1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00

feat: split policy report per policy bases (#4147)

* feat: split policy report per policy bases

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

* add policy name as a handler key

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

* update merge change request logic

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

* handle the delete resource update on policy report

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

* add splitPolicyReport feature gate

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

* delete old reports if splitPolicyReport feature enable

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

* use trim policyname as label and create name

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

* fix change request result

Signed-off-by: prateekpandey14 <prateek.pandey@nirmata.com>
This commit is contained in:
Prateek Pandey 2022-06-28 20:57:57 +05:30 committed by GitHub
parent 77fb10a430
commit 9226873e68
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 322 additions and 39 deletions

View file

@ -70,6 +70,7 @@ var (
clientRateLimitQPS float64
clientRateLimitBurst int
changeRequestLimit int
splitPolicyReport bool
webhookRegistrationTimeout time.Duration
setupLog = log.Log.WithName("setup")
)
@ -94,7 +95,7 @@ func main() {
flag.Func(toggle.AutogenInternalsFlagName, toggle.AutogenInternalsDescription, toggle.AutogenInternalsFlag)
flag.DurationVar(&webhookRegistrationTimeout, "webhookRegistrationTimeout", 120*time.Second, "Timeout for webhook registration, e.g., 30s, 1m, 5m.")
flag.IntVar(&changeRequestLimit, "maxReportChangeRequests", 1000, "maximum pending report change requests per namespace or for the cluster-wide policy report")
flag.BoolVar(&splitPolicyReport, "splitPolicyReport", false, "Set the flag to 'true', to enable the split-up PolicyReports per policy.")
if err := flag.Set("v", "2"); err != nil {
setupLog.Error(err, "failed to set log level")
os.Exit(1)
@ -206,6 +207,7 @@ func main() {
kyvernoV1.ClusterPolicies(),
kyvernoV1.Policies(),
changeRequestLimit,
splitPolicyReport,
log.Log.WithName("ReportChangeRequestGenerator"),
)
@ -218,6 +220,7 @@ func main() {
kyvernoV1alpha2.ClusterReportChangeRequests(),
kubeInformer.Core().V1().Namespaces(),
reportReqGen.CleanupChangeRequest,
splitPolicyReport,
log.Log.WithName("PolicyReportGenerator"),
)
if err != nil {

View file

@ -28,6 +28,7 @@ const (
// the following labels are used to list rcr / crcr
ResourceLabelNamespace string = "kyverno.io/resource.namespace"
policyLabel string = "kyverno.io/policy-name"
deletedLabelPolicy string = "kyverno.io/delete.policy"
deletedLabelRule string = "kyverno.io/delete.rule"
@ -56,6 +57,13 @@ func GeneratePolicyReportName(ns string) string {
return name
}
func TrimmedName(s string) string {
if len(s) > 63 {
return s[:63]
}
return s
}
// GeneratePRsFromEngineResponse generate Violations from engine responses
func GeneratePRsFromEngineResponse(ers []*response.EngineResponse, log logr.Logger) (pvInfos []Info) {
for _, er := range ers {
@ -209,6 +217,7 @@ func set(obj *unstructured.Unstructured, info Info) {
obj.SetLabels(map[string]string{
ResourceLabelNamespace: info.Namespace,
policyLabel: TrimmedName(info.PolicyName),
appVersion: version.BuildVersion,
})
}

View file

@ -36,19 +36,23 @@ type changeRequestCreator struct {
mutex sync.RWMutex
queue []string
// splitPolicyReport enable/disable the PolicyReport split-up per policy feature
splitPolicyReport bool
tickerInterval time.Duration
log logr.Logger
}
func newChangeRequestCreator(client kyvernoclient.Interface, tickerInterval time.Duration, log logr.Logger) creator {
func newChangeRequestCreator(client kyvernoclient.Interface, tickerInterval time.Duration, splitPolicyReport bool, log logr.Logger) creator {
return &changeRequestCreator{
client: client,
RCRCache: cache.New(0, 24*time.Hour),
CRCRCache: cache.New(0, 24*time.Hour),
queue: []string{},
tickerInterval: tickerInterval,
log: log,
client: client,
RCRCache: cache.New(0, 24*time.Hour),
CRCRCache: cache.New(0, 24*time.Hour),
queue: []string{},
tickerInterval: tickerInterval,
splitPolicyReport: splitPolicyReport,
log: log,
}
}
@ -110,10 +114,23 @@ func (c *changeRequestCreator) run(stopChan <-chan struct{}) {
ticker := time.NewTicker(c.tickerInterval)
defer ticker.Stop()
if c.splitPolicyReport {
err := CleanupPolicyReport(c.client)
if err != nil {
c.log.Error(err, "failed to delete old reports")
}
}
for {
select {
case <-ticker.C:
requests, size := c.mergeRequests()
requests := []*unstructured.Unstructured{}
var size int
if c.splitPolicyReport {
requests, size = c.mergeRequestsPerPolicy()
} else {
requests, size = c.mergeRequests()
}
for _, request := range requests {
if err := c.create(request); err != nil {
c.log.Error(err, "failed to create report change request", "req", request.Object)
@ -216,7 +233,96 @@ func (c *changeRequestCreator) mergeRequests() (results []*unstructured.Unstruct
results = append(results, mergedNamespacedRCR)
}
}
return
}
// mergeRequests merges all current cached requests per policy
// it blocks writing to the cache
func (c *changeRequestCreator) mergeRequestsPerPolicy() (results []*unstructured.Unstructured, size int) {
c.mutex.Lock()
defer c.mutex.Unlock()
mergedCRCR := make(map[string]*unstructured.Unstructured)
mergedRCR := make(map[string]*unstructured.Unstructured)
size = len(c.queue)
for _, uid := range c.queue {
if unstr, ok := c.CRCRCache.Get(uid); ok {
if crcr, ok := unstr.(*unstructured.Unstructured); ok {
policyName := crcr.GetLabels()[policyLabel]
mergedPolicyCRCR, ok := mergedCRCR[policyName]
if !ok {
mergedPolicyCRCR = &unstructured.Unstructured{}
}
if isDeleteRequest(crcr) {
if !reflect.DeepEqual(mergedPolicyCRCR, &unstructured.Unstructured{}) {
results = append(results, mergedPolicyCRCR)
mergedCRCR[policyName] = &unstructured.Unstructured{}
}
results = append(results, crcr)
} else {
if reflect.DeepEqual(mergedPolicyCRCR, &unstructured.Unstructured{}) {
mergedCRCR[policyName] = crcr
continue
}
if ok := merge(mergedPolicyCRCR, crcr); !ok {
results = append(results, mergedPolicyCRCR)
mergedCRCR[policyName] = crcr
} else {
mergedCRCR[policyName] = mergedPolicyCRCR
}
}
}
continue
}
if unstr, ok := c.RCRCache.Get(uid); ok {
if rcr, ok := unstr.(*unstructured.Unstructured); ok {
policyName := rcr.GetLabels()[policyLabel]
resourceNS := rcr.GetLabels()[ResourceLabelNamespace]
mergedNamespacedRCR, ok := mergedRCR[policyName+resourceNS]
if !ok {
mergedNamespacedRCR = &unstructured.Unstructured{}
}
if isDeleteRequest(rcr) {
if !reflect.DeepEqual(mergedNamespacedRCR, &unstructured.Unstructured{}) {
results = append(results, mergedNamespacedRCR)
mergedRCR[policyName+resourceNS] = &unstructured.Unstructured{}
}
results = append(results, rcr)
} else {
if reflect.DeepEqual(mergedNamespacedRCR, &unstructured.Unstructured{}) {
mergedRCR[policyName+resourceNS] = rcr
continue
}
if ok := merge(mergedNamespacedRCR, rcr); !ok {
results = append(results, mergedNamespacedRCR)
mergedRCR[policyName+resourceNS] = rcr
} else {
mergedRCR[policyName+resourceNS] = mergedNamespacedRCR
}
}
}
}
}
for _, mergedPolicyCRCR := range mergedCRCR {
if !reflect.DeepEqual(mergedPolicyCRCR, &unstructured.Unstructured{}) {
results = append(results, mergedPolicyCRCR)
}
}
for _, mergedNamespacedRCR := range mergedRCR {
if !reflect.DeepEqual(mergedNamespacedRCR, &unstructured.Unstructured{}) {
results = append(results, mergedNamespacedRCR)
}
}
return
}

View file

@ -1,6 +1,7 @@
package policyreport
import (
"context"
"encoding/json"
"fmt"
"reflect"
@ -12,7 +13,10 @@ import (
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
kyvernov1alpha2listers "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1alpha2"
policyreportv1alpha2listers "github.com/kyverno/kyverno/pkg/client/listers/policyreport/v1alpha2"
"github.com/kyverno/kyverno/pkg/config"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/labels"
)
type PolicyReportEraser interface {
@ -220,3 +224,41 @@ func mapToStruct(in, out interface{}) error {
jsonBytes, _ := json.Marshal(in)
return json.Unmarshal(jsonBytes, out)
}
func CleanupPolicyReport(client kyvernoclient.Interface) error {
var errors []string
var gracePeriod int64 = 0
deleteOptions := metav1.DeleteOptions{GracePeriodSeconds: &gracePeriod}
selector := labels.SelectorFromSet(labels.Set(map[string]string{LabelSelectorKey: LabelSelectorValue}))
err := client.KyvernoV1alpha2().ClusterReportChangeRequests().DeleteCollection(context.TODO(), deleteOptions, metav1.ListOptions{})
if err != nil {
errors = append(errors, err.Error())
}
err = client.KyvernoV1alpha2().ReportChangeRequests(config.KyvernoNamespace()).DeleteCollection(context.TODO(), deleteOptions, metav1.ListOptions{})
if err != nil {
errors = append(errors, err.Error())
}
err = client.Wgpolicyk8sV1alpha2().ClusterPolicyReports().DeleteCollection(context.TODO(), deleteOptions, metav1.ListOptions{LabelSelector: selector.String()})
if err != nil {
errors = append(errors, err.Error())
}
reports, err := client.Wgpolicyk8sV1alpha2().PolicyReports(metav1.NamespaceAll).List(context.TODO(), metav1.ListOptions{LabelSelector: selector.String()})
if err != nil {
errors = append(errors, err.Error())
}
for _, report := range reports.Items {
err = client.Wgpolicyk8sV1alpha2().PolicyReports(report.Namespace).Delete(context.TODO(), report.Name, metav1.DeleteOptions{})
if err != nil {
errors = append(errors, err.Error())
}
}
if len(errors) == 0 {
return nil
}
return fmt.Errorf("%v", strings.Join(errors, ";"))
}

View file

@ -67,6 +67,8 @@ type ReportGenerator struct {
reportChangeRequestLister kyvernov1alpha2listers.ReportChangeRequestLister
clusterReportChangeRequestLister kyvernov1alpha2listers.ClusterReportChangeRequestLister
nsLister corev1listers.NamespaceLister
// splitPolicyReport enable/disable the PolicyReport split-up per policy feature
splitPolicyReport bool
informersSynced []cache.InformerSynced
@ -91,6 +93,7 @@ func NewReportGenerator(
clusterReportReqInformer kyvernov1alpha2informers.ClusterReportChangeRequestInformer,
namespace corev1informers.NamespaceInformer,
cleanupChangeRequest chan<- ReconcileInfo,
splitPolicyReport bool,
log logr.Logger,
) (*ReportGenerator, error) {
gen := &ReportGenerator{
@ -101,6 +104,7 @@ func NewReportGenerator(
reportReqInformer: reportReqInformer,
clusterReportReqInformer: clusterReportReqInformer,
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), prWorkQueueName),
splitPolicyReport: splitPolicyReport,
ReconcileCh: make(chan bool, 10),
cleanupChangeRequest: cleanupChangeRequest,
log: log,
@ -120,7 +124,7 @@ func NewReportGenerator(
// - <namespace name> for the resource
// - "" for cluster wide resource
// - "deletedpolicy/policyName/ruleName(optional)" for a deleted policy or rule
func generateCacheKey(changeRequest interface{}) string {
func (g *ReportGenerator) generateCacheKey(changeRequest interface{}) string {
if request, ok := changeRequest.(*kyvernov1alpha2.ReportChangeRequest); ok {
label := request.GetLabels()
policy := label[deletedLabelPolicy]
@ -133,7 +137,12 @@ func generateCacheKey(changeRequest interface{}) string {
if ns == "" {
ns = "default"
}
return ns
if g.splitPolicyReport {
policy = label[policyLabel]
return strings.Join([]string{ns, policy}, "/")
} else {
return ns
}
} else if request, ok := changeRequest.(*kyvernov1alpha2.ClusterReportChangeRequest); ok {
label := request.GetLabels()
policy := label[deletedLabelPolicy]
@ -141,9 +150,13 @@ func generateCacheKey(changeRequest interface{}) string {
if rule != "" || policy != "" {
return strings.Join([]string{deletedPolicyKey, policy, rule}, "/")
}
return ""
if g.splitPolicyReport {
policy = label[policyLabel]
return strings.Join([]string{"", policy}, "/")
} else {
return ""
}
}
return ""
}
@ -171,7 +184,7 @@ func (g *ReportGenerator) addReportChangeRequest(obj interface{}) {
return
}
key := generateCacheKey(obj)
key := g.generateCacheKey(obj)
g.queue.Add(key)
}
@ -187,7 +200,7 @@ func (g *ReportGenerator) updateReportChangeRequest(old interface{}, cur interfa
return
}
key := generateCacheKey(cur)
key := g.generateCacheKey(cur)
g.queue.Add(key)
}
@ -197,7 +210,7 @@ func (g *ReportGenerator) addClusterReportChangeRequest(obj interface{}) {
return
}
key := generateCacheKey(obj)
key := g.generateCacheKey(obj)
g.queue.Add(key)
}
@ -213,7 +226,8 @@ func (g *ReportGenerator) updateClusterReportChangeRequest(old interface{}, cur
return
}
g.queue.Add("")
key := g.generateCacheKey(cur)
g.queue.Add(key)
}
func (g *ReportGenerator) deletePolicyReport(obj interface{}) {
@ -321,22 +335,43 @@ func (g *ReportGenerator) handleErr(err error, key interface{}, aggregatedReques
}
// syncHandler reconciles clusterPolicyReport if namespace == ""
// otherwise it updates policyReport
// otherwise it updates policyReport. the key is of type "namespace/policyname"
func (g *ReportGenerator) syncHandler(key string) (aggregatedRequests interface{}, err error) {
g.log.V(4).Info("syncing policy report", "key", key)
namespace := key
if policy, rule, ok := isDeletedPolicyKey(key); ok {
g.log.V(4).Info("sync policy report on policy deletion")
return g.removePolicyEntryFromReport(policy, rule)
}
new, aggregatedRequests, err := g.aggregateReports(namespace)
var namespace, policyName string
if g.splitPolicyReport {
namespace = strings.Split(key, "/")[0]
policyName = strings.Split(key, "/")[1]
} else {
namespace = key
}
new, aggregatedRequests, err := g.aggregateReports(namespace, policyName)
if err != nil {
return aggregatedRequests, fmt.Errorf("failed to aggregate reportChangeRequest results %v", err)
}
report, err := g.reportLister.PolicyReports(namespace).Get(GeneratePolicyReportName(namespace))
if g.splitPolicyReport {
deleteResources := getDeletedResources(aggregatedRequests)
if len(deleteResources) != 0 {
for _, dr := range deleteResources {
if err := g.updateReportsForDeletedResource(dr.name, new, aggregatedRequests); err != nil {
return aggregatedRequests, err
}
}
}
}
var report *policyreportv1alpha2.PolicyReport
if g.splitPolicyReport {
report, err = g.reportLister.PolicyReports(namespace).Get(TrimmedName(GeneratePolicyReportName(namespace) + "-" + policyName))
} else {
report, err = g.reportLister.PolicyReports(namespace).Get(GeneratePolicyReportName(namespace))
}
if err == nil {
if val, ok := report.GetLabels()[inactiveLabelKey]; ok && val == inactiveLabelVal {
g.log.Info("got resourceExhausted error, please opt-in via \"splitPolicyReport\" to generate report per policy")
@ -344,8 +379,9 @@ func (g *ReportGenerator) syncHandler(key string) (aggregatedRequests interface{
}
}
// Delete changes request does not have the policyName label set
var old interface{}
if old, err = g.createReportIfNotPresent(namespace, new, aggregatedRequests); err != nil {
if old, err = g.createReportIfNotPresent(namespace, policyName, new, aggregatedRequests); err != nil {
return aggregatedRequests, err
}
@ -365,7 +401,7 @@ func (g *ReportGenerator) syncHandler(key string) (aggregatedRequests interface{
// createReportIfNotPresent creates cluster / policyReport if not present
// return the existing report if exist
func (g *ReportGenerator) createReportIfNotPresent(namespace string, new *unstructured.Unstructured, aggregatedRequests interface{}) (report interface{}, err error) {
func (g *ReportGenerator) createReportIfNotPresent(namespace, policyName string, new *unstructured.Unstructured, aggregatedRequests interface{}) (report interface{}, err error) {
log := g.log.WithName("createReportIfNotPresent")
obj, hasDuplicate, err := updateResults(new.UnstructuredContent(), new.UnstructuredContent(), nil)
if hasDuplicate && err != nil {
@ -387,7 +423,11 @@ func (g *ReportGenerator) createReportIfNotPresent(namespace string, new *unstru
return nil, nil
}
report, err = g.reportLister.PolicyReports(namespace).Get(GeneratePolicyReportName(namespace))
if g.splitPolicyReport {
report, err = g.reportLister.PolicyReports(namespace).Get(TrimmedName(GeneratePolicyReportName(namespace) + "-" + policyName))
} else {
report, err = g.reportLister.PolicyReports(namespace).Get(GeneratePolicyReportName(namespace))
}
if err != nil {
if apierrors.IsNotFound(err) && new != nil {
polr, err := convertToPolr(new)
@ -407,7 +447,12 @@ func (g *ReportGenerator) createReportIfNotPresent(namespace string, new *unstru
return nil, fmt.Errorf("unable to get policyReport: %v", err)
}
} else {
report, err = g.clusterReportLister.Get(GeneratePolicyReportName(namespace))
if g.splitPolicyReport {
report, err = g.clusterReportLister.Get(TrimmedName(GeneratePolicyReportName(namespace) + "-" + policyName))
} else {
report, err = g.clusterReportLister.Get(GeneratePolicyReportName(namespace))
}
if err != nil {
if apierrors.IsNotFound(err) {
if new != nil {
@ -485,6 +530,7 @@ func (g *ReportGenerator) removeFromClusterPolicyReport(policyName, ruleName str
}
func (g *ReportGenerator) removeFromPolicyReport(policyName, ruleName string) error {
namespaces, err := g.client.ListResource("", "Namespace", "", nil)
if err != nil {
return fmt.Errorf("unable to list namespace %v", err)
@ -520,6 +566,7 @@ func (g *ReportGenerator) removeFromPolicyReport(policyName, ruleName string) er
gv := policyreportv1alpha2.SchemeGroupVersion
gvk := schema.GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: "PolicyReport"}
r.SetGroupVersionKind(gvk)
if _, err := g.pclient.Wgpolicyk8sV1alpha2().PolicyReports(r.GetNamespace()).Update(context.TODO(), r, metav1.UpdateOptions{}); err != nil {
return fmt.Errorf("failed to update PolicyReport %s %v", r.GetName(), err)
}
@ -528,7 +575,7 @@ func (g *ReportGenerator) removeFromPolicyReport(policyName, ruleName string) er
}
// aggregateReports aggregates cluster / report change requests to a policy report
func (g *ReportGenerator) aggregateReports(namespace string) (
func (g *ReportGenerator) aggregateReports(namespace, policyName string) (
report *unstructured.Unstructured,
aggregatedRequests interface{},
err error,
@ -538,14 +585,19 @@ func (g *ReportGenerator) aggregateReports(namespace string) (
g.log.Error(err, "failed to get Kyverno namespace, policy reports will not be garbage collected upon termination")
}
selector := labels.NewSelector()
if namespace == "" {
selector := labels.SelectorFromSet(labels.Set(map[string]string{appVersion: version.BuildVersion}))
if g.splitPolicyReport {
selector = labels.SelectorFromSet(labels.Set(map[string]string{appVersion: version.BuildVersion, policyLabel: TrimmedName(policyName)}))
} else {
selector = labels.SelectorFromSet(labels.Set(map[string]string{appVersion: version.BuildVersion}))
}
requests, err := g.clusterReportChangeRequestLister.List(selector)
if err != nil {
return nil, nil, fmt.Errorf("unable to list ClusterReportChangeRequests within: %v", err)
}
if report, aggregatedRequests, err = mergeRequests(nil, kyvernoNamespace, requests); err != nil {
if report, aggregatedRequests, err = g.mergeRequests(nil, kyvernoNamespace, policyName, requests); err != nil {
return nil, nil, fmt.Errorf("unable to merge ClusterReportChangeRequests results: %v", err)
}
} else {
@ -561,13 +613,17 @@ func (g *ReportGenerator) aggregateReports(namespace string) (
ns.SetDeletionTimestamp(&now)
}
selector := labels.SelectorFromSet(labels.Set(map[string]string{appVersion: version.BuildVersion, ResourceLabelNamespace: namespace}))
if g.splitPolicyReport {
selector = labels.SelectorFromSet(labels.Set(map[string]string{appVersion: version.BuildVersion, ResourceLabelNamespace: namespace, policyLabel: TrimmedName(policyName)}))
} else {
selector = labels.SelectorFromSet(labels.Set(map[string]string{appVersion: version.BuildVersion, ResourceLabelNamespace: namespace}))
}
requests, err := g.reportChangeRequestLister.ReportChangeRequests(config.KyvernoNamespace()).List(selector)
if err != nil {
return nil, nil, fmt.Errorf("unable to list reportChangeRequests within namespace %s: %v", ns, err)
}
if report, aggregatedRequests, err = mergeRequests(ns, kyvernoNamespace, requests); err != nil {
if report, aggregatedRequests, err = g.mergeRequests(ns, kyvernoNamespace, policyName, requests); err != nil {
return nil, nil, fmt.Errorf("unable to merge results: %v", err)
}
}
@ -575,9 +631,8 @@ func (g *ReportGenerator) aggregateReports(namespace string) (
return report, aggregatedRequests, nil
}
func mergeRequests(ns, kyvernoNs *corev1.Namespace, requestsGeneral interface{}) (*unstructured.Unstructured, interface{}, error) {
func (g *ReportGenerator) mergeRequests(ns, kyvernoNs *corev1.Namespace, policyName string, requestsGeneral interface{}) (*unstructured.Unstructured, interface{}, error) {
results := []policyreportv1alpha2.PolicyReportResult{}
if requests, ok := requestsGeneral.([]*kyvernov1alpha2.ClusterReportChangeRequest); ok {
aggregatedRequests := []*kyvernov1alpha2.ClusterReportChangeRequest{}
for _, request := range requests {
@ -601,7 +656,9 @@ func mergeRequests(ns, kyvernoNs *corev1.Namespace, requestsGeneral interface{})
}
req := &unstructured.Unstructured{Object: obj}
setReport(req, nil, kyvernoNs)
g.setReport(req, ns, kyvernoNs, policyName)
return req, aggregatedRequests, nil
}
@ -628,7 +685,8 @@ func mergeRequests(ns, kyvernoNs *corev1.Namespace, requestsGeneral interface{})
}
req := &unstructured.Unstructured{Object: obj}
setReport(req, ns, kyvernoNs)
g.setReport(req, ns, kyvernoNs, policyName)
return req, aggregatedRequests, nil
}
@ -636,7 +694,7 @@ func mergeRequests(ns, kyvernoNs *corev1.Namespace, requestsGeneral interface{})
return nil, nil, nil
}
func setReport(reportUnstructured *unstructured.Unstructured, ns, kyvernoNs *corev1.Namespace) {
func (g *ReportGenerator) setReport(reportUnstructured *unstructured.Unstructured, ns, kyvernoNs *corev1.Namespace, policyname string) {
reportUnstructured.SetAPIVersion(policyreportv1alpha2.SchemeGroupVersion.String())
reportUnstructured.SetLabels(LabelSelector.MatchLabels)
@ -655,12 +713,20 @@ func setReport(reportUnstructured *unstructured.Unstructured, ns, kyvernoNs *cor
}
if ns == nil {
reportUnstructured.SetName(GeneratePolicyReportName(""))
if g.splitPolicyReport {
reportUnstructured.SetName(TrimmedName(GeneratePolicyReportName("") + "-" + policyname))
} else {
reportUnstructured.SetName(GeneratePolicyReportName(""))
}
reportUnstructured.SetKind("ClusterPolicyReport")
return
}
reportUnstructured.SetName(GeneratePolicyReportName(ns.GetName()))
if g.splitPolicyReport {
reportUnstructured.SetName(TrimmedName(GeneratePolicyReportName(ns.GetName()) + "-" + policyname))
} else {
reportUnstructured.SetName(GeneratePolicyReportName(ns.GetName()))
}
reportUnstructured.SetNamespace(ns.GetName())
reportUnstructured.SetKind("PolicyReport")
}
@ -779,6 +845,62 @@ func (g *ReportGenerator) updateReport(old interface{}, new *unstructured.Unstru
return
}
func (g *ReportGenerator) updateReportsForDeletedResource(resName string, new *unstructured.Unstructured, aggregatedRequests interface{}) (err error) {
if _, ok := aggregatedRequests.([]*kyvernov1alpha2.ClusterReportChangeRequest); ok {
cpolrs, err := g.clusterReportLister.List(labels.Everything())
if err != nil {
return fmt.Errorf("failed to list clusterPolicyReport %v", err)
}
for _, cpolr := range cpolrs {
newRes := []policyreportv1alpha2.PolicyReportResult{}
for _, result := range cpolr.Results {
if len(result.Resources) != 0 {
for _, res := range result.Resources {
if res.Name != resName {
newRes = append(newRes, result)
}
}
}
}
cpolr.Results = newRes
cpolr.Summary = calculateSummary(newRes)
gv := policyreportv1alpha2.SchemeGroupVersion
cpolr.SetGroupVersionKind(schema.GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: "ClusterPolicyReport"})
if _, err := g.pclient.Wgpolicyk8sV1alpha2().ClusterPolicyReports().Update(context.TODO(), cpolr, metav1.UpdateOptions{}); err != nil {
return fmt.Errorf("failed to update clusterPolicyReport %s %v", cpolr.Name, err)
}
}
} else {
polrs, err := g.reportLister.List(labels.Everything())
if err != nil {
return fmt.Errorf("failed to list clusterPolicyReport %v", err)
}
for _, polr := range polrs {
newRes1 := []policyreportv1alpha2.PolicyReportResult{}
for _, result := range polr.Results {
if len(result.Resources) != 0 {
for _, res := range result.Resources {
if res.Name != resName {
newRes1 = append(newRes1, result)
}
}
}
}
polr.Results = newRes1
polr.Summary = calculateSummary(newRes1)
gv := policyreportv1alpha2.SchemeGroupVersion
polr.SetGroupVersionKind(schema.GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: "PolicyReport"})
if _, err := g.pclient.Wgpolicyk8sV1alpha2().PolicyReports(new.GetNamespace()).Update(context.TODO(), polr, metav1.UpdateOptions{}); err != nil {
return fmt.Errorf("failed to update clusterPolicyReport %s %v", polr.Name, err)
}
}
}
return
}
func (g *ReportGenerator) cleanupReportRequests(requestsGeneral interface{}) {
defer g.log.V(5).Info("successfully cleaned up report requests")
if requests, ok := requestsGeneral.([]*kyvernov1alpha2.ReportChangeRequest); ok {

View file

@ -70,6 +70,7 @@ func NewReportChangeRequestGenerator(client kyvernoclient.Interface,
cpolInformer kyvernov1informers.ClusterPolicyInformer,
polInformer kyvernov1informers.PolicyInformer,
changeRequestLimit int,
splitPolicyReport bool,
log logr.Logger,
) *Generator {
gen := Generator{
@ -81,9 +82,9 @@ func NewReportChangeRequestGenerator(client kyvernoclient.Interface,
polLister: polInformer.Lister(),
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), workQueueName),
dataStore: newDataStore(),
requestCreator: newChangeRequestCreator(client, 3*time.Second, log.WithName("requestCreator")),
changeRequestLimit: changeRequestLimit,
CleanupChangeRequest: make(chan ReconcileInfo, 10),
requestCreator: newChangeRequestCreator(client, 3*time.Second, splitPolicyReport, log.WithName("requestCreator")),
log: log,
}