Skip to content

Commit

Permalink
Add VirtualMachine hub-spoke-hub and spoke-hub-spoke tests
Browse files Browse the repository at this point in the history
Start with a nearly fully populated v1a2 VM and ensure that
the VM resulting from conversion is the same. We can keep adding
these explicit conversion tests to ensure that fields are converted
as we expect instead of always depending on the fuzzer. Add typical
v1a1 TKG VM and ensure spoke-hub-spoke conversion works.

Fix a few conversion issues around the Network and Advanced fields.

Always restore the full VM Status from the annotations. Our controller
should be the only one updating the Status, and an update from the
conversion will cause our controllers to reconcile and reevaluate the
Status.
  • Loading branch information
bryanv committed Dec 14, 2023
1 parent e923645 commit e7bedff
Show file tree
Hide file tree
Showing 3 changed files with 396 additions and 39 deletions.
25 changes: 17 additions & 8 deletions api/v1alpha1/conversion_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,25 +85,30 @@ func TestFuzzyConversion(t *testing.T) {
}

func overrideVirtualMachineFieldsFuncs(codecs runtimeserializer.CodecFactory) []interface{} {
// TODO: The changes from v1a1 to v1a2 is quite large so several parts of the input objects are
// defaulted out until we start to marshall the object in the annotations for down conversions
// and back.
return []interface{}{
func(vmSpec *v1alpha1.VirtualMachineSpec, c fuzz.Continue) {
c.Fuzz(vmSpec)

for i := range vmSpec.Volumes {
// Not present in v1a2.
vmSpec.Volumes[i].VsphereVolume = nil
var volumes []v1alpha1.VirtualMachineVolume
for _, vol := range vmSpec.Volumes {
// vSphere volumes are gone in v1a2 so skip those.
if vol.VsphereVolume == nil {
volumes = append(volumes, vol)
}
}
vmSpec.Volumes = volumes

if vmSpec.AdvancedOptions != nil {
if provOpts := vmSpec.AdvancedOptions.DefaultVolumeProvisioningOptions; provOpts != nil {
if opts := vmSpec.AdvancedOptions; opts != nil {
if provOpts := opts.DefaultVolumeProvisioningOptions; provOpts != nil {
if provOpts.ThinProvisioned != nil {
// Both cannot be set.
provOpts.EagerZeroed = nil
}
}

if opts.ChangeBlockTracking != nil && !*opts.ChangeBlockTracking {
opts.ChangeBlockTracking = nil
}
}

// This is effectively deprecated.
Expand Down Expand Up @@ -226,3 +231,7 @@ func overrideConditionsObservedGeneration(conditions []metav1.Condition) {
conditions[i].ObservedGeneration = 0
}
}

func ptrOf[T any](v T) *T {
return &v
}
79 changes: 48 additions & 31 deletions api/v1alpha1/virtualmachine_conversion.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,9 @@ func convert_v1alpha2_BootstrapSpec_To_v1alpha1_VmMetadata(
out.Transport = VirtualMachineMetadataExtraConfigTransport
case "user-data":
out.Transport = VirtualMachineMetadataCloudInitTransport
default:
// Best approx we can do.
out.Transport = VirtualMachineMetadataCloudInitTransport
}
} else if cloudInit.CloudConfig != nil {
out.Transport = VirtualMachineMetadataCloudInitTransport
Expand Down Expand Up @@ -358,34 +361,39 @@ func convert_v1alpha2_ReadinessProbeSpec_To_v1alpha1_Probe(in *v1alpha2.VirtualM
}

func convert_v1alpha1_VirtualMachineAdvancedOptions_To_v1alpha2_VirtualMachineAdvancedSpec(
in *VirtualMachineAdvancedOptions) *v1alpha2.VirtualMachineAdvancedSpec {
in *VirtualMachineAdvancedOptions, inVolumes []VirtualMachineVolume) *v1alpha2.VirtualMachineAdvancedSpec {

bootDiskCapacity := convert_v1alpha1_VsphereVolumes_To_v1alpha2_BootDiskCapacity(inVolumes)

if in == nil || apiequality.Semantic.DeepEqual(*in, VirtualMachineAdvancedOptions{}) {
if (in == nil || apiequality.Semantic.DeepEqual(*in, VirtualMachineAdvancedOptions{})) && bootDiskCapacity == nil {
return nil
}

out := v1alpha2.VirtualMachineAdvancedSpec{}

if opts := in.DefaultVolumeProvisioningOptions; opts != nil {
if opts.ThinProvisioned != nil {
if *opts.ThinProvisioned {
out.DefaultVolumeProvisioningMode = v1alpha2.VirtualMachineVolumeProvisioningModeThin
} else {
out.DefaultVolumeProvisioningMode = v1alpha2.VirtualMachineVolumeProvisioningModeThick
out.BootDiskCapacity = bootDiskCapacity

if in != nil {
if opts := in.DefaultVolumeProvisioningOptions; opts != nil {
if opts.ThinProvisioned != nil {
if *opts.ThinProvisioned {
out.DefaultVolumeProvisioningMode = v1alpha2.VirtualMachineVolumeProvisioningModeThin
} else {
out.DefaultVolumeProvisioningMode = v1alpha2.VirtualMachineVolumeProvisioningModeThick
}
} else if opts.EagerZeroed != nil && *opts.EagerZeroed {
out.DefaultVolumeProvisioningMode = v1alpha2.VirtualMachineVolumeProvisioningModeThickEagerZero
}
} else if opts.EagerZeroed != nil && *opts.EagerZeroed {
out.DefaultVolumeProvisioningMode = v1alpha2.VirtualMachineVolumeProvisioningModeThickEagerZero
}
}

if in.ChangeBlockTracking != nil {
out.ChangeBlockTracking = *in.ChangeBlockTracking
if in.ChangeBlockTracking != nil {
out.ChangeBlockTracking = *in.ChangeBlockTracking
}
}

return &out
}

func convert_v1alpha1_VsphereVolumes_To_v1alpah2_BootDiskCapacity(volumes []VirtualMachineVolume) *resource.Quantity {
func convert_v1alpha1_VsphereVolumes_To_v1alpha2_BootDiskCapacity(volumes []VirtualMachineVolume) *resource.Quantity {
// The v1a1 VsphereVolume was never a great API as you had to know the DeviceKey upfront; at the time our
// API was private - only used by CAPW - and predates the "VM Service" VMs; In v1a2, we only support resizing
// the boot disk via an explicit field. As good as we can here, map v1a1 volume into the v1a2 specific field.
Expand Down Expand Up @@ -441,7 +449,7 @@ func convert_v1alpha2_VirtualMachineAdvancedSpec_To_v1alpha1_VirtualMachineAdvan
}

func convert_v1alpha2_BootDiskCapacity_To_v1alpha1_VirtualMachineVolume(capacity *resource.Quantity) *VirtualMachineVolume {
if capacity == nil || capacity.IsZero() {
if capacity == nil {
return nil
}

Expand Down Expand Up @@ -577,10 +585,7 @@ func Convert_v1alpha1_VirtualMachineSpec_To_v1alpha2_VirtualMachineSpec(
}

out.ReadinessProbe = convert_v1alpha1_Probe_To_v1alpha2_ReadinessProbeSpec(in.ReadinessProbe)
out.Advanced = convert_v1alpha1_VirtualMachineAdvancedOptions_To_v1alpha2_VirtualMachineAdvancedSpec(in.AdvancedOptions)
if out.Advanced != nil {
out.Advanced.BootDiskCapacity = convert_v1alpha1_VsphereVolumes_To_v1alpah2_BootDiskCapacity(in.Volumes)
}
out.Advanced = convert_v1alpha1_VirtualMachineAdvancedOptions_To_v1alpha2_VirtualMachineAdvancedSpec(in.AdvancedOptions, in.Volumes)

if in.ResourcePolicyName != "" {
if out.Reserved == nil {
Expand Down Expand Up @@ -610,6 +615,7 @@ func Convert_v1alpha2_VirtualMachineSpec_To_v1alpha1_VirtualMachineSpec(
out.VmMetadata = convert_v1alpha2_BootstrapSpec_To_v1alpha1_VmMetadata(in.Bootstrap)

if in.Network != nil {
out.NetworkInterfaces = make([]VirtualMachineNetworkInterface, 0, len(in.Network.Interfaces))
for _, networkInterfaceSpec := range in.Network.Interfaces {
networkInterface := convert_v1alpha2_NetworkInterfaceSpec_To_v1alpha1_NetworkInterface(networkInterfaceSpec)
out.NetworkInterfaces = append(out.NetworkInterfaces, networkInterface)
Expand Down Expand Up @@ -821,16 +827,20 @@ func restore_v1alpha2_VirtualMachineBootstrapSpec(
}
}

func restore_v1alpha2_VirtualMachineNetwork(
func restore_v1alpha2_VirtualMachineNetworkSpec(
dst, src *v1alpha2.VirtualMachine) {

dstNetwork := dst.Spec.Network
srcNetwork := src.Spec.Network

if dstNetwork == nil || srcNetwork == nil {
if srcNetwork == nil || (srcNetwork.HostName == "" && !srcNetwork.Disabled && len(srcNetwork.Interfaces) == 0) {
// Nothing to restore.
return
}

if dst.Spec.Network == nil {
dst.Spec.Network = &v1alpha2.VirtualMachineNetworkSpec{}
}
dstNetwork := dst.Spec.Network

dstNetwork.HostName = srcNetwork.HostName
dstNetwork.Disabled = srcNetwork.Disabled

Expand Down Expand Up @@ -859,6 +869,17 @@ func restore_v1alpha2_VirtualMachineNetwork(
}
}

func restore_v1alpha2_VirtualMachineReadinessProbeSpec(
dst, src *v1alpha2.VirtualMachine) {

if src.Spec.ReadinessProbe != nil {
if dst.Spec.ReadinessProbe == nil {
dst.Spec.ReadinessProbe = &v1alpha2.VirtualMachineReadinessProbeSpec{}
}
dst.Spec.ReadinessProbe.GuestInfo = src.Spec.ReadinessProbe.GuestInfo
}
}

// ConvertTo converts this VirtualMachine to the Hub version.
func (src *VirtualMachine) ConvertTo(dstRaw conversion.Hub) error {
dst := dstRaw.(*v1alpha2.VirtualMachine)
Expand All @@ -873,14 +894,10 @@ func (src *VirtualMachine) ConvertTo(dstRaw conversion.Hub) error {
}

restore_v1alpha2_VirtualMachineBootstrapSpec(dst, restored)
restore_v1alpha2_VirtualMachineNetwork(dst, restored)
restore_v1alpha2_VirtualMachineNetworkSpec(dst, restored)
restore_v1alpha2_VirtualMachineReadinessProbeSpec(dst, restored)

if restored.Spec.ReadinessProbe != nil {
if dst.Spec.ReadinessProbe == nil {
dst.Spec.ReadinessProbe = &v1alpha2.VirtualMachineReadinessProbeSpec{}
}
dst.Spec.ReadinessProbe.GuestInfo = restored.Spec.ReadinessProbe.GuestInfo
}
dst.Status = restored.Status

return nil
}
Expand Down
Loading

0 comments on commit e7bedff

Please sign in to comment.