Skip to content

Commit e0d78da

Browse files
committed
🌱 Patch device spec with data from PVCs
This commit implements the vmCreateGenConfigSpecImagePVCDataSourceRefs method as part of the AllDisksArePVCs initiative. For each of the disks in createArgs.ConfigSpec, the following is done: 1. Iterates over spec.volumes and looks for an entry with an unmanagedVolumeSource with a type of "FromImage" and name set to the value that identifies the current disk. If no such entry exists, then continues to the next disk. 3. Gets the referred PVC. If no such PVC exists, then an error is thrown indicating the PVC for the specified claim is missing and VM creation may not proceed. 4. Gets the PVC's specified storage class and requested capacity. a. Updates the disk device's specified storage class using the value from the PVC. b. Updates the disk device's specified capacity using the value from the PVC *if* it is larger than the disk's current requested size. Signed-off-by: Nabarun Pal <[email protected]>
1 parent cc3d033 commit e0d78da

File tree

1 file changed

+139
-40
lines changed

1 file changed

+139
-40
lines changed

pkg/providers/vsphere/vmprovider_vm.go

Lines changed: 139 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2456,47 +2456,146 @@ func (vs *vSphereVMProvider) vmCreateGenConfigSpecImagePVCDataSourceRefs(
24562456
vmCtx pkgctx.VirtualMachineContext,
24572457
createArgs *VMCreateArgs) error {
24582458

2459-
_, _ = vmCtx, createArgs // Remove once args are used.
2459+
if createArgs.ConfigSpec.DeviceChange == nil {
2460+
return nil
2461+
}
24602462

2461-
// TODO(AllDisksArePVCs)
2462-
//
2463-
// Implement this function. For example, for each of the disks in
2464-
// createArgs.ConfigSpec, do the following:
2465-
//
2466-
// 1. Iterate over spec.volumes and look for an entry with an
2467-
// unmanagedVolumeSource with a type of "FromImage" and name set to
2468-
// the value that identifies the current disk (the logic for
2469-
// deriving this name is located in the UpdateVmiWithOVF and
2470-
// UpdateVmiWithVirtualMachine functions in the file
2471-
// pkg/providers/vsphere/contentlibrary/content_library_utils.go).
2472-
//
2473-
// 2. If no such entry exists, then continue to the next iteration of the
2474-
// loop.
2475-
//
2476-
// 3. Use the k8s client's Get function (do not use CreateOrPatch)
2477-
// to see if a PersistentVolumeClaim object already exists for
2478-
// this disk. The name of the PersistentVolumeClaim object should
2479-
// be what was specified in the field
2480-
// spec.volumes[].persistentVolumeClaim.claimName from the prior
2481-
// step.
2482-
//
2483-
// If no such entry exists, then return an error indicating the PVC for
2484-
// the specified claim is missing and VM creation may not proceed.
2485-
//
2486-
// 4. Get the PVC's specified storage class and requested capacity.
2487-
//
2488-
// The PVC *may* specify a different encryption class from the VM, but it
2489-
// is probably too much work to handle multiple encryption classes in our
2490-
// BYOK reconciler at this point. We will allow the PVC to be recrypted
2491-
// by CSI *after* the VM is created and the disk is turned into a PVC.
2492-
//
2493-
// Update the disk device's specified storage class using the value from
2494-
// the PVC. Update the disk device's specified capacity using the value
2495-
// from the PVC *if* it is larger than the disk's current requested size.
2496-
//
2497-
// That should be it! We are not actually registering these disks as PVCs
2498-
// at this point. That happens in the VM's update workflow later. For now
2499-
// we just need the information about these disks *from* the PVCs.
2463+
// lookup map to avoid iterating over the volumes for each disk
2464+
unmanagedVolumeClaimsFromImage := make(map[string]vmopv1.VirtualMachineVolume)
2465+
for _, vol := range vmCtx.VM.Spec.Volumes {
2466+
if vol.PersistentVolumeClaim == nil {
2467+
continue
2468+
}
2469+
2470+
unmanagedVolumeClaim := vol.PersistentVolumeClaim.UnmanagedVolumeClaim
2471+
if unmanagedVolumeClaim == nil {
2472+
continue
2473+
}
2474+
2475+
if unmanagedVolumeClaim.Type != vmopv1.UnmanagedVolumeClaimVolumeTypeFromImage {
2476+
continue
2477+
}
2478+
2479+
unmanagedVolumeClaimsFromImage[unmanagedVolumeClaim.Name] = vol
2480+
}
2481+
2482+
var errs []error
2483+
2484+
for _, deviceChange := range createArgs.ConfigSpec.DeviceChange {
2485+
if deviceSpec := deviceChange.GetVirtualDeviceConfigSpec(); deviceSpec != nil {
2486+
if disk, ok := deviceSpec.Device.(*vimtypes.VirtualDisk); ok {
2487+
if di := disk.DeviceInfo; di != nil {
2488+
if d := di.GetDescription(); d != nil {
2489+
volume, ok := unmanagedVolumeClaimsFromImage[d.Label]
2490+
if ok {
2491+
// update the uuid in the disk backing info
2492+
vmCreateGenConfigSpecSetDiskBackingUUID(volume, disk)
2493+
2494+
// update the storage profile and size based on the PVC
2495+
if err := vs.updateDiskDeviceFromPVC(
2496+
vmCtx,
2497+
volume.PersistentVolumeClaim.ClaimName,
2498+
createArgs.Storage.StorageClassToPolicyID,
2499+
deviceSpec,
2500+
disk,
2501+
); err != nil {
2502+
errs = append(errs, err)
2503+
}
2504+
}
2505+
}
2506+
}
2507+
}
2508+
}
2509+
}
2510+
2511+
if len(errs) > 0 {
2512+
return apierrorsutil.NewAggregate(errs)
2513+
}
2514+
2515+
return nil
2516+
}
2517+
2518+
func vmCreateGenConfigSpecSetDiskBackingUUID(volume vmopv1.VirtualMachineVolume, disk *vimtypes.VirtualDisk) {
2519+
// The following backing info types do not have a UUID field
2520+
// - VirtualDiskFlatVer1BackingInfo
2521+
// - VirtualDiskSparseVer1BackingInfo
2522+
2523+
switch tb := disk.Backing.(type) {
2524+
case *vimtypes.VirtualDiskSeSparseBackingInfo:
2525+
tb.Uuid = volume.PersistentVolumeClaim.UnmanagedVolumeClaim.UUID
2526+
case *vimtypes.VirtualDiskSparseVer2BackingInfo:
2527+
tb.Uuid = volume.PersistentVolumeClaim.UnmanagedVolumeClaim.UUID
2528+
case *vimtypes.VirtualDiskFlatVer2BackingInfo:
2529+
tb.Uuid = volume.PersistentVolumeClaim.UnmanagedVolumeClaim.UUID
2530+
case *vimtypes.VirtualDiskLocalPMemBackingInfo:
2531+
tb.Uuid = volume.PersistentVolumeClaim.UnmanagedVolumeClaim.UUID
2532+
case *vimtypes.VirtualDiskRawDiskMappingVer1BackingInfo:
2533+
tb.Uuid = volume.PersistentVolumeClaim.UnmanagedVolumeClaim.UUID
2534+
case *vimtypes.VirtualDiskRawDiskVer2BackingInfo:
2535+
tb.Uuid = volume.PersistentVolumeClaim.UnmanagedVolumeClaim.UUID
2536+
case *vimtypes.VirtualDiskPartitionedRawDiskVer2BackingInfo:
2537+
tb.Uuid = volume.PersistentVolumeClaim.UnmanagedVolumeClaim.UUID
2538+
}
2539+
}
2540+
2541+
func (vs *vSphereVMProvider) updateDiskDeviceFromPVC(
2542+
vmCtx pkgctx.VirtualMachineContext,
2543+
claimName string,
2544+
storageClassToPolicyID map[string]string,
2545+
deviceSpec *vimtypes.VirtualDeviceConfigSpec,
2546+
disk *vimtypes.VirtualDisk,
2547+
) error {
2548+
pvc := &corev1.PersistentVolumeClaim{}
2549+
key := ctrlclient.ObjectKey{
2550+
Namespace: vmCtx.VM.Namespace,
2551+
Name: claimName,
2552+
}
2553+
2554+
if err := vs.k8sClient.Get(vmCtx, key, pvc); err != nil {
2555+
if apierrors.IsNotFound(err) {
2556+
return fmt.Errorf(
2557+
"pvc %s/%s not found for the specified claim",
2558+
key.Namespace, key.Name,
2559+
)
2560+
}
2561+
2562+
return fmt.Errorf(
2563+
"failed to get pvc %s/%s for the specified claim: %w",
2564+
key.Namespace, key.Name, err,
2565+
)
2566+
}
2567+
2568+
// Update disk device with PVC information
2569+
// - Set the profile based on the PVC's storage class
2570+
// - Adjust disk size if PVC requests more than image disk size
2571+
storageClassName := pvc.Spec.StorageClassName
2572+
2573+
if storageClassName == nil ||
2574+
storageClassToPolicyID == nil ||
2575+
storageClassToPolicyID[*storageClassName] == "" {
2576+
2577+
return fmt.Errorf(
2578+
"pvc %s/%s has no storage class or no Policy IDmapping for the storage class",
2579+
key.Namespace, key.Name,
2580+
)
2581+
}
2582+
2583+
deviceSpec.Profile = []vimtypes.BaseVirtualMachineProfileSpec{
2584+
&vimtypes.VirtualMachineDefinedProfileSpec{
2585+
ProfileId: storageClassToPolicyID[*storageClassName],
2586+
},
2587+
}
2588+
2589+
if pvcCapacity, ok := pvc.Spec.Resources.Requests[corev1.ResourceStorage]; ok && !pvcCapacity.IsZero() {
2590+
// TODO: Verify this again
2591+
// Is it possible to set the size for a child disk if the VM is a linked clone?
2592+
pvcSizeBytes := pvcCapacity.Value()
2593+
2594+
diskSizeBytes := disk.CapacityInBytes
2595+
if pvcSizeBytes > diskSizeBytes {
2596+
disk.CapacityInBytes = pvcSizeBytes
2597+
}
2598+
}
25002599

25012600
return nil
25022601
}

0 commit comments

Comments
 (0)