SPLAT-2410: Introduce Cluster API for OpenShift Installations on vSphere#455
SPLAT-2410: Introduce Cluster API for OpenShift Installations on vSphere#455AnnaZivkovic wants to merge 7 commits intoopenshift:mainfrom
Conversation
|
Pipeline controller notification For optional jobs, comment This repository is configured in: LGTM mode |
|
@AnnaZivkovic: This pull request references SPLAT-2410 which is a valid jira issue. Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.22.0" version, but no target version was set. DetailsIn response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds vSphere platform support and feature‑gate driven startup: registers the VSphere API scheme; implements bidirectional MAPI↔CAPI vSphere converters, controller platform branches, v1beta2 condition helpers, and extensive unit + fuzz tests; feature gates now control vSphere controller startup. Changes
Sequence Diagram(s)sequenceDiagram
participant Admin as Administrator
participant CAPI as CAPI (VSphereMachine / Template)
participant MigCtrl as Migration Controller
participant C2M as CAPI→MAPI Converter
participant MAPI as MAPI (Machine / ProviderSpec)
participant Cluster as Target Cluster
Admin->>CAPI: Create/Modify VSphere CAPI resources
CAPI->>MigCtrl: Controller watch / reconcile
MigCtrl->>C2M: FromMachineAndVSphereMachineAndVSphereCluster(...)
C2M->>C2M: Parse CAPV spec (networks, disks, clone, workspace)
C2M->>MAPI: Emit MAPI Machine + ProviderSpec
MigCtrl->>Cluster: Apply MAPI Machine
Cluster->>Admin: Provisioning outcome
sequenceDiagram
participant Admin as Administrator
participant Cluster as MAPI (Machine with vSphere ProviderSpec)
participant SyncCtrl as Sync Controller
participant Parser as ProviderSpec Parser
participant M2C as MAPI→CAPI Converter
participant CAPI as CAPI (VSphereMachine / Template)
Admin->>Cluster: Create MAPI Machine with vSphere ProviderSpec
Cluster->>SyncCtrl: Controller reconcile
SyncCtrl->>Parser: ProviderSpecFromRawExtension(...)
Parser->>M2C: vSphere provider parsed
M2C->>M2C: Build VSphereMachine and Template, validate
M2C->>CAPI: Return CAPI Machine + Template
SyncCtrl->>CAPI: Create/Update CAPI resources
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
@AnnaZivkovic: This pull request references SPLAT-2410 which is a valid jira issue. Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.22.0" version, but no target version was set. DetailsIn response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In `@pkg/controllers/machinesetsync/machineset_sync_controller.go`:
- Around line 395-400: The loop that appends pointers uses &template (range
variable) which causes pointer aliasing so every entry in outdatedTemplates
points to the same item; change the iteration to index-based access (e.g., for i
:= range list.Items { tmpl := &list.Items[i]; if tmpl.GetName() !=
newInfraMachineTemplateName { outdatedTemplates = append(outdatedTemplates,
tmpl) } }) for the VSphereMachineTemplateList case and make the identical change
in the AWS, IBMPowerVS, and OpenStack cases so you take the address of the slice
element (list.Items[i]) instead of the range variable.
In `@pkg/conversion/mapi2capi/vsphere.go`:
- Around line 130-135: The code dereferences v.infrastructure in the error path;
change the block to compute a nil-safe infraName before calling field.Invalid
(e.g. infraName := ""; if v.infrastructure != nil { infraName =
v.infrastructure.Status.InfrastructureName }) and then call errs = append(errs,
field.Invalid(field.NewPath("infrastructure", "status", "infrastructureName"),
infraName, "infrastructure cannot be nil and
infrastructure.Status.InfrastructureName cannot be empty")); keep the existing
else branch that sets capiMachine.Spec.ClusterName and
capiMachine.Labels[clusterv1.ClusterNameLabel] unchanged.
- Around line 197-203: The code dereferences v.infrastructure without checking
for nil when building the field.Invalid error and when assigning cluster fields;
change the logic to first check nil before accessing Status.InfrastructureName
(e.g., evaluate infraName only after confirming v.infrastructure != nil) and use
that safe value for the field.Invalid call and in the assignments to
capiMachineSet.Spec.Template.Spec.ClusterName, capiMachineSet.Spec.ClusterName,
and capiMachineSet.Labels[clusterv1.ClusterNameLabel]; ensure the nil branch
appends the error and the non-nil branch performs the assignments.
In `@pkg/util/conditions.go`:
- Around line 147-159: The docstring for GetConditionStatusFromInfraObject
contradicts the implementation: the code (and inline comment) call
GetConditionStatus (v1beta1) first, then fall back to GetV1Beta2ConditionStatus
(v1beta2); update the function comment to state it tries v1beta1 first (AWS,
Azure, GCP, etc.) and then falls back to v1beta2 (vSphere/newer providers), and
adjust any inline comment to match this behavior so documentation and
implementation are consistent.
🧹 Nitpick comments (4)
pkg/conversion/capi2mapi/vsphere_test.go (1)
348-399: Consider expanding MachineSet test coverage.The MachineSet conversion test table has only a single base configuration entry, while the Machine conversion tests cover many scenarios (clone modes, data disks, network configurations, etc.). Since
ToMachineSetinternally calls the Machine conversion logic, the core paths are tested, but adding a few more MachineSet-specific scenarios (e.g., with different replica counts, failure domains, or template variations) could improve confidence in the integration.pkg/conversion/capi2mapi/vsphere_fuzz_test.go (1)
142-189: Consider extracting shared spec normalization logic.The normalization logic in the
VSphereMachineSpecfuzzer (lines 142-189) andVSphereMachineTemplateSpecfuzzer (lines 210-254) is nearly identical. The only difference is that the template fuzzer accesses fields viaspec.Template.Spec.*instead ofspec.*.While acceptable for fuzz tests, extracting a shared helper function could reduce maintenance burden if fields need to be added or removed in the future.
Also applies to: 210-254
pkg/conversion/capi2mapi/vsphere.go (1)
202-206: Remove commented-out code artifacts.These lines appear to be leftover development artifacts that should be cleaned up before merging:
- Line 202-203: Commented TODO about delete policy
- Line 205: Incomplete comment about labels
🧹 Proposed fix
mapiMachineSet.Spec.Template.ObjectMeta.Annotations = mapiMachine.ObjectMeta.Annotations mapiMachineSet.Spec.Template.ObjectMeta.Labels = mapiMachine.ObjectMeta.Labels - //// todo: jcallen: afaik the default delete policy is empty - //mapiMachineSet.Spec.DeletePolicy = "" - - //mapiMachineSet.Spec.Template.ObjectMeta.Labels[] - return mapiMachineSet, warnings, nilpkg/conversion/mapi2capi/vsphere.go (1)
399-408: Consider warning on unknown clone mode values.The function silently defaults to
FullClonefor any unrecognized clone mode value. While defaulting is reasonable, this could mask configuration errors or unexpected values.Consider logging a warning or returning it in the warnings slice when an unexpected value is encountered.
💡 Example approach
// To add warning capability, change the function signature: func convertMAPICloneModeToCAPI(mapiMode mapiv1beta1.CloneMode) (vspherev1.CloneMode, []string) { switch mapiMode { case mapiv1beta1.FullClone: return vspherev1.FullClone, nil case mapiv1beta1.LinkedClone: return vspherev1.LinkedClone, nil case "": return vspherev1.FullClone, nil default: return vspherev1.FullClone, []string{fmt.Sprintf("unknown clone mode %q, defaulting to FullClone", mapiMode)} } }
a0cd7fd to
4a280fc
Compare
|
@AnnaZivkovic: This pull request references SPLAT-2410 which is a valid jira issue. Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.22.0" version, but no target version was set. DetailsIn response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
4a280fc to
b7f603d
Compare
|
@AnnaZivkovic: This pull request references SPLAT-2410 which is a valid jira issue. Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.22.0" version, but no target version was set. DetailsIn response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
|
/test e2e-vsphere-capi-techpreview |
|
/test lint pod something something failed |
|
@AnnaZivkovic: This pull request references SPLAT-2410 which is a valid jira issue. Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.22.0" version, but no target version was set. DetailsIn response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
48a5a82 to
4846757
Compare
|
@AnnaZivkovic: This pull request references SPLAT-2410 which is a valid jira issue. Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.22.0" version, but no target version was set. DetailsIn response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
Verify each finding against the current code and only fix it if needed.
In `@pkg/conversion/capi2mapi/vsphere_test.go`:
- Around line 348-399: The test suite for MachineSet conversion only contains a
single base Entry; add additional DescribeTable entries using the
vsphereCAPI2MAPIMachinesetConversionInput struct to mirror the Machine tests
(cover unsupported clone mode, invalid data disk provisioning mode, and network
DHCP+static IP mix) so
FromMachineSetAndVSphereMachineTemplateAndVSphereCluster(...).ToMachineSet() is
exercised for those edge cases; create VSphereMachineTemplate.Spec.Template.Spec
variants that set VirtualMachineCloneSpec.CloneMode unsupported value, DataDisks
with invalid ProvisioningMode, and Network interfaces combining DHCP and static
IPs, and assert expectedErrors/expectedWarnings matching the Machine test
expectations.
In `@pkg/util/conditions.go`:
- Around line 135-160: GetConditionStatusFromInfraObject currently falls back to
GetV1Beta2ConditionStatus and returns its error, which causes reconciles to fail
when a v1beta2 status block is simply absent; change the fallback logic in
GetConditionStatusFromInfraObject so that after calling
GetV1Beta2ConditionStatus you check for the sentinel errStatusV1Beta2NotFound
and treat it as a non-error by returning corev1.ConditionUnknown, nil; otherwise
return the status/error from GetV1Beta2ConditionStatus as before. Use the
existing symbols GetConditionStatusFromInfraObject, GetConditionStatus,
GetV1Beta2ConditionStatus, and errStatusV1Beta2NotFound to locate and implement
this conditional handling.
🧹 Nitpick comments (1)
🤖 Fix all nitpicks with AI agents
Verify each finding against the current code and only fix it if needed. In `@pkg/conversion/capi2mapi/vsphere_test.go`: - Around line 348-399: The test suite for MachineSet conversion only contains a single base Entry; add additional DescribeTable entries using the vsphereCAPI2MAPIMachinesetConversionInput struct to mirror the Machine tests (cover unsupported clone mode, invalid data disk provisioning mode, and network DHCP+static IP mix) so FromMachineSetAndVSphereMachineTemplateAndVSphereCluster(...).ToMachineSet() is exercised for those edge cases; create VSphereMachineTemplate.Spec.Template.Spec variants that set VirtualMachineCloneSpec.CloneMode unsupported value, DataDisks with invalid ProvisioningMode, and Network interfaces combining DHCP and static IPs, and assert expectedErrors/expectedWarnings matching the Machine test expectations.pkg/conversion/capi2mapi/vsphere_test.go (1)
348-399: Consider expanding MachineSet test coverage.The MachineSet conversion tests have only one entry (base case), while the Machine conversion tests above cover 14 scenarios including clone modes, data disks, networks, tags, and various error/warning cases.
Since
VSphereMachineTemplatewraps the sameVSphereMachineSpec, similar edge cases and error paths should ideally be validated for MachineSet conversions to ensure parity.Consider adding test entries for at least:
- Unsupported clone mode (error case)
- Invalid provisioning mode in data disks (error case)
- Network configurations with DHCP + static IPs (warning case)
This could be deferred if the underlying conversion logic is shared and already covered by the Machine tests.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pkg/conversion/capi2mapi/vsphere_test.go` around lines 348 - 399, The test suite for MachineSet conversion only contains a single base Entry; add additional DescribeTable entries using the vsphereCAPI2MAPIMachinesetConversionInput struct to mirror the Machine tests (cover unsupported clone mode, invalid data disk provisioning mode, and network DHCP+static IP mix) so FromMachineSetAndVSphereMachineTemplateAndVSphereCluster(...).ToMachineSet() is exercised for those edge cases; create VSphereMachineTemplate.Spec.Template.Spec variants that set VirtualMachineCloneSpec.CloneMode unsupported value, DataDisks with invalid ProvisioningMode, and Network interfaces combining DHCP and static IPs, and assert expectedErrors/expectedWarnings matching the Machine test expectations.
4846757 to
de8ce8d
Compare
|
@damdo Could you give this pr a review? |
|
/lgtm |
|
/assign @damdo |
|
Scheduling tests matching the |
|
/test e2e-vsphere-capi-techpreview |
|
/retest |
|
/lgtm |
|
Scheduling tests matching the |
fd0e98d to
d602b86
Compare
5d146bb to
ef41483
Compare
|
/lgtm |
|
Scheduling tests matching the |
|
/retest |
damdo
left a comment
There was a problem hiding this comment.
Thanks @AnnaZivkovic great work here!
I left some thoughts and some minor nits.
The two main themes we need to reason get right here are:
- ensure we have status conversion everywhere as well as spec
- understand what to do with v1beta1 vs v1betaX status conversion
| Labels: m.Spec.Template.ObjectMeta.Labels, //nolint:staticcheck // ObjectMeta is a field, not embedded | ||
| Annotations: m.Spec.Template.ObjectMeta.Annotations, //nolint:staticcheck // ObjectMeta is a field, not embedded | ||
| }, |
There was a problem hiding this comment.
We don't do this in other providers implementations. What's the reason for this?
There was a problem hiding this comment.
The reason I enabled vSphere to copy Labels and Annotations from the MachineSet template (while AWS/OpenStack don't) was for roundtrip conversion consistency. Tho, I can see not being necessary, but if we don't populate the template labels/annotations couldn't they be lost during conversion?
| // ProviderID - Populated at a different level. | ||
| // FailureDomain - Handled via zone label in buildAdditionalMetadata. | ||
| // PowerOffMode - Controls VM power operations (hard vs soft power off), not part of machine provisioning spec. | ||
| // GuestSoftPowerOffTimeout - Timeout for soft power operations, not part of machine provisioning spec. | ||
| // NamingStrategy - Controls VM naming behavior, not part of machine provisioning spec. | ||
| // Thumbprint - Ignore - Not required, TLS validation handled by cluster-level configuration. | ||
| // StoragePolicyName - Ignore - Not supported in MAPI VSphereMachineProviderSpec. | ||
| // Resources - Ignore - CPU/memory reservations, limits, and shares not supported in MAPI. | ||
| // AdditionalDisksGiB - Deprecated in CAPV, converted to DataDisks above. | ||
| // CustomVMXKeys - Ignore - Not supported in MAPI VSphereMachineProviderSpec. | ||
| // PciDevices - Ignore - Not supported in MAPI VSphereMachineProviderSpec. | ||
| // OS - Ignore - Not supported in MAPI VSphereMachineProviderSpec. | ||
| // HardwareVersion - Ignore - Not supported in MAPI VSphereMachineProviderSpec. |
There was a problem hiding this comment.
Any field that we are expected to set in MAPV (required), for which CAPV doesn't have a value and we need to make one up?
There was a problem hiding this comment.
I dont think there are any required MAPI fields that we need to "make up" values for. All required MAPI fields (Template and Network) have direct equivalents in CAPV that are also required. The only fields we set defaults for are optional fields
| // handleUnsupportedVSphereFields checks for CAPV fields that are not supported in MAPI and returns a list of errors. | ||
| func handleUnsupportedVSphereFields(fldPath *field.Path, spec vspherev1.VSphereMachineSpec) field.ErrorList { | ||
| errs := field.ErrorList{} | ||
|
|
||
| if spec.Thumbprint != "" { | ||
| // TLS validation is handled at the cluster level, not per-machine. | ||
| errs = append(errs, field.Invalid(fldPath.Child("thumbprint"), spec.Thumbprint, "thumbprint is not supported")) | ||
| } | ||
|
|
||
| if spec.StoragePolicyName != "" { | ||
| // Not required for our use case. | ||
| errs = append(errs, field.Invalid(fldPath.Child("storagePolicyName"), spec.StoragePolicyName, "storagePolicyName is not supported")) | ||
| } | ||
|
|
||
| if !reflect.DeepEqual(spec.Resources, vspherev1.VirtualMachineResources{}) { | ||
| // CPU/memory reservations, limits, and shares are not supported in MAPI. | ||
| errs = append(errs, field.Invalid(fldPath.Child("resources"), spec.Resources, "resources are not supported")) | ||
| } | ||
|
|
||
| // AdditionalDisksGiB is deprecated in CAPV in favor of DataDisks. | ||
| // This field is handled during conversion by merging with DataDisks. | ||
|
|
||
| if len(spec.CustomVMXKeys) > 0 { | ||
| // Not required for our use case. | ||
| errs = append(errs, field.Invalid(fldPath.Child("customVMXKeys"), spec.CustomVMXKeys, "customVMXKeys are not supported")) | ||
| } | ||
|
|
||
| if len(spec.PciDevices) > 0 { | ||
| // Not required for our use case. | ||
| errs = append(errs, field.Invalid(fldPath.Child("pciDevices"), spec.PciDevices, "pciDevices are not supported")) | ||
| } | ||
|
|
||
| if spec.OS != "" { | ||
| // Not required for our use case. | ||
| errs = append(errs, field.Invalid(fldPath.Child("os"), spec.OS, "os is not supported")) | ||
| } | ||
|
|
||
| if spec.HardwareVersion != "" { | ||
| // Not required for our use case. | ||
| errs = append(errs, field.Invalid(fldPath.Child("hardwareVersion"), spec.HardwareVersion, "hardwareVersion is not supported")) | ||
| } | ||
|
|
||
| if spec.PowerOffMode != "" && spec.PowerOffMode != vspherev1.VirtualMachinePowerOpModeHard { | ||
| // We always use hard power off mode. Other modes are not supported in MAPI. | ||
| errs = append(errs, field.Invalid(fldPath.Child("powerOffMode"), spec.PowerOffMode, "powerOffMode must be hard or unset")) | ||
| } | ||
|
|
||
| if spec.GuestSoftPowerOffTimeout != nil { | ||
| // This is only used with soft power off modes, which we don't support. | ||
| errs = append(errs, field.Invalid(fldPath.Child("guestSoftPowerOffTimeout"), spec.GuestSoftPowerOffTimeout, "guestSoftPowerOffTimeout is not supported")) | ||
| } | ||
|
|
||
| if spec.NamingStrategy != nil { | ||
| // Not required for our use case. | ||
| errs = append(errs, field.Invalid(fldPath.Child("namingStrategy"), spec.NamingStrategy, "namingStrategy is not supported")) | ||
| } | ||
|
|
||
| return errs | ||
| } |
There was a problem hiding this comment.
As this logic stands, if any of these is being set on CAPV, the conversion of that machine/machineset on MAPV will fail.
Is that always ok? Or are there certain cases where warning is also ok instead of erroring?
There was a problem hiding this comment.
I moved some of them to warnings.
| func convertCAPVMachineConditionsToMAPIVSphereMachineProviderConditions(vSphereMachine *vspherev1.VSphereMachine) []metav1.Condition { | ||
| message := "" | ||
|
|
||
| // Try to extract a meaningful message from v1beta2 conditions | ||
| if vSphereMachine.Status.V1Beta2 != nil { | ||
| // Prefer VirtualMachineProvisioned condition as it has more detailed status | ||
| if cond := meta.FindStatusCondition(vSphereMachine.Status.V1Beta2.Conditions, vspherev1.VSphereMachineVirtualMachineProvisionedV1Beta2Condition); cond != nil && cond.Message != "" { | ||
| message = cond.Message | ||
| } else if cond := meta.FindStatusCondition(vSphereMachine.Status.V1Beta2.Conditions, vspherev1.VSphereMachineReadyV1Beta2Condition); cond != nil && cond.Message != "" { | ||
| // Fall back to Ready condition if VirtualMachineProvisioned doesn't have a message | ||
| message = cond.Message | ||
| } | ||
| } | ||
|
|
||
| if vSphereMachine.Status.Ready { | ||
| // Set conditionSuccess | ||
| if message == "" { | ||
| message = "Machine successfully created" | ||
| } | ||
|
|
||
| return []metav1.Condition{{ | ||
| Type: string(mapiv1beta1.MachineCreation), | ||
| Status: metav1.ConditionTrue, | ||
| Reason: mapiv1beta1.MachineCreationSucceededConditionReason, | ||
| Message: message, | ||
| // LastTransitionTime will be set by the condition utilities. | ||
| }} | ||
| } | ||
|
|
||
| // Set conditionFailed | ||
| if message == "" { | ||
| message = "See VSphereMachine conditions." | ||
| } | ||
|
|
||
| return []metav1.Condition{{ | ||
| Type: string(mapiv1beta1.MachineCreation), | ||
| Status: metav1.ConditionFalse, | ||
| Reason: mapiv1beta1.MachineCreationFailedConditionReason, | ||
| Message: message, | ||
| // LastTransitionTime will be set by the condition utilities. | ||
| }} | ||
| } |
There was a problem hiding this comment.
This is again something we'll need to think about with regards to v1beta1 vs v1betaX
There was a problem hiding this comment.
@damdo Do you have any ideas of how to approach this? I am not sure how to come up with a more generic solution in the scope of this pr. My naive solution would be to have all of the platforms upgrade.
ef41483 to
53f454d
Compare
|
New changes are detected. LGTM label has been removed. |
363b4ee to
6124e00
Compare
|
@AnnaZivkovic: The following tests failed, say
Full PR test history. Your PR dashboard. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here. |
ca73b00 to
3d44e65
Compare
This enables bidirectional conversion between vSphere Machine API Machines/MachineSets and Cluster API Machines/MachineTemplates, including comprehensive fuzz and unit tests. # Conflicts: # cmd/machine-api-migration/main.go
Add functions to handle v1beta2 conditions (used by vSphere provider) while maintaining backward compatibility with v1beta1 conditions (used by AWS, Azure, GCP providers).
Gate vSphere migration functionality behind theClusterAPIMachineManagementVSphere feature gate. The migrationcontrollers for vSphere will now only start when both the generalMachineAPIMigration feature gate and the vSphere-specificClusterAPIMachineManagementVSphere feature gate are enabled.
Implements admission-time validation to block unsupported vSphere fieldsin VSphereMachine and VSphereMachineTemplate resources, providing clear error messages before conversion attempts.
Align vSphere conversion with AWS implementation by converting and setting ProviderStatus during CAPI to MAPI conversion to ensure proper status synchronization between the two APIs.
3d44e65 to
a662b42
Compare
Enables vSphere support in the Machine API to Cluster API conversion framework. It implements bidirectional conversion between vSphere Machine API resources (Machines/MachineSets) and Cluster API resources (Machines/MachineTemplates), including support for vSphere-specific v1beta2 conditions.
Changes
Summary by CodeRabbit
New Features
Bug Fixes
Tests