Skip to content

Conversation

@chrischdi
Copy link
Contributor

@chrischdi chrischdi commented Oct 30, 2025

Summary by CodeRabbit

  • Bug Fixes

    • Improved machine synchronization to create and reconcile the Cluster API infrastructure machine when it is missing, avoiding synchronization failures and nil-pointer issues.
    • Refined infra resource fetching and error handling for more stable reconciliation sequencing.
  • Tests

    • Updated end-to-end tests to expect successful infra creation and synchronization.
    • Added unit tests covering infra resource presence/absence scenarios.

✏️ Tip: You can customize this high-level summary in your review settings.

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

@chrischdi: This pull request references Jira Issue OCPBUGS-63411, which is invalid:

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

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

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

Details

In response to this:

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci-robot openshift-ci-robot added the jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. label Oct 30, 2025
@coderabbitai
Copy link

coderabbitai bot commented Oct 30, 2025

📝 Walkthrough

Walkthrough

Adds private helpers to fetch and check existence of Cluster API infra Machines and updates MachineSyncReconciler.Reconcile to route synchronization either MAPI→CAPI when a CAPI infra Machine is absent (and timing permits) or retain the existing CAPI→MAPI flow. Tests updated and new unit tests added for infra-resource fetch logic.

Changes

Cohort / File(s) Change Summary
Controller Logic
pkg/controllers/machinesync/machine_sync_controller.go
Added private helpers fetchCAPIInfraMachine and doesCAPIInfraMachineExist; refactored fetchCAPIInfraResources to use the new helper; extended lint annotation (funlen → cyclop); altered Reconcile switch to conditionally route to MAPI→CAPI synchronization when CAPI infra Machine is absent; added nil-safety and adjusted error propagation.
Controller Tests (integration-like)
pkg/controllers/machinesync/machine_sync_controller_test.go
Updated expectations for the scenario where infra Machine is absent: test now asserts that a CAPA InfraMachine is created and the MAPI Machine receives Synchronized=True (ResourceSynchronized) instead of previously expecting a conversion error and Synchronized=False.
Unit Tests
pkg/controllers/machinesync/machine_sync_controller_unit_test.go
New unit tests (Ginkgo/Gomega) covering fetchCAPIInfraResources behavior across: nil CAPI Machine, missing infra Cluster, infra Cluster present with and without infra Machine. Uses fake client and AWS platform types.

Sequence Diagram(s)

sequenceDiagram
    participant Reconciler as MachineSyncReconciler
    participant MAPI as MAPI Machine
    participant CAPI as CAPI Machine
    participant Infra as CAPI InfraMachine
    participant Cluster as CAPI Cluster

    Reconciler->>MAPI: fetch mapped MAPI Machine
    Reconciler->>CAPI: fetch corresponding CAPI Machine
    Reconciler->>Cluster: fetch CAPI infra Cluster (via fetchCAPIInfraResources)
    alt InfraMachine exists
        Reconciler->>Infra: fetch infra Machine
        Reconciler->>CAPI: reconcile CAPI→MAPI sync flow
        CAPI-->>Reconciler: status/result
        Reconciler-->>MAPI: update synchronization condition
    else InfraMachine missing
        Reconciler->>Reconciler: doesCAPIInfraMachineExist -> false
        Reconciler->>CAPI: initiate MAPI→CAPI reconciliation (create InfraMachine)
        CAPI-->>Infra: create InfraMachine
        Infra-->>Reconciler: created
        Reconciler-->>MAPI: update synchronization condition (ResourceSynchronized)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Areas requiring extra attention:

  • The conditional logic in Reconcile that chooses between MAPI→CAPI vs CAPI→MAPI paths and associated timing guards
  • Nil-safety and error propagation in fetchCAPIInfraMachine, doesCAPIInfraMachineExist, and the refactored fetchCAPIInfraResources
  • Test expectations updated to reflect successful creation/synchronization when infra Machine is absent

Poem

🐰 I hopped through code to peek and see,
If infra machines sprout or flee,
When none are found I build with care,
Then mark them synced — a tidy pair.
Tests clap softly, carrots for tea 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and specifically describes the main change: creating a Cluster API InfraMachine when it doesn't exist while a Cluster API Machine exists.
Docstring Coverage ✅ Passed Docstring coverage is 82.69% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing touches
  • 📝 Generate docstrings

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.5.0)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions


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

@openshift-ci openshift-ci bot requested review from nrb and racheljpg October 30, 2025 07:42
Copy link

@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: 0

🧹 Nitpick comments (1)
pkg/controllers/machinesync/machine_sync_controller.go (1)

246-246: Fix typo in comment.

"existense" should be "existence".

Apply this diff:

-	// Check for existense of the Cluster API Infrastructure Machine or if it needs to get created from MAPI first.
+	// Check for existence of the Cluster API Infrastructure Machine or if it needs to get created from MAPI first.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 8207993 and ebbcf2d.

📒 Files selected for processing (2)
  • pkg/controllers/machinesync/machine_sync_controller.go (4 hunks)
  • pkg/controllers/machinesync/machine_sync_controller_test.go (1 hunks)
🔇 Additional comments (5)
pkg/controllers/machinesync/machine_sync_controller_test.go (1)

782-795: LGTM! Test correctly validates the new InfraMachine creation behavior.

The test expectations have been properly updated to reflect the new functionality where the Cluster API InfraMachine is now created successfully when it doesn't exist, rather than failing. The test now:

  • Expects successful synchronization (Status=True, Reason=ResourceSynchronized)
  • Verifies the InfraMachine is actually created

This aligns well with the implementation changes.

pkg/controllers/machinesync/machine_sync_controller.go (4)

258-262: Good timestamp-based precedence logic.

The condition correctly creates the InfraMachine from MAPI only when:

  1. Cluster API is authoritative
  2. CAPI Machine exists but InfraMachine doesn't
  3. MAPI machine was created first (or simultaneously)

The timestamp comparison (mapiMachine.CreationTimestamp.Equal(&capiMachine.CreationTimestamp) || mapiMachine.CreationTimestamp.Before(&capiMachine.CreationTimestamp)) ensures MAPI-originated configuration takes precedence only when appropriate, preventing overwriting of potentially newer CAPI-originated state.


950-974: Clean refactoring that improves modularity.

The refactored fetchCAPIInfraResources now properly separates InfraCluster and InfraMachine retrieval, delegating the latter to the dedicated fetchCAPIInfraMachine helper. This improves code reusability and maintains clear separation of concerns.


976-994: Well-implemented helper function.

The fetchCAPIInfraMachine helper is cleanly designed with:

  • Focused responsibility (fetch infrastructure machine by name/namespace)
  • Proper NotFound handling (returns nil rather than error)
  • Appropriate error wrapping for clarity
  • Platform-agnostic initialization

996-1012: Solid existence check implementation with proper nil handling.

The doesCAPIInfraMachineExist helper correctly:

  • Handles nil capiMachine by falling back to mapiMachine.Name
  • Uses capiMachine.Spec.InfrastructureRef when available for accurate lookup
  • Returns a clear boolean result rather than requiring nil checks
  • Wraps errors appropriately for context

@chrischdi
Copy link
Contributor Author

/jira refresh

@openshift-ci-robot openshift-ci-robot added jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. and removed jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. labels Oct 30, 2025
@openshift-ci-robot
Copy link

@chrischdi: This pull request references Jira Issue OCPBUGS-63411, which is valid.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (4.21.0) matches configured target version for branch (4.21.0)
  • bug is in the state POST, which is one of the valid states (NEW, ASSIGNED, POST)

Requesting review from QA contact:
/cc @sunzhaohua2

Details

In response to this:

/jira refresh

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 requested a review from sunzhaohua2 October 30, 2025 10:02
@nrb
Copy link
Contributor

nrb commented Oct 30, 2025

/lgtm
/approve

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Oct 30, 2025
@openshift-ci-robot
Copy link

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-aws-capi-techpreview
/test e2e-aws-ovn
/test e2e-aws-ovn-serial-1of2
/test e2e-aws-ovn-serial-2of2
/test e2e-aws-ovn-techpreview
/test e2e-aws-ovn-techpreview-upgrade
/test e2e-azure-capi-techpreview
/test e2e-azure-ovn-techpreview
/test e2e-azure-ovn-techpreview-upgrade
/test e2e-gcp-capi-techpreview
/test e2e-gcp-ovn-techpreview
/test e2e-metal3-capi-techpreview
/test e2e-openstack-capi-techpreview
/test e2e-openstack-ovn-techpreview
/test e2e-vsphere-capi-techpreview
/test regression-clusterinfra-aws-ipi-techpreview-capi

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Oct 30, 2025

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: nrb

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

The pull request process is described 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 the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Oct 30, 2025
@sunzhaohua2
Copy link
Contributor

Hi @chrischdi I tried to test this, follow below steps:

  • create a capi machine
  • create same name mapi machine with authoritativeAPI: ClusterAPI
  • check if awsmachine will be created.

result: FailedToConvertCAPIMachineToMAPI, awsmachine was not created.

$ oc get machine.m zhsunaws21-zf4rb-worker-us-east-1b-machine
status:
  authoritativeAPI: ClusterAPI
  conditions:
  - lastTransitionTime: "2025-10-31T08:30:08Z"
    status: "True"
    type: Drainable
  - lastTransitionTime: "2025-10-31T08:30:08Z"
    message: The AuthoritativeAPI status is set to 'ClusterAPI'
    reason: AuthoritativeAPINotMachineAPI
    status: "True"
    type: Paused
  - lastTransitionTime: "2025-10-31T08:30:08Z"
    status: "True"
    type: Terminable
  - lastTransitionTime: "2025-10-31T08:30:08Z"
    message: 'failed to convert Cluster API machine to Machine API machine: unexpected
      InfraMachine type, expected AWSMachine, got <nil>'
    reason: FailedToConvertCAPIMachineToMAPI
    severity: Error
    status: "False"
    type: Synchronized
  lastUpdated: "2025-10-31T08:30:08Z"
  phase: ""

$ oc get machine.m | grep machine                                                 
zhsunaws21-zf4rb-worker-us-east-1b-machine                                                   10m
$ oc get machine.c -n openshift-cluster-api | grep machine                           
zhsunaws21-zf4rb-worker-us-east-1b-machine   zhsunaws21-zf4rb                                                                                       Pending   15m
$ oc get awsmachine -n openshift-cluster-api | grep machine                                
$

@damdo
Copy link
Member

damdo commented Oct 31, 2025

/hold

For checking issue

@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 Oct 31, 2025
@chrischdi
Copy link
Contributor Author

I think this is the expected behavior for the code:

https://github.com/openshift/cluster-capi-operator/pull/402/files#diff-a00680d231c0783b5333cc3e2c6f15e625b31572f57b7fb4b598dcb18d2418f3R258-R259

I did it this way assuming the scenarios are:

  • Create MAPI Machine with CAPI Authoratitive --> create CAPI and Infra machine from MAPI Machine
    • here this PR fixes the case where the infra machine creation did not happen
  • Create CAPI Machine + Infra Machine --> create MAPI Machine from CAPI and Infra Machine

Not sure if it is right to "just create" the InfraMachine from the MAPI Machine in case the CAPI Machine was created first.

WDYT @damdo?

@chrischdi
Copy link
Contributor Author

/retest

@theobarberbany
Copy link
Contributor

Looks like Cluster API Suite: [It] [sig-cluster-lifecycle][OCPFeatureGate:MachineAPIMigration] Machine Migration CAPI Authoritative Tests Machine Migration Round Trip Tests CAPI (and no existing CAPI Machine with same name) -> MAPI -> CAPI round trip should verify mirror machines are deleted when deleting CAPI machine is consistently failing.

Have we impacted the deletion logic with this change?

@openshift-merge-robot openshift-merge-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Nov 5, 2025
@chrischdi
Copy link
Contributor Author

Looks like Cluster API Suite: [It] [sig-cluster-lifecycle][OCPFeatureGate:MachineAPIMigration] Machine Migration CAPI Authoritative Tests Machine Migration Round Trip Tests CAPI (and no existing CAPI Machine with same name) -> MAPI -> CAPI round trip should verify mirror machines are deleted when deleting CAPI machine is consistently failing.

Have we impacted the deletion logic with this change?

Fun... yeah that could actually be true. Have to check on this.

@theobarberbany
Copy link
Contributor

theobarberbany commented Nov 5, 2025

Have to check on this.

Happy to pair some time this week if you fancy :)

@chrischdi chrischdi force-pushed the pr-machinesync-create-inframachine-if-not-exists branch from ebbcf2d to debacfc Compare November 6, 2025 07:48
@openshift-ci openshift-ci bot removed the lgtm Indicates that a PR is ready to be merged. label Nov 6, 2025
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Nov 6, 2025

New changes are detected. LGTM label has been removed.

@chrischdi
Copy link
Contributor Author

/retest

@chrischdi
Copy link
Contributor Author

/pipeline required

@openshift-ci-robot
Copy link

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-aws-capi-techpreview
/test e2e-aws-ovn
/test e2e-aws-ovn-serial-1of2
/test e2e-aws-ovn-serial-2of2
/test e2e-aws-ovn-techpreview
/test e2e-aws-ovn-techpreview-upgrade
/test e2e-azure-capi-techpreview
/test e2e-azure-ovn-techpreview
/test e2e-azure-ovn-techpreview-upgrade
/test e2e-gcp-capi-techpreview
/test e2e-gcp-ovn-techpreview
/test e2e-metal3-capi-techpreview
/test e2e-openstack-capi-techpreview
/test e2e-openstack-ovn-techpreview
/test e2e-vsphere-capi-techpreview
/test regression-clusterinfra-aws-ipi-techpreview-capi

@chrischdi
Copy link
Contributor Author

/retest

@chrischdi chrischdi force-pushed the pr-machinesync-create-inframachine-if-not-exists branch from b635f0b to b6333ab Compare December 10, 2025 08:18
@chrischdi
Copy link
Contributor Author

Rebased to main

/pipeline required

@openshift-ci-robot
Copy link

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-aws-capi-techpreview
/test e2e-aws-ovn
/test e2e-aws-ovn-serial-1of2
/test e2e-aws-ovn-serial-2of2
/test e2e-aws-ovn-techpreview
/test e2e-aws-ovn-techpreview-upgrade
/test e2e-azure-capi-techpreview
/test e2e-azure-ovn-techpreview
/test e2e-azure-ovn-techpreview-upgrade
/test e2e-gcp-capi-techpreview
/test e2e-gcp-ovn-techpreview
/test e2e-metal3-capi-techpreview
/test e2e-openstack-capi-techpreview
/test e2e-openstack-ovn-techpreview
/test e2e-vsphere-capi-techpreview
/test regression-clusterinfra-aws-ipi-techpreview-capi

@openshift-ci-robot
Copy link

@chrischdi: This pull request references Jira Issue OCPBUGS-63411, which is valid.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (4.21.0) matches configured target version for branch (4.21.0)
  • bug is in the state POST, which is one of the valid states (NEW, ASSIGNED, POST)

Requesting review from QA contact:
/cc @sunzhaohua2

Details

In response to this:

Summary by CodeRabbit

  • Improvements

  • Reconciliation now more reliably detects infra-machine existence and creation timing, improving choice of sync direction between providers and reducing incorrect error-driven outcomes; infra resource fetch order and error handling refined.

  • Tests

  • Integration tests updated to assert successful ResourceSynchronized (Status=True) and infra-machine creation.

  • New unit tests cover presence/absence scenarios for infra-cluster and infra-machine fetching.

✏️ Tip: You can customize this high-level summary in your review settings.

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.

@chrischdi
Copy link
Contributor Author

/pipeline required

@openshift-ci-robot
Copy link

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-aws-capi-techpreview
/test e2e-aws-ovn
/test e2e-aws-ovn-serial-1of2
/test e2e-aws-ovn-serial-2of2
/test e2e-aws-ovn-techpreview
/test e2e-aws-ovn-techpreview-upgrade
/test e2e-azure-capi-techpreview
/test e2e-azure-ovn-techpreview
/test e2e-azure-ovn-techpreview-upgrade
/test e2e-gcp-capi-techpreview
/test e2e-gcp-ovn-techpreview
/test e2e-metal3-capi-techpreview
/test e2e-openstack-capi-techpreview
/test e2e-openstack-ovn-techpreview
/test e2e-vsphere-capi-techpreview
/test regression-clusterinfra-aws-ipi-techpreview-capi

@chrischdi chrischdi force-pushed the pr-machinesync-create-inframachine-if-not-exists branch from 7df1c6a to df25ead Compare December 16, 2025 07:53
@openshift-ci-robot openshift-ci-robot added jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. and removed jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. labels Dec 16, 2025
@openshift-ci-robot
Copy link

@chrischdi: This pull request references Jira Issue OCPBUGS-63411, which is invalid:

  • expected the bug to target either version "4.22." or "openshift-4.22.", but it targets "4.21" instead

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

Details

In response to this:

Summary by CodeRabbit

  • Improvements

  • Reconciliation now better detects and handles infrastructure machine presence, improving sync decisions and reducing spurious errors.

  • Tests

  • Updated integration/e2e tests to v1beta2 API shapes; added unit tests covering infra-cluster and infra-machine presence/absence.

  • Chores

  • Project tooling and configs updated (linters, module replacements) and admission/webhook manifests moved to the v1beta2 API surface.

✏️ Tip: You can customize this high-level summary in your review settings.

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.

Copy link

@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: 11

Caution

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

⚠️ Outside diff range comments (3)
e2e/machineset_migration_mapi_authoritative_test.go (1)

296-306: Fix assertion on line 305 to check the correct v1beta2 field.

The code updates Spec.Deletion.Order on the v1beta2 CAPI MachineSet (correct), but then asserts on Spec.DeletePolicy which was replaced by the Deletion struct in v1beta2. Line 305 should check Spec.Deletion.Order instead of Spec.DeletePolicy for capiMachineSet.

pkg/controllers/corecluster/corecluster_controller_test.go (1)

170-177: Incorrect condition constant name.

The condition constant should be ClusterControlPlaneInitializedV1Beta2Condition, not ControlPlaneInitializedV1Beta1Condition. The status path change to Status.Deprecated.V1Beta1.Conditions correctly reflects the v1beta2 backward compatibility structure where v1beta1 conditions are maintained under the Deprecated path.

pkg/util/sync.go (1)

119-126: Duplicate diff checks for ReadyReplicas and AvailableReplicas.

Lines 119-125 already check ReadyReplicas and AvailableReplicas, then lines 164-170 check them again. This results in redundant work and potentially overwriting the diff keys with identical values.

Remove the duplicate checks at lines 164-170:

 	if diffUpToDateReplicas := deep.Equal(a.UpToDateReplicas, b.UpToDateReplicas); len(diffUpToDateReplicas) > 0 {
 		diff[".upToDateReplicas"] = diffUpToDateReplicas
 	}

-	if diffAvailableReplicas := deep.Equal(a.AvailableReplicas, b.AvailableReplicas); len(diffAvailableReplicas) > 0 {
-		diff[".availableReplicas"] = diffAvailableReplicas
-	}
-
-	if diffReadyReplicas := deep.Equal(a.ReadyReplicas, b.ReadyReplicas); len(diffReadyReplicas) > 0 {
-		diff[".readyReplicas"] = diffReadyReplicas
-	}
-
 	if diffConditions := compareCAPIV1Beta2Conditions(a.Conditions, b.Conditions); len(diffConditions) > 0 {
 		diff[".conditions"] = diffConditions
 	}

Also applies to: 160-174

♻️ Duplicate comments (1)
pkg/controllers/machinesync/machine_sync_controller.go (1)

256-273: Timestamp gate still blocks InfraMachine creation for certain scenarios.

The condition at line 271 !mapiMachine.CreationTimestamp.After(capiMachine.CreationTimestamp.Time) prevents InfraMachine creation when the MAPI Machine is created after the CAPI Machine. This matches the QA-reported failure where creating a CAPI Machine first, then a MAPI Machine with authoritativeAPI: ClusterAPI, did not result in InfraMachine creation.

Per the author's comment, the intended flow is:

  1. MAPI Machine (with CAPI authoritative) → creates CAPI Machine + InfraMachine
  2. CAPI Machine + InfraMachine → creates MAPI Machine

The current logic intentionally restricts scenario where CAPI Machine exists without InfraMachine and MAPI Machine arrives later. Given the /hold and ongoing discussion, verify this is the desired behavior.

🧹 Nitpick comments (6)
pkg/controllers/machinemigration/machine_migration_controller.go (1)

227-244: Condition status type usage appears inconsistent but functionally correct.

The code compares machinePausedCondition.Status (type metav1.ConditionStatus) against metav1.ConditionTrue, and infraMachinePausedConditionStatus (type corev1.ConditionStatus) against corev1.ConditionTrue. While both are ultimately string types with the same value "True", consider using consistent types for clarity.

-	return (machinePausedCondition.Status == metav1.ConditionTrue) && (infraMachinePausedConditionStatus == corev1.ConditionTrue), nil
+	return (machinePausedCondition.Status == metav1.ConditionTrue) && (string(infraMachinePausedConditionStatus) == string(corev1.ConditionTrue)), nil

Alternatively, refactor util.GetConditionStatus to return metav1.ConditionStatus for consistency with the new v1beta2 conditions API.

e2e/framework/machine.go (1)

88-102: Unused cl parameter in GetMachineWithError.

The cl client.Client parameter is declared but never used in the function body. This appears to be for API consistency with other helper functions but should either be used or documented.

Consider one of these options:

-// GetMachine gets a machine by its name.
+// GetMachineWithError gets a machine by its name and returns an error if not found.
+// The cl parameter is unused but kept for API consistency with other helpers.
 func GetMachineWithError(cl client.Client, name string, namespace string) (*clusterv1.Machine, error) {

Or remove the unused parameter if API consistency is not required:

-func GetMachineWithError(cl client.Client, name string, namespace string) (*clusterv1.Machine, error) {
+func GetMachineWithError(name string, namespace string) (*clusterv1.Machine, error) {
pkg/controllers/machinesync/machine_sync_controller_test.go (1)

950-964: New ClusterAPI‑authoritative test for missing InfraMachine matches PR intent

The “when the CAPI machine exists and the InfraMachine does not exist” test verifies:

  • SynchronizedCondition becomes True with a “Successfully synchronized CAPI Machine to MAPI” message.
  • An AWSMachine is eventually created in the CAPI namespace with the mirrored name.

This directly exercises the new behavior described in the PR and should catch regressions in infra‑machine creation when only the CAPI Machine exists.

You might also consider asserting the infra-machine’s OwnerReferences point at the v1beta2 Machine (kind and APIVersion) to fully validate the new flow, but that’s optional here.

pkg/controllers/machinesetsync/machineset_sync_controller_test.go (1)

406-413: Status.Replicas expectation uses nil for zero; verify intent vs conversion helper

This assertion treats a zero mapiMachineSet.Status.Replicas as implying a nil Status.Replicas pointer on the CAPI MachineSet:

var expectedValue *int32
if mapiMachineSet.Status.Replicas != 0 {
	expectedValue = ptr.To(mapiMachineSet.Status.Replicas)
}
Eventually(k.Object(capiMachineSet), timeout).Should(
	HaveField("Status.Replicas", BeEquivalentTo(expectedValue)),
)

However, convertMAPIMachineSetToCAPIMachineSetStatus in pkg/conversion/mapi2capi/machineset.go currently sets Replicas: ptr.To(mapiMachineSet.Status.Replicas) unconditionally, which would yield a non‑nil pointer even when the value is 0.

If the sync controller reuses that helper for initial/status updates, this test may not match the actual behavior. Either:

  • adjust the conversion to use nilIfZero for .Status.Replicas as well, or
  • update this expectation to always compare against ptr.To(mapiMachineSet.Status.Replicas).
pkg/conversion/mapi2capi/machineset.go (1)

85-145: MachineSetStatus conversion populates both Deprecated.V1Beta1 and v1beta2 status correctly

convertMAPIMachineSetToCAPIMachineSetStatus:

  • fills Deprecated.V1Beta1 replicas, readiness, availability, and conditions,
  • sets pointer fields Replicas, ReadyReplicas, AvailableReplicas (using nilIfZero for the latter two),
  • initializes v1beta2 Conditions via convertMAPIMachineSetConditionsToCAPIMachineSetV1Beta2StatusConditions,
  • always sets UpToDateReplicas to 0 as per the in‑code comment and linked CAPI controller logic,
  • moves ErrorReason/ErrorMessage into Deprecated.V1Beta1.FailureReason/FailureMessage,
  • best‑effort populates Selector.

All of that is in line with the referenced CAPI status proposal.

You might consider using nilIfZero for Replicas as well for symmetry with ReadyReplicas/AvailableReplicas, unless the v1beta2 contract explicitly prefers a non‑nil Replicas pointer even when zero.

pkg/controllers/machinesetsync/machineset_sync_controller.go (1)

239-255: InfrastructureRef validation should also check Kind and APIGroup.

The validation at line 252 only checks if infraMachineTemplateRef.Name is empty. Since ContractVersionedObjectReference requires APIGroup, Kind, and Name, consider validating all required fields to catch misconfigured MachineSet resources early.

 	if capiMachineSet.Spec.ClusterName == "" {
 		return nil, nil, fmt.Errorf("machine set %s/%s: %w",
 			capiMachineSet.Namespace, capiMachineSet.Name, errInvalidInfraClusterReference)
 	}

-	if infraMachineTemplateRef.Name == "" {
+	if infraMachineTemplateRef.Name == "" || infraMachineTemplateRef.Kind == "" || infraMachineTemplateRef.APIGroup == "" {
 		return nil, nil, fmt.Errorf("machine %s/%s: %w",
 			capiMachineSet.Namespace, capiMachineSet.Name, errInvalidInfraMachineTemplateReference)
 	}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 7df1c6a and 69e4a67.

⛔ Files ignored due to path filters (62)
  • e2e/go.sum is excluded by !**/*.sum
  • go.sum is excluded by !**/*.sum
  • go.work is excluded by !**/*.work
  • go.work.sum is excluded by !**/*.sum
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/resourcebuilder/cluster-api/core/v1beta1/cluster.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/resourcebuilder/cluster-api/core/v1beta1/machine.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/resourcebuilder/cluster-api/core/v1beta1/machineset.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/resourcebuilder/cluster-api/core/v1beta2/cluster.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/resourcebuilder/cluster-api/core/v1beta2/machine.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/resourcebuilder/cluster-api/core/v1beta2/machineset.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/resourcebuilder/cluster-api/infrastructure/v1beta1/openstackcluster.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/resourcebuilder/cluster-api/infrastructure/v1beta1/openstackmachine.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/resourcebuilder/cluster-api/infrastructure/v1beta2/awscluster.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/resourcebuilder/cluster-api/infrastructure/v1beta2/awsmachine.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/resourcebuilder/cluster-api/infrastructure/v1beta2/powervscluster.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/resourcebuilder/cluster-api/infrastructure/v1beta2/powervsmachine.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/tools.go is excluded by !**/vendor/**, !vendor/**
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/controllers/external/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/controllers/external/tracker.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/controllers/external/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/controllers/external/util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/bootstrap.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/bootstrap_config_template.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/controlplane.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/controlplane_template.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/infrastructure_cluster.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/infrastructure_cluster_template.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/infrastructure_machine.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/infrastructure_machine_template.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/infrastructure_machinepool_template.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/metadata.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/references.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/version.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/aggregate.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/deprecated/v1beta1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/deprecated/v1beta1/getter.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/deprecated/v1beta1/matcher.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/deprecated/v1beta1/matchers.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/deprecated/v1beta1/merge.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/deprecated/v1beta1/merge_strategies.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/deprecated/v1beta1/patch.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/deprecated/v1beta1/setter.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/deprecated/v1beta1/unstructured.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/getter.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/matcher.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/merge_strategies.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/mirror.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/options.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/patch.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/setter.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/sort.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/summary.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/contract/contract.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/contract/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/labels/helpers.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/predicates/cluster_predicates.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/predicates/generic_predicates.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/version/version.go is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (87)
  • .golangci.yml (1 hunks)
  • cmd/cluster-capi-operator/main.go (3 hunks)
  • cmd/machine-api-migration/main.go (2 hunks)
  • e2e/aws_test.go (2 hunks)
  • e2e/azure_test.go (3 hunks)
  • e2e/baremetal_test.go (3 hunks)
  • e2e/e2e_common.go (3 hunks)
  • e2e/framework/cluster.go (3 hunks)
  • e2e/framework/machine.go (6 hunks)
  • e2e/framework/machineset.go (13 hunks)
  • e2e/framework/node.go (1 hunks)
  • e2e/gcp_test.go (3 hunks)
  • e2e/go.mod (1 hunks)
  • e2e/machine_migration_capi_authoritative_test.go (9 hunks)
  • e2e/machine_migration_helpers.go (7 hunks)
  • e2e/machine_migration_mapi_authoritative_test.go (8 hunks)
  • e2e/machineset_migration_capi_authoritative_test.go (8 hunks)
  • e2e/machineset_migration_helpers.go (10 hunks)
  • e2e/machineset_migration_mapi_authoritative_test.go (10 hunks)
  • e2e/migration_common.go (2 hunks)
  • e2e/openstack_test.go (3 hunks)
  • e2e/powervs_test.go (3 hunks)
  • e2e/vsphere_test.go (5 hunks)
  • go.mod (1 hunks)
  • manifests/0000_30_cluster-api_09_admission-policies.yaml (7 hunks)
  • manifests/0000_30_cluster-api_10_webhooks.yaml (1 hunks)
  • pkg/controllers/corecluster/corecluster_controller.go (11 hunks)
  • pkg/controllers/corecluster/corecluster_controller_test.go (6 hunks)
  • pkg/controllers/infracluster/aws.go (2 hunks)
  • pkg/controllers/infracluster/azure.go (3 hunks)
  • pkg/controllers/infracluster/gcp.go (2 hunks)
  • pkg/controllers/infracluster/infracluster_controller.go (2 hunks)
  • pkg/controllers/infracluster/infracluster_controller_test.go (9 hunks)
  • pkg/controllers/infracluster/metal3.go (2 hunks)
  • pkg/controllers/infracluster/powervs.go (2 hunks)
  • pkg/controllers/infracluster/vsphere.go (2 hunks)
  • pkg/controllers/kubeconfig/kubeconfig.go (2 hunks)
  • pkg/controllers/machinemigration/machine_migration_controller.go (8 hunks)
  • pkg/controllers/machinemigration/machine_migration_controller_test.go (12 hunks)
  • pkg/controllers/machinesetmigration/machineset_migration_controller.go (6 hunks)
  • pkg/controllers/machinesetmigration/machineset_migration_controller_test.go (11 hunks)
  • pkg/controllers/machinesetsync/machineset_sync_controller.go (34 hunks)
  • pkg/controllers/machinesetsync/machineset_sync_controller_test.go (15 hunks)
  • pkg/controllers/machinesetsync/machineset_sync_controller_unit_test.go.bak (1 hunks)
  • pkg/controllers/machinesetsync/machineset_vap_test.go (10 hunks)
  • pkg/controllers/machinesync/aws_test.go (4 hunks)
  • pkg/controllers/machinesync/machine_sync_controller.go (34 hunks)
  • pkg/controllers/machinesync/machine_sync_controller_test.go (39 hunks)
  • pkg/controllers/machinesync/machine_sync_controller_unit_test.go (1 hunks)
  • pkg/controllers/machinesync/machine_sync_mapi2capi_infrastructure.go (3 hunks)
  • pkg/conversion/capi2mapi/aws.go (5 hunks)
  • pkg/conversion/capi2mapi/aws_fuzz_test.go (4 hunks)
  • pkg/conversion/capi2mapi/aws_test.go (1 hunks)
  • pkg/conversion/capi2mapi/common.go (4 hunks)
  • pkg/conversion/capi2mapi/machine.go (8 hunks)
  • pkg/conversion/capi2mapi/machine_test.go (4 hunks)
  • pkg/conversion/capi2mapi/machineset.go (4 hunks)
  • pkg/conversion/capi2mapi/machineset_test.go (3 hunks)
  • pkg/conversion/capi2mapi/openstack.go (4 hunks)
  • pkg/conversion/capi2mapi/openstack_fuzz_test.go (4 hunks)
  • pkg/conversion/capi2mapi/openstack_test.go (1 hunks)
  • pkg/conversion/capi2mapi/powervs.go (3 hunks)
  • pkg/conversion/capi2mapi/powervs_fuzz_test.go (4 hunks)
  • pkg/conversion/capi2mapi/powervs_test.go (2 hunks)
  • pkg/conversion/capi2mapi/suite_test.go (2 hunks)
  • pkg/conversion/mapi2capi/aws.go (9 hunks)
  • pkg/conversion/mapi2capi/aws_fuzz_test.go (3 hunks)
  • pkg/conversion/mapi2capi/interface.go (1 hunks)
  • pkg/conversion/mapi2capi/machine.go (15 hunks)
  • pkg/conversion/mapi2capi/machine_test.go (24 hunks)
  • pkg/conversion/mapi2capi/machineset.go (8 hunks)
  • pkg/conversion/mapi2capi/machineset_test.go (9 hunks)
  • pkg/conversion/mapi2capi/openstack.go (8 hunks)
  • pkg/conversion/mapi2capi/openstack_fuzz_test.go (3 hunks)
  • pkg/conversion/mapi2capi/powervs.go (7 hunks)
  • pkg/conversion/mapi2capi/powervs_fuzz_test.go (3 hunks)
  • pkg/conversion/mapi2capi/util.go (6 hunks)
  • pkg/conversion/test/fuzz/fuzz.go (19 hunks)
  • pkg/conversion/test/matchers/capi_condition.go (3 hunks)
  • pkg/conversion/util/util.go (1 hunks)
  • pkg/test/crdbuilder.go (4 hunks)
  • pkg/test/envtest.go (2 hunks)
  • pkg/util/conditions.go (3 hunks)
  • pkg/util/sync.go (8 hunks)
  • pkg/util/sync_test.go (5 hunks)
  • pkg/util/watch_filters.go (2 hunks)
  • pkg/webhook/cluster.go (6 hunks)
🧰 Additional context used
🧬 Code graph analysis (42)
e2e/machineset_migration_capi_authoritative_test.go (1)
pkg/conversion/mapi2capi/interface.go (1)
  • MachineSet (29-31)
e2e/framework/node.go (1)
pkg/conversion/mapi2capi/interface.go (1)
  • Machine (24-26)
e2e/azure_test.go (1)
pkg/conversion/mapi2capi/interface.go (1)
  • MachineSet (29-31)
e2e/machine_migration_capi_authoritative_test.go (1)
pkg/conversion/mapi2capi/interface.go (1)
  • Machine (24-26)
pkg/controllers/machinesync/machine_sync_controller_test.go (3)
pkg/conversion/mapi2capi/interface.go (2)
  • Machine (24-26)
  • MachineSet (29-31)
e2e/migration_common.go (1)
  • SynchronizedCondition (10-10)
pkg/controllers/common_consts.go (1)
  • SynchronizedCondition (41-41)
pkg/controllers/machinesync/machine_sync_mapi2capi_infrastructure.go (1)
pkg/util/conditions.go (1)
  • EnsureCAPIV1Beta1Conditions (222-231)
pkg/controllers/machinesetmigration/machineset_migration_controller.go (2)
pkg/conversion/mapi2capi/interface.go (1)
  • MachineSet (29-31)
e2e/framework/framework.go (1)
  • CAPINamespace (14-14)
pkg/conversion/capi2mapi/machineset.go (1)
pkg/conversion/mapi2capi/interface.go (1)
  • MachineSet (29-31)
e2e/gcp_test.go (1)
pkg/conversion/mapi2capi/interface.go (1)
  • MachineSet (29-31)
e2e/openstack_test.go (1)
pkg/conversion/mapi2capi/interface.go (1)
  • MachineSet (29-31)
e2e/powervs_test.go (1)
pkg/conversion/mapi2capi/interface.go (1)
  • MachineSet (29-31)
pkg/conversion/mapi2capi/aws_fuzz_test.go (2)
pkg/conversion/mapi2capi/interface.go (2)
  • Machine (24-26)
  • MachineSet (29-31)
pkg/conversion/capi2mapi/interface.go (2)
  • MachineAndInfrastructureMachine (21-23)
  • MachineSetAndMachineTemplate (26-28)
e2e/machine_migration_mapi_authoritative_test.go (1)
pkg/conversion/mapi2capi/interface.go (1)
  • Machine (24-26)
pkg/conversion/capi2mapi/powervs_fuzz_test.go (3)
pkg/conversion/mapi2capi/interface.go (2)
  • Machine (24-26)
  • MachineSet (29-31)
pkg/conversion/capi2mapi/interface.go (1)
  • MachineAndInfrastructureMachine (21-23)
pkg/conversion/test/fuzz/fuzz.go (2)
  • CAPIMachineFuzzerFuncs (475-546)
  • CAPIMachineSetFuzzerFuncs (549-626)
pkg/conversion/mapi2capi/machineset_test.go (1)
pkg/conversion/test/matchers/capi_condition.go (1)
  • MatchCAPICondition (51-55)
e2e/machine_migration_helpers.go (2)
pkg/conversion/mapi2capi/interface.go (1)
  • Machine (24-26)
e2e/framework/machine.go (2)
  • GetMachineWithError (89-102)
  • GetMachine (75-86)
pkg/controllers/machinesync/machine_sync_controller_unit_test.go (2)
pkg/controllers/machinesync/machine_sync_controller.go (1)
  • MachineSyncReconciler (138-147)
pkg/conversion/mapi2capi/interface.go (1)
  • Machine (24-26)
pkg/conversion/mapi2capi/util.go (1)
pkg/conversion/mapi2capi/interface.go (1)
  • Machine (24-26)
pkg/conversion/capi2mapi/openstack_fuzz_test.go (1)
pkg/conversion/test/fuzz/fuzz.go (2)
  • CAPIMachineFuzzerFuncs (475-546)
  • CAPIMachineSetFuzzerFuncs (549-626)
e2e/vsphere_test.go (1)
pkg/conversion/mapi2capi/interface.go (1)
  • MachineSet (29-31)
pkg/conversion/mapi2capi/machineset.go (1)
pkg/conversion/mapi2capi/interface.go (1)
  • MachineSet (29-31)
pkg/controllers/machinemigration/machine_migration_controller_test.go (1)
pkg/conversion/mapi2capi/interface.go (2)
  • Machine (24-26)
  • MachineSet (29-31)
pkg/conversion/capi2mapi/powervs.go (3)
pkg/conversion/mapi2capi/interface.go (2)
  • Machine (24-26)
  • MachineSet (29-31)
pkg/conversion/capi2mapi/interface.go (2)
  • MachineAndInfrastructureMachine (21-23)
  • MachineSetAndMachineTemplate (26-28)
pkg/conversion/consts/consts.go (1)
  • MAPIMachineMetadataLabelZone (26-26)
e2e/aws_test.go (1)
pkg/conversion/mapi2capi/interface.go (1)
  • MachineSet (29-31)
e2e/framework/machineset.go (2)
pkg/conversion/mapi2capi/interface.go (2)
  • MachineSet (29-31)
  • Machine (24-26)
e2e/framework/machine.go (1)
  • GetMachines (18-44)
pkg/conversion/mapi2capi/powervs.go (1)
pkg/conversion/mapi2capi/interface.go (2)
  • Machine (24-26)
  • MachineSet (29-31)
pkg/conversion/mapi2capi/openstack_fuzz_test.go (2)
pkg/conversion/mapi2capi/interface.go (2)
  • Machine (24-26)
  • MachineSet (29-31)
pkg/conversion/capi2mapi/interface.go (2)
  • MachineAndInfrastructureMachine (21-23)
  • MachineSetAndMachineTemplate (26-28)
e2e/machineset_migration_helpers.go (2)
pkg/conversion/mapi2capi/interface.go (1)
  • MachineSet (29-31)
e2e/framework/framework.go (2)
  • WaitOverLong (26-26)
  • RetryLong (19-19)
e2e/baremetal_test.go (1)
pkg/conversion/mapi2capi/interface.go (1)
  • MachineSet (29-31)
pkg/controllers/machinesync/aws_test.go (1)
pkg/conversion/mapi2capi/interface.go (1)
  • Machine (24-26)
pkg/conversion/capi2mapi/aws_fuzz_test.go (1)
pkg/conversion/test/fuzz/fuzz.go (2)
  • CAPIMachineFuzzerFuncs (475-546)
  • CAPIMachineSetFuzzerFuncs (549-626)
pkg/conversion/mapi2capi/machine.go (1)
pkg/conversion/mapi2capi/interface.go (1)
  • Machine (24-26)
pkg/conversion/capi2mapi/machine_test.go (2)
pkg/conversion/mapi2capi/interface.go (1)
  • Machine (24-26)
pkg/util/annotations.go (1)
  • MapiDeleteMachineAnnotation (24-24)
pkg/conversion/mapi2capi/aws.go (1)
pkg/conversion/mapi2capi/interface.go (2)
  • Machine (24-26)
  • MachineSet (29-31)
pkg/conversion/capi2mapi/machine.go (1)
pkg/conversion/mapi2capi/interface.go (1)
  • Machine (24-26)
pkg/conversion/capi2mapi/openstack.go (3)
pkg/conversion/mapi2capi/interface.go (2)
  • Machine (24-26)
  • MachineSet (29-31)
pkg/conversion/capi2mapi/interface.go (2)
  • MachineAndInfrastructureMachine (21-23)
  • MachineSetAndMachineTemplate (26-28)
pkg/conversion/consts/consts.go (1)
  • MAPIMachineMetadataLabelZone (26-26)
pkg/conversion/mapi2capi/machine_test.go (1)
pkg/conversion/test/matchers/capi_condition.go (1)
  • MatchCAPICondition (51-55)
pkg/conversion/mapi2capi/openstack.go (1)
pkg/conversion/mapi2capi/interface.go (2)
  • Machine (24-26)
  • MachineSet (29-31)
pkg/conversion/capi2mapi/aws.go (2)
pkg/conversion/consts/consts.go (1)
  • MAPIMachineMetadataLabelZone (26-26)
third_party/sigs.k8s.io/cluster-api/util/util.go (1)
  • IsControlPlaneMachine (25-28)
pkg/conversion/capi2mapi/powervs_test.go (1)
pkg/conversion/mapi2capi/interface.go (2)
  • Machine (24-26)
  • MachineSet (29-31)
pkg/controllers/machinesetmigration/machineset_migration_controller_test.go (1)
pkg/conversion/mapi2capi/interface.go (2)
  • MachineSet (29-31)
  • Machine (24-26)
pkg/controllers/machinesetsync/machineset_sync_controller.go (3)
pkg/conversion/mapi2capi/interface.go (1)
  • MachineSet (29-31)
pkg/util/conditions.go (2)
  • EnsureCAPIDeprecatedV1Beta1Conditions (246-255)
  • EnsureCAPIConditions (258-267)
pkg/util/finalizer.go (1)
  • RemoveFinalizer (60-85)

openstackv1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1"
vspherev1 "sigs.k8s.io/cluster-api-provider-vsphere/apis/v1beta1"
clusterv1beta1 "sigs.k8s.io/cluster-api/api/core/v1beta1"
clusterv1 "sigs.k8s.io/cluster-api/api/core/v1beta2"
Copy link

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:

rg -n 'infraAPIVersion' --type go

Repository: openshift/cluster-capi-operator

Length of output: 191


Remove unused infraAPIVersion constant.

The import and scheme registration updates to v1beta2 are correct. However, infraAPIVersion (defined on line 34) is no longer used—ContractVersionedObjectReference uses only APIGroup. Remove the unused constant on line 34.

🤖 Prompt for AI Agents
In e2e/e2e_common.go around lines 22–34, remove the unused infraAPIVersion
constant declaration (the constant defined on line 34) since
ContractVersionedObjectReference now only uses APIGroup; delete the unused
constant and any trailing comma/blank line left behind so the file compiles and
imports remain correct.

Comment on lines 32 to 33
clusterv1beta1 "sigs.k8s.io/cluster-api/api/core/v1beta1"
clusterv1 "sigs.k8s.io/cluster-api/api/core/v1beta2"
Copy link

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
# Inspect the specific lines and usage in powervs.go
echo "=== Lines 30-40 (around imports) ==="
sed -n '30,40p' pkg/controllers/infracluster/powervs.go

echo -e "\n=== Lines 100-110 (around ManagedByAnnotation and APIEndpoint usage) ==="
sed -n '100,110p' pkg/controllers/infracluster/powervs.go

echo -e "\n=== Check all usages of APIEndpoint and ManagedByAnnotation ==="
rg -n "APIEndpoint|ManagedByAnnotation" pkg/controllers/infracluster/powervs.go

echo -e "\n=== Check all clusterv1beta1 usage in the file ==="
rg -n "clusterv1beta1\." pkg/controllers/infracluster/powervs.go

echo -e "\n=== Check all clusterv1 usage in the file (v1beta2) ==="
rg -n "clusterv1\." pkg/controllers/infracluster/powervs.go

Repository: openshift/cluster-capi-operator

Length of output: 1548


Complete v1beta2 Cluster API migration by using APIEndpoint from v1beta2 package.

The file uses both v1beta1 and v1beta2 imports, but only one v1beta1 usage remains: line 107 uses clusterv1beta1.APIEndpoint. Line 103 successfully uses clusterv1.ManagedByAnnotation from v1beta2. Since APIEndpoint is defined identically in v1beta2 with the same structure (Host string, Port int32), update line 107 to use clusterv1.APIEndpoint and remove the v1beta1 import.

🤖 Prompt for AI Agents
In pkg/controllers/infracluster/powervs.go around lines 32-33 and 107, replace
the remaining usage of clusterv1beta1.APIEndpoint with clusterv1.APIEndpoint and
remove the unused import of clusterv1beta1; ensure the import block only
includes clusterv1 ("sigs.k8s.io/cluster-api/api/core/v1beta2") and update the
type reference at line ~107 to clusterv1.APIEndpoint so the file consistently
uses v1beta2.

Comment on lines 1 to 28
/*
Copyright 2025 Red Hat, Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package machinesetsync

import (
"time"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/ptr"

clusterv1beta1 "sigs.k8s.io/cluster-api/api/core/v1beta1"
)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

File has .bak extension - tests won't execute.

This file has a .bak extension which means it won't be picked up by the Go test runner. If these tests are intended to be part of the test suite, rename the file to machineset_sync_controller_unit_test.go.

Additionally, this file imports clusterv1beta1 (v1beta1) while the rest of the PR migrates to v1beta2. If this is intentional for testing v1beta1 compatibility, consider adding a comment explaining the purpose. Otherwise, update imports and types to v1beta2 for consistency.

#!/bin/bash
# Check if there's already a non-.bak version of this file
fd -t f "machineset_sync_controller_unit_test.go" pkg/controllers/machinesetsync/

# Check for other .bak files that might be accidentally committed
fd -e bak .
🤖 Prompt for AI Agents
In pkg/controllers/machinesetsync/machineset_sync_controller_unit_test.go.bak
lines 1-28, the file has a .bak extension so Go test runner will ignore it;
rename the file to machineset_sync_controller_unit_test.go so it runs as part of
the test suite, and also update the Cluster API import and used types from
clusterv1beta1 to clusterv1beta2 to match the PR migration (or if you
intentionally test v1beta1, keep the import but add a short clarifying comment
at the top explaining this backward-compatibility test).

Comment on lines 140 to 144
if capiMachine.Status.Deprecated.V1Beta1.FailureReason == nil &&
capiMachine.Status.Deprecated.V1Beta1.FailureMessage == nil &&
len(capiMachine.Status.Deprecated.V1Beta1.Conditions) == 0 {
capiMachine.Status.Deprecated = nil
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Add nil checks before accessing nested Deprecated fields.

Lines 140-143 access capiMachine.Status.Deprecated.V1Beta1 fields without checking if Deprecated or V1Beta1 are nil. Based on line 588 which checks if m.Deprecated != nil && m.Deprecated.V1Beta1 != nil, these appear to be pointers. This could cause a nil pointer panic during fuzz tests.

Apply this diff to add proper nil guards:

-		if capiMachine.Status.Deprecated.V1Beta1.FailureReason == nil &&
-			capiMachine.Status.Deprecated.V1Beta1.FailureMessage == nil &&
-			len(capiMachine.Status.Deprecated.V1Beta1.Conditions) == 0 {
+		if capiMachine.Status.Deprecated != nil &&
+			capiMachine.Status.Deprecated.V1Beta1 != nil &&
+			capiMachine.Status.Deprecated.V1Beta1.FailureReason == nil &&
+			capiMachine.Status.Deprecated.V1Beta1.FailureMessage == nil &&
+			len(capiMachine.Status.Deprecated.V1Beta1.Conditions) == 0 {
 			capiMachine.Status.Deprecated = nil
 		}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if capiMachine.Status.Deprecated.V1Beta1.FailureReason == nil &&
capiMachine.Status.Deprecated.V1Beta1.FailureMessage == nil &&
len(capiMachine.Status.Deprecated.V1Beta1.Conditions) == 0 {
capiMachine.Status.Deprecated = nil
}
if capiMachine.Status.Deprecated != nil &&
capiMachine.Status.Deprecated.V1Beta1 != nil &&
capiMachine.Status.Deprecated.V1Beta1.FailureReason == nil &&
capiMachine.Status.Deprecated.V1Beta1.FailureMessage == nil &&
len(capiMachine.Status.Deprecated.V1Beta1.Conditions) == 0 {
capiMachine.Status.Deprecated = nil
}
🤖 Prompt for AI Agents
In pkg/conversion/test/fuzz/fuzz.go around lines 140 to 144, the code accesses
capiMachine.Status.Deprecated.V1Beta1 fields without guarding that Deprecated
and V1Beta1 are non-nil; update the conditional to first check that
capiMachine.Status.Deprecated != nil && capiMachine.Status.Deprecated.V1Beta1 !=
nil before evaluating FailureReason, FailureMessage, and Conditions, and only
then set capiMachine.Status.Deprecated = nil when those inner fields are all
empty/nil.

// fakeAzureClusterKind is the Kind for the AWSCluster.
fakeAzureClusterKind = "AzureCluster"

// fakeAWSClusterCRD is a fake AzureCluster CRD.
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix comment typo.

The comment incorrectly refers to "fakeAWSClusterCRD" instead of "fakeAzureClusterCRD".

Apply this diff to fix the comment:

-	// fakeAWSClusterCRD is a fake AzureCluster CRD.
+	// fakeAzureClusterCRD is a fake AzureCluster CRD.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// fakeAWSClusterCRD is a fake AzureCluster CRD.
// fakeAzureClusterCRD is a fake AzureCluster CRD.
🤖 Prompt for AI Agents
In pkg/test/crdbuilder.go around line 113, the comment above the AzureCluster
fake is incorrectly labeled "fakeAWSClusterCRD"; update the comment text to
correctly read "fakeAzureClusterCRD" so it matches the variable/name and
describes the AzureCluster CRD accurately.

@chrischdi chrischdi force-pushed the pr-machinesync-create-inframachine-if-not-exists branch 2 times, most recently from a8d9b03 to e00163b Compare December 16, 2025 17:38
Copy link

@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: 5

Caution

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

⚠️ Outside diff range comments (3)
pkg/controllers/corecluster/corecluster_controller_test.go (1)

170-177: Add assertions for the newer ClusterControlPlaneInitializedCondition condition.

The controller sets both the deprecated v1beta1 condition and the newer condition type (clusterv1.ClusterControlPlaneInitializedCondition), but the tests only verify the deprecated path. Add assertions to verify that Status.Conditions contains the newer condition with the correct type and status.

Also applies to: 231-238

pkg/conversion/mapi2capi/openstack.go (1)

121-126: Avoid nil dereference when infrastructure is nil

Both in ToMachineAndInfrastructureMachine and ToMachineSetAndMachineTemplate you guard with:

if m.infrastructure == nil || m.infrastructure.Status.InfrastructureName == "" {
    errors = append(errors, field.Invalid(
        field.NewPath("infrastructure", "status", "infrastructureName"),
        m.infrastructure.Status.InfrastructureName,
        "infrastructure cannot be nil and infrastructure.Status.InfrastructureName cannot be empty"))
}

If m.infrastructure is actually nil, this will panic when evaluating m.infrastructure.Status.InfrastructureName for the BadValue.

Safer pattern that keeps behavior identical on valid inputs:

- if m.infrastructure == nil || m.infrastructure.Status.InfrastructureName == "" {
-     errors = append(errors, field.Invalid(
-         field.NewPath("infrastructure", "status", "infrastructureName"),
-         m.infrastructure.Status.InfrastructureName,
-         "infrastructure cannot be nil and infrastructure.Status.InfrastructureName cannot be empty"))
- } else {
-     capiMachine.Spec.ClusterName = m.infrastructure.Status.InfrastructureName
-     capiMachine.Labels[clusterv1.ClusterNameLabel] = m.infrastructure.Status.InfrastructureName
- }
+ infraName := ""
+ if m.infrastructure != nil {
+     infraName = m.infrastructure.Status.InfrastructureName
+ }
+ if infraName == "" {
+     errors = append(errors, field.Invalid(
+         field.NewPath("infrastructure", "status", "infrastructureName"),
+         infraName,
+         "infrastructure cannot be nil and infrastructure.Status.InfrastructureName cannot be empty"))
+ } else {
+     capiMachine.Spec.ClusterName = infraName
+     capiMachine.Labels[clusterv1.ClusterNameLabel] = infraName
+ }

Apply the same pattern in the MachineSet path.

Also applies to: 187-193

pkg/conversion/mapi2capi/aws.go (1)

143-148: Guard against nil infrastructure in AWS converters

As in the OpenStack path, both AWS converters use:

if m.infrastructure == nil || m.infrastructure.Status.InfrastructureName == "" {
    errs = append(errs, field.Invalid(
        field.NewPath("infrastructure", "status", "infrastructureName"),
        m.infrastructure.Status.InfrastructureName,
        "infrastructure cannot be nil and infrastructure.Status.InfrastructureName cannot be empty"))
} else {
    // use m.infrastructure.Status.InfrastructureName
}

If m.infrastructure is nil, this will panic while building the error (due to m.infrastructure.Status...).

Safer, without changing behavior for valid inputs:

- if m.infrastructure == nil || m.infrastructure.Status.InfrastructureName == "" {
-     errs = append(errs, field.Invalid(
-         field.NewPath("infrastructure", "status", "infrastructureName"),
-         m.infrastructure.Status.InfrastructureName,
-         "infrastructure cannot be nil and infrastructure.Status.InfrastructureName cannot be empty"))
- } else {
-     capiMachine.Spec.ClusterName = m.infrastructure.Status.InfrastructureName
-     capiMachine.Labels[clusterv1.ClusterNameLabel] = m.infrastructure.Status.InfrastructureName
- }
+ infraName := ""
+ if m.infrastructure != nil {
+     infraName = m.infrastructure.Status.InfrastructureName
+ }
+ if infraName == "" {
+     errs = append(errs, field.Invalid(
+         field.NewPath("infrastructure", "status", "infrastructureName"),
+         infraName,
+         "infrastructure cannot be nil and infrastructure.Status.InfrastructureName cannot be empty"))
+ } else {
+     capiMachine.Spec.ClusterName = infraName
+     capiMachine.Labels[clusterv1.ClusterNameLabel] = infraName
+ }

and analogously in ToMachineSetAndMachineTemplate.

Also applies to: 211-217

♻️ Duplicate comments (7)
e2e/go.mod (1)

7-8: Duplicate: Version mismatch already flagged in past review.

This concern was already raised in a prior review. The versions in the replace block for cluster-api-actuator-pkg modules remain out of sync with the root go.mod. If this is still unresolved, please address it by synchronizing the dependency versions.

pkg/test/crdbuilder.go (1)

113-113: Comment typo already flagged.

This typo ("fakeAWSClusterCRD" → "fakeAzureClusterCRD") was identified in a previous review.

pkg/conversion/test/fuzz/fuzz.go (2)

140-144: Add nil checks before accessing nested Deprecated fields.

Lines 140-143 access capiMachine.Status.Deprecated.V1Beta1 fields without checking if Deprecated or V1Beta1 are nil. This pattern at line 588 shows the proper guard: if m.Deprecated != nil && m.Deprecated.V1Beta1 != nil. This could cause a nil pointer panic during fuzz tests.

-		if capiMachine.Status.Deprecated.V1Beta1.FailureReason == nil &&
-			capiMachine.Status.Deprecated.V1Beta1.FailureMessage == nil &&
-			len(capiMachine.Status.Deprecated.V1Beta1.Conditions) == 0 {
+		if capiMachine.Status.Deprecated != nil &&
+			capiMachine.Status.Deprecated.V1Beta1 != nil &&
+			capiMachine.Status.Deprecated.V1Beta1.FailureReason == nil &&
+			capiMachine.Status.Deprecated.V1Beta1.FailureMessage == nil &&
+			len(capiMachine.Status.Deprecated.V1Beta1.Conditions) == 0 {
 			capiMachine.Status.Deprecated = nil
 		}

240-249: Add nil checks before accessing nested Deprecated fields.

Similar to lines 140-144, this code accesses capiMachineSet.Status.Deprecated.V1Beta1 fields without nil checks, risking a panic.

-		capiMachineSet.Status.Deprecated.V1Beta1.Conditions = nil
-		// Set Deprecated to nil if the values are zero
-		if capiMachineSet.Status.Deprecated.V1Beta1.FullyLabeledReplicas == 0 &&
-			capiMachineSet.Status.Deprecated.V1Beta1.ReadyReplicas == 0 &&
-			capiMachineSet.Status.Deprecated.V1Beta1.AvailableReplicas == 0 &&
-			capiMachineSet.Status.Deprecated.V1Beta1.FailureReason == nil &&
-			capiMachineSet.Status.Deprecated.V1Beta1.FailureMessage == nil &&
-			len(capiMachineSet.Status.Deprecated.V1Beta1.Conditions) == 0 {
-			capiMachineSet.Status.Deprecated = nil
-		}
+		if capiMachineSet.Status.Deprecated != nil &&
+			capiMachineSet.Status.Deprecated.V1Beta1 != nil {
+			capiMachineSet.Status.Deprecated.V1Beta1.Conditions = nil
+			// Set Deprecated to nil if the values are zero
+			if capiMachineSet.Status.Deprecated.V1Beta1.FullyLabeledReplicas == 0 &&
+				capiMachineSet.Status.Deprecated.V1Beta1.ReadyReplicas == 0 &&
+				capiMachineSet.Status.Deprecated.V1Beta1.AvailableReplicas == 0 &&
+				capiMachineSet.Status.Deprecated.V1Beta1.FailureReason == nil &&
+				capiMachineSet.Status.Deprecated.V1Beta1.FailureMessage == nil {
+				capiMachineSet.Status.Deprecated = nil
+			}
+		}
pkg/controllers/infracluster/powervs.go (1)

32-33: Incomplete v1beta2 migration - mixed API version usage.

The file imports both clusterv1beta1 (v1beta1) and clusterv1 (v1beta2), but only uses clusterv1beta1 at line 107 for APIEndpoint. Since APIEndpoint has the same structure in v1beta2, complete the migration by updating line 107 to use clusterv1.APIEndpoint and remove the unused clusterv1beta1 import.

-	ibmpowervsv1 "sigs.k8s.io/cluster-api-provider-ibmcloud/api/v1beta2"
-	clusterv1beta1 "sigs.k8s.io/cluster-api/api/core/v1beta1"
-	clusterv1 "sigs.k8s.io/cluster-api/api/core/v1beta2"
+	ibmpowervsv1 "sigs.k8s.io/cluster-api-provider-ibmcloud/api/v1beta2"
+	clusterv1 "sigs.k8s.io/cluster-api/api/core/v1beta2"

And at line 107:

-			ControlPlaneEndpoint: clusterv1beta1.APIEndpoint{
+			ControlPlaneEndpoint: clusterv1.APIEndpoint{
e2e/framework/machine.go (1)

88-88: Copy-paste error in doc comment.

The doc comment says "GetMachine" but the function is GetMachineWithError. This issue was already flagged in a previous review.

pkg/controllers/machinesync/machine_sync_controller.go (1)

268-273: Critical: Timestamp gate prevents InfraMachine creation in intended scenario.

The timestamp check on line 271 (!mapiMachine.CreationTimestamp.After(capiMachine.CreationTimestamp.Time)) blocks the PR's stated objective. When a user creates a CAPI Machine first, then creates a MAPI Machine with authoritativeAPI: ClusterAPI, this condition will be false (MAPI created after CAPI), preventing InfraMachine creation. This matches the QA failure report where no AWSMachine was created.

Apply this diff to enable InfraMachine creation based solely on existence and deletion state:

-		if capiMachine.DeletionTimestamp.IsZero() && mapiMachine.DeletionTimestamp.IsZero() &&
-			!capiInfraMachineExists && !mapiMachine.CreationTimestamp.After(capiMachine.CreationTimestamp.Time) {
+		if capiMachine.DeletionTimestamp.IsZero() && mapiMachine.DeletionTimestamp.IsZero() &&
+			!capiInfraMachineExists {
 			return r.reconcileMAPIMachinetoCAPIMachine(ctx, mapiMachine, capiMachine)
 		}

Note: This issue was previously identified in past review comments.

🧹 Nitpick comments (5)
pkg/conversion/mapi2capi/machineset_test.go (1)

255-255: Consider using consistent pointer comparison pattern.

Line 255 dereferences capiStatus.Replicas before comparing, while lines 123, 209, and 282 compare the pointer directly using Equal(ptr.To(int32(...))). For consistency with the rest of the test, consider:

-			Expect(ptr.Deref(capiStatus.Replicas, 0)).To(Equal(int32(3)))
+			Expect(capiStatus.Replicas).To(Equal(ptr.To(int32(3))))
pkg/conversion/test/fuzz/fuzz.go (1)

749-760: Consider simplifying NodeRef normalization logic.

The two consecutive if m.NodeRef != nil blocks could be combined for clarity:

-				// The only valid node reference is of kind Node and APIVersion v1.
-				if m.NodeRef != nil {
-					m.NodeRef = &corev1.ObjectReference{
-						Kind:       "Node",
-						Name:       m.NodeRef.Name,
-						APIVersion: "v1",
-					}
-				}
-				// Otherwise set it to nil.
-				if m.NodeRef != nil && m.NodeRef.Name == "" {
-					m.NodeRef = nil
-				}
+				// The only valid node reference is of kind Node and APIVersion v1.
+				if m.NodeRef != nil && m.NodeRef.Name != "" {
+					m.NodeRef = &corev1.ObjectReference{
+						Kind:       "Node",
+						Name:       m.NodeRef.Name,
+						APIVersion: "v1",
+					}
+				} else {
+					m.NodeRef = nil
+				}
pkg/controllers/corecluster/corecluster_controller.go (2)

162-162: Consider refactoring the function signature to reduce parameter count.

The function signature is correct but could be simplified. Consider grouping related parameters (APIGroup, Kind) into a struct or using the existing mapping function's return values more directly.

Example refactor:

type InfraClusterReference struct {
    APIGroup string
    Kind     string
    Version  string
}

func (r *CoreClusterController) generateCoreClusterObject(_ context.Context, clusterObjectKey client.ObjectKey, infraRef InfraClusterReference) (*clusterv1.Cluster, error) {

This would make the signature more maintainable if additional infrastructure reference fields are needed in the future.


225-239: LGTM: Platform mapping correctly returns APIGroup.

The function properly maps each platform to its infrastructure cluster kind, version, and API group. The explicit return of capiInfraClusterAPIGroup in each case is correct and maintains clarity.

Optional: The function name mapOCPPlatformToInfraClusterKindAndVersionAndGroup is quite long. Consider a shorter alternative like getInfraClusterReference or mapPlatformToInfraClusterRef, especially if you refactor to return a struct (see comment on line 162).

pkg/controllers/machinesync/machine_sync_controller_test.go (1)

831-852: Context name vs. setup: “owned by a machineset” branch doesn’t set an ownerRef

Inside Context("when the CAPI infra machine resource does not exist")Context("when the MAPI machine is owned by a machineset"), the MachineAPI‑authoritative branch builds the MAPI machine with ownerReferencesToMapiMachineSet, but the ClusterAPI‑authoritative branch later does:

mapiMachine = mapiMachineBuilder.WithName("test-machine").Build()
...
// no WithOwnerReferences(ownerReferencesToMapiMachineSet) here

So in the ClusterAPI‑authoritative tests, the MAPI machine is not actually owned by a MachineSet, despite the enclosing context name. That can be confusing when reasoning about which ownership paths are covered.

If the intention is to validate behavior specifically when a MachineSet owns the MAPI machine, consider also applying ownerReferencesToMapiMachineSet in this branch; otherwise, you might want to tweak the context description to clarify that this sub‑scenario is “without MAPI MachineSet ownership”.

Also applies to: 931-942

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between a8d9b03 and e00163b.

⛔ Files ignored due to path filters (62)
  • e2e/go.sum is excluded by !**/*.sum
  • go.sum is excluded by !**/*.sum
  • go.work is excluded by !**/*.work
  • go.work.sum is excluded by !**/*.sum
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/resourcebuilder/cluster-api/core/v1beta1/cluster.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/resourcebuilder/cluster-api/core/v1beta1/machine.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/resourcebuilder/cluster-api/core/v1beta1/machineset.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/resourcebuilder/cluster-api/core/v1beta2/cluster.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/resourcebuilder/cluster-api/core/v1beta2/machine.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/resourcebuilder/cluster-api/core/v1beta2/machineset.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/resourcebuilder/cluster-api/infrastructure/v1beta1/openstackcluster.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/resourcebuilder/cluster-api/infrastructure/v1beta1/openstackmachine.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/resourcebuilder/cluster-api/infrastructure/v1beta2/awscluster.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/resourcebuilder/cluster-api/infrastructure/v1beta2/awsmachine.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/resourcebuilder/cluster-api/infrastructure/v1beta2/powervscluster.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/resourcebuilder/cluster-api/infrastructure/v1beta2/powervsmachine.go is excluded by !**/vendor/**, !vendor/**
  • vendor/github.com/openshift/cluster-api-actuator-pkg/testutils/tools.go is excluded by !**/vendor/**, !vendor/**
  • vendor/modules.txt is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/controllers/external/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/controllers/external/tracker.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/controllers/external/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/controllers/external/util.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/bootstrap.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/bootstrap_config_template.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/controlplane.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/controlplane_template.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/infrastructure_cluster.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/infrastructure_cluster_template.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/infrastructure_machine.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/infrastructure_machine_template.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/infrastructure_machinepool_template.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/metadata.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/references.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/types.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/internal/contract/version.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/aggregate.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/deprecated/v1beta1/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/deprecated/v1beta1/getter.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/deprecated/v1beta1/matcher.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/deprecated/v1beta1/matchers.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/deprecated/v1beta1/merge.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/deprecated/v1beta1/merge_strategies.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/deprecated/v1beta1/patch.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/deprecated/v1beta1/setter.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/deprecated/v1beta1/unstructured.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/getter.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/matcher.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/merge_strategies.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/mirror.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/options.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/patch.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/setter.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/sort.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/conditions/summary.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/contract/contract.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/contract/doc.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/labels/helpers.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/predicates/cluster_predicates.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/predicates/generic_predicates.go is excluded by !**/vendor/**, !vendor/**
  • vendor/sigs.k8s.io/cluster-api/util/version/version.go is excluded by !**/vendor/**, !vendor/**
📒 Files selected for processing (87)
  • .golangci.yml (1 hunks)
  • cmd/cluster-capi-operator/main.go (3 hunks)
  • cmd/machine-api-migration/main.go (2 hunks)
  • e2e/aws_test.go (2 hunks)
  • e2e/azure_test.go (3 hunks)
  • e2e/baremetal_test.go (3 hunks)
  • e2e/e2e_common.go (3 hunks)
  • e2e/framework/cluster.go (3 hunks)
  • e2e/framework/machine.go (6 hunks)
  • e2e/framework/machineset.go (13 hunks)
  • e2e/framework/node.go (1 hunks)
  • e2e/gcp_test.go (3 hunks)
  • e2e/go.mod (1 hunks)
  • e2e/machine_migration_capi_authoritative_test.go (9 hunks)
  • e2e/machine_migration_helpers.go (7 hunks)
  • e2e/machine_migration_mapi_authoritative_test.go (8 hunks)
  • e2e/machineset_migration_capi_authoritative_test.go (8 hunks)
  • e2e/machineset_migration_helpers.go (10 hunks)
  • e2e/machineset_migration_mapi_authoritative_test.go (10 hunks)
  • e2e/migration_common.go (2 hunks)
  • e2e/openstack_test.go (3 hunks)
  • e2e/powervs_test.go (3 hunks)
  • e2e/vsphere_test.go (5 hunks)
  • go.mod (1 hunks)
  • manifests/0000_30_cluster-api_09_admission-policies.yaml (7 hunks)
  • manifests/0000_30_cluster-api_10_webhooks.yaml (1 hunks)
  • pkg/controllers/corecluster/corecluster_controller.go (11 hunks)
  • pkg/controllers/corecluster/corecluster_controller_test.go (6 hunks)
  • pkg/controllers/infracluster/aws.go (2 hunks)
  • pkg/controllers/infracluster/azure.go (3 hunks)
  • pkg/controllers/infracluster/gcp.go (2 hunks)
  • pkg/controllers/infracluster/infracluster_controller.go (2 hunks)
  • pkg/controllers/infracluster/infracluster_controller_test.go (9 hunks)
  • pkg/controllers/infracluster/metal3.go (2 hunks)
  • pkg/controllers/infracluster/powervs.go (2 hunks)
  • pkg/controllers/infracluster/vsphere.go (2 hunks)
  • pkg/controllers/kubeconfig/kubeconfig.go (2 hunks)
  • pkg/controllers/machinemigration/machine_migration_controller.go (8 hunks)
  • pkg/controllers/machinemigration/machine_migration_controller_test.go (12 hunks)
  • pkg/controllers/machinesetmigration/machineset_migration_controller.go (6 hunks)
  • pkg/controllers/machinesetmigration/machineset_migration_controller_test.go (11 hunks)
  • pkg/controllers/machinesetsync/machineset_sync_controller.go (34 hunks)
  • pkg/controllers/machinesetsync/machineset_sync_controller_test.go (15 hunks)
  • pkg/controllers/machinesetsync/machineset_sync_controller_unit_test.go.bak (1 hunks)
  • pkg/controllers/machinesetsync/machineset_vap_test.go (10 hunks)
  • pkg/controllers/machinesync/aws_test.go (4 hunks)
  • pkg/controllers/machinesync/machine_sync_controller.go (34 hunks)
  • pkg/controllers/machinesync/machine_sync_controller_test.go (39 hunks)
  • pkg/controllers/machinesync/machine_sync_controller_unit_test.go (1 hunks)
  • pkg/controllers/machinesync/machine_sync_mapi2capi_infrastructure.go (3 hunks)
  • pkg/conversion/capi2mapi/aws.go (5 hunks)
  • pkg/conversion/capi2mapi/aws_fuzz_test.go (4 hunks)
  • pkg/conversion/capi2mapi/aws_test.go (1 hunks)
  • pkg/conversion/capi2mapi/common.go (4 hunks)
  • pkg/conversion/capi2mapi/machine.go (8 hunks)
  • pkg/conversion/capi2mapi/machine_test.go (4 hunks)
  • pkg/conversion/capi2mapi/machineset.go (4 hunks)
  • pkg/conversion/capi2mapi/machineset_test.go (3 hunks)
  • pkg/conversion/capi2mapi/openstack.go (4 hunks)
  • pkg/conversion/capi2mapi/openstack_fuzz_test.go (4 hunks)
  • pkg/conversion/capi2mapi/openstack_test.go (1 hunks)
  • pkg/conversion/capi2mapi/powervs.go (3 hunks)
  • pkg/conversion/capi2mapi/powervs_fuzz_test.go (4 hunks)
  • pkg/conversion/capi2mapi/powervs_test.go (2 hunks)
  • pkg/conversion/capi2mapi/suite_test.go (2 hunks)
  • pkg/conversion/mapi2capi/aws.go (9 hunks)
  • pkg/conversion/mapi2capi/aws_fuzz_test.go (3 hunks)
  • pkg/conversion/mapi2capi/interface.go (1 hunks)
  • pkg/conversion/mapi2capi/machine.go (15 hunks)
  • pkg/conversion/mapi2capi/machine_test.go (24 hunks)
  • pkg/conversion/mapi2capi/machineset.go (8 hunks)
  • pkg/conversion/mapi2capi/machineset_test.go (9 hunks)
  • pkg/conversion/mapi2capi/openstack.go (8 hunks)
  • pkg/conversion/mapi2capi/openstack_fuzz_test.go (3 hunks)
  • pkg/conversion/mapi2capi/powervs.go (7 hunks)
  • pkg/conversion/mapi2capi/powervs_fuzz_test.go (3 hunks)
  • pkg/conversion/mapi2capi/util.go (6 hunks)
  • pkg/conversion/test/fuzz/fuzz.go (19 hunks)
  • pkg/conversion/test/matchers/capi_condition.go (3 hunks)
  • pkg/conversion/util/util.go (1 hunks)
  • pkg/test/crdbuilder.go (4 hunks)
  • pkg/test/envtest.go (2 hunks)
  • pkg/util/conditions.go (3 hunks)
  • pkg/util/sync.go (8 hunks)
  • pkg/util/sync_test.go (5 hunks)
  • pkg/util/watch_filters.go (2 hunks)
  • pkg/webhook/cluster.go (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (29)
  • pkg/controllers/infracluster/metal3.go
  • pkg/controllers/infracluster/vsphere.go
  • pkg/controllers/machinesync/machine_sync_controller_unit_test.go
  • pkg/conversion/capi2mapi/openstack_test.go
  • pkg/controllers/infracluster/infracluster_controller.go
  • e2e/vsphere_test.go
  • pkg/util/watch_filters.go
  • pkg/conversion/mapi2capi/util.go
  • pkg/controllers/machinesetsync/machineset_sync_controller_unit_test.go.bak
  • pkg/controllers/machinesync/machine_sync_mapi2capi_infrastructure.go
  • e2e/e2e_common.go
  • pkg/conversion/mapi2capi/openstack_fuzz_test.go
  • e2e/machineset_migration_capi_authoritative_test.go
  • e2e/framework/node.go
  • pkg/conversion/mapi2capi/powervs_fuzz_test.go
  • cmd/machine-api-migration/main.go
  • e2e/azure_test.go
  • pkg/conversion/capi2mapi/openstack.go
  • pkg/conversion/util/util.go
  • .golangci.yml
  • go.mod
  • e2e/framework/machineset.go
  • pkg/controllers/infracluster/azure.go
  • pkg/conversion/mapi2capi/interface.go
  • e2e/openstack_test.go
  • pkg/conversion/capi2mapi/machineset_test.go
  • manifests/0000_30_cluster-api_10_webhooks.yaml
  • pkg/webhook/cluster.go
  • pkg/conversion/test/matchers/capi_condition.go
🧰 Additional context used
🧬 Code graph analysis (26)
pkg/controllers/machinesetmigration/machineset_migration_controller.go (2)
pkg/conversion/mapi2capi/interface.go (1)
  • MachineSet (29-31)
e2e/framework/framework.go (1)
  • CAPINamespace (14-14)
e2e/aws_test.go (1)
pkg/conversion/mapi2capi/interface.go (1)
  • MachineSet (29-31)
e2e/machine_migration_helpers.go (2)
pkg/conversion/mapi2capi/interface.go (1)
  • Machine (24-26)
e2e/framework/machine.go (2)
  • GetMachineWithError (89-102)
  • GetMachine (75-86)
pkg/conversion/mapi2capi/machineset_test.go (1)
pkg/conversion/test/matchers/capi_condition.go (1)
  • MatchCAPICondition (51-55)
e2e/powervs_test.go (1)
pkg/conversion/mapi2capi/interface.go (1)
  • MachineSet (29-31)
pkg/conversion/mapi2capi/machineset.go (1)
pkg/conversion/mapi2capi/interface.go (1)
  • MachineSet (29-31)
e2e/gcp_test.go (1)
pkg/conversion/mapi2capi/interface.go (1)
  • MachineSet (29-31)
pkg/conversion/mapi2capi/aws_fuzz_test.go (1)
pkg/conversion/mapi2capi/interface.go (2)
  • Machine (24-26)
  • MachineSet (29-31)
e2e/machine_migration_mapi_authoritative_test.go (1)
pkg/conversion/mapi2capi/interface.go (1)
  • Machine (24-26)
pkg/controllers/machinemigration/machine_migration_controller.go (4)
pkg/conversion/mapi2capi/interface.go (1)
  • Machine (24-26)
e2e/framework/framework.go (1)
  • CAPINamespace (14-14)
pkg/util/conditions.go (1)
  • GetConditionStatus (88-99)
pkg/util/annotations.go (1)
  • RemoveAnnotation (27-39)
e2e/framework/cluster.go (1)
e2e/framework/framework.go (1)
  • CAPINamespace (14-14)
e2e/framework/machine.go (2)
pkg/conversion/mapi2capi/interface.go (1)
  • Machine (24-26)
e2e/framework/framework.go (2)
  • WaitLong (25-25)
  • RetryMedium (18-18)
pkg/conversion/capi2mapi/openstack_fuzz_test.go (1)
pkg/conversion/test/fuzz/fuzz.go (2)
  • CAPIMachineFuzzerFuncs (475-546)
  • CAPIMachineSetFuzzerFuncs (549-626)
pkg/controllers/machinesetsync/machineset_vap_test.go (1)
pkg/conversion/mapi2capi/interface.go (2)
  • MachineSet (29-31)
  • Machine (24-26)
pkg/controllers/machinesync/aws_test.go (1)
pkg/conversion/mapi2capi/interface.go (1)
  • Machine (24-26)
pkg/controllers/machinesync/machine_sync_controller_test.go (3)
pkg/conversion/mapi2capi/interface.go (2)
  • Machine (24-26)
  • MachineSet (29-31)
e2e/migration_common.go (1)
  • SynchronizedCondition (10-10)
pkg/controllers/common_consts.go (1)
  • SynchronizedCondition (41-41)
e2e/machineset_migration_mapi_authoritative_test.go (2)
pkg/conversion/mapi2capi/interface.go (1)
  • MachineSet (29-31)
e2e/framework/framework.go (3)
  • WaitMedium (24-24)
  • RetryShort (17-17)
  • WaitShort (23-23)
pkg/conversion/mapi2capi/machine_test.go (1)
pkg/conversion/test/matchers/capi_condition.go (1)
  • MatchCAPICondition (51-55)
pkg/conversion/mapi2capi/aws.go (1)
pkg/conversion/mapi2capi/interface.go (2)
  • Machine (24-26)
  • MachineSet (29-31)
pkg/controllers/machinesync/machine_sync_controller.go (5)
pkg/conversion/mapi2capi/interface.go (1)
  • Machine (24-26)
pkg/controllers/common.go (1)
  • InitInfraMachineAndInfraClusterFromProvider (41-52)
e2e/framework/framework.go (1)
  • CAPINamespace (14-14)
pkg/util/finalizer.go (1)
  • RemoveFinalizer (60-85)
pkg/util/conditions.go (2)
  • EnsureCAPIDeprecatedV1Beta1Conditions (246-255)
  • EnsureCAPIConditions (258-267)
pkg/controllers/machinesetmigration/machineset_migration_controller_test.go (1)
pkg/conversion/mapi2capi/interface.go (2)
  • MachineSet (29-31)
  • Machine (24-26)
pkg/conversion/mapi2capi/machine.go (1)
pkg/conversion/mapi2capi/interface.go (1)
  • Machine (24-26)
pkg/conversion/capi2mapi/aws.go (3)
pkg/conversion/capi2mapi/interface.go (2)
  • MachineAndInfrastructureMachine (21-23)
  • MachineSetAndMachineTemplate (26-28)
pkg/conversion/consts/consts.go (1)
  • MAPIMachineMetadataLabelZone (26-26)
third_party/sigs.k8s.io/cluster-api/util/util.go (1)
  • IsControlPlaneMachine (25-28)
pkg/conversion/capi2mapi/aws_fuzz_test.go (1)
pkg/conversion/test/fuzz/fuzz.go (2)
  • CAPIMachineFuzzerFuncs (475-546)
  • CAPIMachineSetFuzzerFuncs (549-626)
pkg/conversion/test/fuzz/fuzz.go (2)
pkg/conversion/mapi2capi/interface.go (2)
  • Machine (24-26)
  • MachineSet (29-31)
pkg/conversion/capi2mapi/interface.go (2)
  • MachineAndInfrastructureMachine (21-23)
  • MachineSetAndMachineTemplate (26-28)
pkg/controllers/machinesetsync/machineset_sync_controller.go (3)
pkg/conversion/mapi2capi/interface.go (1)
  • MachineSet (29-31)
pkg/util/conditions.go (2)
  • EnsureCAPIDeprecatedV1Beta1Conditions (246-255)
  • EnsureCAPIConditions (258-267)
pkg/util/finalizer.go (1)
  • RemoveFinalizer (60-85)

Comment on lines 44 to 45
MinReadySeconds: ptr.Deref(capiMachineSet.Spec.Template.Spec.MinReadySeconds, 0),
DeletePolicy: string(capiMachineSet.Spec.Deletion.Order),
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential nil pointer dereference when accessing Deletion.Order.

If capiMachineSet.Spec.Deletion is nil, accessing Deletion.Order will cause a panic. Consider adding a nil guard or using ptr.Deref pattern similar to the MinReadySeconds handling.

-			MinReadySeconds: ptr.Deref(capiMachineSet.Spec.Template.Spec.MinReadySeconds, 0),
-			DeletePolicy:    string(capiMachineSet.Spec.Deletion.Order),
+			MinReadySeconds: ptr.Deref(capiMachineSet.Spec.Template.Spec.MinReadySeconds, 0),
+			DeletePolicy:    getDeletionOrder(capiMachineSet.Spec.Deletion),

Add a helper function:

func getDeletionOrder(deletion *clusterv1.MachineSetDeletionSpec) string {
	if deletion == nil {
		return ""
	}
	return string(deletion.Order)
}
🤖 Prompt for AI Agents
In pkg/conversion/capi2mapi/machineset.go around lines 44 to 45, accessing
capiMachineSet.Spec.Deletion.Order can panic if Spec.Deletion is nil; update the
code to guard against nil by adding a helper that returns an empty string when
Deletion is nil (e.g., getDeletionOrder(deletion
*clusterv1.MachineSetDeletionSpec) string) and replace direct access with a call
to that helper so DeletePolicy :=
getDeletionOrder(capiMachineSet.Spec.Deletion).

gcpv1 "sigs.k8s.io/cluster-api-provider-gcp/api/v1beta1"
openstackv1 "sigs.k8s.io/cluster-api-provider-openstack/api/v1beta1"
clusterv1beta1 "sigs.k8s.io/cluster-api/api/core/v1beta1"
clusterv1 "sigs.k8s.io/cluster-api/api/core/v1beta2"
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check for remaining v1beta1 references to ensure migration consistency

echo "=== Checking for remaining v1beta1 imports ==="
rg -n 'cluster-api/api/core/v1beta1' --type=go

echo "=== Checking for clusterv1beta1 alias usage ==="
rg -n '\bclusterv1beta1\b' --type=go

echo "=== Overview of all v1beta imports in the repo ==="
rg -n 'cluster-api/api/core/v1beta' --type=go | head -20

Repository: openshift/cluster-capi-operator

Length of output: 6595


🌐 Web query:

Cluster API v1beta2 release notes breaking changes

💡 Result:

Key breaking changes introduced with the v1beta2 API (and in Cluster API v1.11 series where v1beta2 became storage) — concise summary:

  • API/CRD contract changes: fields made required or renamed (e.g., KubeadmControlPlane.rolloutStrategy.type becomes required in v1beta2 causing conversion failures from v1beta1 if omitted). (github.com)
  • Status model changes: switch to Kubernetes-aligned metav1.Conditions, removal of FailureReason/FailureMessage, and standardized/changed replica counters and status semantics. (cluster-api.sigs.k8s.io)
  • Object reference changes: some fields removed/changed to be GitOps-friendly (API version not overwritten). (cluster-api.sigs.k8s.io)
  • Provider/runtime SDK changes: Runtime SDK behavioral changes (e.g., chained upgrade observability and AfterClusterUpgrade hook made blocking) noted as breaking. (github.com)
  • Tooling/dependency bumps and operational changes: controller-runtime/controller-tools version bumps and clusterctl behavior changes (e.g., blocking move when Cluster or ClusterClass is paused); CI and other infra changes flagged as breaking. (github.com)

If you want, I can:

  • list every CRD/field changed in v1beta2 with example diffs, or
  • fetch the full v1.11 (v1beta2) release notes and link each breaking-change PR.

Citations:


Incomplete cluster-api version migration creates version mismatch between test environment and infrastructure controllers.

The migration from v1beta1 to v1beta2 in pkg/test/envtest.go is mechanically correct, but the codebase migration is incomplete. Infrastructure controllers (pkg/controllers/infracluster/{aws,gcp,azure,openstack,powervs}.go) and other files remain on v1beta1, creating a version mismatch with the v1beta2 test environment. v1beta2 introduces breaking changes to status models (metav1.Conditions, removal of FailureReason/FailureMessage), which could cause compatibility issues. Before merging, complete the migration of all infrastructure controllers to v1beta2 to ensure consistency and avoid contributing to InfraMachine creation failures.

🤖 Prompt for AI Agents
In pkg/test/envtest.go around line 37, the test environment was migrated to
cluster-api v1beta2 but several infrastructure controllers still use v1beta1,
causing a version mismatch; update all infracluster controllers
(pkg/controllers/infracluster/{aws,gcp,azure,openstack,powervs}.go) and any
other files still importing sigs.k8s.io/cluster-api/api/core/v1beta1 to use
sigs.k8s.io/cluster-api/api/core/v1beta2, then adapt code to v1beta2 breaking
changes: replace Usage of FailureReason/FailureMessage with metav1.Conditions
for status, update status types and getters/setters, adjust any helper functions
and RBAC/CRD references accordingly, run go mod tidy to update deps and run
unit/integration tests to confirm InfraMachine creation and controller behaviors
are consistent with v1beta2.

@chrischdi chrischdi force-pushed the pr-machinesync-create-inframachine-if-not-exists branch from e00163b to 8c6f770 Compare December 16, 2025 19:14
@sunzhaohua2
Copy link
Contributor

/retest

@chrischdi chrischdi force-pushed the pr-machinesync-create-inframachine-if-not-exists branch from 8c6f770 to b30800f Compare December 22, 2025 14:43
Copy link

@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

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between e00163b and b30800f.

📒 Files selected for processing (3)
  • pkg/controllers/machinesync/machine_sync_controller.go
  • pkg/controllers/machinesync/machine_sync_controller_test.go
  • pkg/controllers/machinesync/machine_sync_controller_unit_test.go
🧰 Additional context used
🧬 Code graph analysis (3)
pkg/controllers/machinesync/machine_sync_controller_test.go (2)
e2e/migration_common.go (1)
  • SynchronizedCondition (10-10)
pkg/controllers/common_consts.go (1)
  • SynchronizedCondition (41-41)
pkg/controllers/machinesync/machine_sync_controller_unit_test.go (2)
pkg/controllers/machinesync/machine_sync_controller.go (1)
  • MachineSyncReconciler (136-145)
pkg/conversion/mapi2capi/interface.go (1)
  • Machine (24-26)
pkg/controllers/machinesync/machine_sync_controller.go (2)
pkg/controllers/common.go (1)
  • InitInfraMachineAndInfraClusterFromProvider (41-52)
e2e/framework/framework.go (1)
  • CAPINamespace (14-14)
🔇 Additional comments (6)
pkg/controllers/machinesync/machine_sync_controller.go (5)

254-258: LGTM: Infrastructure existence check.

The existence check is well-placed before routing reconciliation paths. Error handling is appropriate and the comment clearly explains the intent.


997-1038: LGTM: Refactored infra resource fetching with proper delegation.

The refactoring cleanly separates infraMachine retrieval into a dedicated helper while maintaining proper error handling. The terminal configuration error checks ensure user intervention is required for misconfigured resources.


1040-1058: LGTM: Clean helper for fetching infra machines.

The helper properly handles the NotFound case by returning nil for the infraMachine while propagating other errors. This allows calling code to distinguish between "not found" (nil) and "error retrieving" scenarios.


1060-1076: LGTM: Existence check with sensible fallback.

The helper properly handles the nil capiMachine case by falling back to the MAPI machine's name. This allows the existence check to work in scenarios where the CAPI machine hasn't been created yet.


266-271: The timestamp check is correctly designed and serves the authoritativeAPI contract.

The condition at line 269 is a guard, not a blocker for all scenarios. The control flow has two distinct paths:

  1. When CAPI Machine doesn't exist (capiMachineNotFound == true): The timestamp check is bypassed entirely—MAPI can create CAPI infrastructure without restriction.

  2. When CAPI Machine exists (!capiMachineNotFound): The timestamp check prevents MAPI (created after CAPI) from creating CAPI infrastructure. Instead, the code delegates to reconcileCAPIMachinetoMAPIMachine, which syncs from the authoritative CAPI Machine to MAPI.

This design correctly enforces the authoritativeAPI: ClusterAPI contract: a MAPI Machine created after an existing CAPI Machine should not attempt to create infrastructure, since the CAPI Machine is the source of truth and should already have its infrastructure provisioned. The timestamp gate prevents duplicate or conflicting infrastructure creation when MAPI is created as a mirror of existing CAPI resources.

The scenario described in the review comment—CAPI created first, then MAPI created later with authoritativeAPI: ClusterAPI—is intentionally prevented from triggering InfraMachine creation through the MAPI path. This is the correct behavior.

pkg/controllers/machinesync/machine_sync_controller_unit_test.go (1)

30-118: LGTM: Comprehensive unit tests for infra resource fetching.

The test cases properly cover all scenarios:

  1. Nil machine input → no resources returned
  2. Missing cluster → error with appropriate message
  3. Missing infra machine → cluster returned, machine nil
  4. All present → both returned

The tests use appropriate fake clients and validate both success and error paths.

Comment on lines +992 to 1005
It("should create the Cluster API InfraMachine", func() {
Eventually(k.Object(mapiMachine), timeout).Should(
HaveField("Status.Conditions", ContainElement(
SatisfyAll(
HaveField("Type", Equal(consts.SynchronizedCondition)),
HaveField("Status", Equal(corev1.ConditionFalse)),
HaveField("Reason", Equal("FailedToConvertCAPIMachineToMAPI")),
HaveField("Message", ContainSubstring("unexpected InfraMachine type, expected AWSMachine, got <nil>")),
HaveField("Status", Equal(corev1.ConditionTrue)),
HaveField("Reason", Equal("ResourceSynchronized")),
HaveField("Message", ContainSubstring("Successfully synchronized CAPI Machine to MAPI")),
))),
)

capiInfraMachine := awsv1resourcebuilder.AWSMachine().WithName(mapiMachine.Name).WithNamespace(capiNamespace.Name).Build()
Eventually(k.Get(capiInfraMachine), timeout).Should(Succeed())
})
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Verify the synchronization message direction.

The test expects the message to contain "Successfully synchronized CAPI Machine to MAPI" (line 999), but the context is "when the MAPI machine has MachineAuthority set to Cluster API" with a missing InfraMachine. According to the controller code at line 270 in machine_sync_controller.go, this scenario calls reconcileMAPIMachinetoCAPIMachine, which should set the message to messageSuccessfullySynchronizedMAPItoCAPI (line 608: "Successfully synchronized MAPI Machine to CAPI").

The test assertion should expect "MAPI Machine to CAPI" not "CAPI Machine to MAPI".

🔎 Proposed fix
 It("should create the Cluster API InfraMachine", func() {
     Eventually(k.Object(mapiMachine), timeout).Should(
         HaveField("Status.Conditions", ContainElement(
             SatisfyAll(
                 HaveField("Type", Equal(consts.SynchronizedCondition)),
                 HaveField("Status", Equal(corev1.ConditionTrue)),
                 HaveField("Reason", Equal("ResourceSynchronized")),
-                HaveField("Message", ContainSubstring("Successfully synchronized CAPI Machine to MAPI")),
+                HaveField("Message", Equal("Successfully synchronized MAPI Machine to CAPI")),
             ))),
     )

     capiInfraMachine := awsv1resourcebuilder.AWSMachine().WithName(mapiMachine.Name).WithNamespace(capiNamespace.Name).Build()
     Eventually(k.Get(capiInfraMachine), timeout).Should(Succeed())
 })
🤖 Prompt for AI Agents
In pkg/controllers/machinesync/machine_sync_controller_test.go around lines 992
to 1005, the test asserts the wrong synchronization message direction; update
the expected message substring from "Successfully synchronized CAPI Machine to
MAPI" to "Successfully synchronized MAPI Machine to CAPI" so the assertion
matches the controller path reconcileMAPIMachinetoCAPIMachine and the
messageSuccessfullySynchronizedMAPItoCAPI constant; leave the rest of the
assertion intact and run tests to verify.

@chrischdi
Copy link
Contributor Author

/pipeline required

@openshift-ci-robot
Copy link

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-aws-capi-techpreview
/test e2e-aws-ovn
/test e2e-aws-ovn-serial-1of2
/test e2e-aws-ovn-serial-2of2
/test e2e-aws-ovn-techpreview
/test e2e-aws-ovn-techpreview-upgrade
/test e2e-azure-capi-techpreview
/test e2e-azure-ovn-techpreview
/test e2e-azure-ovn-techpreview-upgrade
/test e2e-gcp-capi-techpreview
/test e2e-gcp-ovn-techpreview
/test e2e-metal3-capi-techpreview
/test e2e-openstack-capi-techpreview
/test e2e-openstack-ovn-techpreview
/test e2e-vsphere-capi-techpreview
/test regression-clusterinfra-aws-ipi-techpreview-capi

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Dec 23, 2025

@chrischdi: 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-metal3-capi-techpreview b30800f link false /test e2e-metal3-capi-techpreview
ci/prow/e2e-aws-ovn-techpreview-upgrade b30800f link true /test e2e-aws-ovn-techpreview-upgrade

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.

@damdo damdo force-pushed the pr-machinesync-create-inframachine-if-not-exists branch from b30800f to 8f1feea Compare January 15, 2026 10:16
@openshift-ci-robot
Copy link

@chrischdi: This pull request references Jira Issue OCPBUGS-63411, which is invalid:

  • expected the bug to target either version "4.22." or "openshift-4.22.", but it targets "4.21" instead

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

Details

In response to this:

Summary by CodeRabbit

  • Bug Fixes

  • Improved machine synchronization to create and reconcile the Cluster API infrastructure machine when it is missing, avoiding synchronization failures and nil-pointer issues.

  • Refined infra resource fetching and error handling for more stable reconciliation sequencing.

  • Tests

  • Updated end-to-end tests to expect successful infra creation and synchronization.

  • Added unit tests covering infra resource presence/absence scenarios.

✏️ Tip: You can customize this high-level summary in your review settings.

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.

Copy link

@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

♻️ Duplicate comments (1)
pkg/controllers/machinesync/machine_sync_controller.go (1)

266-271: Timestamp gate blocks intended InfraMachine creation flow.

The condition !mapiMachine.CreationTimestamp.After(capiMachine.CreationTimestamp.Time) prevents InfraMachine creation when the MAPI Machine is created after the CAPI Machine. This matches the QA failure where creating a CAPI Machine first, then a MAPI Machine with authoritativeAPI: ClusterAPI, results in no InfraMachine being created.

Per the PR objective (scenario 1: "creating a MAPI Machine with CAPI authoritative should produce a CAPI Machine and an InfraMachine from the MAPI Machine"), consider removing the timestamp comparison:

Suggested fix
-		// Create Cluster API Infrastructure Machine from MAPI if it doesn't exist and no deletion is in progress.
-		// the CAPI machine is not marked for deletion and the MAPI machine was created before the Cluster API machine.
-		if capiMachine.DeletionTimestamp.IsZero() && mapiMachine.DeletionTimestamp.IsZero() &&
-			!capiInfraMachineExists && !mapiMachine.CreationTimestamp.After(capiMachine.CreationTimestamp.Time) {
+		// Create Cluster API Infrastructure Machine from MAPI if it doesn't exist and no deletion is in progress.
+		if capiMachine.DeletionTimestamp.IsZero() && mapiMachine.DeletionTimestamp.IsZero() &&
+			!capiInfraMachineExists {
 			return r.reconcileMAPIMachinetoCAPIMachine(ctx, mapiMachine, capiMachine)
 		}
🧹 Nitpick comments (1)
pkg/controllers/machinesync/machine_sync_controller.go (1)

1040-1058: Consider avoiding duplicate InitInfraMachineAndInfraClusterFromProvider calls.

When fetchCAPIInfraResources calls fetchCAPIInfraMachine (line 1032), InitInfraMachineAndInfraClusterFromProvider is invoked twice: once at line 1023 and again at line 1041. While not incorrect, passing the already-initialized infraMachine type or extracting the initialization could reduce redundancy.

Optional refactor
 func (r *MachineSyncReconciler) fetchCAPIInfraResources(ctx context.Context, capiMachine *clusterv1.Machine) (client.Object, client.Object, error) {
 	if capiMachine == nil {
 		return nil, nil, nil
 	}

-	var infraCluster client.Object
+	infraMachine, infraCluster, err := controllers.InitInfraMachineAndInfraClusterFromProvider(r.Platform)
+	if err != nil {
+		return nil, nil, fmt.Errorf("unable to devise Cluster API infra resources: %w", err)
+	}

 	infraClusterKey := client.ObjectKey{
 		Namespace: capiMachine.Namespace,
 		Name:      capiMachine.Spec.ClusterName,
 	}

 	infraMachineRef := capiMachine.Spec.InfrastructureRef

 	// Validate that required references are not empty...
 	if capiMachine.Spec.ClusterName == "" {
 		return nil, nil, fmt.Errorf("machine %s/%s: %w",
 			capiMachine.Namespace, capiMachine.Name, errInvalidInfraClusterReference)
 	}

 	if infraMachineRef.Name == "" {
 		return nil, nil, fmt.Errorf("machine %s/%s: %w",
 			capiMachine.Namespace, capiMachine.Name, errInvalidInfraMachineReference)
 	}

-	_, infraCluster, err := controllers.InitInfraMachineAndInfraClusterFromProvider(r.Platform)
-	if err != nil {
-		return nil, nil, fmt.Errorf("unable to devise Cluster API infra resources: %w", err)
-	}

 	if err := r.Get(ctx, infraClusterKey, infraCluster); err != nil {
 		return nil, nil, fmt.Errorf("failed to get Cluster API infrastructure cluster: %w", err)
 	}

-	infraMachine, err := r.fetchCAPIInfraMachine(ctx, infraMachineRef.Name, capiMachine.Namespace)
-	if err != nil {
-		return nil, nil, fmt.Errorf("failed to fetch Cluster API infrastructure machine: %w", err)
+	infraMachineKey := client.ObjectKey{
+		Namespace: capiMachine.Namespace,
+		Name:      infraMachineRef.Name,
 	}

+	if err := r.Get(ctx, infraMachineKey, infraMachine); err != nil && !apierrors.IsNotFound(err) {
+		return nil, nil, fmt.Errorf("failed to get Cluster API infrastructure machine: %w", err)
+	} else if apierrors.IsNotFound(err) {
+		infraMachine = nil
+	}
+
 	return infraCluster, infraMachine, nil
 }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between b30800f and 8f1feea.

📒 Files selected for processing (3)
  • pkg/controllers/machinesync/machine_sync_controller.go
  • pkg/controllers/machinesync/machine_sync_controller_test.go
  • pkg/controllers/machinesync/machine_sync_controller_unit_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • pkg/controllers/machinesync/machine_sync_controller_test.go
  • pkg/controllers/machinesync/machine_sync_controller_unit_test.go
🧰 Additional context used
🧬 Code graph analysis (1)
pkg/controllers/machinesync/machine_sync_controller.go (2)
pkg/controllers/common.go (1)
  • InitInfraMachineAndInfraClusterFromProvider (41-52)
e2e/framework/framework.go (1)
  • CAPINamespace (14-14)
🔇 Additional comments (2)
pkg/controllers/machinesync/machine_sync_controller.go (2)

254-258: LGTM on the existence check.

The existence check is properly placed after confirming mapiMachine is not nil, and doesCAPIInfraMachineExist correctly handles nil capiMachine by falling back to mapiMachine.Name.


1002-1037: Clean refactoring of infrastructure resource fetching.

The separation of fetchCAPIInfraMachine from fetchCAPIInfraResources improves modularity. The return order (infraCluster, infraMachine) is consistent with call sites at lines 305 and 440.

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

Comment on lines +1060 to 1076
// doesCAPIInfraMachineExist checks if the Cluster API Infrastructure Machine exists. It uses the infrastructureRef of the Cluster API Machine with fallback to the name of the MAPI Machine.
func (r *MachineSyncReconciler) doesCAPIInfraMachineExist(ctx context.Context, capiMachine *clusterv1.Machine, mapiMachine *mapiv1beta1.Machine) (bool, error) {
namespace := r.CAPINamespace
name := mapiMachine.Name

if capiMachine != nil {
name = capiMachine.Spec.InfrastructureRef.Name
namespace = capiMachine.Namespace
}

infraMachine, err := r.fetchCAPIInfraMachine(ctx, name, namespace)
if err != nil {
return false, fmt.Errorf("checking existence: %w", err)
}

return infraMachine != nil, nil
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Consider validating InfrastructureRef.Name when capiMachine is not nil.

When capiMachine is not nil but capiMachine.Spec.InfrastructureRef.Name is empty, the method will search for an infra machine with an empty name, which could return misleading results. Consider adding validation or falling back to mapiMachine.Name:

Suggested fix
 func (r *MachineSyncReconciler) doesCAPIInfraMachineExist(ctx context.Context, capiMachine *clusterv1.Machine, mapiMachine *mapiv1beta1.Machine) (bool, error) {
 	namespace := r.CAPINamespace
 	name := mapiMachine.Name

-	if capiMachine != nil {
+	if capiMachine != nil && capiMachine.Spec.InfrastructureRef.Name != "" {
 		name = capiMachine.Spec.InfrastructureRef.Name
 		namespace = capiMachine.Namespace
 	}

 	infraMachine, err := r.fetchCAPIInfraMachine(ctx, name, namespace)
 	if err != nil {
 		return false, fmt.Errorf("checking existence: %w", err)
 	}

 	return infraMachine != nil, nil
 }

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

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. jira/invalid-bug Indicates that a referenced Jira bug is invalid for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants