Skip to content

Commit de4f99a

Browse files
Add option to watch List object types (#138)
This commit modifies `dependentResourceWatcher` to accept `List` kinds while watching dependent resources. It also adds test to verify if `setWatchOnResource` works for lists. Reference: operator-framework/operator-sdk#4682 Signed-off-by: varshaprasad96 <[email protected]>
1 parent 70c7509 commit de4f99a

File tree

2 files changed

+88
-16
lines changed

2 files changed

+88
-16
lines changed

pkg/reconciler/internal/hook/hook.go

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"helm.sh/helm/v3/pkg/releaseutil"
2626
"k8s.io/apimachinery/pkg/api/meta"
2727
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
28+
"k8s.io/apimachinery/pkg/runtime"
2829
"k8s.io/apimachinery/pkg/runtime/schema"
2930
"sigs.k8s.io/controller-runtime/pkg/controller"
3031
"sigs.k8s.io/controller-runtime/pkg/handler"
@@ -69,32 +70,65 @@ func (d *dependentResourceWatcher) Exec(owner *unstructured.Unstructured, rel re
6970
}
7071

7172
depGVK := obj.GroupVersionKind()
72-
if _, ok := d.watches[depGVK]; ok || depGVK.Empty() {
73+
if depGVK.Empty() {
7374
continue
7475
}
7576

76-
useOwnerRef, err := controllerutil.SupportsOwnerReference(d.restMapper, owner, &obj)
77-
if err != nil {
78-
return err
79-
}
77+
var setWatchOnResource = func(dependent runtime.Object) error {
78+
unstructuredObj := dependent.(*unstructured.Unstructured)
79+
gvkDependent := unstructuredObj.GroupVersionKind()
80+
81+
if gvkDependent.Empty() {
82+
return nil
83+
}
84+
85+
_, ok := d.watches[gvkDependent]
86+
if ok {
87+
return nil
88+
}
8089

81-
if useOwnerRef && !manifestutil.HasResourcePolicyKeep(obj.GetAnnotations()) {
82-
if err := d.controller.Watch(&source.Kind{Type: &obj}, &handler.EnqueueRequestForOwner{
83-
OwnerType: owner,
84-
IsController: true,
85-
}, dependentPredicate); err != nil {
90+
useOwnerRef, err := controllerutil.SupportsOwnerReference(d.restMapper, owner, unstructuredObj)
91+
if err != nil {
8692
return err
8793
}
94+
95+
if useOwnerRef && !manifestutil.HasResourcePolicyKeep(unstructuredObj.GetAnnotations()) { // Setup watch using owner references.
96+
if err := d.controller.Watch(&source.Kind{Type: unstructuredObj}, &handler.EnqueueRequestForOwner{
97+
OwnerType: owner,
98+
IsController: true,
99+
}, dependentPredicate); err != nil {
100+
return err
101+
}
102+
} else { // Setup watch using annotations.
103+
if err := d.controller.Watch(&source.Kind{Type: unstructuredObj}, &sdkhandler.EnqueueRequestForAnnotation{
104+
Type: owner.GetObjectKind().GroupVersionKind().GroupKind(),
105+
}, dependentPredicate); err != nil {
106+
return err
107+
}
108+
}
109+
110+
d.watches[depGVK] = struct{}{}
111+
log.V(1).Info("Watching dependent resource", "dependentAPIVersion", depGVK.GroupVersion(), "dependentKind", depGVK.Kind)
112+
return nil
113+
}
114+
115+
// List is not actually a resource and therefore cannot have a
116+
// watch on it. The watch will be on the kinds listed in the list
117+
// and will therefore need to be handled individually.
118+
listGVK := schema.GroupVersionKind{Group: "", Version: "v1", Kind: "List"}
119+
if depGVK == listGVK {
120+
errListItem := obj.EachListItem(func(o runtime.Object) error {
121+
return setWatchOnResource(o)
122+
})
123+
if errListItem != nil {
124+
return errListItem
125+
}
88126
} else {
89-
if err := d.controller.Watch(&source.Kind{Type: &obj}, &sdkhandler.EnqueueRequestForAnnotation{
90-
Type: owner.GetObjectKind().GroupVersionKind().GroupKind(),
91-
}, dependentPredicate); err != nil {
127+
err := setWatchOnResource(&obj)
128+
if err != nil {
92129
return err
93130
}
94131
}
95-
96-
d.watches[depGVK] = struct{}{}
97-
log.V(1).Info("Watching dependent resource", "dependentAPIVersion", depGVK.GroupVersion(), "dependentKind", depGVK.Kind)
98132
}
99133
return nil
100134
}

pkg/reconciler/internal/hook/hook_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,24 @@ var _ = Describe("Hook", func() {
215215
Expect(c.WatchCalls[1].Handler).To(BeAssignableToTypeOf(&sdkhandler.EnqueueRequestForAnnotation{}))
216216
Expect(c.WatchCalls[2].Handler).To(BeAssignableToTypeOf(&sdkhandler.EnqueueRequestForAnnotation{}))
217217
})
218+
It("should iterate the kind list and be able to set watches on each item", func() {
219+
rel = &release.Release{
220+
Manifest: strings.Join([]string{replicaSetList}, "---\n"),
221+
}
222+
drw = internalhook.NewDependentResourceWatcher(c, rm)
223+
Expect(drw.Exec(owner, *rel, log)).To(Succeed())
224+
Expect(c.WatchCalls).To(HaveLen(2))
225+
Expect(c.WatchCalls[0].Handler).To(BeAssignableToTypeOf(&handler.EnqueueRequestForOwner{}))
226+
Expect(c.WatchCalls[1].Handler).To(BeAssignableToTypeOf(&handler.EnqueueRequestForOwner{}))
227+
})
228+
It("should error when unable to list objects", func() {
229+
rel = &release.Release{
230+
Manifest: strings.Join([]string{errReplicaSetList}, "---\n"),
231+
}
232+
drw = internalhook.NewDependentResourceWatcher(c, rm)
233+
err := drw.Exec(owner, *rel, log)
234+
Expect(err).To(HaveOccurred())
235+
})
218236
})
219237
})
220238
})
@@ -280,5 +298,25 @@ metadata:
280298
name: testClusterRoleBinding
281299
annotations:
282300
helm.sh/resource-policy: keep
301+
`
302+
replicaSetList = `
303+
apiVersion: v1
304+
kind: List
305+
items:
306+
- apiVersion: apps/v1
307+
kind: ReplicaSet
308+
metadata:
309+
name: testReplicaSet1
310+
namespace: ownerNamespace
311+
- apiVersion: apps/v1
312+
kind: ReplicaSet
313+
metadata:
314+
name: testReplicaSet2
315+
namespace: ownerNamespace
316+
`
317+
errReplicaSetList = `
318+
apiVersion: v1
319+
kind: List
320+
items:
283321
`
284322
)

0 commit comments

Comments
 (0)