Skip to content

Commit bffc97f

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 bffc97f

File tree

1 file changed

+135
-40
lines changed

1 file changed

+135
-40
lines changed

pkg/providers/vsphere/vmprovider_vm.go

Lines changed: 135 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -2456,47 +2456,142 @@ 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+
deviceSpec := deviceChange.GetVirtualDeviceConfigSpec()
2486+
if deviceSpec == nil {
2487+
continue
2488+
}
2489+
2490+
disk, ok := deviceSpec.Device.(*vimtypes.VirtualDisk)
2491+
if !ok {
2492+
continue
2493+
}
2494+
2495+
var diskName string
2496+
2497+
// TODO(future): Deduplicate this logic as similar is
2498+
// also there in content_library_utils.go
2499+
switch tb := disk.Backing.(type) {
2500+
case *vimtypes.VirtualDiskSeSparseBackingInfo:
2501+
diskName = strings.TrimSuffix(path.Base(tb.FileName), path.Ext(tb.FileName))
2502+
case *vimtypes.VirtualDiskSparseVer1BackingInfo:
2503+
diskName = strings.TrimSuffix(path.Base(tb.FileName), path.Ext(tb.FileName))
2504+
case *vimtypes.VirtualDiskSparseVer2BackingInfo:
2505+
diskName = strings.TrimSuffix(path.Base(tb.FileName), path.Ext(tb.FileName))
2506+
case *vimtypes.VirtualDiskFlatVer1BackingInfo:
2507+
diskName = strings.TrimSuffix(path.Base(tb.FileName), path.Ext(tb.FileName))
2508+
case *vimtypes.VirtualDiskFlatVer2BackingInfo:
2509+
diskName = strings.TrimSuffix(path.Base(tb.FileName), path.Ext(tb.FileName))
2510+
case *vimtypes.VirtualDiskLocalPMemBackingInfo:
2511+
diskName = strings.TrimSuffix(path.Base(tb.FileName), path.Ext(tb.FileName))
2512+
case *vimtypes.VirtualDiskRawDiskMappingVer1BackingInfo:
2513+
diskName = strings.TrimSuffix(path.Base(tb.FileName), path.Ext(tb.FileName))
2514+
case *vimtypes.VirtualDiskRawDiskVer2BackingInfo:
2515+
diskName = strings.TrimSuffix(path.Base(tb.DescriptorFileName), path.Ext(tb.DescriptorFileName))
2516+
case *vimtypes.VirtualDiskPartitionedRawDiskVer2BackingInfo:
2517+
diskName = strings.TrimSuffix(path.Base(tb.DescriptorFileName), path.Ext(tb.DescriptorFileName))
2518+
default:
2519+
if di := disk.DeviceInfo; di != nil {
2520+
if d := di.GetDescription(); d != nil {
2521+
diskName = d.Label
2522+
}
2523+
}
2524+
}
2525+
2526+
volume, ok := unmanagedVolumeClaimsFromImage[diskName]
2527+
if !ok {
2528+
// there's no claim corresponding to the disk, process further
2529+
continue
2530+
}
2531+
2532+
pvc := &corev1.PersistentVolumeClaim{}
2533+
key := ctrlclient.ObjectKey{
2534+
Namespace: vmCtx.VM.Namespace,
2535+
Name: volume.PersistentVolumeClaim.ClaimName,
2536+
}
2537+
if err := vs.k8sClient.Get(vmCtx, key, pvc); err != nil {
2538+
if apierrors.IsNotFound(err) {
2539+
errs = append(errs, fmt.Errorf(
2540+
"pvc %s/%s not found for the specified claim %s",
2541+
key.Namespace, key.Name, diskName,
2542+
))
2543+
}
2544+
2545+
errs = append(errs, fmt.Errorf(
2546+
"failed to get pvc %s/%s for the specified claim %s: %w",
2547+
key.Namespace, key.Name, diskName, err,
2548+
))
2549+
2550+
// process the next disk as this one can't be processed further
2551+
continue
2552+
}
2553+
2554+
// Update disk device with PVC information
2555+
// - Set the profile based on the PVC's storage class
2556+
// - Adjust disk size if PVC requests more than image disk size
2557+
//
2558+
// TODO: Does the UUID need to be set as well?
2559+
storageClassName := pvc.Spec.StorageClassName
2560+
storageClassToPolicyID := createArgs.Storage.StorageClassToPolicyID
2561+
2562+
if storageClassName == nil ||
2563+
storageClassToPolicyID == nil ||
2564+
storageClassToPolicyID[*storageClassName] == "" {
2565+
2566+
errs = append(errs, fmt.Errorf(
2567+
"pvc %s/%s has no storage class or no Policy IDmapping for the storage class",
2568+
key.Namespace, key.Name),
2569+
)
2570+
2571+
continue
2572+
}
2573+
2574+
deviceSpec.Profile = []vimtypes.BaseVirtualMachineProfileSpec{
2575+
&vimtypes.VirtualMachineDefinedProfileSpec{
2576+
ProfileId: storageClassToPolicyID[*storageClassName],
2577+
},
2578+
}
2579+
2580+
if pvcCapacity, ok := pvc.Spec.Resources.Requests[corev1.ResourceStorage]; ok && !pvcCapacity.IsZero() {
2581+
// TODO: Verify this again
2582+
pvcSizeBytes := pvcCapacity.Value()
2583+
2584+
diskSizeBytes := disk.CapacityInBytes
2585+
if pvcSizeBytes > diskSizeBytes {
2586+
disk.CapacityInBytes = pvcSizeBytes
2587+
disk.CapacityInKB = pvcSizeBytes / 1024
2588+
}
2589+
}
2590+
}
2591+
2592+
if len(errs) > 0 {
2593+
return apierrorsutil.NewAggregate(errs)
2594+
}
25002595

25012596
return nil
25022597
}

0 commit comments

Comments
 (0)