Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose generic mechanism for configuring the controller builder #153

Merged
merged 1 commit into from
Jul 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions pkg/reconciler/reconciler.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ type Reconciler struct {
reconcilePeriod time.Duration
maxHistory int
skipPrimaryGVKSchemeRegistration bool
controllerSetupFuncs []ControllerSetupFunc

annotSetupOnce sync.Once
annotations map[string]struct{}
Expand Down Expand Up @@ -145,6 +146,13 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
return err
}

for _, f := range r.controllerSetupFuncs {
err = f(c)
if err != nil {
return fmt.Errorf("failed to execute custom controller setup function: %v", err)
}
}

r.log.Info("Watching resource",
"group", r.gvk.Group,
"version", r.gvk.Version,
Expand Down Expand Up @@ -478,6 +486,30 @@ func WithSelector(s metav1.LabelSelector) Option {
}
}

// WithControllerSetupFunc is an Option that allows customizing a controller before it is started.
// The only supported customization here is adding additional Watch sources to the controller.
func WithControllerSetupFunc(f ControllerSetupFunc) Option {
return func(r *Reconciler) error {
r.controllerSetupFuncs = append(r.controllerSetupFuncs, f)
return nil
}
}

// ControllerSetup allows restricted access to the Controller using the WithControllerSetupFunc option.
// Currently the only supposed configuration is adding additional watchers do the controller.
type ControllerSetup interface {
// Watch takes events provided by a Source and uses the EventHandler to
// enqueue reconcile.Requests in response to the events.
//
// Watch may be provided one or more Predicates to filter events before
// they are given to the EventHandler. Events will be passed to the
// EventHandler if all provided Predicates evaluate to true.
Watch(src source.Source, eventhandler handler.EventHandler, predicates ...predicate.Predicate) error
varshaprasad96 marked this conversation as resolved.
Show resolved Hide resolved
}

// ControllerSetupFunc allows configuring a controller's builder.
type ControllerSetupFunc func(c ControllerSetup) error

// Reconcile reconciles a CR that defines a Helm v3 release.
//
// - If a release does not exist for this CR, a new release is installed.
Expand Down
39 changes: 39 additions & 0 deletions pkg/reconciler/reconciler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/log/zap"
"sigs.k8s.io/controller-runtime/pkg/manager"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"
"sigs.k8s.io/yaml"

"github.com/operator-framework/helm-operator-plugins/internal/sdk/controllerutil"
Expand All @@ -58,6 +59,7 @@ import (
"github.com/operator-framework/helm-operator-plugins/pkg/reconciler/internal/conditions"
helmfake "github.com/operator-framework/helm-operator-plugins/pkg/reconciler/internal/fake"
"github.com/operator-framework/helm-operator-plugins/pkg/values"
sdkhandler "github.com/operator-framework/operator-lib/handler"
)

// custom is used within the reconciler test suite as underlying type for the GVK scheme.
Expand Down Expand Up @@ -1328,6 +1330,43 @@ var _ = Describe("Reconciler", func() {
})

})

var _ = Describe("Test custom controller setup", func() {
var (
mgr manager.Manager
r *Reconciler
err error
controllerSetupCalled bool
)
additionalGVK := schema.GroupVersionKind{Group: "example.com", Version: "v1", Kind: "SomeOtherKind"}
setupController := func(c ControllerSetup) error {
controllerSetupCalled = true
u := &unstructured.Unstructured{}
u.SetGroupVersionKind(additionalGVK)
return c.Watch(&source.Kind{Type: u}, &sdkhandler.InstrumentedEnqueueRequestForObject{})
}

It("Registering builder setup function for reconciler works", func() {
mgr = getManagerOrFail()
r, err = New(
WithGroupVersionKind(gvk),
WithChart(chrt),
WithInstallAnnotations(annotation.InstallDescription{}),
WithUpgradeAnnotations(annotation.UpgradeDescription{}),
WithUninstallAnnotations(annotation.UninstallDescription{}),
WithOverrideValues(map[string]string{
"image.repository": "custom-nginx",
}),
WithControllerSetupFunc(setupController),
)
Expect(err).To(BeNil())
})

It("Setting up reconciler with manager causes custom builder setup to be executed", func() {
Expect(r.SetupWithManager(mgr)).To(Succeed())
Expect(controllerSetupCalled).To(BeTrue())
})
})
})

func getManagerOrFail() manager.Manager {
Expand Down