Skip to content

Commit

Permalink
Image Customizer: Functional tests for kernel modules API. (#10363)
Browse files Browse the repository at this point in the history
Add functional tests for the kernel modules API. There are already good test coverage for this feature from unit tests. So, the functional tests don't need to be that extensive.
  • Loading branch information
cwize1 authored Sep 5, 2024
1 parent 250db44 commit 9c978f0
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 17 deletions.
29 changes: 21 additions & 8 deletions toolkit/tools/pkg/imagecustomizerlib/kernelmoduleutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,27 @@ import (
"github.com/microsoft/azurelinux/toolkit/tools/internal/logger"
)

const (
modprobeConfigDir = "/etc/modprobe.d"
modulesLoadConfigDir = "/etc/modules-load.d"

moduleDisabledFileName = "modules-disabled.conf"
moduleLoadFileName = "modules-load.conf"
moduleOptionsFileName = "module-options.conf"

moduleDisabledPath = modprobeConfigDir + "/" + moduleDisabledFileName
moduleLoadPath = modulesLoadConfigDir + "/" + moduleLoadFileName
moduleOptionsPath = modprobeConfigDir + "/" + moduleOptionsFileName
)

func loadOrDisableModules(modules []imagecustomizerapi.Module, rootDir string) error {
var err error
var modulesToLoad []string
var modulesToDisable []string
moduleOptionsUpdates := make(map[string]map[string]string)
moduleDisableFilePath := filepath.Join(rootDir, "etc/modprobe.d/modules-disabled.conf")
moduleLoadFilePath := filepath.Join(rootDir, "etc/modules-load.d/modules-load.conf")
moduleOptionsFilePath := filepath.Join(rootDir, "etc/modprobe.d/module-options.conf")
moduleDisableFilePath := filepath.Join(rootDir, moduleDisabledPath)
moduleLoadFilePath := filepath.Join(rootDir, moduleLoadPath)
moduleOptionsFilePath := filepath.Join(rootDir, moduleOptionsPath)

for i, module := range modules {
switch module.LoadMode {
Expand Down Expand Up @@ -154,10 +167,10 @@ func ensureModulesDisabled(moduleNames []string, moduleDisableFilePath string) e
needUpdate := false

for _, moduleName := range moduleNames {
blacklistEntry := "blacklist " + moduleName
if !strings.Contains(contentString, blacklistEntry+"\n") {
disableEntry := "blacklist " + moduleName
if !strings.Contains(contentString, disableEntry+"\n") {
// Append the module to be disabled if it's not already in the file
updatedContent += blacklistEntry + "\n"
updatedContent += disableEntry + "\n"
needUpdate = true
logger.Log.Infof("Setting module (%s) to be disabled", moduleName)
}
Expand Down Expand Up @@ -188,8 +201,8 @@ func isModuleDisabled(moduleName, moduleDisableFilePath string) (bool, error) {
return false, err
}

blacklistEntry := "blacklist " + moduleName
if strings.Contains(string(content), blacklistEntry+"\n") {
disableEntry := "blacklist " + moduleName
if strings.Contains(string(content), disableEntry+"\n") {
return true, nil
}

Expand Down
59 changes: 50 additions & 9 deletions toolkit/tools/pkg/imagecustomizerlib/kernelmoduleutils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"testing"

"github.com/microsoft/azurelinux/toolkit/tools/imagecustomizerapi"
"github.com/microsoft/azurelinux/toolkit/tools/internal/file"
"github.com/stretchr/testify/assert"
)

Expand All @@ -35,9 +36,9 @@ func TestLoadOrDisableModules(t *testing.T) {
err := loadOrDisableModules(modules, rootDir)
assert.NoError(t, err)

moduleLoadFilePath := filepath.Join(rootDir, "etc/modules-load.d/modules-load.conf")
moduleOptionsFilePath := filepath.Join(rootDir, "etc/modprobe.d/module-options.conf")
moduleDisableFilePath := filepath.Join(rootDir, "etc/modprobe.d/modules-disabled.conf")
moduleLoadFilePath := filepath.Join(rootDir, moduleLoadPath)
moduleOptionsFilePath := filepath.Join(rootDir, moduleOptionsPath)
moduleDisableFilePath := filepath.Join(rootDir, moduleDisabledPath)

moduleLoadContent, err := os.ReadFile(moduleLoadFilePath)
if err != nil {
Expand Down Expand Up @@ -118,8 +119,8 @@ func TestLoadOrDisableModules(t *testing.T) {

func TestEnsureModulesLoaded(t *testing.T) {
buildDir := filepath.Join(tmpDir, "TestEnsureModulesLoaded")
modulesLoadPath := filepath.Join(buildDir, "etc/modules-load.d")
moduleLoadFilePath := filepath.Join(modulesLoadPath, "modules.conf")
modulesLoadPath := filepath.Join(buildDir, modulesLoadConfigDir)
moduleLoadFilePath := filepath.Join(modulesLoadPath, moduleLoadFileName)

// Only create parent directory. Test case where the file does not exist
err := os.MkdirAll(modulesLoadPath, os.ModePerm)
Expand Down Expand Up @@ -153,8 +154,8 @@ func TestEnsureModulesLoaded(t *testing.T) {

func TestEnsureModulesDisabled(t *testing.T) {
buildDir := filepath.Join(tmpDir, "TestEnsureModulesDisabled")
modprobePath := filepath.Join(buildDir, "etc/modprobe.d")
moduleDisableFilePath := filepath.Join(modprobePath, "blacklist.conf")
modprobePath := filepath.Join(buildDir, modprobeConfigDir)
moduleDisableFilePath := filepath.Join(modprobePath, moduleDisabledFileName)
err := os.MkdirAll(modprobePath, os.ModePerm)
assert.NoError(t, err)

Expand Down Expand Up @@ -185,8 +186,8 @@ func TestEnsureModulesDisabled(t *testing.T) {

func TestRemoveModuleFromDisableList(t *testing.T) {
buildDir := filepath.Join(tmpDir, "TestRemoveModuleFromDisableList")
modprobePath := filepath.Join(buildDir, "etc/modprobe.d")
moduleDisableFilePath := filepath.Join(modprobePath, "blacklist.conf")
modprobePath := filepath.Join(buildDir, modprobeConfigDir)
moduleDisableFilePath := filepath.Join(modprobePath, moduleDisabledFileName)
err := os.MkdirAll(modprobePath, os.ModePerm)
assert.NoError(t, err)

Expand Down Expand Up @@ -216,3 +217,43 @@ func TestRemoveModuleFromDisableList(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, "blacklist module2\n", string(content))
}

func TestCustomizeImageKernelModules(t *testing.T) {
baseImage := checkSkipForCustomizeImage(t, baseImageTypeCoreEfi, baseImageVersionDefault)

testTmpDir := filepath.Join(tmpDir, "TestCustomizeImageKernelModules")
buildDir := filepath.Join(testTmpDir, "build")
configFile := filepath.Join(testDir, "modules-config.yaml")
outImageFilePath := filepath.Join(testTmpDir, "image.raw")

// Customize image.
err := CustomizeImageWithConfigFile(buildDir, configFile, baseImage, nil, outImageFilePath, "raw", "",
false /*useBaseImageRpmRepos*/, false /*enableShrinkFilesystems*/)
if !assert.NoError(t, err) {
return
}

imageConnection, err := connectToCoreEfiImage(buildDir, outImageFilePath)
if !assert.NoError(t, err) {
return
}
defer imageConnection.Close()

// Verify 'loadMode: always'
loadContent, err := file.Read(filepath.Join(imageConnection.Chroot().RootDir(), moduleLoadPath))
assert.NoError(t, err)
assert.Regexp(t, "(?m)^vfio$", loadContent)
assert.Regexp(t, "(?m)^mlx5_ib$", loadContent)

// Verify 'loadMode: disable'
disabledContent, err := file.Read(filepath.Join(imageConnection.Chroot().RootDir(), moduleDisabledPath))
assert.NoError(t, err)
assert.Regexp(t, "(?m)^blacklist mousedev$", disabledContent)

// Verify 'options'.
optionsContent, err := file.Read(filepath.Join(imageConnection.Chroot().RootDir(), moduleOptionsPath))
assert.NoError(t, err)
assert.Regexp(t, "(?m)^options vfio.* enable_unsafe_noiommu_mode=Y", optionsContent)
assert.Regexp(t, "(?m)^options vfio.* disable_vga=Y", optionsContent)
assert.Regexp(t, "(?m)^options e1000e InterruptThrottleRate=3000,3000,3000$", optionsContent)
}

0 comments on commit 9c978f0

Please sign in to comment.