Skip to content

Commit

Permalink
Ansible operator: Adding support for event filtering via predicates
Browse files Browse the repository at this point in the history
Event filtering will allow Ansible operator to skip reconciles that are not required

Fixes operator-framework#1968
  • Loading branch information
Rammohan authored and rammohanc committed Oct 23, 2019
1 parent bfabaf5 commit 31c7887
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 43 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

### Added

- Added support for event filtering for ansible operator. ([#1968](https://github.com/operator-framework/operator-sdk/issues/1968))
- Added new `--skip-generation` flag to the `operator-sdk add api` command to support skipping generation of deepcopy and OpenAPI code and OpenAPI CRD specs. ([#1890](https://github.com/operator-framework/operator-sdk/pull/1890))
- The `operator-sdk olm-catalog gen-csv` command now produces indented JSON for the `alm-examples` annotation. ([#1793](https://github.com/operator-framework/operator-sdk/pull/1793))
- Added flag `--dep-manager` to command [`operator-sdk print-deps`](https://github.com/operator-framework/operator-sdk/blob/master/doc/sdk-cli-reference.md#print-deps) to specify the type of dependency manager file to print. The choice of dependency manager is inferred from top-level dependency manager files present if `--dep-manager` is not set. ([#1819](https://github.com/operator-framework/operator-sdk/pull/1819))
Expand Down
9 changes: 7 additions & 2 deletions pkg/ansible/proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"github.com/operator-framework/operator-sdk/pkg/ansible/proxy/kubeconfig"
k8sRequest "github.com/operator-framework/operator-sdk/pkg/ansible/proxy/requestfactory"
osdkHandler "github.com/operator-framework/operator-sdk/pkg/handler"
"github.com/operator-framework/operator-sdk/pkg/internal/predicates"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
Expand Down Expand Up @@ -210,6 +211,10 @@ func addWatchToController(owner kubeconfig.NamespacedOwnerReference, cMap *contr
awMap := contents.AnnotationWatchMap
u := &unstructured.Unstructured{}
u.SetGroupVersionKind(ownerMapping.GroupVersionKind)

// Adding dependentPredicate for avoiding reconciles when dependent objects are not changed by user
dependentPredicate := predicates.PredicateFuncs()

// Add a watch to controller
if contents.WatchDependentResources {
// Store watch in map
Expand All @@ -224,8 +229,8 @@ func addWatchToController(owner kubeconfig.NamespacedOwnerReference, cMap *contr

owMap.Store(resource.GroupVersionKind())
log.Info("Watching child resource", "kind", resource.GroupVersionKind(), "enqueue_kind", u.GroupVersionKind())
err := contents.Controller.Watch(&source.Kind{Type: resource}, &handler.EnqueueRequestForOwner{OwnerType: u}, dependentPredicate)
// Store watch in map
err := contents.Controller.Watch(&source.Kind{Type: resource}, &handler.EnqueueRequestForOwner{OwnerType: u})
if err != nil {
return err
}
Expand All @@ -238,7 +243,7 @@ func addWatchToController(owner kubeconfig.NamespacedOwnerReference, cMap *contr
awMap.Store(resource.GroupVersionKind())
typeString := fmt.Sprintf("%v.%v", owner.Kind, ownerGV.Group)
log.Info("Watching child resource", "kind", resource.GroupVersionKind(), "enqueue_annotation_type", typeString)
err = contents.Controller.Watch(&source.Kind{Type: resource}, &osdkHandler.EnqueueRequestForAnnotation{Type: typeString})
err = contents.Controller.Watch(&source.Kind{Type: resource}, &osdkHandler.EnqueueRequestForAnnotation{Type: typeString}, dependentPredicate)
if err != nil {
return err
}
Expand Down
44 changes: 3 additions & 41 deletions pkg/helm/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
"bytes"
"fmt"
"io"
"reflect"
"strings"
"sync"
"time"
Expand All @@ -30,14 +29,13 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
rpb "k8s.io/helm/pkg/proto/hapi/release"
"sigs.k8s.io/controller-runtime/pkg/controller"
"sigs.k8s.io/controller-runtime/pkg/event"
crthandler "sigs.k8s.io/controller-runtime/pkg/handler"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/manager"
crtpredicate "sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/source"

"github.com/operator-framework/operator-sdk/pkg/helm/release"
"github.com/operator-framework/operator-sdk/pkg/internal/predicates"
"github.com/operator-framework/operator-sdk/pkg/predicate"
)

Expand Down Expand Up @@ -92,44 +90,8 @@ func watchDependentResources(mgr manager.Manager, r *HelmOperatorReconciler, c c
owner := &unstructured.Unstructured{}
owner.SetGroupVersionKind(r.GVK)

dependentPredicate := crtpredicate.Funcs{
// We don't need to reconcile dependent resource creation events
// because dependent resources are only ever created during
// reconciliation. Another reconcile would be redundant.
CreateFunc: func(e event.CreateEvent) bool {
o := e.Object.(*unstructured.Unstructured)
log.V(1).Info("Skipping reconciliation for dependent resource creation", "name", o.GetName(), "namespace", o.GetNamespace(), "apiVersion", o.GroupVersionKind().GroupVersion(), "kind", o.GroupVersionKind().Kind)
return false
},

// Reconcile when a dependent resource is deleted so that it can be
// recreated.
DeleteFunc: func(e event.DeleteEvent) bool {
o := e.Object.(*unstructured.Unstructured)
log.V(1).Info("Reconciling due to dependent resource deletion", "name", o.GetName(), "namespace", o.GetNamespace(), "apiVersion", o.GroupVersionKind().GroupVersion(), "kind", o.GroupVersionKind().Kind)
return true
},

// Reconcile when a dependent resource is updated, so that it can
// be patched back to the resource managed by the Helm release, if
// necessary. Ignore updates that only change the status and
// resourceVersion.
UpdateFunc: func(e event.UpdateEvent) bool {
old := e.ObjectOld.(*unstructured.Unstructured).DeepCopy()
new := e.ObjectNew.(*unstructured.Unstructured).DeepCopy()

delete(old.Object, "status")
delete(new.Object, "status")
old.SetResourceVersion("")
new.SetResourceVersion("")

if reflect.DeepEqual(old.Object, new.Object) {
return false
}
log.V(1).Info("Reconciling due to dependent resource update", "name", new.GetName(), "namespace", new.GetNamespace(), "apiVersion", new.GroupVersionKind().GroupVersion(), "kind", new.GroupVersionKind().Kind)
return true
},
}
// using predefined functions for filtering events
dependentPredicate := predicates.PredicateFuncs()

var m sync.RWMutex
watches := map[schema.GroupVersionKind]struct{}{}
Expand Down
78 changes: 78 additions & 0 deletions pkg/internal/predicates/predicates.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright 2019 The Operator-SDK 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 predicates

import (
"reflect"

"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/event"
logf "sigs.k8s.io/controller-runtime/pkg/log"
crtpredicate "sigs.k8s.io/controller-runtime/pkg/predicate"
)

var log = logf.Log.WithName("predicates")

// PredicateFuncs returns functions defined for filtering events
func PredicateFuncs() crtpredicate.Funcs {

dependentPredicate := crtpredicate.Funcs{
// We don't need to reconcile dependent resource creation events
// because dependent resources are only ever created during
// reconciliation. Another reconcile would be redundant.
CreateFunc: func(e event.CreateEvent) bool {
o := e.Object.(*unstructured.Unstructured)
log.V(1).Info("Skipping reconciliation for dependent resource creation", "name", o.GetName(), "namespace", o.GetNamespace(), "apiVersion", o.GroupVersionKind().GroupVersion(), "kind", o.GroupVersionKind().Kind)
return false
},

// Reconcile when a dependent resource is deleted so that it can be
// recreated.
DeleteFunc: func(e event.DeleteEvent) bool {
o := e.Object.(*unstructured.Unstructured)
log.V(1).Info("Reconciling due to dependent resource deletion", "name", o.GetName(), "namespace", o.GetNamespace(), "apiVersion", o.GroupVersionKind().GroupVersion(), "kind", o.GroupVersionKind().Kind)
return true
},

// Don't reconcile when a generic event is received for a dependent
GenericFunc: func(e event.GenericEvent) bool {
o := e.Object.(*unstructured.Unstructured)
log.V(1).Info("Skipping reconcile due to generic event", "name", o.GetName(), "namespace", o.GetNamespace(), "apiVersion", o.GroupVersionKind().GroupVersion(), "kind", o.GroupVersionKind().Kind)
return false
},

// Reconcile when a dependent resource is updated, so that it can
// be patched back to the resource managed by the CR, if
// necessary. Ignore updates that only change the status and
// resourceVersion.
UpdateFunc: func(e event.UpdateEvent) bool {
old := e.ObjectOld.(*unstructured.Unstructured).DeepCopy()
new := e.ObjectNew.(*unstructured.Unstructured).DeepCopy()

delete(old.Object, "status")
delete(new.Object, "status")
old.SetResourceVersion("")
new.SetResourceVersion("")

if reflect.DeepEqual(old.Object, new.Object) {
return false
}
log.V(1).Info("Reconciling due to dependent resource update", "name", new.GetName(), "namespace", new.GetNamespace(), "apiVersion", new.GroupVersionKind().GroupVersion(), "kind", new.GroupVersionKind().Kind)
return true
},
}

return dependentPredicate
}

0 comments on commit 31c7887

Please sign in to comment.