-
Notifications
You must be signed in to change notification settings - Fork 71
🐛 fix: Configuration validation errors now show "Failed" status instead of "Absent" #2465
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
🐛 fix: Configuration validation errors now show "Failed" status instead of "Absent" #2465
Conversation
✅ Deploy Preview for olmv1 ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR refines how the controller reports installation status when configuration validation fails, ensuring Boxcutter behavior matches Helm by using Installed=False with Reason=Failed instead of Absent for config errors. It also adds unit and e2e coverage to lock in the new semantics.
Changes:
- Updated
setInstalledStatusFromRevisionStatesto derive the Installed condition reason via a newdetermineFailureReasonhelper that distinguishes config validation errors from normal rollouts. - Introduced
hasConfigValidationErrorto detect"invalid configuration:"/"invalid ClusterExtension configuration:"messages on rolling revisions and treat them as failures. - Extended unit tests and e2e scenarios to verify that, for config validation errors, the ClusterExtension
Installedcondition isFalsewithReason=Failed.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| test/e2e/features/install.feature | Adds assertions that, during config validation failures in single/own-namespace scenarios, the ClusterExtension Installed condition is False with Reason=Failed. |
| internal/operator-controller/controllers/common_controller.go | Refactors Installed-condition calculation to use determineFailureReason and hasConfigValidationError, mapping specific config error messages to ReasonFailed and otherwise using ReasonAbsent. |
| internal/operator-controller/controllers/common_controller_test.go | Adds table-driven tests for setInstalledStatusFromRevisionStates to cover no revisions, non-config errors (Absent), and both config error message variants (Failed). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
416a487 to
d7a076c
Compare
d7a076c to
0421c38
Compare
There was a problem hiding this comment.
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 3 out of 3 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #2465 +/- ##
==========================================
+ Coverage 69.52% 73.63% +4.10%
==========================================
Files 102 102
Lines 8231 8273 +42
==========================================
+ Hits 5723 6092 +369
+ Misses 2056 1717 -339
- Partials 452 464 +12
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
0421c38 to
d9786e0
Compare
| if len(revisionStates.RollingOut) == 0 { | ||
| setInstalledStatusConditionFalse(ext, ocv1.ReasonFailed, "No bundle installed") | ||
| } else { | ||
| setInstalledStatusConditionFalse(ext, ocv1.ReasonAbsent, "No bundle installed") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would set ReasonAbset always when we should say Failed if we see that we are retrying due to errors
c/c @pedjak @perdasilva ^
d9786e0 to
a5ba252
Compare
a5ba252 to
f059a7b
Compare
| // Retrying indicates an error occurred (config, apply, validation, etc.) | ||
| // Use Failed for semantic correctness: installation failed due to error | ||
| return ocv1.ReasonFailed | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pedjak @perdasilva ^ We check the LATEST only
f059a7b to
0b603c4
Compare
There was a problem hiding this comment.
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 4 out of 4 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
When configuration is invalid, mark it as a permanent error so the system doesn't keep trying to install it over and over. This saves resources and makes it clear the user needs to fix their config. Assisted-by: Claude <noreply@anthropic.com>
2d2cbaf to
7c2fd16
Compare
Before: Invalid config showed status as "Absent" which was confusing After: Shows "Failed" so users know something is wrong Only checks the latest attempt, not old ones that don't matter anymore. Assisted-by: Claude <noreply@anthropic.com>
BOXCUTTER runtime was returning early on config errors without setting the status. Now it updates the status first so users can see what went wrong. Assisted-by: Claude <noreply@anthropic.com>
Tests check: - Config errors are permanent (not retried) - Status shows "Failed" when config is wrong - Namespace names are validated - AllNamespaces operators reject watchNamespace config Includes both unit tests and end-to-end tests. Assisted-by: Claude <noreply@anthropic.com>
When TerminalError is used, unwrap it before showing the error message in status conditions. This prevents the 'terminal error:' prefix from appearing in user-facing messages. Changes: - Add UnwrapTerminal() helper function to cleanly unwrap terminal errors - Use the helper in setStatusProgressing and wrapErrorWithResolutionInfo - Don't set Installed condition when Progressing is Blocked (terminal error) since the Progressing condition already provides all necessary information Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Previously, all terminal errors used the generic "Blocked" reason in the Progressing condition. This wasn't semantically correct - "Blocked" was intended for external blockers like resource collisions, not for user configuration errors. This commit introduces a custom TerminalError type that can carry a specific Reason field, allowing more precise categorization of terminal errors in status conditions. Changes: - Add ReasonInvalidConfiguration constant for configuration errors - Create NewTerminalError(reason, err) to wrap errors with a reason - Add ExtractTerminalReason(err) to retrieve the reason from errors - Update setStatusProgressing to use extracted reason when available - Fall back to ReasonBlocked for backward compatibility with plain reconcile.TerminalError() usage - Update config validation to use ReasonInvalidConfiguration - Update tests and e2e expectations accordingly Result: - Config errors now show: Progressing: False, Reason: InvalidConfiguration - Generic terminal errors show: Progressing: False, Reason: Blocked - More helpful and semantically correct status reporting Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
7c2fd16 to
511c8c1
Compare
There was a problem hiding this comment.
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 10 out of 10 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
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 10 out of 10 changed files in this pull request and generated 1 comment.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
internal/operator-controller/controllers/boxcutter_reconcile_steps.go
Outdated
Show resolved
Hide resolved
…teps.go Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
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 10 out of 10 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
All addressed now. WDYT? |
|
/approve |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: perdasilva The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
|
/lgtm |
ee4bab5
into
operator-framework:main
Problem
When the operator-controller encounters configuration validation errors (like missing required fields or invalid namespace names), it
was showing confusing status messages:
Progressing: True, Reason: Retrying(keeps retrying forever)Installed: False, Reason: Absent(wrong - it's not absent, it failed)Additionally, the generic
Blockedreason was used for all terminal errors, even though it was semantically intended for externalblockers (resource collisions, etc.), not user configuration errors.
Changes Made
1. Config errors are now permanent with specific reason (
provider.go)NewTerminalError(ReasonInvalidConfiguration, err)Progressing: False, Reason: InvalidConfigurationinstead ofRetryingReasonInvalidConfigurationconstant distinguishes config errors from external blockers2. Custom TerminalError with granular Reason support (
terminal.go)NewTerminalError(reason, err)to create terminal errors with specific reasonsExtractTerminalReason(err)to retrieve the reason from errorswrapErrorWithResolutionInfo()ReasonBlockedfor backward compatibility with plainreconcile.TerminalError()Blockednow reserved for its intended purpose (external blockers)3. Status shows "Failed" for config errors (
common_controller.go)determineFailureReason()functionFailedwhen revision hasReason: Retrying(indicates error)Absentwhen revision hasReason: RollingOut(healthy progress)4. BOXCUTTER sets status even on errors (
boxcutter_reconcile_steps.go)5. Clean error messages (
common_controller.go,clusterextension_controller.go)UnwrapTerminal(err)helper to remove "terminal error:" prefixResult
Before:
After:
Testing
InvalidConfigurationAPI Changes
ReasonInvalidConfigurationconstant toapi/v1/common_types.goconditionsets.goConditionReasons list