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
…2024)

Event filtering will allow Ansible operator to skip reconciles that are not required

Fixes #1968
  • Loading branch information
rammohanc authored and joelanford committed Oct 30, 2019
1 parent 0e7e74d commit 662d20b
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 @@ -40,6 +40,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.DependentPredicateFuncs()

// 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.DependentPredicateFuncs()

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")

// DependentPredicateFuncs returns functions defined for filtering events
func DependentPredicateFuncs() 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 662d20b

Please sign in to comment.