Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions internal/kmmmodule/dockerfiles/DockerfileTemplate.sles
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# SPDX-License-Identifier: MIT
#
# Uses a SUSE built AMD GPU driver image as source, avoiding the need
# for a SUSEConnect registration key. modules.dep uses relative paths so it is
# valid for any kernel version in the same codestream (stable kABI).
#
# Build args:
# KERNEL_FULL_VERSION - target kernel version, e.g. "6.4.0-150700.53.25-default"
# SUSE_PREBUILT_DRIVER_IMG - SUSE-published driver image (built against GA kernel)

ARG SUSE_PREBUILT_DRIVER_IMG

FROM ${SUSE_PREBUILT_DRIVER_IMG} AS driver-source

FROM $$BASEIMG_REGISTRY/bci/bci-micro:$$VERSION

ARG KERNEL_FULL_VERSION

# Relocate modules, kernel tree and depmod metadata from the GA kernel path to
# the target kernel version path; no depmod re-run needed (relative paths).
COPY --from=driver-source /opt/lib/modules/ /opt/lib/modules-prebuilt/
RUN set -euo pipefail; \
GA_KERNEL=$(ls /opt/lib/modules-prebuilt/ | head -1); \
mkdir -p /opt/lib/modules/${KERNEL_FULL_VERSION}/updates/dkms; \
cp /opt/lib/modules-prebuilt/${GA_KERNEL}/updates/dkms/amd* \
/opt/lib/modules/${KERNEL_FULL_VERSION}/updates/dkms/; \
cp /opt/lib/modules-prebuilt/${GA_KERNEL}/modules.* \
/opt/lib/modules/${KERNEL_FULL_VERSION}/; \
cp -r /opt/lib/modules-prebuilt/${GA_KERNEL}/kernel \
/opt/lib/modules/${KERNEL_FULL_VERSION}/kernel; \
rm -rf /opt/lib/modules-prebuilt

RUN mkdir -p /firmwareDir/updates/amdgpu
COPY --from=driver-source /firmwareDir/updates/amdgpu /firmwareDir/updates/amdgpu
50 changes: 50 additions & 0 deletions internal/kmmmodule/kmmmodule.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ var (
dockerfileTemplateCoreOSFromSrcImage string
//go:embed dockerfiles/DockerfileTemplate.rpm.coreos
dockerfileTemplateCoreOSFromRPM string
//go:embed dockerfiles/DockerfileTemplate.sles
dockerfileTemplateSLES string
//go:embed devdockerfiles/devdockerfile.txt
dockerfileDevTemplateUbuntu string
//go:embed dockerfiles/DockerfileTemplate.ubuntu.gim
Expand All @@ -93,6 +95,14 @@ var (
dockerfileTemplateGIMCoreOS string
)

// slesCSDPrebuiltDriverImages maps SLES codestream version -> driver version -> prebuilt image.
// Tag format: sles-<codestream>-<ga_kernel>-<driver_version>
var slesCSDPrebuiltDriverImages = map[string]map[string]string{
"15.7": {
"7.0.3": "registry.suse.com/third-party/amd/amdgpu-driver:sles-15.7-7.0.3",
},
}
Comment on lines +100 to +104
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug — data tables are inconsistent. This prebuilt-image table only registers 15.7 → 7.0.3, but SLESDefaultDriverVersionsMapper (utils.go) defaults to 7.0.2 for SP6 and 6.2.2 for SP5/base. With those defaults, the lookup in getKM (around line 572) silently misses and SUSE_PREBUILT_DRIVER_IMG is never injected. The new Dockerfile template has no fallback — FROM ${SUSE_PREBUILT_DRIVER_IMG} AS driver-source resolves to FROM AS driver-source, which fails the build.

Net effect: with the defaults this PR ships, SP5 and SP6 nodes (which the PR claims to support) cannot build. Either add prebuilt entries for the SP5/SP6 default driver versions, narrow SLESDefaultDriverVersionsMapper to only return versions present here, or surface an explicit error on lookup miss.

Copy link
Copy Markdown
Contributor Author

@Priyankasaggu11929 Priyankasaggu11929 May 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the pointer.

SLESDefaultDriverVersionsMapper in utils.go was supposed to be cleaned up as part of my previous commit refreshes.

I have narrowed the supported versions to SLES 15 SP7 only and keeping just the 15.7 -> 7.0.3 entry in the table. Since, we are now going to build the prebuilt driver container images starting SLES 15 SP7.

(I'll either send a new PR or update this one to add SLES 16.0 as well to the table, as soon as the respective prebuilt container image is ready).

Also addressed the silent-skip behavior to now properly return error messages on any version outside SLES 15.7 for now.

Also, please note - I will update the driver version to use the new amdgpu driver version - v31.20 once the respective prebuilt container image is ready and published. Thanks!


//go:generate mockgen -source=kmmmodule.go -package=kmmmodule -destination=mock_kmmmodule.go KMMModuleAPI
type KMMModuleAPI interface {
SetNodeVersionLabelAsDesired(ctx context.Context, devConfig *amdv1alpha1.DeviceConfig, nodes *v1.NodeList) error
Expand Down Expand Up @@ -290,6 +300,8 @@ func resolveDockerfile(cmName string, devConfig *amdv1alpha1.DeviceConfig) (stri
dockerfileTemplate = dockerfileTemplateCoreOSFromSrcImage
}
}
case "sles":
dockerfileTemplate = dockerfileTemplateSLES
// FIX ME
// add the RHEL back when it is fully supported
/*case "rhel":
Expand All @@ -308,7 +320,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 precedence
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
Expand Down Expand Up @@ -564,6 +580,25 @@ func getKM(devConfig *amdv1alpha1.DeviceConfig, node v1.Node, inTreeModuleToRemo
)
}

// Inject SUSE_PREBUILT_DRIVER_IMG build arg for SLES nodes.
if strings.HasPrefix(osName, "sles-") {
csVersion := strings.TrimPrefix(osName, "sles-") // e.g. "15.7"
driverVersions, ok := slesCSDPrebuiltDriverImages[csVersion]
if !ok {
return kmmv1beta1.KernelMapping{}, "", fmt.Errorf("no prebuilt driver image registered for SLES codestream %q", csVersion)
}
prebuiltImg, ok := driverVersions[driversVersion]
if !ok {
return kmmv1beta1.KernelMapping{}, "", fmt.Errorf("no prebuilt driver image registered for SLES codestream %q with driver version %q", csVersion, driversVersion)
}
kmmBuild.BuildArgs = append(kmmBuild.BuildArgs,
kmmv1beta1.BuildArg{
Name: "SUSE_PREBUILT_DRIVER_IMG",
Value: prebuiltImg,
},
)
}
Comment thread
Priyankasaggu11929 marked this conversation as resolved.

// trim suffix "+" to handle the dirty build kernel version
// e.g., "5.15.0-76-generic+"
// on KMM side it is trimming the suffix "+" to read kernel mapping
Expand Down Expand Up @@ -624,6 +659,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 {
Expand Down Expand Up @@ -657,6 +694,19 @@ func ubuntuCMNameMapper(osImageStr string) string {
return fmt.Sprintf("%s-%s", os, trimmedVersion)
}

func slesCMNameMapper(osImageStr string) string {
// Example: "SUSE Linux Enterprise Server 15 SP7" -> "sles-15.7"
// Example: "suse linux enterprise server 15-sp7" -> "sles-15.7"
// 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])
}
return "sles-" + osImageLower
}

func GetK8SNodes(ctx context.Context, cli client.Client, labelSelector labels.Selector) (*v1.NodeList, error) {
options := &client.ListOptions{
LabelSelector: labelSelector,
Expand Down
57 changes: 57 additions & 0 deletions internal/kmmmodule/kmmmodule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -732,3 +732,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/bci/bci-micro: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/bci/bci-micro: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"))
})
})
17 changes: 17 additions & 0 deletions internal/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,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) {
Expand Down Expand Up @@ -232,6 +234,21 @@ func UbuntuDefaultDriverVersionsMapper(fullImageStr string) (string, error) {
return "", fmt.Errorf("unsupported Ubuntu version: %s. Supported versions include 20.04, 22.04 and 24.04", fullImageStr)
}

var slesSPRegexp = regexp.MustCompile(`15\s*-?\s*sp(\d+)`)

func SLESDefaultDriverVersionsMapper(fullImageStr string) (string, error) {
if strings.Contains(fullImageStr, "15") {
match := slesSPRegexp.FindStringSubmatch(strings.ToLower(fullImageStr))
if len(match) > 1 {
spVersion, err := strconv.Atoi(match[1])
if err == nil && spVersion >= 7 {
return "7.0.3", nil // Latest stable version for SP7+
}
}
}
return "", fmt.Errorf("unsupported SLES version: %s. Supported versions include SLES 15 SP7 and above", fullImageStr)
}

func HasNodeLabelKey(node v1.Node, labelKey string) bool {
for k := range node.Labels {
if k == labelKey {
Expand Down
47 changes: 47 additions & 0 deletions internal/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -364,3 +364,50 @@ func TestUbuntuDefaultDriverVersionsMapper(t *testing.T) {
})
}
}

func TestSLESDefaultDriverVersionsMapper(t *testing.T) {
tests := []struct {
name string
osImage string
expected string
wantErr bool
}{
{
name: "SLES 15 SP7",
osImage: "SUSE Linux Enterprise Server 15 SP7",
expected: "7.0.3",
wantErr: false,
},
{
name: "SLES 15 SP7 with dash format",
osImage: "sles 15-sp7",
expected: "7.0.3",
wantErr: false,
},
{
name: "SLES 15 SP6 unsupported",
osImage: "SUSE Linux Enterprise Server 15 SP6",
wantErr: true,
},
{
name: "SLES 15 base unsupported",
osImage: "SUSE Linux Enterprise Server 15",
wantErr: true,
},
}

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)
}
})
}
}
Loading