From a8eed56c6c999606fab01e3cd1dcf024e1bb2a29 Mon Sep 17 00:00:00 2001 From: Vishal Choudhary Date: Tue, 17 Dec 2024 13:59:11 +0530 Subject: [PATCH] feat: sort policies in alphabetical order before executing (#254) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Vishal Choudhary Signed-off-by: Vishal Choudhary Co-authored-by: Charles-Edouard Brétéché --- go.mod | 2 +- pkg/policy/provider.go | 55 ++++++++++++++++++++++++++++++------------ 2 files changed, 40 insertions(+), 17 deletions(-) diff --git a/go.mod b/go.mod index 2c8d4da6..0a427a4d 100644 --- a/go.mod +++ b/go.mod @@ -65,7 +65,7 @@ require ( github.com/stoewer/go-strcase v1.3.0 // indirect github.com/x448/float16 v0.8.4 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect + golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c golang.org/x/net v0.30.0 // indirect golang.org/x/oauth2 v0.23.0 // indirect golang.org/x/sys v0.26.0 // indirect diff --git a/pkg/policy/provider.go b/pkg/policy/provider.go index 55e7f49e..3b7ae500 100644 --- a/pkg/policy/provider.go +++ b/pkg/policy/provider.go @@ -1,13 +1,15 @@ package policy import ( + "cmp" "context" "fmt" + "slices" "sync" "github.com/kyverno/kyverno-envoy-plugin/apis/v1alpha1" + "golang.org/x/exp/maps" "k8s.io/apimachinery/pkg/api/errors" - "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -25,28 +27,54 @@ func NewKubeProvider(mgr ctrl.Manager, compiler Compiler) (Provider, error) { } type policyReconciler struct { - client client.Client - compiler Compiler - lock *sync.RWMutex - policies map[types.NamespacedName]PolicyFunc + client client.Client + compiler Compiler + lock *sync.Mutex + policies map[string]PolicyFunc + sortPolicies func() []PolicyFunc } func newPolicyReconciler(client client.Client, compiler Compiler) *policyReconciler { return &policyReconciler{ client: client, compiler: compiler, - lock: &sync.RWMutex{}, - policies: map[types.NamespacedName]PolicyFunc{}, + lock: &sync.Mutex{}, + policies: map[string]PolicyFunc{}, + sortPolicies: func() []PolicyFunc { + return nil + }, } } +func mapToSortedSlice[K cmp.Ordered, V any](in map[K]V) []V { + if in == nil { + return nil + } + out := make([]V, 0, len(in)) + keys := maps.Keys(in) + slices.Sort(keys) + for _, key := range keys { + out = append(out, in[key]) + } + return out +} + func (r *policyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { var policy v1alpha1.AuthorizationPolicy + // Reset the sorted func on every reconcile so the policies get resorted in next call + resetSortPolicies := func() { + r.sortPolicies = sync.OnceValue(func() []PolicyFunc { + r.lock.Lock() + defer r.lock.Unlock() + return mapToSortedSlice(r.policies) + }) + } err := r.client.Get(ctx, req.NamespacedName, &policy) if errors.IsNotFound(err) { r.lock.Lock() defer r.lock.Unlock() - delete(r.policies, req.NamespacedName) + defer resetSortPolicies() + delete(r.policies, req.NamespacedName.String()) return ctrl.Result{}, nil } if err != nil { @@ -60,16 +88,11 @@ func (r *policyReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr } r.lock.Lock() defer r.lock.Unlock() - r.policies[req.NamespacedName] = compiled + r.policies[req.NamespacedName.String()] = compiled + resetSortPolicies() return ctrl.Result{}, nil } func (r *policyReconciler) CompiledPolicies(ctx context.Context) ([]PolicyFunc, error) { - r.lock.RLock() - defer r.lock.RUnlock() - out := make([]PolicyFunc, 0, len(r.policies)) - for _, policy := range r.policies { - out = append(out, policy) - } - return out, nil + return slices.Clone(r.sortPolicies()), nil }