1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-04-08 10:04:25 +00:00

refactor: introduce ur updater ()

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>

Signed-off-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>
This commit is contained in:
Charles-Edouard Brétéché 2022-09-08 14:07:18 +02:00 committed by GitHub
parent aa6abd99f2
commit ed31fb0326
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 167 additions and 24 deletions

View file

@ -35,6 +35,7 @@ func NewFakeHandlers(ctx context.Context, policyCache policycache.Cache) webhook
configuration := config.NewFakeConfig()
rbLister := informers.Rbac().V1().RoleBindings().Lister()
crbLister := informers.Rbac().V1().ClusterRoleBindings().Lister()
urLister := kyvernoInformers.Kyverno().V1beta1().UpdateRequests().Lister().UpdateRequests(config.KyvernoNamespace())
return &handlers{
client: dclient,
@ -44,13 +45,14 @@ func NewFakeHandlers(ctx context.Context, policyCache policycache.Cache) webhook
nsLister: informers.Core().V1().Namespaces().Lister(),
rbLister: rbLister,
crbLister: crbLister,
urLister: kyvernoInformers.Kyverno().V1beta1().UpdateRequests().Lister().UpdateRequests(config.KyvernoNamespace()),
urLister: urLister,
prGenerator: policyreport.NewFake(),
urGenerator: updaterequest.NewFake(),
eventGen: event.NewFake(),
auditHandler: newFakeAuditHandler(),
openAPIController: openapi.NewFake(),
pcBuilder: webhookutils.NewPolicyContextBuilder(configuration, dclient, rbLister, crbLister),
urUpdater: webhookutils.NewUpdateRequestUpdater(kyvernoclient, urLister),
}
}

View file

@ -10,7 +10,6 @@ import (
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/autogen"
gencommon "github.com/kyverno/kyverno/pkg/background/common"
gen "github.com/kyverno/kyverno/pkg/background/generate"
"github.com/kyverno/kyverno/pkg/common"
"github.com/kyverno/kyverno/pkg/config"
@ -131,31 +130,12 @@ func (h *handlers) handleUpdateGenerateSourceResource(resLabels map[string]strin
}
for _, ur := range urList {
h.updateAnnotationInUR(ur, logger)
h.urUpdater.UpdateAnnotation(logger, ur.GetName())
}
}
}
}
// updateAnnotationInUR - function used to update UR annotation
// updating UR will trigger reprocessing of UR and recreation/updation of generated resource
func (h *handlers) updateAnnotationInUR(ur *kyvernov1beta1.UpdateRequest, logger logr.Logger) {
if _, err := gencommon.Update(h.kyvernoClient, h.urLister, ur.GetName(), func(ur *kyvernov1beta1.UpdateRequest) {
urAnnotations := ur.Annotations
if len(urAnnotations) == 0 {
urAnnotations = make(map[string]string)
}
urAnnotations["generate.kyverno.io/updation-time"] = time.Now().String()
ur.SetAnnotations(urAnnotations)
}); err != nil {
logger.Error(err, "failed to update update request update-time annotations for the resource", "update request", ur.Name)
return
}
if _, err := gencommon.UpdateStatus(h.kyvernoClient, h.urLister, ur.GetName(), kyvernov1beta1.Pending, "", nil); err != nil {
logger.Error(err, "failed to set UpdateRequest state to Pending", "update request", ur.Name)
}
}
// handleUpdateGenerateTargetResource - handles update of target resource for generate policy
func (h *handlers) handleUpdateGenerateTargetResource(request *admissionv1.AdmissionRequest, policies []kyvernov1.PolicyInterface, resLabels map[string]string, logger logr.Logger) {
enqueueBool := false
@ -214,7 +194,7 @@ func (h *handlers) handleUpdateGenerateTargetResource(request *admissionv1.Admis
logger.Error(err, "failed to get update request", "name", urName)
return
}
h.updateAnnotationInUR(ur, logger)
h.urUpdater.UpdateAnnotation(logger, ur.GetName())
}
}

View file

@ -61,6 +61,7 @@ type handlers struct {
auditHandler AuditHandler
openAPIController openapi.ValidateInterface
pcBuilder webhookutils.PolicyContextBuilder
urUpdater webhookutils.UpdateRequestUpdater
}
func NewHandlers(
@ -95,6 +96,7 @@ func NewHandlers(
auditHandler: auditHandler,
openAPIController: openAPIController,
pcBuilder: webhookutils.NewPolicyContextBuilder(configuration, client, rbLister, crbLister),
urUpdater: webhookutils.NewUpdateRequestUpdater(kyvernoClient, urLister),
}
}
@ -406,6 +408,6 @@ func (h *handlers) handleDelete(logger logr.Logger, request *admissionv1.Admissi
if ur.Spec.Type == kyvernov1beta1.Mutate {
return
}
h.updateAnnotationInUR(ur, logger)
h.urUpdater.UpdateAnnotation(logger, ur.GetName())
}
}

View file

@ -0,0 +1,52 @@
package utils
import (
"time"
"github.com/go-logr/logr"
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/background/common"
"github.com/kyverno/kyverno/pkg/client/clientset/versioned"
kyvernov1beta1listers "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1beta1"
)
type UpdateRequestUpdater interface {
// UpdateAnnotation updates UR annotation, triggering reprocessing of UR and recreation/updation of generated resource
UpdateAnnotation(logger logr.Logger, name string)
}
type updateRequestUpdater struct {
client versioned.Interface
lister kyvernov1beta1listers.UpdateRequestNamespaceLister
}
func NewUpdateRequestUpdater(client versioned.Interface, lister kyvernov1beta1listers.UpdateRequestNamespaceLister) UpdateRequestUpdater {
return &updateRequestUpdater{
client: client,
lister: lister,
}
}
func (h *updateRequestUpdater) updateAnnotation(logger logr.Logger, name string) {
if _, err := common.Update(h.client, h.lister, name, func(ur *kyvernov1beta1.UpdateRequest) {
urAnnotations := ur.Annotations
if len(urAnnotations) == 0 {
urAnnotations = make(map[string]string)
}
urAnnotations["generate.kyverno.io/updation-time"] = time.Now().String()
ur.SetAnnotations(urAnnotations)
}); err != nil {
logger.Error(err, "failed to update update request update-time annotations for the resource", "update request", name)
}
}
func (h *updateRequestUpdater) setPendingStatus(logger logr.Logger, name string) {
if _, err := common.UpdateStatus(h.client, h.lister, name, kyvernov1beta1.Pending, "", nil); err != nil {
logger.Error(err, "failed to set UpdateRequest state to Pending", "update request", name)
}
}
func (h *updateRequestUpdater) UpdateAnnotation(logger logr.Logger, name string) {
h.updateAnnotation(logger, name)
h.setPendingStatus(logger, name)
}

View file

@ -0,0 +1,107 @@
package utils
import (
"context"
"testing"
"github.com/go-logr/logr"
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/client/clientset/versioned"
"github.com/kyverno/kyverno/pkg/client/clientset/versioned/fake"
kyvernoinformers "github.com/kyverno/kyverno/pkg/client/informers/externalversions"
kyvernov1beta1listers "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1beta1"
"github.com/kyverno/kyverno/pkg/config"
"github.com/stretchr/testify/assert"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
func TestNewUpdateRequestUpdater(t *testing.T) {
type args struct {
client versioned.Interface
lister kyvernov1beta1listers.UpdateRequestNamespaceLister
}
tests := []struct {
name string
args args
want UpdateRequestUpdater
}{{
name: "nil",
args: args{nil, nil},
want: &updateRequestUpdater{nil, nil},
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := NewUpdateRequestUpdater(tt.args.client, tt.args.lister)
assert.Equal(t, tt.want, got)
})
}
}
func Test_updateRequestUpdater_updateAnnotation(t *testing.T) {
type data struct {
objects []runtime.Object
}
tests := []struct {
name string
data data
urName string
updated bool
}{{
name: "success",
data: data{
[]runtime.Object{
&kyvernov1beta1.UpdateRequest{
ObjectMeta: v1.ObjectMeta{
Name: "test",
Namespace: config.KyvernoNamespace(),
},
},
},
},
urName: "test",
updated: true,
}, {
name: "not found",
data: data{
[]runtime.Object{
&kyvernov1beta1.UpdateRequest{
ObjectMeta: v1.ObjectMeta{
Name: "dummy",
Namespace: config.KyvernoNamespace(),
},
},
},
},
urName: "dummy",
updated: false,
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
done := ctx.Done()
t.Cleanup(cancel)
client := fake.NewSimpleClientset(tt.data.objects...)
kyvernoInformers := kyvernoinformers.NewSharedInformerFactory(client, 0)
lister := kyvernoInformers.Kyverno().V1beta1().UpdateRequests().Lister().UpdateRequests(config.KyvernoNamespace())
kyvernoInformers.Start(done)
kyvernoInformers.WaitForCacheSync(done)
h := &updateRequestUpdater{
client: client,
lister: lister,
}
h.updateAnnotation(logr.Discard(), "test")
ur, err := client.KyvernoV1beta1().UpdateRequests(config.KyvernoNamespace()).Get(ctx, tt.urName, v1.GetOptions{})
assert.NoError(t, err)
assert.NotNil(t, ur)
if tt.updated {
annotations := ur.GetAnnotations()
assert.NotNil(t, annotations)
assert.NotNil(t, annotations["generate.kyverno.io/updation-time"])
} else {
annotations := ur.GetAnnotations()
assert.Nil(t, annotations)
}
})
}
}