Skip to content

API-1835: intro dispatcher filters#7552

Open
p0lyn0mial wants to merge 5 commits intoopenshift:mainfrom
p0lyn0mial:om-phase-2-in-res-dispatcher-filters
Open

API-1835: intro dispatcher filters#7552
p0lyn0mial wants to merge 5 commits intoopenshift:mainfrom
p0lyn0mial:om-phase-2-in-res-dispatcher-filters

Conversation

@p0lyn0mial
Copy link
Contributor

@p0lyn0mial p0lyn0mial commented Jan 20, 2026

requires #7477 and #7543

prepares matchers to filter cluster(s) resources based on inputResources

please reviewfeat(openshiftmanager-phase2): intro buildInputResourceFilters and feat(openshiftmanager-phase2): remove fakeRESTMapperFor

Adds an input resource initializer runnable for OpenShiftManager that discovers
input resources and wires informers, and registers it in the controller setup.

Notes: discovery is still a stub and we still need to register informer handlers and add filtering.
inputResourceDispatcher is a simple dispatcher that applies GVK scoped filters
and forwards matching events.

Each GVK has its own set of filters. Today these
may include name/namespace checks, and in the future label selectors.

Longer term, this dispatcher is expected to track which input resources are
associated with which operator.
@openshift-merge-robot openshift-merge-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jan 20, 2026
@openshift-merge-robot
Copy link
Contributor

PR needs rebase.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 20, 2026

Walkthrough

Adds an input resource dispatcher and initializer to discover, validate, filter, and dispatch input resource events by GVK; includes unit tests for both components, wires the initializer into the openshiftmanager controller setup, and updates module dependencies.

Changes

Cohort / File(s) Summary
Input Resource Dispatcher
control-plane-operator/controllers/openshiftmanager/input_resource_dispatcher.go
New unexported inputResourceDispatcher with newInputResourceDispatcher(filters map[schema.GroupVersionKind][]inputResourceEventFilter), Handle(gvk schema.GroupVersionKind, cObj client.Object) applying GVK-specific filters to emit event.GenericEvent, and ResultChan() <-chan event.GenericEvent.
Dispatcher Tests
control-plane-operator/controllers/openshiftmanager/input_resource_dispatcher_test.go
New tests covering filter match, non-match, no-filters, multiple-filters scenarios; includes helpers readEvents and ensureNoMoreEvents.
Input Resource Initializer
control-plane-operator/controllers/openshiftmanager/input_resource_initializer.go
New unexported inputResourceInitializer with constructor, discovery/validation logic (supports only ApplyConfigurationResources.exactResources), informer startup (startAndWaitForInformersFor), filter builder (buildInputResourceFilters), and exact-resource matching predicates; contains TODOs for remaining features.
Initializer Tests & Fakes
control-plane-operator/controllers/openshiftmanager/input_resource_initializer_test.go
New comprehensive tests: validation scenarios, startAndWaitForInformersFor behavior (deduplication, mapper/informer/cache errors), and buildInputResourceFilters; adds fakeCache and fakeRESTMapperForResources helpers.
Controller Integration
control-plane-operator/controllers/openshiftmanager/openshiftmanager_controller.go
Removes unused fmt import and replaces the previous not-implemented error in SetupWithManager with creation and mgr.Add(inputResInitializer) to register the initializer.
Module Dependencies
go.mod
Adds github.com/openshift/multi-operator-manager v0.0.0-20260112172834-b64ebc8c627b and indirect requires github.com/PaesslerAG/gval, github.com/PaesslerAG/jsonpath, github.com/shopspring/decimal.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

@openshift-ci openshift-ci bot requested review from csrwng and sjenning January 20, 2026 13:15
@p0lyn0mial p0lyn0mial changed the title Om phase 2 in res dispatcher filters API-1835: intro dispatcher filters Jan 20, 2026
@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jan 20, 2026
@openshift-ci-robot
Copy link

openshift-ci-robot commented Jan 20, 2026

@p0lyn0mial: This pull request references API-1835 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the epic to target the "4.22.0" version, but no target version was set.

Details

In response to this:

What this PR does / why we need it:

Which issue(s) this PR fixes:

Fixes

Special notes for your reviewer:

Checklist:

  • Subject and description added to both, commit and PR.
  • Relevant issues have been referenced.
  • This change includes docs.
  • This change includes unit tests.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci openshift-ci bot added area/control-plane-operator Indicates the PR includes changes for the control plane operator - in an OCP release and removed do-not-merge/needs-area labels Jan 20, 2026
@openshift-ci-robot
Copy link

openshift-ci-robot commented Jan 20, 2026

@p0lyn0mial: This pull request references API-1835 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the epic to target the "4.22.0" version, but no target version was set.

Details

In response to this:

requires #7477 and #7543

prepares matchers to filter cluster(s) resources based on inputResources

please reviewfeat(openshiftmanager-phase2): intro buildInputResourceFilters and feat(openshiftmanager-phase2): remove fakeRESTMapperFor

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@p0lyn0mial
Copy link
Contributor Author

/assign @benluddy @bertinatto @csrwng

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In
`@control-plane-operator/controllers/openshiftmanager/input_resource_dispatcher.go`:
- Around line 10-42: The dispatcher currently creates an unbuffered eventsCh
which makes inputResourceDispatcher.Handle block if no receiver is ready; update
newInputResourceDispatcher to create a buffered channel (eventsCh := make(chan
event.GenericEvent, <reasonableSize>)) so Handle can send without blocking
briefly (choose a small constant like 16 or make the buffer size configurable),
keep the rest of inputResourceDispatcher, Handle and filters logic unchanged,
and ensure any shutdown/consumer code can drain the channel if needed.

In
`@control-plane-operator/controllers/openshiftmanager/input_resource_initializer.go`:
- Around line 36-50: The Start method always fails because
discoverInputResources currently returns a "not implemented" error; replace the
stub so discovery is a safe no-op until real discovery is implemented: change
discoverInputResources to return an empty
map[string]*libraryinputresources.InputResources and nil (so inputResources is
empty) or alternatively early-return from Start when discovery is not ready, but
do not return an error. Update references to
inputResourceInitializer.discoverInputResources, Start,
checkSupportedInputResources, and startAndWaitForInformersFor to handle an empty
map appropriately so the operator can start successfully.

Comment on lines +10 to +42
type inputResourceEventFilter func(obj client.Object) bool

// inputResourceDispatcher is a simple dispatcher that applies GVK scoped filters
// and forwards matching events.
//
// Each GVK has its own set of filters. Today these
// may include name/namespace checks, and in the future label selectors.
//
// Longer term, this dispatcher is expected to track which input resources are
// associated with which operator.
type inputResourceDispatcher struct {
eventsCh chan event.GenericEvent
filters map[schema.GroupVersionKind][]inputResourceEventFilter
}

func newInputResourceDispatcher(filters map[schema.GroupVersionKind][]inputResourceEventFilter) *inputResourceDispatcher {
return &inputResourceDispatcher{
eventsCh: make(chan event.GenericEvent),
filters: filters,
}
}

func (d *inputResourceDispatcher) Handle(gvk schema.GroupVersionKind, cObj client.Object) {
filters := d.filters[gvk]
if len(filters) == 0 {
d.eventsCh <- event.GenericEvent{Object: cObj}
return
}

for _, filter := range filters {
if filter(cObj) {
d.eventsCh <- event.GenericEvent{Object: cObj}
return
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid blocking producers on the dispatcher channel.

eventsCh is unbuffered, so Handle blocks until a receiver reads. If callers emit events while no consumer is ready, this can stall producers. Consider buffering (or other non-blocking dispatch) to prevent deadlocks.

🛠️ Possible fix (buffered channel)
 type inputResourceEventFilter func(obj client.Object) bool
 
+const defaultDispatchBuffer = 100
+
 // inputResourceDispatcher is a simple dispatcher that applies GVK scoped filters
 // and forwards matching events.
 //
@@
 func newInputResourceDispatcher(filters map[schema.GroupVersionKind][]inputResourceEventFilter) *inputResourceDispatcher {
 	return &inputResourceDispatcher{
-		eventsCh: make(chan event.GenericEvent),
+		eventsCh: make(chan event.GenericEvent, defaultDispatchBuffer),
 		filters:  filters,
 	}
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
type inputResourceEventFilter func(obj client.Object) bool
// inputResourceDispatcher is a simple dispatcher that applies GVK scoped filters
// and forwards matching events.
//
// Each GVK has its own set of filters. Today these
// may include name/namespace checks, and in the future label selectors.
//
// Longer term, this dispatcher is expected to track which input resources are
// associated with which operator.
type inputResourceDispatcher struct {
eventsCh chan event.GenericEvent
filters map[schema.GroupVersionKind][]inputResourceEventFilter
}
func newInputResourceDispatcher(filters map[schema.GroupVersionKind][]inputResourceEventFilter) *inputResourceDispatcher {
return &inputResourceDispatcher{
eventsCh: make(chan event.GenericEvent),
filters: filters,
}
}
func (d *inputResourceDispatcher) Handle(gvk schema.GroupVersionKind, cObj client.Object) {
filters := d.filters[gvk]
if len(filters) == 0 {
d.eventsCh <- event.GenericEvent{Object: cObj}
return
}
for _, filter := range filters {
if filter(cObj) {
d.eventsCh <- event.GenericEvent{Object: cObj}
return
type inputResourceEventFilter func(obj client.Object) bool
const defaultDispatchBuffer = 100
// inputResourceDispatcher is a simple dispatcher that applies GVK scoped filters
// and forwards matching events.
//
// Each GVK has its own set of filters. Today these
// may include name/namespace checks, and in the future label selectors.
//
// Longer term, this dispatcher is expected to track which input resources are
// associated with which operator.
type inputResourceDispatcher struct {
eventsCh chan event.GenericEvent
filters map[schema.GroupVersionKind][]inputResourceEventFilter
}
func newInputResourceDispatcher(filters map[schema.GroupVersionKind][]inputResourceEventFilter) *inputResourceDispatcher {
return &inputResourceDispatcher{
eventsCh: make(chan event.GenericEvent, defaultDispatchBuffer),
filters: filters,
}
}
func (d *inputResourceDispatcher) Handle(gvk schema.GroupVersionKind, cObj client.Object) {
filters := d.filters[gvk]
if len(filters) == 0 {
d.eventsCh <- event.GenericEvent{Object: cObj}
return
}
for _, filter := range filters {
if filter(cObj) {
d.eventsCh <- event.GenericEvent{Object: cObj}
return
🤖 Prompt for AI Agents
In
`@control-plane-operator/controllers/openshiftmanager/input_resource_dispatcher.go`
around lines 10 - 42, The dispatcher currently creates an unbuffered eventsCh
which makes inputResourceDispatcher.Handle block if no receiver is ready; update
newInputResourceDispatcher to create a buffered channel (eventsCh := make(chan
event.GenericEvent, <reasonableSize>)) so Handle can send without blocking
briefly (choose a small constant like 16 or make the buffer size configurable),
keep the rest of inputResourceDispatcher, Handle and filters logic unchanged,
and ensure any shutdown/consumer code can drain the channel if needed.

Comment on lines +36 to +50
func (r *inputResourceInitializer) Start(ctx context.Context) error {
inputResources, err := r.discoverInputResources()
if err != nil {
return err
}
if err = r.checkSupportedInputResources(inputResources); err != nil {
return err
}
// TODO: register filters for dispatcher based on inputRes
return r.startAndWaitForInformersFor(ctx, inputResources)
}

func (r *inputResourceInitializer) discoverInputResources() (map[string]*libraryinputresources.InputResources, error) {
return nil, fmt.Errorf("not implemented")
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Start always fails because discovery is stubbed.

discoverInputResources returns a "not implemented" error, so Start will always error and the manager will fail to start when this controller is enabled. Consider gating until discovery exists or making discovery a temporary no-op.

🛠️ Possible no-op stub to avoid startup failure
 func (r *inputResourceInitializer) discoverInputResources() (map[string]*libraryinputresources.InputResources, error) {
-	return nil, fmt.Errorf("not implemented")
+	// TODO: replace with real discovery; empty map keeps initializer a no-op for now.
+	return map[string]*libraryinputresources.InputResources{}, nil
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func (r *inputResourceInitializer) Start(ctx context.Context) error {
inputResources, err := r.discoverInputResources()
if err != nil {
return err
}
if err = r.checkSupportedInputResources(inputResources); err != nil {
return err
}
// TODO: register filters for dispatcher based on inputRes
return r.startAndWaitForInformersFor(ctx, inputResources)
}
func (r *inputResourceInitializer) discoverInputResources() (map[string]*libraryinputresources.InputResources, error) {
return nil, fmt.Errorf("not implemented")
}
func (r *inputResourceInitializer) Start(ctx context.Context) error {
inputResources, err := r.discoverInputResources()
if err != nil {
return err
}
if err = r.checkSupportedInputResources(inputResources); err != nil {
return err
}
// TODO: register filters for dispatcher based on inputRes
return r.startAndWaitForInformersFor(ctx, inputResources)
}
func (r *inputResourceInitializer) discoverInputResources() (map[string]*libraryinputresources.InputResources, error) {
// TODO: replace with real discovery; empty map keeps initializer a no-op for now.
return map[string]*libraryinputresources.InputResources{}, nil
}
🤖 Prompt for AI Agents
In
`@control-plane-operator/controllers/openshiftmanager/input_resource_initializer.go`
around lines 36 - 50, The Start method always fails because
discoverInputResources currently returns a "not implemented" error; replace the
stub so discovery is a safe no-op until real discovery is implemented: change
discoverInputResources to return an empty
map[string]*libraryinputresources.InputResources and nil (so inputResources is
empty) or alternatively early-return from Start when discovery is not ready, but
do not return an error. Update references to
inputResourceInitializer.discoverInputResources, Start,
checkSupportedInputResources, and startAndWaitForInformersFor to handle an empty
map appropriately so the operator can start successfully.

prepares matchers to filter cluster(s) resources based on inputResources
refactors tests so that they use a common function for getting a RESTMapper
@p0lyn0mial p0lyn0mial force-pushed the om-phase-2-in-res-dispatcher-filters branch from c8ccec4 to efc86c9 Compare January 20, 2026 15:13
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Jan 20, 2026

@p0lyn0mial: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-aks-4-21 efc86c9 link true /test e2e-aks-4-21
ci/prow/security efc86c9 link true /test security
ci/prow/e2e-aks efc86c9 link true /test e2e-aks
ci/prow/e2e-aws efc86c9 link true /test e2e-aws
ci/prow/unit efc86c9 link true /test unit
ci/prow/e2e-kubevirt-aws-ovn-reduced efc86c9 link true /test e2e-kubevirt-aws-ovn-reduced
ci/prow/images efc86c9 link true /test images
ci/prow/e2e-aws-upgrade-hypershift-operator efc86c9 link true /test e2e-aws-upgrade-hypershift-operator
ci/prow/verify efc86c9 link true /test verify
ci/prow/okd-scos-images efc86c9 link true /test okd-scos-images

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Jan 20, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: p0lyn0mial
Once this PR has been reviewed and has the lgtm label, please ask for approval from csrwng. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

}
if def.Name != "" && obj.GetName() != def.Name {
return false
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like we can safely drop the checks for empty strings for both Name and Namespace.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/control-plane-operator Indicates the PR includes changes for the control plane operator - in an OCP release jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants