CNTRLPLANE-3532: migrate CPO status patches to statuspatching helpers - #8966
CNTRLPLANE-3532: migrate CPO status patches to statuspatching helpers#8966vsolanki12 wants to merge 1 commit into
Conversation
|
Pipeline controller notification For optional jobs, comment This repository is configured in: LGTM mode |
|
@vsolanki12: This pull request references CNTRLPLANE-3532 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. |
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis PR adds stream-aware NodePool image resolution and OS stream status inference, targeted HostedControlPlane status patching, encryption-config hash convergence checks, cloud-provider retry and cleanup paths, GCP PSC network-scoped subnet discovery, and HyperShift AWS resource tagging. It also updates router and deployment ordering, secret cleanup labels, resource override handling, E2E utilities, logging, tests, and build tooling. Sequence Diagram(s)sequenceDiagram
participant NodePoolReconciler
participant ReleaseImage
participant ProviderImageResolver
participant MachineTemplate
NodePoolReconciler->>ReleaseImage: Resolve selected RHEL stream
NodePoolReconciler->>ProviderImageResolver: Request stream-specific image
ProviderImageResolver->>MachineTemplate: Build provider machine template
MachineTemplate-->>NodePoolReconciler: Return image and rollout identity
Possibly related PRs
Suggested reviewers: ✨ Finishing Touches🧪 Generate unit tests (beta)
|
fb8a23c to
d73cc0d
Compare
Codecov Report❌ Patch coverage is Please upload reports for the commit 9a6b2ba to get more accurate results. Additional details and impacted files@@ Coverage Diff @@
## main #8966 +/- ##
==========================================
- Coverage 44.61% 44.10% -0.52%
==========================================
Files 774 772 -2
Lines 97098 96167 -931
==========================================
- Hits 43317 42410 -907
- Misses 50785 50816 +31
+ Partials 2996 2941 -55
... and 59 files with indirect coverage changes
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: 2
🤖 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
`@control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go`:
- Around line 1117-1139: The status patch in hostedcontrolplane_controller.go is
using a stale copy of HostedControlPlane and will overwrite earlier updates made
in update() and reconcileCPOV2. Fix the PatchStatus call to patch the current
in-memory hostedControlPlane state, or explicitly merge the existing status
fields back before setting ValidReleaseInfo. Keep the existing status mutations
such as Ready, KubeConfig, KubeadminPassword, ControlPlaneVersion, Initialized,
and prior conditions intact when applying the patch.
In
`@control-plane-operator/hostedclusterconfigoperator/controllers/reencryption/reencryption.go`:
- Around line 76-89: The `desiredCondition` in `reconcile` is a pointer into
`hcp.Status.Conditions`, so `statuspatching.PatchStatus` may re-fetch and
overwrite the backing slice before the callback uses it. Capture the condition
by value before calling `PatchStatus` (for example, copy the result of
`meta.FindStatusCondition` into a standalone variable) and then use that copied
value inside the patch callback when setting `hcp.Status.Conditions`.
🪄 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: ddb9d783-3baf-45e9-a217-5ed2a8755bb9
📒 Files selected for processing (3)
control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.gocontrol-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller_test.gocontrol-plane-operator/hostedclusterconfigoperator/controllers/reencryption/reencryption.go
d73cc0d to
7848ce8
Compare
|
Both failures are now fully analyzed. Let me produce the final report. Test Failure Analysis CompleteJob Information
Test Failure AnalysisErrorSummaryBoth failures are transient infrastructure flakes completely unrelated to the code changes in PR #8966. The Root CauseJob 1 — verify / Verify:
These are server-side errors from the Go module proxy CDN, not local network issues or code problems. Job 2 — Red Hat Konflux / control-plane-operator-main-on-pull-request: Neither failure is related to the PR's code changes (migrating CPO status patches to statuspatching helpers). Recommendations
Evidence
|
cblecker
left a comment
There was a problem hiding this comment.
The migration to statuspatching helpers looks well-executed across all call sites. F1 (metrics regression in reencryption.go) is the main concern — the rest are suggestions.
| } | ||
|
|
||
| // Record metrics when encryption status changed. | ||
| if !equality.Semantic.DeepEqual(previousEncryption, desiredEncryption) { |
There was a problem hiding this comment.
recordMigrationState is now gated behind the DeepEqual check, but the old code called it unconditionally on every reconcile. After an HCCO pod restart in steady state (no encryption change), all hypershift_encryption_migration_state gauges stay at zero indefinitely — the "idle" gauge is never re-set to 1. This could confuse dashboards/alerts until the next key rotation, which may be weeks away.
Consider moving recordMigrationState outside the if !equality.Semantic.DeepEqual(...) block so it runs unconditionally, matching the old behavior. recordMigrationDuration should stay inside the guard since it should only fire on actual transitions.
There was a problem hiding this comment.
Done. Moved recordMigrationState outside the DeepEqual guard so it runs unconditionally on every reconcile, matching the old behavior. recordMigrationDuration stays inside the guard since it should only fire on actual transitions.
AI-assisted response via Claude Code
|
|
||
| func (r *HostedControlPlaneReconciler) reconcileDeletion(ctx context.Context, hostedControlPlane *hyperv1.HostedControlPlane, originalHostedControlPlane *hyperv1.HostedControlPlane) (ctrl.Result, error) { | ||
| func (r *HostedControlPlaneReconciler) reconcileDeletion(ctx context.Context, hostedControlPlane *hyperv1.HostedControlPlane) (ctrl.Result, error) { | ||
| condition := &metav1.Condition{ |
There was a problem hiding this comment.
Nit: condition is declared as a pointer (&metav1.Condition{...}) and then dereferenced (*condition) when passed to PatchStatusCondition. The other migrated sites (reconcileDefaultSecurityGroup, removeCloudResources) use value types or inline literals. Switching to a value type here would be more consistent and avoids the unnecessary indirection.
There was a problem hiding this comment.
Done. Changed condition from *metav1.Condition to metav1.Condition — consistent with the other migrated sites now.
AI-assisted response via Claude Code
| if err := statuspatching.PatchStatus(ctx, r.Client, hcp, func() error { | ||
| meta.SetStatusCondition(&hcp.Status.Conditions, condition) | ||
| if creationErr == nil { | ||
| hcp.Status.Platform = &hyperv1.PlatformStatus{ |
There was a problem hiding this comment.
Pre-existing, but worth noting since the PatchStatus migration touches this: the callback replaces the entire hcp.Status.Platform struct with a new one containing only the security group ID. If PlatformStatus gains additional fields in the future, they'd be silently cleared on every reconcile. With PatchStatus retrying on conflict, the fresh struct also discards whatever the server has at retry time.
Consider initializing hcp.Status.Platform / hcp.Status.Platform.AWS if nil instead of replacing, then setting only DefaultWorkerSecurityGroupID.
There was a problem hiding this comment.
Done. Changed to init-if-nil pattern — hcp.Status.Platform and hcp.Status.Platform.AWS are now initialized only if nil, then only DefaultWorkerSecurityGroupID is set. This preserves any other fields that may be added to PlatformStatus in the future.
AI-assisted response via Claude Code
| Status: metav1.ConditionTrue, | ||
| Reason: hyperv1.AsExpectedReason, | ||
| Message: hyperv1.AllIsWellMessage, | ||
| ObservedGeneration: hostedControlPlane.Generation, |
There was a problem hiding this comment.
Not a regression (old code also re-fetched before referencing Generation), but ObservedGeneration inside the PatchStatus closure will reflect the re-fetched HCP's generation, which may be newer than the generation used to compute missingImages. If the spec changed between the original read and the re-fetch, the condition content won't match what that generation actually means. A follow-up reconcile self-corrects, so this is minor — just flagging in case you want to snapshot the generation before the PatchStatus call.
There was a problem hiding this comment.
Acknowledged. This is pre-existing — the old code also re-fetched before referencing Generation. A follow-up reconcile self-corrects, so leaving as-is for now.
AI-assisted response via Claude Code
7848ce8 to
4237039
Compare
| // Capture desired status changes computed by reconcile(). | ||
| // Copy by value — PatchStatus re-fetches hcp, which replaces the backing slice. | ||
| desiredEncryption := *hcp.Status.SecretEncryption.DeepCopy() | ||
| var desiredCondition metav1.Condition |
There was a problem hiding this comment.
Potential semantic narrowing: The original MergeFrom(originalHCP) patch captured all status mutations made by reconcile(). This new code snapshots only SecretEncryption and the EtcdDataEncryptionUpToDate condition, then replays just those two fields inside the PatchStatus closure.
If reconcile() (or any of its sub-functions like handleInitialBootstrap, startNewRotation, handleMigratingPhase, etc.) sets other status fields or conditions beyond these two, those changes are silently dropped after PatchStatus re-fetches the object.
Is EtcdDataEncryptionUpToDate the only condition reconcile() touches? If so this is fine — but worth a comment saying so. If not, the other conditions need to be captured and replayed too.
There was a problem hiding this comment.
Good catch. Confirmed — reconcile() only mutates SecretEncryption and the EtcdDataEncryptionUpToDate condition. No other status fields or conditions. Added a comment on the snapshot block stating this explicitly.
…ng helpers Migrate 9 status patch call sites across hostedcontrolplane_controller.go and reencryption.go to use the shared statuspatching package, adding retry-on-conflict and consistent optimistic locking. - hostedcontrolplane_controller.go: 7 sites migrated to PatchStatus / PatchStatusCondition (reconcileDeletion, update, reconcileValidIDP, removeCloudResources, reconcileDefaultSecurityGroup) - reencryption.go: 1 site migrated to PatchStatus - 2 batch-patch sites (lines 686, 869) deferred — they accumulate status changes across the full reconcile loop and need restructuring Signed-off-by: Vimal Solanki <vsolanki@redhat.com>
50d87f2 to
6aa69ee
Compare
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: vsolanki12 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 |
6aa69ee to
9a6b2ba
Compare
There was a problem hiding this comment.
Actionable comments posted: 10
🧹 Nitpick comments (9)
support/controlplane-component/status.go (1)
39-40: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winAdd regression coverage for the new dependency exclusions.
Please add or verify focused tests in
support/controlplane-component/status_test.goproving that bothignition-serverandignition-server-proxyomit the kube-apiserver dependency while existing components retain it. A typo or accidental removal would otherwise silently change reconciliation ordering.As per coding guidelines, Go code changes and additions must be unit tested.
🤖 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 `@support/controlplane-component/status.go` around lines 39 - 40, Add focused unit tests in the status test suite covering the dependency exclusions for both “ignition-server” and “ignition-server-proxy”, asserting they omit kube-apiserver while existing components still include it. Reuse the existing status/dependency test helpers and preserve current reconciliation behavior.Source: Coding guidelines
hack/tools/crd-schema-check/main.go (1)
58-60: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd regression coverage for common-directory repositories.
Please add or verify a test in
hack/tools/crd-schema-check/main_test.gothat exercises a.gitfile pointing to a common Git directory. This option changes repository-opening behavior and should not rely only on the standard repository path.As per coding guidelines, Go code changes and additions must be unit tested.
🤖 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 `@hack/tools/crd-schema-check/main.go` around lines 58 - 60, Add regression coverage in main_test.go for the repository-opening flow around gogit.PlainOpenWithOptions, using a repository whose .git is a file pointing to a common Git directory. Verify the repository opens and the CRD schema check behavior succeeds, while preserving existing standard-repository test coverage.Source: Coding guidelines
control-plane-operator/controllers/hostedcontrolplane/v2/router/component.go (1)
105-124: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueRoute names are duplicated string literals.
ignition-server,oauth-internal, etc. already exist as constants/manifest helpers elsewhere (e.g.hypershift-operator/controllers/manifests/ignitionserverexposes the ignition route name). Referencing those keeps this gate in sync if a route is ever renamed.🤖 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 `@control-plane-operator/controllers/hostedcontrolplane/v2/router/component.go` around lines 105 - 124, Replace the duplicated route-name literals in aroBaseHCPRouterRouteNames and aroExpectedHCPRouterRouteNames with the existing route-name constants or manifest helpers, including the ignition, OAuth, and metrics-proxy routes. Reuse the canonical symbols from the relevant packages so route validation stays synchronized with any future renames.cmd/cluster/core/create_test.go (1)
1814-1822: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider making the backoff injectable to avoid real sleeps in unit tests.
validateClusterExistenceWithClienthardcodes a 1s/2x/5-step backoff, so the persistent-timeout and service-unavailable cases sleep for real (~15s and ~3s respectively), noticeably slowing this package's tests. Passing thewait.Backoffas a parameter (or a package-level var overridable in tests) would keep coverage while dropping runtime to near zero.🤖 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 `@cmd/cluster/core/create_test.go` around lines 1814 - 1822, The backoff used by validateClusterExistenceWithClient is hardcoded, causing persistent-error tests to sleep in real time. Make its wait.Backoff configurable—prefer passing it into validateClusterExistenceWithClient or using an overridable package-level value—and configure the relevant tests with a near-zero backoff while preserving production defaults and retry behavior.hypershift-operator/controllers/platform/gcp/privateserviceconnect_controller.go (1)
313-333: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win
isSubnetInUsere-lists all service attachments for every candidate subnet.Each loop iteration issues a fresh
ListServiceAttachmentscall (with its own timeout). For a project with many PSC subnets this is O(N) identical API calls and increases the chance of hitting quota/rate limits. Listing once before the loop and matching in-memory would be equivalent.♻️ Sketch
+ usedSubnets, err := r.usedNATSubnets(ctx) + if err != nil { + return "", fmt.Errorf("failed to list service attachments: %w", err) + } + // Find the first available PSC subnet in the MC's VPC not already in use by another Service Attachment. - var checkErrors int for _, subnet := range subnets { - inUse, err := r.isSubnetInUse(ctx, subnet.Name) - if err != nil { - log.Error(err, "Failed to check subnet usage", "subnet", subnet.Name) - checkErrors++ - continue - } - - if !inUse { + if !usedSubnets.Has(subnet.Name) { log.Info("Found available PSC subnet", "subnet", subnet.Name) return subnet.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/platform/gcp/privateserviceconnect_controller.go` around lines 313 - 333, Update the subnet-selection flow around isSubnetInUse to list the project’s Service Attachments once before iterating over subnets, then determine each candidate’s usage from that in-memory result. Remove the per-candidate isSubnetInUse API calls while preserving the existing available-subnet selection, error logging, and no-available-subnet behavior.hypershift-operator/controllers/platform/gcp/privateserviceconnect_controller_test.go (1)
387-435: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider consolidating these into table-driven subtests.
TestLookupForwardingRule_*andTestDiscoverNATSubnet_*are near-identical single-scenario functions differing only in fake inputs and expectations; the filter assertion is copy-pasted four times. Folding each group into one table-driven test withWhen ... it should ...case names would match the repo's test conventions.As per coding guidelines: "Use table-driven tests where possible" and "Always use 'When ... it should ...' format for describing test cases when creating unit tests".
Also applies to: 529-600
🤖 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/platform/gcp/privateserviceconnect_controller_test.go` around lines 387 - 435, Consolidate the TestLookupForwardingRule_* cases and the TestDiscoverNATSubnet_* cases into one table-driven test per function, using subtest names in “When ... it should ...” format. Preserve each scenario’s fake inputs, expected result, error handling, and forwarding-rule filter assertions while removing duplicated test setup and checks.Source: Coding guidelines
hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure_test.go (1)
560-566: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
expectedErroris never exercised.No test case sets
expectedError: true, so the error branch is dead. Either add a case (e.g. an injected List/Update failure via an interceptor client) or drop the field.Also applies to: 704-708
🤖 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/hostedcluster/internal/platform/azure/azure_test.go` around lines 560 - 566, Update the test cases around the expectedError field so the error path is actually exercised: add a case that injects a List or Update failure through the interceptor client and asserts the expected error, or remove expectedError and its related assertions if error coverage is not intended. Apply the same change to the additional test table occurrence.control-plane-operator/hostedclusterconfigoperator/controllers/machine/machine.go (1)
138-146: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueFlatten the nested conditionals.
The per-family guards can be combined into single conditions, which keeps this loop body flatter. As per coding guidelines, "Do not over-nest control flow (e.g., nested
iforforblocks)."♻️ Proposed refactor
- if parsedAddr.Is4() { - if len(ipv4MachineAddresses) == 0 { - ipv4MachineAddresses = append(ipv4MachineAddresses, machineAddress.Address) - } - } else { - if len(ipv6MachineAddresses) == 0 { - ipv6MachineAddresses = append(ipv6MachineAddresses, machineAddress.Address) - } - } + if parsedAddr.Is4() && len(ipv4MachineAddresses) == 0 { + ipv4MachineAddresses = append(ipv4MachineAddresses, machineAddress.Address) + } else if !parsedAddr.Is4() && len(ipv6MachineAddresses) == 0 { + ipv6MachineAddresses = append(ipv6MachineAddresses, machineAddress.Address) + }🤖 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 `@control-plane-operator/hostedclusterconfigoperator/controllers/machine/machine.go` around lines 138 - 146, Flatten the nested conditionals in the machine address loop: combine each `parsedAddr.Is4()`/`len(...) == 0` guard into one condition, and likewise combine the IPv6 guard, while preserving the existing append behavior and family-specific slices.Source: Coding guidelines
hypershift-operator/controllers/nodepool/version_test.go (1)
283-291: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueType the fixtures as
[]*v1beta1.Machineand drop the conversion loop.Now that the helpers take
[]*capiv1.Machinedirectly, the[]client.Objectfield plus uncheckedobj.(*v1beta1.Machine)assertion in both tests is unnecessary indirection (and would panic on a mistyped fixture).Also applies to: 581-588
🤖 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/version_test.go` around lines 283 - 291, Update both affected tests to declare their machine fixtures as []*v1beta1.Machine (or the helper’s expected machine type) instead of []client.Object, then pass those fixtures directly to setNodesInfoStatus. Remove the conversion loops and unchecked obj.(*v1beta1.Machine) assertions while preserving the existing test cases and expectations.
🤖 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 `@cmd/infra/aws/create_iam.go`:
- Around line 173-178: Update the InfraID handling in the IAM tag construction
flow to find and replace any existing additionalIAMTags entry with key
supportawsutil.HypershiftInfraIDTagKey using the enforced o.InfraID value. Only
append a new tag when no matching key exists, preserving unique tag keys for
CreateRole and TagRole.
In `@cmd/infra/aws/route53.go`:
- Around line 118-131: The TestCreatePrivateZone mock expectation for
ChangeTagsForResource must assert the complete Route53 tag set instead of
accepting gomock.Any(). Match the expected HyperShift and additional EC2 tag
keys and values, preserving the production tags assembled in r53Tags, and add or
update unit-test coverage for this assertion.
In `@cmd/infra/azure/networking.go`:
- Around line 315-321: The retry budget comments overstate the maximum wait
because retry.OnError sleeps only between attempts. In
cmd/infra/azure/networking.go lines 315-321, update the backoff comment to
approximately 75 seconds; in cmd/cluster/core/create.go lines 814-820, update
the corresponding comment to approximately 15 seconds. Keep the existing Steps
values unchanged.
In
`@control-plane-operator/controllers/hostedcontrolplane/v2/assets/openshift-oauth-apiserver/deployment.yaml`:
- Around line 129-145: Add a resources.requests block to the wait-for-etcd init
container, using the matching small request values cpu: 5m and memory: 10Mi
consistent with audit-logs. Do not alter its existing command, environment,
image, or other settings.
In
`@control-plane-operator/controllers/hostedcontrolplane/v2/router/component.go`:
- Around line 126-132: Update metricsProxyRouteRequired and the
aroExpectedHCPRouterRouteNames/ensureHCPRouterRoutesExist call chain to return
and propagate the endpointresolverv2.Predicate error, allowing routerPredicate
to return it and trigger reconciliation rather than treating failure as not
required. Pass the real cpContext into component.WorkloadContext instead of
constructing one with nil Client and Context, while preserving the existing
route requirement checks.
In
`@control-plane-operator/hostedclusterconfigoperator/controllers/reencryption/reencryption.go`:
- Around line 337-340: Update the decode error handling after
secretencryption.DecodeEncryptionConfiguration in the reencryption function to
wrap the returned error with context identifying the encryption configuration
that failed to decode, while preserving the existing TargetKeyAbsent and
configHash return values.
In
`@hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure_test.go`:
- Around line 713-723: Update the expectedFinalizersRemoved branch in the Azure
machine test to assert directly on machine-1 rather than relying on iterating
azureMachineList.Items. Treat the expected outcome as either machine-1 being
absent from the list or, if present, having empty finalizers; leave the
non-removal assertion unchanged.
In
`@hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure.go`:
- Around line 371-375: Update Azure.DeleteOrphanedMachines to return nil when
hc.Spec.Platform.Azure is nil before accessing
AzureAuthenticationConfig.ManagedIdentities, while preserving the existing
managed-identities guard. Add a test covering cleanup with a nil Azure platform
spec and verify it completes without error or panic.
In `@hypershift-operator/controllers/nodepool/version.go`:
- Around line 96-118: Update rhcosOSImageRe and rhcosStreamFromOSImage to
recognize RHEL-based OSImage versions in both 9.x and 10.x forms, such as
“CoreOS 9.6...” and “CoreOS 10.6...”, while preserving existing 4xx-to-RHEL9 and
5xx-to-RHEL10 mappings; return StreamRHEL9 or StreamRHEL10 for the corresponding
formats and keep unrecognized versions returning an empty string.
In `@test/e2e/nodepool_spot_termination_handler_test.go`:
- Around line 150-155: Add the SQS-specific red-hat=true authorization tag to
sqsTags before the CreateQueue call in the node pool termination handler test,
preserving the existing environment, infrastructure, and cluster tags so
NodePoolSQSActions can authorize queue access.
---
Nitpick comments:
In `@cmd/cluster/core/create_test.go`:
- Around line 1814-1822: The backoff used by validateClusterExistenceWithClient
is hardcoded, causing persistent-error tests to sleep in real time. Make its
wait.Backoff configurable—prefer passing it into
validateClusterExistenceWithClient or using an overridable package-level
value—and configure the relevant tests with a near-zero backoff while preserving
production defaults and retry behavior.
In
`@control-plane-operator/controllers/hostedcontrolplane/v2/router/component.go`:
- Around line 105-124: Replace the duplicated route-name literals in
aroBaseHCPRouterRouteNames and aroExpectedHCPRouterRouteNames with the existing
route-name constants or manifest helpers, including the ignition, OAuth, and
metrics-proxy routes. Reuse the canonical symbols from the relevant packages so
route validation stays synchronized with any future renames.
In
`@control-plane-operator/hostedclusterconfigoperator/controllers/machine/machine.go`:
- Around line 138-146: Flatten the nested conditionals in the machine address
loop: combine each `parsedAddr.Is4()`/`len(...) == 0` guard into one condition,
and likewise combine the IPv6 guard, while preserving the existing append
behavior and family-specific slices.
In `@hack/tools/crd-schema-check/main.go`:
- Around line 58-60: Add regression coverage in main_test.go for the
repository-opening flow around gogit.PlainOpenWithOptions, using a repository
whose .git is a file pointing to a common Git directory. Verify the repository
opens and the CRD schema check behavior succeeds, while preserving existing
standard-repository test coverage.
In
`@hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure_test.go`:
- Around line 560-566: Update the test cases around the expectedError field so
the error path is actually exercised: add a case that injects a List or Update
failure through the interceptor client and asserts the expected error, or remove
expectedError and its related assertions if error coverage is not intended.
Apply the same change to the additional test table occurrence.
In `@hypershift-operator/controllers/nodepool/version_test.go`:
- Around line 283-291: Update both affected tests to declare their machine
fixtures as []*v1beta1.Machine (or the helper’s expected machine type) instead
of []client.Object, then pass those fixtures directly to setNodesInfoStatus.
Remove the conversion loops and unchecked obj.(*v1beta1.Machine) assertions
while preserving the existing test cases and expectations.
In
`@hypershift-operator/controllers/platform/gcp/privateserviceconnect_controller_test.go`:
- Around line 387-435: Consolidate the TestLookupForwardingRule_* cases and the
TestDiscoverNATSubnet_* cases into one table-driven test per function, using
subtest names in “When ... it should ...” format. Preserve each scenario’s fake
inputs, expected result, error handling, and forwarding-rule filter assertions
while removing duplicated test setup and checks.
In
`@hypershift-operator/controllers/platform/gcp/privateserviceconnect_controller.go`:
- Around line 313-333: Update the subnet-selection flow around isSubnetInUse to
list the project’s Service Attachments once before iterating over subnets, then
determine each candidate’s usage from that in-memory result. Remove the
per-candidate isSubnetInUse API calls while preserving the existing
available-subnet selection, error logging, and no-available-subnet behavior.
In `@support/controlplane-component/status.go`:
- Around line 39-40: Add focused unit tests in the status test suite covering
the dependency exclusions for both “ignition-server” and
“ignition-server-proxy”, asserting they omit kube-apiserver while existing
components still include it. Reuse the existing status/dependency test helpers
and preserve current reconciliation behavior.
🪄 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: Pro Plus
Run ID: b334061b-bbd9-49a5-905b-60b2092e6526
⛔ Files ignored due to path filters (26)
cmd/cluster/azure/testdata/zz_fixture_TestCreateCluster_When_endpoint_access_is_Private_with_endpoint_access_private_flags_it_should_render_HostedCluster_with_Private_endpoint_access.yamlis excluded by!**/testdata/**cmd/cluster/azure/testdata/zz_fixture_TestCreateCluster_When_oauth_publishing_strategy_is_LoadBalancer_with_workload_identities_it_should_render_HostedCluster_with_OAuth_LoadBalancer.yamlis excluded by!**/testdata/**cmd/cluster/azure/testdata/zz_fixture_TestCreateCluster_complicated_invocation_from_bryan.yamlis excluded by!**/testdata/**cmd/cluster/azure/testdata/zz_fixture_TestCreateCluster_minimal_flags_necessary_to_render.yamlis excluded by!**/testdata/**cmd/cluster/azure/testdata/zz_fixture_TestCreateCluster_with_KubeAPIServerDNSName.yamlis excluded by!**/testdata/**cmd/cluster/azure/testdata/zz_fixture_TestCreateCluster_with_availability_zones.yamlis excluded by!**/testdata/**cmd/cluster/azure/testdata/zz_fixture_TestCreateCluster_with_disabled_capabilities.yamlis excluded by!**/testdata/**cmd/infra/aws/delegating_client.gois excluded by!cmd/infra/aws/delegating_client.gocontrol-plane-operator/controllers/hostedcontrolplane/testdata/cluster-version-operator/AROSwift/zz_fixture_TestControlPlaneComponents_cluster_version_operator_deployment.yamlis excluded by!**/testdata/**control-plane-operator/controllers/hostedcontrolplane/testdata/cluster-version-operator/GCP/zz_fixture_TestControlPlaneComponents_cluster_version_operator_deployment.yamlis excluded by!**/testdata/**control-plane-operator/controllers/hostedcontrolplane/testdata/cluster-version-operator/IBMCloud/zz_fixture_TestControlPlaneComponents_cluster_version_operator_deployment.yamlis excluded by!**/testdata/**control-plane-operator/controllers/hostedcontrolplane/testdata/cluster-version-operator/TechPreviewNoUpgrade/zz_fixture_TestControlPlaneComponents_cluster_version_operator_deployment.yamlis excluded by!**/testdata/**control-plane-operator/controllers/hostedcontrolplane/testdata/cluster-version-operator/zz_fixture_TestControlPlaneComponents_cluster_version_operator_deployment.yamlis excluded by!**/testdata/**control-plane-operator/controllers/hostedcontrolplane/testdata/kube-apiserver/AROSwift/zz_fixture_TestControlPlaneComponents_kube_apiserver_deployment.yamlis excluded by!**/testdata/**control-plane-operator/controllers/hostedcontrolplane/testdata/openshift-oauth-apiserver/AROSwift/zz_fixture_TestControlPlaneComponents_openshift_oauth_apiserver_deployment.yamlis excluded by!**/testdata/**control-plane-operator/controllers/hostedcontrolplane/testdata/openshift-oauth-apiserver/GCP/zz_fixture_TestControlPlaneComponents_openshift_oauth_apiserver_deployment.yamlis excluded by!**/testdata/**control-plane-operator/controllers/hostedcontrolplane/testdata/openshift-oauth-apiserver/IBMCloud/zz_fixture_TestControlPlaneComponents_openshift_oauth_apiserver_deployment.yamlis excluded by!**/testdata/**control-plane-operator/controllers/hostedcontrolplane/testdata/openshift-oauth-apiserver/TechPreviewNoUpgrade/zz_fixture_TestControlPlaneComponents_openshift_oauth_apiserver_deployment.yamlis excluded by!**/testdata/**control-plane-operator/controllers/hostedcontrolplane/testdata/openshift-oauth-apiserver/zz_fixture_TestControlPlaneComponents_openshift_oauth_apiserver_deployment.yamlis excluded by!**/testdata/**control-plane-operator/controllers/hostedcontrolplane/testdata/router/AROSwift/zz_fixture_TestControlPlaneComponents_router_controlplanecomponent.yamlis excluded by!**/testdata/**control-plane-operator/controllers/hostedcontrolplane/testdata/router/GCP/zz_fixture_TestControlPlaneComponents_router_controlplanecomponent.yamlis excluded by!**/testdata/**control-plane-operator/controllers/hostedcontrolplane/testdata/router/IBMCloud/zz_fixture_TestControlPlaneComponents_router_controlplanecomponent.yamlis excluded by!**/testdata/**control-plane-operator/controllers/hostedcontrolplane/testdata/router/TechPreviewNoUpgrade/zz_fixture_TestControlPlaneComponents_router_controlplanecomponent.yamlis excluded by!**/testdata/**control-plane-operator/controllers/hostedcontrolplane/testdata/router/zz_fixture_TestControlPlaneComponents_router_controlplanecomponent.yamlis excluded by!**/testdata/**docs/content/reference/aggregated-docs.mdis excluded by!docs/content/reference/aggregated-docs.mdvendor/github.com/openshift/hypershift/api/hypershift/v1beta1/nodepool_types.gois excluded by!vendor/**,!**/vendor/**
📒 Files selected for processing (100)
.pre-commit-config.yamlMakefileOWNERS_ALIASESapi/hypershift/v1beta1/nodepool_types.gocmd/bastion/aws/create.gocmd/cluster/aws/create.gocmd/cluster/aws/create_test.gocmd/cluster/azure/create_test.gocmd/cluster/azure/manifests.gocmd/cluster/core/create.gocmd/cluster/core/create_test.gocmd/cluster/gcp/create.gocmd/cluster/gcp/create_test.gocmd/fix/dr_oidc_iam.gocmd/infra/aws/create.gocmd/infra/aws/create_cli_role.gocmd/infra/aws/create_iam.gocmd/infra/aws/delegatingclientgenerator/main.gocmd/infra/aws/ec2.gocmd/infra/aws/iam.gocmd/infra/aws/iam_test.gocmd/infra/aws/route53.gocmd/infra/aws/route53_test.gocmd/infra/azure/networking.gocmd/infra/azure/networking_test.gocontrol-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.gocontrol-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller_test.gocontrol-plane-operator/controllers/hostedcontrolplane/manifests/cno.gocontrol-plane-operator/controllers/hostedcontrolplane/v2/assets/openshift-oauth-apiserver/deployment.yamlcontrol-plane-operator/controllers/hostedcontrolplane/v2/cno/component.gocontrol-plane-operator/controllers/hostedcontrolplane/v2/cvo/deployment.gocontrol-plane-operator/controllers/hostedcontrolplane/v2/cvo/deployment_test.gocontrol-plane-operator/controllers/hostedcontrolplane/v2/kas/deployment.gocontrol-plane-operator/controllers/hostedcontrolplane/v2/kas/secretencryption.gocontrol-plane-operator/controllers/hostedcontrolplane/v2/oauth_apiserver/deployment.gocontrol-plane-operator/controllers/hostedcontrolplane/v2/router/component.gocontrol-plane-operator/controllers/hostedcontrolplane/v2/router/component_test.gocontrol-plane-operator/hostedclusterconfigoperator/controllers/machine/machine.gocontrol-plane-operator/hostedclusterconfigoperator/controllers/machine/machine_test.gocontrol-plane-operator/hostedclusterconfigoperator/controllers/reencryption/reencryption.gocontrol-plane-operator/hostedclusterconfigoperator/controllers/reencryption/reencryption_test.gocontrol-plane-operator/hostedclusterconfigoperator/controllers/resources/ingress/params.gocontrol-plane-operator/hostedclusterconfigoperator/controllers/resources/ingress/params_test.gocontrol-plane-operator/hostedclusterconfigoperator/controllers/resources/resources.godocs/content/reference/infrastructure/aws.mdhack/tools/crd-schema-check/main.gohypershift-operator/controllers/hostedcluster/internal/platform/azure/azure.gohypershift-operator/controllers/hostedcluster/internal/platform/azure/azure_test.gohypershift-operator/controllers/nodepool/aws.gohypershift-operator/controllers/nodepool/aws_test.gohypershift-operator/controllers/nodepool/azure.gohypershift-operator/controllers/nodepool/azure_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/kubevirt.gohypershift-operator/controllers/nodepool/kubevirt/kubevirt.gohypershift-operator/controllers/nodepool/kubevirt/kubevirt_test.gohypershift-operator/controllers/nodepool/nodepool_controller.gohypershift-operator/controllers/nodepool/nodepool_controller_test.gohypershift-operator/controllers/nodepool/openstack.gohypershift-operator/controllers/nodepool/openstack/openstack.gohypershift-operator/controllers/nodepool/openstack/openstack_test.gohypershift-operator/controllers/nodepool/osstream.gohypershift-operator/controllers/nodepool/osstream_test.gohypershift-operator/controllers/nodepool/powervs.gohypershift-operator/controllers/nodepool/powervs_test.gohypershift-operator/controllers/nodepool/stream.gohypershift-operator/controllers/nodepool/stream_test.gohypershift-operator/controllers/nodepool/stream_test_helpers_test.gohypershift-operator/controllers/nodepool/token.gohypershift-operator/controllers/nodepool/token_test.gohypershift-operator/controllers/nodepool/version.gohypershift-operator/controllers/nodepool/version_test.gohypershift-operator/controllers/platform/gcp/privateserviceconnect_controller.gohypershift-operator/controllers/platform/gcp/privateserviceconnect_controller_test.goproduct-cli/main.goproduct-cli/main_test.gosupport/awsapi/elasticloadbalancingv2.gosupport/awsapi/route53.gosupport/awsutil/tags.gosupport/controlplane-component/defaults.gosupport/controlplane-component/defaults_test.gosupport/controlplane-component/status.gosupport/releaseinfo/releaseinfo.gosupport/releaseinfo/releaseinfo_test.gosupport/secretencryption/encryptionconfig.gosupport/secretencryption/encryptionconfig_test.gotest/e2e/external_oidc_test.gotest/e2e/karpenter_control_plane_upgrade_test.gotest/e2e/karpenter_test.gotest/e2e/nodepool_spot_termination_handler_test.gotest/e2e/util/aws.gotest/e2e/util/fixture.gotest/e2e/util/globalps.gotest/e2e/util/util_metrics_proxy.gotest/e2e/v2/cmd/create-guests/main.gotest/e2e/v2/tests/hosted_cluster_psc_test.go
💤 Files with no reviewable changes (2)
- control-plane-operator/controllers/hostedcontrolplane/v2/cno/component.go
- control-plane-operator/controllers/hostedcontrolplane/manifests/cno.go
🚧 Files skipped from review as they are similar to previous changes (1)
- control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go
There was a problem hiding this comment.
Caution
Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.
🛑 Comments failed to post (10)
cmd/infra/aws/create_iam.go (1)
173-178: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "== file exists and relevant lines ==" if [ -f cmd/infra/aws/create_iam.go ]; then nl -ba cmd/infra/aws/create_iam.go | sed -n '130,205p' else echo "missing cmd/infra/aws/create_iam.go" git ls-files | rg '(^|/)create_iam\.go$' || true fi echo echo "== search for additionalIAMTags and additional tags parsing ==" rg -n "additionalIAMTags|additional-tags|HyperShift|HypershiftInfraIDTagKey|infra-id|Tags:" cmd/infra/aws . -g '*.go' | head -n 200 echo echo "== AST outline if available ==" ast-grep outline cmd/infra/aws/create_iam.go --view compact || trueRepository: openshift/hypershift
Length of output: 235
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "== file exists and relevant lines ==" if [ -f cmd/infra/aws/create_iam.go ]; then sed -n '1,260p' cmd/infra/aws/create_iam.go else echo "missing cmd/infra/aws/create_iam.go" git ls-files | grep -E '(^|/)create_iam\.go$' || true fi echo echo "== search for additionalIAMTags, additional-tags, InfraID tag references ==" grep -RInE "additionalIAMTags|additional-tags|HypershiftInfraIDTagKey|Hyper.*(Infra|INFRA|infra).*Tag|infra-id|Tags:" --include='*.go' --include='*.sh' . | head -n 240 echo echo "== repository tooling/dependencies hints ==" ls -la | sed -n '1,80p'Repository: openshift/hypershift
Length of output: 40089
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "== remaining create_iam.go from parse method through IAM tag usage ==" sed -n '240,800p' cmd/infra/aws/create_iam.go echo echo "== cmd/util ParseAWSTags implementation/candidates ==" grep -RInE "func ParseAWSTags|ParseAWSTags|AdditionalTags|Tag:" --include='*.go' cmd util support | head -n 240 echo echo "== behavioral probe: deterministic ordering of parsed entries and duplicate append possibility ==" cat cmd/infra/aws/create_iam.go > /tmp/create_iam.go grep -n "ParseAWSTags\\|additionalIAMTags\\|HypershiftInfraIDTagKey\\|CreateKarpenterRoleARN\\|Create.*Role\\|Tag\\[|Tags" /tmp/create_iam.goRepository: openshift/hypershift
Length of output: 7437
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "== create_cli_role IAM tag helper ==" sed -n '220,280p' cmd/infra/aws/create_cli_role.go echo echo "== operator roles additional tag parsing and InfraID handling ==" sed -n '100,150p' cmd/infra/aws/create_operator_roles.go sed -n '300,345p' cmd/infra/aws/create_operator_roles.go grep -n "HypershiftInfraIDTagKey|additionalIAMTags|Tags:" cmd/infra/aws/create_operator_roles.go echo echo "== remaining create_iam.go IAM tag references ==" grep -n "additionalIAMTags|Tags\\s*:|TagSpecifications|PutRole|CreateRole|CreateKarpenterRole\\|CreateWorkerInstanceProfile" cmd/infra/aws/create_iam.go echo echo "== awsutil constants ==" grep -RInE "HypershiftInfraIDTagKey\\s*=|HypershiftSourceTagKey\\s*=" --include='*.go' support cmd/hypershift support | head -n 50 echo echo "== read AWS SDK Go v2 docs from repository vendored package if present ==" python3 - <<'PY' from pathlib import Path roots = [ Path('go.mod'), Path('cmd/util/client.go'), Path('cmd/infra/aws/create_cli_role.go'), Path('cmd/infra/aws/create_iam.go'), ] for p in roots: if p.exists(): print(f"exists: {p}") PYRepository: openshift/hypershift
Length of output: 4219
🌐 Web query:
AWS IAM CreateRole requires tags array duplicate tag keys behavior💡 Result:
When using the AWS IAM CreateRole API, providing duplicate tag keys in the Tags array will cause the request to fail [1]. Specifically, IAM enforces uniqueness for tag keys in a single request, and the presence of duplicate keys will typically result in an InvalidInput error [1]. It is important to note that IAM tag keys are case-insensitive [1][2]. Therefore, if you attempt to provide two tags that differ only by case (e.g., "Department" and "department"), the API will treat them as duplicates, and the request will be rejected [1][2]. To ensure successful creation of the role, verify that all tag keys provided in the request are unique, regardless of their casing [1]. If any tag in the request is invalid or violates these constraints, the entire request will fail, and no resource will be created [3][4][5].
Citations:
- 1: https://stackoverflow.com/questions/67871517/duplicate-tag-keys-found-in-iam-role-while-deploying-aws-cdk-package
- 2: https://docs.aws.amazon.com/IAM/latest/UserGuide/access_tags.html
- 3: https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateRole.html
- 4: https://docs.aws.amazon.com/cli/latest/reference/iam/create-role.html
- 5: https://docs.aws.amazon.com/botocore/latest/reference/services/iam/client/create_role.html
Avoid duplicate enforced IAM tag keys.
A
--additional-tags hypershift.openshift.io/infra-id=...entry is parsed intoadditionalIAMTagsfirst, then the enforced InfraID tag is appended again. IAM does not accept duplicate tag keys inCreateRole/TagRole; replace any already-present InfraID tag with the enforced value before appends instead of appending it unconditionally.🤖 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 `@cmd/infra/aws/create_iam.go` around lines 173 - 178, Update the InfraID handling in the IAM tag construction flow to find and replace any existing additionalIAMTags entry with key supportawsutil.HypershiftInfraIDTagKey using the enforced o.InfraID value. Only append a new tag when no matching key exists, preserving unique tag keys for CreateRole and TagRole.cmd/infra/aws/route53.go (1)
118-131: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Assert the Route53 tag set.
TestCreatePrivateZoneacceptsChangeTagsForResourcewithgomock.Any(), so wrong or missing HyperShift tags would pass. Match the expected tag keys and values.As per coding guidelines, “Unit test any code changes and additions.”
🤖 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 `@cmd/infra/aws/route53.go` around lines 118 - 131, The TestCreatePrivateZone mock expectation for ChangeTagsForResource must assert the complete Route53 tag set instead of accepting gomock.Any(). Match the expected HyperShift and additional EC2 tag keys and values, preserving the production tags assembled in r53Tags, and add or update unit-test coverage for this assertion.Source: Coding guidelines
cmd/infra/azure/networking.go (1)
315-321: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Stated retry budgets overstate the actual wait. With
Steps: 5,retry.OnErrormakes 5 attempts and therefore sleeps only 4 times, so the last term in each comment's sum never occurs.
cmd/infra/azure/networking.go#L315-L321: max wait is ~75s (5+10+20+40), not ~155s — update the comment or bumpStepsto 6 if 155s was intended.cmd/cluster/core/create.go#L814-L820: max wait is ~15s (1+2+4+8), not ~31s — same correction applies.📍 Affects 2 files
cmd/infra/azure/networking.go#L315-L321(this comment)cmd/cluster/core/create.go#L814-L820🤖 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 `@cmd/infra/azure/networking.go` around lines 315 - 321, The retry budget comments overstate the maximum wait because retry.OnError sleeps only between attempts. In cmd/infra/azure/networking.go lines 315-321, update the backoff comment to approximately 75 seconds; in cmd/cluster/core/create.go lines 814-820, update the corresponding comment to approximately 15 seconds. Keep the existing Steps values unchanged.control-plane-operator/controllers/hostedcontrolplane/v2/assets/openshift-oauth-apiserver/deployment.yaml (1)
129-145: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash # Compare with the KAS asset's wait-for-etcd init container and check whether the framework defaults init-container resources. fd -t f 'deployment.yaml' control-plane-operator/controllers/hostedcontrolplane/v2/assets --exec rg -l 'wait-for-etcd' {} \ | xargs -r rg -n -A20 'name: wait-for-etcd|- args:' rg -nP -C5 'InitContainers' support/controlplane-component/defaults.goRepository: openshift/hypershift
Length of output: 30965
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "== defaults.go relevant section ==" rg -C 12 'NeedDefaultInitContainerResourcesAnnotation|InitContainerResources|apply.*Resource|InitContainers|requestLimit' support/controlplane-component/defaults.go || true echo echo "== v2 deployment resource blocks ==" python3 - <<'PY' from pathlib import Path for path in [ Path('control-plane-operator/controllers/hostedcontrolplane/v2/assets/openshift-oauth-apiserver/deployment.yaml'), Path('control-plane-operator/controllers/hostedcontrolplane/v2/assets/kube-apiserver/deployment.yaml'), ]: print(f'\n--- {path} ---') text = path.read_text() lines = text.splitlines() in_first = False for idx,l in enumerate(lines, 1): if 'name:' in l and ('audit-logs:' in l or 'wait-for-etcd:' in l or 'openshift-oauth:' in l or 'kube-apiserver:' in l or 'konnectivity:' in l): start=max(1, idx-3); end=min(len(lines), idx+45) print(f'\ncontainer around line {idx}:') for no in range(start,end+1): if 'resources:' in lines[no-1]: print('--- resource block ---') print(f'{no}: {lines[no-1]}') PYRepository: openshift/hypershift
Length of output: 5799
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "== defaults.go key definitions and assignments ==" rg -n -C 12 'ResourceRequestOverrideAnnotationPrefix|NeedDefaultInitContainerResourcesAnnotation|NeedDefaultResourcesAnnotation|InitContainers\[' support/controlplane-component/defaults.go echo echo "== openshift-oauth-apiserver deployment relevant lines ==" sed -n '1,170p' control-plane-operator/controllers/hostedcontrolplane/v2/assets/openshift-oauth-apiserver/deployment.yaml echo echo "== kube-apiserver deployment relevant lines ==" sed -n '220,340p' control-plane-operator/controllers/hostedcontrolplane/v2/assets/kube-apiserver/deployment.yamlRepository: openshift/hypershift
Length of output: 11454
Add resource requests to
wait-for-etcd.
openshift-oauth-apiserveralready declares requests on its explicit containers, but this new init container has noresourcesblock. Resource requests affect the pod’s effective request calculation, so add a small matching request set, e.g.cpu: 5m/memory: 10Milikeaudit-logs.🤖 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 `@control-plane-operator/controllers/hostedcontrolplane/v2/assets/openshift-oauth-apiserver/deployment.yaml` around lines 129 - 145, Add a resources.requests block to the wait-for-etcd init container, using the matching small request values cpu: 5m and memory: 10Mi consistent with audit-logs. Do not alter its existing command, environment, image, or other settings.control-plane-operator/controllers/hostedcontrolplane/v2/router/component.go (1)
126-132: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Don't swallow the predicate error, and be wary of the synthetic
WorkloadContext.Two concerns here:
errfromendpointresolverv2.Predicateis discarded and treated as "not required". A transient failure then silently dropsmetrics-proxyfrom the expected route set, so the router can be admitted before its metrics-proxy route exists — the exact condition this gate is meant to prevent. Propagate the error up througharoExpectedHCPRouterRouteNames/ensureHCPRouterRoutesExistsorouterPredicatereturns it and the reconcile is retried.component.WorkloadContext{HCP: hcp}has a nilClientand nilContext. This works only as long asendpointresolverv2.Predicatetouches nothing butHCP; any future read ofClientbecomes a nil dereference here. Passing the realcpContextthrough would be safer.As per coding guidelines: "Always check errors — don't ignore them."
🛠️ Sketch of error propagation
-func metricsProxyRouteRequired(hcp *hyperv1.HostedControlPlane) bool { - enabled, err := endpointresolverv2.Predicate(component.WorkloadContext{HCP: hcp}) - if err != nil || !enabled { - return false - } - return netutil.LabelHCPRoutes(hcp) || netutil.IsPrivateHCP(hcp) -} +func metricsProxyRouteRequired(cpContext component.WorkloadContext) (bool, error) { + enabled, err := endpointresolverv2.Predicate(cpContext) + if err != nil { + return false, fmt.Errorf("failed to evaluate endpoint resolver predicate: %w", err) + } + if !enabled { + return false, nil + } + hcp := cpContext.HCP + return netutil.LabelHCPRoutes(hcp) || netutil.IsPrivateHCP(hcp), 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 `@control-plane-operator/controllers/hostedcontrolplane/v2/router/component.go` around lines 126 - 132, Update metricsProxyRouteRequired and the aroExpectedHCPRouterRouteNames/ensureHCPRouterRoutesExist call chain to return and propagate the endpointresolverv2.Predicate error, allowing routerPredicate to return it and trigger reconciliation rather than treating failure as not required. Pass the real cpContext into component.WorkloadContext instead of constructing one with nil Client and Context, while preserving the existing route requirement checks.Source: Coding guidelines
control-plane-operator/hostedclusterconfigoperator/controllers/reencryption/reencryption.go (1)
337-340: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Wrap the decode error with context.
Every other error return in this function is wrapped; the decode path returns the raw error, so callers lose the "which config failed to decode" context. As per coding guidelines, "Wrap errors with context when rethrowing."
🛠️ Proposed fix
currentConfig, err := secretencryption.DecodeEncryptionConfiguration(configBytes) if err != nil { - return secretencryption.TargetKeyAbsent, configHash, err + return secretencryption.TargetKeyAbsent, configHash, fmt.Errorf("failed to decode encryption config secret %s/%s: %w", secretKey.Namespace, secretKey.Name, err) }📝 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.currentConfig, err := secretencryption.DecodeEncryptionConfiguration(configBytes) if err != nil { return secretencryption.TargetKeyAbsent, configHash, fmt.Errorf("failed to decode encryption config secret %s/%s: %w", secretKey.Namespace, secretKey.Name, err) }🤖 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 `@control-plane-operator/hostedclusterconfigoperator/controllers/reencryption/reencryption.go` around lines 337 - 340, Update the decode error handling after secretencryption.DecodeEncryptionConfiguration in the reencryption function to wrap the returned error with context identifying the encryption configuration that failed to decode, while preserving the existing TargetKeyAbsent and configHash return values.Source: Coding guidelines
hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure_test.go (1)
713-723: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash # Confirm fake-client behavior: does removing the last finalizer on a deleting object delete it? fd -t f 'client.go' vendor/sigs.k8s.io/controller-runtime/pkg/client/fake --exec rg -n -C8 'deleteObject|Finalizers) == 0|DeletionTimestamp' {}Repository: openshift/hypershift
Length of output: 315
🏁 Script executed:
#!/bin/bash set -e printf 'Files matching azure_test.go:\n' fd -t f 'azure_test\.go$' . | sed -n '1,20p' printf '\nRelevant section:\n' f=$(fd -t f 'azure_test\.go$' . | grep 'controllers/hostedcluster/internal/platform/azure/azure_test.go' | head -n1) if [ -n "$f" ]; then sed -n '630,735p' "$f" | nl -ba -v630 fi printf '\nSearch fake client handling in vendored dependency/path metadata:\n' rg -n 'controller-runtime|sigs.k8s.io/controller-runtime' go.mod go.sum 2>/dev/null | sed -n '1,40p' || trueRepository: openshift/hypershift
Length of output: 641
🏁 Script executed:
#!/bin/bash set -e # Try deterministic behavioral evidence from source code: find relevant fake client implementation # without assuming vendor layout. printf 'Candidate controller-runtime fake client files:\n' find . -path '*/sigs.k8s.io/controller-runtime/pkg/client/fake/client.go' -o -path '*/client/fake/client.go' | sed -n '1,20p' for f in $(find . -path '*/sigs.k8s.io/controller-runtime/pkg/client/fake/client.go' -o -path '*/client/fake/client.go' 2>/dev/null | sed -n '1,5p'); do echo "--- $f" rg -n -C8 'Finalizers) == 0|DeletionTimestamp|deleteObject|Delete\(' "$f" | sed -n '1,160p' doneRepository: openshift/hypershift
Length of output: 517
🏁 Script executed:
#!/bin/bash set -e printf 'Relevant test section:\n' f='hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure_test.go' awk 'NR>=630 && NR<=735 { printf "%6d\t%s\n", NR, $0 }' "$f" printf '\nController-runtime fake client relevant implementation:\n' rg -n -C8 'Finalizers) == 0|DeletionTimestamp|delet|deleteObject|Delete\(' vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/client.go | sed -n '1,220p'Repository: openshift/hypershift
Length of output: 3927
🏁 Script executed:
#!/bin/bash set -e printf 'Test cases around AzureMachine list construction and expectedFinalizersRemoved cases:\n' f='hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure_test.go' awk 'NR>=540 && NR<=685 { printf "%6d\t%s\n", NR, $0 }' "$f" printf '\nController-runtime fake client Delete implementation:\n' sed -n '1,260p' vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/client.go | awk '/func \(.*Delete\(|Finalizers|deletion|deleteObject|Delete\(/ { p=1 } p { print } /func \(.*Update\(/ { if (p && NR>first) exit; p=0 } /^func \(.*Update\(/ { first=NR }' || true printf '\nAll Finalizers / DeletionTimestamp handling in fake client:\n' grep -n -E 'Finalizers|DeletionTimestamp|deleteObject|Delete\(' vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/client.go | sed -n '1,120p'Repository: openshift/hypershift
Length of output: 7131
🏁 Script executed:
#!/bin/bash set -e awk 'NR>=570 && NR<=665 { printf "%6d\t%s\n", NR, $0 }' vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/client.go printf '\n--- Update behavior around deletion timestamp finalizer block ---\n' awk 'NR>=870 && NR<=930 { printf "%6d\t%s\n", NR, $0 }' vendor/sigs.k8s.io/controller-runtime/pkg/client/fake/client.goRepository: openshift/hypershift
Length of output: 6364
Make the finalizer-removal assertion non-vacuous.
In the stale-deletion path, the fake client deletes the object once its finalizers are removed while it still has a
DeletionTimestamp, soListmay return no machines and thisforloop can pass without checkingmachine-1’s finalizer state. Assert onmachine-1directly: either the object is absent or it has empty finalizers.Suggested tightening
if tc.expectedFinalizersRemoved { - for _, machine := range azureMachineList.Items { - if !machine.DeletionTimestamp.IsZero() { - g.Expect(machine.Finalizers).to(BeEmpty(), "finalizers should be removed for machines with DeletionFailed condition") - } - } + machine := &capiazure.AzureMachine{} + err := fakeClient.Get(ctx, client.ObjectKey{Namespace: controlPlaneNamespace, Name: "machine-1"}, machine) + if err == nil { + g.Expect(machine.Finalizers).To(BeEmpty(), "finalizers should be removed for machines with DeletionFailed condition") + } else { + g.Expect(apierrors.IsNotFound(err)).To(BeTrue(), "machine should be gone once its last finalizer is removed") + } } else {📝 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.if tc.expectedFinalizersRemoved { machine := &capiazure.AzureMachine{} err := fakeClient.Get(ctx, client.ObjectKey{Namespace: controlPlaneNamespace, Name: "machine-1"}, machine) if err == nil { g.Expect(machine.Finalizers).To(BeEmpty(), "finalizers should be removed for machines with DeletionFailed condition") } else { g.Expect(apierrors.IsNotFound(err)).To(BeTrue(), "machine should be gone once its last finalizer is removed") } } else { for _, machine := range azureMachineList.Items { g.Expect(machine.Finalizers).To(Equal(tc.azureMachines[0].Finalizers), "finalizers should not be modified") } }🤖 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/hostedcluster/internal/platform/azure/azure_test.go` around lines 713 - 723, Update the expectedFinalizersRemoved branch in the Azure machine test to assert directly on machine-1 rather than relying on iterating azureMachineList.Items. Treat the expected outcome as either machine-1 being absent from the list or, if present, having empty finalizers; leave the non-removal assertion unchanged.hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure.go (1)
371-375: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash # Find callers of DeleteOrphanedMachines and check whether they guarantee a non-nil Azure platform spec. rg -nP -C6 '\bDeleteOrphanedMachines\s*\(' --type=goRepository: openshift/hypershift
Length of output: 158
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "== locate azure.go ==" fd -a 'azure\.go$' . | sed 's#^\./##' echo "== locate references ==" rg -n "DeleteOrphanedMachines|AzureAuthenticationConfig|Platform\.Azure|Spec\.Platform|Azure" --type=go -g '*.go' | head -n 200 echo "== target file outline ==" file="$(fd 'azure\.go$' . | grep 'platform/azure/azure.go' | head -n 1)" [ -n "$file" ] && ast-grep outline "$file" || true echo "== target lines ==" [ -n "$file" ] && sed -n '340,405p' "$file"Repository: openshift/hypershift
Length of output: 1785
🏁 Script executed:
#!/bin/bash set -euo pipefail file=$(fd 'azure\.go$' . | grep 'hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure.go' | head -n 1) echo "== target file: $file" echo "== target lines 340-405 ==" sed -n '340,405p' "$file" echo "== all exact references in checked-out tree ==" rg -n "DeleteOrphanedMachines|AzureAuthenticationConfig|Spec\.Platform\.Azure\.AzureAuthenticationConfig|Platform\.Azure" -g '*.go'Repository: openshift/hypershift
Length of output: 3215
🌐 Web query:
hypershift-operator controllers hostedcluster internal platform azure DeleteOrphanedMachines calls💡 Result:
The DeleteOrphanedMachines function within the HyperShift operator is a mechanism designed to perform emergency cleanup of machine resources (such as AWSMachine or AzureMachine objects) that become stuck or orphaned when the cluster's cloud identity provider or credentials are determined to be invalid [1][2][3]. When the HostedCluster controller identifies that the cloud provider credentials or identity configurations are invalid (based on status conditions like ValidAWSIdentityProvider or similar checks for Azure), it invokes DeleteOrphanedMachines to prevent these orphaned resources from blocking further reconciliation or deletion processes [1][3]. For the Azure platform, the DeleteOrphanedMachines function performs the following operations [3]: 1. Credential Validation: It first checks if the cluster credentials/managed identities are valid. If they are valid, it returns early and takes no action [3]. 2. Resource Listing: If credentials are invalid, it lists all capiav2 AzureMachine resources located within the HostedCluster's control plane namespace [3]. 3. Cleanup: For any machine found with a non-zero DeletionTimestamp (indicating it is already in a state of deletion but stuck), the function removes the finalizers associated with that resource to allow the Kubernetes garbage collector to finalize the deletion [3]. 4. Error Aggregation: It aggregates and returns any errors encountered during the update of these machine resources [3]. Similar logic exists for the AWS platform, where the function scans for AWSMachine objects and clears finalizers if the AWS identity provider is deemed invalid [1][2][4]. This process ensures that infrastructure resources that cannot be properly deleted via standard controller reconciliation—due to the inability to communicate with the cloud provider—are cleaned up from the control plane [1][3].
Citations:
- 1: https://github.com/openshift/hypershift/blob/v0.1.76/hypershift-operator/controllers/hostedcluster/internal/platform/aws/aws.go
- 2: 1b1fad6
- 3: #8296
- 4: 8a66371...f06c7a6
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "== git status/diff stat ==" git status --short git diff --stat echo "== tracked files matching azure.go ==" git ls-files | grep -E 'hypershift-operator/controllers/hostedcluster/internal/platform/.*/azure\.go|hypershift-operator/controllers/hostedcluster/.*/azure\.go' || true echo "== exact strings in tracked Go files ==" rg -n "DeleteOrphanedMachines|AzureAuthenticationConfig|Spec\.Platform\.Azure" --glob '*.go' . || true echo "== azure.go around relevant export/calls ==" rg -n "DeleteCredentials|Reconcile.*Azure|NewAzure|func .*\b[A-Z]" hypershift-operator/controllers/hostedcluster -g '*.go' || trueRepository: openshift/hypershift
Length of output: 50377
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "== azure.go azureutil nil guard around Azure spec ==" sed -n '190,235p' hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure.go echo "== hostedcluster controller relevant guard before DeleteOrphanedMachines ==" sed -n '3765,3810p' hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go echo "== azureutil IsSelfManagedAzureWithWorkloadIdentity implementation ==" sed -n '1,90p' support/azureutil/azureutil.goRepository: openshift/hypershift
Length of output: 6841
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "== platform GetPlatform implementation ==" rg -n "func GetPlatform|type OrphanDeleter|type.*Azure|func .*OrphanDeleter" hypershift-operator/controllers/hostedcluster --glob '*.go' -C 4 echo "== all IsSelfManagedAzureWithWorkloadIdentity callers within platform/azure ==" rg -n "func .*Azure|IsSelfManagedAzureWithWorkloadIdentity|AzureAuthenticationConfig\.ManagedIdentities|Platform\.Azure" hypershift-operator/controllers/hostedcluster/internal/platform/azure --glob '*.go' -C 3 echo "== exact implementation of IsSelfManagedAzureWithWorkloadIdentity in support/azureutil ==" rg -n "func IsSelfManagedAzureWithWorkloadIdentity" support/azureutil/azureutil.go -C 15Repository: openshift/hypershift
Length of output: 30041
Guard against a nil Azure platform spec before dereferencing it.
DeleteOrphanedMachinesis reached from the deletion path afterplatform.GetPlatformreturns the Azure implementation, but the nil check is not enforced there and the tests only populateAzure. If an Azure HostedCluster reaches cleanup without a platform spec,hc.Spec.Platform.Azure.AzureAuthenticationConfig.ManagedIdentitiespanics. Add the nil guard at the top and add a test case for a nil Azure spec.🛡️ Proposed guard
- // This orphaning behavior is intended for managed-identity cleanup flow. - if hc.Spec.Platform.Azure.AzureAuthenticationConfig.ManagedIdentities == nil { + // This orphaning behavior is intended for managed-identity cleanup flow. + if hc.Spec.Platform.Azure == nil || hc.Spec.Platform.Azure.AzureAuthenticationConfig.ManagedIdentities == nil { return 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.func (Azure) DeleteOrphanedMachines(ctx context.Context, c client.Client, hc *hyperv1.HostedCluster, controlPlaneNamespace string) error { // This orphaning behavior is intended for managed-identity cleanup flow. if hc.Spec.Platform.Azure == nil || hc.Spec.Platform.Azure.AzureAuthenticationConfig.ManagedIdentities == nil { return 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/hostedcluster/internal/platform/azure/azure.go` around lines 371 - 375, Update Azure.DeleteOrphanedMachines to return nil when hc.Spec.Platform.Azure is nil before accessing AzureAuthenticationConfig.ManagedIdentities, while preserving the existing managed-identities guard. Add a test covering cleanup with a nil Azure platform spec and verify it completes without error or panic.hypershift-operator/controllers/nodepool/version.go (1)
96-118: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash # Look for other places in the repo that parse RHCOS OSImage strings / known samples rg -nP --type=go -C3 'Red Hat Enterprise Linux CoreOS' | head -50Repository: openshift/hypershift
Length of output: 158
🏁 Script executed:
#!/bin/bash set -euo pipefail echo "== file excerpt ==" wc -l hypershift-operator/controllers/nodepool/version.go sed -n '1,180p' hypershift-operator/controllers/nodepool/version.go echo echo "== relevant usages/tests ==" rg -n -C3 'rhcosOSImageRe|rhcosStreamFromOSImage|OSImage|StreamRHEL|RHCOS|RHEL9|RHEL10' hypershift-operator -g '*.go' || trueRepository: openshift/hypershift
Length of output: 50376
🏁 Script executed:
#!/bin/bash set -euo pipefail python3 - <<'PY' import re rhcosOSImageRe = re.compile(r'Red Hat Enterprise Linux CoreOS (\d)\d{2}\.') samples = [ "Red Hat Enterprise Linux CoreOS 419.97.202505081234-0 (Plow)", "Red Hat Enterprise Linux CoreOS 510.97.202506011200-0 (Plow)", "Red Hat Enterprise Linux CoreOS 9.6.20250523-0", "Red Hat Enterprise Linux CoreOS 10.6.20250523-0", "Red Hat Enterprise Linux CoreOS 910.5.20250523-0", "Ubuntu 22.04 LTS", ] for s in samples: matches = rhcosOSImageRe.findall(s) print(f"{s!r}: {matches!r}") PYRepository: openshift/hypershift
Length of output: 486
🌐 Web query:
Red Hat Enterprise Linux CoreOS 9.6 NodeInfo OSImage💡 Result:
In Red Hat Enterprise Linux CoreOS (RHCOS), the.status.nodeInfo.osImage field is a standard Kubernetes Node API attribute that reports the operating system image information as defined in the node's /etc/os-release file [1][2]. For RHCOS nodes based on RHEL 9.6, the osImage string is typically represented in the format "Red Hat Enterprise Linux CoreOS 9.6.YYYYMMDD-0" [3][4]. Key characteristics regarding this field include: Identification: This field is the primary method for confirming the RHEL base version (e.g., 9.6, 9.8) and the specific RHCOS build/snapshot version currently running on a node [1]. Data Source: The string is derived from the /etc/os-release file, which is maintained and updated by the Machine Config Operator (MCO) during cluster updates [3][2]. Context in OpenShift: RHCOS versions are tightly coupled with OpenShift Container Platform (OCP) release versions [5]. For example, OCP 4.20 and 4.21 clusters have utilized RHEL 9.6-based RHCOS images [5]. Command to check: You can view this information for all nodes in a cluster using the following command: oc get node -o custom-columns=NAME:.metadata.name,OSIMAGE:.status.nodeInfo.osImage [6] The specific version string, such as 9.6.20260512-0, represents the RHEL minor release (9.6) followed by a timestamped build identifier [4]. As OpenShift clusters are updated, the MCO manages the transition of this image version across the cluster nodes [1][5].
Citations:
- 1: https://github.com/openshift-eng/ai-helpers/blob/main/plugins/ci/skills/prow-job-analysis/references/operating-system-changes.md
- 2: https://docs.redhat.com/en/documentation/openshift_container_platform/4.19/html-multi/node_apis/node-v1
- 3: https://github.com/openshift/os/blob/128a6b95d2ae0910073aae0dd6a309ab9b8f319d/manifest-ocp-rhel-9.6.yaml
- 4: openshift/installer#10580
- 5: https://access.redhat.com/articles/6907891
- 6: https://xphyr.net/post/updating_coreos_with_additional_packages/
Handle RHEL-based
NodeInfo.OSImageformats.The current regex only supports three-digit RHCOS versions like
419.x/510.x, so RHEL-based strings such asRed Hat Enterprise Linux CoreOS 9.6.20250523-0or10.6.20250523-0are ignored and stream inference may silently fail. Cover these two-component RHEL forms or otherwise define the supported OSImage formats.🤖 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/version.go` around lines 96 - 118, Update rhcosOSImageRe and rhcosStreamFromOSImage to recognize RHEL-based OSImage versions in both 9.x and 10.x forms, such as “CoreOS 9.6...” and “CoreOS 10.6...”, while preserving existing 4xx-to-RHEL9 and 5xx-to-RHEL10 mappings; return StreamRHEL9 or StreamRHEL10 for the corresponding formats and keep unrecognized versions returning an empty string.test/e2e/nodepool_spot_termination_handler_test.go (1)
150-155: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Restore the SQS authorization tag.
These provenance tags omit
red-hat=true; the NodePool SQS policy conditions access onaws:ResourceTag/red-hat, so the handler can be denied queue access.Proposed fix
sqsTags := e2eutil.E2ETagsFromEnvironment() +sqsTags["red-hat"] = "true" sqsTags[supportawsutil.HypershiftInfraIDTagKey] = s.hostedCluster.Spec.InfraIDBased on learnings,
red-hat=trueis intentionally SQS-specific and is required byNodePoolSQSActions.📝 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.sqsTags := e2eutil.E2ETagsFromEnvironment() sqsTags["red-hat"] = "true" sqsTags[supportawsutil.HypershiftInfraIDTagKey] = s.hostedCluster.Spec.InfraID sqsTags[supportawsutil.HypershiftClusterNameTagKey] = s.hostedCluster.Name createQueueResult, err := sqsClient.CreateQueue(s.ctx, &sqs.CreateQueueInput{ QueueName: aws.String(sqsQueueName), Tags: sqsTags,🤖 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 `@test/e2e/nodepool_spot_termination_handler_test.go` around lines 150 - 155, Add the SQS-specific red-hat=true authorization tag to sqsTags before the CreateQueue call in the node pool termination handler test, preserving the existing environment, infrastructure, and cluster tags so NodePoolSQSActions can authorize queue access.Source: Learnings
|
@vsolanki12: all tests passed! Full PR test history. Your PR dashboard. DetailsInstructions 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. |
What this PR does / why we need it:
Migrates 9 status patch call sites in the CPO to use
statuspatching.PatchStatus/PatchStatusCondition, adding retry-on-conflict and consistent optimistic locking.Part of the broader CNTRLPLANE-3532 migration. Depends on PR #8782 (merged).
Which issue(s) this PR fixes:
Fixes CNTRLPLANE-3532
Special notes for your reviewer:
originalHostedControlPlaneparameter was removed fromreconcileDeletionsince the migrated helpers handle re-fetching internally.Checklist:
Summary by CodeRabbit
EtcdDataEncryptionUpToDatetracks the correct desired encryption state.