Merge pull request #1145 from mslacken/ShimGrubArm

Tests and fix for shim and grub detection on aarch64
This commit is contained in:
Jonathon Anderson
2024-04-19 16:38:04 -06:00
committed by GitHub
9 changed files with 114 additions and 120 deletions

View File

@@ -61,6 +61,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Fix Suse package by moving yq command to `%install` section. #1169
- Fix a rendering bug in the documentation for GRUB boot support. #1132
- Fix a locking issue with concurrent read/writes for node status. #1174
- Fix shim and grub detection for aarch64. #1145
## 4.5.0, 2024-02-08

View File

@@ -37,10 +37,9 @@ func CobraRunE(cmd *cobra.Command, args []string) error {
if len(args) > 0 {
kernelVersion = args[0]
} else {
kernelVersion, err = kernel.FindKernelVersion(OptRoot)
_, kernelVersion, err = kernel.FindKernel(OptRoot)
if err != nil {
wwlog.Error("could not detect kernel under %s", OptRoot)
os.Exit(1)
return err
}
}
kernelName := kernelVersion

View File

@@ -11,6 +11,7 @@ import (
"github.com/pkg/errors"
"github.com/warewulf/warewulf/internal/pkg/api/routes/wwapiv1"
"github.com/warewulf/warewulf/internal/pkg/container"
"github.com/warewulf/warewulf/internal/pkg/kernel"
"github.com/warewulf/warewulf/internal/pkg/node"
"github.com/warewulf/warewulf/internal/pkg/util"
"github.com/warewulf/warewulf/internal/pkg/warewulfd"
@@ -272,7 +273,7 @@ func ContainerList() (containerInfo []*wwapiv1.ContainerInfo, err error) {
}
wwlog.Debug("Finding kernel version for: %s", source)
kernelVersion := container.KernelVersion(source)
_, kernelVersion, _ := kernel.FindKernel(container.RootFsDir(source))
containerInfo = append(containerInfo, &wwapiv1.ContainerInfo{
Name: source,

View File

@@ -12,6 +12,7 @@ import (
"github.com/pkg/errors"
"github.com/warewulf/warewulf/internal/pkg/api/routes/wwapiv1"
"github.com/warewulf/warewulf/internal/pkg/container"
"github.com/warewulf/warewulf/internal/pkg/kernel"
"github.com/warewulf/warewulf/internal/pkg/node"
"github.com/warewulf/warewulf/internal/pkg/util"
"github.com/warewulf/warewulf/internal/pkg/warewulfd"
@@ -324,7 +325,7 @@ func ContainerList() (containerInfo []*wwapiv1.ContainerInfo, err error) {
}
wwlog.Debug("Finding kernel version for: %s", source)
kernelVersion := container.KernelVersion(source)
_, kernelVersion, _ := kernel.FindKernel(container.RootFsDir(source))
var creationTime uint64
sourceStat, err := os.Stat(container.SourceDir(source))
if err != nil {
@@ -376,7 +377,7 @@ func ContainerShow(csp *wwapiv1.ContainerShowParameter) (response *wwapiv1.Conta
err = fmt.Errorf("%s is not a valid container", containerName)
return
}
kernelVersion := container.KernelVersion(containerName)
_, kernelVersion, _ := kernel.FindKernel(container.RootFsDir(containerName))
nodeDB, err := node.New()
if err != nil {

View File

@@ -1,78 +0,0 @@
package container
import (
"path"
"path/filepath"
"sort"
"strings"
"github.com/warewulf/warewulf/internal/pkg/wwlog"
)
var (
kernelNames = []string{
`vmlinux`,
`vmlinuz`,
`vmlinux-*`,
`vmlinuz-*`,
`vmlinuz.gz`}
kernelDirs = []string{
`/lib/modules/*/`,
`/boot/`}
)
func KernelFind(container string) string {
wwlog.Debug("Finding kernel")
container_path := RootFsDir(container)
if container_path == "" {
return ""
}
for _, kdir := range kernelDirs {
wwlog.Debug("Checking kernel directory: %s", kdir)
for _, kname := range kernelNames {
wwlog.Debug("Checking for kernel name: %s", kname)
kernelPaths, err := filepath.Glob(path.Join(container_path, kdir, kname))
if err != nil {
return ""
}
if len(kernelPaths) == 0 {
continue
}
sort.Slice(kernelPaths, func(i, j int) bool {
return kernelPaths[i] > kernelPaths[j]
})
for _, kernelPath := range kernelPaths {
wwlog.Debug("Checking for kernel path: %s", kernelPath)
// Only succeeds if kernelPath exists and, if a
// symlink, links to a path that also exists
kernelPath, err = filepath.EvalSymlinks(kernelPath)
if err == nil {
wwlog.Debug("found kernel: %s", kernelPath)
return kernelPath
}
}
}
}
return ""
}
func KernelVersion(container string) string {
wwlog.Debug("Finding kernel version inside container: %s", container)
kernel := KernelFind(container)
if kernel == "" {
return ""
}
ret := path.Base(path.Dir(kernel))
if ret == "boot" {
ret = path.Base(kernel)
}
return strings.TrimPrefix(ret, "vmlinuz-")
}

View File

@@ -10,7 +10,7 @@ import (
func shimDirs() []string {
return []string{
`/usr/share/efi/x86_64/`,
`/usr/share/efi/*/`,
`/usr/lib64/efi/`,
`/boot/efi/EFI/*/`,
}
@@ -53,7 +53,7 @@ func ShimFind(container string) string {
} else {
container_path = "/"
}
wwlog.Debug("Finding grub under paths: %s", container_path)
wwlog.Debug("Finding shim under paths: %s", container_path)
return BootLoaderFindPath(container_path, shimNames, shimDirs)
}
@@ -76,10 +76,13 @@ find the path of the shim binary in container
*/
func BootLoaderFindPath(cpath string, names func() []string, paths func() []string) string {
for _, bdir := range paths() {
wwlog.Debug("Checking shim directory: %s", bdir)
wwlog.Debug("Checking directory: %s", bdir)
for _, bname := range names() {
wwlog.Debug("Checking for bootloader name: %s", bname)
shimPaths, _ := filepath.Glob(path.Join(cpath, bdir, bname))
wwlog.Debug("Checking for bootloader name: %s", path.Join(cpath, bdir, bname))
shimPaths, err := filepath.Glob(path.Join(cpath, bdir, bname))
if err != nil {
wwlog.Debug("Got error when globing %s: %s", path.Join(cpath, bdir, bname), err)
}
for _, shimPath := range shimPaths {
wwlog.Debug("Checking for bootloader path: %s", shimPath)
// Only succeeds if shimPath exists and, if a

View File

@@ -0,0 +1,61 @@
package container
import (
"os"
"path"
"testing"
"github.com/stretchr/testify/assert"
warewulfconf "github.com/warewulf/warewulf/internal/pkg/config"
"github.com/warewulf/warewulf/internal/pkg/testenv"
"github.com/warewulf/warewulf/internal/pkg/wwlog"
)
func Test_Find_ShimX86(t *testing.T) {
testenv.New(t)
conf := warewulfconf.Get()
wwlog.SetLogLevel(wwlog.DEBUG)
_ = os.MkdirAll(path.Join(conf.Paths.WWChrootdir, "suse/rootfs/usr/lib64/efi/"), 0755)
shimF, err := os.Create(path.Join(conf.Paths.WWChrootdir, "suse/rootfs/usr/lib64/efi/shim.efi"))
assert.NoError(t, err)
_, _ = shimF.WriteString("shim.efi")
assert.FileExists(t, path.Join(conf.Paths.WWChrootdir, "suse/rootfs/usr/lib64/efi/shim.efi"))
shimPath := ShimFind("suse")
assert.Equal(t, path.Join(conf.Paths.WWChrootdir, "suse/rootfs/usr/lib64/efi/shim.efi"), shimPath)
}
func Test_Find_ShimArch64(t *testing.T) {
testenv.New(t)
conf := warewulfconf.Get()
wwlog.SetLogLevel(wwlog.DEBUG)
_ = os.MkdirAll(path.Join(conf.Paths.WWChrootdir, "suse/rootfs/usr/share/efi/aarch64"), 0755)
shimF, err := os.Create(path.Join(conf.Paths.WWChrootdir, "suse/rootfs/usr/share/efi/aarch64/shim.efi"))
assert.NoError(t, err)
_, _ = shimF.WriteString("shim.efi")
assert.FileExists(t, path.Join(conf.Paths.WWChrootdir, "suse/rootfs/usr/share/efi/aarch64/shim.efi"))
shimPath := ShimFind("suse")
assert.Equal(t, path.Join(conf.Paths.WWChrootdir, "suse/rootfs/usr/share/efi/aarch64/shim.efi"), shimPath)
}
func Test_Find_GrubX86(t *testing.T) {
testenv.New(t)
conf := warewulfconf.Get()
wwlog.SetLogLevel(wwlog.DEBUG)
_ = os.MkdirAll(path.Join(conf.Paths.WWChrootdir, "suse/rootfs/usr/share/efi/x86_64"), 0755)
shimF, err := os.Create(path.Join(conf.Paths.WWChrootdir, "suse/rootfs/usr/share/efi/x86_64/grub.efi"))
assert.NoError(t, err)
_, _ = shimF.WriteString("grub.efi")
assert.FileExists(t, path.Join(conf.Paths.WWChrootdir, "suse/rootfs//usr/share/efi/x86_64/grub.efi"))
shimPath := GrubFind("suse")
assert.Equal(t, path.Join(conf.Paths.WWChrootdir, "suse/rootfs/usr/share/efi/x86_64/grub.efi"), shimPath)
}
func Test_Find_GrubAarch64(t *testing.T) {
testenv.New(t)
conf := warewulfconf.Get()
wwlog.SetLogLevel(wwlog.DEBUG)
_ = os.MkdirAll(path.Join(conf.Paths.WWChrootdir, "suse/rootfs/usr/share/efi/aarch64/"), 0755)
shimF, err := os.Create(path.Join(conf.Paths.WWChrootdir, "suse/rootfs/usr/share/efi/aarch64/grub.efi"))
assert.NoError(t, err)
_, _ = shimF.WriteString("grub.efi")
assert.FileExists(t, path.Join(conf.Paths.WWChrootdir, "suse/rootfs/usr/share/efi/aarch64/grub.efi"))
shimPath := GrubFind("suse")
assert.Equal(t, path.Join(conf.Paths.WWChrootdir, "suse/rootfs/usr/share/efi/aarch64/grub.efi"), shimPath)
}

View File

@@ -8,6 +8,7 @@ import (
"path"
"path/filepath"
"regexp"
"strings"
"github.com/pkg/errors"
@@ -19,12 +20,18 @@ import (
var (
kernelSearchPaths = []string{
// This is a printf format where the %s will be the kernel version
"/boot/Image-%s", // this is the aarch64 for SUSE, vmlinux which is also present won't boot
"/boot/vmlinuz-linux%.s",
"/boot/vmlinuz-%s",
"/boot/vmlinuz-%s.gz",
"/lib/modules/%s/vmlinuz",
"/lib/modules/%s/vmlinuz.gz",
}
kernelDrivers = []string{
"lib/modules/%s/*",
"lib/firmware/*",
"lib/modprobe.d",
"lib/modules-load.d"}
)
func KernelImageTopDir() string {
@@ -117,15 +124,9 @@ kernel version. A name for this kernel and were to find has also to be
supplied
*/
func Build(kernelVersion, kernelName, root string) error {
kernelDrivers := []string{path.Join("lib/modules/",
kernelVersion, "*"),
"lib/firmware/*",
"lib/modprobe.d",
"lib/modules-load.d"}
kernelDestination := KernelImage(kernelName)
driversDestination := KmodsImage(kernelName)
versionDestination := KernelVersionFile(kernelName)
var kernelSource string
// Create the destination paths just in case it doesn't exist
err := os.MkdirAll(path.Dir(kernelDestination), 0755)
@@ -143,18 +144,11 @@ func Build(kernelVersion, kernelName, root string) error {
return fmt.Errorf("failed to create version dest: %s", err)
}
for _, searchPath := range kernelSearchPaths {
testPath := fmt.Sprintf(path.Join(root, searchPath), kernelVersion)
wwlog.Verbose("Looking for kernel at: %s", testPath)
if util.IsFile(testPath) {
kernelSource = testPath
break
}
}
if kernelSource == "" {
wwlog.Error("Could not locate kernel image")
return errors.New("could not locate kernel image")
kernelSource, kernelVersFound, err := FindKernel(root)
if err != nil {
return err
} else if kernelVersFound != kernelVersion {
return fmt.Errorf("requested %s and found kernel version %s differ", kernelVersion, kernelVersFound)
} else {
wwlog.Info("Found kernel at: %s", kernelSource)
}
@@ -193,13 +187,21 @@ func Build(kernelVersion, kernelName, root string) error {
}
name := kernelName + " drivers"
var kernelDriversSpecific []string
for _, kPath := range kernelDrivers {
if strings.Contains(kPath, "%s") {
kernelDriversSpecific = append(kernelDriversSpecific, fmt.Sprintf(kPath, kernelVersion))
} else {
kernelDriversSpecific = append(kernelDriversSpecific, kPath)
}
}
wwlog.Debug("kernelDriversSpecific: %v", kernelDriversSpecific)
wwlog.Verbose("Creating image for %s: %s", name, root)
err = util.BuildFsImage(
name,
root,
driversDestination,
kernelDrivers,
kernelDriversSpecific,
[]string{},
// ignore cross-device files
true,
@@ -235,27 +237,32 @@ func DeleteKernel(name string) error {
return os.RemoveAll(fullPath)
}
func FindKernelVersion(root string) (string, error) {
/*
Searches for kernel under a given path. First return result is the
full path, second the version and an error if the kernel couldn't be found.
*/
func FindKernel(root string) (kPath string, version string, err error) {
wwlog.Debug("root: %s", root)
for _, searchPath := range kernelSearchPaths {
testPattern := fmt.Sprintf(path.Join(root, searchPath), `*`)
wwlog.Verbose("Looking for kernel version with pattern at: %s", testPattern)
wwlog.Debug("Looking for kernel version with pattern at: %s", testPattern)
potentialKernel, _ := filepath.Glob(testPattern)
if len(potentialKernel) == 0 {
continue
}
for _, foundKernel := range potentialKernel {
wwlog.Verbose("Parsing out kernel version for %s", foundKernel)
wwlog.Debug("Parsing out kernel version for %s", foundKernel)
re := regexp.MustCompile(fmt.Sprintf(path.Join(root, searchPath), `([\w\d-\.]*)`))
version := re.FindAllStringSubmatch(foundKernel, -1)
if version == nil {
return "", fmt.Errorf("could not parse kernel version")
return foundKernel, "", fmt.Errorf("could not parse kernel version")
}
wwlog.Verbose("found kernel version %s", version)
return version[0][1], nil
wwlog.Verbose("found kernel version %s", strings.TrimSuffix(version[0][1], ".gz"))
return foundKernel, strings.TrimSuffix(version[0][1], ".gz"), nil
}
}
return "", fmt.Errorf("could not find kernel version")
return "", "", fmt.Errorf("could not find kernel version")
}

View File

@@ -108,10 +108,9 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
if node.Kernel.Override.Defined() {
stage_file = kernel.KernelImage(node.Kernel.Override.Get())
} else if node.ContainerName.Defined() {
stage_file = container.KernelFind(node.ContainerName.Get())
if stage_file == "" {
wwlog.Error("No kernel found for container %s", node.ContainerName.Get())
stage_file, _, err = kernel.FindKernel(container.RootFsDir(node.ContainerName.Get()))
if err != nil {
wwlog.Error("No kernel found for container %s: %s", node.ContainerName.Get(), err)
}
} else {
wwlog.Warn("No kernel version set for node %s", node.Id.Get())