CNTRLPLANE-3553: Wire osImageStream into NodePool controller (hash, token, status, validation)#8730
Conversation
|
Pipeline controller notification For optional jobs, comment This repository is configured in: LGTM mode |
|
@sdminonne: This pull request references CNTRLPLANE-3553 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. DetailsIn response to this:
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. |
|
Skipping CI for Draft Pull Request. |
📝 WalkthroughWalkthroughThis PR wires RHEL OS image stream support through the NodePool controller. It adds Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 11✅ Passed checks (11 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: sdminonne The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #8730 +/- ##
==========================================
+ Coverage 41.79% 41.81% +0.01%
==========================================
Files 759 760 +1
Lines 94037 94099 +62
==========================================
+ Hits 39304 39344 +40
- Misses 51983 52004 +21
- Partials 2750 2751 +1
Flags with carried forward coverage won't be shown. Click here to find out more. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
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 (1)
hypershift-operator/controllers/nodepool/config.go (1)
88-94:⚠️ Potential issue | 🟠 Major | ⚡ Quick winThread the resolved OS stream, not the raw spec field.
getRHELStream()is the contract for this feature: whenspec.osImageStreamis unset, the controller derivesrhel-9/rhel-10from the release. These sites currently cache/forwardnodePool.Spec.OSImageStream.Namedirectly, so the value collapses to""for defaulted NodePools. That leaves the hash path out of sync withstatus.osImageStreamtoday, and it will feed the wrong stream into AWS/GCP image selection as soon as the dependent multi-stream metadata work starts usingrhelStreamafter rebase.Compute the effective stream once from
getRHELStream(nodePool, releaseImage)and thread that value throughrolloutConfig,CAPI, and the platform validation helpers.🤖 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 `@hypershift-operator/controllers/nodepool/config.go` around lines 88 - 94, Compute the effective RHEL stream once by calling getRHELStream(nodePool, releaseImage) and pass that computed value into rolloutConfig.rhelStream instead of using nodePool.Spec.OSImageStream.Name; also propagate the same computed value into any CAPI-related code paths and platform validation helper calls that previously read spec.osImageStream so all consumers use the resolved stream (e.g., update usages in rolloutConfig initialization, CAPI helpers, and platform validation functions to accept/consume the new resolved rhelStream variable).
🧹 Nitpick comments (2)
hypershift-operator/controllers/nodepool/osstream_test.go (1)
17-80: ⚡ Quick winAdd test coverage for getRHELStream error path.
TestGetRHELStreamonly covers success cases. Add a test case for whenreleaseImage.Version()returns an invalid semver string, to verify thatgetRHELStreamreturns an error as expected (Line 26-29 in osstream.go handles this, but it's untested).📋 Proposed test case for invalid semver
expectedStream: "rhel-10", }, + { + name: "When spec.osImageStream.Name is empty and version is invalid, it should return error", + nodePool: &hyperv1.NodePool{ + Spec: hyperv1.NodePoolSpec{}, + }, + releaseImage: &releaseinfo.ReleaseImage{ + ImageStream: &imageapi.ImageStream{ObjectMeta: metav1.ObjectMeta{Name: "invalid-version"}}, + }, + expectErr: true, + }, }🤖 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 `@hypershift-operator/controllers/nodepool/osstream_test.go` around lines 17 - 80, TestGetRHELStream lacks coverage for the error path in getRHELStream when releaseImage.Version() yields an invalid semver; add a new test case in TestGetRHELStream that supplies a releaseinfo.ReleaseImage whose ImageStream.ObjectMeta.Name is an invalid version string (e.g., "not-a-semver"), call getRHELStream(nodePool, releaseImage) and assert that an error is returned (Expect(err).To(HaveOccurred())); reference the existing test harness and types (TestGetRHELStream, getRHELStream, releaseinfo.ReleaseImage, imageapi.ImageStream/ObjectMeta.Name) so the new case is consistent with the other table-driven cases.hypershift-operator/controllers/nodepool/nodepool_controller.go (1)
407-409: ⚡ Quick winLog or surface
getRHELStreamerrors in all three status-update paths.In
nodepool_controller.go(Line 407-409),capi.goreconcileMachineDeploymentStatus (Line 617-619), andcapi.goreconcileMachineSet (Line 1018-1020), errors fromgetRHELStreamare silently ignored withif err == nilguards. The shared root cause is missing error visibility: when OS stream resolution fails (e.g., invalid semver in release version),Status.OSImageStreamremains unset or stale and no log or condition surfaces the issue to the user. As per coding guidelines, "Always check errors in Go — don't ignore them." Add logging or set a condition in each path to surface failures.🤖 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 `@hypershift-operator/controllers/nodepool/nodepool_controller.go` around lines 407 - 409, getRHELStream errors are being ignored in three places (nodepool_controller.go when setting nodePool.Status.OSImageStream, capi.go reconcileMachineDeploymentStatus, and capi.go reconcileMachineSet); update each location to handle the error path: when getRHELStream returns an error, log the error with the controller logger (including err.Error()) and set a clear status condition (e.g., "OSImageStreamResolutionFailed") on the owning object with the error message so users see the failure, and when getRHELStream succeeds clear that condition and set Status.OSImageStream as before; reference the getRHELStream call sites and the Status.OSImageStream update points and ensure status updates are persisted.Source: Coding guidelines
🤖 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 `@hypershift-operator/controllers/nodepool/osstream.go`:
- Around line 21-35: The getRHELStream function dereferences nodePool
(nodePool.Spec.OSImageStream.Name) and releaseImage (releaseImage.Version())
without nil checks; add defensive nil guards at the top of getRHELStream to
return a clear error if nodePool or releaseImage is nil, and also guard
nodePool.Spec or nodePool.Spec.OSImageStream as needed before accessing Name to
avoid panics, then proceed with semver.Parse on releaseImage.Version() only when
releaseImage is non-nil.
---
Outside diff comments:
In `@hypershift-operator/controllers/nodepool/config.go`:
- Around line 88-94: Compute the effective RHEL stream once by calling
getRHELStream(nodePool, releaseImage) and pass that computed value into
rolloutConfig.rhelStream instead of using nodePool.Spec.OSImageStream.Name; also
propagate the same computed value into any CAPI-related code paths and platform
validation helper calls that previously read spec.osImageStream so all consumers
use the resolved stream (e.g., update usages in rolloutConfig initialization,
CAPI helpers, and platform validation functions to accept/consume the new
resolved rhelStream variable).
---
Nitpick comments:
In `@hypershift-operator/controllers/nodepool/nodepool_controller.go`:
- Around line 407-409: getRHELStream errors are being ignored in three places
(nodepool_controller.go when setting nodePool.Status.OSImageStream, capi.go
reconcileMachineDeploymentStatus, and capi.go reconcileMachineSet); update each
location to handle the error path: when getRHELStream returns an error, log the
error with the controller logger (including err.Error()) and set a clear status
condition (e.g., "OSImageStreamResolutionFailed") on the owning object with the
error message so users see the failure, and when getRHELStream succeeds clear
that condition and set Status.OSImageStream as before; reference the
getRHELStream call sites and the Status.OSImageStream update points and ensure
status updates are persisted.
In `@hypershift-operator/controllers/nodepool/osstream_test.go`:
- Around line 17-80: TestGetRHELStream lacks coverage for the error path in
getRHELStream when releaseImage.Version() yields an invalid semver; add a new
test case in TestGetRHELStream that supplies a releaseinfo.ReleaseImage whose
ImageStream.ObjectMeta.Name is an invalid version string (e.g., "not-a-semver"),
call getRHELStream(nodePool, releaseImage) and assert that an error is returned
(Expect(err).To(HaveOccurred())); reference the existing test harness and types
(TestGetRHELStream, getRHELStream, releaseinfo.ReleaseImage,
imageapi.ImageStream/ObjectMeta.Name) so the new case is consistent with the
other table-driven cases.
🪄 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 YAML (base), Central YAML (inherited)
Review profile: CHILL
Plan: Enterprise
Run ID: e87df744-44ee-4acb-9a91-4746ce49edd8
⛔ Files ignored due to path filters (1)
vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/nodepool_conditions.gois excluded by!vendor/**,!**/vendor/**
📒 Files selected for processing (13)
api/hypershift/v1beta1/nodepool_conditions.gohypershift-operator/controllers/nodepool/aws.gohypershift-operator/controllers/nodepool/aws_test.gohypershift-operator/controllers/nodepool/capi.gohypershift-operator/controllers/nodepool/config.gohypershift-operator/controllers/nodepool/gcp.gohypershift-operator/controllers/nodepool/gcp_test.gohypershift-operator/controllers/nodepool/nodepool_controller.gohypershift-operator/controllers/nodepool/nodepool_controller_test.gohypershift-operator/controllers/nodepool/osstream.gohypershift-operator/controllers/nodepool/osstream_test.gohypershift-operator/controllers/nodepool/token.gohypershift-operator/controllers/nodepool/token_test.go
| func getRHELStream(nodePool *hyperv1.NodePool, releaseImage *releaseinfo.ReleaseImage) (string, error) { | ||
| if nodePool.Spec.OSImageStream.Name != "" { | ||
| return nodePool.Spec.OSImageStream.Name, nil | ||
| } | ||
|
|
||
| version, err := semver.Parse(releaseImage.Version()) | ||
| if err != nil { | ||
| return "", fmt.Errorf("failed to parse release image version %q: %w", releaseImage.Version(), err) | ||
| } | ||
|
|
||
| if version.Major >= 5 { | ||
| return "rhel-10", nil | ||
| } | ||
| return "rhel-9", nil | ||
| } |
There was a problem hiding this comment.
Add nil-safety guards to prevent panics.
getRHELStream dereferences nodePool (Line 22) and releaseImage (Line 26) without nil checks. If either parameter is nil, the function will panic. Current callers appear to pass valid pointers, but defensive validation would prevent runtime panics if the contract changes or a new caller is added.
🛡️ Proposed fix to add nil guards
func getRHELStream(nodePool *hyperv1.NodePool, releaseImage *releaseinfo.ReleaseImage) (string, error) {
+ if nodePool == nil {
+ return "", fmt.Errorf("nodePool cannot be nil")
+ }
+ if releaseImage == nil {
+ return "", fmt.Errorf("releaseImage cannot be nil")
+ }
if nodePool.Spec.OSImageStream.Name != "" {
return nodePool.Spec.OSImageStream.Name, nil
}🤖 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 `@hypershift-operator/controllers/nodepool/osstream.go` around lines 21 - 35,
The getRHELStream function dereferences nodePool
(nodePool.Spec.OSImageStream.Name) and releaseImage (releaseImage.Version())
without nil checks; add defensive nil guards at the top of getRHELStream to
return a clear error if nodePool or releaseImage is nil, and also guard
nodePool.Spec or nodePool.Spec.OSImageStream as needed before accessing Name to
avoid panics, then proceed with semver.Parse on releaseImage.Version() only when
releaseImage is non-nil.
03a5cef to
8e027da
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
api/hypershift/v1beta1/nodepool_types.go (1)
51-60: 💤 Low valueConsider nil check for defensive safety.
The function dereferences
nodePoolat Line 52 without a nil check. While current callers in context snippets (conditions.go:390) pass valid pointers, adding a guard would prevent panics if a new caller is added or the contract changes.🛡️ Optional defensive nil guard
func validateOSImageStream(nodePool *hyperv1.NodePool) error { + if nodePool == nil { + return fmt.Errorf("nodePool cannot be nil") + } name := nodePool.Spec.OSImageStream.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 `@api/hypershift/v1beta1/nodepool_types.go` around lines 51 - 60, Locate the function that dereferences the nodePool parameter (likely in the nodepool_types.go file around the specified line range) and add a nil check guard before the dereference operation. The check should verify that nodePool is not nil before attempting to access its fields or methods, returning an appropriate error or early exit if the pointer is nil. This defensive check prevents potential panics if the function contract changes or new callers pass nil values in the future.hypershift-operator/controllers/nodepool/capi_test.go (2)
2771-2773: ⚡ Quick winAdd nil-safety to OSImageStream assertion.
The assertion at line 2772 directly accesses
nodePool.Status.OSImageStream.Namewithout first checking ifnodePool.Status.OSImageStreamis nil. If the status field is unexpectedly nil whenexpectedOSImageStreamis non-empty, this will panic rather than provide a clear test failure message.Safer assertion pattern
if tc.expectedOSImageStream != "" { + g.Expect(nodePool.Status.OSImageStream).ToNot(BeNil(), "OSImageStream should be set when stream is expected") g.Expect(nodePool.Status.OSImageStream.Name).To(Equal(tc.expectedOSImageStream)) }🤖 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 `@hypershift-operator/controllers/nodepool/capi_test.go` around lines 2771 - 2773, In the test assertion block where tc.expectedOSImageStream is checked, add a nil-safety check before accessing the Name field. When tc.expectedOSImageStream is non-empty, first verify that nodePool.Status.OSImageStream is not nil before attempting to access nodePool.Status.OSImageStream.Name in the Expect call. This will prevent a panic and provide a clear test failure message if the OSImageStream field is unexpectedly nil.
2636-2674: ⚡ Quick winAdd test case to verify OSImageStream status population on rollout completion.
The test infrastructure includes an
expectedOSImageStreamfield and conditional assertion (lines 2771-2773), but no test case actually verifies thatnodePool.Status.OSImageStreamis populated when the MachineDeployment completes. The test case at line 2652 setsexpectedOSImageStream: "", which skips the assertion entirely.According to the layer description,
reconcileMachineDeploymentStatusshould callgetRHELStreamand populatenodePool.Status.OSImageStreamwhen the deployment reaches completion. Add a test case that sets a non-emptyexpectedOSImageStreamvalue and verifies the status field is correctly populated.Consider also updating the test name at line 2652 to reflect what is actually being verified, or add a separate test case specifically for OSImageStream status population.
🤖 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 `@hypershift-operator/controllers/nodepool/capi_test.go` around lines 2636 - 2674, Add a new test case to the testCases slice in the TestReconcileMachineDeploymentStatus function that verifies OSImageStream status population when a MachineDeployment completes. This test case should have a non-empty expectedOSImageStream value (such as a valid RHEL stream identifier) and match the completion conditions of the existing test case (all replica counts at 3, ObservedGeneration matching Generation). This will ensure the conditional assertion at lines 2771-2773 that checks nodePool.Status.OSImageStream is actually exercised with a meaningful verification rather than being skipped due to an empty expected value.
🤖 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 `@hypershift-operator/controllers/nodepool/nodepool_controller.go`:
- Around line 406-408: In the nodepool_controller.go file, the call to
getRHELStream is silently ignoring errors by only handling the success case with
if err == nil. Instead of dropping the error, properly handle failure cases by
either logging the error with context and returning it to trigger
reconciliation, or updating the NodePool status to reflect the error condition.
This ensures that stream-resolution failures are visible and the status remains
synchronized with the actual state rather than remaining stale and unset.
In `@hypershift-operator/controllers/nodepool/token.go`:
- Around line 358-359: The assignment of TokenSecretOSStreamKey to
tokenSecret.Data only executes within a conditional block that checks if
tokenSecret.Data is nil, meaning existing token secrets never get the os-stream
field populated on reconciliation. Move the line
tokenSecret.Data[TokenSecretOSStreamKey] = []byte(t.rhelStream) outside of the
nil-check conditional so it runs on every reconciliation, ensuring all token
secrets have the os-stream field persisted consistently. Additionally, add unit
tests to verify that the os-stream field is set during both initial creation and
subsequent reconciliations, and add e2e tests to validate this behavior impacts
consumer behavior correctly.
---
Nitpick comments:
In `@api/hypershift/v1beta1/nodepool_types.go`:
- Around line 51-60: Locate the function that dereferences the nodePool
parameter (likely in the nodepool_types.go file around the specified line range)
and add a nil check guard before the dereference operation. The check should
verify that nodePool is not nil before attempting to access its fields or
methods, returning an appropriate error or early exit if the pointer is nil.
This defensive check prevents potential panics if the function contract changes
or new callers pass nil values in the future.
In `@hypershift-operator/controllers/nodepool/capi_test.go`:
- Around line 2771-2773: In the test assertion block where
tc.expectedOSImageStream is checked, add a nil-safety check before accessing the
Name field. When tc.expectedOSImageStream is non-empty, first verify that
nodePool.Status.OSImageStream is not nil before attempting to access
nodePool.Status.OSImageStream.Name in the Expect call. This will prevent a panic
and provide a clear test failure message if the OSImageStream field is
unexpectedly nil.
- Around line 2636-2674: Add a new test case to the testCases slice in the
TestReconcileMachineDeploymentStatus function that verifies OSImageStream status
population when a MachineDeployment completes. This test case should have a
non-empty expectedOSImageStream value (such as a valid RHEL stream identifier)
and match the completion conditions of the existing test case (all replica
counts at 3, ObservedGeneration matching Generation). This will ensure the
conditional assertion at lines 2771-2773 that checks
nodePool.Status.OSImageStream is actually exercised with a meaningful
verification rather than being skipped due to an empty expected value.
🪄 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 YAML (base), Central YAML (inherited)
Review profile: CHILL
Plan: Enterprise
Run ID: 8ebdba94-e5e5-4bf0-8e2a-0fa112fff63f
⛔ Files ignored due to path filters (5)
api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/nodepools.hypershift.openshift.io/OSStreams.yamlis excluded by!**/zz_generated.featuregated-crd-manifests/**cmd/install/assets/crds/hypershift-operator/tests/nodepools.hypershift.openshift.io/featuregated.nodepools.osimagestream.testsuite.yamlis excluded by!cmd/install/assets/**/*.yamlcmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/nodepools-CustomNoUpgrade.crd.yamlis excluded by!**/zz_generated.crd-manifests/**,!cmd/install/assets/**/*.yamlcmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/nodepools-TechPreviewNoUpgrade.crd.yamlis excluded by!**/zz_generated.crd-manifests/**,!cmd/install/assets/**/*.yamlvendor/github.com/openshift/hypershift/api/hypershift/v1beta1/nodepool_types.gois excluded by!vendor/**,!**/vendor/**
📒 Files selected for processing (16)
api/hypershift/v1beta1/nodepool_types.gohypershift-operator/controllers/nodepool/aws.gohypershift-operator/controllers/nodepool/aws_test.gohypershift-operator/controllers/nodepool/capi.gohypershift-operator/controllers/nodepool/capi_test.gohypershift-operator/controllers/nodepool/conditions.gohypershift-operator/controllers/nodepool/config.gohypershift-operator/controllers/nodepool/config_test.gohypershift-operator/controllers/nodepool/gcp.gohypershift-operator/controllers/nodepool/gcp_test.gohypershift-operator/controllers/nodepool/nodepool_controller.gohypershift-operator/controllers/nodepool/nodepool_controller_test.gohypershift-operator/controllers/nodepool/osstream.gohypershift-operator/controllers/nodepool/osstream_test.gohypershift-operator/controllers/nodepool/token.gohypershift-operator/controllers/nodepool/token_test.go
✅ Files skipped from review due to trivial changes (2)
- hypershift-operator/controllers/nodepool/nodepool_controller_test.go
- hypershift-operator/controllers/nodepool/aws_test.go
🚧 Files skipped from review as they are similar to previous changes (6)
- hypershift-operator/controllers/nodepool/config.go
- hypershift-operator/controllers/nodepool/aws.go
- hypershift-operator/controllers/nodepool/gcp_test.go
- hypershift-operator/controllers/nodepool/gcp.go
- hypershift-operator/controllers/nodepool/capi.go
- hypershift-operator/controllers/nodepool/config_test.go
| if stream, err := getRHELStream(nodePool, releaseImage); err == nil { | ||
| nodePool.Status.OSImageStream = hyperv1.OSImageStreamReference{Name: stream} | ||
| } |
There was a problem hiding this comment.
Do not silently drop getRHELStream errors when updating status.
On Line 406, ignoring the error makes stream-resolution failures invisible and can leave status.osImageStream stale/unset without any reconcile signal.
As per coding guidelines, "Never ignore error returns".
Suggested fix
- if stream, err := getRHELStream(nodePool, releaseImage); err == nil {
- nodePool.Status.OSImageStream = hyperv1.OSImageStreamReference{Name: stream}
- }
+ stream, err := getRHELStream(nodePool, releaseImage)
+ if err != nil {
+ return ctrl.Result{}, fmt.Errorf("failed to resolve OS image stream: %w", err)
+ }
+ nodePool.Status.OSImageStream = hyperv1.OSImageStreamReference{Name: stream}🤖 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 `@hypershift-operator/controllers/nodepool/nodepool_controller.go` around lines
406 - 408, In the nodepool_controller.go file, the call to getRHELStream is
silently ignoring errors by only handling the success case with if err == nil.
Instead of dropping the error, properly handle failure cases by either logging
the error with context and returning it to trigger reconciliation, or updating
the NodePool status to reflect the error condition. This ensures that
stream-resolution failures are visible and the status remains synchronized with
the actual state rather than remaining stale and unset.
Source: Coding guidelines
| tokenSecret.Data[TokenSecretOSStreamKey] = []byte(t.rhelStream) | ||
| } |
There was a problem hiding this comment.
Persist os-stream on every token-secret reconcile, not only on create.
Line 358 runs only when tokenSecret.Data == nil. Existing token secrets can miss os-stream indefinitely, which weakens the new cross-component secret contract.
As per coding guidelines, "Include unit tests for any code changes and additions, and include e2e tests when changes impact consumer behavior".
Suggested fix
- tokenSecret.Data[TokenSecretOSStreamKey] = []byte(t.rhelStream)
}
+ tokenSecret.Data[TokenSecretOSStreamKey] = []byte(t.rhelStream)
// TODO (alberto): Only apply this on creation and change the hash generation to only use triggering upgrade fields.
// We let this change to happen inplace now as the tokenSecret and the mcs config use the whole spec.Config for the comparing hash.
// Otherwise if something which does not trigger a new token generation from spec.Config changes, like .IDP, both hashes would mismatch forever.
tokenSecret.Data[TokenSecretHCConfigurationHashKey] = t.globalConfigHash🤖 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 `@hypershift-operator/controllers/nodepool/token.go` around lines 358 - 359,
The assignment of TokenSecretOSStreamKey to tokenSecret.Data only executes
within a conditional block that checks if tokenSecret.Data is nil, meaning
existing token secrets never get the os-stream field populated on
reconciliation. Move the line tokenSecret.Data[TokenSecretOSStreamKey] =
[]byte(t.rhelStream) outside of the nil-check conditional so it runs on every
reconciliation, ensuring all token secrets have the os-stream field persisted
consistently. Additionally, add unit tests to verify that the os-stream field is
set during both initial creation and subsequent reconciliations, and add e2e
tests to validate this behavior impacts consumer behavior correctly.
Source: Coding guidelines
|
I now have all the information needed. Here is the final report: Test Failure Analysis CompleteJob Information
Test Failure AnalysisErrorSummaryBoth jobs fail due to the same root cause: a duplicate Go test function name ( Root CauseError 1 — Duplicate PR #8669 (CNTRLPLANE-3552, merged 2026-06-17T00:06:30Z) added PR #8730 then adds The PR author refactored Error 2 — Unused The function Recommendations
Evidence
|
Add a FeatureGateAwareXValidation CEL rule on NodePoolSpec that prevents removing the osImageStream field once set, closing the two-step bypass for optional immutable fields on feature-gated types. Add an envtest case covering the removal scenario. Also add OSImageStreamRHEL9 and OSImageStreamRHEL10 constants for consistent use of stream name strings across the codebase. Co-Authored-By: Claude Opus 4.6 <[email protected]>
Wire the spec.osImageStream and status.osImageStream API fields (added in CNTRLPLANE-3017) into the NodePool reconciliation loop so that an explicit stream name is validated, included in the config hash (triggering rollouts), propagated to the token secret, and reported in status. - Add ValidOSImageStream condition and InvalidOSImageStream reason constants to the API. - Create osstream.go with getRHELStream() (derives stream from spec or release version) and validOSImageStreamCondition(). - Add rhelStream to rolloutConfig, Hash(), and HashWithoutVersion() for rollout triggering (backward compatible when empty). - Write os-stream key into the token secret for downstream ignition. - Set status.osImageStream on rollout completion in both Replace (MachineDeployment) and InPlace (MachineSet) paths. - Thread rhelStream parameter through boot image resolution functions (defaultNodePoolAMI, defaultNodePoolGCPImage, and their callers) in preparation for multi-stream metadata parsing (CNTRLPLANE-3553). Signed-off-by: Salvatore Dario Minonne <[email protected]> Commit-Message-Assisted-by: Claude (via Claude Code) Co-Authored-By: Claude Opus 4.6 <[email protected]>
…us, and error path - Add "When rhelStream is set, it should change the hash" case to TestHash and TestHashWithoutVersion, verifying that changing rhelStream changes the hash and that empty rhelStream preserves backward-compatible values. - Add expectedOSImageStream assertion to TestReconcileMachineDeploymentStatus, verifying status.osImageStream is set to rhel-9 on rollout completion with a 4.x release. - Add error path case to TestGetRHELStream for unparseable version strings. Signed-off-by: Salvatore Dario Minonne <[email protected]> Commit-Message-Assisted-by: Claude (via Claude Code) Co-Authored-By: Claude Opus 4.6 <[email protected]>
…hancement Fix getRHELStream() to return "" for unset+<5.0 (legacy single-stream behavior where no OSImageStream CR is generated), matching the enhancement spec. For unset+>=5.0 it returns "rhel-10". Extract defaultRHELStream() for version-based derivation, used by NewConfigGenerator to normalize the hash: when the user explicitly sets osImageStream to the version-derived default (e.g. "rhel-9" on 4.x), the hash stays unchanged and no spurious rollout is triggered. Only a non-default stream produces a different hash. Move osImageStream validation from a separate ValidOSImageStream condition into validMachineConfigCondition, consistent with the enhancement design where stream validation runs alongside config validation and has access to the ConfigGenerator context. Co-Authored-By: Claude Opus 4.6 <[email protected]>
The nilerr linter flagged that validateOSImageStream error was checked but the function returned nil instead of the error. Propagate the error to match the pattern used by other validation failures in the same function. Signed-off-by: Salvatore Dario Minonne <[email protected]> Commit-Message-Assisted-by: Claude (via Claude Code) Co-Authored-By: Claude Opus 4.6 <[email protected]>
49e64cb to
ebde395
Compare
|
I'll rebase this once #8699 will be merged |
Summary
Wire
spec.osImageStreamandstatus.osImageStreaminto the NodePoolreconciliation loop: config hash (triggering rollouts on stream change),
token secret propagation, status reporting, and boot image function
parameter threading.
Aligns with the dual-stream RHEL NodePool enhancement
Phase 2 controller plumbing.
Dependencies
CNTRLPLANE-3023: CEL rule to prevent osImageStream removal, API constants)Changes
Config hash integration (
config.go)rhelStreamtorolloutConfig,Hash(), andHashWithoutVersion()rhelStreaminNewConfigGenerator: when the explicitspec.osImageStream.namematches the version-derived default (e.g."rhel-9"on a 4.x release), it is kept as""so the hash doesn'tchange and no spurious rollout is triggered. Only a non-default stream
produces a different hash
defaultRHELStream()for the normalization comparisonStream resolution (
osstream.go)getRHELStream()returns:spec.osImageStream.namewhen set"rhel-10"when unset and release >= 5.0""when unset and release < 5.0 (legacy single-stream behavior,no OSImageStream CR generated)
validateOSImageStream()checks that the stream name, if set, is oneof
rhel-9orrhel-10Validation (
conditions.go)validMachineConfigCondition(not a separate condition), consistent with the enhancement design
where stream validation has access to the ConfigGenerator context
Token secret (
token.go)os-streamkey into the token secret for downstream ignitionStatus propagation (
capi.go)status.osImageStreamon rollout completion in both Replace(MachineDeployment) and InPlace (MachineSet) paths
Boot image threading (
aws.go,gcp.go)rhelStreamparameter throughdefaultNodePoolAMI,defaultNodePoolGCPImage, and their callers. Parameter is acceptedbut not yet consumed — marked with
TODO([CNTRLPLANE-3553](https://redhat.atlassian.net/browse/CNTRLPLANE-3553))for whenmulti-stream metadata parsing lands
What's not yet implemented (future work)
usesRuncguard (explicit rhel-10 + runc → error, implicit >=5.0 + runc → fallback to rhel-9)GetPayload())Test plan
TestGetRHELStream— covers explicit stream, 4.x/5.x/6.x defaults, unparsable versionTestDefaultRHELStream— covers version-based derivationTestValidateOSImageStream— covers empty, valid, and invalid stream namesTestHash/TestHashWithoutVersion— covers non-default stream changing the hashTestReconcileMachineDeploymentStatus— covers status.osImageStream on rollout completionmake verifypasses clean🤖 Generated with Claude Code
Summary by CodeRabbit
Release Notes
New Features
Tests