Add initramfs stage to warewulfd
The initramfs stage supports serving an initramfs image from within the container image, typically generated by dracut. Signed-off-by: xu yang <xyang@ciq.com> Signed-off-by: Jonathon Anderson <janderson@ciq.com>
This commit is contained in:
committed by
Jonathon Anderson
parent
892db0f089
commit
a322061fe9
@@ -38,6 +38,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
### Added
|
||||
|
||||
- Add examples for building overlays in parallel to documentation
|
||||
- Add `stage=initramfs` to warewulfd provision to serve initramfs from container image. #1115
|
||||
|
||||
### Changed
|
||||
|
||||
|
||||
@@ -1,11 +1,25 @@
|
||||
package container
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
|
||||
"github.com/warewulf/warewulf/internal/pkg/util"
|
||||
"github.com/warewulf/warewulf/internal/pkg/wwlog"
|
||||
|
||||
warewulfconf "github.com/warewulf/warewulf/internal/pkg/config"
|
||||
)
|
||||
|
||||
var (
|
||||
initramfsSearchPaths = []string{
|
||||
// This is a printf format where the %s will be the kernel version
|
||||
"boot/initramfs-%s",
|
||||
"boot/initramfs-%s.img",
|
||||
"boot/initrd-%s",
|
||||
"boot/initrd-%s.img",
|
||||
}
|
||||
)
|
||||
|
||||
func SourceParentDir() string {
|
||||
conf := warewulfconf.Get()
|
||||
return conf.Paths.WWChrootdir
|
||||
@@ -27,3 +41,16 @@ func ImageParentDir() string {
|
||||
func ImageFile(name string) string {
|
||||
return path.Join(ImageParentDir(), name+".img")
|
||||
}
|
||||
|
||||
// InitramfsBootPath returns the dracut built initramfs path, as dracut built initramfs inside container
|
||||
// the function returns host path of the built file
|
||||
func InitramfsBootPath(image, kver string) (string, error) {
|
||||
for _, searchPath := range initramfsSearchPaths {
|
||||
initramfs_path := path.Join(RootFsDir(image), fmt.Sprintf(searchPath, kver))
|
||||
wwlog.Debug("Looking for initramfs at: %s", initramfs_path)
|
||||
if util.IsFile(initramfs_path) {
|
||||
return initramfs_path, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("Failed to find a target kernel version initramfs")
|
||||
}
|
||||
|
||||
88
internal/pkg/container/config_test.go
Normal file
88
internal/pkg/container/config_test.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package container
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
warewulfconf "github.com/warewulf/warewulf/internal/pkg/config"
|
||||
)
|
||||
|
||||
func TestInitramfsBootPath(t *testing.T) {
|
||||
conf := warewulfconf.Get()
|
||||
temp, err := os.MkdirTemp(os.TempDir(), "ww-conf-*")
|
||||
assert.NoError(t, err)
|
||||
defer os.RemoveAll(temp)
|
||||
conf.Paths.WWChrootdir = temp
|
||||
|
||||
assert.NoError(t, os.MkdirAll(filepath.Join(RootFsDir("image"), "boot"), 0700))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
initramfs []string
|
||||
ver string
|
||||
err error
|
||||
retName string
|
||||
}{
|
||||
{
|
||||
name: "ok case 1",
|
||||
initramfs: []string{"initramfs-1.1.1.aarch64.img"},
|
||||
ver: "1.1.1.aarch64",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "ok case 2",
|
||||
initramfs: []string{"initrd-1.1.1.aarch64"},
|
||||
ver: "1.1.1.aarch64",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "ok case 3",
|
||||
initramfs: []string{"initramfs-1.1.1.aarch64"},
|
||||
ver: "1.1.1.aarch64",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "ok case 4",
|
||||
initramfs: []string{"initrd-1.1.1.aarch64.img"},
|
||||
ver: "1.1.1.aarch64",
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "error case, wrong init name",
|
||||
initramfs: []string{"initrr-1.1.1.aarch64.img"},
|
||||
ver: "1.1.1.aarch64",
|
||||
err: fmt.Errorf("Failed to find a target kernel version initramfs"),
|
||||
},
|
||||
{
|
||||
name: "error case, wrong ver",
|
||||
initramfs: []string{"initrr-1.1.1.aarch64.img"},
|
||||
ver: "1.1.2.aarch64",
|
||||
err: fmt.Errorf("Failed to find a target kernel version initramfs"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Logf("running test: %s", tt.name)
|
||||
for _, init := range tt.initramfs {
|
||||
assert.NoError(t, os.WriteFile(filepath.Join(RootFsDir("image"), "boot", init), []byte(""), 0600))
|
||||
}
|
||||
initPath, err := InitramfsBootPath("image", tt.ver)
|
||||
assert.Equal(t, tt.err, err)
|
||||
if err == nil {
|
||||
assert.NotEmpty(t, initPath)
|
||||
} else {
|
||||
assert.Empty(t, initPath)
|
||||
}
|
||||
|
||||
if tt.retName != "" {
|
||||
assert.Equal(t, filepath.Base(initPath), tt.retName)
|
||||
}
|
||||
// remove the file
|
||||
for _, init := range tt.initramfs {
|
||||
assert.NoError(t, os.Remove(filepath.Join(RootFsDir("image"), "boot", init)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -73,6 +73,8 @@ func parseReq(req *http.Request) (parserInfo, error) {
|
||||
ret.stage = "runtime"
|
||||
} else if stage == "efiboot" {
|
||||
ret.stage = "efiboot"
|
||||
} else if stage == "initramfs" {
|
||||
ret.stage = "initramfs"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -56,12 +56,13 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
|
||||
status_stages := map[string]string{
|
||||
"efiboot": "EFI",
|
||||
"ipxe": "IPXE",
|
||||
"kernel": "KERNEL",
|
||||
"kmods": "KMODS_OVERLAY",
|
||||
"system": "SYSTEM_OVERLAY",
|
||||
"runtime": "RUNTIME_OVERLAY"}
|
||||
"efiboot": "EFI",
|
||||
"ipxe": "IPXE",
|
||||
"kernel": "KERNEL",
|
||||
"kmods": "KMODS_OVERLAY",
|
||||
"system": "SYSTEM_OVERLAY",
|
||||
"runtime": "RUNTIME_OVERLAY",
|
||||
"initramfs": "INITRAMFS"}
|
||||
|
||||
status_stage := status_stages[rinfo.stage]
|
||||
var stage_file string
|
||||
@@ -213,6 +214,19 @@ func ProvisionSend(w http.ResponseWriter, req *http.Request) {
|
||||
} else {
|
||||
wwlog.Warn("No conainer set for node %s", node.Id.Get())
|
||||
}
|
||||
} else if rinfo.stage == "initramfs" {
|
||||
if node.ContainerName.Defined() {
|
||||
_, kver, err := kernel.FindKernel(container.RootFsDir(node.ContainerName.Get()))
|
||||
if err != nil {
|
||||
wwlog.Error("No kernel found for initramfs for container %s: %s", node.ContainerName.Get(), err)
|
||||
}
|
||||
stage_file, err = container.InitramfsBootPath(node.ContainerName.Get(), kver)
|
||||
if err != nil {
|
||||
wwlog.Error("No initramfs found for container %s: %s", node.ContainerName.Get(), err)
|
||||
}
|
||||
} else {
|
||||
wwlog.Warn("No container set for node %s", node.Id.Get())
|
||||
}
|
||||
}
|
||||
|
||||
wwlog.Serv("stage_file '%s'", stage_file)
|
||||
|
||||
@@ -30,6 +30,7 @@ var provisionSendTests = []struct {
|
||||
{"find shim", "/efiboot/shim.efi", "", 404, "10.10.10.11:9873"},
|
||||
{"find grub", "/efiboot/grub.efi", "", 200, "10.10.10.10:9873"},
|
||||
{"find grub", "/efiboot/grub.efi", "", 404, "10.10.10.11:9873"},
|
||||
{"find initramfs", "/provision/00:00:00:ff:ff:ff?stage=initramfs", "", 200, "10.10.10.10:9873"},
|
||||
}
|
||||
|
||||
func Test_ProvisionSend(t *testing.T) {
|
||||
@@ -84,6 +85,11 @@ nodes:
|
||||
_, err := os.Create(path.Join(containerDir, "suse/rootfs/usr/share/efi/x86_64/", "grub.efi"))
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
assert.NoError(t, os.MkdirAll(path.Join(containerDir, "suse/rootfs/boot"), 0700))
|
||||
{
|
||||
_, err := os.Create(path.Join(containerDir, "suse/rootfs/boot", "initramfs-.img"))
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
dbErr := LoadNodeDB()
|
||||
assert.NoError(t, dbErr)
|
||||
|
||||
Reference in New Issue
Block a user