From 77d1673507dde030d733b41add997d5cc408abf0 Mon Sep 17 00:00:00 2001 From: Abrar Shivani Date: Fri, 21 Aug 2026 16:25:10 -0700 Subject: [PATCH] Mount host /lib/modules for precompiled drivers on SUSE getDriverAdditionalConfigs placed the lib-modules volume and mount inside the "if !cr.Spec.UsePrecompiledDrivers()" branch, guarded by a check for UsePrecompiledDrivers. That inner condition can never hold there, so an NVIDIADriver with usePrecompiled: true on sles or sl-micro rendered a driver pod without /run/host/lib/modules. Move the mount out to its own block after the non-precompiled branch. The comment above it goes as well, since the guard already says precompiled and SUSE and the volume literals already say host module tree. The equivalent code in the ClusterPolicy path sits before the early return for precompiled drivers and works as intended, so only the NVIDIADriver path was affected. That is also why this went unnoticed: the tests added with the mount only covered the ClusterPolicy path. Add a table-driven test that renders the DaemonSet and asserts the volume on the pod spec and the mount on nvidia-driver-ctr. Going through the render catches a template change that stopped threading AdditionalConfigs into the pod as well as the Go-side bug. Fixes #2776 Signed-off-by: Abrar Shivani --- internal/state/driver_test.go | 140 +++++++++++++++++++++++++++++++ internal/state/driver_volumes.go | 36 ++++---- 2 files changed, 157 insertions(+), 19 deletions(-) diff --git a/internal/state/driver_test.go b/internal/state/driver_test.go index a3d89e25a5..92907fb62c 100644 --- a/internal/state/driver_test.go +++ b/internal/state/driver_test.go @@ -91,6 +91,33 @@ func getYAMLString(objs []*unstructured.Unstructured) (string, error) { return sb.String(), nil } +func findVolumeByName(volumes []corev1.Volume, name string) *corev1.Volume { + for i := range volumes { + if volumes[i].Name == name { + return &volumes[i] + } + } + return nil +} + +func findVolumeMountByName(volumeMounts []corev1.VolumeMount, name string) *corev1.VolumeMount { + for i := range volumeMounts { + if volumeMounts[i].Name == name { + return &volumeMounts[i] + } + } + return nil +} + +func findContainerByName(containers []corev1.Container, name string) *corev1.Container { + for i := range containers { + if containers[i].Name == name { + return &containers[i] + } + } + return nil +} + func hasSubscriptionVolumeMount(volumeMounts []corev1.VolumeMount) bool { for _, volumeMount := range volumeMounts { if strings.HasPrefix(volumeMount.Name, "subscription-config-") { @@ -657,6 +684,119 @@ func TestDriverAdditionalConfigsSubscriptionMounts(t *testing.T) { } } +func TestDriverPrecompiledLibModules(t *testing.T) { + const ( + libModulesVolumeName = "lib-modules" + driverContainerName = "nvidia-driver-ctr" + precompiledKernelVersion = "5.14.21-150500.55.44-default" + ) + + state, err := NewStateDriver( + fake.NewClientBuilder().WithScheme(scheme.Scheme).Build(), + "test-ns", + scheme.Scheme, + manifestDir) + require.NoError(t, err) + stateDriver, ok := state.(*stateDriver) + require.True(t, ok) + + clusterInfo := testClusterInfo{runtime: consts.Containerd} + + testCases := []struct { + description string + osRelease string + osVersion string + usePrecompiled bool + expectLibModulesMounted bool + }{ + { + description: "sles with precompiled drivers mounts host /lib/modules", + osRelease: "sles", + osVersion: "15.6", + usePrecompiled: true, + expectLibModulesMounted: true, + }, + { + description: "sl-micro with precompiled drivers mounts host /lib/modules", + osRelease: "sl-micro", + osVersion: "6.0", + usePrecompiled: true, + expectLibModulesMounted: true, + }, + { + description: "sles without precompiled drivers does not mount host /lib/modules", + osRelease: "sles", + osVersion: "15.6", + usePrecompiled: false, + expectLibModulesMounted: false, + }, + { + description: "ubuntu with precompiled drivers does not mount host /lib/modules", + osRelease: "ubuntu", + osVersion: "22.04", + usePrecompiled: true, + expectLibModulesMounted: false, + }, + } + + for _, tc := range testCases { + t.Run(tc.description, func(t *testing.T) { + driver := &nvidiav1alpha1.NVIDIADriver{} + driver.Spec.UsePrecompiled = ptr.To(tc.usePrecompiled) + + additionalConfigs, err := stateDriver.getDriverAdditionalConfigs( + context.Background(), + driver, + clusterInfo, + nodePool{osRelease: tc.osRelease, osVersion: tc.osVersion}, + ) + require.NoError(t, err) + + renderData := getMinimalDriverRenderData() + renderData.Driver.Spec.UsePrecompiled = ptr.To(tc.usePrecompiled) + renderData.AdditionalConfigs = additionalConfigs + if tc.usePrecompiled { + renderData.Precompiled = &precompiledSpec{ + KernelVersion: precompiledKernelVersion, + SanitizedKernelVersion: precompiledKernelVersion, + } + } + + objs, err := stateDriver.renderer.RenderObjects( + &render.TemplatingData{ + Data: renderData, + }) + require.NoError(t, err) + + ds, err := getDaemonsetFromObjects(objs) + require.NoError(t, err) + + libModulesVolume := findVolumeByName(ds.Spec.Template.Spec.Volumes, libModulesVolumeName) + + driverContainer := findContainerByName(ds.Spec.Template.Spec.Containers, driverContainerName) + require.NotNil(t, driverContainer) + + libModulesMount := findVolumeMountByName(driverContainer.VolumeMounts, libModulesVolumeName) + + if !tc.expectLibModulesMounted { + assert.Nil(t, libModulesVolume, "unexpected lib-modules volume on the driver pod spec") + assert.Nil(t, libModulesMount, "unexpected lib-modules volume mount on nvidia-driver-ctr") + return + } + + require.NotNil(t, libModulesVolume, "expected a lib-modules volume on the driver pod spec") + require.NotNil(t, libModulesVolume.HostPath) + assert.Equal(t, "/lib/modules", libModulesVolume.HostPath.Path) + require.NotNil(t, libModulesVolume.HostPath.Type) + assert.Equal(t, corev1.HostPathDirectory, *libModulesVolume.HostPath.Type) + + require.NotNil(t, libModulesMount, "expected a lib-modules volume mount on nvidia-driver-ctr") + assert.Equal(t, "/run/host/lib/modules", libModulesMount.MountPath) + assert.True(t, libModulesMount.ReadOnly) + }) + } +} + func TestDriverConfigPathHelpers(t *testing.T) { repoConfigPath, err := getRepoConfigPath("rhel") require.NoError(t, err) diff --git a/internal/state/driver_volumes.go b/internal/state/driver_volumes.go index f0aeb2f5c3..34f60ea609 100644 --- a/internal/state/driver_volumes.go +++ b/internal/state/driver_volumes.go @@ -220,29 +220,27 @@ func (s *stateDriver) getDriverAdditionalConfigs(ctx context.Context, cr *v1alph additionalCfgs.Volumes = append(additionalCfgs.Volumes, subscriptionVol) } } + } - // Mount /lib/modules for precompiled drivers on SUSE distributions. - // Those containers need access to host /lib/modules at runtime. - if cr.Spec.UsePrecompiledDrivers() && (pool.osRelease == "sles" || pool.osRelease == "sl-micro") { - logger.Info("Mounting /lib/modules into the driver container") - libModulesVolMount := corev1.VolumeMount{ - Name: "lib-modules", - MountPath: "/run/host/lib/modules", - ReadOnly: true, - } - additionalCfgs.VolumeMounts = append(additionalCfgs.VolumeMounts, libModulesVolMount) + if cr.Spec.UsePrecompiledDrivers() && (pool.osRelease == "sles" || pool.osRelease == "sl-micro") { + logger.Info("Mounting /lib/modules into the driver pod") + libModulesVolMount := corev1.VolumeMount{ + Name: "lib-modules", + MountPath: "/run/host/lib/modules", + ReadOnly: true, + } + additionalCfgs.VolumeMounts = append(additionalCfgs.VolumeMounts, libModulesVolMount) - libModulesVol := corev1.Volume{ - Name: "lib-modules", - VolumeSource: corev1.VolumeSource{ - HostPath: &corev1.HostPathVolumeSource{ - Path: "/lib/modules", - Type: ptr.To(corev1.HostPathDirectory), - }, + libModulesVol := corev1.Volume{ + Name: "lib-modules", + VolumeSource: corev1.VolumeSource{ + HostPath: &corev1.HostPathVolumeSource{ + Path: "/lib/modules", + Type: ptr.To(corev1.HostPathDirectory), }, - } - additionalCfgs.Volumes = append(additionalCfgs.Volumes, libModulesVol) + }, } + additionalCfgs.Volumes = append(additionalCfgs.Volumes, libModulesVol) } // mount any custom kernel module configuration parameters at /drivers