Skip to content

Conversation

@maxcao13
Copy link
Member

What this PR does / why we need it:

This commit introduces the OpenshiftNodePool CRD.

The CRD acts as the de-facto interface for cluster-users interacting with AutoNode NodePools. Similar to OpenshiftEC2NodeClass, the creation of a ONP will render a Karpenter NodePool, protected with a VAP. The ValidatingAdmissionPolicy in the guest cluster will be constantly reconciled to mitigate deletion race conditions.

This allows us as a cluster service provider to:

  • set enforcable/immutable fields and restrictions on NodePools
  • hide fields that cluster-users should not touch
  • add OpenShift-specific fields as a user interface

Which issue(s) this PR fixes:

Fixes AUTOSCALE-491

Special notes for your reviewer:

As of now, there is nothing that we need to override or hide. We are simply just reflecting the OpenshiftNodePool spec to the NodePool, and the NodePool status back to the ONP.

Checklist:

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

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

openshift-ci-robot commented Jan 15, 2026

@maxcao13: This pull request references AUTOSCALE-491 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 "4.22.0" version, but no target version was set.

Details

In response to this:

What this PR does / why we need it:

This commit introduces the OpenshiftNodePool CRD.

The CRD acts as the de-facto interface for cluster-users interacting with AutoNode NodePools. Similar to OpenshiftEC2NodeClass, the creation of a ONP will render a Karpenter NodePool, protected with a VAP. The ValidatingAdmissionPolicy in the guest cluster will be constantly reconciled to mitigate deletion race conditions.

This allows us as a cluster service provider to:

  • set enforcable/immutable fields and restrictions on NodePools
  • hide fields that cluster-users should not touch
  • add OpenShift-specific fields as a user interface

Which issue(s) this PR fixes:

Fixes AUTOSCALE-491

Special notes for your reviewer:

As of now, there is nothing that we need to override or hide. We are simply just reflecting the OpenshiftNodePool spec to the NodePool, and the NodePool status back to the ONP.

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.

@maxcao13
Copy link
Member Author

/test e2e-aws-autonode

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 15, 2026

Walkthrough

Adds an OpenshiftNodePool CRD and full client/informer/lister/applyconfiguration scaffolding, a NodePoolReconciler controller (with tests), CRD assets, and related wiring; exports a GlobalPS label constant and updates operatorpkg and Kubernetes-related module versions.

Changes

Cohort / File(s) Summary
API Types & Registration
api/karpenter/v1beta1/openshiftnodepool_types.go, api/karpenter/v1beta1/register.go, api/karpenter/v1beta1/karpenter_types.go
Adds OpenshiftNodePool, OpenshiftNodePoolSpec, OpenshiftNodePoolStatus, OpenshiftNodePoolList and registers them; updates OpenshiftEC2NodeClassSpec docstring.
Deepcopy Generation
api/karpenter/v1beta1/zz_generated.deepcopy.go
Adds deepcopy methods for new OpenshiftNodePool types and required imports.
ApplyConfiguration Builders
client/applyconfiguration/karpenter/v1beta1/openshiftnodepool*.go, client/applyconfiguration/utils.go
Generates OpenshiftNodePool apply-configuration types, fluent builders, getters, and maps new kinds in ForKind.
Clientset (typed) & Fakes
client/clientset/clientset/typed/karpenter/v1beta1/karpenter_client.go, .../openshiftnodepool.go, .../fake_*.go, .../generated_expansion.go
Adds OpenshiftNodePoolInterface, concrete client, fake client, and expansion types to support CRUD, apply, and status operations.
Informers & Listers
client/informers/externalversions/karpenter/v1beta1/openshiftnodepool.go, client/informers/externalversions/generic.go, client/informers/externalversions/karpenter/v1beta1/interface.go, client/listers/karpenter/v1beta1/openshiftnodepool.go, client/listers/karpenter/v1beta1/expansion_generated.go
Adds informer, lister, version accessor, and generic switch case for OpenshiftNodePool.
NodePool Controller & Tests
karpenter-operator/controllers/nodepool/nodepool_controller.go, karpenter-operator/controllers/nodepool/nodepool_controller_test.go
New NodePoolReconciler: CRD/VAP reconciliation, translate OpenshiftNodePool ↔ NodePool, status sync, finalizer handling; includes unit tests.
Karpenter Operator Wiring & Tests
karpenter-operator/main.go, karpenter-operator/controllers/karpenter/karpenter_controller.go, karpenter-operator/controllers/karpenter/assets/karpenter.hypershift.openshift.io_openshiftnodepools.yaml, karpenter-operator/controllers/karpenter/assets/karpenter.hypershift.openshift.io_openshiftec2nodeclasses.yaml, karpenter-operator/controllers/nodeclass/ec2_nodeclass_controller.go, karpenter-operator/controllers/karpenter/karpenter_controller_test.go
Adds OpenshiftNodePool CRD asset, updates EC2 nodeclass CRD doc, switches deletion/listing to OpenshiftNodePool types, uses dynamic CRD names, and wires the new reconciler; updates tests to use OpenshiftNodePool.
Control Plane Operator Global PS Label
control-plane-operator/hostedclusterconfigoperator/controllers/globalps/globalps.go, control-plane-operator/hostedclusterconfigoperator/controllers/globalps/globalps_test.go
Renames/unifies label key to exported GlobalPSLabelKey and updates references/tests.
Module Dependency Updates
api/go.mod, go.mod
Promotes github.com/awslabs/operatorpkg to direct dependency (v0.0.0-20250320000002-...), updates k8s-related indirect versions (k8s.io/cloud-provider, k8s.io/csi-translation-lib), and adjusts karpenter module entries.
Test Assets
test/e2e/assets/karpenter-nodepool.yaml
Converts e2e manifest from NodePool/karpenter.sh to OpenshiftNodePool/karpenter.hypershift.openshift.io and updates nodeClassRef/group/kind; removes manual GlobalPS label.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

✨ Finishing touches
  • 📝 Generate docstrings

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

@openshift-ci openshift-ci bot requested review from bryan-cox and devguyio January 15, 2026 06:10
@openshift-ci openshift-ci bot added the area/api Indicates the PR includes changes for the API label Jan 15, 2026
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Jan 15, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: maxcao13
Once this PR has been reviewed and has the lgtm label, please assign muraee 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/control-plane-operator Indicates the PR includes changes for the control plane operator - in an OCP release area/platform/aws PR/issue for AWS (AWSPlatform) platform area/testing Indicates the PR includes changes for e2e testing and removed do-not-merge/needs-area labels Jan 15, 2026
@maxcao13
Copy link
Member Author

/cc @muraee @jkyros

@openshift-ci openshift-ci bot requested review from jkyros and muraee January 15, 2026 06:10
Copy link
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: 2

🤖 Fix all issues with AI agents
In `@karpenter-operator/controllers/nodepool/nodepool_controller.go`:
- Around line 143-149: The error message in the Patch call refers to
openshiftEC2NodeClass but the code is removing a finalizer from
openshiftNodePool; update the fmt.Errorf message in the error return of the
r.guestClient.Patch call to reference openshiftNodePool (or a generic
"OpenshiftNodePool") so it correctly identifies the resource being patched; the
change should be made where controllerutil.ContainsFinalizer(openshiftNodePool,
finalizer) then controllerutil.RemoveFinalizer(openshiftNodePool, finalizer) and
the subsequent r.guestClient.Patch(...) error is returned.
- Around line 82-88: getHCP currently returns a generic fmt.Errorf when no
HostedControlPlane is found, so apierrors.IsNotFound(err) in the reconciler will
never match; change getHCP to return a Kubernetes NotFound error (use
apierrors.NewNotFound with schema.GroupResource{Group:
"hypershift.openshift.io", Resource: "hostedcontrolplanes"} and the HCP name)
instead of fmt.Errorf, and add the necessary imports
(k8s.io/apimachinery/pkg/api/errors and k8s.io/apimachinery/pkg/runtime/schema)
so the existing IsNotFound check in the caller works as intended.
🧹 Nitpick comments (3)
karpenter-operator/controllers/nodepool/nodepool_controller_test.go (1)

268-292: Potential test flakiness with metav1.Now() in condition comparison.

The test uses metav1.Now() for LastTransitionTime in both nodePoolStatus (line 275) and expectedStatus (line 286). Since these are evaluated at different times during test setup, the timestamps will differ slightly, which could cause intermittent failures if the test ever compares LastTransitionTime directly.

The current assertions (lines 330-335) avoid comparing LastTransitionTime directly, which mitigates this. However, for clarity and to prevent future regressions, consider using a fixed timestamp:

🔧 Suggested improvement
+		fixedTime := metav1.Now()
 		{
 			name: "When NodePool status has conditions they should be mirrored to OpenshiftNodePool",
 			nodePoolStatus: karpenterv1.NodePoolStatus{
 				Conditions: []status.Condition{
 					{
 						Type:               string(karpenterv1.ConditionTypeValidationSucceeded),
 						Status:             metav1.ConditionTrue,
-						LastTransitionTime: metav1.Now(),
+						LastTransitionTime: fixedTime,
 						Reason:             "Valid",
 						Message:            "NodePool is valid",
 					},
 				},
 			},
 			expectedStatus: hyperkarpenterv1.OpenshiftNodePoolStatus{
 				Conditions: []status.Condition{
 					{
 						Type:               string(karpenterv1.ConditionTypeValidationSucceeded),
 						Status:             metav1.ConditionTrue,
-						LastTransitionTime: metav1.Now(),
+						LastTransitionTime: fixedTime,
 						Reason:             "Valid",
 						Message:            "NodePool is valid",
 					},
 				},
 			},
 		},
karpenter-operator/controllers/nodepool/nodepool_controller.go (2)

174-206: Logging op when it may be uninitialized.

When onlyCreate is true, op is never assigned, so line 203 logs a zero-value OperationResult. Consider logging only when op is meaningful, or restructuring the log statement.

Proposed fix
-	log.Info("Reconciled CRDs", "op", op)
+	if !onlyCreate {
+		log.Info("Reconciled CRDs", "op", op)
+	} else {
+		log.Info("Reconciled CRDs")
+	}

331-341: Consider adding context if multiple HCPs could exist.

The function returns the first HCP found without warning if multiple exist. If this is expected to be a single-HCP namespace, this is fine; otherwise, consider logging a warning or returning an error for ambiguous cases.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to Reviews -> Disable Knowledge Base setting

📥 Commits

Reviewing files that changed from the base of the PR and between 88a0b59 and 06e664a.

⛔ Files ignored due to path filters (14)
  • api/go.sum is excluded by !**/*.sum
  • api/vendor/github.com/awslabs/operatorpkg/status/condition_set.go is excluded by !**/vendor/**
  • api/vendor/github.com/awslabs/operatorpkg/status/controller.go is excluded by !**/vendor/**
  • api/vendor/github.com/awslabs/operatorpkg/status/unstructured_adapter.go is excluded by !**/vendor/**
  • api/vendor/modules.txt is excluded by !**/vendor/**
  • go.sum is excluded by !**/*.sum
  • vendor/github.com/awslabs/operatorpkg/status/condition_set.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/awslabs/operatorpkg/status/controller.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/awslabs/operatorpkg/status/unstructured_adapter.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/karpenter/v1beta1/karpenter_types.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/karpenter/v1beta1/openshiftnodepool_types.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/karpenter/v1beta1/register.go is excluded by !vendor/**, !**/vendor/**
  • vendor/github.com/openshift/hypershift/api/karpenter/v1beta1/zz_generated.deepcopy.go is excluded by !vendor/**, !**/vendor/**
  • vendor/modules.txt is excluded by !vendor/**, !**/vendor/**
📒 Files selected for processing (30)
  • api/go.mod
  • api/karpenter/v1beta1/karpenter_types.go
  • api/karpenter/v1beta1/openshiftnodepool_types.go
  • api/karpenter/v1beta1/register.go
  • api/karpenter/v1beta1/zz_generated.deepcopy.go
  • client/applyconfiguration/karpenter/v1beta1/openshiftnodepool.go
  • client/applyconfiguration/karpenter/v1beta1/openshiftnodepoolspec.go
  • client/applyconfiguration/karpenter/v1beta1/openshiftnodepoolstatus.go
  • client/applyconfiguration/utils.go
  • client/clientset/clientset/typed/karpenter/v1beta1/fake/fake_karpenter_client.go
  • client/clientset/clientset/typed/karpenter/v1beta1/fake/fake_openshiftnodepool.go
  • client/clientset/clientset/typed/karpenter/v1beta1/generated_expansion.go
  • client/clientset/clientset/typed/karpenter/v1beta1/karpenter_client.go
  • client/clientset/clientset/typed/karpenter/v1beta1/openshiftnodepool.go
  • client/informers/externalversions/generic.go
  • client/informers/externalversions/karpenter/v1beta1/interface.go
  • client/informers/externalversions/karpenter/v1beta1/openshiftnodepool.go
  • client/listers/karpenter/v1beta1/expansion_generated.go
  • client/listers/karpenter/v1beta1/openshiftnodepool.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/globalps/globalps.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/globalps/globalps_test.go
  • go.mod
  • karpenter-operator/controllers/karpenter/assets/karpenter.hypershift.openshift.io_openshiftec2nodeclasses.yaml
  • karpenter-operator/controllers/karpenter/assets/karpenter.hypershift.openshift.io_openshiftnodepools.yaml
  • karpenter-operator/controllers/karpenter/karpenter_controller.go
  • karpenter-operator/controllers/nodeclass/ec2_nodeclass_controller.go
  • karpenter-operator/controllers/nodepool/nodepool_controller.go
  • karpenter-operator/controllers/nodepool/nodepool_controller_test.go
  • karpenter-operator/main.go
  • test/e2e/assets/karpenter-nodepool.yaml
🧰 Additional context used
📓 Path-based instructions (1)
**

⚙️ CodeRabbit configuration file

-Focus on major issues impacting performance, readability, maintainability and security. Avoid nitpicks and avoid verbosity.

Files:

  • client/clientset/clientset/typed/karpenter/v1beta1/generated_expansion.go
  • api/karpenter/v1beta1/karpenter_types.go
  • client/informers/externalversions/generic.go
  • client/listers/karpenter/v1beta1/expansion_generated.go
  • karpenter-operator/controllers/karpenter/karpenter_controller.go
  • client/clientset/clientset/typed/karpenter/v1beta1/karpenter_client.go
  • client/informers/externalversions/karpenter/v1beta1/interface.go
  • client/applyconfiguration/utils.go
  • karpenter-operator/controllers/nodeclass/ec2_nodeclass_controller.go
  • go.mod
  • client/applyconfiguration/karpenter/v1beta1/openshiftnodepoolstatus.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/globalps/globalps_test.go
  • client/listers/karpenter/v1beta1/openshiftnodepool.go
  • karpenter-operator/controllers/nodepool/nodepool_controller_test.go
  • control-plane-operator/hostedclusterconfigoperator/controllers/globalps/globalps.go
  • api/karpenter/v1beta1/zz_generated.deepcopy.go
  • client/clientset/clientset/typed/karpenter/v1beta1/fake/fake_openshiftnodepool.go
  • client/clientset/clientset/typed/karpenter/v1beta1/fake/fake_karpenter_client.go
  • karpenter-operator/controllers/karpenter/assets/karpenter.hypershift.openshift.io_openshiftec2nodeclasses.yaml
  • client/clientset/clientset/typed/karpenter/v1beta1/openshiftnodepool.go
  • client/applyconfiguration/karpenter/v1beta1/openshiftnodepool.go
  • client/applyconfiguration/karpenter/v1beta1/openshiftnodepoolspec.go
  • client/informers/externalversions/karpenter/v1beta1/openshiftnodepool.go
  • karpenter-operator/main.go
  • api/karpenter/v1beta1/openshiftnodepool_types.go
  • karpenter-operator/controllers/nodepool/nodepool_controller.go
  • api/karpenter/v1beta1/register.go
  • api/go.mod
  • karpenter-operator/controllers/karpenter/assets/karpenter.hypershift.openshift.io_openshiftnodepools.yaml
  • test/e2e/assets/karpenter-nodepool.yaml
🧬 Code graph analysis (14)
client/informers/externalversions/generic.go (1)
api/auditlogpersistence/v1alpha1/register.go (1)
  • SchemeGroupVersion (12-12)
karpenter-operator/controllers/karpenter/karpenter_controller.go (1)
api/karpenter/v1beta1/openshiftnodepool_types.go (1)
  • OpenshiftNodePoolList (66-70)
client/clientset/clientset/typed/karpenter/v1beta1/karpenter_client.go (1)
client/clientset/clientset/typed/karpenter/v1beta1/openshiftnodepool.go (2)
  • OpenshiftNodePoolsGetter (34-36)
  • OpenshiftNodePoolInterface (39-54)
client/informers/externalversions/karpenter/v1beta1/interface.go (1)
client/informers/externalversions/karpenter/v1beta1/openshiftnodepool.go (1)
  • OpenshiftNodePoolInformer (36-39)
client/applyconfiguration/karpenter/v1beta1/openshiftnodepoolstatus.go (2)
test/e2e/util/eventually.go (2)
  • Conditions (435-506)
  • Condition (415-420)
api/karpenter/v1beta1/openshiftnodepool_types.go (1)
  • OpenshiftNodePoolStatus (13-20)
control-plane-operator/hostedclusterconfigoperator/controllers/globalps/globalps_test.go (1)
control-plane-operator/hostedclusterconfigoperator/controllers/globalps/globalps.go (1)
  • GlobalPSLabelKey (30-30)
client/listers/karpenter/v1beta1/openshiftnodepool.go (3)
api/karpenter/v1beta1/openshiftnodepool_types.go (1)
  • OpenshiftNodePool (55-62)
client/listers/karpenter/v1beta1/expansion_generated.go (2)
  • OpenshiftNodePoolListerExpansion (30-30)
  • OpenshiftNodePoolNamespaceListerExpansion (34-34)
api/karpenter/v1beta1/register.go (1)
  • Resource (18-20)
karpenter-operator/controllers/nodepool/nodepool_controller_test.go (2)
api/karpenter/v1beta1/openshiftnodepool_types.go (3)
  • OpenshiftNodePoolSpec (23-40)
  • OpenshiftNodePool (55-62)
  • OpenshiftNodePoolStatus (13-20)
control-plane-operator/hostedclusterconfigoperator/controllers/globalps/globalps.go (1)
  • GlobalPSLabelKey (30-30)
api/karpenter/v1beta1/zz_generated.deepcopy.go (1)
api/karpenter/v1beta1/openshiftnodepool_types.go (4)
  • OpenshiftNodePool (55-62)
  • OpenshiftNodePoolList (66-70)
  • OpenshiftNodePoolSpec (23-40)
  • OpenshiftNodePoolStatus (13-20)
client/clientset/clientset/typed/karpenter/v1beta1/fake/fake_karpenter_client.go (1)
client/clientset/clientset/typed/karpenter/v1beta1/openshiftnodepool.go (1)
  • OpenshiftNodePoolInterface (39-54)
client/applyconfiguration/karpenter/v1beta1/openshiftnodepoolspec.go (1)
api/karpenter/v1beta1/openshiftnodepool_types.go (1)
  • OpenshiftNodePoolSpec (23-40)
client/informers/externalversions/karpenter/v1beta1/openshiftnodepool.go (4)
client/listers/karpenter/v1beta1/openshiftnodepool.go (2)
  • OpenshiftNodePoolLister (29-36)
  • NewOpenshiftNodePoolLister (44-46)
client/informers/externalversions/karpenter/v1beta1/interface.go (1)
  • Interface (25-30)
api/karpenter/v1beta1/openshiftnodepool_types.go (1)
  • OpenshiftNodePool (55-62)
client/applyconfiguration/karpenter/v1beta1/openshiftnodepool.go (1)
  • OpenshiftNodePool (37-44)
karpenter-operator/main.go (1)
karpenter-operator/controllers/nodepool/nodepool_controller.go (1)
  • NodePoolReconciler (45-51)
api/karpenter/v1beta1/register.go (2)
api/karpenter/v1beta1/openshiftnodepool_types.go (2)
  • OpenshiftNodePool (55-62)
  • OpenshiftNodePoolList (66-70)
client/applyconfiguration/karpenter/v1beta1/openshiftnodepool.go (1)
  • OpenshiftNodePool (37-44)
🪛 golangci-lint (2.5.0)
karpenter-operator/controllers/nodepool/nodepool_controller_test.go

[error] 228-228: : # github.com/openshift/hypershift/sync-global-pullsecret [github.com/openshift/hypershift/sync-global-pullsecret.test]
sync-global-pullsecret/sync-global-pullsecret_test.go:228:23: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:234:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:247:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:257:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:270:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:283:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:296:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:309:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:327:12: undefined: NewMockdbusConn

(typecheck)

client/applyconfiguration/karpenter/v1beta1/openshiftnodepool.go

[error] 228-228: : # github.com/openshift/hypershift/sync-global-pullsecret [github.com/openshift/hypershift/sync-global-pullsecret.test]
sync-global-pullsecret/sync-global-pullsecret_test.go:228:23: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:234:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:247:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:257:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:270:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:283:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:296:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:309:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:327:12: undefined: NewMockdbusConn

(typecheck)

karpenter-operator/controllers/nodepool/nodepool_controller.go

[error] 228-228: : # github.com/openshift/hypershift/sync-global-pullsecret [github.com/openshift/hypershift/sync-global-pullsecret.test]
sync-global-pullsecret/sync-global-pullsecret_test.go:228:23: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:234:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:247:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:257:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:270:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:283:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:296:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:309:26: undefined: MockdbusConn
sync-global-pullsecret/sync-global-pullsecret_test.go:327:12: undefined: NewMockdbusConn

(typecheck)

🔇 Additional comments (37)
karpenter-operator/controllers/karpenter/assets/karpenter.hypershift.openshift.io_openshiftec2nodeclasses.yaml (1)

47-49: LGTM!

Good fix correcting the spec description to reference the correct resource type (OpenshiftEC2NodeClass) instead of the previously inconsistent reference.

control-plane-operator/hostedclusterconfigoperator/controllers/globalps/globalps.go (3)

30-30: LGTM!

The constant is appropriately exported with a clear, descriptive name following Go naming conventions. The value remains unchanged.


252-255: LGTM!

Consistent usage of the exported constant for node label management.


293-295: LGTM!

The nodeSelector correctly uses the exported constant, ensuring DaemonSet pods only schedule on nodes labeled by labelNodesForGlobalPullSecret.

control-plane-operator/hostedclusterconfigoperator/controllers/globalps/globalps_test.go (1)

584-586: LGTM!

The test correctly uses the exported GlobalPSLabelKey constant to verify node labeling behavior, maintaining consistency with the implementation.

api/karpenter/v1beta1/karpenter_types.go (1)

62-64: LGTM!

The documentation comment now correctly references OpenshiftEC2NodeClass, matching the type it describes.

client/clientset/clientset/typed/karpenter/v1beta1/generated_expansion.go (1)

21-22: LGTM!

Generated expansion interface correctly follows the existing pattern for the new OpenshiftNodePool resource.

api/go.mod (2)

80-81: Transitive dependency updates.

The k8s.io/cloud-provider and k8s.io/csi-translation-lib updates to v0.32.3 appear to be indirect dependency alignment. Ensure these are compatible with the primary k8s.io dependencies at v0.34.2.


7-11: Manual verification required for new direct dependencies in api/go.mod.

Verify the following before approving:

  • operatorpkg is actually imported and used for status/conditions handling in OpenshiftNodePool types
  • karpenter is actually imported and used for NodePool spec embedding
  • Both are required as direct dependencies (not already provided transitively)
  • Karpenter pseudo-version v1.2.1-0.20250212185021-45f73ec7a790 is a valid commit
client/listers/karpenter/v1beta1/expansion_generated.go (1)

27-34: LGTM!

Generated lister expansion interfaces correctly follow the existing pattern, providing extension points for both OpenshiftNodePoolLister and OpenshiftNodePoolNamespaceLister.

client/clientset/clientset/typed/karpenter/v1beta1/openshiftnodepool.go (1)

1-73: LGTM!

This is correctly generated client-gen code following standard Kubernetes client-go patterns for the new OpenshiftNodePool resource.

api/karpenter/v1beta1/register.go (1)

32-33: LGTM!

The new OpenshiftNodePool types are correctly registered following the same pattern as the existing OpenshiftEC2NodeClass types.

karpenter-operator/main.go (1)

133-138: LGTM!

The NodePoolReconciler is correctly wired following the same pattern as existing reconcilers (EC2NodeClassReconciler). Error handling is consistent with the established conventions.

client/informers/externalversions/generic.go (1)

83-84: LGTM!

The new OpenshiftNodePools informer case correctly follows the existing pattern for openshiftec2nodeclasses.

karpenter-operator/controllers/nodeclass/ec2_nodeclass_controller.go (1)

71-83: LGTM!

Good improvements:

  • Explicit controller naming with Named("ec2nodeclass") improves clarity and distinguishes this controller from the new NodePoolReconciler.
  • Using GetName() on the CRD objects instead of hardcoded strings is more maintainable and reduces the risk of name mismatches.
client/clientset/clientset/typed/karpenter/v1beta1/fake/fake_karpenter_client.go (1)

34-36: LGTM!

The generated fake client method follows the established pattern and correctly implements the OpenshiftNodePoolsGetter interface.

client/informers/externalversions/karpenter/v1beta1/interface.go (1)

28-29: LGTM!

The generated informer interface extension and implementation follow the established patterns.

Also applies to: 47-51

client/clientset/clientset/typed/karpenter/v1beta1/fake/fake_openshiftnodepool.go (1)

1-52: LGTM!

The generated fake client implementation for OpenshiftNodePool follows the standard client-go patterns with proper resource/kind registration and type factory functions.

client/clientset/clientset/typed/karpenter/v1beta1/karpenter_client.go (1)

31-31: LGTM!

The generated client properly extends the interface with OpenshiftNodePoolsGetter and implements the accessor method following the established pattern.

Also applies to: 43-45

karpenter-operator/controllers/karpenter/karpenter_controller.go (1)

181-201: LGTM - Correctly updated to use OpenshiftNodePoolList.

The deletion flow properly handles the new OpenshiftNodePool resources. The OpenshiftNodePool controller explicitly deletes the underlying Karpenter NodePool during reconciliation (nodepool_controller.go lines 133-141), and the existing NodeClaim wait (lines 203-211) ensures all dependent resources are cleaned up before removing the finalizer.

client/applyconfiguration/karpenter/v1beta1/openshiftnodepoolspec.go (1)

1-69: LGTM!

This is properly generated apply-configuration code that correctly mirrors the OpenshiftNodePoolSpec type from api/karpenter/v1beta1/openshiftnodepool_types.go. The fluent builder pattern is consistent with other apply configurations in this codebase.

karpenter-operator/controllers/nodepool/nodepool_controller_test.go (1)

27-241: LGTM!

The test cases for TestReconcileNodePool are comprehensive and well-structured:

  • Validates spec mirroring with GlobalPullSecret label injection
  • Tests NodeClassRef translation from OpenshiftEC2NodeClass to EC2NodeClass
  • Verifies OwnerReferences are correctly set

Good coverage of the core reconciliation logic.

client/applyconfiguration/utils.go (1)

368-373: LGTM!

The new switch cases correctly map the OpenshiftNodePool, OpenshiftNodePoolSpec, and OpenshiftNodePoolStatus kinds to their respective apply configuration types, following the same pattern as other karpenter types in this generated file.

test/e2e/assets/karpenter-nodepool.yaml (1)

1-22: LGTM!

The E2E test asset correctly migrates to the new OpenshiftNodePool API:

  • Uses the new karpenter.hypershift.openshift.io/v1beta1 API version
  • References OpenshiftEC2NodeClass which will be translated to EC2NodeClass by the controller
  • The removal of the hypershift.openshift.io/nodepool-globalps-enabled label is correct since the controller automatically injects it during reconciliation (as verified by the unit tests)
karpenter-operator/controllers/karpenter/assets/karpenter.hypershift.openshift.io_openshiftnodepools.yaml (2)

1-474: LGTM overall - CRD is well-structured.

The CRD is comprehensive with:

  • Appropriate validation rules using CEL expressions
  • Immutability constraints on nodeClassRef.group and nodeClassRef.kind to prevent drift
  • Well-defined disruption budgets with schedule/duration validation
  • Proper status subresource enabled

The schema aligns with the Go types defined in api/karpenter/v1beta1/openshiftnodepool_types.go.


24-26: Remove or fix the Nodes printer column—status.resources.nodes is not a valid Kubernetes resource key.

The Resources field is a standard corev1.ResourceList, which uses Kubernetes resource names like cpu, memory, and pods. The key nodes is non-standard and is never populated, so the Nodes column will always be empty. Either remove this column or change the jsonPath to reference a valid resource or a different field.

Likely an incorrect or invalid review comment.

client/applyconfiguration/karpenter/v1beta1/openshiftnodepoolstatus.go (1)

1-54: LGTM!

Generated apply-configuration code follows standard patterns and correctly mirrors the OpenshiftNodePoolStatus type definition.

client/listers/karpenter/v1beta1/openshiftnodepool.go (1)

1-69: LGTM!

Generated lister code follows standard Kubernetes client patterns.

api/karpenter/v1beta1/zz_generated.deepcopy.go (1)

264-379: LGTM!

Generated deepcopy implementations correctly handle all field types including maps, slices, and pointers.

client/informers/externalversions/karpenter/v1beta1/openshiftnodepool.go (1)

1-101: LGTM!

Generated informer code follows standard Kubernetes informer patterns with both context-aware and legacy list/watch functions.

api/karpenter/v1beta1/openshiftnodepool_types.go (1)

1-70: Verify generated client code aligns with cluster scope.

The type definitions are clean and properly leverage Karpenter types. However, the CRD is marked as scope=Cluster (line 44), but the generated lister and informer code include namespace parameters—for example, OpenshiftNodePools(namespace string) in the lister interface and client.KarpenterV1beta1().OpenshiftNodePools(namespace) in the informer. For cluster-scoped resources, generated client code typically omits namespace handling.

Note that OpenshiftEC2NodeClass, also marked scope=Cluster in the same package, exhibits the same namespace parameter pattern. This suggests either the code generation was not run after setting the scope markers, or the lister-gen tool in use does not respect the scope=Cluster annotation. Confirm whether code generation needs to be re-run or clarify if passing empty strings for namespace at runtime is the intended behavior.

karpenter-operator/controllers/nodepool/nodepool_controller.go (5)

1-43: LGTM!

Imports, constants, and CRD variable declarations follow standard patterns for controller-runtime based operators.


45-76: LGTM!

The reconciler setup correctly initializes both management and guest clients, applies CRDs and VAP on startup, and watches both OpenshiftNodePool and NodePool resources for bidirectional synchronization.


208-233: LGTM!

The field mapping from OpenshiftNodePool to NodePool is clear, and the automatic injection of the GlobalPullSecret label and NodeClass reference translation are well-documented.


235-252: LGTM!

Status mirroring from NodePool back to OpenshiftNodePool with conditional patching based on reflect.DeepEqual is a clean approach.


254-329: LGTM!

The ValidatingAdmissionPolicy correctly blocks direct manipulation of NodePool resources by users while allowing the controller (running as system:hosted-cluster-config) to manage them through OpenshiftNodePool.

client/applyconfiguration/karpenter/v1beta1/openshiftnodepool.go (1)

1-241: LGTM!

This is correctly generated apply-configuration code following standard Kubernetes client-go patterns. The fluent builder methods and lazy initialization are consistent with other generated apply configurations.

Note: The static analysis hint about MockdbusConn at line 228 references a different file (sync-global-pullsecret_test.go) and is unrelated to this file.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@openshift-merge-robot openshift-merge-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jan 16, 2026
This commit introduces the OpenshiftNodePool CRD.

The CRD acts as the de-facto interface for cluster-users interacting with AutoNode NodePools.
Similar to OpenshiftEC2NodeClass, the creation of a ONP will render a Karpenter NodePool, protected with a VAP.
The ValidatingAdmissionPolicy in the guest cluster will be constantly reconciled to mitigate deletion race conditions.

This allows us as a cluster service provider to:
- set enforcable/immutable fields and restrictions on NodePools
- hide fields that cluster-users should not touch
- add OpenShift-specific fields as a user interface

Signed-off-by: Max Cao <macao@redhat.com>
@openshift-merge-robot openshift-merge-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Jan 20, 2026
@openshift-ci openshift-ci bot added the area/karpenter-operator Indicates the PR includes changes related to the Karpenter operator label Jan 20, 2026
@maxcao13
Copy link
Member Author

/test e2e-aws-autonode

Copy link
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
karpenter-operator/controllers/nodeclass/ec2_nodeclass_controller.go (1)

157-162: Bug: Finalizer check is on wrong object.

Line 157 checks hcp for the finalizer, but line 159 adds the finalizer to openshiftEC2NodeClass. This will cause the finalizer to be added on every reconcile if hcp doesn't contain this finalizer, or never added if hcp already has it.

🐛 Proposed fix
-	if !controllerutil.ContainsFinalizer(hcp, finalizer) {
+	if !controllerutil.ContainsFinalizer(openshiftEC2NodeClass, finalizer) {
 		original := openshiftEC2NodeClass.DeepCopy()
 		controllerutil.AddFinalizer(openshiftEC2NodeClass, finalizer)
 		if err := r.guestClient.Patch(ctx, openshiftEC2NodeClass, client.MergeFromWithOptions(original, client.MergeFromWithOptimisticLock{})); err != nil {
 			return ctrl.Result{}, fmt.Errorf("failed to add finalizer to OpenshiftEC2NodeClass: %w", err)
 		}
 	}
🤖 Fix all issues with AI agents
In `@api/go.mod`:
- Line 7: The go.mod entry for the karpenter dependency is using a
pseudo-version; update the dependency for module github.com/aws/karpenter from
the pseudo-version to the latest stable release (e.g., v1.8.2) in go.mod and run
go get/Go toolchain to pin and tidy the module versions (or, if a stable release
cannot be used, add a short documented rationale in the repository (e.g., in
DEPENDENCY.md or go.mod comment) explaining why the pseudo-version is required),
ensuring the change references the module name github.com/aws/karpenter and that
you run go mod tidy to verify the dependency graph.
🧹 Nitpick comments (2)
karpenter-operator/controllers/nodepool/nodepool_controller.go (1)

198-203: Log message may show empty operation result.

When onlyCreate is true (lines 184-189), the op variable remains unset (zero value), so the log at line 203 will show op="". Consider moving the log inside the else branch or handling both paths.

Suggested fix
 		} else {
 			op, err = r.CreateOrUpdate(ctx, r.guestClient, crd, func() error {
 				return nil
 			})
 			if err != nil {
 				errs = append(errs, err)
 			}
-
+			log.Info("Reconciled CRD", "name", crd.Name, "op", op)
 		}
 	}
 	if err := utilerrors.NewAggregate(errs); err != nil {
 		return fmt.Errorf("failed to reconcile CRDs: %w", err)
 	}
-	log.Info("Reconciled CRDs", "op", op)
 
 	return nil
karpenter-operator/controllers/nodepool/nodepool_controller_test.go (1)

303-305: Unused fake client.

fakeManagementClient is created but never used in this test. Consider removing it to clean up the test setup.

🧹 Proposed cleanup
 		g := NewWithT(t)
-		fakeManagementClient := fake.NewClientBuilder().
-			WithScheme(scheme).
-			Build()
-
 		fakeGuestClient := fake.NewClientBuilder().
 			WithScheme(scheme).
 			WithObjects(openshiftNodePool).
 			WithStatusSubresource(openshiftNodePool).
 			Build()

 		r := &NodePoolReconciler{
-			managementClient: fakeManagementClient,
 			guestClient:      fakeGuestClient,
 			Namespace:        "namespace",
 		}


require (
github.com/aws/karpenter-provider-aws v1.0.8
github.com/awslabs/operatorpkg v0.0.0-20250320000002-b05af0f15c68
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check available releases for operatorpkg and karpenter

echo "=== Checking operatorpkg releases ==="
gh api repos/awslabs/operatorpkg/releases --jq '.[0:10] | .[] | {tag_name, published_at, prerelease}' 2>/dev/null || echo "gh cli not available or repo access issue"

echo -e "\n=== Checking karpenter releases ==="
gh api repos/kubernetes-sigs/karpenter/releases --jq '.[0:10] | .[] | {tag_name, published_at, prerelease}' 2>/dev/null || echo "gh cli not available or repo access issue"

echo -e "\n=== Fallback: Check via web for recent releases ==="
echo "operatorpkg repo: https://github.com/awslabs/operatorpkg/releases"
echo "karpenter repo: https://github.com/kubernetes-sigs/karpenter/releases"

Repository: openshift/hypershift

Length of output: 1117


🌐 Web query:

operatorpkg awslabs stable releases v1.0

💡 Result:

There is no awslabs/operatorpkg v1.0 stable release. The GitHub repo shows the project is pre-1.0 (uses 0.x / development versions) and releases/tags reflect 0.* or pseudo module versions rather than a 1.0 stable tag. [1][2]

Sources:

  • awslabs/operatorpkg (GitHub repository, README / versioning). [1]
  • Libraries.io release listing for github.com/awslabs/operatorpkg (shows releases/tags; no v1.0). [2]

🌐 Web query:

kubernetes-sigs karpenter stable releases latest version

💡 Result:

The latest stable Karpenter release is v1.8.2 — released Jan 15, 2026. [1][2]

Sources:

  • GitHub releases (kubernetes-sigs/karpenter) — v1.8.2 (Jan 15, 2026). [1]
  • Karpenter documentation / compatibility & upgrade pages. [2]

Consider upgrading karpenter to a stable release.

karpenter is now a direct dependency using a pseudo-version (v1.2.1-0.20250212185021-45f73ec7a790 from Feb 12, 2025), but stable releases are available—most recently v1.8.2 (Jan 15, 2026). Using a pseudo-version for direct dependencies complicates supply chain auditing and dependency tracking. If a stable release meets the feature requirements, upgrade to it; if not, document why the pseudo-version is necessary.

operatorpkg uses a pseudo-version by necessity—this project has no stable releases and only pre-release versions, so this is acceptable.

🤖 Prompt for AI Agents
In `@api/go.mod` at line 7, The go.mod entry for the karpenter dependency is using
a pseudo-version; update the dependency for module github.com/aws/karpenter from
the pseudo-version to the latest stable release (e.g., v1.8.2) in go.mod and run
go get/Go toolchain to pin and tidy the module versions (or, if a stable release
cannot be used, add a short documented rationale in the repository (e.g., in
DEPENDENCY.md or go.mod comment) explaining why the pseudo-version is required),
ensuring the change references the module name github.com/aws/karpenter and that
you run go mod tidy to verify the dependency graph.

@maxcao13
Copy link
Member Author

/retest
/test e2e-aws-autonode

@maxcao13
Copy link
Member Author

/retest

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Jan 20, 2026

@maxcao13: The following tests 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-autonode aaf0c18 link false /test e2e-aws-autonode
ci/prow/e2e-aws-4-21 aaf0c18 link true /test e2e-aws-4-21

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.

@maxcao13
Copy link
Member Author

Test failures look like its suffering the same fate as #7478 because of disk space reasons on the node:

karpenter_test.go:401: DisruptionTarget=True: TerminationByKubelet(The node was low on resource: ephemeral-storage. Threshold quantity: 2486223151, available: 2143532Ki. )

@enxebre
Copy link
Member

enxebre commented Jan 21, 2026

pending openshift/enhancements#1924

@enxebre
Copy link
Member

enxebre commented Jan 21, 2026

can we make sure this passes the tech-preview tests before others?

@maxcao13 maxcao13 marked this pull request as draft January 21, 2026 15:36
@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 Jan 21, 2026
@enxebre
Copy link
Member

enxebre commented Jan 21, 2026

/hold
until we decide a path forward for openshift/enhancements#1924

@openshift-ci openshift-ci bot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Jan 21, 2026
@maxcao13
Copy link
Member Author

Seems like this has been decided on a "wont-do" in our rosa sync meeting. I will close this now.

@maxcao13 maxcao13 closed this Jan 21, 2026
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/control-plane-operator Indicates the PR includes changes for the control plane operator - in 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/testing Indicates the PR includes changes for e2e testing do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. 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.

4 participants