Skip to content

Commit

Permalink
Handle List kind in watch
Browse files Browse the repository at this point in the history
Signed-off-by: Martin Hickey <martin.hickey@ie.ibm.com>
  • Loading branch information
hickeyma committed Mar 18, 2021
1 parent a37320e commit 7ec5eaf
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 24 deletions.
11 changes: 11 additions & 0 deletions changelog/fragments/helm-handle-list-kind.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# entries is a list of entries to include in
# release notes and/or the migration guide
entries:
- description: >
For Helm-based operators, fixes handling of `kind: List` whereby the
operator fails when trying to set watch on the object. The fix now sets
the watch on the objects of the list instead.
kind: "bugfix"
breaking: false
76 changes: 52 additions & 24 deletions internal/helm/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ import (
"sync"
"time"

"github.com/operator-framework/operator-lib/handler"
rpb "helm.sh/helm/v3/pkg/release"
"helm.sh/helm/v3/pkg/releaseutil"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/controller"
crthandler "sigs.k8s.io/controller-runtime/pkg/handler"
Expand Down Expand Up @@ -80,7 +80,7 @@ func Add(mgr manager.Manager, options WatchOptions) error {

o := &unstructured.Unstructured{}
o.SetGroupVersionKind(options.GVK)
if err := c.Watch(&source.Kind{Type: o}, &handler.InstrumentedEnqueueRequestForObject{}); err != nil {
if err := c.Watch(&source.Kind{Type: o}, &libhandler.InstrumentedEnqueueRequestForObject{}); err != nil {
return err
}

Expand Down Expand Up @@ -113,37 +113,65 @@ func watchDependentResources(mgr manager.Manager, r *HelmOperatorReconciler, c c
if gvk.Empty() {
continue
}
m.RLock()
_, ok := watches[gvk]
m.RUnlock()
if ok {
continue
}

restMapper := mgr.GetRESTMapper()
useOwnerRef, err := k8sutil.SupportsOwnerReference(restMapper, owner, &u)
if err != nil {
return err
}
var setWatchOnResource = func(dependent runtime.Object) error {
unstructuredObj := dependent.(*unstructured.Unstructured)
gvkDependent := unstructuredObj.GroupVersionKind()
if gvkDependent.Empty() {
return nil
}

m.RLock()
_, ok := watches[gvkDependent]
m.RUnlock()
if ok {
return nil
}

if useOwnerRef { // Setup watch using owner references.
err = c.Watch(&source.Kind{Type: &u}, &crthandler.EnqueueRequestForOwner{OwnerType: owner},
predicate.DependentPredicate{})
restMapper := mgr.GetRESTMapper()
useOwnerRef, err := k8sutil.SupportsOwnerReference(restMapper, owner, dependent)
if err != nil {
return err
}
} else { // Setup watch using annotations.
err = c.Watch(&source.Kind{Type: &u}, &libhandler.EnqueueRequestForAnnotation{Type: gvk.GroupKind()},
predicate.DependentPredicate{})

if useOwnerRef { // Setup watch using owner references.
err = c.Watch(&source.Kind{Type: unstructuredObj}, &crthandler.EnqueueRequestForOwner{OwnerType: owner},
predicate.DependentPredicate{})
if err != nil {
return err
}
} else { // Setup watch using annotations.
err = c.Watch(&source.Kind{Type: unstructuredObj}, &libhandler.EnqueueRequestForAnnotation{Type: gvkDependent.GroupKind()},
predicate.DependentPredicate{})
if err != nil {
return err
}
}
m.Lock()
watches[gvkDependent] = struct{}{}
m.Unlock()
log.Info("Watching dependent resource", "ownerApiVersion", r.GVK.GroupVersion(),
"ownerKind", r.GVK.Kind, "apiVersion", gvkDependent.GroupVersion(), "kind", gvkDependent.Kind)
return nil
}

// List is not actually a resource and therefore cannot have a
// watch on it. The watch will be on the kinds listed in the list
// and will therefore need to be handled individually.
listGVK := schema.GroupVersionKind{Group: "", Version: "v1", Kind: "List"}
if gvk == listGVK {
errListItem := u.EachListItem(func(obj runtime.Object) error {
return setWatchOnResource(obj)
})
if errListItem != nil {
return errListItem
}
} else {
err := setWatchOnResource(&u)
if err != nil {
return err
}
}
m.Lock()
watches[gvk] = struct{}{}
m.Unlock()
log.Info("Watching dependent resource", "ownerApiVersion", r.GVK.GroupVersion(),
"ownerKind", r.GVK.Kind, "apiVersion", gvk.GroupVersion(), "kind", gvk.Kind)
}
return nil
}
Expand Down

0 comments on commit 7ec5eaf

Please sign in to comment.