1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-06 16:06:56 +00:00

fix: stop mutation policies when autogen internals is enabled (#4004,#4009,#3996) (#4016)

* fix: stop mutation policies when autogen internals is enabled (#4004)

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>
(cherry picked from commit c9f8a68d8a)
Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>

* fix: use background helper in ur generator (#4009)

* fix: stop mutating cached resource in ur controller (#4003)

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>
(cherry picked from commit dac733755b)
Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>

* fix: use background helper in ur generator

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>
(cherry picked from commit 3a3556919f)
Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>

* refactor: move label helper utils from policy package to background package (#3996)

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>
(cherry picked from commit 1712dfa947)
Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>
This commit is contained in:
Charles-Edouard Brétéché 2022-05-25 06:14:40 +02:00 committed by GitHub
parent eaa629714e
commit 56d32e93e7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 226 additions and 307 deletions

View file

@ -457,17 +457,3 @@ type CloneFrom struct {
// Name specifies name of the resource.
Name string `json:"name,omitempty" yaml:"name,omitempty"`
}
type ResourceSpec struct {
// APIVersion specifies resource apiVersion.
// +optional
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
// Kind specifies resource kind.
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
// Namespace specifies resource namespace.
// +optional
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
// Name specifies the resource name.
// +optional
Name string `json:"name,omitempty" yaml:"name,omitempty"`
}

View file

@ -0,0 +1,20 @@
package v1
type ResourceSpec struct {
// APIVersion specifies resource apiVersion.
// +optional
APIVersion string `json:"apiVersion,omitempty" yaml:"apiVersion,omitempty"`
// Kind specifies resource kind.
Kind string `json:"kind,omitempty" yaml:"kind,omitempty"`
// Namespace specifies resource namespace.
// +optional
Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"`
// Name specifies the resource name.
// +optional
Name string `json:"name,omitempty" yaml:"name,omitempty"`
}
func (s ResourceSpec) GetName() string { return s.Name }
func (s ResourceSpec) GetNamespace() string { return s.Namespace }
func (s ResourceSpec) GetKind() string { return s.Kind }
func (s ResourceSpec) GetAPIVersion() string { return s.APIVersion }

View file

@ -9,5 +9,9 @@ const (
URMutatetriggerAPIVersionLabel = "mutate.updaterequest.kyverno.io/trigger-apiversion"
// URGeneratePolicyLabel adds the policy name to URs for generate policies
URGeneratePolicyLabel = "generate.kyverno.io/policy-name"
URGeneratePolicyLabel = "generate.kyverno.io/policy-name"
URGenerateResourceNameLabel = "generate.kyverno.io/resource-name"
URGenerateResourceNSLabel = "generate.kyverno.io/resource-namespace"
URGenerateResourceKindLabel = "generate.kyverno.io/resource-kind"
URGenerateRetryCountAnnotation = "generate.kyverno.io/retry-count"
)

View file

@ -278,10 +278,7 @@ func main() {
os.Exit(1)
}
urgen := webhookgenerate.NewGenerator(kyvernoClient,
kyvernoInformer.Kyverno().V1beta1().UpdateRequests(),
stopCh,
log.Log.WithName("UpdateRequestGenerator"))
urgen := webhookgenerate.NewGenerator(kyvernoClient, kyvernoInformer.Kyverno().V1beta1().UpdateRequests())
urc := background.NewController(
kubeClient,

View file

@ -2,11 +2,21 @@ package common
import (
"fmt"
"reflect"
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
pkglabels "k8s.io/apimachinery/pkg/labels"
"sigs.k8s.io/controller-runtime/pkg/log"
)
type Object interface {
GetName() string
GetNamespace() string
GetKind() string
GetAPIVersion() string
}
func ManageLabels(unstr *unstructured.Unstructured, triggerResource unstructured.Unstructured) {
// add managedBY label if not defined
labels := unstr.GetLabels()
@ -23,6 +33,35 @@ func ManageLabels(unstr *unstructured.Unstructured, triggerResource unstructured
unstr.SetLabels(labels)
}
func MutateLabelsSet(policyKey string, trigger Object) pkglabels.Set {
set := pkglabels.Set{
kyvernov1beta1.URMutatePolicyLabel: policyKey,
}
isNil := trigger == nil || (reflect.ValueOf(trigger).Kind() == reflect.Ptr && reflect.ValueOf(trigger).IsNil())
if !isNil {
set[kyvernov1beta1.URMutateTriggerNameLabel] = trigger.GetName()
set[kyvernov1beta1.URMutateTriggerNSLabel] = trigger.GetNamespace()
set[kyvernov1beta1.URMutatetriggerKindLabel] = trigger.GetKind()
if trigger.GetAPIVersion() != "" {
set[kyvernov1beta1.URMutatetriggerAPIVersionLabel] = trigger.GetAPIVersion()
}
}
return set
}
func GenerateLabelsSet(policyKey string, trigger Object) pkglabels.Set {
set := pkglabels.Set{
kyvernov1beta1.URGeneratePolicyLabel: policyKey,
}
isNil := trigger == nil || (reflect.ValueOf(trigger).Kind() == reflect.Ptr && reflect.ValueOf(trigger).IsNil())
if !isNil {
set[kyvernov1beta1.URGenerateResourceNameLabel] = trigger.GetName()
set[kyvernov1beta1.URGenerateResourceNSLabel] = trigger.GetNamespace()
set[kyvernov1beta1.URGenerateResourceKindLabel] = trigger.GetKind()
}
return set
}
func managedBy(labels map[string]string) {
// ManagedBy label
key := "app.kubernetes.io/managed-by"

View file

@ -4,12 +4,12 @@ import (
"strconv"
"github.com/go-logr/logr"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
dclient "github.com/kyverno/kyverno/pkg/dclient"
apierrors "k8s.io/apimachinery/pkg/api/errors"
)
func (c *Controller) processUR(ur urkyverno.UpdateRequest) error {
func (c *Controller) processUR(ur kyvernov1beta1.UpdateRequest) error {
logger := c.log.WithValues("kind", ur.Kind, "namespace", ur.Namespace, "name", ur.Name)
// 1- Corresponding policy has been deleted
// then we don't delete the generated resources
@ -19,7 +19,7 @@ func (c *Controller) processUR(ur urkyverno.UpdateRequest) error {
deleteUR := false
// check retry count in annotaion
urAnnotations := ur.Annotations
if val, ok := urAnnotations["generate.kyverno.io/retry-count"]; ok {
if val, ok := urAnnotations[kyvernov1beta1.URGenerateRetryCountAnnotation]; ok {
retryCount, err := strconv.ParseUint(val, 10, 32)
if err != nil {
logger.Error(err, "unable to convert retry-count")
@ -44,7 +44,7 @@ func (c *Controller) processUR(ur urkyverno.UpdateRequest) error {
return nil
}
func ownerResourceExists(log logr.Logger, client dclient.Interface, ur urkyverno.UpdateRequest) bool {
func ownerResourceExists(log logr.Logger, client dclient.Interface, ur kyvernov1beta1.UpdateRequest) bool {
_, err := client.GetResource("", ur.Spec.Resource.Kind, ur.Spec.Resource.Namespace, ur.Spec.Resource.Name)
// trigger resources has been deleted
if apierrors.IsNotFound(err) {
@ -58,7 +58,7 @@ func ownerResourceExists(log logr.Logger, client dclient.Interface, ur urkyverno
return true
}
func deleteGeneratedResources(log logr.Logger, client dclient.Interface, ur urkyverno.UpdateRequest) error {
func deleteGeneratedResources(log logr.Logger, client dclient.Interface, ur kyvernov1beta1.UpdateRequest) error {
for _, genResource := range ur.Status.GeneratedResources {
err := client.DeleteResource("", genResource.Kind, genResource.Namespace, genResource.Name, false)
if err != nil && !apierrors.IsNotFound(err) {

View file

@ -12,7 +12,7 @@ import (
"github.com/go-logr/logr"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/autogen"
"github.com/kyverno/kyverno/pkg/background/common"
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
@ -96,7 +96,7 @@ func NewGenerateController(
return &c, nil
}
func (c *GenerateController) ProcessUR(ur *urkyverno.UpdateRequest) error {
func (c *GenerateController) ProcessUR(ur *kyvernov1beta1.UpdateRequest) error {
logger := c.log.WithValues("name", ur.Name, "policy", ur.Spec.Policy, "kind", ur.Spec.Resource.Kind, "apiVersion", ur.Spec.Resource.APIVersion, "namespace", ur.Spec.Resource.Namespace, "name", ur.Spec.Resource.Name)
var err error
var resource *unstructured.Unstructured
@ -114,10 +114,11 @@ func (c *GenerateController) ProcessUR(ur *urkyverno.UpdateRequest) error {
urAnnotations := ur.Annotations
if len(urAnnotations) == 0 {
urAnnotations = make(map[string]string)
urAnnotations["generate.kyverno.io/retry-count"] = "1"
urAnnotations = map[string]string{
urAnnotations[kyvernov1beta1.URGenerateRetryCountAnnotation]: "1",
}
} else {
if val, ok := urAnnotations["generate.kyverno.io/retry-count"]; ok {
if val, ok := urAnnotations[kyvernov1beta1.URGenerateRetryCountAnnotation]; ok {
sleepCountInt64, err := strconv.ParseUint(val, 10, 32)
if err != nil {
logger.Error(err, "unable to convert retry-count")
@ -136,12 +137,12 @@ func (c *GenerateController) ProcessUR(ur *urkyverno.UpdateRequest) error {
} else {
time.Sleep(time.Second * time.Duration(sleepCountInt))
incrementedCountString := strconv.Itoa(sleepCountInt)
urAnnotations["generate.kyverno.io/retry-count"] = incrementedCountString
urAnnotations[kyvernov1beta1.URGenerateRetryCountAnnotation] = incrementedCountString
}
} else {
time.Sleep(time.Second * 1)
urAnnotations["generate.kyverno.io/retry-count"] = "1"
urAnnotations[kyvernov1beta1.URGenerateRetryCountAnnotation] = "1"
}
}
@ -182,7 +183,7 @@ func (c *GenerateController) ProcessUR(ur *urkyverno.UpdateRequest) error {
const doesNotApply = "policy does not apply to resource"
func (c *GenerateController) applyGenerate(resource unstructured.Unstructured, ur urkyverno.UpdateRequest, namespaceLabels map[string]string) ([]kyverno.ResourceSpec, bool, error) {
func (c *GenerateController) applyGenerate(resource unstructured.Unstructured, ur kyvernov1beta1.UpdateRequest, namespaceLabels map[string]string) ([]kyverno.ResourceSpec, bool, error) {
logger := c.log.WithValues("name", ur.GetName(), "policy", ur.Spec.Policy, "kind", ur.Spec.Resource.Kind, "apiVersion", ur.Spec.Resource.APIVersion, "namespace", ur.Spec.Resource.Namespace, "name", ur.Spec.Resource.Name)
logger.V(3).Info("applying generate policy rule")
@ -219,10 +220,10 @@ func (c *GenerateController) applyGenerate(resource unstructured.Unstructured, u
if r.Status != response.RuleStatusPass {
logger.V(4).Info("querying all update requests")
selector := labels.SelectorFromSet(labels.Set(map[string]string{
urkyverno.URGeneratePolicyLabel: engineResponse.PolicyResponse.Policy.Name,
"generate.kyverno.io/resource-name": engineResponse.PolicyResponse.Resource.Name,
"generate.kyverno.io/resource-kind": engineResponse.PolicyResponse.Resource.Kind,
"generate.kyverno.io/resource-namespace": engineResponse.PolicyResponse.Resource.Namespace,
kyvernov1beta1.URGeneratePolicyLabel: engineResponse.PolicyResponse.Policy.Name,
kyvernov1beta1.URGenerateResourceNameLabel: engineResponse.PolicyResponse.Resource.Name,
kyvernov1beta1.URGenerateResourceKindLabel: engineResponse.PolicyResponse.Resource.Kind,
kyvernov1beta1.URGenerateResourceNSLabel: engineResponse.PolicyResponse.Resource.Namespace,
}))
urList, err := c.urLister.List(selector)
if err != nil {
@ -271,7 +272,7 @@ func (c *GenerateController) cleanupClonedResource(targetSpec kyverno.ResourceSp
}
// getPolicySpec gets the policy spec from the ClusterPolicy/Policy
func (c *GenerateController) getPolicySpec(ur urkyverno.UpdateRequest) (kyverno.ClusterPolicy, error) {
func (c *GenerateController) getPolicySpec(ur kyvernov1beta1.UpdateRequest) (kyverno.ClusterPolicy, error) {
var policy kyverno.ClusterPolicy
pNamespace, pName, err := cache.SplitMetaNamespaceKey(ur.Spec.Policy)
@ -299,7 +300,7 @@ func (c *GenerateController) getPolicySpec(ur urkyverno.UpdateRequest) (kyverno.
}
}
func updateStatus(statusControl common.StatusControlInterface, ur urkyverno.UpdateRequest, err error, genResources []kyverno.ResourceSpec, precreatedResource bool) error {
func updateStatus(statusControl common.StatusControlInterface, ur kyvernov1beta1.UpdateRequest, err error, genResources []kyverno.ResourceSpec, precreatedResource bool) error {
if err != nil {
if _, err := statusControl.Failed(ur.GetName(), err.Error(), genResources); err != nil {
return err
@ -316,7 +317,7 @@ func updateStatus(statusControl common.StatusControlInterface, ur urkyverno.Upda
return nil
}
func (c *GenerateController) applyGeneratePolicy(log logr.Logger, policyContext *engine.PolicyContext, ur urkyverno.UpdateRequest, applicableRules []string) (genResources []kyverno.ResourceSpec, processExisting bool, err error) {
func (c *GenerateController) applyGeneratePolicy(log logr.Logger, policyContext *engine.PolicyContext, ur kyvernov1beta1.UpdateRequest, applicableRules []string) (genResources []kyverno.ResourceSpec, processExisting bool, err error) {
// Get the response as the actions to be performed on the resource
// - - substitute values
policy := policyContext.Policy
@ -398,7 +399,7 @@ func getResourceInfo(object map[string]interface{}) (kind, name, namespace, apiv
return
}
func applyRule(log logr.Logger, client dclient.Interface, rule kyverno.Rule, resource unstructured.Unstructured, ctx context.EvalInterface, policy kyverno.PolicyInterface, ur urkyverno.UpdateRequest) (kyverno.ResourceSpec, error) {
func applyRule(log logr.Logger, client dclient.Interface, rule kyverno.Rule, resource unstructured.Unstructured, ctx context.EvalInterface, policy kyverno.PolicyInterface, ur kyvernov1beta1.UpdateRequest) (kyverno.ResourceSpec, error) {
var rdata map[string]interface{}
var err error
var mode ResourceMode
@ -640,7 +641,7 @@ func getUnstrRule(rule *kyverno.Generation) (*unstructured.Unstructured, error)
return utils.ConvertToUnstructured(ruleData)
}
func deleteGeneratedResources(log logr.Logger, client dclient.Interface, ur urkyverno.UpdateRequest) error {
func deleteGeneratedResources(log logr.Logger, client dclient.Interface, ur kyvernov1beta1.UpdateRequest) error {
for _, genResource := range ur.Status.GeneratedResources {
err := client.DeleteResource("", genResource.Kind, genResource.Namespace, genResource.Name, false)
if err != nil && !apierrors.IsNotFound(err) {

View file

@ -10,7 +10,7 @@ import (
"time"
"github.com/go-logr/logr"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
utilscommon "github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/common"
"github.com/kyverno/kyverno/pkg/autogen"
@ -27,6 +27,7 @@ import (
"github.com/kyverno/kyverno/pkg/event"
"github.com/kyverno/kyverno/pkg/metrics"
"github.com/kyverno/kyverno/pkg/policyreport"
"github.com/kyverno/kyverno/pkg/toggle"
"github.com/kyverno/kyverno/pkg/utils"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
@ -152,7 +153,7 @@ func NewPolicyController(
return &pc, nil
}
func (pc *PolicyController) canBackgroundProcess(p kyverno.PolicyInterface) bool {
func (pc *PolicyController) canBackgroundProcess(p kyvernov1.PolicyInterface) bool {
logger := pc.log.WithValues("policy", p.GetName())
if !p.BackgroundProcessingEnabled() {
logger.V(4).Info("background processed is disabled")
@ -169,7 +170,7 @@ func (pc *PolicyController) canBackgroundProcess(p kyverno.PolicyInterface) bool
func (pc *PolicyController) addPolicy(obj interface{}) {
logger := pc.log
p := obj.(*kyverno.ClusterPolicy)
p := obj.(*kyvernov1.ClusterPolicy)
logger.Info("policy created", "uid", p.UID, "kind", "ClusterPolicy", "name", p.Name)
@ -178,11 +179,13 @@ func (pc *PolicyController) addPolicy(obj interface{}) {
// register kyverno_policy_changes_total metric concurrently
go pc.registerPolicyChangesMetricAddPolicy(logger, p)
if p.Spec.Background == nil || p.Spec.ValidationFailureAction == "" || missingAutoGenRules(p, logger) {
pol, _ := utilscommon.MutatePolicy(p, logger)
_, err := pc.kyvernoClient.KyvernoV1().ClusterPolicies().Update(context.TODO(), pol.(*kyverno.ClusterPolicy), metav1.UpdateOptions{})
if err != nil {
logger.Error(err, "failed to add policy ")
if !toggle.AutogenInternals() {
if p.Spec.Background == nil || p.Spec.ValidationFailureAction == "" || missingAutoGenRules(p, logger) {
pol, _ := utilscommon.MutatePolicy(p, logger)
_, err := pc.kyvernoClient.KyvernoV1().ClusterPolicies().Update(context.TODO(), pol.(*kyvernov1.ClusterPolicy), metav1.UpdateOptions{})
if err != nil {
logger.Error(err, "failed to add policy ")
}
}
}
@ -196,19 +199,21 @@ func (pc *PolicyController) addPolicy(obj interface{}) {
func (pc *PolicyController) updatePolicy(old, cur interface{}) {
logger := pc.log
oldP := old.(*kyverno.ClusterPolicy)
curP := cur.(*kyverno.ClusterPolicy)
oldP := old.(*kyvernov1.ClusterPolicy)
curP := cur.(*kyvernov1.ClusterPolicy)
// register kyverno_policy_rule_info_total metric concurrently
go pc.registerPolicyRuleInfoMetricUpdatePolicy(logger, oldP, curP)
// register kyverno_policy_changes_total metric concurrently
go pc.registerPolicyChangesMetricUpdatePolicy(logger, oldP, curP)
if curP.Spec.Background == nil || curP.Spec.ValidationFailureAction == "" || missingAutoGenRules(curP, logger) {
pol, _ := utilscommon.MutatePolicy(curP, logger)
_, err := pc.kyvernoClient.KyvernoV1().ClusterPolicies().Update(context.TODO(), pol.(*kyverno.ClusterPolicy), metav1.UpdateOptions{})
if err != nil {
logger.Error(err, "failed to update policy ")
if !toggle.AutogenInternals() {
if curP.Spec.Background == nil || curP.Spec.ValidationFailureAction == "" || missingAutoGenRules(curP, logger) {
pol, _ := utilscommon.MutatePolicy(curP, logger)
_, err := pc.kyvernoClient.KyvernoV1().ClusterPolicies().Update(context.TODO(), pol.(*kyvernov1.ClusterPolicy), metav1.UpdateOptions{})
if err != nil {
logger.Error(err, "failed to update policy ")
}
}
}
@ -228,14 +233,14 @@ func (pc *PolicyController) updatePolicy(old, cur interface{}) {
func (pc *PolicyController) deletePolicy(obj interface{}) {
logger := pc.log
p, ok := obj.(*kyverno.ClusterPolicy)
p, ok := obj.(*kyvernov1.ClusterPolicy)
if !ok {
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
if !ok {
logger.Info("couldn't get object from tombstone", "obj", obj)
return
}
p, ok = tombstone.Obj.(*kyverno.ClusterPolicy)
p, ok = tombstone.Obj.(*kyvernov1.ClusterPolicy)
if !ok {
logger.Info("tombstone container object that is not a policy", "obj", obj)
return
@ -264,7 +269,7 @@ func (pc *PolicyController) deletePolicy(obj interface{}) {
func (pc *PolicyController) addNsPolicy(obj interface{}) {
logger := pc.log
p := obj.(*kyverno.Policy)
p := obj.(*kyvernov1.Policy)
// register kyverno_policy_rule_info_total metric concurrently
go pc.registerPolicyRuleInfoMetricAddPolicy(logger, p)
@ -273,14 +278,17 @@ func (pc *PolicyController) addNsPolicy(obj interface{}) {
logger.Info("policy created", "uid", p.UID, "kind", "Policy", "name", p.Name, "namespaces", p.Namespace)
spec := p.GetSpec()
if spec.Background == nil || spec.ValidationFailureAction == "" || missingAutoGenRules(p, logger) {
nsPol, _ := utilscommon.MutatePolicy(p, logger)
_, err := pc.kyvernoClient.KyvernoV1().Policies(p.Namespace).Update(context.TODO(), nsPol.(*kyverno.Policy), metav1.UpdateOptions{})
if err != nil {
logger.Error(err, "failed to add namespace policy")
if !toggle.AutogenInternals() {
spec := p.GetSpec()
if spec.Background == nil || spec.ValidationFailureAction == "" || missingAutoGenRules(p, logger) {
nsPol, _ := utilscommon.MutatePolicy(p, logger)
_, err := pc.kyvernoClient.KyvernoV1().Policies(p.Namespace).Update(context.TODO(), nsPol.(*kyvernov1.Policy), metav1.UpdateOptions{})
if err != nil {
logger.Error(err, "failed to add namespace policy")
}
}
}
if !pc.canBackgroundProcess(p) {
return
}
@ -290,19 +298,21 @@ func (pc *PolicyController) addNsPolicy(obj interface{}) {
func (pc *PolicyController) updateNsPolicy(old, cur interface{}) {
logger := pc.log
oldP := old.(*kyverno.Policy)
curP := cur.(*kyverno.Policy)
oldP := old.(*kyvernov1.Policy)
curP := cur.(*kyvernov1.Policy)
// register kyverno_policy_rule_info_total metric concurrently
go pc.registerPolicyRuleInfoMetricUpdatePolicy(logger, oldP, curP)
// register kyverno_policy_changes_total metric concurrently
go pc.registerPolicyChangesMetricUpdatePolicy(logger, oldP, curP)
if curP.Spec.Background == nil || curP.Spec.ValidationFailureAction == "" || missingAutoGenRules(curP, logger) {
nsPol, _ := utilscommon.MutatePolicy(curP, logger)
_, err := pc.kyvernoClient.KyvernoV1().Policies(curP.GetNamespace()).Update(context.TODO(), nsPol.(*kyverno.Policy), metav1.UpdateOptions{})
if err != nil {
logger.Error(err, "failed to update namespace policy ")
if !toggle.AutogenInternals() {
if curP.Spec.Background == nil || curP.Spec.ValidationFailureAction == "" || missingAutoGenRules(curP, logger) {
nsPol, _ := utilscommon.MutatePolicy(curP, logger)
_, err := pc.kyvernoClient.KyvernoV1().Policies(curP.GetNamespace()).Update(context.TODO(), nsPol.(*kyvernov1.Policy), metav1.UpdateOptions{})
if err != nil {
logger.Error(err, "failed to update namespace policy ")
}
}
}
@ -322,14 +332,14 @@ func (pc *PolicyController) updateNsPolicy(old, cur interface{}) {
func (pc *PolicyController) deleteNsPolicy(obj interface{}) {
logger := pc.log
p, ok := obj.(*kyverno.Policy)
p, ok := obj.(*kyvernov1.Policy)
if !ok {
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
if !ok {
logger.Info("couldn't get object from tombstone", "obj", obj)
return
}
p, ok = tombstone.Obj.(*kyverno.Policy)
p, ok = tombstone.Obj.(*kyvernov1.Policy)
if !ok {
logger.Info("tombstone container object that is not a policy", "obj", obj)
return
@ -358,7 +368,7 @@ func (pc *PolicyController) deleteNsPolicy(obj interface{}) {
pc.enqueuePolicy(pol)
}
func (pc *PolicyController) enqueueRCRDeletedRule(old, cur kyverno.PolicyInterface) {
func (pc *PolicyController) enqueueRCRDeletedRule(old, cur kyvernov1.PolicyInterface) {
curRule := make(map[string]bool)
for _, rule := range autogen.ComputeRules(cur) {
curRule[rule.Name] = true
@ -370,7 +380,7 @@ func (pc *PolicyController) enqueueRCRDeletedRule(old, cur kyverno.PolicyInterfa
PolicyName: cur.GetName(),
Results: []policyreport.EngineResponseResult{
{
Rules: []kyverno.ViolatedRule{
Rules: []kyvernov1.ViolatedRule{
{Name: rule.Name},
},
},
@ -386,7 +396,7 @@ func (pc *PolicyController) enqueueRCRDeletedPolicy(policyName string) {
})
}
func (pc *PolicyController) enqueuePolicy(policy kyverno.PolicyInterface) {
func (pc *PolicyController) enqueuePolicy(policy kyvernov1.PolicyInterface) {
logger := pc.log
key, err := cache.MetaNamespaceKeyFunc(policy)
if err != nil {
@ -493,7 +503,7 @@ func (pc *PolicyController) syncPolicy(key string) error {
return nil
}
func (pc *PolicyController) getPolicy(key string) (policy kyverno.PolicyInterface, err error) {
func (pc *PolicyController) getPolicy(key string) (policy kyvernov1.PolicyInterface, err error) {
namespace, key, isNamespacedPolicy := ParseNamespacedPolicy(key)
if !isNamespacedPolicy {
return pc.pLister.Get(key)
@ -507,7 +517,7 @@ func (pc *PolicyController) getPolicy(key string) (policy kyverno.PolicyInterfac
return
}
func generateTriggers(client client.Interface, rule kyverno.Rule, log logr.Logger) []*unstructured.Unstructured {
func generateTriggers(client client.Interface, rule kyvernov1.Rule, log logr.Logger) []*unstructured.Unstructured {
list := &unstructured.UnstructuredList{}
kinds := fetchUniqueKinds(rule)
@ -559,7 +569,7 @@ func updateUR(kyvernoClient kyvernoclient.Interface, urLister kyvernov1beta1list
}
}
func missingAutoGenRules(policy kyverno.PolicyInterface, log logr.Logger) bool {
func missingAutoGenRules(policy kyvernov1.PolicyInterface, log logr.Logger) bool {
var podRuleName []string
ruleCount := 1
spec := policy.GetSpec()
@ -571,7 +581,7 @@ func missingAutoGenRules(policy kyverno.PolicyInterface, log logr.Logger) bool {
if len(podRuleName) > 0 {
annotations := policy.GetAnnotations()
val, ok := annotations[kyverno.PodControllersAnnotation]
val, ok := annotations[kyvernov1.PodControllersAnnotation]
if !ok {
return true
}

View file

@ -6,7 +6,7 @@ import (
"github.com/gardener/controller-manager-library/pkg/logger"
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
urkyverno "github.com/kyverno/kyverno/api/kyverno/v1beta1"
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
common "github.com/kyverno/kyverno/pkg/background/common"
"github.com/kyverno/kyverno/pkg/config"
"github.com/kyverno/kyverno/pkg/engine"
@ -35,10 +35,10 @@ func (pc *PolicyController) updateUR(policyKey string, policy kyverno.PolicyInte
updateUR(pc.kyvernoClient, pc.urLister.UpdateRequests(config.KyvernoNamespace), policyKey, append(mutateURs, generateURs...), pc.log.WithName("updateUR"))
for _, rule := range policy.GetSpec().Rules {
var ruleType urkyverno.RequestType
var ruleType kyvernov1beta1.RequestType
if rule.IsMutateExisting() {
ruleType = urkyverno.Mutate
ruleType = kyvernov1beta1.Mutate
triggers := generateTriggers(pc.client, rule, pc.log)
for _, trigger := range triggers {
@ -65,7 +65,7 @@ func (pc *PolicyController) updateUR(policyKey string, policy kyverno.PolicyInte
}
}
if policy.GetSpec().IsGenerateExistingOnPolicyUpdate() {
ruleType = urkyverno.Generate
ruleType = kyvernov1beta1.Generate
triggers := generateTriggers(pc.client, rule, pc.log)
for _, trigger := range triggers {
gurs := pc.listGenerateURs(policyKey, trigger)
@ -98,7 +98,7 @@ func (pc *PolicyController) updateUR(policyKey string, policy kyverno.PolicyInte
return nil
}
func (pc *PolicyController) handleUpdateRequest(ur *urkyverno.UpdateRequest, triggerResource *unstructured.Unstructured, rule kyverno.Rule, policy kyverno.PolicyInterface) (skip bool, err error) {
func (pc *PolicyController) handleUpdateRequest(ur *kyvernov1beta1.UpdateRequest, triggerResource *unstructured.Unstructured, rule kyverno.Rule, policy kyverno.PolicyInterface) (skip bool, err error) {
policyContext, _, err := common.NewBackgroundContext(pc.client, ur, policy, triggerResource, pc.configHandler, nil, pc.log)
if err != nil {
return false, errors.Wrapf(err, "failed to build policy context for rule %s", rule.Name)
@ -124,27 +124,23 @@ func (pc *PolicyController) handleUpdateRequest(ur *urkyverno.UpdateRequest, tri
return false, err
}
func (pc *PolicyController) listMutateURs(policyKey string, trigger *unstructured.Unstructured) []*urkyverno.UpdateRequest {
selector := createMutateLabels(policyKey, trigger)
mutateURs, err := pc.urLister.List(labels.SelectorFromSet(selector))
func (pc *PolicyController) listMutateURs(policyKey string, trigger *unstructured.Unstructured) []*kyvernov1beta1.UpdateRequest {
mutateURs, err := pc.urLister.List(labels.SelectorFromSet(common.MutateLabelsSet(policyKey, trigger)))
if err != nil {
logger.Error(err, "failed to list update request for mutate policy")
}
return mutateURs
}
func (pc *PolicyController) listGenerateURs(policyKey string, trigger *unstructured.Unstructured) []*urkyverno.UpdateRequest {
selector := createGenerateLabels(policyKey, trigger)
generateURs, err := pc.urLister.List(labels.SelectorFromSet(selector))
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 {
logger.Error(err, "failed to list update request for generate policy")
}
return generateURs
}
func newUR(policy kyverno.PolicyInterface, trigger *unstructured.Unstructured, ruleType urkyverno.RequestType) *urkyverno.UpdateRequest {
func newUR(policy kyverno.PolicyInterface, trigger *unstructured.Unstructured, ruleType kyvernov1beta1.RequestType) *kyvernov1beta1.UpdateRequest {
var policyNameNamespaceKey string
if policy.IsNamespaced() {
@ -154,19 +150,19 @@ func newUR(policy kyverno.PolicyInterface, trigger *unstructured.Unstructured, r
}
var label labels.Set
if ruleType == urkyverno.Mutate {
label = createMutateLabels(policyNameNamespaceKey, trigger)
if ruleType == kyvernov1beta1.Mutate {
label = common.MutateLabelsSet(policyNameNamespaceKey, trigger)
} else {
label = createGenerateLabels(policyNameNamespaceKey, trigger)
label = common.GenerateLabelsSet(policyNameNamespaceKey, trigger)
}
return &urkyverno.UpdateRequest{
return &kyvernov1beta1.UpdateRequest{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "ur-",
Namespace: config.KyvernoNamespace,
Labels: label,
},
Spec: urkyverno.UpdateRequestSpec{
Spec: kyvernov1beta1.UpdateRequestSpec{
Type: ruleType,
Policy: policyNameNamespaceKey,
Resource: kyverno.ResourceSpec{
@ -178,44 +174,3 @@ func newUR(policy kyverno.PolicyInterface, trigger *unstructured.Unstructured, r
},
}
}
func createMutateLabels(policyKey string, trigger *unstructured.Unstructured) labels.Set {
var selector labels.Set
if trigger == nil {
selector = labels.Set(map[string]string{
urkyverno.URMutatePolicyLabel: policyKey,
})
} else {
selector = labels.Set(map[string]string{
urkyverno.URMutatePolicyLabel: policyKey,
urkyverno.URMutateTriggerNameLabel: trigger.GetName(),
urkyverno.URMutateTriggerNSLabel: trigger.GetNamespace(),
urkyverno.URMutatetriggerKindLabel: trigger.GetKind(),
})
if trigger.GetAPIVersion() != "" {
selector[urkyverno.URMutatetriggerAPIVersionLabel] = trigger.GetAPIVersion()
}
}
return selector
}
func createGenerateLabels(policyKey string, trigger *unstructured.Unstructured) labels.Set {
var selector labels.Set
if trigger == nil {
selector = labels.Set(map[string]string{
urkyverno.URGeneratePolicyLabel: policyKey,
})
} else {
selector = labels.Set(map[string]string{
urkyverno.URGeneratePolicyLabel: policyKey,
"generate.kyverno.io/resource-name": trigger.GetName(),
"generate.kyverno.io/resource-kind": trigger.GetKind(),
"generate.kyverno.io/resource-namespace": trigger.GetNamespace(),
})
}
return selector
}

View file

@ -374,7 +374,7 @@ func (ws *WebhookServer) deleteGR(logger logr.Logger, engineResponse *response.E
}
}
func applyUpdateRequest(request *admissionv1.AdmissionRequest, ruleType kyvernov1beta1.RequestType, grGenerator updaterequest.Interface, userRequestInfo kyvernov1beta1.RequestInfo,
func applyUpdateRequest(request *admissionv1.AdmissionRequest, ruleType kyvernov1beta1.RequestType, grGenerator updaterequest.Generator, userRequestInfo kyvernov1beta1.RequestInfo,
action admissionv1.Operation, engineResponses ...*response.EngineResponse) (failedUpdateRequest []updateRequestResponse) {
requestBytes, err := json.Marshal(request)

View file

@ -77,7 +77,7 @@ type WebhookServer struct {
prGenerator policyreport.GeneratorInterface
// update request generator
urGenerator webhookgenerate.Interface
urGenerator webhookgenerate.Generator
auditHandler AuditHandler
@ -111,7 +111,7 @@ func NewWebhookServer(
webhookMonitor *webhookconfig.Monitor,
configHandler config.Configuration,
prGenerator policyreport.GeneratorInterface,
urGenerator webhookgenerate.Interface,
urGenerator webhookgenerate.Generator,
auditHandler AuditHandler,
cleanUp chan<- struct{},
log logr.Logger,

View file

@ -5,197 +5,55 @@ import (
"time"
backoff "github.com/cenkalti/backoff"
"github.com/gardener/controller-manager-library/pkg/logger"
"github.com/go-logr/logr"
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/background/common"
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
urkyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1beta1"
urkyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1beta1"
kyvernov1beta1informers "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1beta1"
kyvernov1beta1listers "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/config"
admissionv1 "k8s.io/api/admission/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/retry"
)
// UpdateRequest provides interface to manage update requests
type Interface interface {
// Generator provides interface to manage update requests
type Generator interface {
Apply(gr kyvernov1beta1.UpdateRequestSpec, action admissionv1.Operation) error
}
// info object stores message data to create update request
type info struct {
spec kyvernov1beta1.UpdateRequestSpec
action admissionv1.Operation
}
// Generator defines the implementation to mange update request resource
type Generator struct {
// generator defines the implementation to manage update request resource
type generator struct {
// clients
client kyvernoclient.Interface
stopCh <-chan struct{}
log logr.Logger
urLister urkyvernolister.UpdateRequestNamespaceLister
// listers
urLister kyvernov1beta1listers.UpdateRequestNamespaceLister
}
// NewGenerator returns a new instance of UpdateRequest resource generator
func NewGenerator(client kyvernoclient.Interface, urInformer urkyvernoinformer.UpdateRequestInformer, stopCh <-chan struct{}, log logr.Logger) *Generator {
gen := &Generator{
func NewGenerator(client kyvernoclient.Interface, urInformer kyvernov1beta1informers.UpdateRequestInformer) Generator {
return &generator{
client: client,
stopCh: stopCh,
log: log,
urLister: urInformer.Lister().UpdateRequests(config.KyvernoNamespace),
}
return gen
}
// Apply creates update request resource
func (g *Generator) Apply(ur kyvernov1beta1.UpdateRequestSpec, action admissionv1.Operation) error {
logger := g.log
func (g *generator) Apply(ur kyvernov1beta1.UpdateRequestSpec, action admissionv1.Operation) error {
logger.V(4).Info("reconcile Update Request", "request", ur)
message := info{
action: action,
spec: ur,
}
go g.processApply(message)
return nil
}
// Run starts the update request spec
func (g *Generator) Run(workers int, stopCh <-chan struct{}) {
logger := g.log
defer utilruntime.HandleCrash()
logger.V(4).Info("starting")
defer func() {
logger.V(4).Info("shutting down")
}()
<-g.stopCh
}
func (g *Generator) processApply(i info) {
if err := g.generate(i); err != nil {
logger.Error(err, "failed to update request CR")
}
}
func (g *Generator) generate(i info) error {
if err := retryApplyResource(g.client, i.spec, g.log, i.action, g.urLister); err != nil {
return err
}
return nil
}
func retryApplyResource(client kyvernoclient.Interface, urSpec kyvernov1beta1.UpdateRequestSpec,
log logr.Logger, action admissionv1.Operation, urLister urkyvernolister.UpdateRequestNamespaceLister) error {
if action == admissionv1.Delete && urSpec.Type == kyvernov1beta1.Generate {
if action == admissionv1.Delete && ur.Type == kyvernov1beta1.Generate {
return nil
}
var i int
var err error
_, policyName, err := cache.SplitMetaNamespaceKey(urSpec.Policy)
_, policyName, err := cache.SplitMetaNamespaceKey(ur.Policy)
if err != nil {
return err
}
go g.applyResource(policyName, ur)
return nil
}
applyResource := func() error {
ur := kyvernov1beta1.UpdateRequest{
Spec: urSpec,
Status: kyvernov1beta1.UpdateRequestStatus{
State: kyvernov1beta1.Pending,
},
}
queryLabels := make(map[string]string)
if ur.Spec.Type == kyvernov1beta1.Mutate {
queryLabels := map[string]string{
kyvernov1beta1.URMutatePolicyLabel: ur.Spec.Policy,
"mutate.updaterequest.kyverno.io/trigger-name": ur.Spec.Resource.Name,
"mutate.updaterequest.kyverno.io/trigger-namespace": ur.Spec.Resource.Namespace,
"mutate.updaterequest.kyverno.io/trigger-kind": ur.Spec.Resource.Kind,
}
if ur.Spec.Resource.APIVersion != "" {
queryLabels["mutate.updaterequest.kyverno.io/trigger-apiversion"] = ur.Spec.Resource.APIVersion
}
} else if ur.Spec.Type == kyvernov1beta1.Generate {
queryLabels = labels.Set(map[string]string{
kyvernov1beta1.URGeneratePolicyLabel: policyName,
"generate.kyverno.io/resource-name": urSpec.Resource.Name,
"generate.kyverno.io/resource-kind": urSpec.Resource.Kind,
"generate.kyverno.io/resource-namespace": urSpec.Resource.Namespace,
})
}
ur.SetNamespace(config.KyvernoNamespace)
isExist := false
log.V(4).Info("apply UpdateRequest", "ruleType", ur.Spec.Type)
urList, err := urLister.List(labels.SelectorFromSet(queryLabels))
if err != nil {
log.Error(err, "failed to get update request for the resource", "kind", urSpec.Resource.Kind, "name", urSpec.Resource.Name, "namespace", urSpec.Resource.Namespace)
return err
}
for _, v := range urList {
log.V(4).Info("updating existing update request", "name", v.GetName())
v.Spec.Context = ur.Spec.Context
v.Spec.Policy = ur.Spec.Policy
v.Spec.Resource = ur.Spec.Resource
v.Status.Message = ""
new, err := client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Update(context.TODO(), v, metav1.UpdateOptions{})
if err != nil {
log.V(4).Info("failed to update UpdateRequest, retrying", "retryCount", i, "name", ur.GetName(), "namespace", ur.GetNamespace(), "err", err.Error())
i++
return err
} else {
log.V(4).Info("successfully updated UpdateRequest", "retryCount", i, "name", ur.GetName(), "namespace", ur.GetNamespace())
}
err = retry.RetryOnConflict(common.DefaultRetry, func() error {
ur, err := client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Get(context.TODO(), new.GetName(), metav1.GetOptions{})
if err != nil {
return err
}
ur.Status.State = kyvernov1beta1.Pending
_, err = client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).UpdateStatus(context.TODO(), ur, metav1.UpdateOptions{})
return err
})
if err != nil {
log.Error(err, "failed to set UpdateRequest state to Pending")
return err
}
isExist = true
}
if !isExist {
log.V(4).Info("creating new UpdateRequest", "type", ur.Spec.Type)
ur.SetGenerateName("ur-")
ur.SetLabels(queryLabels)
new, err := client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Create(context.TODO(), &ur, metav1.CreateOptions{})
if err != nil {
log.V(4).Info("failed to create UpdateRequest, retrying", "retryCount", i, "name", ur.GetGenerateName(), "namespace", ur.GetNamespace(), "err", err.Error())
i++
return err
} else {
log.V(4).Info("successfully created UpdateRequest", "retryCount", i, "name", new.GetName(), "namespace", ur.GetNamespace())
}
}
return nil
}
func (g *generator) applyResource(policyName string, urSpec kyvernov1beta1.UpdateRequestSpec) {
exbackoff := &backoff.ExponentialBackOff{
InitialInterval: 500 * time.Millisecond,
RandomizationFactor: 0.5,
@ -204,13 +62,57 @@ func retryApplyResource(client kyvernoclient.Interface, urSpec kyvernov1beta1.Up
MaxElapsedTime: 3 * time.Second,
Clock: backoff.SystemClock,
}
exbackoff.Reset()
err = backoff.Retry(applyResource, exbackoff)
if err := backoff.Retry(func() error { return g.tryApplyResource(policyName, urSpec) }, exbackoff); err != nil {
logger.Error(err, "failed to update request CR")
}
}
func (g *generator) tryApplyResource(policyName string, urSpec kyvernov1beta1.UpdateRequestSpec) error {
l := logger.WithValues("ruleType", urSpec.Type, "kind", urSpec.Resource.Kind, "name", urSpec.Resource.Name, "namespace", urSpec.Resource.Namespace)
var queryLabels labels.Set
if urSpec.Type == kyvernov1beta1.Mutate {
queryLabels = common.MutateLabelsSet(urSpec.Policy, urSpec.Resource)
} else if urSpec.Type == kyvernov1beta1.Generate {
queryLabels = common.GenerateLabelsSet(urSpec.Policy, urSpec.Resource)
}
urList, err := g.urLister.List(labels.SelectorFromSet(queryLabels))
if err != nil {
l.Error(err, "failed to get update request for the resource", "kind", urSpec.Resource.Kind, "name", urSpec.Resource.Name, "namespace", urSpec.Resource.Namespace)
return err
}
for _, v := range urList {
l := l.WithValues("name", v.GetName())
l.V(4).Info("updating existing update request")
if _, err := common.Update(g.client, g.urLister, v.GetName(), func(ur *kyvernov1beta1.UpdateRequest) {
v.Spec = urSpec
}); err != nil {
l.V(4).Error(err, "failed to update UpdateRequest")
return err
} else {
l.V(4).Info("successfully updated UpdateRequest")
}
if _, err := common.UpdateStatus(g.client, g.urLister, v.GetName(), kyvernov1beta1.Pending, "", nil); err != nil {
l.V(4).Error(err, "failed to update UpdateRequest status")
return err
}
}
if len(urList) == 0 {
l.V(4).Info("creating new UpdateRequest")
ur := kyvernov1beta1.UpdateRequest{
ObjectMeta: metav1.ObjectMeta{
Namespace: config.KyvernoNamespace,
GenerateName: "ur-",
Labels: queryLabels,
},
Spec: urSpec,
}
if new, err := g.client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace).Create(context.TODO(), &ur, metav1.CreateOptions{}); 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())
}
}
return nil
}

View file

@ -0,0 +1,5 @@
package updaterequest
import "sigs.k8s.io/controller-runtime/pkg/log"
var logger = log.Log.WithName("updaterequest-generator")