Skip to content

Commit 162c615

Browse files
authored
Only watch ResourceGroups with the correct owner label (#1439)
* Only watch ResourceGroups with the correct owner label * Check new object for ownership too * Refactor test to cover all cases * Fix more failing checks * Only filter events for ResourceGroup resources * Fix typo * Set GVK on all test objects * Test that we always include events from non-ResourceGroup resources
1 parent efad112 commit 162c615

File tree

3 files changed

+142
-0
lines changed

3 files changed

+142
-0
lines changed

e2e/nomostest/testresourcegroup/resourcegroup.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"kpt.dev/configsync/e2e/nomostest/testkubeclient"
2626
"kpt.dev/configsync/pkg/api/configmanagement"
2727
"kpt.dev/configsync/pkg/api/kpt.dev/v1alpha1"
28+
"kpt.dev/configsync/pkg/metadata"
2829
"kpt.dev/configsync/pkg/resourcegroup/controllers/resourcegroup"
2930
"kpt.dev/configsync/pkg/resourcegroup/controllers/status"
3031
"sigs.k8s.io/cli-utils/pkg/common"
@@ -45,6 +46,7 @@ func New(nn types.NamespacedName, id string) *v1alpha1.ResourceGroup {
4546
if id != "" {
4647
rg.SetLabels(map[string]string{
4748
common.InventoryLabel: id,
49+
metadata.ManagedByKey: metadata.ManagedByValue,
4850
})
4951
}
5052
return rg

pkg/resourcegroup/controllers/root/root_controller.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"k8s.io/client-go/rest"
2828
"k8s.io/client-go/util/retry"
2929
"kpt.dev/configsync/pkg/api/kpt.dev/v1alpha1"
30+
"kpt.dev/configsync/pkg/metadata"
3031
"kpt.dev/configsync/pkg/resourcegroup/controllers/handler"
3132
"kpt.dev/configsync/pkg/resourcegroup/controllers/resourcegroup"
3233
"kpt.dev/configsync/pkg/resourcegroup/controllers/resourcemap"
@@ -211,6 +212,8 @@ func NewController(mgr manager.Manager, channel chan event.GenericEvent,
211212
WithEventFilter(ResourceGroupPredicate{}).
212213
// skip the Generic events
213214
WithEventFilter(NoGenericEventPredicate{}).
215+
// only reconcile resource groups owned by Config Sync
216+
WithEventFilter(OwnedByConfigSyncPredicate{}).
214217
Watches(&apiextensionsv1.CustomResourceDefinition{}, &handler.CRDEventHandler{
215218
Mapping: resMap,
216219
Channel: channel,
@@ -296,3 +299,37 @@ func isConditionTrue(cType v1alpha1.ConditionType, conditions []v1alpha1.Conditi
296299

297300
return false
298301
}
302+
303+
// OwnedByConfigSyncPredicate filters events for objects that have the label "app.kubernetes.io/managed-by=configmanagement.gke.io"
304+
type OwnedByConfigSyncPredicate struct{}
305+
306+
// Create implements predicate.Predicate
307+
func (OwnedByConfigSyncPredicate) Create(e event.CreateEvent) bool {
308+
return !isResourceGroup(e.Object) || isOwnedByConfigSync(e.Object)
309+
}
310+
311+
// Delete implements predicate.Predicate
312+
func (OwnedByConfigSyncPredicate) Delete(e event.DeleteEvent) bool {
313+
return !isResourceGroup(e.Object) || isOwnedByConfigSync(e.Object)
314+
}
315+
316+
// Update implements predicate.Predicate
317+
func (OwnedByConfigSyncPredicate) Update(e event.UpdateEvent) bool {
318+
return !isResourceGroup(e.ObjectOld) || !isResourceGroup(e.ObjectNew) || isOwnedByConfigSync(e.ObjectOld) || isOwnedByConfigSync(e.ObjectNew)
319+
}
320+
321+
// Generic implements predicate.Predicate
322+
func (OwnedByConfigSyncPredicate) Generic(e event.GenericEvent) bool {
323+
return !isResourceGroup(e.Object) || isOwnedByConfigSync(e.Object)
324+
}
325+
326+
func isResourceGroup(o client.Object) bool {
327+
return o.GetObjectKind().GroupVersionKind().Group == v1alpha1.SchemeGroupVersion.Group &&
328+
o.GetObjectKind().GroupVersionKind().Kind == v1alpha1.ResourceGroupKind
329+
}
330+
331+
func isOwnedByConfigSync(o client.Object) bool {
332+
labels := o.GetLabels()
333+
owner, ok := labels[metadata.ManagedByKey]
334+
return ok && owner == metadata.ManagedByValue
335+
}

pkg/resourcegroup/controllers/root/root_controller_test.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"time"
2121

2222
"github.com/stretchr/testify/assert"
23+
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
2324
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2425
"k8s.io/apimachinery/pkg/runtime/schema"
2526
"k8s.io/apimachinery/pkg/types"
@@ -196,3 +197,105 @@ func TestRootReconciler(t *testing.T) {
196197
time.Sleep(time.Second)
197198
assert.Equal(t, "group0", e.Object.GetName())
198199
}
200+
201+
func TestOwnedByConfigSyncPredicate(t *testing.T) {
202+
type testCase struct {
203+
name string
204+
got bool
205+
want bool
206+
}
207+
208+
ownedByConfigSync := &v1alpha1.ResourceGroup{
209+
ObjectMeta: metav1.ObjectMeta{
210+
Labels: map[string]string{
211+
"app.kubernetes.io/managed-by": "configmanagement.gke.io",
212+
},
213+
Namespace: "foo",
214+
Name: "bar",
215+
},
216+
}
217+
ownedByConfigSync.SetGroupVersionKind(v1alpha1.SchemeGroupVersion.WithKind("ResourceGroup"))
218+
219+
ownedBySomeoneElse := &v1alpha1.ResourceGroup{
220+
ObjectMeta: metav1.ObjectMeta{
221+
Labels: map[string]string{
222+
"app.kubernetes.io/managed-by": "someone-else",
223+
},
224+
Namespace: "foo",
225+
Name: "bar",
226+
},
227+
}
228+
ownedBySomeoneElse.SetGroupVersionKind(v1alpha1.SchemeGroupVersion.WithKind("ResourceGroup"))
229+
230+
notOwned := &v1alpha1.ResourceGroup{
231+
ObjectMeta: metav1.ObjectMeta{
232+
Namespace: "foo",
233+
Name: "bar",
234+
},
235+
}
236+
notOwned.SetGroupVersionKind(v1alpha1.SchemeGroupVersion.WithKind("ResourceGroup"))
237+
238+
notResourceGroup := &v1.CustomResourceDefinition{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}
239+
notResourceGroup.SetGroupVersionKind(v1.SchemeGroupVersion.WithKind("CustomResourceDefinition"))
240+
241+
create := func(o client.Object) bool {
242+
return OwnedByConfigSyncPredicate{}.Create(
243+
event.TypedCreateEvent[client.Object]{Object: o},
244+
)
245+
}
246+
update := func(o client.Object, n client.Object) bool {
247+
return OwnedByConfigSyncPredicate{}.Update(
248+
event.TypedUpdateEvent[client.Object]{ObjectOld: o, ObjectNew: n},
249+
)
250+
}
251+
252+
// not allowed to redefine delete, so we use a different name
253+
yeet := func(o client.Object) bool {
254+
return OwnedByConfigSyncPredicate{}.Delete(
255+
event.TypedDeleteEvent[client.Object]{Object: o},
256+
)
257+
}
258+
259+
generic := func(o client.Object) bool {
260+
return OwnedByConfigSyncPredicate{}.Generic(
261+
event.TypedGenericEvent[client.Object]{Object: o},
262+
)
263+
}
264+
265+
testCases := []testCase{
266+
{name: "create owned by configsync", got: create(ownedByConfigSync), want: true},
267+
{name: "create owned by someone else", got: create(ownedBySomeoneElse), want: false},
268+
{name: "create not owned", got: create(notOwned), want: false},
269+
{name: "create non-resourcegroup owned by configsync", got: create(notResourceGroup), want: true},
270+
271+
{name: "update both owned by configsync", got: update(ownedByConfigSync, ownedByConfigSync), want: true},
272+
{name: "update old owned by configsync, new owned by someone else", got: update(ownedByConfigSync, ownedBySomeoneElse), want: true},
273+
{name: "update old owned by someone else, new owned by configsync", got: update(ownedBySomeoneElse, ownedByConfigSync), want: true},
274+
{name: "update both owned by someone else", got: update(ownedBySomeoneElse, ownedBySomeoneElse), want: false},
275+
{name: "update old not owned, new owned by configsync", got: update(notOwned, ownedByConfigSync), want: true},
276+
{name: "update old owned by configsync, new not owned", got: update(ownedByConfigSync, notOwned), want: true},
277+
{name: "update both not owned", got: update(notOwned, notOwned), want: false},
278+
{name: "update old not owned, new owned by someone else", got: update(notOwned, ownedBySomeoneElse), want: false},
279+
{name: "update old owned by someone else, new not owned", got: update(ownedBySomeoneElse, notOwned), want: false},
280+
{name: "update non-resourcegroup owned by configsync", got: update(notResourceGroup, notResourceGroup), want: true},
281+
282+
{name: "delete owned by configsync", got: yeet(ownedByConfigSync), want: true},
283+
{name: "delete owned by someone else", got: yeet(ownedBySomeoneElse), want: false},
284+
{name: "delete not owned", got: yeet(notOwned), want: false},
285+
{name: "delete non-resourcegroup owned by configsync", got: yeet(notResourceGroup), want: true},
286+
287+
{name: "generic owned by configsync", got: generic(ownedByConfigSync), want: true},
288+
{name: "generic owned by someone else", got: generic(ownedBySomeoneElse), want: false},
289+
{name: "generic not owned", got: generic(notOwned), want: false},
290+
{name: "generic non-resourcegroup owned by configsync", got: generic(notResourceGroup), want: true},
291+
}
292+
293+
for _, testCase := range testCases {
294+
t.Run(testCase.name, func(t *testing.T) {
295+
t.Parallel()
296+
if testCase.got != testCase.want {
297+
t.Errorf("%s = %v, want %v", testCase.name, testCase.got, testCase.want)
298+
}
299+
})
300+
}
301+
}

0 commit comments

Comments
 (0)