Skip to content

MCO-1540: Set up events for builds - #6252

Open
eric200428 wants to merge 1 commit into
openshift:mainfrom
eric200428:OCL_Events
Open

MCO-1540: Set up events for builds#6252
eric200428 wants to merge 1 commit into
openshift:mainfrom
eric200428:OCL_Events

Conversation

@eric200428

@eric200428 eric200428 commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

- What I did

  • Added a new OCLEventRecorder wrapper (ocl_events.go) that fire Kubernetes Event object at each OCL build lifecycle transitions
  • Wired recorder into buildReconciler so event attach directly to the relevant resources (MachineOSBuild, MachineOSConfig, or MachineConfigPool), giving a readable timeline by using the oc describe command
  • Used EventTypeWarning for failures and degradation transition and EventTypeNormal for everything else

- How to verify it
Run the command below for the unit test

go test ./pkg/controller/build/

or

  • Trigger a build by creating or updating a MachineOSConfig, then get the build name with oc get machineosbuild -n openshift-machine-config-operator
  • Run oc describe machineosbuild <name> -n openshift-machine-config-operator and scroll to the Events: section at the bottom
  • You should see a timeline of Normal/Warning events like BuildStarted, BuildBuilding, BuildCompleted (or BuildFailed/BuildDegraded on failure) with timestamps and messages

- Description for the changelog

Add Kubernetes event recording for OCL build lifecycle transitions

Summary by CodeRabbit

  • New Features
    • Added Kubernetes event recording for build, job, machine OS config (reconcile/rebuild/delete), degradation/recovery, and machine pool config changes.
    • Build reconciliation now emits detailed lifecycle events (started/preparing/building/completed/failed/interrupted/deleted), including “build degraded” and “build recovered”, plus “pool config changed” when rendered config changes.
  • Bug Fixes
    • Improved event accuracy by deriving job/build events from the referenced build state, including correct “job started/completed/failed” and “build interrupted” when the build reference is missing.
    • Ensures “build deleted” is emitted when deletions succeed or when the build was already absent.
  • Tests
    • Added unit tests covering event types/reasons and key message content.

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Pipeline controller notification
This repo is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. To trigger manually all jobs from second stage use /pipeline required command.

This repository is configured in: LGTM mode

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jun 30, 2026
@openshift-ci-robot

openshift-ci-robot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

@eric200428: This pull request references MCO-1540 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 story to target the "5.0.0" version, but no target version was set.

Details

In response to this:

- What I did

  • Added a new OCLEventRecorder wrapper (ocl_events.go) that fire Kubernetes Event object at each OCL build lifecycle transitions
  • Wired recorder into buildReconciler so event attach directly to the relevant resources (MachineOSBuild, MachineOSConfig, or MachineConfigPool), giving a readable timeline by using the oc describe command
  • Used EventTypeWarning for failures and degradation transition and EventTypeNormal for everything else

- How to verify it
Run the command below for the unit test

go test ./pkg/controller/build/

or

  • Trigger a build by creating or updating a MachineOSConfig, then get the build name with oc get machineosbuild -n openshift-machine-config-operator
  • Run oc describe machineosbuild <name> -n openshift-machine-config-operator and scroll to the Events: section at the bottom
  • You should see a timeline of Normal/Warning events like BuildStarted, BuildBuilding, BuildCompleted (or BuildFailed/BuildDegraded on failure) with timestamps and messages

- Description for the changelog

Add Kubernetes event recording for OCL build lifecycle transitions

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.

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 20c4d25d-3e6a-4e9a-8cff-981b5803b828

📥 Commits

Reviewing files that changed from the base of the PR and between 9f879a6 and 25c8da3.

📒 Files selected for processing (4)
  • pkg/controller/build/ocl_events.go
  • pkg/controller/build/ocl_events_test.go
  • pkg/controller/build/osbuildcontroller.go
  • pkg/controller/build/reconciler.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • pkg/controller/build/osbuildcontroller.go
  • pkg/controller/build/ocl_events_test.go
  • pkg/controller/build/ocl_events.go
  • pkg/controller/build/reconciler.go

Walkthrough

Adds an OCLEventRecorder with Kubernetes event reasons and emits build, job, config, degradation, deletion, and pool-configuration events through the build reconciler. The controller passes its recorder into the reconciler, with tests covering event types, reasons, and message content.

Changes

Build lifecycle events

Layer / File(s) Summary
Event recorder contracts and methods
pkg/controller/build/ocl_events.go
Defines event reasons and recording methods for build, job, config, degradation, and pool configuration states.
Reconciler event integration
pkg/controller/build/osbuildcontroller.go, pkg/controller/build/reconciler.go
Wires the Kubernetes recorder into the reconciler and emits events during config, job, build, pool, and deletion transitions.
Recorder behavior validation
pkg/controller/build/ocl_events_test.go
Uses fake recorders and table-driven tests to verify event types, reasons, message content, and single-event emission.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant osbuildcontroller
  participant buildReconciler
  participant OCLEventRecorder
  participant KubernetesEventRecorder
  osbuildcontroller->>buildReconciler: Construct with eventRecorder
  buildReconciler->>OCLEventRecorder: Record lifecycle event
  OCLEventRecorder->>KubernetesEventRecorder: Emit typed event with reason and message
Loading

Possibly related PRs

Suggested reviewers: harshwardhanpatil07


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 1 warning)

Check name Status Explanation Resolution
No-Sensitive-Data-In-Logs ❌ Error FAIL: event logging writes full image pullspecs and raw errors to klog via StartLogging(klog.Infof); pullspecs can include internal hostnames. Redact or truncate pullspecs and error text in event messages, or avoid StartLogging for these events; keep only generic reasons.
Docstring Coverage ⚠️ Warning Docstring coverage is 23.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (13 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding build event recording support.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed The new tests use static t.Run names only; no Describe/It/Context titles or dynamic identifiers appear in the changed file.
Test Structure And Quality ✅ Passed Not applicable: the new tests are plain Go unit tests, not Ginkgo, and they use isolated fake recorders with no cluster resources, waits, or cleanup concerns.
Microshift Test Compatibility ✅ Passed No Ginkgo e2e tests were added; the new test file uses Go's testing package, so MicroShift-specific API compatibility isn’t implicated.
Single Node Openshift (Sno) Test Compatibility ✅ Passed No new Ginkgo e2e tests were added; the new tests are plain Go unit tests using testing/FakeRecorder with no SNO/HA assumptions.
Topology-Aware Scheduling Compatibility ✅ Passed The PR only adds Kubernetes event recording and wiring; no node selectors, affinity/spread, replica, or PDB scheduling constraints were introduced.
Ote Binary Stdout Contract ✅ Passed No main/init/TestMain/suite hooks or stdout prints were added; the touched files only add event recording and unit tests.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed No new Ginkgo/e2e tests were added; the changed tests are plain testing unit tests with no IPv4 or external connectivity assumptions.
No-Weak-Crypto ✅ Passed Diff-only scan found no MD5/SHA1/DES/RC4/3DES/Blowfish/ECB or secret/token comparisons; changes are event-recording plumbing only.
Container-Privileges ✅ Passed Only Go controller/test files were touched; no manifests or privilege-related fields (privileged, hostPID/network/IPC, SYS_ADMIN, allowPrivilegeEscalation) were found.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
pkg/controller/build/reconciler.go (2)

122-134: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Early return nil now skips syncMachineOSConfigs(ctx) on the spec-changed path.

Previously this branch fell through to return b.syncMachineOSConfigs(ctx) at line 133 after creating/reusing the build. The new code adds return nil right after RecordConfigReconciled, so syncMachineOSConfigs(ctx) is now unconditionally skipped whenever the MachineOSConfig spec changed. If syncMachineOSConfigs performs reconciliation work beyond what createNewMachineOSBuildOrReuseExisting does (e.g. syncing other configs, updating aggregate status), this is an unrelated functional regression introduced alongside the event-recording change.

🐛 Proposed fix to preserve prior sync behavior
 	if !equality.Semantic.DeepEqual(old.Spec, cur.Spec) {
 		klog.Infof("Detected MachineOSConfig change for %s", cur.Name)
 		b.eventRecorder.RecordConfigReconciling(cur)
 		if err := b.createNewMachineOSBuildOrReuseExisting(ctx, cur, false); err != nil {
 			return err
 		}
 		b.eventRecorder.RecordConfigReconciled(cur)
-		return nil
+		return b.syncMachineOSConfigs(ctx)
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controller/build/reconciler.go` around lines 122 - 134, The spec-changed
branch in reconciler.go is returning too early and bypassing the existing sync
path. In the reconcile flow around createNewMachineOSBuildOrReuseExisting,
RecordConfigReconciled should not end the method; preserve the prior behavior by
letting the code continue to the shared syncMachineOSConfigs(ctx) reconciliation
work instead of unconditionally returning nil after the event recording.

520-526: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

RecordBuildStarted fires before the build job is actually created.

RecordBuildStarted is emitted at line 520, but the actual job creation (imagebuilder...Start(ctx)) happens afterward and can fail and return an error at line 525-526. If Start(ctx) fails, the Events list on the MachineOSBuild will already show "Started build for pool ..." even though no build job was ever created — misleading for the exact oc describe workflow this PR is meant to support. Consider emitting RecordBuildStarted only after Start(ctx) succeeds.

🐛 Proposed fix to emit after success
-	b.eventRecorder.RecordBuildStarted(mosb, mosc)
 	b.eventRecorder.RecordBuildPreparing(mosb, fmt.Sprintf("creating build job for pool %q", mosc.Spec.MachineConfigPool.Name))
 
 	// Next, create our new MachineOSBuild.
 	if err := imagebuilder.NewJobImageBuilder(b.kubeclient, b.mcfgclient, mosb, mosc).Start(ctx); err != nil {
 		return fmt.Errorf("imagebuilder could not start build for MachineOSBuild %q: %w", mosb.Name, err)
 	}
+
+	b.eventRecorder.RecordBuildStarted(mosb, mosc)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controller/build/reconciler.go` around lines 520 - 526,
`RecordBuildStarted` is emitted too early in `reconciler.go`, before
`imagebuilder.NewJobImageBuilder(...).Start(ctx)` succeeds, which can leave a
misleading “started” event when job creation fails. Move the
`RecordBuildStarted(mosb, mosc)` call to after the `Start(ctx)` call in the
build flow, so it only fires once the build job is actually created; keep
`RecordBuildPreparing` before the start attempt and preserve the existing error
handling in the reconciler path.
🧹 Nitpick comments (3)
pkg/controller/build/ocl_events_test.go (1)

78-103: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consolidate duplicated test-runner loop.

The for _, tt := range tests { t.Run(...) {...} } body is identical across all four test functions. Extracting a shared helper would remove ~40 lines of duplication and make adding new cases less error-prone.

♻️ Suggested helper extraction
type eventCase struct {
	name       string
	record     func(*OCLEventRecorder)
	wantType   string
	wantReason string
}

func runEventCases(t *testing.T, tests []eventCase) {
	t.Helper()
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			t.Parallel()
			recorder, fake := newTestOCLRecorder(1)
			tt.record(recorder)
			assertEvent(t, fake.Events, tt.wantType, tt.wantReason)
			assertNoEvent(t, fake.Events)
		})
	}
}

Then each test becomes:

-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			t.Parallel()
-			recorder, fake := newTestOCLRecorder(1)
-			tt.record(recorder)
-			assertEvent(t, fake.Events, tt.wantType, tt.wantReason)
-			assertNoEvent(t, fake.Events)
-		})
-	}
+	runEventCases(t, tests)

Also applies to: 111-133, 140-162, 171-194

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controller/build/ocl_events_test.go` around lines 78 - 103, The test
functions in OCLEventRecorder all repeat the same t.Run loop over event cases,
so extract that shared runner into a helper and reuse it across the tests.
Define a common case type and a helper like runEventCases that owns the
t.Run/t.Parallel/newTestOCLRecorder/assertEvent/assertNoEvent flow, then replace
each duplicated loop in the OCLEventRecorder test cases with a call to that
helper while keeping the per-test case lists intact.
pkg/controller/build/ocl_events.go (1)

199-209: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Redundant mcp parameter alongside mosc.

RecordBuildDegraded/RecordBuildRecovered both take mosc and mcp, but only use mcp.Name for the message while mosc.Spec.MachineConfigPool.Name already provides the pool name. Could drop the mcp parameter for a smaller, more consistent API surface (other methods only take the object types they actually need fields from).

Also note RecordBuildDegraded quotes the pool name with %q (line 202) while RecordBuildRecovered uses %s (line 208) — purely cosmetic but worth aligning.

♻️ Possible simplification
-func (r *OCLEventRecorder) RecordBuildDegraded(mosc *mcfgv1.MachineOSConfig, mcp *mcfgv1.MachineConfigPool) {
+func (r *OCLEventRecorder) RecordBuildDegraded(mosc *mcfgv1.MachineOSConfig) {
 	r.recorder.Event(mosc, corev1.EventTypeWarning, EventBuildDegraded,
-		fmt.Sprintf("Build for pool %q degraded; see MachineOSBuild status conditions for details", mcp.Name))
+		fmt.Sprintf("Build for pool %q degraded; see MachineOSBuild status conditions for details", mosc.Spec.MachineConfigPool.Name))
 }
 
-func (r *OCLEventRecorder) RecordBuildRecovered(mosc *mcfgv1.MachineOSConfig, mcp *mcfgv1.MachineConfigPool) {
+func (r *OCLEventRecorder) RecordBuildRecovered(mosc *mcfgv1.MachineOSConfig) {
 	r.recorder.Event(mosc, corev1.EventTypeNormal, EventBuildRecovered,
-		fmt.Sprintf("Build for pool %s recovered from degraded state", mcp.Name))
+		fmt.Sprintf("Build for pool %q recovered from degraded state", mosc.Spec.MachineConfigPool.Name))
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controller/build/ocl_events.go` around lines 199 - 209,
RecordBuildDegraded and RecordBuildRecovered in OCLEventRecorder take mosc and
mcp, but only need the pool name already available from
mosc.Spec.MachineConfigPool.Name, so remove the redundant mcp parameter and
update the callers accordingly. While touching these methods, make the pool-name
formatting consistent between RecordBuildDegraded and RecordBuildRecovered by
using the same verb style in both event messages.
pkg/controller/build/reconciler.go (1)

352-368: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Extra live API GET on every successful build transition.

liveMCP is fetched via a direct API call (bypassing the lister cache) on every build success transition specifically to detect recovery for the event. This adds an uncached API round-trip to a path that already does several lister/API calls; for clusters with frequent build churn this adds incremental API server load. Consider verifying this is acceptable, or scoping the live fetch to only fire when the lister-cached mcp indicates a possible stale degraded condition.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controller/build/reconciler.go` around lines 352 - 368, The
successful-build path in reconciler.go always performs a live MachineConfigPool
GET in the build completion flow, which adds an uncached API call on every
transition. Update the logic around the current build-recovery check in the
Build reconciler (using mcp, liveMCP, and RecordBuildRecovered) to avoid the
unconditional live fetch, either by gating it behind a cached indication that
recovery is possible or otherwise narrowing when the direct API call is needed.
Keep the recovery event behavior intact while reducing API-server load on
frequent build completions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/controller/build/reconciler.go`:
- Line 981: Move the RecordBuildDeleted event in deleteMachineOSBuild so it is
emitted only after deleteMOSBImage, the digest ConfigMap cleanup, and the
MachineOSBuild delete call have all succeeded; right now
b.eventRecorder.RecordBuildDeleted(mosb, "build resources removed") is called
too early and can report success before deletion completes. Keep the existing
deleteMachineOSBuild flow, but place the event at the end of the successful path
so the emitted “build resources removed” message reflects an actually completed
deletion.

---

Outside diff comments:
In `@pkg/controller/build/reconciler.go`:
- Around line 122-134: The spec-changed branch in reconciler.go is returning too
early and bypassing the existing sync path. In the reconcile flow around
createNewMachineOSBuildOrReuseExisting, RecordConfigReconciled should not end
the method; preserve the prior behavior by letting the code continue to the
shared syncMachineOSConfigs(ctx) reconciliation work instead of unconditionally
returning nil after the event recording.
- Around line 520-526: `RecordBuildStarted` is emitted too early in
`reconciler.go`, before `imagebuilder.NewJobImageBuilder(...).Start(ctx)`
succeeds, which can leave a misleading “started” event when job creation fails.
Move the `RecordBuildStarted(mosb, mosc)` call to after the `Start(ctx)` call in
the build flow, so it only fires once the build job is actually created; keep
`RecordBuildPreparing` before the start attempt and preserve the existing error
handling in the reconciler path.

---

Nitpick comments:
In `@pkg/controller/build/ocl_events_test.go`:
- Around line 78-103: The test functions in OCLEventRecorder all repeat the same
t.Run loop over event cases, so extract that shared runner into a helper and
reuse it across the tests. Define a common case type and a helper like
runEventCases that owns the
t.Run/t.Parallel/newTestOCLRecorder/assertEvent/assertNoEvent flow, then replace
each duplicated loop in the OCLEventRecorder test cases with a call to that
helper while keeping the per-test case lists intact.

In `@pkg/controller/build/ocl_events.go`:
- Around line 199-209: RecordBuildDegraded and RecordBuildRecovered in
OCLEventRecorder take mosc and mcp, but only need the pool name already
available from mosc.Spec.MachineConfigPool.Name, so remove the redundant mcp
parameter and update the callers accordingly. While touching these methods, make
the pool-name formatting consistent between RecordBuildDegraded and
RecordBuildRecovered by using the same verb style in both event messages.

In `@pkg/controller/build/reconciler.go`:
- Around line 352-368: The successful-build path in reconciler.go always
performs a live MachineConfigPool GET in the build completion flow, which adds
an uncached API call on every transition. Update the logic around the current
build-recovery check in the Build reconciler (using mcp, liveMCP, and
RecordBuildRecovered) to avoid the unconditional live fetch, either by gating it
behind a cached indication that recovery is possible or otherwise narrowing when
the direct API call is needed. Keep the recovery event behavior intact while
reducing API-server load on frequent build completions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: f4854e10-9eea-4ba2-aa36-a5da140be606

📥 Commits

Reviewing files that changed from the base of the PR and between f05e487 and e310387.

📒 Files selected for processing (4)
  • pkg/controller/build/ocl_events.go
  • pkg/controller/build/ocl_events_test.go
  • pkg/controller/build/osbuildcontroller.go
  • pkg/controller/build/reconciler.go

Comment thread pkg/controller/build/reconciler.go Outdated
@umohnani8

Copy link
Copy Markdown
Contributor

/approve
/lgtm (to trigger tests)

@openshift-ci

openshift-ci Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: eric200428, umohnani8

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

The pull request process is described 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

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 14, 2026

@dkhater-redhat dkhater-redhat 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.

nice work! leaving some comments for you to review. LMK when you're ready for a second round :)

Comment thread pkg/controller/build/ocl_events.go Outdated
EventBuildCompleted = "BuildCompleted"
EventBuildFailed = "BuildFailed"
EventBuildInterrupted = "BuildInterrupted"
EventBuildRetrying = "BuildRetrying"

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.

nit: I may be incorrect but I dont believe we have a retrying condition in the MOSB API. we do have a controller-level concept of deleting an old build and recreating a new one though. AFAIK the MOSB state machine only knows: Prepared → Building → (Succeeded | Failed | Interrupted). I would remove this event entirely.

Comment thread pkg/controller/build/ocl_events.go Outdated
// RecordBuildRetrying records when an existing build is replaced due to a config change
func (r *OCLEventRecorder) RecordBuildRetrying(mosb *mcfgv1.MachineOSBuild) {
r.recorder.Event(mosb, corev1.EventTypeNormal, EventBuildRetrying,
"Existing build replaced due to config change")

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.

technically when we are doing a "retry", the config doesn't change, the MOSB actually stays the same. Imo it would make sense to remove this event because we dont have this notion of retrying. we have more of a notion that a rebuild is a new build lifecycle.

Comment thread pkg/controller/build/ocl_events.go Outdated
Comment on lines +41 to +43
EventCleanupStarted = "CleanupStarted"
EventCleanupCompleted = "CleanupCompleted"
EventCleanupFailed = "CleanupFailed"

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.

nit: I dont know if these are useful to the user. I think this may be noisy and its just for our internal bookkeeping

Comment thread pkg/controller/build/ocl_events.go Outdated
Comment on lines +147 to +151
// RecordConfigChanged records when a config changes triggering a new build
func (r *OCLEventRecorder) RecordConfigChanged(mosc *mcfgv1.MachineOSConfig, oldConfig, newConfig string) {
r.recorder.Event(mosc, corev1.EventTypeNormal, EventConfigChanged,
fmt.Sprintf("Configuration changed from %s to %s, triggering new build", oldConfig, newConfig))
}

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.

nit: I think this function was only called in tests? Also, the event signature assumes there's a simple "old config" and "new config" string, but the MOSC spec is a complex object. The existing events you have (RecordConfigReconciling and RecordConfigReconciled) should already be sufficient. I would consider removing.

Comment thread pkg/controller/build/reconciler.go Outdated
Comment on lines +125 to +129
b.eventRecorder.RecordConfigReconciling(cur)
if err := b.createNewMachineOSBuildOrReuseExisting(ctx, cur, false); err != nil {
return err
}
b.eventRecorder.RecordConfigReconciled(cur)

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.

nit: This leaves dangling "ConfigReconciling" events when reconciliation fails. Every reconcile loop emits "reconciling" but only successful ones emit "reconciled", creating noise.

Comment thread pkg/controller/build/reconciler.go Outdated
if !oldState.IsBuildFailure() && curState.IsBuildFailure() {
klog.Infof("MachineOSBuild %s failed, leaving ephemeral objects in place for inspection", current.Name)

b.eventRecorder.RecordBuildFailed(current)

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.

nit: the event fires before the MCP fetch that could fail. Event says "build failed" but degradation state might not get set if the MCP fetch errors. so consider recording the event after successfully updating the degraded condition

Comment thread pkg/controller/build/reconciler.go Outdated

// If we need to rebuild, then we need to create a new MachineOSBuild
if imageNeedsRebuild {
b.eventRecorder.RecordBuildRetrying(existingMosb)

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.

nit: the event is recorded on the old MOSB right before deletion, so the event disappears with the object. we should record on MOSC or new MOSB instead.

Comment thread pkg/controller/build/ocl_events.go Outdated
Comment on lines +177 to +195
// Cleanup event recording

// RecordCleanupStarted records when cleanup of build artifacts starts
func (r *OCLEventRecorder) RecordCleanupStarted(mosb *mcfgv1.MachineOSBuild) {
r.recorder.Event(mosb, corev1.EventTypeNormal, EventCleanupStarted,
"Started cleanup of build artifacts")
}

// RecordCleanupCompleted records when cleanup completes
func (r *OCLEventRecorder) RecordCleanupCompleted(mosb *mcfgv1.MachineOSBuild) {
r.recorder.Event(mosb, corev1.EventTypeNormal, EventCleanupCompleted,
"Cleanup of build artifacts completed")
}

// RecordCleanupFailed records when cleanup fails
func (r *OCLEventRecorder) RecordCleanupFailed(mosb *mcfgv1.MachineOSBuild) {
r.recorder.Event(mosb, corev1.EventTypeWarning, EventCleanupFailed,
fmt.Sprintf("Cleanup of build artifacts failed; see MachineOSBuild %q status conditions for details", mosb.Name))
}

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.

see my comment above

@umohnani8

Copy link
Copy Markdown
Contributor

/pipeline required

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-aws-ovn
/test e2e-aws-ovn-upgrade
/test e2e-gcp-op-ocl-part1
/test e2e-gcp-op-ocl-part2
/test e2e-gcp-op-part1
/test e2e-gcp-op-part2
/test e2e-gcp-op-single-node
/test e2e-hypershift

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/controller/build/reconciler.go`:
- Around line 280-283: Update the deleteJob flow to deep-copy the
informer-provided Job before calling SetDeletionTimestamp, mutate the copied
Job, and pass that copy to updateMachineOSBuildWithStatus. Keep DeleteJob
operating on the original Job as currently intended.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: c4ad3be6-7fad-4775-b973-87fcadc2878d

📥 Commits

Reviewing files that changed from the base of the PR and between 6c156fd and 3ab1d57.

📒 Files selected for processing (4)
  • pkg/controller/build/ocl_events.go
  • pkg/controller/build/ocl_events_test.go
  • pkg/controller/build/osbuildcontroller.go
  • pkg/controller/build/reconciler.go

Comment thread pkg/controller/build/reconciler.go Outdated
@umohnani8

Copy link
Copy Markdown
Contributor

/pipeline required

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-aws-ovn
/test e2e-aws-ovn-upgrade
/test e2e-gcp-op-ocl-part1
/test e2e-gcp-op-ocl-part2
/test e2e-gcp-op-part1
/test e2e-gcp-op-part2
/test e2e-gcp-op-single-node
/test e2e-hypershift

@eric200428

Copy link
Copy Markdown
Contributor Author

/retest

Comment thread pkg/controller/build/reconciler.go Outdated

// Performs the deletion reconciliation of the MachineOSConfig.
func (b *buildReconciler) deleteMachineOSConfig(ctx context.Context, mosc *mcfgv1.MachineOSConfig) error {
b.eventRecorder.RecordConfigDeleted(mosc)

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.

looks like this is recording a deleted event before the deletion s successful. There is a chance it might fail, I would suggest moving this towards the end of the function once the deletion is actually successful.

@openshift-ci

openshift-ci Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

@eric200428: all tests passed!

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.

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

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants