From 7de7db5728c01024915bf1547c3072ec611b6952 Mon Sep 17 00:00:00 2001 From: Gaurav Mehta Date: Fri, 10 May 2024 14:11:09 +1000 Subject: [PATCH] additional vgpu validations --- pkg/webhook/vgpu.go | 15 ++++++++++ pkg/webhook/vgpu_test.go | 65 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/pkg/webhook/vgpu.go b/pkg/webhook/vgpu.go index 8d47971a..67bdd915 100644 --- a/pkg/webhook/vgpu.go +++ b/pkg/webhook/vgpu.go @@ -52,6 +52,10 @@ func (v *vgpuValidator) Update(_ *types.Request, oldObj runtime.Object, newObj r return checkVGPUUsage(v.kubevirtCache, newVGPUObj.Name) } + // vGPU was enabled, run some basic sanity checks on request + if !oldVGPUObj.Spec.Enabled && newVGPUObj.Spec.Enabled { + return validateVGPUProfiles(oldVGPUObj, newVGPUObj) + } return nil } @@ -73,3 +77,14 @@ func checkVGPUUsage(kc kubevirtctl.VirtualMachineCache, deviceName string) error return nil } + +func validateVGPUProfiles(oldVGPUObj, newVGPUObj *devicesv1beta1.VGPUDevice) error { + if newVGPUObj.Spec.VGPUTypeName == "" { + return fmt.Errorf("VGPUTypeName cannot be empty for vGPU device %s", newVGPUObj.Name) + } + + if _, ok := oldVGPUObj.Status.AvailableTypes[newVGPUObj.Spec.VGPUTypeName]; !ok { + return fmt.Errorf("VGPUTypeName %s is not a valid profile for vGPU device %s", newVGPUObj.Spec.VGPUTypeName, newVGPUObj.Name) + } + return nil +} diff --git a/pkg/webhook/vgpu_test.go b/pkg/webhook/vgpu_test.go index 1a76d517..00cf234b 100644 --- a/pkg/webhook/vgpu_test.go +++ b/pkg/webhook/vgpu_test.go @@ -50,6 +50,30 @@ var ( Enabled: false, }, } + + oldDisabledVGPU = &devicesv1beta1.VGPUDevice{ + ObjectMeta: metav1.ObjectMeta{ + Name: "vgpu1", + }, + Spec: devicesv1beta1.VGPUDeviceSpec{ + Enabled: false, + }, + Status: devicesv1beta1.VGPUDeviceStatus{ + AvailableTypes: map[string]string{ + "GRID A100-8C": "nvidia-470", + "GRID A100-10C": "nvidia-471", + }, + }, + } + newEnabledVGPU = &devicesv1beta1.VGPUDevice{ + ObjectMeta: metav1.ObjectMeta{ + Name: "vgpu1", + }, + Spec: devicesv1beta1.VGPUDeviceSpec{ + Enabled: true, + }, + } + vm1 = &kubevirtv1.VirtualMachine{ ObjectMeta: metav1.ObjectMeta{ Name: "vgpu-vm", @@ -121,7 +145,7 @@ func Test_VGPUUpdates(t *testing.T) { if v.expectError { assert.Error(err, fmt.Sprintf("expected to find error for test case %s", v.name)) } else { - assert.NoError(err, fmt.Sprintf("expected to find no errorerror for test case %s", v.name)) + assert.NoError(err, fmt.Sprintf("expected to find no error for test case %s", v.name)) } } } @@ -156,3 +180,42 @@ func Test_VGPUDeletion(t *testing.T) { } } } + +func Test_validateVGPUProfile(t *testing.T) { + var testCases = []struct { + name string + gpu *devicesv1beta1.VGPUDevice + vGPUProfile string + expectError bool + }{ + { + name: "no vGPU Profile", + gpu: oldDisabledVGPU, + expectError: true, + }, + { + name: "invalid vGPU Profile", + gpu: newFreeVGPU, + vGPUProfile: "GRID A100-40C", + expectError: true, + }, + { + name: "valid vGPU Profile", + gpu: newFreeVGPU, + vGPUProfile: "GRID A100-10C", + expectError: false, + }, + } + + assert := require.New(t) + for _, v := range testCases { + newEnabledVGPUCopy := newEnabledVGPU.DeepCopy() + newEnabledVGPUCopy.Spec.VGPUTypeName = v.vGPUProfile + err := validateVGPUProfiles(oldDisabledVGPU, newEnabledVGPUCopy) + if v.expectError { + assert.Error(err, fmt.Sprintf("expected to find error for test case: %s", v.name)) + } else { + assert.NoError(err, fmt.Sprintf("expected to find no error for test case: %s", v.name)) + } + } +}