Skip to content

Commit

Permalink
resolve operators on catalog availability change
Browse files Browse the repository at this point in the history
Signed-off-by: Ankita Thomas <ankithom@redhat.com>
  • Loading branch information
ankitathomas committed May 16, 2023
1 parent 4ea83e6 commit 9eaf91f
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 3 deletions.
7 changes: 7 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ rules:
verbs:
- list
- watch
- apiGroups:
- catalogd.operatorframework.io
resources:
- catalogsources
verbs:
- list
- watch
- apiGroups:
- catalogd.operatorframework.io
resources:
Expand Down
115 changes: 115 additions & 0 deletions controllers/catalog_predicates.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package controllers

import (
"context"
"fmt"

"github.com/go-logr/logr"
catalogd "github.com/operator-framework/catalogd/pkg/apis/core/v1beta1"
operatorv1alpha1 "github.com/operator-framework/operator-controller/api/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)

// Predicate for reconciling operators when available (i.e. ready) catalogsources on cluster change
type catalogReadyTransitionPredicate struct {
predicate.Funcs
catalogReady map[string]bool
}

func newCatalogReadyTransitionPredicate() *catalogReadyTransitionPredicate {
return &catalogReadyTransitionPredicate{
catalogReady: map[string]bool{},
}
}

func (c *catalogReadyTransitionPredicate) Create(e event.CreateEvent) bool {
fmt.Println("CreateEvent CatalogSource", e.Object.GetName())
catalogReady, err := isCatalogReady(e.Object)
if err != nil {
fmt.Println(err)
return false
}
c.catalogReady[e.Object.GetName()] = catalogReady
return catalogReady
}

func (c *catalogReadyTransitionPredicate) Update(e event.UpdateEvent) bool {
fmt.Println("UpdateEvent CatalogSource", e.ObjectOld.GetName(), e.ObjectNew.GetName())
oldCatalogReady, err := isCatalogReady(e.ObjectOld)
if err != nil {
fmt.Println(err)
return false
}

newCatalogReady, err := isCatalogReady(e.ObjectNew)
if err != nil {
fmt.Println(err)
return false
}

c.catalogReady[e.ObjectNew.GetName()] = newCatalogReady
// TODO: determine if ready -> non-ready transition triggers reconcile with stale catalog contents
return oldCatalogReady != newCatalogReady
}

func (c *catalogReadyTransitionPredicate) Delete(e event.DeleteEvent) bool {
fmt.Println("DeleteEvent CatalogSource", e.Object.GetName())
delete(c.catalogReady, e.Object.GetName())
return true
}

func (c *catalogReadyTransitionPredicate) Generic(e event.GenericEvent) bool {
fmt.Println("GenericEvent CatalogSource", e.Object.GetName())
catalogReady, err := isCatalogReady(e.Object)
if err != nil {
fmt.Println(err)
return false
}
predicateState := c.catalogReady[e.Object.GetName()] != catalogReady
c.catalogReady[e.Object.GetName()] = catalogReady
return predicateState
}

func isCatalogReady(o client.Object) (bool, error) {
catalog, ok := o.(*catalogd.CatalogSource)
if !ok {
return false, fmt.Errorf("wrong object type: not a catalogsource: %+v", o)
}
if len(catalog.Status.Conditions) > 0 {
for _, cond := range catalog.Status.Conditions {
if cond.Type == catalogd.TypeReady && cond.Status == v1.ConditionTrue {
return true, nil
}
}
}
return false, nil
}

// Generate reconcile requests for all operators affected by a catalog change
func operatorRequestsForCatalog(ctx context.Context, c client.Client, logger logr.Logger) handler.MapFunc {
return func(object client.Object) []reconcile.Request {
// no way of associating an operator to a catalog so create reconcile requests for everything
operators := operatorv1alpha1.OperatorList{}
err := c.List(ctx, &operators)
if err != nil {
logger.Error(err, "unable to enqueue operators for catalog reconcile")
return nil
}
var requests []reconcile.Request
for _, op := range operators.Items {
requests = append(requests, reconcile.Request{
NamespacedName: types.NamespacedName{
Namespace: op.GetNamespace(),
Name: op.GetName(),
},
})
}
return requests
}
}
11 changes: 9 additions & 2 deletions controllers/operator_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ import (
"context"
"fmt"

catalogd "github.com/operator-framework/catalogd/pkg/apis/core/v1beta1"
"github.com/operator-framework/deppy/pkg/deppy/solver"
"github.com/operator-framework/operator-controller/controllers/validators"
rukpakv1alpha1 "github.com/operator-framework/rukpak/api/v1alpha1"
"k8s.io/apimachinery/pkg/api/equality"
apimeta "k8s.io/apimachinery/pkg/api/meta"
Expand All @@ -31,10 +33,11 @@ import (
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/utils/pointer"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/log"

"github.com/operator-framework/operator-controller/controllers/validators"
"sigs.k8s.io/controller-runtime/pkg/source"

operatorsv1alpha1 "github.com/operator-framework/operator-controller/api/v1alpha1"
"github.com/operator-framework/operator-controller/internal/resolution"
Expand All @@ -57,6 +60,7 @@ type OperatorReconciler struct {

//+kubebuilder:rbac:groups=catalogd.operatorframework.io,resources=bundlemetadata,verbs=list;watch
//+kubebuilder:rbac:groups=catalogd.operatorframework.io,resources=packages,verbs=list;watch
//+kubebuilder:rbac:groups=catalogd.operatorframework.io,resources=catalogsources,verbs=list;watch

func (r *OperatorReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
l := log.FromContext(ctx).WithName("operator-controller")
Expand Down Expand Up @@ -294,6 +298,9 @@ func (r *OperatorReconciler) generateExpectedBundleDeployment(o operatorsv1alpha
func (r *OperatorReconciler) SetupWithManager(mgr ctrl.Manager) error {
err := ctrl.NewControllerManagedBy(mgr).
For(&operatorsv1alpha1.Operator{}).
Watches(source.NewKindWithCache(&catalogd.CatalogSource{}, mgr.GetCache()),
handler.EnqueueRequestsFromMapFunc(operatorRequestsForCatalog(context.TODO(), mgr.GetClient(), mgr.GetLogger())),
builder.WithPredicates(newCatalogReadyTransitionPredicate())).
Owns(&rukpakv1alpha1.BundleDeployment{}).
Complete(r)

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.19

require (
github.com/blang/semver/v4 v4.0.0
github.com/go-logr/logr v1.2.3
github.com/onsi/ginkgo/v2 v2.8.3
github.com/onsi/gomega v1.27.1
github.com/operator-framework/catalogd v0.1.3
Expand All @@ -26,7 +27,6 @@ require (
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-air/gini v1.0.4 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/zapr v1.2.3 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.20.0 // indirect
Expand Down

0 comments on commit 9eaf91f

Please sign in to comment.