Skip to content

Commit a0c3284

Browse files
Update only affected replicated policies
Signed-off-by: Yi Rae Kim <[email protected]>
1 parent db38835 commit a0c3284

24 files changed

+1719
-216
lines changed

controllers/common/common.go

Lines changed: 117 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ const (
3232
var ErrInvalidLabelValue = errors.New("unexpected format of label value")
3333

3434
// IsInClusterNamespace check if policy is in cluster namespace
35-
func IsInClusterNamespace(c client.Client, ns string) (bool, error) {
35+
func IsInClusterNamespace(ctx context.Context, c client.Client, ns string) (bool, error) {
3636
cluster := &clusterv1.ManagedCluster{}
3737

38-
err := c.Get(context.TODO(), types.NamespacedName{Name: ns}, cluster)
38+
err := c.Get(ctx, types.NamespacedName{Name: ns}, cluster)
3939
if k8serrors.IsNotFound(err) {
4040
return false, nil
4141
}
@@ -58,7 +58,7 @@ func IsReplicatedPolicy(c client.Client, policy client.Object) (bool, error) {
5858
return false, fmt.Errorf("invalid value set in %s: %w", RootPolicyLabel, err)
5959
}
6060

61-
return IsInClusterNamespace(c, policy.GetNamespace())
61+
return IsInClusterNamespace(context.TODO(), c, policy.GetNamespace())
6262
}
6363

6464
// IsForPolicyOrPolicySet returns true if any of the subjects of the PlacementBinding are Policies
@@ -96,11 +96,11 @@ func IsPbForPolicySet(pb *policiesv1.PlacementBinding) bool {
9696

9797
// GetPoliciesInPlacementBinding returns a list of the Policies that are either direct subjects of
9898
// the given PlacementBinding, or are in PolicySets that are subjects of the PlacementBinding.
99-
// The list items are not guaranteed to be unique (for example if a policy is in multiple sets).
99+
// The list items are guaranteed to be unique (for example if a policy is in multiple sets).
100100
func GetPoliciesInPlacementBinding(
101101
ctx context.Context, c client.Client, pb *policiesv1.PlacementBinding,
102102
) []reconcile.Request {
103-
result := make([]reconcile.Request, 0)
103+
table := map[reconcile.Request]bool{}
104104

105105
for _, subject := range pb.Subjects {
106106
if subject.APIGroup != policiesv1.SchemeGroupVersion.Group {
@@ -109,10 +109,12 @@ func GetPoliciesInPlacementBinding(
109109

110110
switch subject.Kind {
111111
case policiesv1.Kind:
112-
result = append(result, reconcile.Request{NamespacedName: types.NamespacedName{
112+
req := reconcile.Request{NamespacedName: types.NamespacedName{
113113
Name: subject.Name,
114114
Namespace: pb.GetNamespace(),
115-
}})
115+
}}
116+
117+
table[req] = true
116118
case policiesv1.PolicySetKind:
117119
setNN := types.NamespacedName{
118120
Name: subject.Name,
@@ -125,14 +127,22 @@ func GetPoliciesInPlacementBinding(
125127
}
126128

127129
for _, plc := range policySet.Spec.Policies {
128-
result = append(result, reconcile.Request{NamespacedName: types.NamespacedName{
130+
req := reconcile.Request{NamespacedName: types.NamespacedName{
129131
Name: string(plc),
130132
Namespace: pb.GetNamespace(),
131-
}})
133+
}}
134+
135+
table[req] = true
132136
}
133137
}
134138
}
135139

140+
result := make([]reconcile.Request, 0, len(table))
141+
142+
for k := range table {
143+
result = append(result, k)
144+
}
145+
136146
return result
137147
}
138148

@@ -162,7 +172,9 @@ func HasValidPlacementRef(pb *policiesv1.PlacementBinding) bool {
162172

163173
// GetDecisions returns the placement decisions from the Placement or PlacementRule referred to by
164174
// the PlacementBinding
165-
func GetDecisions(c client.Client, pb *policiesv1.PlacementBinding) ([]appsv1.PlacementDecision, error) {
175+
func GetDecisions(
176+
ctx context.Context, c client.Client, pb *policiesv1.PlacementBinding,
177+
) ([]appsv1.PlacementDecision, error) {
166178
if !HasValidPlacementRef(pb) {
167179
return nil, fmt.Errorf("placement binding %s/%s reference is not valid", pb.Name, pb.Namespace)
168180
}
@@ -176,7 +188,7 @@ func GetDecisions(c client.Client, pb *policiesv1.PlacementBinding) ([]appsv1.Pl
176188
case "Placement":
177189
pl := &clusterv1beta1.Placement{}
178190

179-
err := c.Get(context.TODO(), refNN, pl)
191+
err := c.Get(ctx, refNN, pl)
180192
if err != nil && !k8serrors.IsNotFound(err) {
181193
return nil, fmt.Errorf("failed to get Placement '%v': %w", pb.PlacementRef.Name, err)
182194
}
@@ -191,7 +203,7 @@ func GetDecisions(c client.Client, pb *policiesv1.PlacementBinding) ([]appsv1.Pl
191203
opts := client.MatchingLabels{"cluster.open-cluster-management.io/placement": pl.GetName()}
192204
opts.ApplyToList(lopts)
193205

194-
err = c.List(context.TODO(), list, lopts)
206+
err = c.List(ctx, list, lopts)
195207
if err != nil && !k8serrors.IsNotFound(err) {
196208
return nil, fmt.Errorf("failed to list the PlacementDecisions for '%v', %w", pb.PlacementRef.Name, err)
197209
}
@@ -210,7 +222,7 @@ func GetDecisions(c client.Client, pb *policiesv1.PlacementBinding) ([]appsv1.Pl
210222
return decisions, nil
211223
case "PlacementRule":
212224
plr := &appsv1.PlacementRule{}
213-
if err := c.Get(context.TODO(), refNN, plr); err != nil && !k8serrors.IsNotFound(err) {
225+
if err := c.Get(ctx, refNN, plr); err != nil && !k8serrors.IsNotFound(err) {
214226
return nil, fmt.Errorf("failed to get PlacementRule '%v': %w", pb.PlacementRef.Name, err)
215227
}
216228

@@ -245,6 +257,33 @@ func FullNameForPolicy(plc *policiesv1.Policy) string {
245257
return plc.GetNamespace() + "." + plc.GetName()
246258
}
247259

260+
// GetRepPoliciesInPlacementBinding returns a list of the replicated policies that are either direct subjects of
261+
// the given PlacementBinding, or are in PolicySets that are subjects of the PlacementBinding.
262+
// The list items are guaranteed to be unique (for example if a policy is in multiple sets).
263+
func GetRepPoliciesInPlacementBinding(
264+
ctx context.Context, c client.Client, pb *policiesv1.PlacementBinding,
265+
) []reconcile.Request {
266+
decisions, err := GetDecisions(ctx, c, pb)
267+
if err != nil {
268+
return []reconcile.Request{}
269+
}
270+
// Use this for removing duplicated policies
271+
rootPolicyRequest := GetPoliciesInPlacementBinding(ctx, c, pb)
272+
273+
result := []reconcile.Request{}
274+
275+
for _, rp := range rootPolicyRequest {
276+
for _, pd := range decisions {
277+
result = append(result, reconcile.Request{NamespacedName: types.NamespacedName{
278+
Name: rp.Namespace + "." + rp.Name,
279+
Namespace: pd.ClusterName,
280+
}})
281+
}
282+
}
283+
284+
return result
285+
}
286+
248287
// TypeConverter is a helper function to converter type struct a to b
249288
func TypeConverter(a, b interface{}) error {
250289
js, err := json.Marshal(a)
@@ -254,3 +293,68 @@ func TypeConverter(a, b interface{}) error {
254293

255294
return json.Unmarshal(js, b)
256295
}
296+
297+
// Select objects that are deleted or created
298+
func GetAffectedObjs[T comparable](oldObjs []T, newObjs []T) []T {
299+
table := make(map[T]int)
300+
301+
for _, oldObj := range oldObjs {
302+
table[oldObj] = 1
303+
}
304+
305+
for _, newObj := range newObjs {
306+
table[newObj]++
307+
}
308+
309+
result := []T{}
310+
311+
for key, val := range table {
312+
if val == 1 {
313+
result = append(result, key)
314+
}
315+
}
316+
317+
return result
318+
}
319+
320+
type PlacementRefKinds string
321+
322+
const (
323+
Placement PlacementRefKinds = "Placement"
324+
PlacementRule PlacementRefKinds = "PlacementRule"
325+
)
326+
327+
// GetRootPolicyResult find and filter placementbindings which have namespace and placementRef.name.
328+
// Gather all root policies under placementbindings
329+
func GetRootPolicyResult(ctx context.Context, c client.Client,
330+
namespace, placementRefName string, refKind PlacementRefKinds,
331+
) ([]reconcile.Request, error) {
332+
kindGroupMap := map[PlacementRefKinds]string{
333+
Placement: clusterv1beta1.SchemeGroupVersion.Group,
334+
PlacementRule: appsv1.SchemeGroupVersion.Group,
335+
}
336+
337+
pbList := &policiesv1.PlacementBindingList{}
338+
// Find pb in the same namespace of placementrule
339+
lopts := &client.ListOptions{Namespace: namespace}
340+
opts := client.MatchingFields{"placementRef.name": placementRefName}
341+
opts.ApplyToList(lopts)
342+
343+
err := c.List(ctx, pbList, lopts)
344+
if err != nil {
345+
return nil, err
346+
}
347+
var rootPolicyResults []reconcile.Request
348+
349+
for i, pb := range pbList.Items {
350+
if pb.PlacementRef.APIGroup != kindGroupMap[refKind] ||
351+
pb.PlacementRef.Kind != string(refKind) || pb.PlacementRef.Name != placementRefName {
352+
continue
353+
}
354+
// GetPoliciesInPlacementBinding only pick root-policy name
355+
rootPolicyResults = append(rootPolicyResults,
356+
GetPoliciesInPlacementBinding(ctx, c, &pbList.Items[i])...)
357+
}
358+
359+
return rootPolicyResults, nil
360+
}

0 commit comments

Comments
 (0)