2020-11-09 11:26:12 -08:00
package policyreport
import (
2022-01-22 13:36:42 +08:00
"context"
2020-11-09 11:26:12 -08:00
"fmt"
"reflect"
"strings"
2020-12-23 17:48:00 -08:00
"time"
2020-11-09 11:26:12 -08:00
"github.com/go-logr/logr"
2021-10-29 18:13:20 +02:00
changerequest "github.com/kyverno/kyverno/api/kyverno/v1alpha2"
2022-06-28 14:18:57 +08:00
policyreportv1alpha2 "github.com/kyverno/kyverno/api/policyreport/v1alpha2"
2022-05-03 18:58:20 +02:00
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
2022-06-28 14:18:57 +08:00
kyvernov1alpha2informers "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1alpha2"
policyreportv1alpha2informers "github.com/kyverno/kyverno/pkg/client/informers/externalversions/policyreport/v1alpha2"
2022-06-28 22:02:52 +05:30
kyvernov1alpha2listers "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1alpha2"
policyreportv1alpha2listers "github.com/kyverno/kyverno/pkg/client/listers/policyreport/v1alpha2"
2022-05-03 18:58:20 +02:00
"github.com/kyverno/kyverno/pkg/config"
dclient "github.com/kyverno/kyverno/pkg/dclient"
2022-07-21 15:19:24 +05:30
"github.com/kyverno/kyverno/pkg/toggle"
2022-05-03 18:58:20 +02:00
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
"github.com/kyverno/kyverno/pkg/version"
2020-11-09 11:26:12 -08:00
v1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2021-10-29 18:13:20 +02:00
"k8s.io/apimachinery/pkg/labels"
2020-11-09 11:26:12 -08:00
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
2022-06-28 14:18:57 +08:00
corev1informers "k8s.io/client-go/informers/core/v1"
2022-06-28 22:02:52 +05:30
corev1listers "k8s.io/client-go/listers/core/v1"
2020-11-09 11:26:12 -08:00
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
)
const (
prWorkQueueName = "policy-report-controller"
clusterpolicyreport = "clusterpolicyreport"
2021-12-17 06:03:52 +01:00
LabelSelectorKey = "managed-by"
LabelSelectorValue = "kyverno"
2022-06-28 14:18:57 +08:00
deletedPolicyKey = "deletedpolicy"
resourceExhaustedErr = "ResourceExhausted"
2020-11-09 11:26:12 -08:00
)
2021-12-17 06:03:52 +01:00
var LabelSelector = & metav1 . LabelSelector {
MatchLabels : map [ string ] string {
LabelSelectorKey : LabelSelectorValue ,
} ,
}
2020-11-09 11:26:12 -08:00
// ReportGenerator creates policy report
type ReportGenerator struct {
2022-05-02 22:30:07 +02:00
pclient kyvernoclient . Interface
2022-05-03 07:30:04 +02:00
dclient dclient . Interface
2020-11-09 11:26:12 -08:00
2022-06-28 17:27:34 +08:00
clusterReportInformer policyreportv1alpha2informers . ClusterPolicyReportInformer
reportInformer policyreportv1alpha2informers . PolicyReportInformer
reportReqInformer kyvernov1alpha2informers . ReportChangeRequestInformer
clusterReportReqInformer kyvernov1alpha2informers . ClusterReportChangeRequestInformer
2021-06-08 12:37:19 -07:00
2022-06-28 22:02:52 +05:30
reportLister policyreportv1alpha2listers . PolicyReportLister
clusterReportLister policyreportv1alpha2listers . ClusterPolicyReportLister
reportChangeRequestLister kyvernov1alpha2listers . ReportChangeRequestLister
clusterReportChangeRequestLister kyvernov1alpha2listers . ClusterReportChangeRequestLister
nsLister corev1listers . NamespaceLister
2022-07-21 15:19:24 +05:30
informersSynced [ ] cache . InformerSynced
2022-06-28 17:27:34 +08:00
2020-11-09 11:26:12 -08:00
queue workqueue . RateLimitingInterface
2021-03-25 12:28:03 -07:00
// ReconcileCh sends a signal to policy controller to force the reconciliation of policy report
// if send true, the reports' results will be erased, this is used to recover from the invalid records
ReconcileCh chan bool
2022-06-28 14:18:57 +08:00
cleanupChangeRequest chan <- ReconcileInfo
2020-11-09 11:26:12 -08:00
log logr . Logger
}
// NewReportGenerator returns a new instance of policy report generator
func NewReportGenerator (
2022-05-02 22:30:07 +02:00
pclient kyvernoclient . Interface ,
2022-05-03 07:30:04 +02:00
dclient dclient . Interface ,
2022-06-28 14:18:57 +08:00
clusterReportInformer policyreportv1alpha2informers . ClusterPolicyReportInformer ,
reportInformer policyreportv1alpha2informers . PolicyReportInformer ,
reportReqInformer kyvernov1alpha2informers . ReportChangeRequestInformer ,
clusterReportReqInformer kyvernov1alpha2informers . ClusterReportChangeRequestInformer ,
namespace corev1informers . NamespaceInformer ,
cleanupChangeRequest chan <- ReconcileInfo ,
log logr . Logger ,
) ( * ReportGenerator , error ) {
2020-11-09 11:26:12 -08:00
gen := & ReportGenerator {
2021-06-08 12:37:19 -07:00
pclient : pclient ,
dclient : dclient ,
clusterReportInformer : clusterReportInformer ,
reportInformer : reportInformer ,
reportReqInformer : reportReqInformer ,
clusterReportReqInformer : clusterReportReqInformer ,
queue : workqueue . NewNamedRateLimitingQueue ( workqueue . DefaultControllerRateLimiter ( ) , prWorkQueueName ) ,
ReconcileCh : make ( chan bool , 10 ) ,
2022-06-28 14:18:57 +08:00
cleanupChangeRequest : cleanupChangeRequest ,
2021-06-08 12:37:19 -07:00
log : log ,
2020-11-09 11:26:12 -08:00
}
gen . clusterReportLister = clusterReportInformer . Lister ( )
gen . reportLister = reportInformer . Lister ( )
gen . clusterReportChangeRequestLister = clusterReportReqInformer . Lister ( )
gen . reportChangeRequestLister = reportReqInformer . Lister ( )
gen . nsLister = namespace . Lister ( )
2022-06-28 17:27:34 +08:00
gen . informersSynced = [ ] cache . InformerSynced { clusterReportInformer . Informer ( ) . HasSynced , reportInformer . Informer ( ) . HasSynced , reportReqInformer . Informer ( ) . HasSynced , clusterReportInformer . Informer ( ) . HasSynced , namespace . Informer ( ) . HasSynced }
2021-06-08 12:37:19 -07:00
return gen , nil
2020-11-09 11:26:12 -08:00
}
// the key of queue can be
// - <namespace name> for the resource
// - "" for cluster wide resource
// - "deletedpolicy/policyName/ruleName(optional)" for a deleted policy or rule
2022-06-28 22:02:52 +05:30
func ( g * ReportGenerator ) generateCacheKey ( changeRequest interface { } ) string {
2020-11-09 11:26:12 -08:00
if request , ok := changeRequest . ( * changerequest . ReportChangeRequest ) ; ok {
label := request . GetLabels ( )
policy := label [ deletedLabelPolicy ]
rule := label [ deletedLabelRule ]
if rule != "" || policy != "" {
return strings . Join ( [ ] string { deletedPolicyKey , policy , rule } , "/" )
}
2022-06-28 14:18:57 +08:00
ns := label [ ResourceLabelNamespace ]
2020-11-09 11:26:12 -08:00
if ns == "" {
ns = "default"
}
2022-07-21 15:19:24 +05:30
if toggle . SplitPolicyReport ( ) {
2022-06-28 22:02:52 +05:30
policy = label [ policyLabel ]
return strings . Join ( [ ] string { ns , policy } , "/" )
} else {
return ns
}
2020-11-09 11:26:12 -08:00
} else if request , ok := changeRequest . ( * changerequest . ClusterReportChangeRequest ) ; ok {
label := request . GetLabels ( )
policy := label [ deletedLabelPolicy ]
rule := label [ deletedLabelRule ]
if rule != "" || policy != "" {
return strings . Join ( [ ] string { deletedPolicyKey , policy , rule } , "/" )
}
2022-07-21 15:19:24 +05:30
if toggle . SplitPolicyReport ( ) {
2022-06-28 22:02:52 +05:30
policy = label [ policyLabel ]
return strings . Join ( [ ] string { "" , policy } , "/" )
} else {
return ""
}
2020-11-09 11:26:12 -08:00
}
return ""
}
2021-09-14 01:06:56 -07:00
// managedRequest returns true if the request is managed by
// the current version of Kyverno instance
func managedRequest ( changeRequest interface { } ) bool {
labels := make ( map [ string ] string )
if request , ok := changeRequest . ( * changerequest . ReportChangeRequest ) ; ok {
labels = request . GetLabels ( )
} else if request , ok := changeRequest . ( * changerequest . ClusterReportChangeRequest ) ; ok {
labels = request . GetLabels ( )
}
if v , ok := labels [ appVersion ] ; ! ok || v != version . BuildVersion {
return false
}
return true
}
2020-11-09 11:26:12 -08:00
func ( g * ReportGenerator ) addReportChangeRequest ( obj interface { } ) {
2021-09-14 01:06:56 -07:00
if ! managedRequest ( obj ) {
g . cleanupReportRequests ( [ ] * changerequest . ReportChangeRequest { obj . ( * changerequest . ReportChangeRequest ) } )
return
}
2022-06-28 22:02:52 +05:30
key := g . generateCacheKey ( obj )
2020-11-09 11:26:12 -08:00
g . queue . Add ( key )
}
func ( g * ReportGenerator ) updateReportChangeRequest ( old interface { } , cur interface { } ) {
oldReq := old . ( * changerequest . ReportChangeRequest )
curReq := cur . ( * changerequest . ReportChangeRequest )
if reflect . DeepEqual ( oldReq . Results , curReq . Results ) {
return
}
2021-09-14 01:06:56 -07:00
if ! managedRequest ( curReq ) {
g . cleanupReportRequests ( [ ] * changerequest . ReportChangeRequest { curReq } )
return
}
2022-06-28 22:02:52 +05:30
key := g . generateCacheKey ( cur )
2020-11-09 11:26:12 -08:00
g . queue . Add ( key )
}
func ( g * ReportGenerator ) addClusterReportChangeRequest ( obj interface { } ) {
2021-09-14 01:06:56 -07:00
if ! managedRequest ( obj ) {
g . cleanupReportRequests ( [ ] * changerequest . ClusterReportChangeRequest { obj . ( * changerequest . ClusterReportChangeRequest ) } )
return
}
2022-06-28 22:02:52 +05:30
key := g . generateCacheKey ( obj )
2020-11-09 11:26:12 -08:00
g . queue . Add ( key )
}
func ( g * ReportGenerator ) updateClusterReportChangeRequest ( old interface { } , cur interface { } ) {
oldReq := old . ( * changerequest . ClusterReportChangeRequest )
curReq := cur . ( * changerequest . ClusterReportChangeRequest )
if reflect . DeepEqual ( oldReq . Results , curReq . Results ) {
return
}
2021-09-14 01:06:56 -07:00
if ! managedRequest ( curReq ) {
return
}
2022-06-28 22:02:52 +05:30
key := g . generateCacheKey ( cur )
g . queue . Add ( key )
2020-11-09 11:26:12 -08:00
}
2021-03-25 12:28:03 -07:00
func ( g * ReportGenerator ) deletePolicyReport ( obj interface { } ) {
2022-06-28 17:27:34 +08:00
report , ok := kubeutils . GetObjectWithTombstone ( obj ) . ( * policyreportv1alpha2 . PolicyReport )
2022-05-03 18:58:20 +02:00
if ok {
g . log . V ( 2 ) . Info ( "PolicyReport deleted" , "name" , report . GetName ( ) )
} else {
g . log . Info ( "Failed to get deleted object" , "obj" , obj )
}
2021-03-25 12:28:03 -07:00
g . ReconcileCh <- false
}
func ( g * ReportGenerator ) deleteClusterPolicyReport ( obj interface { } ) {
g . log . V ( 2 ) . Info ( "ClusterPolicyReport deleted" )
g . ReconcileCh <- false
}
2020-11-09 11:26:12 -08:00
// Run starts the workers
func ( g * ReportGenerator ) Run ( workers int , stopCh <- chan struct { } ) {
logger := g . log
defer utilruntime . HandleCrash ( )
defer g . queue . ShutDown ( )
logger . Info ( "start" )
defer logger . Info ( "shutting down" )
2022-06-28 17:27:34 +08:00
if ! cache . WaitForNamedCacheSync ( "PolicyReportGenerator" , stopCh , g . informersSynced ... ) {
return
}
2021-06-08 12:37:19 -07:00
g . reportReqInformer . Informer ( ) . AddEventHandler (
cache . ResourceEventHandlerFuncs {
AddFunc : g . addReportChangeRequest ,
UpdateFunc : g . updateReportChangeRequest ,
} )
g . clusterReportReqInformer . Informer ( ) . AddEventHandler (
cache . ResourceEventHandlerFuncs {
AddFunc : g . addClusterReportChangeRequest ,
UpdateFunc : g . updateClusterReportChangeRequest ,
} )
g . reportInformer . Informer ( ) . AddEventHandler (
cache . ResourceEventHandlerFuncs {
DeleteFunc : g . deletePolicyReport ,
} )
g . clusterReportInformer . Informer ( ) . AddEventHandler (
cache . ResourceEventHandlerFuncs {
DeleteFunc : g . deleteClusterPolicyReport ,
} )
2020-11-09 11:26:12 -08:00
for i := 0 ; i < workers ; i ++ {
2020-12-23 17:48:00 -08:00
go wait . Until ( g . runWorker , time . Second , stopCh )
2020-11-09 11:26:12 -08:00
}
<- stopCh
}
func ( g * ReportGenerator ) runWorker ( ) {
for g . processNextWorkItem ( ) {
}
}
func ( g * ReportGenerator ) processNextWorkItem ( ) bool {
key , shutdown := g . queue . Get ( )
if shutdown {
return false
}
defer g . queue . Done ( key )
keyStr , ok := key . ( string )
if ! ok {
g . queue . Forget ( key )
g . log . Info ( "incorrect type; expecting type 'string'" , "obj" , key )
return true
}
2021-07-14 09:57:16 -07:00
aggregatedRequests , err := g . syncHandler ( keyStr )
g . handleErr ( err , key , aggregatedRequests )
2020-11-09 11:26:12 -08:00
return true
}
2021-07-14 09:57:16 -07:00
func ( g * ReportGenerator ) handleErr ( err error , key interface { } , aggregatedRequests interface { } ) {
2020-11-09 11:26:12 -08:00
logger := g . log
if err == nil {
g . queue . Forget ( key )
return
}
// retires requests if there is error
if g . queue . NumRequeues ( key ) < workQueueRetryLimit {
2020-12-01 12:30:08 -08:00
logger . V ( 3 ) . Info ( "retrying policy report" , "key" , key , "error" , err . Error ( ) )
2020-11-09 11:26:12 -08:00
g . queue . AddRateLimited ( key )
return
}
2020-12-01 12:30:08 -08:00
logger . Error ( err , "failed to process policy report" , "key" , key )
2020-11-09 11:26:12 -08:00
g . queue . Forget ( key )
2021-07-14 09:57:16 -07:00
if aggregatedRequests != nil {
g . cleanupReportRequests ( aggregatedRequests )
}
2020-11-09 11:26:12 -08:00
}
// syncHandler reconciles clusterPolicyReport if namespace == ""
2022-06-28 22:02:52 +05:30
// otherwise it updates policyReport. the key is of type "namespace/policyname"
2021-07-14 09:57:16 -07:00
func ( g * ReportGenerator ) syncHandler ( key string ) ( aggregatedRequests interface { } , err error ) {
2020-12-21 11:04:19 -08:00
g . log . V ( 4 ) . Info ( "syncing policy report" , "key" , key )
2020-11-09 11:26:12 -08:00
if policy , rule , ok := isDeletedPolicyKey ( key ) ; ok {
2021-10-27 22:59:59 -07:00
g . log . V ( 4 ) . Info ( "sync policy report on policy deletion" )
2020-11-09 11:26:12 -08:00
return g . removePolicyEntryFromReport ( policy , rule )
}
2022-06-28 22:02:52 +05:30
var namespace , policyName string
2022-07-21 15:19:24 +05:30
if toggle . SplitPolicyReport ( ) {
2022-06-28 22:02:52 +05:30
namespace = strings . Split ( key , "/" ) [ 0 ]
policyName = strings . Split ( key , "/" ) [ 1 ]
} else {
namespace = key
}
new , aggregatedRequests , err := g . aggregateReports ( namespace , policyName )
2020-11-09 11:26:12 -08:00
if err != nil {
2021-07-14 09:57:16 -07:00
return aggregatedRequests , fmt . Errorf ( "failed to aggregate reportChangeRequest results %v" , err )
2020-11-09 11:26:12 -08:00
}
2022-07-21 15:19:24 +05:30
if toggle . SplitPolicyReport ( ) {
2022-06-28 22:02:52 +05:30
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
2022-07-21 15:19:24 +05:30
report , err = g . reportLister . PolicyReports ( namespace ) . Get ( GeneratePolicyReportName ( namespace , policyName ) )
2022-06-28 14:18:57 +08:00
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" )
return aggregatedRequests , nil
}
}
2022-06-28 22:02:52 +05:30
// Delete changes request does not have the policyName label set
2020-11-09 11:26:12 -08:00
var old interface { }
2022-06-28 22:02:52 +05:30
if old , err = g . createReportIfNotPresent ( namespace , policyName , new , aggregatedRequests ) ; err != nil {
2021-07-14 09:57:16 -07:00
return aggregatedRequests , err
2020-11-09 11:26:12 -08:00
}
2021-10-27 22:59:59 -07:00
2020-12-08 23:04:16 -08:00
if old == nil {
2021-10-27 22:59:59 -07:00
g . log . V ( 4 ) . Info ( "no existing policy report is found, clean up related report change requests" )
2020-12-08 23:04:16 -08:00
g . cleanupReportRequests ( aggregatedRequests )
2021-07-14 09:57:16 -07:00
return nil , nil
2020-12-08 23:04:16 -08:00
}
2020-11-09 11:26:12 -08:00
if err := g . updateReport ( old , new , aggregatedRequests ) ; err != nil {
2021-07-14 09:57:16 -07:00
return aggregatedRequests , err
2020-11-09 11:26:12 -08:00
}
2020-12-04 10:04:46 -08:00
g . cleanupReportRequests ( aggregatedRequests )
2021-07-14 09:57:16 -07:00
return nil , nil
2020-11-09 11:26:12 -08:00
}
// createReportIfNotPresent creates cluster / policyReport if not present
// return the existing report if exist
2022-06-28 22:02:52 +05:30
func ( g * ReportGenerator ) createReportIfNotPresent ( namespace , policyName string , new * unstructured . Unstructured , aggregatedRequests interface { } ) ( report interface { } , err error ) {
2020-11-09 11:26:12 -08:00
log := g . log . WithName ( "createReportIfNotPresent" )
2021-02-08 14:42:17 -08:00
obj , hasDuplicate , err := updateResults ( new . UnstructuredContent ( ) , new . UnstructuredContent ( ) , nil )
if hasDuplicate && err != nil {
g . log . Error ( err , "failed to remove duplicate results" , "policy report" , new . GetName ( ) )
} else {
new . Object = obj
}
2020-11-09 11:26:12 -08:00
if namespace != "" {
2020-12-08 23:04:16 -08:00
ns , err := g . nsLister . Get ( namespace )
if err != nil {
if apierrors . IsNotFound ( err ) {
2020-11-16 13:02:45 -08:00
return nil , nil
}
2020-12-08 23:04:16 -08:00
return nil , fmt . Errorf ( "failed to fetch namespace: %v" , err )
}
if ns . GetDeletionTimestamp ( ) != nil {
return nil , nil
2020-11-16 13:02:45 -08:00
}
2022-07-21 15:19:24 +05:30
report , err = g . reportLister . PolicyReports ( namespace ) . Get ( GeneratePolicyReportName ( namespace , policyName ) )
2020-11-09 11:26:12 -08:00
if err != nil {
if apierrors . IsNotFound ( err ) && new != nil {
2022-01-22 13:36:42 +08:00
polr , err := convertToPolr ( new )
if err != nil {
return nil , fmt . Errorf ( "failed to convert to policyReport: %v" , err )
}
if _ , err := g . pclient . Wgpolicyk8sV1alpha2 ( ) . PolicyReports ( new . GetNamespace ( ) ) . Create ( context . TODO ( ) , polr , metav1 . CreateOptions { } ) ; err != nil {
2020-11-09 11:26:12 -08:00
return nil , fmt . Errorf ( "failed to create policyReport: %v" , err )
}
log . V ( 2 ) . Info ( "successfully created policyReport" , "namespace" , new . GetNamespace ( ) , "name" , new . GetName ( ) )
2020-12-04 10:04:46 -08:00
g . cleanupReportRequests ( aggregatedRequests )
2020-11-09 11:26:12 -08:00
return nil , nil
}
return nil , fmt . Errorf ( "unable to get policyReport: %v" , err )
}
} else {
2022-07-21 15:19:24 +05:30
report , err = g . clusterReportLister . Get ( GeneratePolicyReportName ( namespace , policyName ) )
2020-11-09 11:26:12 -08:00
if err != nil {
if apierrors . IsNotFound ( err ) {
if new != nil {
2022-01-22 13:36:42 +08:00
cpolr , err := convertToCpolr ( new )
if err != nil {
return nil , fmt . Errorf ( "failed to convert to ClusterPolicyReport: %v" , err )
}
if _ , err := g . pclient . Wgpolicyk8sV1alpha2 ( ) . ClusterPolicyReports ( ) . Create ( context . TODO ( ) , cpolr , metav1 . CreateOptions { } ) ; err != nil {
2020-11-09 11:26:12 -08:00
return nil , fmt . Errorf ( "failed to create ClusterPolicyReport: %v" , err )
}
log . V ( 2 ) . Info ( "successfully created ClusterPolicyReport" )
2020-12-04 10:04:46 -08:00
g . cleanupReportRequests ( aggregatedRequests )
2020-11-09 11:26:12 -08:00
return nil , nil
}
return nil , nil
}
return nil , fmt . Errorf ( "unable to get ClusterPolicyReport: %v" , err )
}
}
return report , nil
}
2021-07-14 09:57:16 -07:00
func ( g * ReportGenerator ) removePolicyEntryFromReport ( policyName , ruleName string ) ( aggregatedRequests interface { } , err error ) {
2020-12-21 11:04:19 -08:00
if err := g . removeFromClusterPolicyReport ( policyName , ruleName ) ; err != nil {
2021-07-14 09:57:16 -07:00
return nil , err
2020-12-21 11:04:19 -08:00
}
if err := g . removeFromPolicyReport ( policyName , ruleName ) ; err != nil {
2021-07-14 09:57:16 -07:00
return nil , err
2020-12-21 11:04:19 -08:00
}
labelset := labels . Set ( map [ string ] string { deletedLabelPolicy : policyName } )
if ruleName != "" {
labelset = labels . Set ( map [ string ] string {
deletedLabelPolicy : policyName ,
deletedLabelRule : ruleName ,
} )
}
2021-07-14 09:57:16 -07:00
aggregatedRequests , err = g . reportChangeRequestLister . ReportChangeRequests ( config . KyvernoNamespace ) . List ( labels . SelectorFromSet ( labelset ) )
2020-12-21 11:04:19 -08:00
if err != nil {
2021-07-14 09:57:16 -07:00
return aggregatedRequests , err
2020-12-21 11:04:19 -08:00
}
g . cleanupReportRequests ( aggregatedRequests )
2021-07-14 09:57:16 -07:00
return nil , nil
2020-12-21 11:04:19 -08:00
}
func ( g * ReportGenerator ) removeFromClusterPolicyReport ( policyName , ruleName string ) error {
2020-11-09 11:26:12 -08:00
cpolrs , err := g . clusterReportLister . List ( labels . Everything ( ) )
if err != nil {
return fmt . Errorf ( "failed to list clusterPolicyReport %v" , err )
}
for _ , cpolr := range cpolrs {
2022-06-28 17:27:34 +08:00
newRes := [ ] policyreportv1alpha2 . PolicyReportResult { }
2020-11-09 11:26:12 -08:00
for _ , result := range cpolr . Results {
if ruleName != "" && result . Rule == ruleName && result . Policy == policyName {
continue
} else if ruleName == "" && result . Policy == policyName {
2022-07-21 15:19:24 +05:30
if toggle . SplitPolicyReport ( ) {
2022-07-01 10:11:05 +05:30
if err := g . pclient . Wgpolicyk8sV1alpha2 ( ) . ClusterPolicyReports ( ) . Delete ( context . TODO ( ) , cpolr . GetName ( ) , metav1 . DeleteOptions { } ) ; err != nil {
if apierrors . IsNotFound ( err ) {
return nil
} else {
return fmt . Errorf ( "failed to delete clusterPolicyReport %s %v" , policyName , err )
}
}
} else {
continue
}
2020-11-09 11:26:12 -08:00
}
newRes = append ( newRes , result )
}
cpolr . Results = newRes
cpolr . Summary = calculateSummary ( newRes )
2022-06-28 17:27:34 +08:00
gv := policyreportv1alpha2 . SchemeGroupVersion
2020-11-09 11:26:12 -08:00
cpolr . SetGroupVersionKind ( schema . GroupVersionKind { Group : gv . Group , Version : gv . Version , Kind : "ClusterPolicyReport" } )
2022-01-22 13:36:42 +08:00
if _ , err := g . pclient . Wgpolicyk8sV1alpha2 ( ) . ClusterPolicyReports ( ) . Update ( context . TODO ( ) , cpolr , metav1 . UpdateOptions { } ) ; err != nil {
2020-11-09 11:26:12 -08:00
return fmt . Errorf ( "failed to update clusterPolicyReport %s %v" , cpolr . Name , err )
}
}
2020-12-21 11:04:19 -08:00
return nil
}
2020-11-09 11:26:12 -08:00
2020-12-21 11:04:19 -08:00
func ( g * ReportGenerator ) removeFromPolicyReport ( policyName , ruleName string ) error {
2020-11-09 11:26:12 -08:00
namespaces , err := g . dclient . ListResource ( "" , "Namespace" , "" , nil )
2022-06-28 22:02:52 +05:30
2020-11-09 11:26:12 -08:00
if err != nil {
return fmt . Errorf ( "unable to list namespace %v" , err )
}
2021-12-17 06:03:52 +01:00
selector , err := metav1 . LabelSelectorAsSelector ( LabelSelector )
2022-01-22 13:36:42 +08:00
if err != nil {
g . log . Error ( err , "failed to build labelSelector" )
}
2022-06-28 17:27:34 +08:00
policyReports := [ ] * policyreportv1alpha2 . PolicyReport { }
2020-11-09 11:26:12 -08:00
for _ , ns := range namespaces . Items {
2021-12-17 06:03:52 +01:00
reports , err := g . reportLister . PolicyReports ( ns . GetName ( ) ) . List ( selector )
2020-11-09 11:26:12 -08:00
if err != nil {
return fmt . Errorf ( "unable to list policyReport for namespace %s %v" , ns . GetName ( ) , err )
}
policyReports = append ( policyReports , reports ... )
}
for _ , r := range policyReports {
2022-06-28 17:27:34 +08:00
newRes := [ ] policyreportv1alpha2 . PolicyReportResult { }
2020-11-09 11:26:12 -08:00
for _ , result := range r . Results {
if ruleName != "" && result . Rule == ruleName && result . Policy == policyName {
continue
} else if ruleName == "" && result . Policy == policyName {
2022-07-21 15:19:24 +05:30
if toggle . SplitPolicyReport ( ) {
2022-07-01 10:11:05 +05:30
if err := g . pclient . Wgpolicyk8sV1alpha2 ( ) . PolicyReports ( r . GetNamespace ( ) ) . Delete ( context . TODO ( ) , r . GetName ( ) , metav1 . DeleteOptions { } ) ; err != nil {
if apierrors . IsNotFound ( err ) {
return nil
} else {
return fmt . Errorf ( "failed to delete PolicyReport %s %v" , r . GetName ( ) , err )
}
}
} else {
continue
}
2020-11-09 11:26:12 -08:00
}
newRes = append ( newRes , result )
}
r . Results = newRes
r . Summary = calculateSummary ( newRes )
2022-06-28 17:27:34 +08:00
gv := policyreportv1alpha2 . SchemeGroupVersion
2020-11-09 11:26:12 -08:00
gvk := schema . GroupVersionKind { Group : gv . Group , Version : gv . Version , Kind : "PolicyReport" }
r . SetGroupVersionKind ( gvk )
2022-06-28 22:02:52 +05:30
2022-01-22 13:36:42 +08:00
if _ , err := g . pclient . Wgpolicyk8sV1alpha2 ( ) . PolicyReports ( r . GetNamespace ( ) ) . Update ( context . TODO ( ) , r , metav1 . UpdateOptions { } ) ; err != nil {
2020-11-09 11:26:12 -08:00
return fmt . Errorf ( "failed to update PolicyReport %s %v" , r . GetName ( ) , err )
}
}
return nil
}
2020-12-21 11:04:19 -08:00
// aggregateReports aggregates cluster / report change requests to a policy report
2022-06-28 22:02:52 +05:30
func ( g * ReportGenerator ) aggregateReports ( namespace , policyName string ) (
report * unstructured . Unstructured ,
aggregatedRequests interface { } ,
err error ,
) {
2022-02-18 16:50:18 +08:00
kyvernoNamespace , err := g . nsLister . Get ( config . KyvernoNamespace )
if err != nil {
g . log . Error ( err , "failed to get Kyverno namespace, policy reports will not be garbage collected upon termination" )
}
2022-06-28 22:02:52 +05:30
selector := labels . NewSelector ( )
2020-11-09 11:26:12 -08:00
if namespace == "" {
2022-07-21 15:19:24 +05:30
if toggle . SplitPolicyReport ( ) {
2022-06-28 22:02:52 +05:30
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 } ) )
}
2021-09-14 01:06:56 -07:00
requests , err := g . clusterReportChangeRequestLister . List ( selector )
2020-11-09 11:26:12 -08:00
if err != nil {
return nil , nil , fmt . Errorf ( "unable to list ClusterReportChangeRequests within: %v" , err )
}
2022-06-28 22:02:52 +05:30
if report , aggregatedRequests , err = g . mergeRequests ( nil , kyvernoNamespace , policyName , requests ) ; err != nil {
2020-11-09 11:26:12 -08:00
return nil , nil , fmt . Errorf ( "unable to merge ClusterReportChangeRequests results: %v" , err )
}
} else {
ns , err := g . nsLister . Get ( namespace )
if err != nil {
2020-11-16 13:02:45 -08:00
if ! apierrors . IsNotFound ( err ) {
return nil , nil , fmt . Errorf ( "unable to get namespace %s: %v" , namespace , err )
}
2020-12-08 23:04:16 -08:00
// Namespace is deleted, create a fake ns to clean up RCRs
ns = new ( v1 . Namespace )
ns . SetName ( namespace )
now := metav1 . Now ( )
ns . SetDeletionTimestamp ( & now )
2020-11-09 11:26:12 -08:00
}
2022-07-21 15:19:24 +05:30
if toggle . SplitPolicyReport ( ) {
2022-06-28 22:02:52 +05:30
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 } ) )
}
2020-11-26 16:07:06 -08:00
requests , err := g . reportChangeRequestLister . ReportChangeRequests ( config . KyvernoNamespace ) . List ( selector )
2020-11-09 11:26:12 -08:00
if err != nil {
return nil , nil , fmt . Errorf ( "unable to list reportChangeRequests within namespace %s: %v" , ns , err )
}
2022-06-28 22:02:52 +05:30
if report , aggregatedRequests , err = g . mergeRequests ( ns , kyvernoNamespace , policyName , requests ) ; err != nil {
2020-11-09 11:26:12 -08:00
return nil , nil , fmt . Errorf ( "unable to merge results: %v" , err )
}
}
return report , aggregatedRequests , nil
}
2022-06-28 22:02:52 +05:30
func ( g * ReportGenerator ) mergeRequests ( ns , kyvernoNs * v1 . Namespace , policyName string , requestsGeneral interface { } ) ( * unstructured . Unstructured , interface { } , error ) {
2022-06-28 17:27:34 +08:00
results := [ ] policyreportv1alpha2 . PolicyReportResult { }
2020-11-09 11:26:12 -08:00
if requests , ok := requestsGeneral . ( [ ] * changerequest . ClusterReportChangeRequest ) ; ok {
aggregatedRequests := [ ] * changerequest . ClusterReportChangeRequest { }
for _ , request := range requests {
if request . GetDeletionTimestamp ( ) != nil {
continue
}
if len ( request . Results ) != 0 {
results = append ( results , request . Results ... )
}
aggregatedRequests = append ( aggregatedRequests , request )
}
2022-06-28 17:27:34 +08:00
report := & policyreportv1alpha2 . ClusterPolicyReport {
2020-11-09 11:26:12 -08:00
Results : results ,
Summary : calculateSummary ( results ) ,
}
obj , err := runtime . DefaultUnstructuredConverter . ToUnstructured ( report )
if err != nil {
return nil , aggregatedRequests , err
}
req := & unstructured . Unstructured { Object : obj }
2022-06-28 22:02:52 +05:30
g . setReport ( req , ns , kyvernoNs , policyName )
2020-11-09 11:26:12 -08:00
return req , aggregatedRequests , nil
}
if requests , ok := requestsGeneral . ( [ ] * changerequest . ReportChangeRequest ) ; ok {
aggregatedRequests := [ ] * changerequest . ReportChangeRequest { }
for _ , request := range requests {
if request . GetDeletionTimestamp ( ) != nil {
continue
}
if len ( request . Results ) != 0 {
results = append ( results , request . Results ... )
}
aggregatedRequests = append ( aggregatedRequests , request )
}
2022-06-28 17:27:34 +08:00
report := & policyreportv1alpha2 . PolicyReport {
2020-11-09 11:26:12 -08:00
Results : results ,
Summary : calculateSummary ( results ) ,
}
obj , err := runtime . DefaultUnstructuredConverter . ToUnstructured ( report )
if err != nil {
return nil , aggregatedRequests , err
}
req := & unstructured . Unstructured { Object : obj }
2022-06-28 22:02:52 +05:30
g . setReport ( req , ns , kyvernoNs , policyName )
2020-12-08 23:04:16 -08:00
2020-11-09 11:26:12 -08:00
return req , aggregatedRequests , nil
}
return nil , nil , nil
}
2022-06-28 22:02:52 +05:30
func ( g * ReportGenerator ) setReport ( reportUnstructured * unstructured . Unstructured , ns , kyvernoNs * v1 . Namespace , policyname string ) {
2022-06-28 17:27:34 +08:00
reportUnstructured . SetAPIVersion ( policyreportv1alpha2 . SchemeGroupVersion . String ( ) )
2021-12-17 06:03:52 +01:00
reportUnstructured . SetLabels ( LabelSelector . MatchLabels )
2020-11-09 11:26:12 -08:00
2022-02-18 16:50:18 +08:00
if kyvernoNs != nil {
controllerFlag := true
reportUnstructured . SetOwnerReferences ( [ ] metav1 . OwnerReference {
{
APIVersion : "v1" ,
Kind : "Namespace" ,
Name : kyvernoNs . GetName ( ) ,
UID : kyvernoNs . GetUID ( ) ,
Controller : & controllerFlag ,
} ,
} )
}
2020-11-09 11:26:12 -08:00
if ns == nil {
2022-07-21 15:19:24 +05:30
reportUnstructured . SetName ( GeneratePolicyReportName ( "" , policyname ) )
2020-11-11 15:09:07 -08:00
reportUnstructured . SetKind ( "ClusterPolicyReport" )
2020-11-09 11:26:12 -08:00
return
}
2022-07-21 15:19:24 +05:30
reportUnstructured . SetName ( GeneratePolicyReportName ( ns . GetName ( ) , policyname ) )
2020-11-11 15:09:07 -08:00
reportUnstructured . SetNamespace ( ns . GetName ( ) )
reportUnstructured . SetKind ( "PolicyReport" )
2020-11-09 11:26:12 -08:00
}
func ( g * ReportGenerator ) updateReport ( old interface { } , new * unstructured . Unstructured , aggregatedRequests interface { } ) ( err error ) {
if new == nil {
g . log . V ( 4 ) . Info ( "empty report to update" )
return nil
}
2021-10-27 22:59:59 -07:00
g . log . V ( 4 ) . Info ( "reconcile policy report" )
2020-11-09 11:26:12 -08:00
2020-12-04 10:04:46 -08:00
oldUnstructured := make ( map [ string ] interface { } )
2020-11-09 11:26:12 -08:00
2022-06-28 17:27:34 +08:00
if oldTyped , ok := old . ( * policyreportv1alpha2 . ClusterPolicyReport ) ; ok {
2020-11-09 11:26:12 -08:00
if oldTyped . GetDeletionTimestamp ( ) != nil {
2022-01-22 13:36:42 +08:00
return g . pclient . Wgpolicyk8sV1alpha2 ( ) . ClusterPolicyReports ( ) . Delete ( context . TODO ( ) , oldTyped . Name , metav1 . DeleteOptions { } )
2020-11-09 11:26:12 -08:00
}
2020-12-04 10:04:46 -08:00
if oldUnstructured , err = runtime . DefaultUnstructuredConverter . ToUnstructured ( oldTyped ) ; err != nil {
2020-11-09 11:26:12 -08:00
return fmt . Errorf ( "unable to convert clusterPolicyReport: %v" , err )
}
new . SetUID ( oldTyped . GetUID ( ) )
new . SetResourceVersion ( oldTyped . GetResourceVersion ( ) )
2022-06-28 17:27:34 +08:00
} else if oldTyped , ok := old . ( * policyreportv1alpha2 . PolicyReport ) ; ok {
2020-11-09 11:26:12 -08:00
if oldTyped . GetDeletionTimestamp ( ) != nil {
2022-01-22 13:36:42 +08:00
return g . pclient . Wgpolicyk8sV1alpha2 ( ) . PolicyReports ( oldTyped . Namespace ) . Delete ( context . TODO ( ) , oldTyped . Name , metav1 . DeleteOptions { } )
2020-11-09 11:26:12 -08:00
}
2020-12-04 10:04:46 -08:00
if oldUnstructured , err = runtime . DefaultUnstructuredConverter . ToUnstructured ( oldTyped ) ; err != nil {
2020-11-09 11:26:12 -08:00
return fmt . Errorf ( "unable to convert policyReport: %v" , err )
}
new . SetUID ( oldTyped . GetUID ( ) )
new . SetResourceVersion ( oldTyped . GetResourceVersion ( ) )
}
2021-10-27 22:59:59 -07:00
g . log . V ( 4 ) . Info ( "update results entries" )
2021-02-08 14:42:17 -08:00
obj , _ , err := updateResults ( oldUnstructured , new . UnstructuredContent ( ) , aggregatedRequests )
2020-11-09 11:26:12 -08:00
if err != nil {
return fmt . Errorf ( "failed to update results entry: %v" , err )
}
new . Object = obj
2020-12-04 10:04:46 -08:00
if ! hasResultsChanged ( oldUnstructured , new . UnstructuredContent ( ) ) {
2020-12-21 11:04:19 -08:00
g . log . V ( 4 ) . Info ( "unchanged policy report" , "kind" , new . GetKind ( ) , "namespace" , new . GetNamespace ( ) , "name" , new . GetName ( ) )
2020-11-09 11:26:12 -08:00
return nil
}
2022-01-22 13:36:42 +08:00
if new . GetKind ( ) == "PolicyReport" {
polr , err := convertToPolr ( new )
if err != nil {
return fmt . Errorf ( "error converting to PolicyReport: %v" , err )
}
if _ , err := g . pclient . Wgpolicyk8sV1alpha2 ( ) . PolicyReports ( new . GetNamespace ( ) ) . Update ( context . TODO ( ) , polr , metav1 . UpdateOptions { } ) ; err != nil {
2022-06-28 14:18:57 +08:00
if strings . Contains ( err . Error ( ) , resourceExhaustedErr ) {
g . log . V ( 4 ) . Info ( "got ResourceExhausted error, cleanning up change requests and erasing report results" )
annotations := polr . GetAnnotations ( )
if annotations == nil {
annotations = make ( map [ string ] string )
}
annotations [ inactiveLabelKey ] = "Unable to update policy report due to resourceExhausted error, please enable the flag \"splitPolicyReport\" to generate a report per policy"
polr . SetAnnotations ( annotations )
labels := polr . GetLabels ( )
labels [ inactiveLabelKey ] = inactiveLabelVal
polr . SetLabels ( labels )
polr . Results = [ ] policyreportv1alpha2 . PolicyReportResult { }
polr . Summary = policyreportv1alpha2 . PolicyReportSummary { }
if _ , err := g . pclient . Wgpolicyk8sV1alpha2 ( ) . PolicyReports ( new . GetNamespace ( ) ) . Update ( context . TODO ( ) , polr , metav1 . UpdateOptions { } ) ; err != nil {
return fmt . Errorf ( "failed to erase policy report results: %v" , err )
}
ns := new . GetNamespace ( )
g . cleanupChangeRequest <- ReconcileInfo { Namespace : & ns , MapperInactive : true }
return nil
}
2022-01-22 13:36:42 +08:00
return fmt . Errorf ( "failed to update PolicyReport: %v" , err )
}
}
if new . GetKind ( ) == "ClusterPolicyReport" {
cpolr , err := convertToCpolr ( new )
if err != nil {
return fmt . Errorf ( "error converting to ClusterPolicyReport: %v" , err )
}
if _ , err := g . pclient . Wgpolicyk8sV1alpha2 ( ) . ClusterPolicyReports ( ) . Update ( context . TODO ( ) , cpolr , metav1 . UpdateOptions { } ) ; err != nil {
2022-06-28 14:18:57 +08:00
if strings . Contains ( err . Error ( ) , resourceExhaustedErr ) {
g . log . V ( 4 ) . Info ( "got ResourceExhausted error, cleanning up change requests and erasing report results" )
annotations := cpolr . GetAnnotations ( )
if annotations == nil {
annotations = make ( map [ string ] string )
}
annotations [ inactiveLabelKey ] = "Unable to update cluster policy report due to resourceExhausted error, please enable the flag \"splitPolicyReport\" to generate report per policy"
cpolr . SetAnnotations ( annotations )
labels := cpolr . GetLabels ( )
labels [ inactiveLabelKey ] = inactiveLabelVal
cpolr . SetLabels ( labels )
cpolr . Results = [ ] policyreportv1alpha2 . PolicyReportResult { }
cpolr . Summary = policyreportv1alpha2 . PolicyReportSummary { }
if _ , err := g . pclient . Wgpolicyk8sV1alpha2 ( ) . ClusterPolicyReports ( ) . Update ( context . TODO ( ) , cpolr , metav1 . UpdateOptions { } ) ; err != nil {
return fmt . Errorf ( "failed to erase cluster policy report results: %v" , err )
}
ns := ""
g . cleanupChangeRequest <- ReconcileInfo { Namespace : & ns , MapperInactive : true }
return nil
}
2022-01-22 13:36:42 +08:00
return fmt . Errorf ( "failed to update ClusterPolicyReport: %v" , err )
}
2020-11-09 11:26:12 -08:00
}
g . log . V ( 3 ) . Info ( "successfully updated policy report" , "kind" , new . GetKind ( ) , "namespace" , new . GetNamespace ( ) , "name" , new . GetName ( ) )
return
}
2022-06-28 22:02:52 +05:30
func ( g * ReportGenerator ) updateReportsForDeletedResource ( resName string , new * unstructured . Unstructured , aggregatedRequests interface { } ) ( err error ) {
if _ , ok := aggregatedRequests . ( [ ] * changerequest . 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" } )
2022-09-26 10:08:33 +00:00
if _ , err := g . pclient . Wgpolicyk8sV1alpha2 ( ) . PolicyReports ( polr . Namespace ) . Update ( context . TODO ( ) , polr , metav1 . UpdateOptions { } ) ; err != nil {
2022-06-28 22:02:52 +05:30
return fmt . Errorf ( "failed to update clusterPolicyReport %s %v" , polr . Name , err )
}
}
}
return
}
2020-12-04 10:04:46 -08:00
func ( g * ReportGenerator ) cleanupReportRequests ( requestsGeneral interface { } ) {
2020-11-09 11:26:12 -08:00
defer g . log . V ( 5 ) . Info ( "successfully cleaned up report requests" )
if requests , ok := requestsGeneral . ( [ ] * changerequest . ReportChangeRequest ) ; ok {
for _ , request := range requests {
2022-01-22 13:36:42 +08:00
if err := g . pclient . KyvernoV1alpha2 ( ) . ReportChangeRequests ( config . KyvernoNamespace ) . Delete ( context . TODO ( ) , request . Name , metav1 . DeleteOptions { } ) ; err != nil {
2020-12-09 09:29:52 -08:00
if ! apierrors . IsNotFound ( err ) {
g . log . Error ( err , "failed to delete report request" )
2020-11-09 11:26:12 -08:00
}
2020-12-09 09:29:52 -08:00
}
2020-11-09 11:26:12 -08:00
}
}
if requests , ok := requestsGeneral . ( [ ] * changerequest . ClusterReportChangeRequest ) ; ok {
for _ , request := range requests {
2022-01-22 13:36:42 +08:00
if err := g . pclient . KyvernoV1alpha2 ( ) . ClusterReportChangeRequests ( ) . Delete ( context . TODO ( ) , request . Name , metav1 . DeleteOptions { } ) ; err != nil {
2020-11-09 11:26:12 -08:00
if ! apierrors . IsNotFound ( err ) {
g . log . Error ( err , "failed to delete clusterReportChangeRequest" )
}
}
}
}
}