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 ed7dd399..86915751 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": @@ -248,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 @@ -686,6 +694,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 +729,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/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")) + }) +}) 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 { 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) + } + }) + } +}