From 781c5b52f6947f3a4137dfcb734be653632d2e50 Mon Sep 17 00:00:00 2001 From: Priyanka Saggu Date: Thu, 23 Oct 2025 11:45:28 +0530 Subject: [PATCH 1/4] add support for detecting SLES nodes and automatically selecting appropriate AMD GPU driver versions * add new `slesCMNameMapper` to parse SLES version strings like 'SUSE Linux Enterprise Server 15 SP6' to 'sles-15.6' * add `SLESDefaultDriverVersionsMapper` to select driver versions - SLES 15 SP6/SP7 -> driver 7.0.2 (ref: https://repo.radeon.com/amdgpu-install/7.0.2/sle/) - SLES 15 SP5 -> driver 6.2.2 (ref: https://repo.radeon.com/amdgpu-install/6.2.2/sle/) * register both 'sles' and 'suse' identifiers in mappers Co-authored-by: alex-isv --- internal/kmmmodule/kmmmodule.go | 21 +++++++++++++++++++++ internal/utils.go | 23 +++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/internal/kmmmodule/kmmmodule.go b/internal/kmmmodule/kmmmodule.go index ed7dd399..88f9ce88 100644 --- a/internal/kmmmodule/kmmmodule.go +++ b/internal/kmmmodule/kmmmodule.go @@ -686,6 +686,8 @@ var cmNameMappers = map[string]func(fullImageStr string) string{ "rhel": rhelCMNameMapper, "red hat": rhelCMNameMapper, "redhat": rhelCMNameMapper, + "sles": slesCMNameMapper, + "suse": slesCMNameMapper, } func rhelCMNameMapper(osImageStr string) string { @@ -719,6 +721,25 @@ func ubuntuCMNameMapper(osImageStr string) string { return fmt.Sprintf("%s-%s", os, trimmedVersion) } +func slesCMNameMapper(osImageStr string) string { + // Example: "SUSE Linux Enterprise Server 15 SP6" -> "sles-15.6" + // Example: "suse linux enterprise server 15-sp6" -> "sles-15.6" + // Convert to lowercase for consistent matching + osImageLower := strings.ToLower(osImageStr) + re := regexp.MustCompile(`(\d+)\s*-?\s*sp(\d+)`) + matches := re.FindStringSubmatch(osImageLower) + if len(matches) >= 3 { + return fmt.Sprintf("sles-%s.%s", matches[1], matches[2]) + } + // Fallback for base version "SLES 15" or "SUSE Linux Enterprise Server 15" + re = regexp.MustCompile(`(\d+)`) + matches = re.FindStringSubmatch(osImageLower) + if len(matches) > 1 { + return fmt.Sprintf("sles-%s", matches[1]) + } + return "sles-" + osImageLower +} + func GetK8SNodes(ctx context.Context, cli client.Client, labelSelector labels.Selector) (*v1.NodeList, error) { options := &client.ListOptions{ LabelSelector: labelSelector, diff --git a/internal/utils.go b/internal/utils.go index c695dbd2..648ee575 100644 --- a/internal/utils.go +++ b/internal/utils.go @@ -195,6 +195,8 @@ var defaultDriverversionsMappers = map[string]func(fullImageStr string) (string, "red hat": func(f string) (string, error) { return defaultOcDriversVersion, nil }, + "sles": SLESDefaultDriverVersionsMapper, + "suse": SLESDefaultDriverVersionsMapper, } func UbuntuDefaultDriverVersionsMapper(fullImageStr string) (string, error) { @@ -229,6 +231,27 @@ func UbuntuDefaultDriverVersionsMapper(fullImageStr string) (string, error) { return "", fmt.Errorf("unsupported Ubuntu version: %s. Supported versions include 20.04, 22.04 and 24.04", fullImageStr) } +func SLESDefaultDriverVersionsMapper(fullImageStr string) (string, error) { + // For SLES 15 SP6 and above, use the latest stable driver version + if strings.Contains(fullImageStr, "15") { + // Check for SP6 or later + re := regexp.MustCompile(`15\s*-?\s*sp(\d+)`) + match := re.FindStringSubmatch(strings.ToLower(fullImageStr)) + if len(match) > 1 { + spVersion, err := strconv.Atoi(match[1]) + if err == nil && spVersion >= 6 { + return "7.0.2", nil // Latest stable version for SP6+ + } + if err == nil && spVersion >= 5 { + return "6.2.2", nil // Stable version for SP5 + } + } + // Default for SLES 15 without SP info + return "6.2.2", nil + } + return "", fmt.Errorf("unsupported SLES version: %s. Supported versions include SLES 15 SP5 and above", fullImageStr) +} + func HasNodeLabelKey(node v1.Node, labelKey string) bool { for k := range node.Labels { if k == labelKey { From 0170a9af582f9cc8abcab298acf6501740e0a7a3 Mon Sep 17 00:00:00 2001 From: Priyanka Saggu Date: Thu, 23 Oct 2025 12:02:30 +0530 Subject: [PATCH 2/4] add SLES Dockerfile template (`DockerfileTemplate.sles`) for building AMD GPU drivers on SLES * also embed the template via go:embed and add SLES case logic Co-authored-by: alex-isv --- .../dockerfiles/DockerfileTemplate.sles | 52 +++++++++++++++++++ internal/kmmmodule/kmmmodule.go | 4 ++ 2 files changed, 56 insertions(+) create mode 100644 internal/kmmmodule/dockerfiles/DockerfileTemplate.sles diff --git a/internal/kmmmodule/dockerfiles/DockerfileTemplate.sles b/internal/kmmmodule/dockerfiles/DockerfileTemplate.sles new file mode 100644 index 00000000..058d8637 --- /dev/null +++ b/internal/kmmmodule/dockerfiles/DockerfileTemplate.sles @@ -0,0 +1,52 @@ +FROM $$BASEIMG_REGISTRY/suse/sle15:$$VERSION AS builder + +ARG KERNEL_FULL_VERSION + +ARG DRIVERS_VERSION + +ARG REPO_URL + +RUN zypper --non-interactive --gpg-auto-import-keys refresh + +# Note: Only kernel-default-devel is needed (provides kernel headers) +# kernel-source package does NOT exist in SLES repositories +RUN zypper --non-interactive install -y \ + kernel-default-devel \ + gcc \ + make \ + bc \ + bison \ + flex \ + libelf-devel \ + perl \ + python3 \ + python3-setuptools \ + python3-wheel + +# Add AMD GPU repository for SLES +# The $$VERSION variable (e.g., "15.6", "15.7") is substituted at runtime +RUN zypper --non-interactive addrepo \ + --no-gpgcheck \ + ${REPO_URL}/amdgpu/${DRIVERS_VERSION}/sle/$$VERSION/main/x86_64/ \ + amdgpu + +# Refresh repositories again to include AMD repo +RUN zypper --non-interactive --gpg-auto-import-keys refresh +RUN zypper --non-interactive --gpg-auto-import-keys install -y amdgpu-dkms +RUN depmod ${KERNEL_FULL_VERSION} + + +FROM $$BASEIMG_REGISTRY/suse/sle15:$$VERSION +ARG KERNEL_FULL_VERSION + +RUN zypper --non-interactive --gpg-auto-import-keys refresh && \ + zypper --non-interactive install -y kmod + +RUN mkdir -p /opt/lib/modules/${KERNEL_FULL_VERSION}/updates/ + +# Note: amdgpu-dkms on SLES places modules in /lib/modules/.../updates/ (not updates/dkms/) +COPY --from=builder /lib/modules/${KERNEL_FULL_VERSION}/updates/amd* /opt/lib/modules/${KERNEL_FULL_VERSION}/updates/ +COPY --from=builder /lib/modules/${KERNEL_FULL_VERSION}/modules.* /opt/lib/modules/${KERNEL_FULL_VERSION}/ +RUN ln -s /lib/modules/${KERNEL_FULL_VERSION}/kernel /opt/lib/modules/${KERNEL_FULL_VERSION}/kernel +RUN mkdir -p /firmwareDir/updates/amdgpu +COPY --from=builder /lib/firmware/updates/amdgpu /firmwareDir/updates/amdgpu diff --git a/internal/kmmmodule/kmmmodule.go b/internal/kmmmodule/kmmmodule.go index 88f9ce88..2832a445 100644 --- a/internal/kmmmodule/kmmmodule.go +++ b/internal/kmmmodule/kmmmodule.go @@ -89,6 +89,8 @@ var ( dockerfileTemplateUbuntu string //go:embed dockerfiles/DockerfileTemplate.coreos dockerfileTemplateCoreOS string + //go:embed dockerfiles/DockerfileTemplate.sles + dockerfileTemplateSLES string //go:embed devdockerfiles/devdockerfile.txt dockerfileDevTemplateUbuntu string //go:embed dockerfiles/DockerfileTemplate.ubuntu.gim @@ -230,6 +232,8 @@ func resolveDockerfile(cmName string, devConfig *amdv1alpha1.DeviceConfig) (stri case utils.DriverTypeVFPassthrough: dockerfileTemplate = dockerfileTemplateGIMCoreOS } + case "sles": + dockerfileTemplate = dockerfileTemplateSLES // FIX ME // add the RHEL back when it is fully supported /*case "rhel": From b6254419acc77215f56226d2a6792ace632007df Mon Sep 17 00:00:00 2001 From: Priyanka Saggu Date: Thu, 23 Oct 2025 14:33:52 +0530 Subject: [PATCH 3/4] tests: update internal/utils_test.go for added support for SLES 15 SP* --- internal/utils_test.go | 61 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/internal/utils_test.go b/internal/utils_test.go index b9eaeec7..c4501f75 100644 --- a/internal/utils_test.go +++ b/internal/utils_test.go @@ -364,3 +364,64 @@ func TestUbuntuDefaultDriverVersionsMapper(t *testing.T) { }) } } + +func TestSLESDefaultDriverVersionsMapper(t *testing.T) { + tests := []struct { + name string + osImage string + expected string + wantErr bool + }{ + { + name: "SLES 15 SP6", + osImage: "SUSE Linux Enterprise Server 15 SP6", + expected: "7.0.2", + wantErr: false, + }, + { + name: "SLES 15 SP7", + osImage: "SUSE Linux Enterprise Server 15 SP7", + expected: "7.0.2", + wantErr: false, + }, + { + name: "SLES 15 SP5", + osImage: "SUSE Linux Enterprise Server 15 SP5", + expected: "6.2.2", + wantErr: false, + }, + { + name: "SLES 15 SP4", + osImage: "suse linux enterprise server 15 sp4", + expected: "6.2.2", + wantErr: false, + }, + { + name: "SLES 15 base", + osImage: "SUSE Linux Enterprise Server 15", + expected: "6.2.2", + wantErr: false, + }, + { + name: "SLES 15 with dash format", + osImage: "sles 15-sp6", + expected: "7.0.2", + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result, err := SLESDefaultDriverVersionsMapper(tt.osImage) + + if (err != nil) != tt.wantErr { + t.Errorf("SLESDefaultDriverVersionsMapper() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if result != tt.expected { + t.Errorf("SLESDefaultDriverVersionsMapper() = %q, want %q", result, tt.expected) + } + }) + } +} From 4da60d363d6b61c80ae700ee8a070ba13ed64edf Mon Sep 17 00:00:00 2001 From: Priyanka Saggu Date: Mon, 27 Oct 2025 12:21:43 +0530 Subject: [PATCH 4/4] use "registry.suse.com" as the default base image registry if OS == "sles" * although, use-specified `BaseImageRegistry` still takes precedence * also extend tests in `internal/kmmodule/kmmodule_test.go` to test above changes in `resolveDockerfile` func --- internal/kmmmodule/kmmmodule.go | 4 ++ internal/kmmmodule/kmmmodule_test.go | 57 ++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/internal/kmmmodule/kmmmodule.go b/internal/kmmmodule/kmmmodule.go index 2832a445..86915751 100644 --- a/internal/kmmmodule/kmmmodule.go +++ b/internal/kmmmodule/kmmmodule.go @@ -252,7 +252,11 @@ func resolveDockerfile(cmName string, devConfig *amdv1alpha1.DeviceConfig) (stri // render base image registry baseImageRegistry := defaultBaseImageRegistry if devConfig.Spec.Driver.ImageBuild.BaseImageRegistry != "" { + // user-specified registry takes precendence baseImageRegistry = devConfig.Spec.Driver.ImageBuild.BaseImageRegistry + } else if osDistro == "sles" { + // if OS == "sles", use default image registry as "registry.suse.com" + baseImageRegistry = "registry.suse.com" } dockerfileTemplate = strings.Replace(dockerfileTemplate, "$$BASEIMG_REGISTRY", baseImageRegistry, -1) // render driver version diff --git a/internal/kmmmodule/kmmmodule_test.go b/internal/kmmmodule/kmmmodule_test.go index f9f30509..e5b448f9 100644 --- a/internal/kmmmodule/kmmmodule_test.go +++ b/internal/kmmmodule/kmmmodule_test.go @@ -678,3 +678,60 @@ var _ = Describe("getKernelMappings", func() { } }) }) + +var _ = Describe("resolveDockerfile", func() { + It("should use correct default registry when not specified by user", func() { + testCases := []struct { + cmName string + expectedImageUrl string + }{ + {"ubuntu-22.04", "docker.io/ubuntu:22.04"}, + {"sles-15.6", "registry.suse.com/suse/sle15:15.6"}, + } + for _, tc := range testCases { + input := &amdv1alpha1.DeviceConfig{ + Spec: amdv1alpha1.DeviceConfigSpec{ + Driver: amdv1alpha1.DriverSpec{}, + }, + } + dockerfile, err := resolveDockerfile(tc.cmName, input) + Expect(err).To(BeNil()) + Expect(dockerfile).To(ContainSubstring(tc.expectedImageUrl)) + } + }) + It("should respect user-specified BaseImageRegistry for all OS types", func() { + testCases := []struct { + cmName string + expectedImageUrl string + }{ + {"ubuntu-22.04", "example-image-registry.com/ubuntu:22.04"}, + {"sles-15.6", "example-image-registry.com/suse/sle15:15.6"}, + } + for _, tc := range testCases { + input := &amdv1alpha1.DeviceConfig{ + Spec: amdv1alpha1.DeviceConfigSpec{ + Driver: amdv1alpha1.DriverSpec{ + ImageBuild: amdv1alpha1.ImageBuildSpec{ + BaseImageRegistry: "example-image-registry.com", + }, + }, + }, + } + dockerfile, err := resolveDockerfile(tc.cmName, input) + Expect(err).To(BeNil()) + Expect(dockerfile).To(ContainSubstring(tc.expectedImageUrl)) + Expect(dockerfile).NotTo(ContainSubstring("docker.io")) + Expect(dockerfile).NotTo(ContainSubstring("registry.suse.com")) + } + }) + It("should return error for unsupported OS", func() { + input := &amdv1alpha1.DeviceConfig{ + Spec: amdv1alpha1.DeviceConfigSpec{ + Driver: amdv1alpha1.DriverSpec{}, + }, + } + _, err := resolveDockerfile("unsupported-os", input) + Expect(err).NotTo(BeNil()) + Expect(err.Error()).To(ContainSubstring("not supported OS")) + }) +})