mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-13 19:28:55 +00:00
add labels to downstream and source resources (#6322)
Signed-off-by: ShutingZhao <shuting@nirmata.com>
This commit is contained in:
parent
9e4ca53c3c
commit
d5684f6794
25 changed files with 592 additions and 239 deletions
|
@ -5,8 +5,8 @@ const (
|
|||
URMutatePolicyLabel = "mutate.updaterequest.kyverno.io/policy-name"
|
||||
URMutateTriggerNameLabel = "mutate.updaterequest.kyverno.io/trigger-name"
|
||||
URMutateTriggerNSLabel = "mutate.updaterequest.kyverno.io/trigger-namespace"
|
||||
URMutatetriggerKindLabel = "mutate.updaterequest.kyverno.io/trigger-kind"
|
||||
URMutatetriggerAPIVersionLabel = "mutate.updaterequest.kyverno.io/trigger-apiversion"
|
||||
URMutateTriggerKindLabel = "mutate.updaterequest.kyverno.io/trigger-kind"
|
||||
URMutateTriggerAPIVersionLabel = "mutate.updaterequest.kyverno.io/trigger-apiversion"
|
||||
|
||||
// URGeneratePolicyLabel adds the policy name to URs for generate policies
|
||||
URGeneratePolicyLabel = "generate.kyverno.io/policy-name"
|
||||
|
|
|
@ -59,7 +59,7 @@ type UpdateRequest struct {
|
|||
metav1.TypeMeta `json:",inline"`
|
||||
metav1.ObjectMeta `json:"metadata,omitempty"`
|
||||
|
||||
// Spec is the information to identify the update request.
|
||||
// ResourceSpec is the information to identify the trigger resource.
|
||||
Spec UpdateRequestSpec `json:"spec,omitempty"`
|
||||
|
||||
// Status contains statistics related to update request.
|
||||
|
@ -86,11 +86,14 @@ type UpdateRequestSpec struct {
|
|||
// Rule is the associate rule name of the current UR.
|
||||
Rule string `json:"rule" yaml:"rule"`
|
||||
|
||||
// DeleteDownstream represents whether the downstream needs to be deleted.
|
||||
DeleteDownstream bool `json:"deleteDownstream" yaml:"deleteDownstream"`
|
||||
|
||||
// Synchronize represents the sync behavior of the corresponding rule
|
||||
// Optional. Defaults to "false" if not specified.
|
||||
Synchronize bool `json:"synchronize,omitempty" yaml:"synchronize,omitempty"`
|
||||
|
||||
// ResourceSpec is the information to identify the update request.
|
||||
// ResourceSpec is the information to identify the trigger resource.
|
||||
Resource kyvernov1.ResourceSpec `json:"resource" yaml:"resource"`
|
||||
|
||||
// Context ...
|
||||
|
|
|
@ -30315,7 +30315,7 @@ spec:
|
|||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: Spec is the information to identify the update request.
|
||||
description: ResourceSpec is the information to identify the trigger resource.
|
||||
properties:
|
||||
context:
|
||||
description: Context ...
|
||||
|
@ -30570,6 +30570,10 @@ spec:
|
|||
type: object
|
||||
type: object
|
||||
type: object
|
||||
deleteDownstream:
|
||||
description: DeleteDownstream represents whether the downstream needs
|
||||
to be deleted.
|
||||
type: boolean
|
||||
policy:
|
||||
description: Specifies the name of the policy.
|
||||
type: string
|
||||
|
@ -30580,8 +30584,8 @@ spec:
|
|||
- generate
|
||||
type: string
|
||||
resource:
|
||||
description: ResourceSpec is the information to identify the update
|
||||
request.
|
||||
description: ResourceSpec is the information to identify the trigger
|
||||
resource.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: APIVersion specifies resource apiVersion.
|
||||
|
@ -30605,6 +30609,7 @@ spec:
|
|||
type: boolean
|
||||
required:
|
||||
- context
|
||||
- deleteDownstream
|
||||
- policy
|
||||
- resource
|
||||
- rule
|
||||
|
|
|
@ -495,6 +495,8 @@ func main() {
|
|||
kubeInformer.Rbac().V1().RoleBindings().Lister(),
|
||||
kubeInformer.Rbac().V1().ClusterRoleBindings().Lister(),
|
||||
kyvernoInformer.Kyverno().V1beta1().UpdateRequests().Lister().UpdateRequests(config.KyvernoNamespace()),
|
||||
kyvernoInformer.Kyverno().V1().ClusterPolicies(),
|
||||
kyvernoInformer.Kyverno().V1().Policies(),
|
||||
urgen,
|
||||
eventGenerator,
|
||||
openApiManager,
|
||||
|
|
|
@ -60,7 +60,7 @@ spec:
|
|||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: Spec is the information to identify the update request.
|
||||
description: ResourceSpec is the information to identify the trigger resource.
|
||||
properties:
|
||||
context:
|
||||
description: Context ...
|
||||
|
@ -315,6 +315,10 @@ spec:
|
|||
type: object
|
||||
type: object
|
||||
type: object
|
||||
deleteDownstream:
|
||||
description: DeleteDownstream represents whether the downstream needs
|
||||
to be deleted.
|
||||
type: boolean
|
||||
policy:
|
||||
description: Specifies the name of the policy.
|
||||
type: string
|
||||
|
@ -325,8 +329,8 @@ spec:
|
|||
- generate
|
||||
type: string
|
||||
resource:
|
||||
description: ResourceSpec is the information to identify the update
|
||||
request.
|
||||
description: ResourceSpec is the information to identify the trigger
|
||||
resource.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: APIVersion specifies resource apiVersion.
|
||||
|
@ -350,6 +354,7 @@ spec:
|
|||
type: boolean
|
||||
required:
|
||||
- context
|
||||
- deleteDownstream
|
||||
- policy
|
||||
- resource
|
||||
- rule
|
||||
|
|
|
@ -4379,7 +4379,7 @@ UpdateRequestSpec
|
|||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>Spec is the information to identify the update request.</p>
|
||||
<p>ResourceSpec is the information to identify the trigger resource.</p>
|
||||
<br/>
|
||||
<br/>
|
||||
<table class="table table-striped">
|
||||
|
@ -4420,6 +4420,17 @@ string
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>deleteDownstream</code><br/>
|
||||
<em>
|
||||
bool
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>DeleteDownstream represents whether the downstream needs to be deleted.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>synchronize</code><br/>
|
||||
<em>
|
||||
bool
|
||||
|
@ -4440,7 +4451,7 @@ ResourceSpec
|
|||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>ResourceSpec is the information to identify the update request.</p>
|
||||
<p>ResourceSpec is the information to identify the trigger resource.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -4642,6 +4653,17 @@ string
|
|||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>deleteDownstream</code><br/>
|
||||
<em>
|
||||
bool
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>DeleteDownstream represents whether the downstream needs to be deleted.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>synchronize</code><br/>
|
||||
<em>
|
||||
bool
|
||||
|
@ -4662,7 +4684,7 @@ ResourceSpec
|
|||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<p>ResourceSpec is the information to identify the update request.</p>
|
||||
<p>ResourceSpec is the information to identify the trigger resource.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
11
pkg/background/common/constants.go
Normal file
11
pkg/background/common/constants.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
package common
|
||||
|
||||
const (
|
||||
GeneratePolicyLabel = "generate.kyverno.io/policy-name"
|
||||
GeneratePolicyNamespaceLabel = "generate.kyverno.io/policy-namespace"
|
||||
GenerateRuleLabel = "generate.kyverno.io/rule-name"
|
||||
GenerateTriggerNameLabel = "generate.kyverno.io/trigger-name"
|
||||
GenerateTriggerNSLabel = "generate.kyverno.io/trigger-namespace"
|
||||
GenerateTriggerKindLabel = "generate.kyverno.io/trigger-kind"
|
||||
GenerateTriggerAPIVersionLabel = "generate.kyverno.io/trigger-apiversion"
|
||||
)
|
|
@ -54,7 +54,7 @@ func NewBackgroundContext(dclient dclient.Interface, ur *kyvernov1beta1.UpdateRe
|
|||
|
||||
err = ctx.AddResource(trigger.Object)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("failed to load resource in contex: %w", err)
|
||||
return nil, false, fmt.Errorf("failed to load resource in context: %w", err)
|
||||
}
|
||||
|
||||
err = ctx.AddOldResource(old.Object)
|
||||
|
|
|
@ -26,7 +26,7 @@ type Object interface {
|
|||
GetAPIVersion() string
|
||||
}
|
||||
|
||||
func ManageLabels(unstr *unstructured.Unstructured, triggerResource unstructured.Unstructured) {
|
||||
func ManageLabels(unstr *unstructured.Unstructured, triggerResource unstructured.Unstructured, policy kyvernov1.PolicyInterface, ruleName string) {
|
||||
// add managedBY label if not defined
|
||||
labels := unstr.GetLabels()
|
||||
if labels == nil {
|
||||
|
@ -38,6 +38,9 @@ func ManageLabels(unstr *unstructured.Unstructured, triggerResource unstructured
|
|||
// handle generatedBy label
|
||||
generatedBy(labels, triggerResource)
|
||||
|
||||
PolicyInfo(labels, policy, ruleName)
|
||||
|
||||
TriggerInfo(labels, &triggerResource)
|
||||
// update the labels
|
||||
unstr.SetLabels(labels)
|
||||
}
|
||||
|
@ -52,9 +55,9 @@ func MutateLabelsSet(policyKey string, trigger Object) pkglabels.Set {
|
|||
if !isNil {
|
||||
set[kyvernov1beta1.URMutateTriggerNameLabel] = trigger.GetName()
|
||||
set[kyvernov1beta1.URMutateTriggerNSLabel] = trigger.GetNamespace()
|
||||
set[kyvernov1beta1.URMutatetriggerKindLabel] = trigger.GetKind()
|
||||
set[kyvernov1beta1.URMutateTriggerKindLabel] = trigger.GetKind()
|
||||
if trigger.GetAPIVersion() != "" {
|
||||
set[kyvernov1beta1.URMutatetriggerAPIVersionLabel] = strings.ReplaceAll(trigger.GetAPIVersion(), "/", "-")
|
||||
set[kyvernov1beta1.URMutateTriggerAPIVersionLabel] = strings.ReplaceAll(trigger.GetAPIVersion(), "/", "-")
|
||||
}
|
||||
}
|
||||
return set
|
||||
|
@ -99,9 +102,7 @@ func generatedBy(labels map[string]string, triggerResource unstructured.Unstruct
|
|||
}
|
||||
|
||||
func checkGeneratedBy(labels map[string]string, key, value string) {
|
||||
if len(value) > 63 {
|
||||
value = value[0:63]
|
||||
}
|
||||
value = trimByLength(value, 63)
|
||||
|
||||
val, ok := labels[key]
|
||||
if ok {
|
||||
|
@ -115,3 +116,23 @@ func checkGeneratedBy(labels map[string]string, key, value string) {
|
|||
labels[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
func PolicyInfo(labels map[string]string, policy kyvernov1.PolicyInterface, ruleName string) {
|
||||
labels[GeneratePolicyLabel] = policy.GetName()
|
||||
labels[GeneratePolicyNamespaceLabel] = policy.GetNamespace()
|
||||
labels[GenerateRuleLabel] = ruleName
|
||||
}
|
||||
|
||||
func TriggerInfo(labels map[string]string, obj Object) {
|
||||
labels[GenerateTriggerAPIVersionLabel] = obj.GetAPIVersion()
|
||||
labels[GenerateTriggerKindLabel] = obj.GetKind()
|
||||
labels[GenerateTriggerNSLabel] = obj.GetNamespace()
|
||||
labels[GenerateTriggerNameLabel] = trimByLength(obj.GetName(), 63)
|
||||
}
|
||||
|
||||
func trimByLength(value string, character int) string {
|
||||
if len(value) > character {
|
||||
return value[0:character]
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
|
|
@ -65,3 +65,10 @@ func UpdateStatus(client versioned.Interface, urLister kyvernov1beta1listers.Upd
|
|||
}
|
||||
return ur, err
|
||||
}
|
||||
|
||||
func PolicyKey(namespace, name string) string {
|
||||
if namespace != "" {
|
||||
return namespace + "/" + name
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
|
|
@ -128,7 +128,6 @@ func (c *GenerateController) ProcessUR(ur *kyvernov1beta1.UpdateRequest) error {
|
|||
// 2 - Apply the generate policy on the resource
|
||||
namespaceLabels := engineutils.GetNamespaceSelectorsFromNamespaceLister(resource.GetKind(), resource.GetNamespace(), c.nsLister, logger)
|
||||
genResources, precreatedResource, err = c.applyGenerate(*resource, *ur, namespaceLabels)
|
||||
|
||||
if err != nil {
|
||||
// Need not update the status when policy doesn't apply on resource, because all the update requests are removed by the cleanup controller
|
||||
if strings.Contains(err.Error(), doesNotApply) {
|
||||
|
@ -166,7 +165,7 @@ func (c *GenerateController) applyGenerate(resource unstructured.Unstructured, u
|
|||
return nil, false, err
|
||||
}
|
||||
|
||||
policyContext, precreatedResource, err := common.NewBackgroundContext(c.client, &ur, &policy, &resource, c.configuration, namespaceLabels, logger)
|
||||
policyContext, precreatedResource, err := common.NewBackgroundContext(c.client, &ur, policy, &resource, c.configuration, namespaceLabels, logger)
|
||||
if err != nil {
|
||||
return nil, precreatedResource, err
|
||||
}
|
||||
|
@ -236,31 +235,24 @@ func (c *GenerateController) cleanupClonedResource(targetSpec kyvernov1.Resource
|
|||
}
|
||||
|
||||
// getPolicySpec gets the policy spec from the ClusterPolicy/Policy
|
||||
func (c *GenerateController) getPolicySpec(ur kyvernov1beta1.UpdateRequest) (kyvernov1.ClusterPolicy, error) {
|
||||
var policy kyvernov1.ClusterPolicy
|
||||
|
||||
func (c *GenerateController) getPolicySpec(ur kyvernov1beta1.UpdateRequest) (kyvernov1.PolicyInterface, error) {
|
||||
pNamespace, pName, err := cache.SplitMetaNamespaceKey(ur.Spec.Policy)
|
||||
if err != nil {
|
||||
return policy, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if pNamespace == "" {
|
||||
policyObj, err := c.policyLister.Get(pName)
|
||||
if err != nil {
|
||||
return policy, err
|
||||
return nil, err
|
||||
}
|
||||
return *policyObj, err
|
||||
return policyObj, err
|
||||
}
|
||||
npolicyObj, err := c.npolicyLister.Policies(pNamespace).Get(pName)
|
||||
if err != nil {
|
||||
return policy, err
|
||||
return nil, err
|
||||
}
|
||||
return kyvernov1.ClusterPolicy{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: pName,
|
||||
},
|
||||
Spec: npolicyObj.Spec,
|
||||
}, nil
|
||||
return npolicyObj, nil
|
||||
}
|
||||
|
||||
func updateStatus(statusControl common.StatusControlInterface, ur kyvernov1beta1.UpdateRequest, err error, genResources []kyvernov1.ResourceSpec, precreatedResource bool) error {
|
||||
|
@ -328,6 +320,12 @@ func (c *GenerateController) ApplyGeneratePolicy(log logr.Logger, policyContext
|
|||
return nil, processExisting, err
|
||||
}
|
||||
|
||||
if ur.Spec.DeleteDownstream {
|
||||
pKey := common.PolicyKey(policy.GetNamespace(), policy.GetName())
|
||||
err = c.deleteResource(pKey, rule, ur)
|
||||
return nil, false, err
|
||||
}
|
||||
|
||||
if policy.GetSpec().IsGenerateExistingOnPolicyUpdate() || !processExisting {
|
||||
genResource, err = applyRule(log, c.client, rule, resource, jsonContext, policy, ur)
|
||||
if err != nil {
|
||||
|
@ -400,7 +398,7 @@ func applyRule(log logr.Logger, client dclient.Interface, rule kyvernov1.Rule, r
|
|||
logger := log.WithValues("genKind", genKind, "genAPIVersion", genAPIVersion, "genNamespace", genNamespace, "genName", genName)
|
||||
|
||||
if rule.Generation.Clone.Name != "" {
|
||||
cresp, mode, err = manageClone(logger, genAPIVersion, genKind, genNamespace, genName, policy.GetName(), ur, rule.Generation, client)
|
||||
cresp, mode, err = manageClone(logger, genAPIVersion, genKind, genNamespace, genName, policy, ur, rule, client)
|
||||
rdatas = append(rdatas, GenerateResponse{
|
||||
Data: cresp,
|
||||
Action: mode,
|
||||
|
@ -411,7 +409,7 @@ func applyRule(log logr.Logger, client dclient.Interface, rule kyvernov1.Rule, r
|
|||
Error: err,
|
||||
})
|
||||
} else if len(rule.Generation.CloneList.Kinds) != 0 {
|
||||
rdatas = manageCloneList(logger, genNamespace, policy.GetName(), ur, rule.Generation, client)
|
||||
rdatas = manageCloneList(logger, genNamespace, ur, policy, rule, client)
|
||||
} else {
|
||||
dresp, mode, err = manageData(logger, genAPIVersion, genKind, genNamespace, genName, rule.Generation.RawData, rule.Generation.Synchronize, ur, client)
|
||||
rdatas = append(rdatas, GenerateResponse{
|
||||
|
@ -455,7 +453,7 @@ func applyRule(log logr.Logger, client dclient.Interface, rule kyvernov1.Rule, r
|
|||
}
|
||||
|
||||
newResource.SetAPIVersion(rdata.GenAPIVersion)
|
||||
common.ManageLabels(newResource, resource)
|
||||
common.ManageLabels(newResource, resource, policy, rule.Name)
|
||||
// Add Synchronize label
|
||||
label := newResource.GetLabels()
|
||||
|
||||
|
@ -590,7 +588,8 @@ func manageData(log logr.Logger, apiVersion, kind, namespace, name string, data
|
|||
return updateObj.UnstructuredContent(), Update, nil
|
||||
}
|
||||
|
||||
func manageClone(log logr.Logger, apiVersion, kind, namespace, name, policy string, ur kyvernov1beta1.UpdateRequest, clone kyvernov1.Generation, client dclient.Interface) (map[string]interface{}, ResourceMode, error) {
|
||||
func manageClone(log logr.Logger, apiVersion, kind, namespace, name string, policy kyvernov1.PolicyInterface, ur kyvernov1beta1.UpdateRequest, rule kyvernov1.Rule, client dclient.Interface) (map[string]interface{}, ResourceMode, error) {
|
||||
clone := rule.Generation
|
||||
// resource namespace can be nil in case of clusters scope resource
|
||||
rNamespace := clone.Clone.Namespace
|
||||
if rNamespace == "" {
|
||||
|
@ -613,6 +612,10 @@ func manageClone(log logr.Logger, apiVersion, kind, namespace, name, policy stri
|
|||
return nil, Skip, fmt.Errorf("source resource %s %s/%s/%s not found. %v", apiVersion, kind, rNamespace, rName, err)
|
||||
}
|
||||
|
||||
if err := updateSourceLabel(client, obj, ur.Spec.Resource, policy, rule); err != nil {
|
||||
log.Error(err, "failed to add labels to the source", "kind", obj.GetKind(), "namespace", obj.GetNamespace(), "name", obj.GetName())
|
||||
}
|
||||
|
||||
// check if cloned resource exists
|
||||
cobj, err := client.GetResource(context.TODO(), apiVersion, kind, namespace, name)
|
||||
if err != nil {
|
||||
|
@ -645,9 +648,9 @@ func manageClone(log logr.Logger, apiVersion, kind, namespace, name, policy stri
|
|||
return obj.UnstructuredContent(), Create, nil
|
||||
}
|
||||
|
||||
func manageCloneList(log logr.Logger, namespace, policy string, ur kyvernov1beta1.UpdateRequest, clone kyvernov1.Generation, client dclient.Interface) []GenerateResponse {
|
||||
func manageCloneList(log logr.Logger, namespace string, ur kyvernov1beta1.UpdateRequest, policy kyvernov1.PolicyInterface, rule kyvernov1.Rule, client dclient.Interface) []GenerateResponse {
|
||||
var response []GenerateResponse
|
||||
|
||||
clone := rule.Generation
|
||||
rNamespace := clone.CloneList.Namespace
|
||||
if rNamespace == "" {
|
||||
log.V(4).Info("resource namespace %s , optional in case of cluster scope resource", rNamespace)
|
||||
|
@ -686,7 +689,7 @@ func manageCloneList(log logr.Logger, namespace, policy string, ur kyvernov1beta
|
|||
// check if the resource as reference in clone exists?
|
||||
obj, err := client.GetResource(context.TODO(), apiVersion, kind, rNamespace, rName.GetName())
|
||||
if err != nil {
|
||||
log.Error(err, "failed to get resoruce", apiVersion, "apiVersion", kind, "kind", rNamespace, "rNamespace", rName.GetName(), "name")
|
||||
log.Error(err, "failed to get resource", apiVersion, "apiVersion", kind, "kind", rNamespace, "rNamespace", rName.GetName(), "name")
|
||||
response = append(response, GenerateResponse{
|
||||
Data: nil,
|
||||
Action: Skip,
|
||||
|
@ -695,6 +698,10 @@ func manageCloneList(log logr.Logger, namespace, policy string, ur kyvernov1beta
|
|||
return response
|
||||
}
|
||||
|
||||
if err := updateSourceLabel(client, obj, ur.Spec.Resource, policy, rule); err != nil {
|
||||
log.Error(err, "failed to add labels to the source", "kind", obj.GetKind(), "namespace", obj.GetNamespace(), "name", obj.GetName())
|
||||
}
|
||||
|
||||
// check if cloned resource exists
|
||||
cobj, err := client.GetResource(context.TODO(), apiVersion, kind, namespace, rName.GetName())
|
||||
if apierrors.IsNotFound(err) && len(ur.Status.GeneratedResources) != 0 && !clone.Synchronize {
|
||||
|
@ -811,3 +818,15 @@ func (c *GenerateController) GetUnstrResource(genResourceSpec kyvernov1.Resource
|
|||
}
|
||||
return resource, nil
|
||||
}
|
||||
|
||||
func (c *GenerateController) deleteResource(policyKey string, rule kyvernov1.Rule, ur kyvernov1beta1.UpdateRequest) error {
|
||||
if policyKey != ur.Spec.Policy {
|
||||
return nil
|
||||
}
|
||||
|
||||
if rule.Name == ur.Spec.Rule {
|
||||
return c.client.DeleteResource(context.TODO(), rule.Generation.GetAPIVersion(), rule.Generation.GetKind(), rule.Generation.GetNamespace(), rule.Generation.GetName(), false)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
24
pkg/background/generate/source.go
Normal file
24
pkg/background/generate/source.go
Normal file
|
@ -0,0 +1,24 @@
|
|||
package generate
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/background/common"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
func updateSourceLabel(client dclient.Interface, source *unstructured.Unstructured, trigger kyvernov1.ResourceSpec, policy kyvernov1.PolicyInterface, rule kyvernov1.Rule) error {
|
||||
labels := source.GetLabels()
|
||||
if labels == nil {
|
||||
labels = make(map[string]string)
|
||||
}
|
||||
|
||||
common.PolicyInfo(labels, policy, rule.Name)
|
||||
common.TriggerInfo(labels, trigger)
|
||||
|
||||
source.SetLabels(labels)
|
||||
_, err := client.UpdateResource(context.TODO(), source.GetAPIVersion(), source.GetKind(), source.GetNamespace(), source, false)
|
||||
return err
|
||||
}
|
|
@ -4,7 +4,9 @@ import (
|
|||
"fmt"
|
||||
"strconv"
|
||||
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
|
||||
"github.com/kyverno/kyverno/pkg/background/common"
|
||||
)
|
||||
|
||||
func increaseRetryAnnotation(ur *kyvernov1beta1.UpdateRequest) (int, map[string]string, error) {
|
||||
|
@ -32,3 +34,12 @@ func increaseRetryAnnotation(ur *kyvernov1beta1.UpdateRequest) (int, map[string]
|
|||
|
||||
return retry, urAnnotations, nil
|
||||
}
|
||||
|
||||
func TriggerFromLabels(labels map[string]string) kyvernov1.ResourceSpec {
|
||||
return kyvernov1.ResourceSpec{
|
||||
Kind: labels[common.GenerateTriggerKindLabel],
|
||||
Namespace: labels[common.GenerateTriggerNSLabel],
|
||||
Name: labels[common.GenerateTriggerNameLabel],
|
||||
APIVersion: labels[common.GenerateTriggerAPIVersionLabel],
|
||||
}
|
||||
}
|
||||
|
|
101
pkg/policy/generate.go
Normal file
101
pkg/policy/generate.go
Normal file
|
@ -0,0 +1,101 @@
|
|||
package policy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
|
||||
"github.com/kyverno/kyverno/pkg/background/common"
|
||||
generateutils "github.com/kyverno/kyverno/pkg/background/generate"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
"go.uber.org/multierr"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
func (pc *PolicyController) handleGenerate(policyKey string, policy kyvernov1.PolicyInterface) error {
|
||||
var errors []error
|
||||
logger := pc.log.WithName("handleGenerate").WithName(policyKey)
|
||||
logger.Info("update URs on policy event")
|
||||
|
||||
generateURs := pc.listGenerateURs(policyKey, nil)
|
||||
updateUR(pc.kyvernoClient, pc.urLister.UpdateRequests(config.KyvernoNamespace()), policyKey, generateURs, pc.log.WithName("updateUR"))
|
||||
|
||||
for _, rule := range policy.GetSpec().Rules {
|
||||
if err := pc.createUR(policy, rule); err != nil {
|
||||
logger.Error(err, "failed to create UR on policy event")
|
||||
}
|
||||
|
||||
var ruleType kyvernov1beta1.RequestType
|
||||
if policy.GetSpec().IsGenerateExistingOnPolicyUpdate() {
|
||||
ruleType = kyvernov1beta1.Generate
|
||||
triggers := generateTriggers(pc.client, rule, pc.log)
|
||||
for _, trigger := range triggers {
|
||||
gurs := pc.listGenerateURs(policyKey, trigger)
|
||||
if gurs != nil {
|
||||
logger.V(4).Info("UR was created", "rule", rule.Name, "rule type", ruleType, "trigger", trigger.GetNamespace()+"/"+trigger.GetName())
|
||||
continue
|
||||
}
|
||||
|
||||
ur := newUR(policy, resourceSpecFromUnstructured(trigger), ruleType)
|
||||
skip, err := pc.handleUpdateRequest(ur, trigger, rule, policy)
|
||||
if err != nil {
|
||||
pc.log.Error(err, "failed to create new UR on policy update", "policy", policy.GetName(), "rule", rule.Name, "rule type", ruleType,
|
||||
"target", fmt.Sprintf("%s/%s/%s/%s", trigger.GetAPIVersion(), trigger.GetKind(), trigger.GetNamespace(), trigger.GetName()))
|
||||
errors = append(errors, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if skip {
|
||||
continue
|
||||
}
|
||||
|
||||
logger.V(4).Info("successfully created UR on policy update", "policy", policy.GetName(), "rule", rule.Name, "rule type", ruleType,
|
||||
"target", fmt.Sprintf("%s/%s/%s/%s", trigger.GetAPIVersion(), trigger.GetKind(), trigger.GetNamespace(), trigger.GetName()))
|
||||
}
|
||||
err := multierr.Combine(errors...)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pc *PolicyController) listGenerateURs(policyKey string, trigger *unstructured.Unstructured) []*kyvernov1beta1.UpdateRequest {
|
||||
generateURs, err := pc.urLister.List(labels.SelectorFromSet(common.GenerateLabelsSet(policyKey, trigger)))
|
||||
if err != nil {
|
||||
pc.log.Error(err, "failed to list update request for generate policy")
|
||||
}
|
||||
return generateURs
|
||||
}
|
||||
|
||||
func (pc *PolicyController) createUR(policy kyvernov1.PolicyInterface, rule kyvernov1.Rule) error {
|
||||
generate := rule.Generation
|
||||
if !generate.Synchronize {
|
||||
// no action for non-sync policy/rule
|
||||
return nil
|
||||
}
|
||||
|
||||
if generate.GetData() != nil {
|
||||
downstream, err := pc.client.GetResource(context.TODO(), generate.APIVersion, generate.Kind, generate.Namespace, generate.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
labels := downstream.GetLabels()
|
||||
trigger := generateutils.TriggerFromLabels(labels)
|
||||
ur := newUR(policy, trigger, kyvernov1beta1.Generate)
|
||||
created, err := pc.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).Create(context.TODO(), ur, metav1.CreateOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updated := created.DeepCopy()
|
||||
updated.Status.State = kyvernov1beta1.Pending
|
||||
_, err = pc.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).UpdateStatus(context.TODO(), updated, metav1.UpdateOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
58
pkg/policy/mutate.go
Normal file
58
pkg/policy/mutate.go
Normal file
|
@ -0,0 +1,58 @@
|
|||
package policy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
|
||||
backgroundcommon "github.com/kyverno/kyverno/pkg/background/common"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
func (pc *PolicyController) handleMutate(policyKey string, policy kyvernov1.PolicyInterface) error {
|
||||
logger := pc.log.WithName("handleMutate").WithName(policyKey)
|
||||
if !policy.GetSpec().MutateExistingOnPolicyUpdate {
|
||||
logger.V(4).Info("skip policy application on policy event", "policyKey", policyKey, "mutateExiting", policy.GetSpec().MutateExistingOnPolicyUpdate)
|
||||
return nil
|
||||
}
|
||||
|
||||
logger.Info("update URs on policy event")
|
||||
for _, rule := range policy.GetSpec().Rules {
|
||||
var ruleType kyvernov1beta1.RequestType
|
||||
if rule.IsMutateExisting() {
|
||||
ruleType = kyvernov1beta1.Mutate
|
||||
triggers := generateTriggers(pc.client, rule, pc.log)
|
||||
for _, trigger := range triggers {
|
||||
murs := pc.listMutateURs(policyKey, trigger)
|
||||
if murs != nil {
|
||||
logger.V(4).Info("UR was created", "rule", rule.Name, "rule type", ruleType, "trigger", trigger.GetNamespace()+trigger.GetName())
|
||||
continue
|
||||
}
|
||||
|
||||
logger.Info("creating new UR for mutate")
|
||||
ur := newUR(policy, resourceSpecFromUnstructured(trigger), ruleType)
|
||||
skip, err := pc.handleUpdateRequest(ur, trigger, rule, policy)
|
||||
if err != nil {
|
||||
pc.log.Error(err, "failed to create new UR on policy update", "policy", policy.GetName(), "rule", rule.Name, "rule type", ruleType,
|
||||
"target", fmt.Sprintf("%s/%s/%s/%s", trigger.GetAPIVersion(), trigger.GetKind(), trigger.GetNamespace(), trigger.GetName()))
|
||||
continue
|
||||
}
|
||||
if skip {
|
||||
continue
|
||||
}
|
||||
pc.log.V(2).Info("successfully created UR on policy update", "policy", policy.GetName(), "rule", rule.Name, "rule type", ruleType,
|
||||
"target", fmt.Sprintf("%s/%s/%s/%s", trigger.GetAPIVersion(), trigger.GetKind(), trigger.GetNamespace(), trigger.GetName()))
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pc *PolicyController) listMutateURs(policyKey string, trigger *unstructured.Unstructured) []*kyvernov1beta1.UpdateRequest {
|
||||
mutateURs, err := pc.urLister.List(labels.SelectorFromSet(backgroundcommon.MutateLabelsSet(policyKey, trigger)))
|
||||
if err != nil {
|
||||
pc.log.Error(err, "failed to list update request for mutate policy")
|
||||
}
|
||||
return mutateURs
|
||||
}
|
|
@ -26,7 +26,6 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/metrics"
|
||||
engineutils "github.com/kyverno/kyverno/pkg/utils/engine"
|
||||
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
||||
"go.uber.org/multierr"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
@ -160,45 +159,77 @@ func (pc *PolicyController) canBackgroundProcess(p kyvernov1.PolicyInterface) bo
|
|||
|
||||
func (pc *PolicyController) addPolicy(obj interface{}) {
|
||||
logger := pc.log
|
||||
p := obj.(*kyvernov1.ClusterPolicy)
|
||||
var p kyvernov1.PolicyInterface
|
||||
|
||||
logger.Info("policy created", "uid", p.UID, "kind", "ClusterPolicy", "name", p.Name)
|
||||
switch obj := obj.(type) {
|
||||
case *kyvernov1.ClusterPolicy:
|
||||
p = obj
|
||||
case *kyvernov1.Policy:
|
||||
p = obj
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
logger.Info("policy created", "uid", p.GetUID(), "kind", p.GetKind(), "namespace", p.GetNamespace(), "name", p.GetName())
|
||||
|
||||
if !pc.canBackgroundProcess(p) {
|
||||
return
|
||||
}
|
||||
|
||||
logger.V(4).Info("queuing policy for background processing", "name", p.Name)
|
||||
logger.V(4).Info("queuing policy for background processing", "name", p.GetName())
|
||||
pc.enqueuePolicy(p)
|
||||
}
|
||||
|
||||
func (pc *PolicyController) updatePolicy(old, cur interface{}) {
|
||||
logger := pc.log
|
||||
oldP := old.(*kyvernov1.ClusterPolicy)
|
||||
curP := cur.(*kyvernov1.ClusterPolicy)
|
||||
var oldP, curP kyvernov1.PolicyInterface
|
||||
|
||||
switch obj := old.(type) {
|
||||
case *kyvernov1.ClusterPolicy:
|
||||
oldP = obj
|
||||
case *kyvernov1.Policy:
|
||||
oldP = obj
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
switch obj := cur.(type) {
|
||||
case *kyvernov1.ClusterPolicy:
|
||||
curP = obj
|
||||
case *kyvernov1.Policy:
|
||||
curP = obj
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
if !pc.canBackgroundProcess(curP) {
|
||||
return
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(oldP.Spec, curP.Spec) {
|
||||
if reflect.DeepEqual(oldP.GetSpec(), curP.GetSpec()) {
|
||||
return
|
||||
}
|
||||
|
||||
logger.V(2).Info("updating policy", "name", oldP.Name)
|
||||
logger.V(2).Info("updating policy", "name", oldP.GetName())
|
||||
|
||||
pc.enqueuePolicy(curP)
|
||||
}
|
||||
|
||||
func (pc *PolicyController) deletePolicy(obj interface{}) {
|
||||
logger := pc.log
|
||||
p, ok := kubeutils.GetObjectWithTombstone(obj).(*kyvernov1.ClusterPolicy)
|
||||
if !ok {
|
||||
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:
|
||||
logger.Info("Failed to get deleted object", "obj", obj)
|
||||
return
|
||||
}
|
||||
|
||||
logger.Info("policy deleted", "uid", p.UID, "kind", "ClusterPolicy", "name", p.Name)
|
||||
logger.Info("policy deleted", "uid", p.GetUID(), "kind", p.GetKind(), "namespace", p.GetNamespace(), "name", p.GetName())
|
||||
|
||||
// do not clean up UR on generate clone (sync=true) policy deletion
|
||||
rules := autogen.ComputeRules(p)
|
||||
|
@ -211,60 +242,6 @@ func (pc *PolicyController) deletePolicy(obj interface{}) {
|
|||
pc.enqueuePolicy(p)
|
||||
}
|
||||
|
||||
func (pc *PolicyController) addNsPolicy(obj interface{}) {
|
||||
logger := pc.log
|
||||
p := obj.(*kyvernov1.Policy)
|
||||
|
||||
logger.Info("policy created", "uid", p.UID, "kind", "Policy", "name", p.Name, "namespaces", p.Namespace)
|
||||
|
||||
if !pc.canBackgroundProcess(p) {
|
||||
return
|
||||
}
|
||||
logger.V(4).Info("queuing policy for background processing", "namespace", p.GetNamespace(), "name", p.GetName())
|
||||
pc.enqueuePolicy(p)
|
||||
}
|
||||
|
||||
func (pc *PolicyController) updateNsPolicy(old, cur interface{}) {
|
||||
logger := pc.log
|
||||
oldP := old.(*kyvernov1.Policy)
|
||||
curP := cur.(*kyvernov1.Policy)
|
||||
|
||||
if !pc.canBackgroundProcess(curP) {
|
||||
return
|
||||
}
|
||||
|
||||
if reflect.DeepEqual(oldP.Spec, curP.Spec) {
|
||||
return
|
||||
}
|
||||
|
||||
logger.V(4).Info("updating namespace policy", "namespace", oldP.Namespace, "name", oldP.Name)
|
||||
|
||||
pc.enqueuePolicy(curP)
|
||||
}
|
||||
|
||||
func (pc *PolicyController) deleteNsPolicy(obj interface{}) {
|
||||
logger := pc.log
|
||||
p, ok := kubeutils.GetObjectWithTombstone(obj).(*kyvernov1.Policy)
|
||||
if !ok {
|
||||
logger.Info("Failed to get deleted object", "obj", obj)
|
||||
return
|
||||
}
|
||||
|
||||
logger.Info("policy deleted event", "uid", p.UID, "kind", "Policy", "policy_name", p.Name, "namespaces", p.Namespace)
|
||||
|
||||
pol := p
|
||||
|
||||
// do not clean up UR on generate clone (sync=true) policy deletion
|
||||
rules := autogen.ComputeRules(pol)
|
||||
for _, r := range rules {
|
||||
clone, sync := r.GetCloneSyncForGenerate()
|
||||
if clone && sync {
|
||||
return
|
||||
}
|
||||
}
|
||||
pc.enqueuePolicy(pol)
|
||||
}
|
||||
|
||||
func (pc *PolicyController) enqueuePolicy(policy kyvernov1.PolicyInterface) {
|
||||
logger := pc.log
|
||||
key, err := cache.MetaNamespaceKeyFunc(policy)
|
||||
|
@ -296,9 +273,9 @@ func (pc *PolicyController) Run(ctx context.Context, workers int) {
|
|||
})
|
||||
|
||||
_, _ = pc.npInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: pc.addNsPolicy,
|
||||
UpdateFunc: pc.updateNsPolicy,
|
||||
DeleteFunc: pc.deleteNsPolicy,
|
||||
AddFunc: pc.addPolicy,
|
||||
UpdateFunc: pc.updatePolicy,
|
||||
DeleteFunc: pc.deletePolicy,
|
||||
})
|
||||
|
||||
for i := 0; i < workers; i++ {
|
||||
|
@ -362,9 +339,14 @@ func (pc *PolicyController) syncPolicy(key string) error {
|
|||
}
|
||||
return err
|
||||
} else {
|
||||
err = pc.updateUR(key, policy)
|
||||
err = pc.handleMutate(key, policy)
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to updateUR on Policy update")
|
||||
logger.Error(err, "failed to updateUR on mutate policy update")
|
||||
}
|
||||
|
||||
err = pc.handleGenerate(key, policy)
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to updateUR on generate policy update")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -424,88 +406,6 @@ func (pc *PolicyController) requeuePolicies() {
|
|||
}
|
||||
}
|
||||
|
||||
func (pc *PolicyController) updateUR(policyKey string, policy kyvernov1.PolicyInterface) error {
|
||||
logger := pc.log.WithName("updateUR").WithName(policyKey)
|
||||
|
||||
if !policy.GetSpec().MutateExistingOnPolicyUpdate && !policy.GetSpec().IsGenerateExistingOnPolicyUpdate() {
|
||||
logger.V(4).Info("skip policy application on policy event", "policyKey", policyKey, "mutateExiting", policy.GetSpec().MutateExistingOnPolicyUpdate, "generateExisting", policy.GetSpec().IsGenerateExistingOnPolicyUpdate())
|
||||
return nil
|
||||
}
|
||||
|
||||
logger.Info("update URs on policy event")
|
||||
|
||||
var errors []error
|
||||
mutateURs := pc.listMutateURs(policyKey, nil)
|
||||
generateURs := pc.listGenerateURs(policyKey, nil)
|
||||
updateUR(pc.kyvernoClient, pc.urLister.UpdateRequests(config.KyvernoNamespace()), policyKey, append(mutateURs, generateURs...), pc.log.WithName("updateUR"))
|
||||
|
||||
for _, rule := range policy.GetSpec().Rules {
|
||||
var ruleType kyvernov1beta1.RequestType
|
||||
|
||||
if rule.IsMutateExisting() {
|
||||
ruleType = kyvernov1beta1.Mutate
|
||||
|
||||
triggers := generateTriggers(pc.client, rule, pc.log)
|
||||
for _, trigger := range triggers {
|
||||
murs := pc.listMutateURs(policyKey, trigger)
|
||||
|
||||
if murs != nil {
|
||||
logger.V(4).Info("UR was created", "rule", rule.Name, "rule type", ruleType, "trigger", trigger.GetNamespace()+trigger.GetName())
|
||||
continue
|
||||
}
|
||||
|
||||
logger.Info("creating new UR for mutate")
|
||||
ur := newUR(policy, trigger, ruleType)
|
||||
skip, err := pc.handleUpdateRequest(ur, trigger, rule, policy)
|
||||
if err != nil {
|
||||
pc.log.Error(err, "failed to create new UR on policy update", "policy", policy.GetName(), "rule", rule.Name, "rule type", ruleType,
|
||||
"target", fmt.Sprintf("%s/%s/%s/%s", trigger.GetAPIVersion(), trigger.GetKind(), trigger.GetNamespace(), trigger.GetName()))
|
||||
continue
|
||||
}
|
||||
if skip {
|
||||
continue
|
||||
}
|
||||
pc.log.V(2).Info("successfully created UR on policy update", "policy", policy.GetName(), "rule", rule.Name, "rule type", ruleType,
|
||||
"target", fmt.Sprintf("%s/%s/%s/%s", trigger.GetAPIVersion(), trigger.GetKind(), trigger.GetNamespace(), trigger.GetName()))
|
||||
}
|
||||
}
|
||||
|
||||
if policy.GetSpec().IsGenerateExistingOnPolicyUpdate() {
|
||||
ruleType = kyvernov1beta1.Generate
|
||||
triggers := generateTriggers(pc.client, rule, pc.log)
|
||||
for _, trigger := range triggers {
|
||||
gurs := pc.listGenerateURs(policyKey, trigger)
|
||||
|
||||
if gurs != nil {
|
||||
logger.V(4).Info("UR was created", "rule", rule.Name, "rule type", ruleType, "trigger", trigger.GetNamespace()+"/"+trigger.GetName())
|
||||
continue
|
||||
}
|
||||
|
||||
ur := newUR(policy, trigger, ruleType)
|
||||
skip, err := pc.handleUpdateRequest(ur, trigger, rule, policy)
|
||||
if err != nil {
|
||||
pc.log.Error(err, "failed to create new UR on policy update", "policy", policy.GetName(), "rule", rule.Name, "rule type", ruleType,
|
||||
"target", fmt.Sprintf("%s/%s/%s/%s", trigger.GetAPIVersion(), trigger.GetKind(), trigger.GetNamespace(), trigger.GetName()))
|
||||
errors = append(errors, err)
|
||||
continue
|
||||
}
|
||||
|
||||
if skip {
|
||||
continue
|
||||
}
|
||||
|
||||
pc.log.V(4).Info("successfully created UR on policy update", "policy", policy.GetName(), "rule", rule.Name, "rule type", ruleType,
|
||||
"target", fmt.Sprintf("%s/%s/%s/%s", trigger.GetAPIVersion(), trigger.GetKind(), trigger.GetNamespace(), trigger.GetName()))
|
||||
}
|
||||
|
||||
err := multierr.Combine(errors...)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (pc *PolicyController) handleUpdateRequest(ur *kyvernov1beta1.UpdateRequest, triggerResource *unstructured.Unstructured, rule kyvernov1.Rule, policy kyvernov1.PolicyInterface) (skip bool, err error) {
|
||||
namespaceLabels := engineutils.GetNamespaceSelectorsFromNamespaceLister(triggerResource.GetKind(), triggerResource.GetNamespace(), pc.nsLister, pc.log)
|
||||
policyContext, _, err := backgroundcommon.NewBackgroundContext(pc.client, ur, policy, triggerResource, pc.configHandler, namespaceLabels, pc.log)
|
||||
|
@ -533,22 +433,6 @@ func (pc *PolicyController) handleUpdateRequest(ur *kyvernov1beta1.UpdateRequest
|
|||
return false, err
|
||||
}
|
||||
|
||||
func (pc *PolicyController) listMutateURs(policyKey string, trigger *unstructured.Unstructured) []*kyvernov1beta1.UpdateRequest {
|
||||
mutateURs, err := pc.urLister.List(labels.SelectorFromSet(backgroundcommon.MutateLabelsSet(policyKey, trigger)))
|
||||
if err != nil {
|
||||
pc.log.Error(err, "failed to list update request for mutate policy")
|
||||
}
|
||||
return mutateURs
|
||||
}
|
||||
|
||||
func (pc *PolicyController) listGenerateURs(policyKey string, trigger *unstructured.Unstructured) []*kyvernov1beta1.UpdateRequest {
|
||||
generateURs, err := pc.urLister.List(labels.SelectorFromSet(backgroundcommon.GenerateLabelsSet(policyKey, trigger)))
|
||||
if err != nil {
|
||||
pc.log.Error(err, "failed to list update request for generate policy")
|
||||
}
|
||||
return generateURs
|
||||
}
|
||||
|
||||
func generateTriggers(client dclient.Interface, rule kyvernov1.Rule, log logr.Logger) []*unstructured.Unstructured {
|
||||
list := &unstructured.UnstructuredList{}
|
||||
|
||||
|
@ -590,3 +474,12 @@ func updateUR(kyvernoClient versioned.Interface, urLister kyvernov1beta1listers.
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func resourceSpecFromUnstructured(obj *unstructured.Unstructured) kyvernov1.ResourceSpec {
|
||||
return kyvernov1.ResourceSpec{
|
||||
APIVersion: obj.GetAPIVersion(),
|
||||
Kind: obj.GetKind(),
|
||||
Namespace: obj.GetNamespace(),
|
||||
Name: obj.GetName(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,11 +6,10 @@ import (
|
|||
common "github.com/kyverno/kyverno/pkg/background/common"
|
||||
"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"
|
||||
)
|
||||
|
||||
func newUR(policy kyvernov1.PolicyInterface, trigger *unstructured.Unstructured, ruleType kyvernov1beta1.RequestType) *kyvernov1beta1.UpdateRequest {
|
||||
func newUR(policy kyvernov1.PolicyInterface, trigger kyvernov1.ResourceSpec, ruleType kyvernov1beta1.RequestType) *kyvernov1beta1.UpdateRequest {
|
||||
var policyNameNamespaceKey string
|
||||
|
||||
if policy.IsNamespaced() {
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/background/generate"
|
||||
gen "github.com/kyverno/kyverno/pkg/background/generate"
|
||||
"github.com/kyverno/kyverno/pkg/client/clientset/versioned"
|
||||
kyvernov1listers "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1"
|
||||
kyvernov1beta1listers "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1beta1"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
|
@ -32,9 +33,8 @@ import (
|
|||
)
|
||||
|
||||
type GenerationHandler interface {
|
||||
// TODO: why do we need to expose that ?
|
||||
HandleUpdatesForGenerateRules(context.Context, *admissionv1.AdmissionRequest, []kyvernov1.PolicyInterface)
|
||||
Handle(context.Context, *admissionv1.AdmissionRequest, []kyvernov1.PolicyInterface, *engine.PolicyContext, time.Time)
|
||||
HandleNew(context.Context, *admissionv1.AdmissionRequest, []kyvernov1.PolicyInterface, *engine.PolicyContext)
|
||||
}
|
||||
|
||||
func NewGenerationHandler(
|
||||
|
@ -44,6 +44,8 @@ func NewGenerationHandler(
|
|||
kyvernoClient versioned.Interface,
|
||||
nsLister corev1listers.NamespaceLister,
|
||||
urLister kyvernov1beta1listers.UpdateRequestNamespaceLister,
|
||||
cpolLister kyvernov1listers.ClusterPolicyLister,
|
||||
polLister kyvernov1listers.PolicyLister,
|
||||
urGenerator webhookgenerate.Generator,
|
||||
urUpdater webhookutils.UpdateRequestUpdater,
|
||||
eventGen event.Interface,
|
||||
|
@ -56,6 +58,8 @@ func NewGenerationHandler(
|
|||
kyvernoClient: kyvernoClient,
|
||||
nsLister: nsLister,
|
||||
urLister: urLister,
|
||||
cpolLister: cpolLister,
|
||||
polLister: polLister,
|
||||
urGenerator: urGenerator,
|
||||
urUpdater: urUpdater,
|
||||
eventGen: eventGen,
|
||||
|
@ -70,6 +74,8 @@ type generationHandler struct {
|
|||
kyvernoClient versioned.Interface
|
||||
nsLister corev1listers.NamespaceLister
|
||||
urLister kyvernov1beta1listers.UpdateRequestNamespaceLister
|
||||
cpolLister kyvernov1listers.ClusterPolicyLister
|
||||
polLister kyvernov1listers.PolicyLister
|
||||
urGenerator webhookgenerate.Generator
|
||||
urUpdater webhookutils.UpdateRequestUpdater
|
||||
eventGen event.Interface
|
||||
|
@ -127,12 +133,12 @@ func (h *generationHandler) Handle(
|
|||
}
|
||||
|
||||
if request.Operation == admissionv1.Update {
|
||||
h.HandleUpdatesForGenerateRules(ctx, request, policies)
|
||||
h.handleUpdatesForGenerateRules(ctx, request, policies)
|
||||
}
|
||||
}
|
||||
|
||||
// HandleUpdatesForGenerateRules handles admission-requests for update
|
||||
func (h *generationHandler) HandleUpdatesForGenerateRules(ctx context.Context, request *admissionv1.AdmissionRequest, policies []kyvernov1.PolicyInterface) {
|
||||
// handleUpdatesForGenerateRules handles admission-requests for update
|
||||
func (h *generationHandler) handleUpdatesForGenerateRules(ctx context.Context, request *admissionv1.AdmissionRequest, policies []kyvernov1.PolicyInterface) {
|
||||
if request.Operation != admissionv1.Update {
|
||||
return
|
||||
}
|
||||
|
@ -200,7 +206,7 @@ func (h *generationHandler) handleUpdateGenerateTargetResource(ctx context.Conte
|
|||
if rule.Generation.Kind == targetSourceKind && rule.Generation.Name == targetSourceName {
|
||||
updatedRule, err := getGeneratedByResource(ctx, newRes, resLabels, h.client, rule, h.log)
|
||||
if err != nil {
|
||||
h.log.V(4).Info("skipping generate policy and resource pattern validaton", "error", err)
|
||||
h.log.V(4).Info("skipping generate policy and resource pattern validation", "error", err)
|
||||
} else {
|
||||
data := updatedRule.Generation.DeepCopy().GetData()
|
||||
if data != nil {
|
||||
|
|
156
pkg/webhooks/resource/generation/handler.go
Normal file
156
pkg/webhooks/resource/generation/handler.go
Normal file
|
@ -0,0 +1,156 @@
|
|||
package generation
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
|
||||
"github.com/kyverno/kyverno/pkg/background/common"
|
||||
generateutils "github.com/kyverno/kyverno/pkg/background/generate"
|
||||
"github.com/kyverno/kyverno/pkg/engine"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
"github.com/kyverno/kyverno/pkg/event"
|
||||
engineutils "github.com/kyverno/kyverno/pkg/utils/engine"
|
||||
webhookutils "github.com/kyverno/kyverno/pkg/webhooks/utils"
|
||||
admissionv1 "k8s.io/api/admission/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
func (h *generationHandler) HandleNew(
|
||||
ctx context.Context,
|
||||
request *admissionv1.AdmissionRequest,
|
||||
policies []kyvernov1.PolicyInterface,
|
||||
policyContext *engine.PolicyContext,
|
||||
) {
|
||||
h.log.V(6).Info("handle admission request for generate")
|
||||
if len(policies) != 0 {
|
||||
h.handleTrigger(ctx, request, policies, policyContext)
|
||||
}
|
||||
|
||||
h.handleNonTrigger(ctx, policyContext, request)
|
||||
}
|
||||
|
||||
func (h *generationHandler) handleTrigger(
|
||||
ctx context.Context,
|
||||
request *admissionv1.AdmissionRequest,
|
||||
policies []kyvernov1.PolicyInterface,
|
||||
policyContext *engine.PolicyContext,
|
||||
) {
|
||||
h.log.V(4).Info("handle trigger resource operation for generate")
|
||||
var engineResponses []*engineapi.EngineResponse
|
||||
for _, policy := range policies {
|
||||
var appliedRules []engineapi.RuleResponse
|
||||
policyContext := policyContext.WithPolicy(policy)
|
||||
if request.Kind.Kind != "Namespace" && request.Namespace != "" {
|
||||
policyContext = policyContext.WithNamespaceLabels(engineutils.GetNamespaceSelectorsFromNamespaceLister(request.Kind.Kind, request.Namespace, h.nsLister, h.log))
|
||||
}
|
||||
engineResponse := h.engine.ApplyBackgroundChecks(ctx, policyContext)
|
||||
for _, rule := range engineResponse.PolicyResponse.Rules {
|
||||
if rule.Status == engineapi.RuleStatusPass {
|
||||
appliedRules = append(appliedRules, rule)
|
||||
}
|
||||
}
|
||||
|
||||
if len(appliedRules) > 0 {
|
||||
engineResponse.PolicyResponse.Rules = appliedRules
|
||||
// some generate rules do apply to the resource
|
||||
engineResponses = append(engineResponses, engineResponse)
|
||||
}
|
||||
|
||||
// registering the kyverno_policy_results_total metric concurrently
|
||||
go webhookutils.RegisterPolicyResultsMetricGeneration(ctx, h.log, h.metrics, string(request.Operation), policy, *engineResponse)
|
||||
// registering the kyverno_policy_execution_duration_seconds metric concurrently
|
||||
go webhookutils.RegisterPolicyExecutionDurationMetricGenerate(ctx, h.log, h.metrics, string(request.Operation), policy, *engineResponse)
|
||||
}
|
||||
|
||||
if failedResponse := applyUpdateRequest(ctx, request, kyvernov1beta1.Generate, h.urGenerator, policyContext.AdmissionInfo(), request.Operation, engineResponses...); failedResponse != nil {
|
||||
// report failure event
|
||||
for _, failedUR := range failedResponse {
|
||||
err := fmt.Errorf("failed to create Update Request: %v", failedUR.err)
|
||||
newResource := policyContext.NewResource()
|
||||
e := event.NewBackgroundFailedEvent(err, failedUR.ur.Policy, "", event.GeneratePolicyController, &newResource)
|
||||
h.eventGen.Add(e...)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (h *generationHandler) handleNonTrigger(
|
||||
ctx context.Context,
|
||||
policyContext *engine.PolicyContext,
|
||||
request *admissionv1.AdmissionRequest,
|
||||
) {
|
||||
resource := policyContext.OldResource()
|
||||
labels := resource.GetLabels()
|
||||
if labels[common.GeneratePolicyLabel] != "" {
|
||||
h.log.V(4).Info("handle non-trigger resource operation for generate")
|
||||
if err := h.createUR(ctx, policyContext, request); err != nil {
|
||||
h.log.Error(err, "failed to create the UR on non-trigger admission request")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (h *generationHandler) createUR(ctx context.Context, policyContext *engine.PolicyContext, request *admissionv1.AdmissionRequest) (err error) {
|
||||
var policy kyvernov1.PolicyInterface
|
||||
new := policyContext.NewResource()
|
||||
labels := new.GetLabels()
|
||||
old := policyContext.OldResource()
|
||||
oldLabels := old.GetLabels()
|
||||
if !compareLabels(labels, oldLabels) {
|
||||
return fmt.Errorf("labels have been changed, new: %v, old: %v", labels, oldLabels)
|
||||
}
|
||||
|
||||
deleteDownstream := false
|
||||
if reflect.DeepEqual(new, unstructured.Unstructured{}) {
|
||||
deleteDownstream = true
|
||||
labels = oldLabels
|
||||
}
|
||||
pName := labels[common.GeneratePolicyLabel]
|
||||
pNamespace := labels[common.GeneratePolicyNamespaceLabel]
|
||||
pRuleName := labels[common.GenerateRuleLabel]
|
||||
|
||||
if pNamespace != "" {
|
||||
policy, err = h.polLister.Policies(pNamespace).Get(pName)
|
||||
} else {
|
||||
policy, err = h.cpolLister.Get(pName)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pKey := common.PolicyKey(pNamespace, pName)
|
||||
for _, rule := range policy.GetSpec().Rules {
|
||||
if rule.Name == pRuleName && rule.Generation.Synchronize {
|
||||
ur := kyvernov1beta1.UpdateRequestSpec{
|
||||
Type: kyvernov1beta1.Generate,
|
||||
Policy: pKey,
|
||||
Rule: rule.Name,
|
||||
Resource: generateutils.TriggerFromLabels(labels),
|
||||
}
|
||||
ur.DeleteDownstream = deleteDownstream
|
||||
if err := h.urGenerator.Apply(ctx, ur, admissionv1.Update); err != nil {
|
||||
e := event.NewBackgroundFailedEvent(err, pKey, pRuleName, event.GeneratePolicyController, &new)
|
||||
h.eventGen.Add(e...)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func compareLabels(new, old map[string]string) bool {
|
||||
if new == nil {
|
||||
return true
|
||||
}
|
||||
if new[common.GeneratePolicyLabel] != old[common.GeneratePolicyLabel] ||
|
||||
new[common.GeneratePolicyNamespaceLabel] != old[common.GeneratePolicyNamespaceLabel] ||
|
||||
new[common.GenerateRuleLabel] != old[common.GenerateRuleLabel] ||
|
||||
new[common.GenerateTriggerNameLabel] != old[common.GenerateTriggerNameLabel] ||
|
||||
new[common.GenerateTriggerNSLabel] != old[common.GenerateTriggerNSLabel] ||
|
||||
new[common.GenerateTriggerKindLabel] != old[common.GenerateTriggerKindLabel] {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
|
@ -121,7 +121,7 @@ func applyUpdateRequest(
|
|||
ctx context.Context,
|
||||
request *admissionv1.AdmissionRequest,
|
||||
ruleType kyvernov1beta1.RequestType,
|
||||
grGenerator updaterequest.Generator,
|
||||
urGenerator updaterequest.Generator,
|
||||
userRequestInfo kyvernov1beta1.RequestInfo,
|
||||
action admissionv1.Operation,
|
||||
engineResponses ...*engineapi.EngineResponse,
|
||||
|
@ -133,7 +133,7 @@ func applyUpdateRequest(
|
|||
|
||||
for _, er := range engineResponses {
|
||||
ur := transform(admissionRequestInfo, userRequestInfo, er, ruleType)
|
||||
if err := grGenerator.Apply(ctx, ur, action); err != nil {
|
||||
if err := urGenerator.Apply(ctx, ur, action); err != nil {
|
||||
failedUpdateRequest = append(failedUpdateRequest, updateRequestResponse{ur: ur, err: err})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ import (
|
|||
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
|
||||
"github.com/kyverno/kyverno/pkg/background/generate"
|
||||
"github.com/kyverno/kyverno/pkg/client/clientset/versioned"
|
||||
kyvernov1informers "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1"
|
||||
kyvernov1listers "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1"
|
||||
kyvernov1beta1listers "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1beta1"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
|
@ -25,7 +27,6 @@ import (
|
|||
jsonutils "github.com/kyverno/kyverno/pkg/utils/json"
|
||||
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
|
||||
"github.com/kyverno/kyverno/pkg/webhooks"
|
||||
"github.com/kyverno/kyverno/pkg/webhooks/resource/generation"
|
||||
"github.com/kyverno/kyverno/pkg/webhooks/resource/imageverification"
|
||||
"github.com/kyverno/kyverno/pkg/webhooks/resource/mutation"
|
||||
"github.com/kyverno/kyverno/pkg/webhooks/resource/validation"
|
||||
|
@ -51,8 +52,10 @@ type handlers struct {
|
|||
pCache policycache.Cache
|
||||
|
||||
// listers
|
||||
nsLister corev1listers.NamespaceLister
|
||||
urLister kyvernov1beta1listers.UpdateRequestNamespaceLister
|
||||
nsLister corev1listers.NamespaceLister
|
||||
urLister kyvernov1beta1listers.UpdateRequestNamespaceLister
|
||||
cpolLister kyvernov1listers.ClusterPolicyLister
|
||||
polLister kyvernov1listers.PolicyLister
|
||||
|
||||
urGenerator webhookgenerate.Generator
|
||||
eventGen event.Interface
|
||||
|
@ -75,6 +78,8 @@ func NewHandlers(
|
|||
rbLister rbacv1listers.RoleBindingLister,
|
||||
crbLister rbacv1listers.ClusterRoleBindingLister,
|
||||
urLister kyvernov1beta1listers.UpdateRequestNamespaceLister,
|
||||
cpolInformer kyvernov1informers.ClusterPolicyInformer,
|
||||
polInformer kyvernov1informers.PolicyInformer,
|
||||
urGenerator webhookgenerate.Generator,
|
||||
eventGen event.Interface,
|
||||
openApiManager openapi.ValidateInterface,
|
||||
|
@ -90,6 +95,8 @@ func NewHandlers(
|
|||
pCache: pCache,
|
||||
nsLister: nsLister,
|
||||
urLister: urLister,
|
||||
cpolLister: cpolInformer.Lister(),
|
||||
polLister: polInformer.Lister(),
|
||||
urGenerator: urGenerator,
|
||||
eventGen: eventGen,
|
||||
openApiManager: openApiManager,
|
||||
|
@ -114,11 +121,6 @@ func (h *handlers) Validate(ctx context.Context, logger logr.Logger, request *ad
|
|||
if len(policies) == 0 && len(mutatePolicies) == 0 && len(generatePolicies) == 0 {
|
||||
logger.V(4).Info("no policies matched admission request")
|
||||
}
|
||||
if len(generatePolicies) == 0 && request.Operation == admissionv1.Update {
|
||||
// handle generate source resource updates
|
||||
gh := generation.NewGenerationHandler(logger, h.engine, h.client, h.kyvernoClient, h.nsLister, h.urLister, h.urGenerator, h.urUpdater, h.eventGen, h.metricsConfig)
|
||||
go gh.HandleUpdatesForGenerateRules(context.TODO(), request, []kyvernov1.PolicyInterface{})
|
||||
}
|
||||
|
||||
logger.V(4).Info("processing policies for validate admission request", "validate", len(policies), "mutate", len(mutatePolicies), "generate", len(generatePolicies))
|
||||
|
||||
|
@ -141,7 +143,7 @@ func (h *handlers) Validate(ctx context.Context, logger logr.Logger, request *ad
|
|||
}
|
||||
|
||||
defer h.handleDelete(logger, request)
|
||||
go h.createUpdateRequests(logger, request, policyContext, generatePolicies, mutatePolicies, startTime)
|
||||
go h.handleBackgroundApplies(ctx, logger, request, policyContext, generatePolicies, mutatePolicies, startTime)
|
||||
|
||||
return admissionutils.ResponseSuccess(request.UID, warnings...)
|
||||
}
|
||||
|
|
|
@ -16,11 +16,10 @@ import (
|
|||
admissionv1 "k8s.io/api/admission/v1"
|
||||
)
|
||||
|
||||
// createUpdateRequests applies generate and mutateExisting policies, and creates update requests for background reconcile
|
||||
func (h *handlers) createUpdateRequests(logger logr.Logger, request *admissionv1.AdmissionRequest, policyContext *engine.PolicyContext, generatePolicies, mutatePolicies []kyvernov1.PolicyInterface, ts time.Time) {
|
||||
gh := generation.NewGenerationHandler(logger, h.engine, h.client, h.kyvernoClient, h.nsLister, h.urLister, h.urGenerator, h.urUpdater, h.eventGen, h.metricsConfig)
|
||||
go h.handleMutateExisting(context.TODO(), logger, request, mutatePolicies, policyContext, ts)
|
||||
go gh.Handle(context.TODO(), request, generatePolicies, policyContext, ts)
|
||||
// handleBackgroundApplies applies generate and mutateExisting policies, and creates update requests for background reconcile
|
||||
func (h *handlers) handleBackgroundApplies(ctx context.Context, logger logr.Logger, request *admissionv1.AdmissionRequest, policyContext *engine.PolicyContext, generatePolicies, mutatePolicies []kyvernov1.PolicyInterface, ts time.Time) {
|
||||
go h.handleMutateExisting(ctx, logger, request, mutatePolicies, policyContext, ts)
|
||||
h.handleGenerate(ctx, logger, request, generatePolicies, policyContext, ts)
|
||||
}
|
||||
|
||||
func (h *handlers) handleMutateExisting(ctx context.Context, logger logr.Logger, request *admissionv1.AdmissionRequest, policies []kyvernov1.PolicyInterface, policyContext *engine.PolicyContext, admissionRequestTimestamp time.Time) {
|
||||
|
@ -71,3 +70,10 @@ func (h *handlers) handleMutateExisting(ctx context.Context, logger logr.Logger,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (h *handlers) handleGenerate(ctx context.Context, logger logr.Logger, request *admissionv1.AdmissionRequest, generatePolicies []kyvernov1.PolicyInterface, policyContext *engine.PolicyContext, ts time.Time) {
|
||||
gh := generation.NewGenerationHandler(logger, h.engine, h.client, h.kyvernoClient, h.nsLister, h.urLister, h.cpolLister, h.polLister, h.urGenerator, h.urUpdater, h.eventGen, h.metricsConfig)
|
||||
// TODO(shuting): clean up old code
|
||||
// go gh.Handle(ctx, request, generatePolicies, policyContext, ts)
|
||||
go gh.HandleNew(ctx, request, generatePolicies, policyContext)
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ func NewGenerator(client versioned.Interface, urInformer kyvernov1beta1informers
|
|||
|
||||
// Apply creates update request resource
|
||||
func (g *generator) Apply(ctx context.Context, ur kyvernov1beta1.UpdateRequestSpec, action admissionv1.Operation) error {
|
||||
logger.V(4).Info("reconcile Update Request", "request", ur)
|
||||
logger.V(4).Info("apply Update Request", "request", ur)
|
||||
if action == admissionv1.Delete && ur.GetRequestType() == kyvernov1beta1.Generate {
|
||||
return nil
|
||||
}
|
||||
|
@ -72,6 +72,7 @@ func (g *generator) tryApplyResource(ctx context.Context, urSpec kyvernov1beta1.
|
|||
} else if urSpec.GetRequestType() == kyvernov1beta1.Generate {
|
||||
queryLabels = common.GenerateLabelsSet(urSpec.Policy, urSpec.GetResource())
|
||||
}
|
||||
|
||||
urList, err := g.urLister.List(labels.SelectorFromSet(queryLabels))
|
||||
if err != nil {
|
||||
l.Error(err, "failed to get update request for the resource", "resource", urSpec.GetResource().String())
|
||||
|
@ -93,7 +94,8 @@ func (g *generator) tryApplyResource(ctx context.Context, urSpec kyvernov1beta1.
|
|||
return err
|
||||
}
|
||||
}
|
||||
if len(urList) == 0 {
|
||||
|
||||
if len(urList) == 0 || urSpec.DeleteDownstream {
|
||||
l.V(4).Info("creating new UpdateRequest")
|
||||
ur := kyvernov1beta1.UpdateRequest{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
## Description
|
||||
|
||||
This test ensures that deletion of the source (upstream) resource used by a ClusterPolicy `generate` rule with sync enabled using a clone declaration does NOT cause deletion of downstream/cloned resources.
|
||||
This test ensures that deletion of the source (upstream) resource used by a ClusterPolicy `generate` rule with sync enabled using a clone declaration DOES cause deletion of downstream/cloned resources.
|
||||
|
||||
## Expected Behavior
|
||||
|
||||
After the source is deleted, the downstream resources should remain. If the downstream resource remains, the test passes. If the downstream resource is deleted, the test fails.
|
||||
After the source is deleted, the downstream resources should be deleted. If the downstream resource remains, the test fails. If the downstream resource is deleted, the test passes.
|
||||
|
||||
## Reference Issue(s)
|
||||
|
||||
N/A
|
||||
https://github.com/kyverno/kyverno/issues/6266
|
Loading…
Add table
Reference in a new issue