Skip to content

refactor: configure the event recorder on the operator instead of the controller - #3581

Open
csviri wants to merge 2 commits into
operator-framework:nextfrom
csviri:mark-er-experimental
Open

refactor: configure the event recorder on the operator instead of the controller#3581
csviri wants to merge 2 commits into
operator-framework:nextfrom
csviri:mark-er-experimental

Conversation

@csviri

@csviri csviri commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Removes EventRecorder from RegisteredController and makes the instance the
controllers record their Kubernetes events through configurable for the whole
operator, via ConfigurationService.eventRecorder() /
ConfigurationServiceOverrider.withEventRecorder(). When none is configured, each
controller keeps recording through a DefaultEventRecorder of its own, which
attributes the events to that controller, as before. Recording events outside of
a reconciliation is now done through the configured instance, which the caller
owns, rather than through one handed out by the registered controller.

… controller

Removes EventRecorder from RegisteredController and makes the instance the
controllers record their Kubernetes events through configurable for the whole
operator, via ConfigurationService.eventRecorder() /
ConfigurationServiceOverrider.withEventRecorder(). When none is configured, each
controller keeps recording through a DefaultEventRecorder of its own, which
attributes the events to that controller, as before. Recording events outside of
a reconciliation is now done through the configured instance, which the caller
owns, rather than through one handed out by the registered controller.
@openshift-ci openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Aug 31, 2026
@coderabbitai

coderabbitai Bot commented Aug 31, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a7bfdd4d-3933-4d84-8e01-141437e562b1

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@csviri
csviri marked this pull request as ready for review August 31, 2026 10:41
Copilot AI lite review requested due to automatic review settings August 31, 2026 10:41
@openshift-ci openshift-ci Bot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Aug 31, 2026
@openshift-ci
openshift-ci Bot requested review from metacosm and xstefank August 31, 2026 10:41
@csviri

csviri commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator Author

FYI @TQJADE added this adjustment. Pls let me know if it makes sense for you.

cc @gaborgsomogyi

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Refactors Kubernetes event recording so controllers use an EventRecorder configured at the operator level via ConfigurationService.eventRecorder() (and ConfigurationServiceOverrider.withEventRecorder()), while preserving per-controller default behavior when none is configured.

Changes:

  • Add operator-level EventRecorder configuration hook (ConfigurationService#eventRecorder) and an overrider (withEventRecorder).
  • Update Controller to use the configured recorder when present, otherwise instantiate a per-controller DefaultEventRecorder.
  • Remove EventRecorder access from RegisteredController and update Javadocs/tests to reflect the new access pattern.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
operator-framework-core/src/test/java/io/javaoperatorsdk/operator/processing/ControllerTest.java Adds coverage for controller using configured vs default event recorder.
operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverriderTest.java Adds coverage for default-empty and overridden operator-level event recorder.
operator-framework-core/src/main/java/io/javaoperatorsdk/operator/RegisteredController.java Removes EventRecorder accessor from the registered controller API.
operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/Controller.java Selects operator-configured EventRecorder or falls back to per-controller DefaultEventRecorder.
operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/Context.java Updates Javadoc to point to operator-configured EventRecorder rather than RegisteredController.
operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/event/EventRecorder.java Updates Javadoc to describe the new configuration/access approach and marks API experimental.
operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverrider.java Adds withEventRecorder support and forwards it via overridden ConfigurationService.
operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java Introduces eventRecorder() as an (experimental) operator-level optional configuration point.
Suppressed comments (1)

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/processing/Controller.java:370

  • The Javadoc link uses ConfigurationService which currently requires an import; switching to a fully-qualified link keeps the Javadoc valid while allowing the unused import to be removed.
  /**
   * The {@link EventRecorder} this controller records its Kubernetes events through, either the one
   * configured for the operator, see {@link ConfigurationService#eventRecorder()}, or a {@link
   * DefaultEventRecorder} of its own.
   */

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 26 to +30
* <p>This is the unbound form of the API: it is scoped to a controller, not to a reconciliation,
* and can therefore be used outside of the reconciliation loop, for example from a status listener
* or a background task. Obtain it from {@link
* io.javaoperatorsdk.operator.RegisteredController#eventRecorder()}. Within a reconciliation,
* prefer {@link io.javaoperatorsdk.operator.api.reconciler.Context#eventRecorder()}, which is
* already bound to the primary resource.
* or a background task. To use it that way, configure the instance the operator records its events
* through, see {@link io.javaoperatorsdk.operator.api.config.ConfigurationService#eventRecorder()},
* and keep a reference to it. Within a reconciliation, prefer {@link
Comment on lines +119 to +123
@Override
public ResourceEventRecorder forResource(HasMetadata regarding) {
return null;
}
};
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (3)

Previously missed (2) — in code that hasn't changed since the last review.

operator-framework-core/src/test/java/io/javaoperatorsdk/operator/api/config/ConfigurationServiceOverriderTest.java:122

  • This test EventRecorder stub returns null from forResource(), which violates EventRecorder's contract and can mask/null-pointer failures if the test (or reused helper) ever exercises Context#eventRecorder(). Return a no-op ResourceEventRecorder instead.
          @Override
          public ResourceEventRecorder forResource(HasMetadata regarding) {
            return null;
          }

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/config/ConfigurationService.java:308

  • ConfigurationService#eventRecorder() documents that the configured recorder is shared across all controllers, but it doesn't mention the implied concurrency requirements. Since multiple reconciliations can run in parallel (and across controllers), a shared EventRecorder must be thread-safe; calling that out here would prevent subtle runtime issues in custom implementations.
   * <p>When empty, which is the default, every controller gets a {@link DefaultEventRecorder} of
   * its own, which attributes the events it records to that controller. A recorder configured here
   * is shared by all controllers of the operator, so it decides on its own what the events it
   * records are attributed to, and it is up to the caller to hold on to the instance if it also
   * records events outside of a reconciliation.

operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/event/EventRecorder.java:27

  • EventRecorder Javadoc still states the API is "scoped to a controller". With the new operator-level configuration (ConfigurationService#eventRecorder()), the same EventRecorder instance can be shared across controllers and attribution becomes implementation-defined, so this wording is misleading.
 * Records Kubernetes events on behalf of a controller.
 *
 * <p>This is the unbound form of the API: it is scoped to a controller, not to a reconciliation,
 * and can therefore be used outside of the reconciliation loop, for example from a status listener

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants