From 33e24d49adfd07c1803027ae161b7426c1635456 Mon Sep 17 00:00:00 2001 From: Nic Cope Date: Tue, 7 May 2024 13:12:40 -0700 Subject: [PATCH] Move realtime composition event handlers into their own file Signed-off-by: Nic Cope --- .../apiextensions/composite/reconciler.go | 48 ---- .../composite/reconciler_test.go | 217 --------------- .../apiextensions/definition/handlers.go | 103 +++++++ .../apiextensions/definition/handlers_test.go | 251 ++++++++++++++++++ .../apiextensions/definition/indexes.go | 23 -- .../apiextensions/definition/reconciler.go | 2 +- 6 files changed, 355 insertions(+), 289 deletions(-) create mode 100644 internal/controller/apiextensions/definition/handlers.go create mode 100644 internal/controller/apiextensions/definition/handlers_test.go diff --git a/internal/controller/apiextensions/composite/reconciler.go b/internal/controller/apiextensions/composite/reconciler.go index e2d634a5577..5c5855c1ebe 100644 --- a/internal/controller/apiextensions/composite/reconciler.go +++ b/internal/controller/apiextensions/composite/reconciler.go @@ -26,12 +26,8 @@ import ( kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - kunstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/util/workqueue" "sigs.k8s.io/controller-runtime/pkg/client" - runtimeevent "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -731,47 +727,3 @@ func getComposerResourcesNames(cds []ComposedResource) []string { } return names } - -// EnqueueForCompositionRevisionFunc returns a function that enqueues (the -// related) XRs when a new CompositionRevision is created. This speeds up -// reconciliation of XRs on changes to the Composition by not having to wait for -// the 60s sync period, but be instant. -func EnqueueForCompositionRevisionFunc(of resource.CompositeKind, list func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error, log logging.Logger) func(ctx context.Context, createEvent runtimeevent.TypedCreateEvent[*v1.CompositionRevision], q workqueue.RateLimitingInterface) { - return func(ctx context.Context, createEvent runtimeevent.TypedCreateEvent[*v1.CompositionRevision], q workqueue.RateLimitingInterface) { - rev := createEvent.Object - - // get all XRs - xrs := kunstructured.UnstructuredList{} - xrs.SetGroupVersionKind(schema.GroupVersionKind(of)) - xrs.SetKind(schema.GroupVersionKind(of).Kind + "List") - if err := list(ctx, &xrs); err != nil { - // logging is most we can do here. This is a programming error if it happens. - log.Info("cannot list in CompositionRevision handler", "type", schema.GroupVersionKind(of).String(), "error", err) - return - } - - // enqueue all those that reference the Composition of this revision - compName := rev.Labels[v1.LabelCompositionName] - if compName == "" { - return - } - for _, u := range xrs.Items { - xr := composite.Unstructured{Unstructured: u} - - // only automatic - if pol := xr.GetCompositionUpdatePolicy(); pol != nil && *pol == xpv1.UpdateManual { - continue - } - - // only those that reference the right Composition - if ref := xr.GetCompositionReference(); ref == nil || ref.Name != compName { - continue - } - - q.Add(reconcile.Request{NamespacedName: types.NamespacedName{ - Name: xr.GetName(), - Namespace: xr.GetNamespace(), - }}) - } - } -} diff --git a/internal/controller/apiextensions/composite/reconciler_test.go b/internal/controller/apiextensions/composite/reconciler_test.go index fbefe27eb14..8a3f1152d0c 100644 --- a/internal/controller/apiextensions/composite/reconciler_test.go +++ b/internal/controller/apiextensions/composite/reconciler_test.go @@ -18,7 +18,6 @@ package composite import ( "context" - "reflect" "testing" "time" @@ -27,19 +26,14 @@ import ( corev1 "k8s.io/api/core/v1" kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - kunstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" - "k8s.io/client-go/util/workqueue" "sigs.k8s.io/controller-runtime/pkg/client" - runtimeevent "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/reconcile" xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" "github.com/crossplane/crossplane-runtime/pkg/errors" "github.com/crossplane/crossplane-runtime/pkg/event" - "github.com/crossplane/crossplane-runtime/pkg/logging" "github.com/crossplane/crossplane-runtime/pkg/meta" "github.com/crossplane/crossplane-runtime/pkg/reconciler/managed" "github.com/crossplane/crossplane-runtime/pkg/resource" @@ -843,214 +837,3 @@ func TestFilterToXRPatches(t *testing.T) { }) } } - -func TestEnqueueForCompositionRevisionFunc(t *testing.T) { - type args struct { - of schema.GroupVersionKind - list func(_ context.Context, list client.ObjectList, opts ...client.ListOption) error - event runtimeevent.TypedCreateEvent[*v1.CompositionRevision] - } - type want struct { - added []interface{} - } - - dog := schema.GroupVersionKind{Group: "example.com", Version: "v1", Kind: "Dog"} - dogList := dog.GroupVersion().WithKind("DogList") - - tests := []struct { - name string - args args - want want - }{ - { - name: "empty", - args: args{ - of: dog, - list: func(_ context.Context, list client.ObjectList, opts ...client.ListOption) error { - // test parameters only here, not in the later tests for brevity. - u, ok := list.(*kunstructured.UnstructuredList) - if !ok { - t.Errorf("list was not an UnstructuredList") - } else if got := u.GroupVersionKind(); got != dogList { - t.Errorf("list was not a DogList, got: %s", got) - } - if len(opts) != 0 { - t.Errorf("unexpected list options: %#v", opts) - } - return nil - }, - event: runtimeevent.TypedCreateEvent[*v1.CompositionRevision]{ - Object: &v1.CompositionRevision{ - ObjectMeta: metav1.ObjectMeta{ - Name: "dachshund-sadfa8", - Labels: map[string]string{ - v1.LabelCompositionName: "dachshund", - }, - }, - }, - }, - }, - }, - { - name: "automatic management policy", - args: args{ - of: dog, - list: func(_ context.Context, list client.ObjectList, _ ...client.ListOption) error { - var obj1 composite.Unstructured - obj1.SetNamespace("ns") - obj1.SetName("obj1") - policy := xpv1.UpdateAutomatic - obj1.SetCompositionUpdatePolicy(&policy) - obj1.SetCompositionReference(&corev1.ObjectReference{Name: "dachshund"}) - - list.(*kunstructured.UnstructuredList).Items = []kunstructured.Unstructured{obj1.Unstructured} - - return nil - }, - event: runtimeevent.TypedCreateEvent[*v1.CompositionRevision]{ - Object: &v1.CompositionRevision{ - ObjectMeta: metav1.ObjectMeta{ - Name: "dachshund-sadfa8", - Labels: map[string]string{ - v1.LabelCompositionName: "dachshund", - }, - }, - }, - }, - }, - want: want{ - added: []interface{}{reconcile.Request{NamespacedName: types.NamespacedName{ - Namespace: "ns", - Name: "obj1", - }}}, - }, - }, - { - name: "manual management policy", - args: args{ - of: dog, - list: func(_ context.Context, list client.ObjectList, _ ...client.ListOption) error { - var obj1 composite.Unstructured - obj1.SetNamespace("ns") - obj1.SetName("obj1") - policy := xpv1.UpdateManual - obj1.SetCompositionUpdatePolicy(&policy) - obj1.SetCompositionReference(&corev1.ObjectReference{Name: "dachshund"}) - - list.(*kunstructured.UnstructuredList).Items = []kunstructured.Unstructured{obj1.Unstructured} - - return nil - }, - event: runtimeevent.TypedCreateEvent[*v1.CompositionRevision]{ - Object: &v1.CompositionRevision{ - ObjectMeta: metav1.ObjectMeta{ - Name: "dachshund-sadfa8", - Labels: map[string]string{ - v1.LabelCompositionName: "dachshund", - }, - }, - }, - }, - }, - want: want{}, - }, - { - name: "other composition", - args: args{ - of: dog, - list: func(_ context.Context, list client.ObjectList, _ ...client.ListOption) error { - var obj1 composite.Unstructured - obj1.SetNamespace("ns") - obj1.SetName("obj1") - policy := xpv1.UpdateAutomatic - obj1.SetCompositionUpdatePolicy(&policy) - obj1.SetCompositionReference(&corev1.ObjectReference{Name: "bernese"}) - - list.(*kunstructured.UnstructuredList).Items = []kunstructured.Unstructured{obj1.Unstructured} - - return nil - }, - event: runtimeevent.TypedCreateEvent[*v1.CompositionRevision]{ - Object: &v1.CompositionRevision{ - ObjectMeta: metav1.ObjectMeta{ - Name: "dachshund-sadfa8", - Labels: map[string]string{ - v1.LabelCompositionName: "dachshund", - }, - }, - }, - }, - }, - want: want{}, - }, - { - name: "multiple", - args: args{ - of: dog, - list: func(_ context.Context, list client.ObjectList, _ ...client.ListOption) error { - var obj1 composite.Unstructured - obj1.SetNamespace("ns") - obj1.SetName("obj1") - automatic := xpv1.UpdateAutomatic - obj1.SetCompositionUpdatePolicy(&automatic) - obj1.SetCompositionReference(&corev1.ObjectReference{Name: "dachshund"}) - - obj2 := obj1.DeepCopy() - obj2.SetName("obj2") - - obj3 := obj1.DeepCopy() - obj3.SetName("obj3") - obj3.SetCompositionReference(&corev1.ObjectReference{Name: "bernese"}) - - obj4 := obj1.DeepCopy() - obj4.SetName("obj4") - manual := xpv1.UpdateManual - obj4.SetCompositionUpdatePolicy(&manual) - - list.(*kunstructured.UnstructuredList).Items = []kunstructured.Unstructured{ - obj1.Unstructured, - obj2.Unstructured, - obj3.Unstructured, - } - - return nil - }, - event: runtimeevent.TypedCreateEvent[*v1.CompositionRevision]{ - Object: &v1.CompositionRevision{ - ObjectMeta: metav1.ObjectMeta{ - Name: "dachshund-sadfa8", - Labels: map[string]string{ - v1.LabelCompositionName: "dachshund", - }, - }, - }, - }, - }, - want: want{ - added: []interface{}{ - reconcile.Request{NamespacedName: types.NamespacedName{Namespace: "ns", Name: "obj1"}}, - reconcile.Request{NamespacedName: types.NamespacedName{Namespace: "ns", Name: "obj2"}}, - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - fn := EnqueueForCompositionRevisionFunc(resource.CompositeKind(tt.args.of), tt.args.list, logging.NewNopLogger()) - q := rateLimitingQueueMock{} - fn(context.TODO(), tt.args.event, &q) - if got := q.added; !reflect.DeepEqual(got, tt.want.added) { - t.Errorf("EnqueueForCompositionRevisionFunc(...)(ctx, event, queue) = %v, want %v", got, tt.want) - } - }) - } -} - -type rateLimitingQueueMock struct { - workqueue.RateLimitingInterface - added []interface{} -} - -func (f *rateLimitingQueueMock) Add(item interface{}) { - f.added = append(f.added, item) -} diff --git a/internal/controller/apiextensions/definition/handlers.go b/internal/controller/apiextensions/definition/handlers.go new file mode 100644 index 00000000000..dc70b3680ef --- /dev/null +++ b/internal/controller/apiextensions/definition/handlers.go @@ -0,0 +1,103 @@ +/* +Copyright 2024 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package definition + +import ( + "context" + + kunstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/workqueue" + cache "sigs.k8s.io/controller-runtime/pkg/cache" + "sigs.k8s.io/controller-runtime/pkg/client" + runtimeevent "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" + "github.com/crossplane/crossplane-runtime/pkg/logging" + "github.com/crossplane/crossplane-runtime/pkg/resource" + "github.com/crossplane/crossplane-runtime/pkg/resource/unstructured/composite" + + v1 "github.com/crossplane/crossplane/apis/apiextensions/v1" +) + +// For comp rev +// EnqueueForCompositionRevisionFunc returns a function that enqueues (the +// related) XRs when a new CompositionRevision is created. This speeds up +// reconciliation of XRs on changes to the Composition by not having to wait for +// the 60s sync period, but be instant. +func EnqueueForCompositionRevisionFunc(of resource.CompositeKind, list func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error, log logging.Logger) func(ctx context.Context, createEvent runtimeevent.TypedCreateEvent[*v1.CompositionRevision], q workqueue.RateLimitingInterface) { + return func(ctx context.Context, createEvent runtimeevent.TypedCreateEvent[*v1.CompositionRevision], q workqueue.RateLimitingInterface) { + rev := createEvent.Object + + // get all XRs + xrs := kunstructured.UnstructuredList{} + xrs.SetGroupVersionKind(schema.GroupVersionKind(of)) + xrs.SetKind(schema.GroupVersionKind(of).Kind + "List") + if err := list(ctx, &xrs); err != nil { + // logging is most we can do here. This is a programming error if it happens. + log.Info("cannot list in CompositionRevision handler", "type", schema.GroupVersionKind(of).String(), "error", err) + return + } + + // enqueue all those that reference the Composition of this revision + compName := rev.Labels[v1.LabelCompositionName] + if compName == "" { + return + } + for _, u := range xrs.Items { + xr := composite.Unstructured{Unstructured: u} + + // only automatic + if pol := xr.GetCompositionUpdatePolicy(); pol != nil && *pol == xpv1.UpdateManual { + continue + } + + // only those that reference the right Composition + if ref := xr.GetCompositionReference(); ref == nil || ref.Name != compName { + continue + } + + q.Add(reconcile.Request{NamespacedName: types.NamespacedName{ + Name: xr.GetName(), + Namespace: xr.GetNamespace(), + }}) + } + } +} + +// TODO(negz): Figure out a way to plumb this with controller-runtime v0.18.x +// style sources. + +func enqueueXRsForMR(ca cache.Cache, xrGVK schema.GroupVersionKind, log logging.Logger) func(ctx context.Context, ev runtimeevent.UpdateEvent, q workqueue.RateLimitingInterface) { //nolint:unused // See comment above. + return func(ctx context.Context, ev runtimeevent.UpdateEvent, q workqueue.RateLimitingInterface) { + mrGVK := ev.ObjectNew.GetObjectKind().GroupVersionKind() + key := refKey(ev.ObjectNew.GetNamespace(), ev.ObjectNew.GetName(), mrGVK.Kind, mrGVK.GroupVersion().String()) + composites := kunstructured.UnstructuredList{} + composites.SetGroupVersionKind(xrGVK.GroupVersion().WithKind(xrGVK.Kind + "List")) + if err := ca.List(ctx, &composites, client.MatchingFields{compositeResourcesRefsIndex: key}); err != nil { + log.Debug("cannot list composite resources related to a MR change", "error", err, "gvk", xrGVK.String(), "fieldSelector", compositeResourcesRefsIndex+"="+key) + return + } + // queue those composites for reconciliation + for _, xr := range composites.Items { + log.Info("Enqueueing composite resource because managed resource changed", "name", xr.GetName(), "mrGVK", mrGVK.String(), "mrName", ev.ObjectNew.GetName()) + q.Add(reconcile.Request{NamespacedName: types.NamespacedName{Name: xr.GetName()}}) + } + } +} diff --git a/internal/controller/apiextensions/definition/handlers_test.go b/internal/controller/apiextensions/definition/handlers_test.go new file mode 100644 index 00000000000..c9e407d25d4 --- /dev/null +++ b/internal/controller/apiextensions/definition/handlers_test.go @@ -0,0 +1,251 @@ +/* +Copyright 2024 The Crossplane Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package definition + +import ( + "context" + "reflect" + "testing" + + xpv1 "github.com/crossplane/crossplane-runtime/apis/common/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + kunstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/util/workqueue" + "sigs.k8s.io/controller-runtime/pkg/client" + runtimeevent "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + "github.com/crossplane/crossplane-runtime/pkg/logging" + "github.com/crossplane/crossplane-runtime/pkg/resource" + "github.com/crossplane/crossplane-runtime/pkg/resource/unstructured/composite" + + v1 "github.com/crossplane/crossplane/apis/apiextensions/v1" +) + +func TestEnqueueForCompositionRevisionFunc(t *testing.T) { + type args struct { + of schema.GroupVersionKind + list func(_ context.Context, list client.ObjectList, opts ...client.ListOption) error + event runtimeevent.TypedCreateEvent[*v1.CompositionRevision] + } + type want struct { + added []interface{} + } + + dog := schema.GroupVersionKind{Group: "example.com", Version: "v1", Kind: "Dog"} + dogList := dog.GroupVersion().WithKind("DogList") + + tests := []struct { + name string + args args + want want + }{ + { + name: "empty", + args: args{ + of: dog, + list: func(_ context.Context, list client.ObjectList, opts ...client.ListOption) error { + // test parameters only here, not in the later tests for brevity. + u, ok := list.(*kunstructured.UnstructuredList) + if !ok { + t.Errorf("list was not an UnstructuredList") + } else if got := u.GroupVersionKind(); got != dogList { + t.Errorf("list was not a DogList, got: %s", got) + } + if len(opts) != 0 { + t.Errorf("unexpected list options: %#v", opts) + } + return nil + }, + event: runtimeevent.TypedCreateEvent[*v1.CompositionRevision]{ + Object: &v1.CompositionRevision{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dachshund-sadfa8", + Labels: map[string]string{ + v1.LabelCompositionName: "dachshund", + }, + }, + }, + }, + }, + }, + { + name: "automatic management policy", + args: args{ + of: dog, + list: func(_ context.Context, list client.ObjectList, _ ...client.ListOption) error { + var obj1 composite.Unstructured + obj1.SetNamespace("ns") + obj1.SetName("obj1") + policy := xpv1.UpdateAutomatic + obj1.SetCompositionUpdatePolicy(&policy) + obj1.SetCompositionReference(&corev1.ObjectReference{Name: "dachshund"}) + + list.(*kunstructured.UnstructuredList).Items = []kunstructured.Unstructured{obj1.Unstructured} + + return nil + }, + event: runtimeevent.TypedCreateEvent[*v1.CompositionRevision]{ + Object: &v1.CompositionRevision{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dachshund-sadfa8", + Labels: map[string]string{ + v1.LabelCompositionName: "dachshund", + }, + }, + }, + }, + }, + want: want{ + added: []interface{}{reconcile.Request{NamespacedName: types.NamespacedName{ + Namespace: "ns", + Name: "obj1", + }}}, + }, + }, + { + name: "manual management policy", + args: args{ + of: dog, + list: func(_ context.Context, list client.ObjectList, _ ...client.ListOption) error { + var obj1 composite.Unstructured + obj1.SetNamespace("ns") + obj1.SetName("obj1") + policy := xpv1.UpdateManual + obj1.SetCompositionUpdatePolicy(&policy) + obj1.SetCompositionReference(&corev1.ObjectReference{Name: "dachshund"}) + + list.(*kunstructured.UnstructuredList).Items = []kunstructured.Unstructured{obj1.Unstructured} + + return nil + }, + event: runtimeevent.TypedCreateEvent[*v1.CompositionRevision]{ + Object: &v1.CompositionRevision{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dachshund-sadfa8", + Labels: map[string]string{ + v1.LabelCompositionName: "dachshund", + }, + }, + }, + }, + }, + want: want{}, + }, + { + name: "other composition", + args: args{ + of: dog, + list: func(_ context.Context, list client.ObjectList, _ ...client.ListOption) error { + var obj1 composite.Unstructured + obj1.SetNamespace("ns") + obj1.SetName("obj1") + policy := xpv1.UpdateAutomatic + obj1.SetCompositionUpdatePolicy(&policy) + obj1.SetCompositionReference(&corev1.ObjectReference{Name: "bernese"}) + + list.(*kunstructured.UnstructuredList).Items = []kunstructured.Unstructured{obj1.Unstructured} + + return nil + }, + event: runtimeevent.TypedCreateEvent[*v1.CompositionRevision]{ + Object: &v1.CompositionRevision{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dachshund-sadfa8", + Labels: map[string]string{ + v1.LabelCompositionName: "dachshund", + }, + }, + }, + }, + }, + want: want{}, + }, + { + name: "multiple", + args: args{ + of: dog, + list: func(_ context.Context, list client.ObjectList, _ ...client.ListOption) error { + var obj1 composite.Unstructured + obj1.SetNamespace("ns") + obj1.SetName("obj1") + automatic := xpv1.UpdateAutomatic + obj1.SetCompositionUpdatePolicy(&automatic) + obj1.SetCompositionReference(&corev1.ObjectReference{Name: "dachshund"}) + + obj2 := obj1.DeepCopy() + obj2.SetName("obj2") + + obj3 := obj1.DeepCopy() + obj3.SetName("obj3") + obj3.SetCompositionReference(&corev1.ObjectReference{Name: "bernese"}) + + obj4 := obj1.DeepCopy() + obj4.SetName("obj4") + manual := xpv1.UpdateManual + obj4.SetCompositionUpdatePolicy(&manual) + + list.(*kunstructured.UnstructuredList).Items = []kunstructured.Unstructured{ + obj1.Unstructured, + obj2.Unstructured, + obj3.Unstructured, + } + + return nil + }, + event: runtimeevent.TypedCreateEvent[*v1.CompositionRevision]{ + Object: &v1.CompositionRevision{ + ObjectMeta: metav1.ObjectMeta{ + Name: "dachshund-sadfa8", + Labels: map[string]string{ + v1.LabelCompositionName: "dachshund", + }, + }, + }, + }, + }, + want: want{ + added: []interface{}{ + reconcile.Request{NamespacedName: types.NamespacedName{Namespace: "ns", Name: "obj1"}}, + reconcile.Request{NamespacedName: types.NamespacedName{Namespace: "ns", Name: "obj2"}}, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + fn := EnqueueForCompositionRevisionFunc(resource.CompositeKind(tt.args.of), tt.args.list, logging.NewNopLogger()) + q := rateLimitingQueueMock{} + fn(context.TODO(), tt.args.event, &q) + if got := q.added; !reflect.DeepEqual(got, tt.want.added) { + t.Errorf("EnqueueForCompositionRevisionFunc(...)(ctx, event, queue) = %v, want %v", got, tt.want) + } + }) + } +} + +type rateLimitingQueueMock struct { + workqueue.RateLimitingInterface + added []interface{} +} + +func (f *rateLimitingQueueMock) Add(item interface{}) { + f.added = append(f.added, item) +} diff --git a/internal/controller/apiextensions/definition/indexes.go b/internal/controller/apiextensions/definition/indexes.go index 6aaca2cd81c..f4829dfa7b9 100644 --- a/internal/controller/apiextensions/definition/indexes.go +++ b/internal/controller/apiextensions/definition/indexes.go @@ -78,26 +78,3 @@ func IndexCompositeResourcesRefs(o client.Object) []string { func refKey(ns, name, kind, apiVersion string) string { return fmt.Sprintf("%s.%s.%s.%s", name, ns, kind, apiVersion) } - -// TODO(negz): Figure out a way to plumb this with controller-runtime v0.18.x -// style sources. - -// func enqueueXRsForMR(ca cache.Cache, xrGVK schema.GroupVersionKind, log logging.Logger) func(ctx context.Context, ev runtimeevent.UpdateEvent, q workqueue.RateLimitingInterface) { -// return func(ctx context.Context, ev runtimeevent.UpdateEvent, q workqueue.RateLimitingInterface) { -// mrGVK := ev.ObjectNew.GetObjectKind().GroupVersionKind() -// key := refKey(ev.ObjectNew.GetNamespace(), ev.ObjectNew.GetName(), mrGVK.Kind, mrGVK.GroupVersion().String()) -// -// composites := kunstructured.UnstructuredList{} -// composites.SetGroupVersionKind(xrGVK.GroupVersion().WithKind(xrGVK.Kind + "List")) -// if err := ca.List(ctx, &composites, client.MatchingFields{compositeResourcesRefsIndex: key}); err != nil { -// log.Debug("cannot list composite resources related to a MR change", "error", err, "gvk", xrGVK.String(), "fieldSelector", compositeResourcesRefsIndex+"="+key) -// return -// } -// -// // queue those composites for reconciliation -// for _, xr := range composites.Items { -// log.Info("Enqueueing composite resource because managed resource changed", "name", xr.GetName(), "mrGVK", mrGVK.String(), "mrName", ev.ObjectNew.GetName()) -// q.Add(reconcile.Request{NamespacedName: types.NamespacedName{Name: xr.GetName()}}) -// } -// } -// } diff --git a/internal/controller/apiextensions/definition/reconciler.go b/internal/controller/apiextensions/definition/reconciler.go index 1536958d3ed..b8d957dadf0 100644 --- a/internal/controller/apiextensions/definition/reconciler.go +++ b/internal/controller/apiextensions/definition/reconciler.go @@ -492,7 +492,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req reconcile.Request) (reco engine.WatchFor(u, &handler.EnqueueRequestForObject{}), // enqueue composites whenever a matching CompositionRevision is created engine.WatchTriggeredBy(source.Kind(r.mgr.GetCache(), &v1.CompositionRevision{}, handler.TypedFuncs[*v1.CompositionRevision]{ - CreateFunc: composite.EnqueueForCompositionRevisionFunc(ck, r.mgr.GetCache().List, r.log), + CreateFunc: EnqueueForCompositionRevisionFunc(ck, r.mgr.GetCache().List, r.log), })), }