1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-28 02:18:15 +00:00

fix: delete downstream for a generate rule removal, with data and sync (#6393)

* remove policy handler for updates

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* remove policy update handler from the ur controller

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* rework cleanup downstream on policy deletion

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix downstream deletion on data rule removal

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* add kuttl test for clusterpolicy

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* linter fix

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* add kuttl test for policy

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* update api docs

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* add delays

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix name assertion

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* delete downstream when deletes the clone source

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* add kuttl test pol-clone-sync-delete-source

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* linter fixes

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* add kuttl test pol-clone-sync-delete-downstream

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* add kuttl test pol-data-sync-modify-rule

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix panic

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix panic

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix labels

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix policy assertions

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix annotation missing names

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* rename policy

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* remove dead code

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* create unique namespaces

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* create more unique namespaces

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* fix assertion

Signed-off-by: ShutingZhao <shuting@nirmata.com>

---------

Signed-off-by: ShutingZhao <shuting@nirmata.com>
Co-authored-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>
This commit is contained in:
shuting 2023-03-01 11:48:18 +08:00 committed by GitHub
parent 8299e03279
commit 0c91e87bbb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
106 changed files with 980 additions and 385 deletions

View file

@ -568,6 +568,20 @@ func (g *Generation) SetData(in apiextensions.JSON) {
g.RawData = ToJSON(in)
}
type GenerateType string
const (
Data GenerateType = "Data"
Clone GenerateType = "Clone"
)
func (g *Generation) GetTypeAndSync() (GenerateType, bool) {
if g.RawData != nil {
return Data, g.Synchronize
}
return Clone, g.Synchronize
}
// CloneFrom provides the location of the source resource used to generate target resources.
// The resource kind is derived from the match criteria.
type CloneFrom struct {

View file

@ -150,18 +150,11 @@ func (r *Rule) IsPodSecurity() bool {
return r.Validation.PodSecurity != nil
}
// IsCloneSyncGenerate checks if the generate rule has the clone block with sync=true
func (r *Rule) GetCloneSyncForGenerate() (clone bool, sync bool) {
func (r *Rule) GetGenerateTypeAndSync() (_ GenerateType, sync bool) {
if !r.HasGenerate() {
return
}
if r.Generation.Clone.Name != "" {
clone = true
}
sync = r.Generation.Synchronize
return
return r.Generation.GetTypeAndSync()
}
func (r *Rule) GetAnyAllConditions() apiextensions.JSON {

View file

@ -1530,6 +1530,10 @@ Kubernetes apiextensions/v1.JSON
</tbody>
</table>
<hr />
<h3 id="kyverno.io/v1.GenerateType">GenerateType
(<code>string</code> alias)</p></h3>
<p>
</p>
<h3 id="kyverno.io/v1.Generation">Generation
</h3>
<p>

View file

@ -10,6 +10,7 @@ import (
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/logging"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/client-go/util/retry"
)
@ -72,3 +73,12 @@ func PolicyKey(namespace, name string) string {
}
return name
}
func ResourceSpecFromUnstructured(obj unstructured.Unstructured) kyvernov1.ResourceSpec {
return kyvernov1.ResourceSpec{
APIVersion: obj.GetAPIVersion(),
Kind: obj.GetKind(),
Namespace: obj.GetNamespace(),
Name: obj.GetName(),
}
}

View file

@ -0,0 +1,83 @@
package generate
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"
"go.uber.org/multierr"
apierrors "k8s.io/apimachinery/pkg/api/errors"
)
func (c *GenerateController) deleteDownstream(policy kyvernov1.PolicyInterface, ur *kyvernov1beta1.UpdateRequest) (err error) {
if !ur.Spec.DeleteDownstream {
return nil
}
// handle data policy/rule deletion
if ur.Status.GeneratedResources != nil {
c.log.V(4).Info("policy/rule no longer exists, deleting the downstream resource based on synchronize", "ur", ur.Name, "policy", ur.Spec.Policy, "rule", ur.Spec.Rule)
var errs []error
failedDownstreams := []kyvernov1.ResourceSpec{}
for _, e := range ur.Status.GeneratedResources {
if err := c.client.DeleteResource(context.TODO(), e.GetAPIVersion(), e.GetKind(), e.GetNamespace(), e.GetName(), false); err != nil && !apierrors.IsNotFound(err) {
failedDownstreams = append(failedDownstreams, e)
errs = append(errs, err)
}
}
if len(errs) != 0 {
c.log.Error(multierr.Combine(errs...), "failed to clean up downstream resources on policy deletion")
_, err = c.statusControl.Failed(ur.GetName(),
fmt.Sprintf("failed to clean up downstream resources on policy deletion: %v", multierr.Combine(errs...)),
failedDownstreams)
} else {
_, err = c.statusControl.Success(ur.GetName(), nil)
}
return
}
if policy == nil {
return nil
}
// handle clone source deletion
return c.deleteDownstreamForClone(policy, ur)
}
func (c *GenerateController) deleteDownstreamForClone(policy kyvernov1.PolicyInterface, ur *kyvernov1beta1.UpdateRequest) error {
if !ur.Spec.DeleteDownstream {
return nil
}
for _, rule := range policy.GetSpec().Rules {
if ur.Spec.Rule != rule.Name {
continue
}
downstreams, err := FindDownstream(c.client, policy, rule)
if err != nil {
return err
}
var errs []error
failedDownstreams := []kyvernov1.ResourceSpec{}
for _, downstream := range downstreams.Items {
if err := c.client.DeleteResource(context.TODO(), downstream.GetAPIVersion(), downstream.GetKind(), downstream.GetNamespace(), downstream.GetName(), false); err != nil && !apierrors.IsNotFound(err) {
failedDownstreams = append(failedDownstreams, common.ResourceSpecFromUnstructured(downstream))
errs = append(errs, err)
}
}
if len(errs) != 0 {
c.log.Error(multierr.Combine(errs...), "failed to clean up downstream resources on source deletion")
_, err = c.statusControl.Failed(ur.GetName(),
fmt.Sprintf("failed to clean up downstream resources on source deletion: %v", multierr.Combine(errs...)),
failedDownstreams)
} else {
_, err = c.statusControl.Success(ur.GetName(), nil)
}
return err
}
return nil
}

View file

@ -151,20 +151,16 @@ func (c *GenerateController) applyGenerate(resource unstructured.Unstructured, u
logger.V(3).Info("applying generate policy rule")
policy, err := c.getPolicySpec(ur)
if err != nil {
if apierrors.IsNotFound(err) {
for _, e := range ur.Status.GeneratedResources {
if err := c.cleanupClonedResource(e); err != nil {
logger.Error(err, "failed to clean up cloned resource on policy deletion")
}
}
return nil, false, nil
}
if err != nil && !apierrors.IsNotFound(err) {
logger.Error(err, "error in fetching policy")
return nil, false, err
}
if ur.Spec.DeleteDownstream || apierrors.IsNotFound(err) {
err = c.deleteDownstream(policy, &ur)
return nil, false, err
}
policyContext, precreatedResource, err := common.NewBackgroundContext(c.client, &ur, policy, &resource, c.configuration, namespaceLabels, logger)
if err != nil {
return nil, precreatedResource, err
@ -209,31 +205,6 @@ func (c *GenerateController) applyGenerate(resource unstructured.Unstructured, u
return c.ApplyGeneratePolicy(logger, policyContext, ur, applicableRules)
}
// cleanupClonedResource deletes cloned resource if sync is not enabled for the clone policy
func (c *GenerateController) cleanupClonedResource(targetSpec kyvernov1.ResourceSpec) error {
target, err := c.client.GetResource(context.TODO(), targetSpec.APIVersion, targetSpec.Kind, targetSpec.Namespace, targetSpec.Name)
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()
syncEnabled := labels[LabelSynchronize] == "enable"
clone := labels[LabelClonePolicyName] != ""
if syncEnabled && !clone {
if err := c.client.DeleteResource(context.TODO(), target.GetAPIVersion(), target.GetKind(), target.GetNamespace(), target.GetName(), false); err != nil {
return fmt.Errorf("cloned resource is not deleted %s/%s: %v", targetSpec.Namespace, targetSpec.Name, err)
}
}
return nil
}
// getPolicySpec gets the policy spec from the ClusterPolicy/Policy
func (c *GenerateController) getPolicySpec(ur kyvernov1beta1.UpdateRequest) (kyvernov1.PolicyInterface, error) {
pNamespace, pName, err := cache.SplitMetaNamespaceKey(ur.Spec.Policy)
@ -320,12 +291,6 @@ 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 {
@ -818,15 +783,3 @@ 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
}

View file

@ -1,19 +1,23 @@
package generate
import (
"context"
"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"
"github.com/kyverno/kyverno/pkg/clients/dclient"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
func increaseRetryAnnotation(ur *kyvernov1beta1.UpdateRequest) (int, map[string]string, error) {
urAnnotations := ur.Annotations
if len(urAnnotations) == 0 {
urAnnotations = map[string]string{
urAnnotations[kyvernov1beta1.URGenerateRetryCountAnnotation]: "1",
kyvernov1beta1.URGenerateRetryCountAnnotation: "1",
}
}
@ -43,3 +47,14 @@ func TriggerFromLabels(labels map[string]string) kyvernov1.ResourceSpec {
APIVersion: labels[common.GenerateTriggerAPIVersionLabel],
}
}
func FindDownstream(client dclient.Interface, policy kyvernov1.PolicyInterface, rule kyvernov1.Rule) (*unstructured.UnstructuredList, error) {
generation := rule.Generation
selector := &metav1.LabelSelector{MatchLabels: map[string]string{
common.GeneratePolicyLabel: policy.GetName(),
common.GeneratePolicyNamespaceLabel: policy.GetNamespace(),
common.GenerateRuleLabel: rule.Name,
}}
return client.ListResource(context.TODO(), generation.GetAPIVersion(), generation.GetKind(), "", selector)
}

21
pkg/background/mutate.go Normal file
View file

@ -0,0 +1,21 @@
package background
import (
"context"
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
common "github.com/kyverno/kyverno/pkg/background/common"
"github.com/kyverno/kyverno/pkg/config"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func (c *controller) handleMutatePolicyAbsence(ur *kyvernov1beta1.UpdateRequest) error {
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)},
)
}

View file

@ -3,7 +3,6 @@ package background
import (
"context"
"fmt"
"strings"
"time"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
@ -20,10 +19,8 @@ import (
"github.com/kyverno/kyverno/pkg/config"
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
"github.com/kyverno/kyverno/pkg/event"
kubeutils "github.com/kyverno/kyverno/pkg/utils/kube"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/wait"
corev1informers "k8s.io/client-go/informers/core/v1"
@ -96,14 +93,6 @@ func NewController(
UpdateFunc: c.updateUR,
DeleteFunc: c.deleteUR,
})
_, _ = cpolInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
UpdateFunc: c.updatePolicy,
DeleteFunc: c.deletePolicy,
})
_, _ = polInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{
UpdateFunc: c.updatePolicy,
DeleteFunc: c.deletePolicy,
})
c.informersSynced = []cache.InformerSynced{cpolInformer.Informer().HasSynced, polInformer.Informer().HasSynced, urInformer.Informer().HasSynced, namespaceInformer.Informer().HasSynced}
@ -186,33 +175,12 @@ func (c *controller) syncUpdateRequest(key string) error {
// Deep-copy otherwise we are mutating our cache.
ur = ur.DeepCopy()
if _, err := c.getPolicy(ur.Spec.Policy); err != nil && apierrors.IsNotFound(err) {
if ur.Spec.GetRequestType() == kyvernov1beta1.Mutate {
return c.handleMutatePolicyAbsence(ur)
}
}
// if not in any state, try to set it to pending
if ur.Status.State == "" {
ur.Status.State = kyvernov1beta1.Pending
_, err := c.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).UpdateStatus(context.TODO(), ur, metav1.UpdateOptions{})
return err
}
// try to get the linked policy
if _, err := c.getPolicy(ur.Spec.Policy); err != nil {
if apierrors.IsNotFound(err) && ur.Spec.GetRequestType() == kyvernov1beta1.Mutate {
// 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)},
)
}
// check if cleanup is required in case policy is no longer exists
if err := c.checkIfCleanupRequired(ur); err != nil {
return err
}
}
// process pending URs
if ur.Status.State == kyvernov1beta1.Pending {
if err := c.processUR(ur); err != nil {
return fmt.Errorf("failed to process UR %s: %v", key, err)
@ -223,59 +191,6 @@ func (c *controller) syncUpdateRequest(key string) error {
return err
}
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 {
target, err := c.client.GetResource(context.TODO(), targetSpec.APIVersion, targetSpec.Kind, targetSpec.Namespace, targetSpec.Name)
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()
syncEnabled := labels[generate.LabelSynchronize] == "enable"
clone := labels[generate.LabelClonePolicyName] != ""
if syncEnabled && !clone {
if err := c.client.DeleteResource(context.TODO(), target.GetAPIVersion(), target.GetKind(), target.GetNamespace(), target.GetName(), false); err != nil {
return fmt.Errorf("failed to delete data resource %s/%s: %v", targetSpec.Namespace, targetSpec.Name, err)
}
}
return nil
}
func (c *controller) enqueueUpdateRequest(obj interface{}) {
key, err := cache.MetaNamespaceKeyFunc(obj)
if err != nil {
@ -286,74 +201,6 @@ func (c *controller) enqueueUpdateRequest(obj interface{}) {
c.queue.Add(key)
}
func (c *controller) updatePolicy(_, obj interface{}) {
key, err := cache.MetaNamespaceKeyFunc(obj)
if err != nil {
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)
}
}
}
func (c *controller) deletePolicy(obj interface{}) {
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.V(4).Info("deleting policy", "name", p.GetName())
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)
// check if deleted policy is clone generate policy
generatePolicyWithClone := c.processDeletePolicyForCloneGenerateRule(p, p.GetName())
// get the generated resource name from update request
selector := labels.SelectorFromSet(labels.Set(map[string]string{
kyvernov1beta1.URGeneratePolicyLabel: p.GetName(),
}))
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
for _, ur := range urList {
logger.V(4).Info("enqueue the ur for cleanup", "ur name", ur.Name)
c.enqueueUpdateRequest(ur)
}
} 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)
}
}
}
}
}
func (c *controller) addUR(obj interface{}) {
ur := obj.(*kyvernov1beta1.UpdateRequest)
c.enqueueUpdateRequest(ur)
@ -399,7 +246,7 @@ func (c *controller) processUR(ur *kyvernov1beta1.UpdateRequest) error {
}
func (c *controller) cleanUR(ur *kyvernov1beta1.UpdateRequest) error {
if ur.Spec.GetRequestType() == kyvernov1beta1.Mutate && ur.Status.State == kyvernov1beta1.Completed {
if ur.Status.State == kyvernov1beta1.Completed {
return c.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).Delete(context.TODO(), ur.GetName(), metav1.DeleteOptions{})
}
return nil
@ -415,67 +262,3 @@ func (c *controller) getPolicy(key string) (kyvernov1.PolicyInterface, error) {
}
return c.polLister.Policies(namespace).Get(name)
}
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 {
return fmt.Errorf("source resource %s/%s/%s not found: %w", rule.Generation.Kind, rule.Generation.Clone.Namespace, rule.Generation.Clone.Name, err)
}
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
}
if labels[generate.LabelClonePolicyName] != "" {
policyNames := labels[generate.LabelClonePolicyName]
if strings.Contains(policyNames, pName) {
desiredLabels := make(map[string]string, len(labels)-1)
for k, v := range labels {
if k != generate.LabelClonePolicyName {
desiredLabels[k] = v
}
}
return true, desiredLabels
}
}
return false, labels
}

View file

@ -6,6 +6,7 @@ import (
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/autogen"
"github.com/kyverno/kyverno/pkg/background/common"
generateutils "github.com/kyverno/kyverno/pkg/background/generate"
"github.com/kyverno/kyverno/pkg/config"
@ -24,7 +25,7 @@ func (pc *PolicyController) handleGenerate(policyKey string, policy kyvernov1.Po
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 {
if err := pc.createUR(policy, rule, false); err != nil {
logger.Error(err, "failed to create UR on policy event")
}
@ -39,7 +40,7 @@ func (pc *PolicyController) handleGenerate(policyKey string, policy kyvernov1.Po
continue
}
ur := newUR(policy, resourceSpecFromUnstructured(trigger), ruleType)
ur := newUR(policy, common.ResourceSpecFromUnstructured(*trigger), rule.Name, ruleType, false)
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,
@ -70,32 +71,81 @@ func (pc *PolicyController) listGenerateURs(policyKey string, trigger *unstructu
return generateURs
}
func (pc *PolicyController) createUR(policy kyvernov1.PolicyInterface, rule kyvernov1.Rule) error {
func (pc *PolicyController) createURForDownstreamDeletion(policy kyvernov1.PolicyInterface) error {
var errs []error
rules := autogen.ComputeRules(policy)
for _, r := range rules {
generateType, sync := r.GetGenerateTypeAndSync()
if sync && (generateType == kyvernov1.Data) {
if err := pc.createUR(policy, r, true); err != nil {
errs = append(errs, err)
}
}
}
return multierr.Combine(errs...)
}
func (pc *PolicyController) createUR(policy kyvernov1.PolicyInterface, rule kyvernov1.Rule, deleteDownstream bool) error {
generate := rule.Generation
if !generate.Synchronize {
// no action for non-sync policy/rule
return nil
}
var errorList []error
if generate.GetData() != nil {
downstream, err := pc.client.GetResource(context.TODO(), generate.APIVersion, generate.Kind, generate.Namespace, generate.Name)
downstreams, err := generateutils.FindDownstream(pc.client, policy, rule)
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
for _, downstream := range downstreams.Items {
labels := downstream.GetLabels()
trigger := generateutils.TriggerFromLabels(labels)
ur := newUR(policy, trigger, rule.Name, kyvernov1beta1.Generate, deleteDownstream)
created, err := pc.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).Create(context.TODO(), ur, metav1.CreateOptions{})
if err != nil {
errorList = append(errorList, err)
continue
}
updated := created.DeepCopy()
updated.Status = newURStatus(downstream)
_, err = pc.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).UpdateStatus(context.TODO(), updated, metav1.UpdateOptions{})
if err != nil {
errorList = append(errorList, err)
continue
}
}
}
return nil
return multierr.Combine(errorList...)
}
// ruleDeletion returns true if any rule is deleted, along with deleted rules
func ruleDeletion(old, new kyvernov1.PolicyInterface) (_ kyvernov1.PolicyInterface, ruleDeleted bool) {
if !new.GetDeletionTimestamp().IsZero() {
return nil, false
}
newRules := new.GetSpec().Rules
oldRules := old.GetSpec().Rules
newRulesMap := make(map[string]bool, len(newRules))
var deletedRules []kyvernov1.Rule
for _, r := range newRules {
newRulesMap[r.Name] = true
}
for _, r := range oldRules {
if exist := newRulesMap[r.Name]; !exist {
deletedRules = append(deletedRules, r)
ruleDeleted = true
}
}
return buildPolicyWithDeletedRules(old, deletedRules), ruleDeleted
}
func buildPolicyWithDeletedRules(policy kyvernov1.PolicyInterface, deletedRules []kyvernov1.Rule) kyvernov1.PolicyInterface {
newPolicy := policy.CreateDeepCopy()
spec := newPolicy.GetSpec()
spec.SetRules(deletedRules)
return newPolicy
}

View file

@ -31,7 +31,7 @@ func (pc *PolicyController) handleMutate(policyKey string, policy kyvernov1.Poli
}
logger.Info("creating new UR for mutate")
ur := newUR(policy, resourceSpecFromUnstructured(trigger), ruleType)
ur := newUR(policy, backgroundcommon.ResourceSpecFromUnstructured(*trigger), rule.Name, ruleType, false)
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,

View file

@ -11,7 +11,6 @@ import (
"github.com/go-logr/logr"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/autogen"
backgroundcommon "github.com/kyverno/kyverno/pkg/background/common"
"github.com/kyverno/kyverno/pkg/client/clientset/versioned"
"github.com/kyverno/kyverno/pkg/client/clientset/versioned/scheme"
@ -211,6 +210,12 @@ func (pc *PolicyController) updatePolicy(old, cur interface{}) {
}
logger.V(2).Info("updating policy", "name", oldP.GetName())
if deleted, ok := ruleDeletion(oldP, curP); ok {
err := pc.createURForDownstreamDeletion(deleted)
if err != nil {
utilruntime.HandleError(fmt.Errorf("failed to create UR on rule deletion, clean up downstream resource may be failed: %v", err))
}
}
pc.enqueuePolicy(curP)
}
@ -230,16 +235,10 @@ func (pc *PolicyController) deletePolicy(obj interface{}) {
}
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)
for _, r := range rules {
clone, sync := r.GetCloneSyncForGenerate()
if clone && sync {
return
}
err := pc.createURForDownstreamDeletion(p)
if err != nil {
utilruntime.HandleError(fmt.Errorf("failed to create UR on policy deletion, clean up downstream resource may be failed: %v", err))
}
pc.enqueuePolicy(p)
}
func (pc *PolicyController) enqueuePolicy(policy kyvernov1.PolicyInterface) {
@ -425,7 +424,13 @@ func (pc *PolicyController) handleUpdateRequest(ur *kyvernov1beta1.UpdateRequest
}
pc.log.V(2).Info("creating new UR for generate")
_, err := pc.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).Create(context.TODO(), ur, metav1.CreateOptions{})
created, err := pc.kyvernoClient.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).Create(context.TODO(), ur, metav1.CreateOptions{})
if err != nil {
return false, 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 false, err
}
@ -474,12 +479,3 @@ 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(),
}
}

View file

@ -6,10 +6,11 @@ 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 kyvernov1.ResourceSpec, ruleType kyvernov1beta1.RequestType) *kyvernov1beta1.UpdateRequest {
func newUR(policy kyvernov1.PolicyInterface, trigger kyvernov1.ResourceSpec, ruleName string, ruleType kyvernov1beta1.RequestType, deleteDownstream bool) *kyvernov1beta1.UpdateRequest {
var policyNameNamespaceKey string
if policy.IsNamespaced() {
@ -26,6 +27,10 @@ func newUR(policy kyvernov1.PolicyInterface, trigger kyvernov1.ResourceSpec, rul
}
return &kyvernov1beta1.UpdateRequest{
TypeMeta: metav1.TypeMeta{
APIVersion: kyvernov1beta1.SchemeGroupVersion.String(),
Kind: "UpdateRequest",
},
ObjectMeta: metav1.ObjectMeta{
GenerateName: "ur-",
Namespace: config.KyvernoNamespace(),
@ -34,12 +39,28 @@ func newUR(policy kyvernov1.PolicyInterface, trigger kyvernov1.ResourceSpec, rul
Spec: kyvernov1beta1.UpdateRequestSpec{
Type: ruleType,
Policy: policyNameNamespaceKey,
Rule: ruleName,
Resource: kyvernov1.ResourceSpec{
Kind: trigger.GetKind(),
Namespace: trigger.GetNamespace(),
Name: trigger.GetName(),
APIVersion: trigger.GetAPIVersion(),
},
DeleteDownstream: deleteDownstream,
},
}
}
func newURStatus(downstream unstructured.Unstructured) kyvernov1beta1.UpdateRequestStatus {
return kyvernov1beta1.UpdateRequestStatus{
State: kyvernov1beta1.Pending,
GeneratedResources: []kyvernov1.ResourceSpec{
{
APIVersion: downstream.GetAPIVersion(),
Kind: downstream.GetKind(),
Namespace: downstream.GetNamespace(),
Name: downstream.GetName(),
},
},
}
}

View file

@ -158,10 +158,13 @@ func (h *generationHandler) createUR(ctx context.Context, policyContext *engine.
return fmt.Errorf("labels have been changed, new: %v, old: %v", labels, oldLabels)
}
managedBy := oldLabels[kyvernov1.LabelAppManagedBy] == kyvernov1.ValueKyvernoApp
deleteDownstream := false
if reflect.DeepEqual(new, unstructured.Unstructured{}) {
deleteDownstream = true
labels = oldLabels
if !managedBy {
deleteDownstream = true
}
}
pName := labels[common.GeneratePolicyLabel]
pNamespace := labels[common.GeneratePolicyNamespaceLabel]
@ -187,6 +190,7 @@ func (h *generationHandler) createUR(ctx context.Context, policyContext *engine.
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...)

View file

@ -105,12 +105,18 @@ func (g *generator) tryApplyResource(ctx context.Context, urSpec kyvernov1beta1.
},
Spec: urSpec,
}
if new, err := g.client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).Create(ctx, &ur, metav1.CreateOptions{}); err != nil {
created, err := g.client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).Create(ctx, &ur, metav1.CreateOptions{})
if err != nil {
l.V(4).Error(err, "failed to create UpdateRequest, retrying", "name", ur.GetGenerateName(), "namespace", ur.GetNamespace())
return err
} else {
l.V(4).Info("successfully created UpdateRequest", "name", new.GetName(), "namespace", ur.GetNamespace())
}
updated := created.DeepCopy()
updated.Status.State = kyvernov1beta1.Pending
_, err = g.client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).UpdateStatus(context.TODO(), updated, metav1.UpdateOptions{})
if err != nil {
return err
}
l.V(4).Info("successfully created UpdateRequest", "name", updated.GetName(), "namespace", ur.GetNamespace())
}
return nil
}

View file

@ -1,4 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: bar
name: cpol-clone-nosync-create-ns

View file

@ -0,0 +1,5 @@
# A command can only run a single command, not a pipeline and not a script. The program called must exist on the system where the test is run.
apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- command: sleep 3

View file

@ -1,4 +0,0 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- command: kubectl delete -f 01-manifests.yaml,02-ns.yaml --force --wait=true --ignore-not-found=true

View file

@ -2,4 +2,4 @@ apiVersion: v1
kind: Secret
metadata:
name: regcred
namespace: bar
namespace: cpol-clone-nosync-delete-downstream-ns

View file

@ -1,4 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: bar
name: cpol-clone-nosync-delete-downstream-ns

View file

@ -1,4 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: bar
name: cpol-clone-nosync-delete-downstream-ns

View file

@ -4,4 +4,4 @@ delete:
- apiVersion: v1
kind: Secret
name: regcred
namespace: bar
namespace: cpol-clone-nosync-delete-downstream-ns

View file

@ -3,4 +3,4 @@ apiVersion: v1
kind: Secret
metadata:
name: regcred
namespace: bar
namespace: cpol-clone-nosync-delete-downstream-ns

View file

@ -1,4 +0,0 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- command: kubectl delete -f 01-manifests.yaml,02-ns.yaml --force --wait=true --ignore-not-found=true

View file

@ -2,4 +2,4 @@ apiVersion: v1
kind: Secret
metadata:
name: regcred
namespace: bar
namespace: cpol-clone-sync-create-ns

View file

@ -1,4 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: bar
name: cpol-clone-sync-create-ns

View file

@ -2,4 +2,4 @@ apiVersion: v1
kind: Secret
metadata:
name: regcred
namespace: bar
namespace: cpol-clone-sync-delete-downstream-ns

View file

@ -1,4 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: bar
name: cpol-clone-sync-delete-downstream-ns

View file

@ -1,4 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: bar
name: cpol-clone-sync-delete-downstream-ns

View file

@ -4,4 +4,4 @@ delete:
- apiVersion: v1
kind: Secret
name: regcred
namespace: bar
namespace: cpol-clone-sync-delete-downstream-ns

View file

@ -3,4 +3,4 @@ apiVersion: v1
kind: Secret
metadata:
name: regcred
namespace: bar
namespace: cpol-clone-sync-delete-downstream-ns

View file

@ -7,4 +7,4 @@ metadata:
labels:
somekey: somevalue
name: zk-kafka-address
namespace: bar
namespace: cpol-data-nosync-delete-downstream-ns

View file

@ -1,4 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: bar
name: cpol-data-nosync-delete-downstream-ns

View file

@ -4,4 +4,4 @@ delete:
- apiVersion: v1
kind: ConfigMap
name: zk-kafka-address
namespace: bar
namespace: cpol-data-nosync-delete-downstream-ns

View file

@ -2,4 +2,4 @@ apiVersion: v1
kind: ConfigMap
metadata:
name: zk-kafka-address
namespace: bar
namespace: cpol-data-nosync-delete-downstream-ns

View file

@ -7,4 +7,4 @@ metadata:
labels:
somekey: somevalue
name: zk-kafka-address
namespace: bar
namespace: cpol-data-sync-create-ns

View file

@ -1,4 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: bar
name: cpol-data-sync-create-ns

View file

@ -1,4 +0,0 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- command: kubectl delete -f 01-manifests.yaml,02-ns.yaml --force --wait=true --ignore-not-found=true

View file

@ -7,4 +7,4 @@ metadata:
labels:
somekey: somevalue
name: zk-kafka-address
namespace: falcon-heavy
namespace: cpol-data-sync-delete-downstream-ns

View file

@ -1,4 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: falcon-heavy
name: cpol-data-sync-delete-downstream-ns

View file

@ -5,4 +5,4 @@ delete:
- apiVersion: v1
kind: ConfigMap
name: zk-kafka-address
namespace: falcon-heavy
namespace: cpol-data-sync-delete-downstream-ns

View file

@ -7,4 +7,4 @@ metadata:
labels:
somekey: somevalue
name: zk-kafka-address
namespace: falcon-heavy
namespace: cpol-data-sync-delete-downstream-ns

View file

@ -1,7 +1,7 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: zk-kafka-address
name: cpol-data-sync-delete-policy
status:
conditions:
- reason: Succeeded

View file

@ -1,11 +1,11 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: zk-kafka-address
name: cpol-data-sync-delete-policy
spec:
generateExistingOnPolicyUpdate: false
rules:
- name: k-kafka-address
- name: cpol-data-sync-delete-rule
match:
any:
- resources:

View file

@ -7,4 +7,4 @@ metadata:
labels:
somekey: somevalue
name: zk-kafka-address
namespace: bar
namespace: cpol-data-sync-delete-policy-ns

View file

@ -1,4 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: bar
name: cpol-data-sync-delete-policy-ns

View file

@ -7,4 +7,4 @@ metadata:
labels:
somekey: somevalue
name: zk-kafka-address
namespace: bar
namespace: cpol-data-sync-delete-policy-ns

View file

@ -2,4 +2,4 @@ apiVersion: v1
kind: ConfigMap
metadata:
name: zk-kafka-address
namespace: bar
namespace: cpol-data-sync-delete-policy-ns

View file

@ -3,4 +3,4 @@ kind: TestStep
delete:
- apiVersion: kyverno.io/v1
kind: ClusterPolicy
name: zk-kafka-address
name: cpol-data-sync-delete-policy

View file

@ -1,4 +0,0 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- command: kubectl delete -f 01-manifests.yaml,02-ns.yaml --force --wait=true --ignore-not-found=true

View file

@ -0,0 +1,6 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
apply:
- policy.yaml
assert:
- policy-ready.yaml

View file

@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: cpol-data-sync-delete-rule

View file

@ -0,0 +1,5 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
assert:
- secret.yaml
- configmap.yaml

View file

@ -0,0 +1,6 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
apply:
- delete-rule.yaml
assert:
- policy-ready.yaml

View file

@ -0,0 +1,5 @@
# A command can only run a single command, not a pipeline and not a script. The program called must exist on the system where the test is run.
apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- command: sleep 3

View file

@ -0,0 +1,7 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
apply:
assert:
- secret.yaml
error:
- configmap.yaml

View file

@ -0,0 +1,11 @@
## Description
This test checks to ensure that deletion of a rule in a ClusterPolicy generate rule, data declaration, with sync enabled, results in the downstream resource's deletion.
## Expected Behavior
The downstream (generated) resource is expected to be deleted if the corresponding rule within a ClusterPolicy is deleted. If it is not deleted, the test fails. If it is deleted, the test passes.
## Reference Issue(s)
https://github.com/kyverno/kyverno/issues/5744

View file

@ -0,0 +1,10 @@
apiVersion: v1
data:
KAFKA_ADDRESS: 192.168.10.13:9092,192.168.10.14:9092,192.168.10.15:9092
ZK_ADDRESS: 192.168.10.10:2181,192.168.10.11:2181,192.168.10.12:2181
kind: ConfigMap
metadata:
labels:
somekey: somevalue
name: zk-kafka-address
namespace: cpol-data-sync-delete-rule

View file

@ -0,0 +1,35 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: multiple-gens
spec:
generateExistingOnPolicyUpdate: false
rules:
- name: super-secret
match:
any:
- resources:
kinds:
- Namespace
exclude:
any:
- resources:
namespaces:
- kube-system
- default
- kube-public
- kyverno
generate:
synchronize: true
apiVersion: v1
kind: Secret
name: supersecret
namespace: "{{request.object.metadata.name}}"
data:
kind: Secret
type: Opaque
metadata:
labels:
somekey: somesecretvalue
data:
mysupersecretkey: bXlzdXBlcnNlY3JldHZhbHVl

View file

@ -0,0 +1,9 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: multiple-gens
status:
conditions:
- reason: Succeeded
status: "True"
type: Ready

View file

@ -0,0 +1,63 @@
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: multiple-gens
spec:
generateExistingOnPolicyUpdate: false
rules:
- name: k-kafka-address
match:
any:
- resources:
kinds:
- Namespace
exclude:
any:
- resources:
namespaces:
- kube-system
- default
- kube-public
- kyverno
generate:
synchronize: true
apiVersion: v1
kind: ConfigMap
name: zk-kafka-address
namespace: "{{request.object.metadata.name}}"
data:
kind: ConfigMap
metadata:
labels:
somekey: somevalue
data:
ZK_ADDRESS: "192.168.10.10:2181,192.168.10.11:2181,192.168.10.12:2181"
KAFKA_ADDRESS: "192.168.10.13:9092,192.168.10.14:9092,192.168.10.15:9092"
- name: super-secret
match:
any:
- resources:
kinds:
- Namespace
exclude:
any:
- resources:
namespaces:
- kube-system
- default
- kube-public
- kyverno
generate:
synchronize: true
apiVersion: v1
kind: Secret
name: supersecret
namespace: "{{request.object.metadata.name}}"
data:
kind: Secret
type: Opaque
metadata:
labels:
somekey: somesecretvalue
data:
mysupersecretkey: bXlzdXBlcnNlY3JldHZhbHVl

View file

@ -0,0 +1,10 @@
apiVersion: v1
data:
mysupersecretkey: bXlzdXBlcnNlY3JldHZhbHVl
kind: Secret
metadata:
labels:
somekey: somesecretvalue
name: supersecret
namespace: cpol-data-sync-delete-rule
type: Opaque

View file

@ -7,4 +7,4 @@ metadata:
labels:
somekey: somevalue
name: zk-kafka-address
namespace: bar
namespace: cpol-data-sync-modify-rule-ns

View file

@ -1,4 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: bar
name: cpol-data-sync-modify-rule-ns

View file

@ -7,4 +7,4 @@ metadata:
labels:
somekey: somevalue
name: zk-kafka-address
namespace: bar
namespace: cpol-data-sync-modify-rule-ns

View file

@ -1,4 +0,0 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- command: kubectl delete -f 01-manifests.yaml,02-ns.yaml --force --wait=true --ignore-not-found=true

View file

@ -0,0 +1,13 @@
apiVersion: v1
kind: Namespace
metadata:
name: pol-sync-clone-delete-downstream
---
apiVersion: v1
data:
foo: YmFy
kind: Secret
metadata:
name: regcred
namespace: pol-sync-clone-delete-downstream
type: Opaque

View file

@ -0,0 +1,13 @@
apiVersion: v1
kind: Namespace
metadata:
name: pol-sync-clone-delete-downstream
---
apiVersion: v1
data:
foo: YmFy
kind: Secret
metadata:
name: regcred
namespace: pol-sync-clone-delete-downstream
type: Opaque

View file

@ -0,0 +1,10 @@
apiVersion: kyverno.io/v2beta1
kind: Policy
metadata:
name: pol-sync-clone-delete-downstream
namespace: pol-sync-clone-delete-downstream
status:
conditions:
- reason: Succeeded
status: "True"
type: Ready

View file

@ -0,0 +1,22 @@
apiVersion: kyverno.io/v2beta1
kind: Policy
metadata:
name: pol-sync-clone-delete-downstream
namespace: pol-sync-clone-delete-downstream
spec:
rules:
- name: gen-zk
match:
any:
- resources:
kinds:
- ConfigMap
generate:
apiVersion: v1
kind: Secret
name: myclonedsecret
namespace: pol-sync-clone-delete-downstream
synchronize: true
clone:
namespace: pol-sync-clone-delete-downstream
name: regcred

View file

@ -0,0 +1,7 @@
apiVersion: v1
data:
foo: bar
kind: ConfigMap
metadata:
name: foo
namespace: pol-sync-clone-delete-downstream

View file

@ -0,0 +1,4 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
assert:
- downstream.yaml

View file

@ -0,0 +1,8 @@
apiVersion: v1
data:
foo: YmFy
kind: Secret
metadata:
name: myclonedsecret
namespace: pol-sync-clone-delete-downstream
type: Opaque

View file

@ -0,0 +1,4 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- command: sleep 3

View file

@ -0,0 +1,4 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
assert:
- downstream.yaml

View file

@ -0,0 +1,11 @@
## Description
This test ensures that deletion of a downstream resource created by a Policy `generate` rule with sync enabled using a clone declaration causes it to be regenerated. If it is not regenerated, the test fails.
## Expected Behavior
The downstream resource, upon deletion, is expected to be recreated/recloned from the source resource.
## Reference Issue(s)
N/A

View file

@ -0,0 +1,8 @@
apiVersion: v1
data:
foo: YmFy
kind: Secret
metadata:
name: myclonedsecret
namespace: pol-sync-clone-delete-downstream
type: Opaque

View file

@ -0,0 +1,6 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
apply:
- policy.yaml
assert:
- policy-ready.yaml

View file

@ -0,0 +1,6 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
apply:
- create-cm.yaml
assert:
- cloned-secret.yaml

View file

@ -0,0 +1,7 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
delete:
- apiVersion: v1
kind: Secret
name: regcred
namespace: pol-clone-sync-delete-source

View file

@ -0,0 +1,4 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- command: sleep 5

View file

@ -0,0 +1,8 @@
apiVersion: v1
data:
foo: YmFy
kind: Secret
metadata:
name: newsecret
namespace: pol-clone-sync-delete-source
type: Opaque

View file

@ -0,0 +1,11 @@
## Description
This test ensures that deletion of the source (upstream) resource used by a Policy `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 be deleted. If the downstream resource remains, the test fails. If the downstream resource is deleted, the test passes.
## Reference Issue(s)
N/A

View file

@ -0,0 +1,8 @@
apiVersion: v1
data:
foo: YmFy
kind: Secret
metadata:
name: newsecret
namespace: pol-clone-sync-delete-source
type: Opaque

View file

@ -0,0 +1,9 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: mycm
namespace: pol-clone-sync-delete-source
data:
food: cheese
day: monday
color: red

View file

@ -0,0 +1,10 @@
apiVersion: kyverno.io/v2beta1
kind: Policy
metadata:
name: pol-clone-sync-delete-source
namespace: pol-clone-sync-delete-source
status:
conditions:
- reason: Succeeded
status: "True"
type: Ready

View file

@ -0,0 +1,36 @@
apiVersion: v1
kind: Namespace
metadata:
name: pol-clone-sync-delete-source
---
apiVersion: v1
data:
foo: YmFy
kind: Secret
metadata:
name: regcred
namespace: pol-clone-sync-delete-source
type: Opaque
---
apiVersion: kyverno.io/v2beta1
kind: Policy
metadata:
name: pol-clone-sync-delete-source
namespace: pol-clone-sync-delete-source
spec:
rules:
- name: pol-clone-sync-delete-source-secret
match:
any:
- resources:
kinds:
- ConfigMap
generate:
apiVersion: v1
kind: Secret
name: newsecret
namespace: pol-clone-sync-delete-source
synchronize: true
clone:
namespace: pol-clone-sync-delete-source
name: regcred

View file

@ -0,0 +1,10 @@
apiVersion: kyverno.io/v1
kind: Policy
metadata:
name: multiple-gens
namespace: pol-data-sync-delete-rule
status:
conditions:
- reason: Succeeded
status: "True"
type: Ready

View file

@ -0,0 +1,57 @@
apiVersion: v1
kind: Namespace
metadata:
name: pol-data-sync-delete-rule
---
apiVersion: kyverno.io/v1
kind: Policy
metadata:
name: multiple-gens
namespace: pol-data-sync-delete-rule
spec:
generateExistingOnPolicyUpdate: false
rules:
- name: k-kafka-address
match:
any:
- resources:
kinds:
- Secret
names:
- trigger-secret
generate:
synchronize: true
apiVersion: v1
kind: ConfigMap
name: zk-kafka-address
namespace: pol-data-sync-delete-rule
data:
kind: ConfigMap
metadata:
labels:
somekey: somevalue
data:
ZK_ADDRESS: "192.168.10.10:2181,192.168.10.11:2181,192.168.10.12:2181"
KAFKA_ADDRESS: "192.168.10.13:9092,192.168.10.14:9092,192.168.10.15:9092"
- name: super-secret
match:
any:
- resources:
kinds:
- Secret
names:
- trigger-secret
generate:
synchronize: true
apiVersion: v1
kind: Secret
name: supersecret
namespace: pol-data-sync-delete-rule
data:
kind: Secret
type: Opaque
metadata:
labels:
somekey: somesecretvalue
data:
mysupersecretkey: bXlzdXBlcnNlY3JldHZhbHVl

View file

@ -0,0 +1,10 @@
apiVersion: v1
data:
foo: YmFy
kind: Secret
metadata:
labels:
org: kyverno
name: trigger-secret
namespace: pol-data-sync-delete-rule
type: Opaque

View file

@ -0,0 +1,5 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
assert:
- secret.yaml
- configmap.yaml

View file

@ -0,0 +1,10 @@
apiVersion: kyverno.io/v1
kind: Policy
metadata:
name: multiple-gens
namespace: pol-data-sync-delete-rule
status:
conditions:
- reason: Succeeded
status: "True"
type: Ready

View file

@ -0,0 +1,30 @@
apiVersion: kyverno.io/v1
kind: Policy
metadata:
name: multiple-gens
namespace: pol-data-sync-delete-rule
spec:
generateExistingOnPolicyUpdate: false
rules:
- name: super-secret
match:
any:
- resources:
kinds:
- Secret
names:
- trigger-secret
generate:
synchronize: true
apiVersion: v1
kind: Secret
name: supersecret
namespace: pol-data-sync-delete-rule
data:
kind: Secret
type: Opaque
metadata:
labels:
somekey: somesecretvalue
data:
mysupersecretkey: bXlzdXBlcnNlY3JldHZhbHVl

View file

@ -0,0 +1,5 @@
# A command can only run a single command, not a pipeline and not a script. The program called must exist on the system where the test is run.
apiVersion: kuttl.dev/v1beta1
kind: TestStep
commands:
- command: sleep 3

View file

@ -0,0 +1,7 @@
apiVersion: kuttl.dev/v1beta1
kind: TestStep
apply:
assert:
- secret.yaml
error:
- configmap.yaml

View file

@ -0,0 +1,11 @@
## Description
This test checks to ensure that deletion of a rule in a Policy (Namespaced) generate rule, data declaration, with sync enabled, results in the downstream resource's deletion.
## Expected Behavior
The downstream (generated) resource is expected to be deleted if the corresponding rule within a Policy is deleted. If it is not deleted, the test fails. If it is deleted, the test passes.
## Reference Issue(s)
https://github.com/kyverno/kyverno/issues/5744

View file

@ -0,0 +1,10 @@
apiVersion: v1
data:
KAFKA_ADDRESS: 192.168.10.13:9092,192.168.10.14:9092,192.168.10.15:9092
ZK_ADDRESS: 192.168.10.10:2181,192.168.10.11:2181,192.168.10.12:2181
kind: ConfigMap
metadata:
labels:
somekey: somevalue
name: zk-kafka-address
namespace: pol-data-sync-delete-rule

View file

@ -0,0 +1,10 @@
apiVersion: v1
data:
mysupersecretkey: bXlzdXBlcnNlY3JldHZhbHVl
kind: Secret
metadata:
labels:
somekey: somesecretvalue
name: supersecret
namespace: pol-data-sync-delete-rule
type: Opaque

View file

@ -0,0 +1,10 @@
apiVersion: kyverno.io/v2beta1
kind: Policy
metadata:
name: zk-kafka-address
namespace: pol-data-sync-modify-rule
status:
conditions:
- reason: Succeeded
status: "True"
type: Ready

Some files were not shown because too many files have changed in this diff Show more