Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🤖 Sync from open-cluster-management-io/governance-policy-propagator: #133 #468

Merged
merged 1 commit into from
Oct 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions controllers/common/policyset_handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Copyright Contributors to the Open Cluster Management project

package common

import (
"context"

"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/util/workqueue"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/reconcile"

policiesv1beta1 "open-cluster-management.io/governance-policy-propagator/api/v1beta1"
)

// EnqueueRequestsFromPolicySet adds reconcile requests for every policy in the policy set,
// except on updates, it'll only add the diff between the old and new sets.
type EnqueueRequestsFromPolicySet struct{}

// mapPolicySetToRequests maps a PolicySet to all the Policies in its policies list.
func mapPolicySetToRequests(object client.Object) []reconcile.Request {
log := log.WithValues("policySetName", object.GetName(), "namespace", object.GetNamespace())
log.V(2).Info("Reconcile Request for PolicySet")

var result []reconcile.Request

//nolint:forcetypeassert
policySet := object.(*policiesv1beta1.PolicySet)

for _, plc := range policySet.Spec.Policies {
log.V(2).Info("Found reconciliation request from a policyset", "policyName", string(plc))

request := reconcile.Request{NamespacedName: types.NamespacedName{
Name: string(plc),
Namespace: object.GetNamespace(),
}}
result = append(result, request)
}

return result
}

// Create implements EventHandler
func (e *EnqueueRequestsFromPolicySet) Create(_ context.Context, evt event.CreateEvent,
q workqueue.RateLimitingInterface,
) {
for _, policy := range mapPolicySetToRequests(evt.Object) {
q.Add(policy)
}
}

// Update implements EventHandler
// Enqueues the diff between the new and old policy sets in the UpdateEvent
func (e *EnqueueRequestsFromPolicySet) Update(_ context.Context, evt event.UpdateEvent,
q workqueue.RateLimitingInterface,
) {
//nolint:forcetypeassert
newPolicySet := evt.ObjectNew.(*policiesv1beta1.PolicySet)
//nolint:forcetypeassert
oldPolicySet := evt.ObjectOld.(*policiesv1beta1.PolicySet)

newPoliciesMap := make(map[string]bool)
oldPoliciesMap := make(map[string]bool)
diffPolicies := []policiesv1beta1.NonEmptyString{}

for _, plc := range newPolicySet.Spec.Policies {
newPoliciesMap[string(plc)] = true
}

for _, plc := range oldPolicySet.Spec.Policies {
oldPoliciesMap[string(plc)] = true
}

for _, plc := range oldPolicySet.Spec.Policies {
if !newPoliciesMap[string(plc)] {
diffPolicies = append(diffPolicies, plc)
}
}

for _, plc := range newPolicySet.Spec.Policies {
if !oldPoliciesMap[string(plc)] {
diffPolicies = append(diffPolicies, plc)
}
}

for _, plc := range diffPolicies {
log.V(2).Info("Found reconciliation request from a policyset", "policyName", string(plc))

request := reconcile.Request{NamespacedName: types.NamespacedName{
Name: string(plc),
Namespace: newPolicySet.GetNamespace(),
}}
q.Add(request)
}
}

// Delete implements EventHandler
func (e *EnqueueRequestsFromPolicySet) Delete(_ context.Context, evt event.DeleteEvent,
q workqueue.RateLimitingInterface,
) {
for _, policy := range mapPolicySetToRequests(evt.Object) {
q.Add(policy)
}
}

// Generic implements EventHandler
func (e *EnqueueRequestsFromPolicySet) Generic(_ context.Context, evt event.GenericEvent,
q workqueue.RateLimitingInterface,
) {
for _, policy := range mapPolicySetToRequests(evt.Object) {
q.Add(policy)
}
}
48 changes: 1 addition & 47 deletions controllers/propagator/rootpolicy_setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"context"

"k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/types"
clusterv1beta1 "open-cluster-management.io/api/cluster/v1beta1"
appsv1 "open-cluster-management.io/multicloud-operators-subscription/pkg/apis/apps/placementrule/v1"
ctrl "sigs.k8s.io/controller-runtime"
Expand Down Expand Up @@ -44,8 +43,7 @@ func (r *RootPolicyReconciler) SetupWithManager(mgr ctrl.Manager, maxConcurrentR
builder.WithPredicates(rootPolicyNonStatusUpdates())).
Watches(
&policiesv1beta1.PolicySet{},
handler.EnqueueRequestsFromMapFunc(mapPolicySetToPolicies),
builder.WithPredicates(policySetPolicyListChanged())).
&common.EnqueueRequestsFromPolicySet{}).
Watches(
&policiesv1.PlacementBinding{},
handler.EnqueueRequestsFromMapFunc(mapBindingToPolicies(mgr.GetClient())),
Expand Down Expand Up @@ -90,50 +88,6 @@ func rootPolicyNonStatusUpdates() predicate.Funcs {
}
}

// mapPolicySetToPolicies maps a PolicySet to all the Policies in its policies list.
func mapPolicySetToPolicies(_ context.Context, object client.Object) []reconcile.Request {
log := log.WithValues("policySetName", object.GetName(), "namespace", object.GetNamespace())
log.V(2).Info("Reconcile Request for PolicySet")

var result []reconcile.Request

//nolint:forcetypeassert
policySet := object.(*policiesv1beta1.PolicySet)

for _, plc := range policySet.Spec.Policies {
log.V(2).Info("Found reconciliation request from a policyset", "policyName", string(plc))

request := reconcile.Request{NamespacedName: types.NamespacedName{
Name: string(plc),
Namespace: object.GetNamespace(),
}}
result = append(result, request)
}

return result
}

// policySetPolicyListChanged triggers reconciliation if the list of policies in the PolicySet has
// changed, or if the PolicySet was just created or deleted.
func policySetPolicyListChanged() predicate.Funcs {
return predicate.Funcs{
UpdateFunc: func(e event.UpdateEvent) bool {
//nolint:forcetypeassert
policySetObjNew := e.ObjectNew.(*policiesv1beta1.PolicySet)
//nolint:forcetypeassert
policySetObjOld := e.ObjectOld.(*policiesv1beta1.PolicySet)

return !equality.Semantic.DeepEqual(policySetObjNew.Spec.Policies, policySetObjOld.Spec.Policies)
},
CreateFunc: func(e event.CreateEvent) bool {
return true
},
DeleteFunc: func(e event.DeleteEvent) bool {
return true
},
}
}

// mapBindingToPolicies maps a PlacementBinding to the Policies that are either directly in its
// subjects list, or are in a PolicySet which is a subject of this PlacementBinding.
func mapBindingToPolicies(c client.Client) handler.MapFunc {
Expand Down