Skip to content

CNTRLPLANE-3603: Migrate clients from CAPI v1beta1 to v1beta2#8717

Draft
clebs wants to merge 3 commits into
openshift:mainfrom
clebs:v1beta2-clients
Draft

CNTRLPLANE-3603: Migrate clients from CAPI v1beta1 to v1beta2#8717
clebs wants to merge 3 commits into
openshift:mainfrom
clebs:v1beta2-clients

Conversation

@clebs

@clebs clebs commented Jun 11, 2026

Copy link
Copy Markdown
Member

What this PR does / why we need it:

As a the next step after bumping CAPI to 1.11 in CNTRLPLANE-2207, we are updating all clients from v1beta1 to v1beta2.

Provider specific code can not be updated yet since all providers are still using v1beta1 in their types.

Which issue(s) this PR fixes:

Fixes CNTRLPLANE-3603

Special notes for your reviewer:

Checklist:

  • Subject and description added to both, commit and PR.
  • Relevant issues have been referenced.
  • This change includes docs.
  • This change includes unit tests.

Summary by CodeRabbit

  • New Features

    • Expose control-plane initialization status to surface provider initialization progress.
  • Refactor

    • Migrate Cluster API usage from v1beta1 to v1beta2 across controllers, operators, tests and manifests.
    • Update machine, health, condition, and timeout handling to v1beta2 shapes.
  • Behavior

    • Controllers now mark control-plane and infrastructure initialization during reconciliation.
    • Removed legacy API-version conversion webhook support.

@openshift-merge-bot

Copy link
Copy Markdown
Contributor

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

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

This repository is configured in: LGTM mode

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

openshift-ci-robot commented Jun 11, 2026

Copy link
Copy Markdown

@clebs: This pull request references CNTRLPLANE-3603 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "5.0.0" version, but no target version was set.

Details

In response to this:

What this PR does / why we need it:

As a the next step after bumping CAPI to 1.11 in CNTRLPLANE-2207, we are updating all clients from v1beta1 to v1beta2.

Provider specific code can not be updated yet since all providers are still using v1beta1 in their types.

Which issue(s) this PR fixes:

Fixes CNTRLPLANE-3603

Special notes for your reviewer:

Checklist:

  • Subject and description added to both, commit and PR.
  • Relevant issues have been referenced.
  • This change includes docs.
  • This change includes unit tests.

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 openshift-ci Bot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jun 11, 2026
@openshift-ci

openshift-ci Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

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

Use the following commands to manage reviews:

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

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR migrates code and tests from Cluster API v1beta1 to v1beta2 across APIs, controllers, platform integrations, schemes, manifests, and utilities. It adds HostedControlPlane.Status.Initialization and HostedControlPlaneInitializationStatus, sets Initialization.ControlPlaneInitialized in HostedControlPlane reconciliation, patches CAPI Cluster Status.Initialization.InfrastructureProvisioned, replaces several CAPI spec/status shapes (ContractVersionedObjectReference, pointer Spec.Paused, seconds-based timeout fields), removes CAPI conversion webhook plumbing, and updates golangci lint exclusions.

Sequence Diagram(s)

sequenceDiagram
  participant HostedControlPlane
  participant HostedControlPlaneController
  participant HostedClusterController
  participant ClusterAPI
  participant Tests
  HostedControlPlane->>HostedControlPlaneController: expose Status.Initialization.ControlPlaneInitialized
  HostedControlPlaneController->>HostedClusterController: reconciliation observes InfrastructureReady
  HostedClusterController->>ClusterAPI: patch status.initialization.infrastructureProvisioned=true
  ClusterAPI->>Tests: tests updated to use v1beta2 types and condition shapes
Loading

Possibly related PRs

  • openshift/hypershift#8594: Related changes touching CAPI webhook conversion wiring and MachineDeployment completion logic during v1beta2 migration.

Suggested reviewers

  • muraee
  • Nirshal
✨ 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

openshift-ci Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: clebs
Once this PR has been reviewed and has the lgtm label, please assign enxebre 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/api Indicates the PR includes changes for the API area/cli Indicates the PR includes changes for CLI area/control-plane-operator Indicates the PR includes changes for the control plane operator - in an OCP release area/hypershift-operator Indicates the PR includes changes for the hypershift operator and API - outside an OCP release area/karpenter-operator Indicates the PR includes changes related to the Karpenter operator area/platform/aws PR/issue for AWS (AWSPlatform) platform area/platform/azure PR/issue for Azure (AzurePlatform) platform area/platform/gcp PR/issue for GCP (GCPPlatform) platform area/platform/ibmcloud PR/issue for IBMCloud (IBMCloudPlatform) platform area/platform/kubevirt PR/issue for KubeVirt (KubevirtPlatform) platform area/platform/openstack PR/issue for OpenStack (OpenStackPlatform) platform area/platform/powervs PR/issue for PowerVS (PowerVSPlatform) platform area/testing Indicates the PR includes changes for e2e testing and removed do-not-merge/needs-area labels Jun 11, 2026
@codecov

codecov Bot commented Jun 11, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 83.67347% with 24 lines in your changes missing coverage. Please review.
✅ Project coverage is 41.65%. Comparing base (39f04eb) to head (319c4c7).

Files with missing lines Patch % Lines
...trollers/hostedcluster/hostedcluster_controller.go 64.70% 11 Missing and 1 partial ⚠️
hypershift-operator/controllers/nodepool/capi.go 88.50% 8 Missing and 2 partials ⚠️
...ers/hostedcluster/internal/platform/azure/azure.go 0.00% 1 Missing ⚠️
...hostedcluster/internal/platform/powervs/powervs.go 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8717      +/-   ##
==========================================
- Coverage   41.66%   41.65%   -0.01%     
==========================================
  Files         758      758              
  Lines       93929    93933       +4     
==========================================
- Hits        39135    39131       -4     
- Misses      52046    52052       +6     
- Partials     2748     2750       +2     
Files with missing lines Coverage Δ
cmd/cluster/core/dump.go 4.27% <ø> (ø)
...ostedcontrolplane/hostedcontrolplane_controller.go 45.79% <100.00%> (+0.08%) ⬆️
...ontrollers/hostedcontrolplane/v2/kas/kubeconfig.go 26.53% <ø> (ø)
...operator/hostedclusterconfigoperator/api/scheme.go 0.00% <ø> (ø)
...tor/controllers/inplaceupgrader/inplaceupgrader.go 68.71% <100.00%> (ø)
...onfigoperator/controllers/inplaceupgrader/setup.go 0.00% <ø> (ø)
...usterconfigoperator/controllers/machine/machine.go 67.00% <ø> (ø)
...clusterconfigoperator/controllers/machine/setup.go 0.00% <ø> (ø)
...stedclusterconfigoperator/controllers/node/node.go 38.70% <ø> (ø)
...tor/controllers/spotremediation/spotremediation.go 65.71% <ø> (ø)
... and 23 more
Flag Coverage Δ
cmd-support 34.95% <ø> (-0.01%) ⬇️
cpo-hostedcontrolplane 44.02% <100.00%> (+0.01%) ⬆️
cpo-other 43.45% <100.00%> (ø)
hypershift-operator 51.63% <82.97%> (-0.03%) ⬇️
other 31.56% <ø> (ø)

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
api/hypershift/v1beta1/hosted_controlplane.go (1)

440-440: ⚡ Quick win

Use consistent marker syntax for default value.

This file uses +kubebuilder:default= on lines 322, 331, and 338. For consistency, change +default=false to +kubebuilder:default=false.

📝 Suggested change
-	// +default=false
+	// +kubebuilder:default=false
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api/hypershift/v1beta1/hosted_controlplane.go` at line 440, Change the marker
annotation for the boolean default to use the same kubebuilder syntax as the
other fields: replace the comment line `+default=false` with
`+kubebuilder:default=false` on the corresponding boolean field in the
HostedControlPlane spec (the same block that contains the other
`+kubebuilder:default=` annotations around lines where the spec fields are
defined), ensuring consistency with the markers used on the other fields.
🤖 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 681-685: Don't set
hostedControlPlane.Status.Initialization.ControlPlaneInitialized
unconditionally; instead gate it on the availability checks already computed by
reconcileAvailabilityStatus. Replace the unconditional assignment of
hostedControlPlane.Status.Initialization.ControlPlaneInitialized = ptr.To(true)
with logic that sets it to true only when the reconciler determines
hyperv1.HostedControlPlaneAvailable is true (and specifically
KubeAPIServerAvailable is true / kubeconfig exists and LB health/component
checks passed); otherwise leave it false or nil. Locate the assignment and use
the results/conditions produced by reconcileAvailabilityStatus (or the same
booleans it computes) to decide the value.

In
`@control-plane-operator/hostedclusterconfigoperator/controllers/machine/machine_test.go`:
- Around line 467-468: The test case title "With Failing machine with internal
addresses and passthrow service should mark endpointslices as not ready/not
serving" does not match the setup which uses
pairOfDualStackMachines(capiv1.MachinePhaseRunning,
capiv1.MachinePhaseDeleting); either rename the test title to refer to a
"Deleting machine" to match the current setup, or change the second machine
phase to capiv1.MachinePhaseFailed so the scenario truly models a failing
machine; update the test case entry (the name string and/or the machines call)
accordingly, keeping the rest of the assertions intact.

In `@hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go`:
- Around line 3043-3044: The ClusterRole that includes Verbs:
[]string{"get","list","patch","watch"} is granting the capi-provider subject
cluster-wide patch (write) access to CRDs which contradicts the later code that
assumes a read-only binding for capi-provider; either remove "patch" from that
ClusterRole's Verbs so capi-provider only gets get/list/watch, or create a
separate ClusterRole (e.g., "capi-provider-crd-reader") with Verbs:
[]string{"get","list","watch"} and bind capi-provider to that instead, leaving
the original ClusterRole with "patch" bound only to trusted controller
subjects—update the RoleBinding/ClusterRoleBinding creation for the
capi-provider subject accordingly so the access model matches the assumptions in
the subsequent code paths (lines around where capi-provider is referenced).

In `@hypershift-operator/controllers/nodepool/capi.go`:
- Around line 249-253: The cleanupMachineTemplates function currently uses
api.Scheme.VersionsForGroupKind(...)[0] to build a single apiVersion and only
lists MachineTemplates for that version; change it to iterate over all versions
returned by api.Scheme.VersionsForGroupKind(schema.GroupKind{Group:
ref.APIGroup, Kind: ref.Kind}) and for each version construct
schema.GroupVersion{Group: ref.APIGroup, Version: ver.Version}.String(), then
list and delete MachineTemplates for each apiVersion (rather than only
versions[0]). Keep using the existing capiv1.ContractVersionedObjectReference
writers (no change needed to the reference type).

---

Nitpick comments:
In `@api/hypershift/v1beta1/hosted_controlplane.go`:
- Line 440: Change the marker annotation for the boolean default to use the same
kubebuilder syntax as the other fields: replace the comment line
`+default=false` with `+kubebuilder:default=false` on the corresponding boolean
field in the HostedControlPlane spec (the same block that contains the other
`+kubebuilder:default=` annotations around lines where the spec fields are
defined), ensuring consistency with the markers used on the other fields.
🪄 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: 5cdbc23e-aa7c-4f55-a404-d1a9a463f044

📥 Commits

Reviewing files that changed from the base of the PR and between 76b27ab and bcb4fda.

⛔ Files ignored due to path filters (1)
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hosted_controlplane.go is excluded by !vendor/**, !**/vendor/**
📒 Files selected for processing (63)
  • api/.golangci.yml
  • api/hypershift/v1beta1/hosted_controlplane.go
  • cmd/cluster/core/dump.go
  • control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/kas/kubeconfig.go
  • control-plane-operator/hostedclusterconfigoperator/api/scheme.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/globalps/globalps_test.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/inplaceupgrader/inplaceupgrader.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/inplaceupgrader/inplaceupgrader_test.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/inplaceupgrader/setup.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/machine/machine.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/machine/machine_test.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/machine/setup.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/node/node.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/node/node_test.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/spotremediation/spotremediation.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/spotremediation/spotremediation_test.go
  • hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go
  • hypershift-operator/controllers/hostedcluster/hostedcluster_controller_test.go
  • hypershift-operator/controllers/hostedcluster/hostedcluster_webhook.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/agent/agent.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/agent/agent_test.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/aws/aws.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/gcp/gcp.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/ibmcloud/ibmcloud.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/ibmcloud/ibmcloud_test.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/kubevirt/kubevirt.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/kubevirt/kubevirt_test.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/openstack/openstack.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/openstack/openstack_test.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/powervs/powervs.go
  • hypershift-operator/controllers/manifests/controlplaneoperator/manifests.go
  • hypershift-operator/controllers/nodepool/aws.go
  • hypershift-operator/controllers/nodepool/aws_test.go
  • hypershift-operator/controllers/nodepool/azure_test.go
  • hypershift-operator/controllers/nodepool/capi.go
  • hypershift-operator/controllers/nodepool/capi_test.go
  • hypershift-operator/controllers/nodepool/conditions.go
  • hypershift-operator/controllers/nodepool/conditions_test.go
  • hypershift-operator/controllers/nodepool/gcp.go
  • hypershift-operator/controllers/nodepool/metrics/metrics.go
  • hypershift-operator/controllers/nodepool/nodepool_controller.go
  • hypershift-operator/controllers/nodepool/nodepool_controller_test.go
  • hypershift-operator/controllers/nodepool/powervs.go
  • hypershift-operator/controllers/nodepool/scale_from_zero_test.go
  • hypershift-operator/controllers/nodepool/version.go
  • hypershift-operator/controllers/nodepool/version_test.go
  • karpenter-operator/controllers/karpenter/karpenter_controller.go
  • karpenter-operator/controllers/karpenter/karpenter_controller_test.go
  • support/api/capi_types.go
  • support/api/scheme.go
  • support/k8sutil/resources.go
  • support/upsert/upsert.go
  • test/e2e/autoscaling_test.go
  • test/e2e/nodepool_day2_tags_test.go
  • test/e2e/nodepool_kv_advanced_multinet_test.go
  • test/e2e/nodepool_osp_advanced_test.go
  • test/e2e/nodepool_rolling_upgrade_test.go
  • test/e2e/nodepool_spot_termination_handler_test.go
  • test/e2e/upgrade_hypershift_operator_test.go
  • test/e2e/util/util.go
  • test/e2e/v2/backuprestore/cleanup.go
💤 Files with no reviewable changes (2)
  • hypershift-operator/controllers/hostedcluster/hostedcluster_webhook.go
  • support/api/scheme.go

Comment on lines +681 to +685
// Set status.initialization.controlPlaneInitialized for CAPI 1.11 v1beta2 contract.
// CAPI reads this field from the ControlPlane provider object to determine if the
// control plane is initialized (ControlPlaneInitialized condition on the CAPI Cluster).
hostedControlPlane.Status.Initialization.ControlPlaneInitialized = ptr.To(true)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Locations writing/readings ControlPlaneInitialized =="
rg -n -C3 'ControlPlaneInitialized|Status\.Initialization|Status\.Initialized' --type go

echo
echo "== Reconcile flow around assignment in hostedcontrolplane controller =="
rg -n -C6 'Status\.Initialization\.ControlPlaneInitialized|Status\.Initialized\s*=' control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go

echo
echo "== CAPI/HostedCluster reconciliation references that depend on initialization contracts =="
rg -n -C4 'ControlPlaneInitialized|InfrastructureReady|initialized' hypershift-operator/controllers/hostedcluster --type go

Repository: openshift/hypershift

Length of output: 49187


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Other writes to hostedControlPlane.Status.Initialized in hostedcontrolplane_controller.go =="
rg -n 'Status\.Initialized\s*=' control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go

echo
echo "== Writes to hostedControlPlane.Status.Initialization.ControlPlaneInitialized =="
rg -n 'Initialization\.ControlPlaneInitialized\s*=' control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go

echo
echo "== Read access patterns of HCP.Status.Initialized in hypershift-operator HostedCluster controller =="
rg -n 'Status\.Initialized' hypershift-operator/controllers/hostedcluster --type go

echo
echo "== Read/contract references of status.initialized / ControlPlaneInitialized in repo =="
rg -n 'status\.initialized|ControlPlaneInitialized' --type go --type ts --type py --type yaml

echo
echo "== Inspect surrounding code for the assignment block (hostedcontrolplane_controller.go:650-710) =="
sed -n '630,710p' control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go | cat -n

Repository: openshift/hypershift

Length of output: 14059


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go"

echo "== Where reconcileAvailabilityAndReadyStatus is defined =="
rg -n 'func \(r \*.*\) reconcileAvailabilityAndReadyStatus\(' "$FILE"

echo
echo "== Body of reconcileAvailabilityAndReadyStatus (up to next func) =="
python3 - <<'PY'
import re, itertools
path="control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go"
start_pat=re.compile(r'func \(r \*.*\) reconcileAvailabilityAndReadyStatus\(')
with open(path,'r') as f:
    lines=f.readlines()
start=None
for i,l in enumerate(lines):
    if start_pat.search(l):
        start=i
        break
assert start is not None
# print next ~250 lines until next "func " at col 0
out=[]
for j in range(start, min(start+350, len(lines))):
    if j>start and lines[j].startswith("func "):
        break
    out.append(f"{j+1}:{lines[j].rstrip()}")
print("\n".join(out))
PY

echo
echo "== Any other writes to ControlPlaneInitialized in control-plane-operator =="
rg -n 'ControlPlaneInitialized\s*=\s*ptr\.To\((true|false)\)' --type go control-plane-operator

echo
echo "== What conditions are set around KubeAPIServerAvailable / InfrastructureReady etc. in this controller =="
rg -n 'KubeAPIServerAvailable|InfrastructureReady|ControlPlaneAvailable|ControlPlaneInitialized' --type go "$FILE"

Repository: openshift/hypershift

Length of output: 2946


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== CAPI contract wording for ControlPlaneInitialized (v1beta2) =="
sed -n '145,190p' vendor/sigs.k8s.io/cluster-api/api/core/v1beta2/cluster_types.go | cat -n
echo
sed -n '1360,1390p' vendor/sigs.k8s.io/cluster-api/api/core/v1beta2/cluster_types.go | cat -n

echo
echo "== Find reconcileAvailabilityStatus definition =="
rg -n 'func reconcileAvailabilityStatus\(' control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go control-plane-operator/controllers/hostedcontrolplane -S

echo
echo "== Print reconcileAvailabilityStatus implementation =="
python3 - <<'PY'
import subprocess, re, pathlib, sys
import os, json
root="control-plane-operator/controllers/hostedcontrolplane"
# find exact file with reconcileAvailabilityStatus
res=subprocess.check_output(["bash","-lc",f"rg -n 'func reconcileAvailabilityStatus\\(' {root} -S | head -n 1"]).decode().strip()
print("match:",res)
file=res.split(":")[0]
line=int(res.split(":")[1])
print("file:",file,"line:",line)
# print 200 lines starting at line-1
start=max(1,line-1)
cmd=f"sed -n '{start},{start+220}p' {file}"
print(subprocess.check_output(["bash","-lc",cmd]).decode())
PY

Repository: openshift/hypershift

Length of output: 15930


Gate CAPI controlPlaneInitialized on API-server readiness (avoid unconditional true)
hostedControlPlane.Status.Initialization.ControlPlaneInitialized = ptr.To(true) is set unconditionally, but the CAPI v1beta2 contract says controlPlaneInitialized should be “functional enough to accept requests” and is used to orchestrate provisioning that depends on a functional API server. This reconciler already computes hyperv1.HostedControlPlaneAvailable via reconcileAvailabilityStatus (which can be False when kubeconfig is missing, KubeAPIServerAvailable is False, load balancer healthz fails, or components aren’t available). Setting ControlPlaneInitialized to true even when those checks aren’t satisfied risks CAPI starting too early.

🤖 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/hostedcontrolplane_controller.go`
around lines 681 - 685, Don't set
hostedControlPlane.Status.Initialization.ControlPlaneInitialized
unconditionally; instead gate it on the availability checks already computed by
reconcileAvailabilityStatus. Replace the unconditional assignment of
hostedControlPlane.Status.Initialization.ControlPlaneInitialized = ptr.To(true)
with logic that sets it to true only when the reconciler determines
hyperv1.HostedControlPlaneAvailable is true (and specifically
KubeAPIServerAvailable is true / kubeconfig exists and LB health/component
checks passed); otherwise leave it false or nil. Locate the assignment and use
the results/conditions produced by reconcileAvailabilityStatus (or the same
booleans it computes) to decide the value.

Comment on lines +3043 to 3044
Verbs: []string{"get", "list", "patch", "watch"},
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't keep capi-provider on the patched CRD role.

Adding patch here means the shared binding now gives capi-provider cluster-wide write access to CRDs, while Lines 3063-3065 still assume the role is read-only. Split the provider onto its own get/list/watch role or stop binding it to this ClusterRole.

Also applies to: 3063-3070

🤖 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 3043 - 3044, The ClusterRole that includes Verbs:
[]string{"get","list","patch","watch"} is granting the capi-provider subject
cluster-wide patch (write) access to CRDs which contradicts the later code that
assumes a read-only binding for capi-provider; either remove "patch" from that
ClusterRole's Verbs so capi-provider only gets get/list/watch, or create a
separate ClusterRole (e.g., "capi-provider-crd-reader") with Verbs:
[]string{"get","list","watch"} and bind capi-provider to that instead, leaving
the original ClusterRole with "patch" bound only to trusted controller
subjects—update the RoleBinding/ClusterRoleBinding creation for the
capi-provider subject accordingly so the access model matches the assumptions in
the subsequent code paths (lines around where capi-provider is referenced).

Comment on lines +249 to +253
versions := api.Scheme.VersionsForGroupKind(schema.GroupKind{Group: ref.APIGroup, Kind: ref.Kind})
if len(versions) == 0 {
return fmt.Errorf("no versions registered for GroupKind %s/%s", ref.APIGroup, ref.Kind)
}
apiVersion := schema.GroupVersion{Group: ref.APIGroup, Version: versions[0].Version}.String()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the file under review
FILE="hypershift-operator/controllers/nodepool/capi.go"
test -f "$FILE" || { echo "Missing $FILE"; exit 1; }

echo "== Snippet around lines 230-290 =="
nl -ba "$FILE" | sed -n '230,290p'

echo "== Snippet around lines 430-480 =="
nl -ba "$FILE" | sed -n '430,480p'

echo "== Snippet around lines 920-990 =="
nl -ba "$FILE" | sed -n '920,990p'

echo "== Finding ContractVersionedObjectReference usages in this file =="
rg -n "ContractVersionedObjectReference" "$FILE" || true

echo "== Locate struct definition in module cache / repo =="
# Try to locate in repo/vendor first
if fd -t f "types.go" . >/dev/null 2>&1; then
  :
fi

# Search in repository for the type definition
rg -n "type +ContractVersionedObjectReference" -S . || true

# If not found, search in Go module cache paths (best-effort; sandbox may limit)
go env GOMODCACHE >/dev/null 2>&1 || true
GOMODCACHE="$(go env GOMODCACHE 2>/dev/null || true)"
if [ -n "${GOMODCACHE:-}" ] && [ -d "$GOMODCACHE" ]; then
  echo "== Searching in GOMODCACHE for ContractVersionedObjectReference =="
  rg -n "type +ContractVersionedObjectReference" "$GOMODCACHE" -S --hidden --no-ignore 2>/dev/null | head -n 20 || true
fi

echo "== Search for VersionsForGroupKind usage =="
rg -n "VersionsForGroupKind" "$FILE" || true

Repository: openshift/hypershift

Length of output: 160


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="hypershift-operator/controllers/nodepool/capi.go"
test -f "$FILE" || { echo "Missing $FILE"; exit 1; }

echo "== Snippet around lines 240-275 =="
sed -n '240,275p' "$FILE"

echo "== Snippet around lines 435-465 =="
sed -n '435,465p' "$FILE"

echo "== Snippet around lines 935-970 =="
sed -n '935,970p' "$FILE"

echo "== Finding ContractVersionedObjectReference usages in this file =="
rg -n "ContractVersionedObjectReference" "$FILE" || true

echo "== Finding VersionsForGroupKind usage in this file =="
rg -n "VersionsForGroupKind" "$FILE" || true

echo "== Attempt to locate ContractVersionedObjectReference type in repo (module/vendor) =="
# Prefer repo search
rg -n "type +ContractVersionedObjectReference" . || true

# If nothing, attempt in module cache
if command -v go >/dev/null 2>&1; then
  GOMODCACHE="$(go env GOMODCACHE 2>/dev/null || true)"
  if [ -n "${GOMODCACHE:-}" ] && [ -d "$GOMODCACHE" ]; then
    rg -n "type +ContractVersionedObjectReference" "$GOMODCACHE" -S --hidden --no-ignore 2>/dev/null | head -n 20 || true
  fi
fi

Repository: openshift/hypershift

Length of output: 4835


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="vendor/sigs.k8s.io/cluster-api/api/core/v1beta2/common_types.go"
test -f "$FILE" || { echo "Missing $FILE"; exit 1; }

# Print around the struct definition
sed -n '330,430p' "$FILE"

# Also search within the vendor file for the struct fields
rg -n "type +ContractVersionedObjectReference +struct" -n "$FILE"

Repository: openshift/hypershift

Length of output: 3141


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE="hypershift-operator/controllers/nodepool/capi.go"
test -f "$FILE" || { echo "Missing $FILE"; exit 1; }

rg -n "func \\(c \\*.*\\) cleanupMachineTemplates" "$FILE" || true
rg -n "cleanupMachineTemplates" "$FILE" || true

# Print the whole function (or as much as reasonable)
# Find start line number
START="$(rg -n "cleanupMachineTemplates" "$FILE" | head -n1 | cut -d: -f1 || true)"
if [ -n "${START:-}" ]; then
  # print 120 lines from start
  END=$((START+140))
  sed -n "${START},${END}p" "$FILE"
fi

# Show the comment near line 248
sed -n '235,265p' "$FILE"

# Search for SetAPIVersion usage in this file
rg -n "SetAPIVersion\\(" "$FILE" || true

Repository: openshift/hypershift

Length of output: 6767


Fix MachineTemplate cleanup to delete across all template API versions (avoid VersionsForGroupKind(...)[0])

cleanupMachineTemplates reconstructs a single apiVersion from api.Scheme.VersionsForGroupKind(...)[0] and lists MachineTemplates for only that APIVersion, so any MachineTemplates stored under other versions for the same GroupKind won’t be discovered/deleted. Update it to list/delete for all versions returned by VersionsForGroupKind (instead of index 0).
The writer sites creating capiv1.ContractVersionedObjectReference don’t need to change: in vendored cluster-api v1beta2 (vendor/sigs.k8s.io/cluster-api/api/core/v1beta2/common_types.go), the type has only Kind, Name, and APIGroup (no Version field), so the version can’t be persisted there.

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

In `@hypershift-operator/controllers/nodepool/capi.go` around lines 249 - 253, The
cleanupMachineTemplates function currently uses
api.Scheme.VersionsForGroupKind(...)[0] to build a single apiVersion and only
lists MachineTemplates for that version; change it to iterate over all versions
returned by api.Scheme.VersionsForGroupKind(schema.GroupKind{Group:
ref.APIGroup, Kind: ref.Kind}) and for each version construct
schema.GroupVersion{Group: ref.APIGroup, Version: ver.Version}.String(), then
list and delete MachineTemplates for each apiVersion (rather than only
versions[0]). Keep using the existing capiv1.ContractVersionedObjectReference
writers (no change needed to the reference type).

@clebs clebs mentioned this pull request Jun 11, 2026
4 tasks
@clebs clebs force-pushed the v1beta2-clients branch from c595b6b to 17b8504 Compare June 11, 2026 14:20
@openshift-ci openshift-ci Bot added the area/documentation Indicates the PR includes changes for documentation label Jun 11, 2026
@github-actions github-actions Bot temporarily deployed to docs-preview/pr-8717 June 11, 2026 14:26 Inactive
@openshift-ci openshift-ci Bot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jun 11, 2026
@clebs clebs force-pushed the v1beta2-clients branch from 17b8504 to 80d79fb Compare June 11, 2026 17:31
@openshift-ci openshift-ci Bot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jun 11, 2026
@github-actions github-actions Bot temporarily deployed to docs-preview/pr-8717 June 11, 2026 17:38 Inactive

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

Inline comments:
In `@hypershift-operator/controllers/nodepool/capi.go`:
- Around line 672-679: The durationToSeconds helper currently casts d.Seconds()
directly to int32 which can overflow or accept negative values; change
durationToSeconds to validate and clamp the seconds: if d is nil return nil;
compute secs := d.Seconds(); if secs < 0 set secs = 0; if secs >
float64(math.MaxInt32) set secs = float64(math.MaxInt32); then convert to int32
and return its pointer. Replace any other direct casts of d.Seconds() to int32
(the conversions referenced at lines 745-746) to use durationToSeconds (or apply
the same clamp logic) so all user-sourced durations are bounds-checked and
non-negative before assigning to *int32 fields.
🪄 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: 997bcf03-5270-4813-8542-4baba563e281

📥 Commits

Reviewing files that changed from the base of the PR and between 17b8504 and 80d79fb.

⛔ Files ignored due to path filters (48)
  • api/hypershift/v1beta1/zz_generated.deepcopy.go is excluded by !**/zz_generated*.go, !**/zz_generated*
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/AAA_ungated.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterUpdateAcceptRisks.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ClusterVersionOperatorConfiguration.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDC.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUIDAndExtraClaimMappings.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ExternalOIDCWithUpstreamParity.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/GCPPlatform.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HCPEtcdBackup.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/HyperShiftOnlyDynamicResourceAllocation.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/ImageStreamImportMode.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/KMSEncryptionProvider.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/OpenStack.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • api/hypershift/v1beta1/zz_generated.featuregated-crd-manifests/hostedcontrolplanes.hypershift.openshift.io/TLSAdherence.yaml is excluded by !**/zz_generated.featuregated-crd-manifests/**
  • client/applyconfiguration/hypershift/v1beta1/hostedcontrolplaneinitializationstatus.go is excluded by !client/**
  • client/applyconfiguration/hypershift/v1beta1/hostedcontrolplanestatus.go is excluded by !client/**
  • client/applyconfiguration/utils.go is excluded by !client/**
  • cmd/install/assets/crds/cluster-api/addons.cluster.x-k8s.io_clusterresourcesetbindings.yaml is excluded by !cmd/install/assets/**/*.yaml
  • cmd/install/assets/crds/cluster-api/addons.cluster.x-k8s.io_clusterresourcesets.yaml is excluded by !cmd/install/assets/**/*.yaml
  • cmd/install/assets/crds/cluster-api/ipam.cluster.x-k8s.io_ipaddressclaims.yaml is excluded by !cmd/install/assets/**/*.yaml
  • cmd/install/assets/crds/cluster-api/ipam.cluster.x-k8s.io_ipaddresses.yaml is excluded by !cmd/install/assets/**/*.yaml
  • cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-CustomNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/**, !cmd/install/assets/**/*.yaml
  • cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-Default.crd.yaml is excluded by !**/zz_generated.crd-manifests/**, !cmd/install/assets/**/*.yaml
  • cmd/install/assets/crds/hypershift-operator/zz_generated.crd-manifests/hostedcontrolplanes-Hypershift-TechPreviewNoUpgrade.crd.yaml is excluded by !**/zz_generated.crd-manifests/**, !cmd/install/assets/**/*.yaml
  • docs/content/reference/aggregated-docs.md is excluded by !docs/content/reference/aggregated-docs.md
  • docs/content/reference/api.md is excluded by !docs/content/reference/api.md
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/hosted_controlplane.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/hypershift/v1beta1/zz_generated.deepcopy.go is excluded by !vendor/**, !**/vendor/**, !**/zz_generated*.go, !**/zz_generated*
  • vendor/modules.txt is excluded by !vendor/**, !**/vendor/**
  • vendor/sigs.k8s.io/cluster-api/api/addons/v1beta1/.import-restrictions is excluded by !vendor/**, !**/vendor/**
  • vendor/sigs.k8s.io/cluster-api/api/addons/v1beta1/clusterresourceset_types.go is excluded by !vendor/**, !**/vendor/**
  • vendor/sigs.k8s.io/cluster-api/api/addons/v1beta1/clusterresourcesetbinding_types.go is excluded by !vendor/**, !**/vendor/**
  • vendor/sigs.k8s.io/cluster-api/api/addons/v1beta1/condition_consts.go is excluded by !vendor/**, !**/vendor/**
  • vendor/sigs.k8s.io/cluster-api/api/addons/v1beta1/conversion.go is excluded by !vendor/**, !**/vendor/**
  • vendor/sigs.k8s.io/cluster-api/api/addons/v1beta1/doc.go is excluded by !vendor/**, !**/vendor/**
  • vendor/sigs.k8s.io/cluster-api/api/addons/v1beta1/groupversion_info.go is excluded by !vendor/**, !**/vendor/**
  • vendor/sigs.k8s.io/cluster-api/api/addons/v1beta1/v1beta2_condition_consts.go is excluded by !vendor/**, !**/vendor/**
  • vendor/sigs.k8s.io/cluster-api/api/addons/v1beta1/zz_generated.conversion.go is excluded by !vendor/**, !**/vendor/**, !**/zz_generated*.go, !**/zz_generated*
  • vendor/sigs.k8s.io/cluster-api/api/addons/v1beta1/zz_generated.deepcopy.go is excluded by !vendor/**, !**/vendor/**, !**/zz_generated*.go, !**/zz_generated*
  • vendor/sigs.k8s.io/cluster-api/api/ipam/v1beta1/.import-restrictions is excluded by !vendor/**, !**/vendor/**
  • vendor/sigs.k8s.io/cluster-api/api/ipam/v1beta1/condition_consts.go is excluded by !vendor/**, !**/vendor/**
  • vendor/sigs.k8s.io/cluster-api/api/ipam/v1beta1/conversion.go is excluded by !vendor/**, !**/vendor/**
  • vendor/sigs.k8s.io/cluster-api/api/ipam/v1beta1/doc.go is excluded by !vendor/**, !**/vendor/**
  • vendor/sigs.k8s.io/cluster-api/api/ipam/v1beta1/groupversion_info.go is excluded by !vendor/**, !**/vendor/**
  • vendor/sigs.k8s.io/cluster-api/api/ipam/v1beta1/ipaddress_types.go is excluded by !vendor/**, !**/vendor/**
  • vendor/sigs.k8s.io/cluster-api/api/ipam/v1beta1/ipaddressclaim_types.go is excluded by !vendor/**, !**/vendor/**
  • vendor/sigs.k8s.io/cluster-api/api/ipam/v1beta1/zz_generated.conversion.go is excluded by !vendor/**, !**/vendor/**, !**/zz_generated*.go, !**/zz_generated*
  • vendor/sigs.k8s.io/cluster-api/api/ipam/v1beta1/zz_generated.deepcopy.go is excluded by !vendor/**, !**/vendor/**, !**/zz_generated*.go, !**/zz_generated*
📒 Files selected for processing (63)
  • api/.golangci.yml
  • api/hypershift/v1beta1/hosted_controlplane.go
  • cmd/cluster/core/dump.go
  • control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/kas/kubeconfig.go
  • control-plane-operator/hostedclusterconfigoperator/api/scheme.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/globalps/globalps_test.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/inplaceupgrader/inplaceupgrader.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/inplaceupgrader/inplaceupgrader_test.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/inplaceupgrader/setup.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/machine/machine.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/machine/machine_test.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/machine/setup.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/node/node.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/node/node_test.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/spotremediation/spotremediation.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/spotremediation/spotremediation_test.go
  • hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go
  • hypershift-operator/controllers/hostedcluster/hostedcluster_controller_test.go
  • hypershift-operator/controllers/hostedcluster/hostedcluster_webhook.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/agent/agent.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/agent/agent_test.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/aws/aws.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/gcp/gcp.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/ibmcloud/ibmcloud.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/ibmcloud/ibmcloud_test.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/kubevirt/kubevirt.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/kubevirt/kubevirt_test.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/openstack/openstack.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/openstack/openstack_test.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/powervs/powervs.go
  • hypershift-operator/controllers/manifests/controlplaneoperator/manifests.go
  • hypershift-operator/controllers/nodepool/aws.go
  • hypershift-operator/controllers/nodepool/aws_test.go
  • hypershift-operator/controllers/nodepool/azure_test.go
  • hypershift-operator/controllers/nodepool/capi.go
  • hypershift-operator/controllers/nodepool/capi_test.go
  • hypershift-operator/controllers/nodepool/conditions.go
  • hypershift-operator/controllers/nodepool/conditions_test.go
  • hypershift-operator/controllers/nodepool/gcp.go
  • hypershift-operator/controllers/nodepool/metrics/metrics.go
  • hypershift-operator/controllers/nodepool/nodepool_controller.go
  • hypershift-operator/controllers/nodepool/nodepool_controller_test.go
  • hypershift-operator/controllers/nodepool/powervs.go
  • hypershift-operator/controllers/nodepool/scale_from_zero_test.go
  • hypershift-operator/controllers/nodepool/version.go
  • hypershift-operator/controllers/nodepool/version_test.go
  • karpenter-operator/controllers/karpenter/karpenter_controller.go
  • karpenter-operator/controllers/karpenter/karpenter_controller_test.go
  • support/api/capi_types.go
  • support/api/scheme.go
  • support/k8sutil/resources.go
  • support/upsert/upsert.go
  • test/e2e/autoscaling_test.go
  • test/e2e/nodepool_day2_tags_test.go
  • test/e2e/nodepool_kv_advanced_multinet_test.go
  • test/e2e/nodepool_osp_advanced_test.go
  • test/e2e/nodepool_rolling_upgrade_test.go
  • test/e2e/nodepool_spot_termination_handler_test.go
  • test/e2e/upgrade_hypershift_operator_test.go
  • test/e2e/util/util.go
  • test/e2e/v2/backuprestore/cleanup.go
💤 Files with no reviewable changes (2)
  • hypershift-operator/controllers/hostedcluster/hostedcluster_webhook.go
  • support/api/scheme.go
✅ Files skipped from review due to trivial changes (4)
  • hypershift-operator/controllers/hostedcluster/internal/platform/kubevirt/kubevirt_test.go
  • hypershift-operator/controllers/nodepool/metrics/metrics.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/node/node.go
  • control-plane-operator/controllers/hostedcontrolplane/hostedcontrolplane_controller.go
🚧 Files skipped from review as they are similar to previous changes (49)
  • control-plane-operator/hostedclusterconfigoperator/controllers/inplaceupgrader/setup.go
  • hypershift-operator/controllers/nodepool/scale_from_zero_test.go
  • support/upsert/upsert.go
  • hypershift-operator/controllers/manifests/controlplaneoperator/manifests.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/machine/machine.go
  • test/e2e/nodepool_spot_termination_handler_test.go
  • control-plane-operator/hostedclusterconfigoperator/api/scheme.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/aws/aws.go
  • api/.golangci.yml
  • test/e2e/nodepool_rolling_upgrade_test.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/powervs/powervs.go
  • hypershift-operator/controllers/nodepool/conditions_test.go
  • test/e2e/nodepool_day2_tags_test.go
  • test/e2e/v2/backuprestore/cleanup.go
  • hypershift-operator/controllers/nodepool/azure_test.go
  • karpenter-operator/controllers/karpenter/karpenter_controller.go
  • test/e2e/util/util.go
  • hypershift-operator/controllers/nodepool/powervs.go
  • test/e2e/autoscaling_test.go
  • hypershift-operator/controllers/nodepool/aws.go
  • test/e2e/nodepool_kv_advanced_multinet_test.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/gcp/gcp.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/ibmcloud/ibmcloud.go
  • support/k8sutil/resources.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/agent/agent_test.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/spotremediation/spotremediation.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/inplaceupgrader/inplaceupgrader.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/azure/azure.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/machine/setup.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/openstack/openstack.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/kas/kubeconfig.go
  • support/api/capi_types.go
  • api/hypershift/v1beta1/hosted_controlplane.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/kubevirt/kubevirt.go
  • hypershift-operator/controllers/hostedcluster/internal/platform/openstack/openstack_test.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/globalps/globalps_test.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/machine/machine_test.go
  • cmd/cluster/core/dump.go
  • test/e2e/upgrade_hypershift_operator_test.go
  • hypershift-operator/controllers/nodepool/aws_test.go
  • test/e2e/nodepool_osp_advanced_test.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/inplaceupgrader/inplaceupgrader_test.go
  • hypershift-operator/controllers/hostedcluster/hostedcluster_controller_test.go
  • hypershift-operator/controllers/nodepool/nodepool_controller.go
  • hypershift-operator/controllers/nodepool/conditions.go
  • hypershift-operator/controllers/nodepool/version_test.go
  • hypershift-operator/controllers/hostedcluster/hostedcluster_controller.go
  • hypershift-operator/controllers/nodepool/nodepool_controller_test.go
  • hypershift-operator/controllers/nodepool/capi_test.go

Comment on lines +672 to +679
// durationToSeconds converts a *metav1.Duration to *int32 seconds.
// CAPI v1beta2 uses integer seconds for timeouts instead of metav1.Duration.
func durationToSeconds(d *metav1.Duration) *int32 {
if d == nil {
return nil
}
s := int32(d.Seconds())
return &s

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard duration→int32 conversions against overflow/invalid values.

Line 678 and Lines 745-746 narrow duration seconds to int32 without bounds checks. Annotation/CR-sourced durations can exceed int32 range (or be negative), which can wrap/produce invalid timeout seconds.

🛠️ Proposed fix
+const maxInt32Seconds = int64(1<<31 - 1)
+
 // durationToSeconds converts a *metav1.Duration to *int32 seconds.
 // CAPI v1beta2 uses integer seconds for timeouts instead of metav1.Duration.
 func durationToSeconds(d *metav1.Duration) *int32 {
 	if d == nil {
 		return nil
 	}
-	s := int32(d.Seconds())
+	seconds := d.Duration / time.Second
+	if seconds < 0 {
+		seconds = 0
+	}
+	if seconds > maxInt32Seconds {
+		seconds = maxInt32Seconds
+	}
+	s := int32(seconds)
 	return &s
 }
@@
-	timeoutSec := int32(timeOut.Seconds())
-	startupSec := int32(nodeStartupTimeout.Seconds())
+	timeoutSec := durationToSeconds(&metav1.Duration{Duration: timeOut})
+	startupSec := durationToSeconds(&metav1.Duration{Duration: nodeStartupTimeout})
 	mhc.Spec = capiv1.MachineHealthCheckSpec{
@@
-		Checks: capiv1.MachineHealthCheckChecks{
-			NodeStartupTimeoutSeconds: &startupSec,
+		Checks: capiv1.MachineHealthCheckChecks{
+			NodeStartupTimeoutSeconds: startupSec,
 			UnhealthyNodeConditions: []capiv1.UnhealthyNodeCondition{
 				{
 					Type:           corev1.NodeReady,
 					Status:         corev1.ConditionFalse,
-					TimeoutSeconds: &timeoutSec,
+					TimeoutSeconds: timeoutSec,
 				},
 				{
 					Type:           corev1.NodeReady,
 					Status:         corev1.ConditionUnknown,
-					TimeoutSeconds: &timeoutSec,
+					TimeoutSeconds: timeoutSec,
 				},
 			},
 		},

As per coding guidelines, “Integer overflow: bounds-check user-supplied sizes” applies here because these timeout values are derived from user-configurable inputs.

Also applies to: 745-746

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

In `@hypershift-operator/controllers/nodepool/capi.go` around lines 672 - 679, The
durationToSeconds helper currently casts d.Seconds() directly to int32 which can
overflow or accept negative values; change durationToSeconds to validate and
clamp the seconds: if d is nil return nil; compute secs := d.Seconds(); if secs
< 0 set secs = 0; if secs > float64(math.MaxInt32) set secs =
float64(math.MaxInt32); then convert to int32 and return its pointer. Replace
any other direct casts of d.Seconds() to int32 (the conversions referenced at
lines 745-746) to use durationToSeconds (or apply the same clamp logic) so all
user-sourced durations are bounds-checked and non-negative before assigning to
*int32 fields.

Source: Coding guidelines

@clebs clebs force-pushed the v1beta2-clients branch from 80d79fb to 8ba6175 Compare June 11, 2026 17:43
@github-actions github-actions Bot temporarily deployed to docs-preview/pr-8717 June 11, 2026 17:48 Inactive
@clebs clebs force-pushed the v1beta2-clients branch from 8ba6175 to 9e5ad59 Compare June 11, 2026 18:57
@github-actions github-actions Bot temporarily deployed to docs-preview/pr-8717 June 11, 2026 19:04 Inactive
@clebs

clebs commented Jun 11, 2026

Copy link
Copy Markdown
Member Author

/test e2e-aws

@cwbotbot

cwbotbot commented Jun 11, 2026

Copy link
Copy Markdown

Test Results

e2e-aws

@clebs

clebs commented Jun 12, 2026

Copy link
Copy Markdown
Member Author

/test e2e-aws

@openshift-ci

openshift-ci Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

@clebs: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-aws 9e5ad59 link true /test e2e-aws

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.

@hypershift-jira-solve-ci

hypershift-jira-solve-ci Bot commented Jun 12, 2026

Copy link
Copy Markdown

Test Failure Analysis Complete

Job Information

Test Failure Analysis

Error

could not resolve inputs: could not determine inputs for step [release:n2minor]: failed to resolve release n2minor: failed to request latest release: Get "https://amd64.ocp.releases.ci.openshift.org/api/v1/releasestream/4.21.0-0.ci/latest": GET https://amd64.ocp.releases.ci.openshift.org/api/v1/releasestream/4.21.0-0.ci/latest giving up after 5 attempt(s)

Summary

This is a CI infrastructure failure, not a test failure caused by PR #8717. The job never built any code or ran any tests. During the input resolution phase, ci-operator attempted to resolve the n2minor release from the 4.21.0-0.ci release stream by calling the OpenShift CI release controller at amd64.ocp.releases.ci.openshift.org. All 5 retry attempts failed because the release controller is returning HTTP 503 (Service Unavailable). The release controller endpoint is still down at the time of this analysis, confirming this is an ongoing infrastructure outage. The PR's changes (migrating CAPI clients from v1beta1 to v1beta2) are completely unrelated to CI release stream resolution.

Root Cause

The OpenShift CI release controller at amd64.ocp.releases.ci.openshift.org is experiencing a service outage, returning HTTP 503 for API requests to resolve release streams.

Failure chain:

  1. ci-operator starts and begins resolving inputs for the e2e-aws test target
  2. The test configuration requires a release named n2minor, which maps to the 4.21.0-0.ci release stream
  3. ci-operator calls GET https://amd64.ocp.releases.ci.openshift.org/api/v1/releasestream/4.21.0-0.ci/latest to resolve the latest release in that stream
  4. The release controller returns 503 (Service Unavailable) on every attempt
  5. After 5 retry attempts spanning ~15 seconds, ci-operator gives up and reports the job as failed with reason resolving_inputs:resolving_release

Key indicators this is infrastructure, not PR-related:

  • The job ran for only 15 seconds — no code was compiled, no images built, no tests executed
  • The failure occurs before any PR code is involved (during CI input resolution)
  • The release controller endpoint is currently still returning 503, confirming an ongoing outage
  • The n2minor release is a standard CI configuration used by all HyperShift e2e-aws jobs, not something introduced by this PR
Recommendations
  1. Retest the PR — Simply re-trigger the job with /retest or /test e2e-aws once the release controller is back online. No code changes are needed.
  2. Check CI infrastructure status — The release controller at amd64.ocp.releases.ci.openshift.org is currently returning 503. Monitor the #forum-ocp-crt or #announce-testplatform Slack channels for outage updates.
  3. Do not block PR review on this failure — This failure is entirely unrelated to the PR's CAPI v1beta1→v1beta2 migration changes. Code review can proceed independently.
Evidence
Evidence Detail
Failure type CI infrastructure outage (not a test/code failure)
Failed component OpenShift CI Release Controller (amd64.ocp.releases.ci.openshift.org)
HTTP status 503 Service Unavailable (confirmed still down at analysis time)
Affected release n2minor → release stream 4.21.0-0.ci
Retry attempts 5 attempts over ~15 seconds, all failed
Job duration 51 seconds total, 15 seconds of ci-operator execution
Code built None — failure occurred before any build or test step
ci-operator reason resolving_inputs:resolving_release
JUnit testcase initialize (failed) — the only testcase recorded
PR relation None — PR changes CAPI client versions, unrelated to CI release resolution

clebs added 3 commits June 12, 2026 11:13
  Bump Cluster API core imports from v1beta1 to v1beta2 across all
  consumers. Provider imports (Azure, GCP, OpenStack, AWS, IBM Cloud)
  remain on v1beta1 as their ControlPlaneEndpoint field still references
  core v1beta1.APIEndpoint — no provider has migrated this yet.

  Key type changes:
  - corev1.ObjectReference → capiv1.ContractVersionedObjectReference
  - Machine.Status.NodeRef: pointer → MachineNodeReference (use .IsDefined())
  - Cluster.Spec.Paused: bool → *bool
  - Version/FailureDomain: *string → string
  - Status replica fields: int32 → *int32 (access via ptr.Deref)
  - Strategy → Rollout.Strategy
  - NodeDrainTimeout → Deletion.NodeDrainTimeoutSeconds
  - MHC: UnhealthyConditions → Checks.UnhealthyNodeConditions,
    MaxUnhealthy → Remediation.TriggerIf.UnhealthyLessThanOrEqualTo
  - Conditions: capiv1.Condition → metav1.Condition
  - ReadyCondition → MachinesReadyCondition (on MachineDeployment/MachineSet)
  - machineConditionResult.Status: corev1.ConditionStatus → metav1.ConditionStatus
  - MachineDeploymentComplete: use UpToDateReplicas + ReadyReplicas
  - Constants renamed with V1Beta1 suffix (e.g. WaitingForNodeRefReason)

  Control plane changes:
  - Add HCP Status.Initialization.ControlPlaneInitialized
  - Add patchInfrastructureInitializationProvisioned for CAPI v1beta2 contract
  - Remove conversion webhook (no longer needed with single API version)
  - Remove v1beta1 scheme registration (core, addons, ipam)

Signed-off-by: Borja Clemente <bclement@redhat.com>
  - ContractVersionedObjectReference (APIGroup instead of APIVersion, no Namespace)
  - FailureDomain: *string nil → empty string
  - Version: *string → string
  - Status replica fields: int32 → *int32 via ptr.To
  - Conditions: []capiv1.Condition → []metav1.Condition
  - MHC: restructured Checks/Remediation fields
  - MachineDeploymentComplete rewritten for v1beta2 native fields
  - MachinePhaseFailed (deprecated) → MachinePhaseDeleting
  - machineConditionResult expectations: corev1 → metav1 ConditionStatus
  - Constants renamed with V1Beta1 suffix
  - Fix bare v1beta2 import and misleading alias in e2e tests

Signed-off-by: Borja Clemente <bclement@redhat.com>
Update vendored dependencies after updating clients.

Signed-off-by: Borja Clemente <bclement@redhat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/api Indicates the PR includes changes for the API area/cli Indicates the PR includes changes for CLI area/control-plane-operator Indicates the PR includes changes for the control plane operator - in an OCP release area/documentation Indicates the PR includes changes for documentation area/hypershift-operator Indicates the PR includes changes for the hypershift operator and API - outside an OCP release area/karpenter-operator Indicates the PR includes changes related to the Karpenter operator area/platform/aws PR/issue for AWS (AWSPlatform) platform area/platform/azure PR/issue for Azure (AzurePlatform) platform area/platform/gcp PR/issue for GCP (GCPPlatform) platform area/platform/ibmcloud PR/issue for IBMCloud (IBMCloudPlatform) platform area/platform/kubevirt PR/issue for KubeVirt (KubevirtPlatform) platform area/platform/openstack PR/issue for OpenStack (OpenStackPlatform) platform area/platform/powervs PR/issue for PowerVS (PowerVSPlatform) platform area/testing Indicates the PR includes changes for e2e testing do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. 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