Skip to content

OCPBUGS-85584: Fix stale api.openshift.com labels on HostedControlPlane#8507

Open
dustman9000 wants to merge 1 commit into
openshift:mainfrom
dustman9000:drow/fix-hcp-label-sync
Open

OCPBUGS-85584: Fix stale api.openshift.com labels on HostedControlPlane#8507
dustman9000 wants to merge 1 commit into
openshift:mainfrom
dustman9000:drow/fix-hcp-label-sync

Conversation

@dustman9000
Copy link
Copy Markdown
Member

@dustman9000 dustman9000 commented May 13, 2026

Summary

Fixes stale api.openshift.com/* labels on HostedControlPlane CRs that persist after being removed from the HostedCluster.

Problem

The label sync in reconcileHostedControlPlane (line 2426-2432) only copies labels from HC to HCP. It never removes HCP labels that were deleted from HC.

When OCM/CS removes api.openshift.com/limited-support from the HostedCluster (via ManifestWork when LS is cleared), the label stays on the HostedControlPlane forever.

Reproduction (stage, 2026-05-13)

Reproduced on stage cluster test-hcp-stable-420 (2q4jijtpbjlrtjavc29s8n54bnah70kl), MC hs-mc-13vnfh7o0:

  1. Cluster had 1 LS reason. Both HC and HCP had api.openshift.com/limited-support: "true". Correct.
  2. Removed LS reason via ocm delete. OCM confirmed 0 LS reasons.
  3. Checked HC: label cleared (CS removed via ManifestWork). Checked HCP: label still "true".
  4. After 60 seconds: HC still cleared, HCP still "true". Label removal never propagated.

Also confirmed on production clusters dai-test-hcp and clairp02ue1 (0 LS reasons in OCM, stale label on HCP).

Impact

Route Monitor Operator checks this label on the HCP to skip probe creation for LS clusters. Stale labels cause RMO to permanently skip synthetic monitoring probe creation for fully supported clusters. ~60% of clusters on some RHOBS cells have no synthetic probes due to this bug.

Fix

Before copying HC labels to HCP, remove any api.openshift.com/* labels from HCP that no longer exist on HC. Includes 4 unit tests covering label copy, stale removal, non-OCM label preservation, and nil HC labels.

Jira

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Enhanced OpenShift API label synchronization to properly remove stale labels that no longer exist on the source resource, while continuing to copy current labels.
  • Tests

    • Added test coverage validating label synchronization behavior, including new label addition, stale label removal, and preservation of non-API labels.

@openshift-merge-bot
Copy link
Copy Markdown
Contributor

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

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

This repository is configured in: LGTM mode

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label May 13, 2026
@openshift-ci-robot
Copy link
Copy Markdown

@dustman9000: This pull request references Jira Issue OCPBUGS-85584, which is invalid:

  • expected the bug to target the "5.0.0" version, but no target version was set

Comment /jira refresh to re-evaluate validity if changes to the Jira bug are made, or edit the title of this pull request to link to a different bug.

The bug has been updated to refer to the pull request using the external bug tracker.

Details

In response to this:

Summary

Fixes stale api.openshift.com/* labels on HostedControlPlane CRs that persist after being removed from the HostedCluster.

Problem

The label sync in reconcileHostedControlPlane (line 2426-2432) only copies labels from HC to HCP. It never removes HCP labels that were deleted from HC.

When OCM/CS removes api.openshift.com/limited-support from the HostedCluster (via ManifestWork when LS is cleared), the label stays on the HostedControlPlane forever. This causes downstream consumers like Route Monitor Operator to permanently skip synthetic probe creation for clusters that are fully supported.

Impact: ~60% of clusters on some RHOBS cells have no synthetic monitoring probes due to stale LS labels, causing "No data" in Grafana dashboards.

Evidence: Production cluster dai-test-hcp (0352d4a2) has api.openshift.com/limited-support: "true" on HCP but 0 LS reasons in OCM ("Fully supported"). Same on clairp02ue1 and multiple other clusters.

Fix

Before copying HC labels to HCP, remove any api.openshift.com/* labels from HCP that no longer exist on HC. This makes the sync bidirectional for this label prefix.

Jira

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.

@openshift-ci-robot openshift-ci-robot added the jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. label May 13, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 13, 2026

📝 Walkthrough

Walkthrough

The reconcileHostedControlPlane function in the hostedcluster controller was changed to fully synchronize api.openshift.com/* labels from a HostedCluster (HC) to its HostedControlPlane (HCP). The reconciler now first removes any api.openshift.com/* labels present on the HCP that are not present on the HC, then copies the current matching api.openshift.com/* labels from the HC onto the HCP. Non-api.openshift.com/* labels on the HCP are preserved.

Sequence Diagram(s)

sequenceDiagram
    participant Reconciler as Reconciler
    participant HC as HostedCluster
    participant HCP as HostedControlPlane
    participant API as Kubernetes API

    Reconciler->>API: Get HostedCluster (HC)
    API-->>Reconciler: HC (labels)
    Reconciler->>API: Get HostedControlPlane (HCP)
    API-->>Reconciler: HCP (labels)
    alt HCP has stale api.openshift.com/* labels
        Reconciler->>API: Patch HCP to delete stale api.openshift.com/* labels
        API-->>Reconciler: Update response
    end
    Reconciler->>API: Patch HCP to add/update api.openshift.com/* labels from HC
    API-->>Reconciler: Update response
Loading
🚥 Pre-merge checks | ✅ 10 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Test Structure And Quality ⚠️ Warning Line 365 uses HasPrefix(key, "api.openshift.com") without slash. This incorrectly matches "api.openshift.complex". Same bug exists in controller implementation lines 2432, 2438. Change line 365 to HasPrefix(key, "api.openshift.com/"). Apply same fix to controller implementation at lines 2432 and 2438.
✅ Passed checks (10 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically identifies the main change: fixing stale api.openshift.com labels on HostedControlPlane, matching the primary purpose of the PR changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Stable And Deterministic Test Names ✅ Passed TestReconcileHostedControlPlaneLabelSync uses static, descriptive test names with no dynamic values, timestamps, UUIDs, or variable elements.
Microshift Test Compatibility ✅ Passed The test added (TestReconcileHostedControlPlaneLabelSync) is a standard Go unit test, not a Ginkgo e2e test. The custom check applies only to Ginkgo e2e tests, so it is not applicable to this PR.
Single Node Openshift (Sno) Test Compatibility ✅ Passed Test added is a standard Go unit test, not a Ginkgo e2e test. Custom check applies only to Ginkgo e2e tests with multi-node assumptions.
Topology-Aware Scheduling Compatibility ✅ Passed PR modifies only label sync logic. No deployment manifests, pod specs, affinity, topology constraints, or scheduling constructs introduced.
Ote Binary Stdout Contract ✅ Passed No OTE stdout contract violations detected. Library packages with no process-level stdout writes. Label sync uses only data structure manipulation. Tests properly use testing framework methods.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed The test added (TestReconcileHostedControlPlaneLabelSync) is a standard Go unit test, not a Ginkgo e2e test. The custom check applies only to Ginkgo e2e tests, so it does not apply here.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 13, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: dustman9000
Once this PR has been reviewed and has the lgtm label, please assign cblecker for approval. For more information see the Code Review Process.

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

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci Bot added area/hypershift-operator Indicates the PR includes changes for the hypershift operator and API - outside an OCP release and removed do-not-merge/needs-area labels May 13, 2026
@openshift-ci openshift-ci Bot requested review from bryan-cox and muraee May 13, 2026 20:53
@dustman9000 dustman9000 force-pushed the drow/fix-hcp-label-sync branch from 2a35868 to f024b83 Compare May 13, 2026 20:55
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go (1)

2426-2442: ⚡ Quick win

Add/adjust unit tests for the new bidirectional label sync path.

Please add coverage for both stale-label removal and prefix scoping so regressions here are caught.

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 `@hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go`
around lines 2426 - 2442, Add unit tests that exercise the api.openshift.com
label sync logic using the hcluster and hcp objects (the code that iterates over
hcp.Labels and hcluster.Labels and uses strings.HasPrefix("api.openshift.com")).
Write tests that (1) verify stale-label removal: start with an
api.openshift.com/* label present on hcp but missing on hcluster and assert the
label is deleted after running the sync routine, and (2) verify prefix
scoping/correct copying: ensure labels that start with the exact
"api.openshift.com" prefix on hcluster are copied to hcp and that other labels
(similar but not matching the prefix) are not touched. Place these cases in the
hostedcluster controller tests (e.g., hostedcluster_controller_test.go) and
invoke the function or reconcile path that performs the hcp/hcluster label sync
so regressions are caught.
🤖 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/hostedcluster/hostedcluster_controller.go`:
- Around line 2432-2440: The label-prefix checks currently use
strings.HasPrefix(key, "api.openshift.com") which can match keys outside the
intended namespace; update both occurrences to use the exact managed prefix
"api.openshift.com/" so only labels under api.openshift.com/* are processed
(modify the two HasPrefix checks around the loops that reference hcluster.Labels
and hcp.Labels).

---

Nitpick comments:
In `@hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go`:
- Around line 2426-2442: Add unit tests that exercise the api.openshift.com
label sync logic using the hcluster and hcp objects (the code that iterates over
hcp.Labels and hcluster.Labels and uses strings.HasPrefix("api.openshift.com")).
Write tests that (1) verify stale-label removal: start with an
api.openshift.com/* label present on hcp but missing on hcluster and assert the
label is deleted after running the sync routine, and (2) verify prefix
scoping/correct copying: ensure labels that start with the exact
"api.openshift.com" prefix on hcluster are copied to hcp and that other labels
(similar but not matching the prefix) are not touched. Place these cases in the
hostedcluster controller tests (e.g., hostedcluster_controller_test.go) and
invoke the function or reconcile path that performs the hcp/hcluster label sync
so regressions are caught.
🪄 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: 06ee7aec-1edd-42a0-8e8b-ff1d514ac695

📥 Commits

Reviewing files that changed from the base of the PR and between 674d92a and 2a35868.

📒 Files selected for processing (1)
  • hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go

@codecov
Copy link
Copy Markdown

codecov Bot commented May 13, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 40.00%. Comparing base (674d92a) to head (f5a37aa).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #8507   +/-   ##
=======================================
  Coverage   40.00%   40.00%           
=======================================
  Files         751      751           
  Lines       92838    92843    +5     
=======================================
+ Hits        37137    37146    +9     
+ Misses      53014    53011    -3     
+ Partials     2687     2686    -1     
Files with missing lines Coverage Δ
...trollers/hostedcluster/hostedcluster_controller.go 43.82% <100.00%> (+0.17%) ⬆️
Flag Coverage Δ
cmd-support 34.09% <ø> (ø)
cpo-hostedcontrolplane 40.56% <ø> (ø)
cpo-other 40.14% <ø> (ø)
hypershift-operator 50.56% <100.00%> (+0.02%) ⬆️
other 31.54% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go (1)

2431-2440: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use the exact managed prefix api.openshift.com/ in both loops.

Line 2432 and Line 2439 currently match "api.openshift.com" (no trailing slash), which can include unintended labels outside api.openshift.com/*.

Proposed fix
+	apiOpenShiftComLabelPrefix := "api.openshift.com/"
 	for key := range hcp.Labels {
-		if strings.HasPrefix(key, "api.openshift.com") {
+		if strings.HasPrefix(key, apiOpenShiftComLabelPrefix) {
 			if _, exists := hcluster.Labels[key]; !exists {
 				delete(hcp.Labels, key)
 			}
 		}
 	}
 	for key, val := range hcluster.Labels {
-		if strings.HasPrefix(key, "api.openshift.com") {
+		if strings.HasPrefix(key, apiOpenShiftComLabelPrefix) {
 			hcp.Labels[key] = val
 		}
 	}
🤖 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/hostedcluster_controller.go`
around lines 2431 - 2440, The prefix match in both loops uses
"api.openshift.com" and should be the exact managed prefix "api.openshift.com/";
update the strings.HasPrefix checks in the loops that iterate hcp.Labels and
hcluster.Labels to use "api.openshift.com/" so only labels under that namespace
(api.openshift.com/*) are considered when deleting from hcp.Labels and when
copying into hcp.Labels.
🧹 Nitpick comments (2)
hypershift-operator/controllers/hostedcluster/hostedcluster_controller_test.go (2)

359-370: ⚡ Quick win

Tighten assertions to catch unexpected non-target label mutations.

The current checks won’t fail if reconcile adds extra non-api.openshift.com/* labels. Assert there are no unexpected labels at all to make this test regression-proof.

Suggested assertion tightening
 			for key, val := range test.expectedLabels {
 				if hcp.Labels[key] != val {
 					t.Errorf("expected label %s=%s, got %s", key, val, hcp.Labels[key])
 				}
 			}
 			for key := range hcp.Labels {
-				if strings.HasPrefix(key, "api.openshift.com") {
-					if _, expected := test.expectedLabels[key]; !expected {
-						t.Errorf("unexpected label %s=%s still on HCP", key, hcp.Labels[key])
-					}
-				}
+				if _, expected := test.expectedLabels[key]; !expected {
+					t.Errorf("unexpected label %s=%s on HCP", key, hcp.Labels[key])
+				}
 			}
🤖 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/hostedcluster_controller_test.go`
around lines 359 - 370, The test currently only verifies expected
api.openshift.com/* labels and that no unexpected api.openshift.com/* keys
remain, but it doesn't fail if reconcile added extra non-target labels; update
the assertions around hcp.Labels and test.expectedLabels so they assert exact
equality: verify the count matches (len(hcp.Labels) == len(test.expectedLabels))
and iterate over every key in hcp.Labels to ensure each key exists in
test.expectedLabels and has the expected value (using the existing hcp and
test.expectedLabels variables), failing the test on any missing, extra, or
mismatched label.

322-344: ⚡ Quick win

Use required “When … it should …” test case naming format.

Please rename the new table test case titles to follow the required deterministic When ... it should ... pattern for unit tests.

As per coding guidelines, Always use "When ... it should ..." format for describing test cases when creating unit tests.

🤖 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/hostedcluster_controller_test.go`
around lines 322 - 344, Rename the table-driven test case "name" values in the
test table inside hostedcluster_controller_test.go to follow the deterministic
"When ... it should ..." format; specifically update entries currently titled
"copies api.openshift.com labels from HC to HCP", "removes stale
api.openshift.com labels from HCP", "preserves non-api.openshift.com labels on
HCP", and "handles nil HC labels" to descriptive phrases like "When HC has
api.openshift.com labels it should copy them to HCP", "When HC labels change it
should remove stale api.openshift.com labels from HCP", "When HCP has
non-api.openshift.com labels it should preserve them", and "When HC labels are
nil it should result in no api.openshift.com labels on HCP" so the test names
(the name field) use the required "When ... it should ..." pattern in the test
table used by the test function that validates label sync behavior.
🤖 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.

Duplicate comments:
In `@hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go`:
- Around line 2431-2440: The prefix match in both loops uses "api.openshift.com"
and should be the exact managed prefix "api.openshift.com/"; update the
strings.HasPrefix checks in the loops that iterate hcp.Labels and
hcluster.Labels to use "api.openshift.com/" so only labels under that namespace
(api.openshift.com/*) are considered when deleting from hcp.Labels and when
copying into hcp.Labels.

---

Nitpick comments:
In
`@hypershift-operator/controllers/hostedcluster/hostedcluster_controller_test.go`:
- Around line 359-370: The test currently only verifies expected
api.openshift.com/* labels and that no unexpected api.openshift.com/* keys
remain, but it doesn't fail if reconcile added extra non-target labels; update
the assertions around hcp.Labels and test.expectedLabels so they assert exact
equality: verify the count matches (len(hcp.Labels) == len(test.expectedLabels))
and iterate over every key in hcp.Labels to ensure each key exists in
test.expectedLabels and has the expected value (using the existing hcp and
test.expectedLabels variables), failing the test on any missing, extra, or
mismatched label.
- Around line 322-344: Rename the table-driven test case "name" values in the
test table inside hostedcluster_controller_test.go to follow the deterministic
"When ... it should ..." format; specifically update entries currently titled
"copies api.openshift.com labels from HC to HCP", "removes stale
api.openshift.com labels from HCP", "preserves non-api.openshift.com labels on
HCP", and "handles nil HC labels" to descriptive phrases like "When HC has
api.openshift.com labels it should copy them to HCP", "When HC labels change it
should remove stale api.openshift.com labels from HCP", "When HCP has
non-api.openshift.com labels it should preserve them", and "When HC labels are
nil it should result in no api.openshift.com labels on HCP" so the test names
(the name field) use the required "When ... it should ..." pattern in the test
table used by the test function that validates label sync behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 205166cf-a1bc-42e3-a2d1-62a0e1b237cc

📥 Commits

Reviewing files that changed from the base of the PR and between 2a35868 and f024b83.

📒 Files selected for processing (2)
  • hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go
  • hypershift-operator/controllers/hostedcluster/hostedcluster_controller_test.go

OCPBUGS-85584

The label sync from HostedCluster to HostedControlPlane was additive-only.
When OCM removes a label from HC (e.g., clearing limited support), the label
was never removed from HCP. This caused downstream consumers like Route
Monitor Operator to permanently skip probe creation for fully supported clusters.

Fix: before copying HC labels to HCP, remove any api.openshift.com/* labels
from HCP that no longer exist on HC.
@dustman9000 dustman9000 force-pushed the drow/fix-hcp-label-sync branch from f024b83 to f5a37aa Compare May 13, 2026 22:02
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
hypershift-operator/controllers/hostedcluster/hostedcluster_controller_test.go (2)

322-344: ⚡ Quick win

Normalize subtest names to When ... it should ... format.

These new test titles are descriptive, but they don’t follow the required naming convention for unit tests.

As per coding guidelines, Always use "When ... it should ..." format for describing test cases when creating unit tests.

🤖 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/hostedcluster_controller_test.go`
around lines 322 - 344, Update the test case "name" strings in the table-driven
tests that exercise label sync (the entries with name values like "copies
api.openshift.com labels from HC to HCP", "removes stale api.openshift.com
labels from HCP", "preserves non-api.openshift.com labels on HCP", "handles nil
HC labels") to follow the required "When ... it should ..." format (e.g. "When
HC has api.openshift.com labels it should copy them to HCP"). Keep the test
logic and expectedLabels/hcLabels/hcpLabels unchanged; only change the
human-readable name fields used by t.Run so they conform to the convention.

359-370: ⚡ Quick win

Prefer gomega assertions for these label assertions.

Replacing manual t.Errorf checks with gomega matchers will align with repo test style and produce cleaner failures.

As per coding guidelines, Prefer gomega for unit test assertions in Go tests.

🤖 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/hostedcluster_controller_test.go`
around lines 359 - 370, Replace the manual t.Errorf label checks in the test
(the loops that inspect hcp.Labels and test.expectedLabels) with gomega
assertions: for each expected label use
g.Expect(hcp.Labels).To(HaveKeyWithValue(key, val)) (or
g.Expect(hcp.Labels).To(HaveKey(key)) plus value assertion) and for the
unexpected-label check use g.Expect(hcp.Labels).ToNot(HaveKey(key)) or
g.Expect(hcp.Labels).ToNot(HaveKeyWithValue(key, _)) as appropriate; ensure you
use the existing g := gomega.NewWithT(t) test harness at the top of the test so
failures produce gomega-style output and replace both t.Errorf occurrences
accordingly.
🤖 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/hostedcluster/hostedcluster_controller_test.go`:
- Line 365: The stale-label check currently uses strings.HasPrefix(key,
"api.openshift.com") which can match unintended keys; update the prefix to
include the slash so it only matches managed OCM label keys by using
strings.HasPrefix(key, "api.openshift.com/") where the check occurs (the
strings.HasPrefix call operating on the variable `key` in the hostedcluster
controller test).

---

Nitpick comments:
In
`@hypershift-operator/controllers/hostedcluster/hostedcluster_controller_test.go`:
- Around line 322-344: Update the test case "name" strings in the table-driven
tests that exercise label sync (the entries with name values like "copies
api.openshift.com labels from HC to HCP", "removes stale api.openshift.com
labels from HCP", "preserves non-api.openshift.com labels on HCP", "handles nil
HC labels") to follow the required "When ... it should ..." format (e.g. "When
HC has api.openshift.com labels it should copy them to HCP"). Keep the test
logic and expectedLabels/hcLabels/hcpLabels unchanged; only change the
human-readable name fields used by t.Run so they conform to the convention.
- Around line 359-370: Replace the manual t.Errorf label checks in the test (the
loops that inspect hcp.Labels and test.expectedLabels) with gomega assertions:
for each expected label use g.Expect(hcp.Labels).To(HaveKeyWithValue(key, val))
(or g.Expect(hcp.Labels).To(HaveKey(key)) plus value assertion) and for the
unexpected-label check use g.Expect(hcp.Labels).ToNot(HaveKey(key)) or
g.Expect(hcp.Labels).ToNot(HaveKeyWithValue(key, _)) as appropriate; ensure you
use the existing g := gomega.NewWithT(t) test harness at the top of the test so
failures produce gomega-style output and replace both t.Errorf occurrences
accordingly.
🪄 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: 12160745-be70-4ee3-b562-f84a6ce5df7f

📥 Commits

Reviewing files that changed from the base of the PR and between f024b83 and f5a37aa.

📒 Files selected for processing (2)
  • hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go
  • hypershift-operator/controllers/hostedcluster/hostedcluster_controller_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci Bot commented May 13, 2026

@dustman9000: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Copy link
Copy Markdown
Member

@cblecker cblecker left a comment

Choose a reason for hiding this comment

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

Fix looks correct — delete-then-copy is the right approach, and the nil map case is handled cleanly. A few minor style suggestions inline.

// on the HC, then copy current values. This ensures label removals (e.g.,
// when limited support is cleared) propagate to the HCP.
for key := range hcp.Labels {
if strings.HasPrefix(key, "api.openshift.com") {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: Since you're already touching both loops, would you mind pulling the prefix out into a const with a trailing slash? Something like:

const apiOpenShiftComLabelPrefix = "api.openshift.com/"

Without the trailing slash, this technically matches anything that starts with api.openshift.com — including a hypothetical api.openshift.company/foo. A shared const fixes that and avoids the duplicated string literal across both loops.

expectedLabels map[string]string
}{
{
name: "copies api.openshift.com labels from HC to HCP",
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: The project convention for test case names is Gherkin-style — "When... it should...". Would you mind renaming these? Something like:

  • "When HC has api.openshift.com labels, it should copy them to HCP"
  • "When HC removes an api.openshift.com label, it should remove the stale label from HCP"
  • "When HCP has non-api.openshift.com labels, it should preserve them"
  • "When HC labels are nil, it should remove all api.openshift.com labels from HCP"

}
err := reconcileHostedControlPlane(hcp, hc, false, false, func() (map[string]string, error) { return nil, nil })
if err != nil {
t.Fatal(err)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: The rest of this file uses gomega — would be nice to stay consistent here. Switching to g.Expect(err).ToNot(HaveOccurred()) and g.Expect(hcp.Labels).To(Equal(test.expectedLabels)) would also let you collapse the two verification loops below into a single assertion, which is simpler and catches unexpected mutations to any label — not just the api.openshift.com ones.

}
// All labels on the HostedCluster with this special prefix are copied
// Those are labels set by OCM
// Sync api.openshift.com/* labels from HostedCluster to HostedControlPlane.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

nit: Most of this comment describes what the code does, which the two loops already make clear. The useful parts are that OCM owns these labels and why delete-before-copy is needed. Maybe condense to:

// These labels are managed by OCM. Delete-then-copy ensures removals
// on the HostedCluster propagate; a copy-only loop leaves stale labels.

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

Labels

area/hypershift-operator Indicates the PR includes changes for the hypershift operator and API - outside an OCP release jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants