2022-04-13 18:15:04 +05:30
package background
2020-01-07 10:33:28 -08:00
import (
2022-05-19 18:06:56 +02:00
"context"
2022-05-06 13:46:36 +08:00
"fmt"
2022-12-21 21:30:45 +01:00
"strings"
2020-10-07 11:12:31 -07:00
"time"
2022-05-24 21:05:11 +02:00
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
2022-05-17 13:12:43 +02:00
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
2022-04-13 18:15:04 +05:30
common "github.com/kyverno/kyverno/pkg/background/common"
2022-05-19 18:06:56 +02:00
"github.com/kyverno/kyverno/pkg/background/generate"
"github.com/kyverno/kyverno/pkg/background/mutate"
2022-09-07 06:01:43 +02:00
"github.com/kyverno/kyverno/pkg/client/clientset/versioned"
2022-05-18 06:02:31 +02:00
kyvernov1informers "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1"
kyvernov1beta1informers "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1beta1"
kyvernov1listers "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1"
kyvernov1beta1listers "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1beta1"
2022-08-31 14:03:47 +08:00
"github.com/kyverno/kyverno/pkg/clients/dclient"
2020-10-07 11:12:31 -07:00
"github.com/kyverno/kyverno/pkg/config"
2023-01-31 08:46:38 +01:00
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
2020-10-07 11:12:31 -07:00
"github.com/kyverno/kyverno/pkg/event"
2022-05-24 21:05:11 +02:00
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
2020-11-20 14:14:59 -08:00
apierrors "k8s.io/apimachinery/pkg/api/errors"
2022-05-19 18:06:56 +02:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2022-09-01 15:09:06 +05:30
"k8s.io/apimachinery/pkg/labels"
2022-05-19 18:06:56 +02:00
"k8s.io/apimachinery/pkg/util/runtime"
2020-01-07 10:33:28 -08:00
"k8s.io/apimachinery/pkg/util/wait"
2022-05-17 17:51:03 +02:00
corev1informers "k8s.io/client-go/informers/core/v1"
corev1listers "k8s.io/client-go/listers/core/v1"
2020-01-07 10:33:28 -08:00
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
)
const (
2020-12-01 12:30:08 -08:00
maxRetries = 10
2020-01-07 10:33:28 -08:00
)
2022-05-19 18:06:56 +02:00
type Controller interface {
2022-05-24 15:30:00 +02:00
// Run starts workers
2022-10-03 11:19:01 +02:00
Run ( context . Context , int )
2022-05-19 18:06:56 +02:00
}
2020-12-22 11:07:31 -08:00
2022-05-19 18:06:56 +02:00
// controller manages the life-cycle for Generate-Requests and applies generate rule
type controller struct {
// clients
client dclient . Interface
2022-09-07 06:01:43 +02:00
kyvernoClient versioned . Interface
2023-02-02 11:58:34 +01:00
engine engineapi . Engine
2020-12-01 12:30:08 -08:00
2022-05-19 18:06:56 +02:00
// listers
2022-05-24 16:41:17 +02:00
cpolLister kyvernov1listers . ClusterPolicyLister
polLister kyvernov1listers . PolicyLister
urLister kyvernov1beta1listers . UpdateRequestNamespaceLister
nsLister corev1listers . NamespaceLister
2022-03-29 18:34:33 +05:30
2022-06-28 12:55:52 +08:00
informersSynced [ ] cache . InformerSynced
2022-05-19 18:06:56 +02:00
// queue
queue workqueue . RateLimitingInterface
2020-08-07 17:09:24 -07:00
2022-12-16 18:26:48 +08:00
eventGen event . Interface
configuration config . Configuration
2023-01-31 08:46:38 +01:00
informerCacheResolvers engineapi . ConfigmapResolver
2020-01-07 10:33:28 -08:00
}
2022-05-17 08:19:03 +02:00
// NewController returns an instance of the Generate-Request Controller
2020-01-07 10:33:28 -08:00
func NewController (
2022-09-07 06:01:43 +02:00
kyvernoClient versioned . Interface ,
2022-05-03 07:30:04 +02:00
client dclient . Interface ,
2023-02-02 11:58:34 +01:00
engine engineapi . Engine ,
2022-05-24 16:41:17 +02:00
cpolInformer kyvernov1informers . ClusterPolicyInformer ,
polInformer kyvernov1informers . PolicyInformer ,
2022-05-18 06:02:31 +02:00
urInformer kyvernov1beta1informers . UpdateRequestInformer ,
2022-05-17 17:51:03 +02:00
namespaceInformer corev1informers . NamespaceInformer ,
2022-05-20 11:43:00 +02:00
eventGen event . Interface ,
2022-05-04 18:05:03 +02:00
dynamicConfig config . Configuration ,
2023-01-31 08:46:38 +01:00
informerCacheResolvers engineapi . ConfigmapResolver ,
2022-05-19 18:06:56 +02:00
) Controller {
urLister := urInformer . Lister ( ) . UpdateRequests ( config . KyvernoNamespace ( ) )
c := controller {
2022-12-16 18:26:48 +08:00
client : client ,
kyvernoClient : kyvernoClient ,
2023-02-02 11:58:34 +01:00
engine : engine ,
2022-12-16 18:26:48 +08:00
cpolLister : cpolInformer . Lister ( ) ,
polLister : polInformer . Lister ( ) ,
urLister : urLister ,
nsLister : namespaceInformer . Lister ( ) ,
2023-02-07 21:44:51 +08:00
queue : workqueue . NewNamedRateLimitingQueue ( workqueue . DefaultControllerRateLimiter ( ) , "background" ) ,
2022-12-16 18:26:48 +08:00
eventGen : eventGen ,
configuration : dynamicConfig ,
informerCacheResolvers : informerCacheResolvers ,
2020-01-07 10:33:28 -08:00
}
2022-12-21 23:33:51 +01:00
_ , _ = urInformer . Informer ( ) . AddEventHandler ( cache . ResourceEventHandlerFuncs {
2022-04-25 20:20:40 +08:00
AddFunc : c . addUR ,
UpdateFunc : c . updateUR ,
DeleteFunc : c . deleteUR ,
} )
2022-12-21 23:33:51 +01:00
_ , _ = cpolInformer . Informer ( ) . AddEventHandler ( cache . ResourceEventHandlerFuncs {
2022-05-24 21:05:11 +02:00
UpdateFunc : c . updatePolicy ,
DeleteFunc : c . deletePolicy ,
2022-05-24 16:41:17 +02:00
} )
2022-12-21 23:33:51 +01:00
_ , _ = polInformer . Informer ( ) . AddEventHandler ( cache . ResourceEventHandlerFuncs {
2022-05-24 21:05:11 +02:00
UpdateFunc : c . updatePolicy ,
DeleteFunc : c . deletePolicy ,
2022-05-19 18:06:56 +02:00
} )
2022-06-28 12:55:52 +08:00
2023-02-07 21:44:51 +08:00
c . informersSynced = [ ] cache . InformerSynced { cpolInformer . Informer ( ) . HasSynced , polInformer . Informer ( ) . HasSynced , urInformer . Informer ( ) . HasSynced , namespaceInformer . Informer ( ) . HasSynced }
2022-06-28 12:55:52 +08:00
2022-05-18 08:07:13 +02:00
return & c
2021-06-08 12:37:19 -07:00
}
2022-10-03 11:19:01 +02:00
func ( c * controller ) Run ( ctx context . Context , workers int ) {
2022-05-19 18:06:56 +02:00
defer runtime . HandleCrash ( )
2021-06-08 12:37:19 -07:00
defer c . queue . ShutDown ( )
2022-05-05 19:49:19 +05:30
logger . Info ( "starting" )
defer logger . Info ( "shutting down" )
2021-06-08 12:37:19 -07:00
2022-10-03 11:19:01 +02:00
if ! cache . WaitForNamedCacheSync ( "background" , ctx . Done ( ) , c . informersSynced ... ) {
2022-06-28 12:55:52 +08:00
return
}
2021-06-08 12:37:19 -07:00
for i := 0 ; i < workers ; i ++ {
2022-10-03 11:19:01 +02:00
go wait . UntilWithContext ( ctx , c . worker , time . Second )
2021-06-08 12:37:19 -07:00
}
2022-10-03 11:19:01 +02:00
<- ctx . Done ( )
2021-06-08 12:37:19 -07:00
}
// worker runs a worker thread that just dequeues items, processes them, and marks them done.
// It enforces that the syncHandler is never invoked concurrently with the same key.
2022-10-03 11:19:01 +02:00
func ( c * controller ) worker ( ctx context . Context ) {
2021-06-08 12:37:19 -07:00
for c . processNextWorkItem ( ) {
}
}
2022-05-19 18:06:56 +02:00
func ( c * controller ) processNextWorkItem ( ) bool {
2021-06-08 12:37:19 -07:00
key , quit := c . queue . Get ( )
if quit {
return false
}
defer c . queue . Done ( key )
2022-04-29 19:05:49 +08:00
err := c . syncUpdateRequest ( key . ( string ) )
2021-06-08 12:37:19 -07:00
c . handleErr ( err , key )
return true
}
2022-05-19 18:06:56 +02:00
func ( c * controller ) handleErr ( err error , key interface { } ) {
2021-06-08 12:37:19 -07:00
if err == nil {
c . queue . Forget ( key )
return
}
if apierrors . IsNotFound ( err ) {
c . queue . Forget ( key )
2022-04-29 19:05:49 +08:00
logger . V ( 4 ) . Info ( "Dropping update request from the queue" , "key" , key , "error" , err . Error ( ) )
2021-06-08 12:37:19 -07:00
return
}
if c . queue . NumRequeues ( key ) < maxRetries {
2022-04-29 19:05:49 +08:00
logger . V ( 3 ) . Info ( "retrying update request" , "key" , key , "error" , err . Error ( ) )
2021-06-08 12:37:19 -07:00
c . queue . AddRateLimited ( key )
return
}
2022-04-29 19:05:49 +08:00
logger . Error ( err , "failed to process update request" , "key" , key )
2021-06-08 12:37:19 -07:00
c . queue . Forget ( key )
}
2022-05-19 18:06:56 +02:00
func ( c * controller ) syncUpdateRequest ( key string ) error {
2021-06-08 12:37:19 -07:00
startTime := time . Now ( )
logger . V ( 4 ) . Info ( "started sync" , "key" , key , "startTime" , startTime )
defer func ( ) {
2022-04-29 19:05:49 +08:00
logger . V ( 4 ) . Info ( "completed sync update request" , "key" , key , "processingTime" , time . Since ( startTime ) . String ( ) )
2021-06-08 12:37:19 -07:00
} ( )
2022-04-29 19:05:49 +08:00
_ , urName , err := cache . SplitMetaNamespaceKey ( key )
2021-06-08 12:37:19 -07:00
if err != nil {
return err
}
2022-04-29 19:05:49 +08:00
ur , err := c . urLister . Get ( urName )
2021-06-08 12:37:19 -07:00
if err != nil {
2022-05-19 18:06:56 +02:00
return err
}
2022-10-20 23:18:27 +05:30
2023-02-10 18:22:11 +08:00
// Deep-copy otherwise we are mutating our cache.
ur = ur . DeepCopy ( )
2022-05-19 18:06:56 +02:00
// if not in any state, try to set it to pending
if ur . Status . State == "" {
ur . Status . State = kyvernov1beta1 . Pending
2023-02-10 18:22:11 +08:00
_ , err := c . kyvernoClient . KyvernoV1beta1 ( ) . UpdateRequests ( config . KyvernoNamespace ( ) ) . UpdateStatus ( context . TODO ( ) , ur , metav1 . UpdateOptions { } )
return err
2022-05-20 11:43:00 +02:00
}
2022-05-24 21:05:11 +02:00
// try to get the linked policy
if _ , err := c . getPolicy ( ur . Spec . Policy ) ; err != nil {
2022-07-12 17:38:15 -04:00
if apierrors . IsNotFound ( err ) && ur . Spec . Type == kyvernov1beta1 . Mutate {
2022-05-24 21:05:11 +02:00
// here only takes care of mutateExisting policies
// generate cleanup controller handles policy deletion
selector := & metav1 . LabelSelector {
MatchLabels : common . MutateLabelsSet ( ur . Spec . Policy , nil ) ,
}
return c . kyvernoClient . KyvernoV1beta1 ( ) . UpdateRequests ( config . KyvernoNamespace ( ) ) . DeleteCollection (
context . TODO ( ) ,
metav1 . DeleteOptions { } ,
metav1 . ListOptions { LabelSelector : metav1 . FormatLabelSelector ( selector ) } ,
)
}
2022-10-20 23:18:27 +05:30
// check if cleanup is required in case policy is no longer exists
if err := c . checkIfCleanupRequired ( ur ) ; err != nil {
return err
}
2022-05-24 21:05:11 +02:00
}
2023-02-07 21:44:51 +08:00
// process pending URs
2022-05-19 18:06:56 +02:00
if ur . Status . State == kyvernov1beta1 . Pending {
if err := c . processUR ( ur ) ; err != nil {
return fmt . Errorf ( "failed to process UR %s: %v" , key , err )
}
2021-06-08 12:37:19 -07:00
}
2023-02-07 21:44:51 +08:00
2022-05-19 18:06:56 +02:00
err = c . cleanUR ( ur )
return err
2020-01-07 10:33:28 -08:00
}
2022-10-20 23:18:27 +05:30
func ( c * controller ) checkIfCleanupRequired ( ur * kyvernov1beta1 . UpdateRequest ) error {
var err error
pNamespace , pName , err := cache . SplitMetaNamespaceKey ( ur . Spec . Policy )
if err != nil {
return err
}
if pNamespace == "" {
_ , err = c . cpolLister . Get ( pName )
} else {
_ , err = c . polLister . Policies ( pNamespace ) . Get ( pName )
}
if err != nil {
if ! apierrors . IsNotFound ( err ) {
return err
}
logger . V ( 4 ) . Info ( "policy no longer exists, deleting the update request and respective resource based on synchronize" , "ur" , ur . Name , "policy" , ur . Spec . Policy )
for _ , e := range ur . Status . GeneratedResources {
if err := c . cleanupDataResource ( e ) ; err != nil {
logger . Error ( err , "failed to clean up data resource on policy deletion" )
}
}
return c . kyvernoClient . KyvernoV1beta1 ( ) . UpdateRequests ( config . KyvernoNamespace ( ) ) . Delete ( context . TODO ( ) , ur . Name , metav1 . DeleteOptions { } )
}
return nil
}
// cleanupDataResource deletes resource if sync is enabled for data policy
func ( c * controller ) cleanupDataResource ( targetSpec kyvernov1 . ResourceSpec ) error {
2022-11-29 14:59:40 +01:00
target , err := c . client . GetResource ( context . TODO ( ) , targetSpec . APIVersion , targetSpec . Kind , targetSpec . Namespace , targetSpec . Name )
2022-10-20 23:18:27 +05:30
if err != nil {
if ! apierrors . IsNotFound ( err ) {
return fmt . Errorf ( "failed to find generated resource %s/%s: %v" , targetSpec . Namespace , targetSpec . Name , err )
}
}
if target == nil {
return nil
}
labels := target . GetLabels ( )
2023-02-10 21:26:51 +08:00
syncEnabled := labels [ generate . LabelSynchronize ] == "enable"
clone := labels [ generate . LabelClonePolicyName ] != ""
2022-10-20 23:18:27 +05:30
if syncEnabled && ! clone {
2022-11-29 14:59:40 +01:00
if err := c . client . DeleteResource ( context . TODO ( ) , target . GetAPIVersion ( ) , target . GetKind ( ) , target . GetNamespace ( ) , target . GetName ( ) , false ) ; err != nil {
2022-10-20 23:18:27 +05:30
return fmt . Errorf ( "failed to delete data resource %s/%s: %v" , targetSpec . Namespace , targetSpec . Name , err )
}
}
return nil
}
2022-05-19 18:06:56 +02:00
func ( c * controller ) enqueueUpdateRequest ( obj interface { } ) {
2022-04-25 20:20:40 +08:00
key , err := cache . MetaNamespaceKeyFunc ( obj )
2020-01-07 10:33:28 -08:00
if err != nil {
2022-05-19 18:06:56 +02:00
logger . Error ( err , "failed to extract name" )
2020-01-07 10:33:28 -08:00
return
}
2022-05-19 18:06:56 +02:00
logger . V ( 5 ) . Info ( "enqueued update request" , "ur" , key )
2020-01-07 10:33:28 -08:00
c . queue . Add ( key )
}
2022-05-24 16:41:17 +02:00
func ( c * controller ) updatePolicy ( _ , obj interface { } ) {
key , err := cache . MetaNamespaceKeyFunc ( obj )
2020-01-07 10:33:28 -08:00
if err != nil {
2022-05-24 16:41:17 +02:00
logger . Error ( err , "failed to compute policy key" )
} else {
logger . V ( 4 ) . Info ( "updating policy" , "key" , key )
urs , err := c . urLister . GetUpdateRequestsForClusterPolicy ( key )
if err != nil {
logger . Error ( err , "failed to list update requests for policy" , "key" , key )
return
}
// re-evaluate the UR as the policy was updated
for _ , ur := range urs {
c . enqueueUpdateRequest ( ur )
}
2020-08-31 23:55:13 +05:30
}
2022-04-25 20:20:40 +08:00
}
2022-05-24 21:05:11 +02:00
func ( c * controller ) deletePolicy ( obj interface { } ) {
2022-12-27 16:59:54 +08:00
var p kyvernov1 . PolicyInterface
switch kubeutils . GetObjectWithTombstone ( obj ) . ( type ) {
case * kyvernov1 . ClusterPolicy :
p = kubeutils . GetObjectWithTombstone ( obj ) . ( * kyvernov1 . ClusterPolicy )
case * kyvernov1 . Policy :
p = kubeutils . GetObjectWithTombstone ( obj ) . ( * kyvernov1 . Policy )
default :
2022-09-01 15:09:06 +05:30
logger . Info ( "Failed to get deleted object" , "obj" , obj )
return
}
2022-12-27 16:59:54 +08:00
logger . V ( 4 ) . Info ( "deleting policy" , "name" , p . GetName ( ) )
2022-05-24 21:05:11 +02:00
key , err := cache . MetaNamespaceKeyFunc ( kubeutils . GetObjectWithTombstone ( obj ) )
if err != nil {
logger . Error ( err , "failed to compute policy key" )
} else {
logger . V ( 4 ) . Info ( "updating policy" , "key" , key )
2022-09-01 15:09:06 +05:30
2022-10-20 23:18:27 +05:30
// check if deleted policy is clone generate policy
2022-12-21 21:30:45 +01:00
generatePolicyWithClone := c . processDeletePolicyForCloneGenerateRule ( p , p . GetName ( ) )
2022-09-01 15:09:06 +05:30
2022-10-20 23:18:27 +05:30
// get the generated resource name from update request
2022-09-01 15:09:06 +05:30
selector := labels . SelectorFromSet ( labels . Set ( map [ string ] string {
2022-12-27 16:59:54 +08:00
kyvernov1beta1 . URGeneratePolicyLabel : p . GetName ( ) ,
2022-09-01 15:09:06 +05:30
} ) )
urList , err := c . urLister . List ( selector )
if err != nil {
logger . Error ( err , "failed to get update request for the resource" , "label" , kyvernov1beta1 . URGeneratePolicyLabel )
return
}
if ! generatePolicyWithClone {
// re-evaluate the UR as the policy was updated
2022-10-20 23:18:27 +05:30
for _ , ur := range urList {
2022-09-01 15:09:06 +05:30
logger . V ( 4 ) . Info ( "enqueue the ur for cleanup" , "ur name" , ur . Name )
c . enqueueUpdateRequest ( ur )
}
2022-10-20 23:18:27 +05:30
} else {
for _ , ur := range urList {
for _ , generatedResource := range ur . Status . GeneratedResources {
logger . V ( 4 ) . Info ( "retaining resource for cloned policy" , "apiVersion" , generatedResource . APIVersion , "kind" , generatedResource . Kind , "name" , generatedResource . Name , "namespace" , generatedResource . Namespace )
}
}
2022-05-24 21:05:11 +02:00
}
}
}
2022-05-19 18:06:56 +02:00
func ( c * controller ) addUR ( obj interface { } ) {
2022-05-17 13:12:43 +02:00
ur := obj . ( * kyvernov1beta1 . UpdateRequest )
2022-04-29 19:05:49 +08:00
c . enqueueUpdateRequest ( ur )
2022-04-25 20:20:40 +08:00
}
2022-05-19 18:06:56 +02:00
func ( c * controller ) updateUR ( _ , cur interface { } ) {
2022-05-17 13:12:43 +02:00
curUr := cur . ( * kyvernov1beta1 . UpdateRequest )
2022-04-29 19:05:49 +08:00
c . enqueueUpdateRequest ( curUr )
2022-04-25 20:20:40 +08:00
}
2022-05-19 18:06:56 +02:00
func ( c * controller ) deleteUR ( obj interface { } ) {
2022-09-01 15:09:06 +05:30
ur , ok := obj . ( * kyvernov1beta1 . UpdateRequest )
if ! ok {
tombstone , ok := obj . ( cache . DeletedFinalStateUnknown )
if ! ok {
logger . Info ( "Couldn't get object from tombstone" , "obj" , obj )
return
}
ur , ok = tombstone . Obj . ( * kyvernov1beta1 . UpdateRequest )
if ! ok {
logger . Info ( "tombstone contained object that is not a Update Request CR" , "obj" , obj )
return
}
2022-04-25 20:20:40 +08:00
}
2022-09-01 15:09:06 +05:30
if ur . Status . Handler != "" {
return
}
// sync Handler will remove it from the queue
c . enqueueUpdateRequest ( ur )
2022-05-19 18:06:56 +02:00
}
2022-04-25 20:20:40 +08:00
2022-05-19 18:06:56 +02:00
func ( c * controller ) processUR ( ur * kyvernov1beta1 . UpdateRequest ) error {
2022-05-24 12:27:26 +02:00
statusControl := common . NewStatusControl ( c . kyvernoClient , c . urLister )
2022-05-19 18:06:56 +02:00
switch ur . Spec . Type {
case kyvernov1beta1 . Mutate :
2023-02-03 06:01:11 +01:00
ctrl := mutate . NewMutateExistingController ( c . client , statusControl , c . engine , c . cpolLister , c . polLister , c . nsLister , c . configuration , c . eventGen , logger )
2022-05-19 18:06:56 +02:00
return ctrl . ProcessUR ( ur )
case kyvernov1beta1 . Generate :
2023-02-03 06:01:11 +01:00
ctrl := generate . NewGenerateController ( c . client , c . kyvernoClient , statusControl , c . engine , c . cpolLister , c . polLister , c . urLister , c . nsLister , c . configuration , c . eventGen , logger )
2022-05-19 18:06:56 +02:00
return ctrl . ProcessUR ( ur )
2022-04-25 20:20:40 +08:00
}
2022-05-19 18:06:56 +02:00
return nil
}
2020-12-01 12:30:08 -08:00
2022-05-19 18:06:56 +02:00
func ( c * controller ) cleanUR ( ur * kyvernov1beta1 . UpdateRequest ) error {
if ur . Spec . Type == kyvernov1beta1 . Mutate && ur . Status . State == kyvernov1beta1 . Completed {
return c . kyvernoClient . KyvernoV1beta1 ( ) . UpdateRequests ( config . KyvernoNamespace ( ) ) . Delete ( context . TODO ( ) , ur . GetName ( ) , metav1 . DeleteOptions { } )
}
return nil
2020-01-07 10:33:28 -08:00
}
2022-05-24 21:05:11 +02:00
func ( c * controller ) getPolicy ( key string ) ( kyvernov1 . PolicyInterface , error ) {
namespace , name , err := cache . SplitMetaNamespaceKey ( key )
if err != nil {
return nil , err
}
if namespace == "" {
return c . cpolLister . Get ( name )
}
2022-07-12 17:38:15 -04:00
return c . polLister . Policies ( namespace ) . Get ( name )
2022-05-24 21:05:11 +02:00
}
2022-12-21 21:30:45 +01:00
func ( c * controller ) processDeletePolicyForCloneGenerateRule ( policy kyvernov1 . PolicyInterface , pName string ) bool {
generatePolicyWithClone := false
for _ , rule := range policy . GetSpec ( ) . Rules {
clone , sync := rule . GetCloneSyncForGenerate ( )
if ! ( clone && sync ) {
continue
}
logger . V ( 4 ) . Info ( "generate policy with clone, remove policy name from label of source resource" )
generatePolicyWithClone = true
var retryCount int
for retryCount < 5 {
err := c . updateSourceResource ( policy . GetName ( ) , rule )
if err != nil {
logger . Error ( err , "failed to update generate source resource labels" )
if apierrors . IsConflict ( err ) {
retryCount ++
} else {
break
}
}
break
}
}
return generatePolicyWithClone
}
func ( c * controller ) updateSourceResource ( pName string , rule kyvernov1 . Rule ) error {
obj , err := c . client . GetResource ( context . TODO ( ) , "" , rule . Generation . Kind , rule . Generation . Clone . Namespace , rule . Generation . Clone . Name )
if err != nil {
2023-02-01 14:38:04 +08:00
return fmt . Errorf ( "source resource %s/%s/%s not found: %w" , rule . Generation . Kind , rule . Generation . Clone . Namespace , rule . Generation . Clone . Name , err )
2022-12-21 21:30:45 +01:00
}
var update bool
labels := obj . GetLabels ( )
update , labels = removePolicyFromLabels ( pName , labels )
if ! update {
return nil
}
obj . SetLabels ( labels )
_ , err = c . client . UpdateResource ( context . TODO ( ) , obj . GetAPIVersion ( ) , rule . Generation . Kind , rule . Generation . Clone . Namespace , obj , false )
return err
}
func removePolicyFromLabels ( pName string , labels map [ string ] string ) ( bool , map [ string ] string ) {
if len ( labels ) == 0 {
return false , labels
}
2023-02-10 21:26:51 +08:00
if labels [ generate . LabelClonePolicyName ] != "" {
policyNames := labels [ generate . LabelClonePolicyName ]
2022-12-21 21:30:45 +01:00
if strings . Contains ( policyNames , pName ) {
desiredLabels := make ( map [ string ] string , len ( labels ) - 1 )
for k , v := range labels {
2023-02-10 21:26:51 +08:00
if k != generate . LabelClonePolicyName {
2022-12-21 21:30:45 +01:00
desiredLabels [ k ] = v
}
}
return true , desiredLabels
}
}
return false , labels
}