mirror of
https://github.com/kairos-io/kairos-agent.git
synced 2025-04-27 03:11:14 +00:00
Use grub binaries and libs from rootfs (#760)
This commit is contained in:
parent
5d5a52930f
commit
d0f0710c78
@ -43,7 +43,11 @@ func (k Finish) Run(c config.Config, spec v1.Spec) error {
|
|||||||
c.Logger.Logger.Info().Msg("Finished encrypt hook")
|
c.Logger.Logger.Info().Msg("Finished encrypt hook")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now that we have everything encrypted and ready if needed
|
// Now that we have everything encrypted and ready to mount if needed
|
||||||
|
err = GrubPostInstallOptions{}.Run(c, spec)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
err = BundlePostInstall{}.Run(c, spec)
|
err = BundlePostInstall{}.Run(c, spec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Logger.Logger.Warn().Err(err).Msg("could not copy run bundles post install")
|
c.Logger.Logger.Warn().Err(err).Msg("could not copy run bundles post install")
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
package hook
|
package hook
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/kairos-io/kairos-agent/v2/pkg/config"
|
||||||
|
cnst "github.com/kairos-io/kairos-agent/v2/pkg/constants"
|
||||||
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
|
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
|
||||||
"strings"
|
"github.com/kairos-io/kairos-agent/v2/pkg/utils"
|
||||||
|
"github.com/kairos-io/kairos-sdk/machine"
|
||||||
config "github.com/kairos-io/kairos-agent/v2/pkg/config"
|
"github.com/kairos-io/kairos-sdk/state"
|
||||||
"github.com/kairos-io/kairos-sdk/system"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GrubOptions struct{}
|
type GrubOptions struct{}
|
||||||
@ -16,9 +18,9 @@ func (b GrubOptions) Run(c config.Config, _ v1.Spec) error {
|
|||||||
}
|
}
|
||||||
c.Logger.Logger.Debug().Msg("Running GrubOptions hook")
|
c.Logger.Logger.Debug().Msg("Running GrubOptions hook")
|
||||||
c.Logger.Debugf("Setting grub options: %s", c.Install.GrubOptions)
|
c.Logger.Debugf("Setting grub options: %s", c.Install.GrubOptions)
|
||||||
err := system.Apply(system.SetGRUBOptions(c.Install.GrubOptions))
|
err := grubOptions(c, c.Install.GrubOptions)
|
||||||
if err != nil && !strings.Contains(err.Error(), "0 errors occurred") {
|
if err != nil {
|
||||||
c.Logger.Logger.Error().Err(err).Msg("Failed to set grub options")
|
return err
|
||||||
}
|
}
|
||||||
c.Logger.Logger.Debug().Msg("Finish GrubOptions hook")
|
c.Logger.Logger.Debug().Msg("Finish GrubOptions hook")
|
||||||
return nil
|
return nil
|
||||||
@ -31,10 +33,32 @@ func (b GrubPostInstallOptions) Run(c config.Config, _ v1.Spec) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
c.Logger.Logger.Debug().Msg("Running GrubOptions hook")
|
c.Logger.Logger.Debug().Msg("Running GrubOptions hook")
|
||||||
err := system.Apply(system.SetGRUBOptions(c.GrubOptions))
|
c.Logger.Debugf("Setting grub options: %s", c.GrubOptions)
|
||||||
|
err := grubOptions(c, c.GrubOptions)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.Logger.Logger.Debug().Msg("Finish GrubOptions hook")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// grubOptions sets the grub options in the grubenv file
|
||||||
|
// It mounts the OEM partition if not already mounted
|
||||||
|
// If its mounted but RO, it remounts it as RW
|
||||||
|
func grubOptions(c config.Config, opts map[string]string) error {
|
||||||
|
runtime, err := state.NewRuntime()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !runtime.OEM.Mounted {
|
||||||
|
err = machine.Mount(cnst.OEMLabel, cnst.OEMPath)
|
||||||
|
defer func() {
|
||||||
|
_ = machine.Umount(cnst.OEMPath)
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
err = utils.SetPersistentVariables(filepath.Join(runtime.OEM.MountPoint, "grubenv"), opts, &c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Logger.Logger.Error().Err(err).Msg("Failed to set grub options")
|
c.Logger.Logger.Error().Err(err).Msg("Failed to set grub options")
|
||||||
}
|
}
|
||||||
c.Logger.Logger.Debug().Msg("Running GrubOptions hook")
|
return err
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ package hook
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
config "github.com/kairos-io/kairos-agent/v2/pkg/config"
|
"github.com/kairos-io/kairos-agent/v2/pkg/config"
|
||||||
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
|
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
|
||||||
"github.com/kairos-io/kairos-sdk/utils"
|
"github.com/kairos-io/kairos-sdk/utils"
|
||||||
"strings"
|
"strings"
|
||||||
@ -15,8 +15,7 @@ type Interface interface {
|
|||||||
// FinishInstall is a list of hooks that run when the install process is finished completely.
|
// FinishInstall is a list of hooks that run when the install process is finished completely.
|
||||||
// Its mean for options that are not related to the install process itself
|
// Its mean for options that are not related to the install process itself
|
||||||
var FinishInstall = []Interface{
|
var FinishInstall = []Interface{
|
||||||
&GrubOptions{}, // Set custom GRUB options in OEM partition
|
&Lifecycle{}, // Handles poweroff/reboot by config options
|
||||||
&Lifecycle{}, // Handles poweroff/reboot by config options
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FinishReset is a list of hooks that run when the reset process is finished completely.
|
// FinishReset is a list of hooks that run when the reset process is finished completely.
|
||||||
@ -46,7 +45,7 @@ var FinishUKIInstall = []Interface{
|
|||||||
// PostInstall is a list of hooks that run after the install process has run.
|
// PostInstall is a list of hooks that run after the install process has run.
|
||||||
// Runs things that need to be done before we run other post install stages like
|
// Runs things that need to be done before we run other post install stages like
|
||||||
// encrypting partitions, copying the install logs or installing bundles
|
// encrypting partitions, copying the install logs or installing bundles
|
||||||
// Most of this options are optional so they are not run by default unless specified int he config
|
// Most of this options are optional so they are not run by default unless specified in the config
|
||||||
var PostInstall = []Interface{
|
var PostInstall = []Interface{
|
||||||
&Finish{},
|
&Finish{},
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ func selectBootEntryGrub(cfg *config.Config, entry string) error {
|
|||||||
vars := map[string]string{
|
vars := map[string]string{
|
||||||
"next_entry": entry,
|
"next_entry": entry,
|
||||||
}
|
}
|
||||||
err = utils.SetPersistentVariables("/oem/grubenv", vars, cfg.Fs)
|
err = utils.SetPersistentVariables("/oem/grubenv", vars, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cfg.Logger.Errorf("could not set default boot entry: %s\n", err)
|
cfg.Logger.Errorf("could not set default boot entry: %s\n", err)
|
||||||
return err
|
return err
|
||||||
|
@ -694,7 +694,7 @@ var _ = Describe("Bootentries tests", Label("bootentry"), func() {
|
|||||||
err = SelectBootEntry(config, "kairos")
|
err = SelectBootEntry(config, "kairos")
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(memLog.String()).To(ContainSubstring("Default boot entry set to kairos"))
|
Expect(memLog.String()).To(ContainSubstring("Default boot entry set to kairos"))
|
||||||
variables, err := utils.ReadPersistentVariables("/oem/grubenv", fs)
|
variables, err := utils.ReadPersistentVariables("/oem/grubenv", config)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(variables["next_entry"]).To(Equal("kairos"))
|
Expect(variables["next_entry"]).To(Equal("kairos"))
|
||||||
})
|
})
|
||||||
|
@ -28,7 +28,6 @@ import (
|
|||||||
agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config"
|
agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config"
|
||||||
"github.com/kairos-io/kairos-agent/v2/pkg/constants"
|
"github.com/kairos-io/kairos-agent/v2/pkg/constants"
|
||||||
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
|
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
|
||||||
"github.com/kairos-io/kairos-agent/v2/pkg/utils"
|
|
||||||
fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
|
fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
|
||||||
v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks"
|
v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks"
|
||||||
"github.com/kairos-io/kairos-sdk/collector"
|
"github.com/kairos-io/kairos-sdk/collector"
|
||||||
@ -150,6 +149,16 @@ var _ = Describe("Install action tests", func() {
|
|||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
_, err = fs.Create(grubCfg)
|
_, err = fs.Create(grubCfg)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
|
// Create fake grub dir in rootfs and fake grub binaries
|
||||||
|
err = fsutils.MkdirAll(fs, filepath.Join(spec.Active.MountPoint, "sbin"), constants.DirPerm)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
f, err := fs.Create(filepath.Join(spec.Active.MountPoint, "sbin", "grub2-install"))
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(f.Chmod(0755)).ToNot(HaveOccurred())
|
||||||
|
err = fsutils.MkdirAll(fs, filepath.Join(spec.Active.MountPoint, "usr", "lib", "grub", "i386-pc"), constants.DirPerm)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
_, err = fs.Create(filepath.Join(spec.Active.MountPoint, "usr", "lib", "grub", "i386-pc", "modinfo.sh"))
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
|
||||||
mainDisk := sdkTypes.Disk{
|
mainDisk := sdkTypes.Disk{
|
||||||
Name: "device",
|
Name: "device",
|
||||||
@ -349,9 +358,10 @@ var _ = Describe("Install action tests", func() {
|
|||||||
Expect(cl.WasGetCalledWith("http://my.config.org")).To(BeTrue())
|
Expect(cl.WasGetCalledWith("http://my.config.org")).To(BeTrue())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("Fails on grub2-install errors", Label("grub"), func() {
|
It("Fails to find grub2-install", Label("grub"), func() {
|
||||||
spec.Target = device
|
spec.Target = device
|
||||||
cmdFail = utils.FindCommand("grub2-install", []string{"grub2-install", "grub-install"})
|
err := config.Fs.Remove(filepath.Join(spec.Active.MountPoint, "sbin", "grub2-install"))
|
||||||
|
Expect(err).To(BeNil())
|
||||||
Expect(installer.Run()).NotTo(BeNil())
|
Expect(installer.Run()).NotTo(BeNil())
|
||||||
Expect(runner.MatchMilestones([][]string{{"grub2-install"}}))
|
Expect(runner.MatchMilestones([][]string{{"grub2-install"}}))
|
||||||
})
|
})
|
||||||
@ -362,5 +372,12 @@ var _ = Describe("Install action tests", func() {
|
|||||||
Expect(installer.Run()).NotTo(BeNil())
|
Expect(installer.Run()).NotTo(BeNil())
|
||||||
Expect(runner.MatchMilestones([][]string{{"tune2fs", "-L", constants.PassiveLabel}}))
|
Expect(runner.MatchMilestones([][]string{{"tune2fs", "-L", constants.PassiveLabel}}))
|
||||||
})
|
})
|
||||||
|
It("Fails if there is no grub2 artifacts", Label("grub"), func() {
|
||||||
|
spec.Target = device
|
||||||
|
err := config.Fs.Remove(filepath.Join(spec.Active.MountPoint, "usr", "lib", "grub", "i386-pc", "modinfo.sh"))
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(installer.Run()).NotTo(BeNil())
|
||||||
|
Expect(runner.MatchMilestones([][]string{{"grub2-install"}}))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -130,7 +130,8 @@ var _ = Describe("Reset action tests", func() {
|
|||||||
ghwTest.AddDisk(mainDisk)
|
ghwTest.AddDisk(mainDisk)
|
||||||
ghwTest.CreateDevices()
|
ghwTest.CreateDevices()
|
||||||
|
|
||||||
fs.Create(constants.EfiDevice)
|
Expect(fsutils.MkdirAll(fs, constants.EfiDevice, constants.DirPerm)).ToNot(HaveOccurred())
|
||||||
|
|
||||||
bootedFrom = constants.SystemLabel
|
bootedFrom = constants.SystemLabel
|
||||||
runner.SideEffect = func(cmd string, args ...string) ([]byte, error) {
|
runner.SideEffect = func(cmd string, args ...string) ([]byte, error) {
|
||||||
if cmd == cmdFail {
|
if cmd == cmdFail {
|
||||||
|
@ -584,7 +584,7 @@ func (e Elemental) SetDefaultGrubEntry(partMountPoint string, imgMountPoint stri
|
|||||||
return utils.SetPersistentVariables(
|
return utils.SetPersistentVariables(
|
||||||
filepath.Join(partMountPoint, cnst.GrubOEMEnv),
|
filepath.Join(partMountPoint, cnst.GrubOEMEnv),
|
||||||
map[string]string{"default_menu_entry": defaultEntry},
|
map[string]string{"default_menu_entry": defaultEntry},
|
||||||
e.config.Fs,
|
e.config,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -848,7 +848,7 @@ var _ = Describe("Elemental", Label("elemental"), func() {
|
|||||||
el := elemental.NewElemental(config)
|
el := elemental.NewElemental(config)
|
||||||
Expect(config.Fs.Mkdir("/tmp", cnst.DirPerm)).To(BeNil())
|
Expect(config.Fs.Mkdir("/tmp", cnst.DirPerm)).To(BeNil())
|
||||||
Expect(el.SetDefaultGrubEntry("/tmp", "/imgMountpoint", "dio")).To(BeNil())
|
Expect(el.SetDefaultGrubEntry("/tmp", "/imgMountpoint", "dio")).To(BeNil())
|
||||||
varsParsed, err := utils.ReadPersistentVariables(filepath.Join("/tmp", cnst.GrubOEMEnv), config.Fs)
|
varsParsed, err := utils.ReadPersistentVariables(filepath.Join("/tmp", cnst.GrubOEMEnv), config)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
Expect(varsParsed["default_menu_entry"]).To(Equal("dio"))
|
Expect(varsParsed["default_menu_entry"]).To(Equal("dio"))
|
||||||
})
|
})
|
||||||
@ -856,7 +856,7 @@ var _ = Describe("Elemental", Label("elemental"), func() {
|
|||||||
el := elemental.NewElemental(config)
|
el := elemental.NewElemental(config)
|
||||||
Expect(config.Fs.Mkdir("/mountpoint", cnst.DirPerm)).To(BeNil())
|
Expect(config.Fs.Mkdir("/mountpoint", cnst.DirPerm)).To(BeNil())
|
||||||
Expect(el.SetDefaultGrubEntry("/mountpoint", "/imgMountPoint", "")).To(BeNil())
|
Expect(el.SetDefaultGrubEntry("/mountpoint", "/imgMountPoint", "")).To(BeNil())
|
||||||
_, err := utils.ReadPersistentVariables(filepath.Join("/tmp", cnst.GrubOEMEnv), config.Fs)
|
_, err := utils.ReadPersistentVariables(filepath.Join("/tmp", cnst.GrubOEMEnv), config)
|
||||||
// Because it didnt do anything due to the entry being empty, the file should not be there
|
// Because it didnt do anything due to the entry being empty, the file should not be there
|
||||||
Expect(err).ToNot(BeNil())
|
Expect(err).ToNot(BeNil())
|
||||||
_, err = config.Fs.Stat(filepath.Join("/tmp", cnst.GrubOEMEnv))
|
_, err = config.Fs.Stat(filepath.Join("/tmp", cnst.GrubOEMEnv))
|
||||||
@ -871,7 +871,7 @@ var _ = Describe("Elemental", Label("elemental"), func() {
|
|||||||
|
|
||||||
el := elemental.NewElemental(config)
|
el := elemental.NewElemental(config)
|
||||||
Expect(el.SetDefaultGrubEntry("/mountpoint", "/imgMountPoint", "")).To(BeNil())
|
Expect(el.SetDefaultGrubEntry("/mountpoint", "/imgMountPoint", "")).To(BeNil())
|
||||||
varsParsed, err := utils.ReadPersistentVariables(filepath.Join("/mountpoint", cnst.GrubOEMEnv), config.Fs)
|
varsParsed, err := utils.ReadPersistentVariables(filepath.Join("/mountpoint", cnst.GrubOEMEnv), config)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
Expect(varsParsed["default_menu_entry"]).To(Equal("test"))
|
Expect(varsParsed["default_menu_entry"]).To(Equal("test"))
|
||||||
|
|
||||||
|
@ -503,11 +503,27 @@ func CalcFileChecksum(fs v1.FS, fileName string) (string, error) {
|
|||||||
|
|
||||||
// FindCommand will search for the command(s) in the options given to find the current command
|
// FindCommand will search for the command(s) in the options given to find the current command
|
||||||
// If it cant find it returns the default value give. Useful for the same binaries with different names across OS
|
// If it cant find it returns the default value give. Useful for the same binaries with different names across OS
|
||||||
func FindCommand(defaultPath string, options []string) string {
|
func FindCommand(fs v1.FS, defaultPath string, options []string) string {
|
||||||
for _, p := range options {
|
for _, p := range options {
|
||||||
path, err := exec.LookPath(p)
|
// If its a full path, check if it exists directly
|
||||||
if err == nil {
|
if strings.Contains(p, "/") {
|
||||||
return path
|
d, err := fs.Stat(p)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if d.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
m := d.Mode()
|
||||||
|
// Check if its executable
|
||||||
|
if m&0111 != 0 {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
path, err := exec.LookPath(p)
|
||||||
|
if err == nil {
|
||||||
|
return path
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
"github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
|
"github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
|
||||||
"github.com/kairos-io/kairos-sdk/utils"
|
"github.com/kairos-io/kairos-sdk/utils"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
@ -61,16 +62,38 @@ func (g Grub) Install(target, rootDir, bootDir, grubConf, tty string, efi bool,
|
|||||||
if !efi {
|
if !efi {
|
||||||
g.config.Logger.Info("Installing GRUB..")
|
g.config.Logger.Info("Installing GRUB..")
|
||||||
|
|
||||||
|
// Find where in the rootDir the grub2 files for i386-pc are
|
||||||
|
// Use the modinfo.sh as a marker
|
||||||
|
grubdir = findGrubDir(g.config.Fs, rootDir)
|
||||||
|
if grubdir == "" {
|
||||||
|
g.config.Logger.Logger.Error().Str("path", rootDir).Msg("Failed to find grub dir")
|
||||||
|
return fmt.Errorf("failed to find grub dir under %s", rootDir)
|
||||||
|
}
|
||||||
|
|
||||||
grubargs = append(
|
grubargs = append(
|
||||||
grubargs,
|
grubargs,
|
||||||
fmt.Sprintf("--root-directory=%s", rootDir),
|
fmt.Sprintf("--directory=%s", grubdir),
|
||||||
fmt.Sprintf("--boot-directory=%s", bootDir),
|
fmt.Sprintf("--boot-directory=%s", bootDir),
|
||||||
"--target=i386-pc",
|
"--target=i386-pc",
|
||||||
target,
|
target,
|
||||||
)
|
)
|
||||||
|
|
||||||
g.config.Logger.Debugf("Running grub with the following args: %s", grubargs)
|
g.config.Logger.Debugf("Running grub with the following args: %s", grubargs)
|
||||||
out, err := g.config.Runner.Run(FindCommand("grub2-install", []string{"grub2-install", "grub-install"}), grubargs...)
|
|
||||||
|
grubBin := FindCommand(g.config.Fs, "", []string{
|
||||||
|
filepath.Join(rootDir, "/usr/sbin/", "grub2-install"),
|
||||||
|
filepath.Join(rootDir, "/usr/bin/", "grub2-install"),
|
||||||
|
filepath.Join(rootDir, "/sbin/", "grub2-install"),
|
||||||
|
filepath.Join(rootDir, "/usr/sbin/", "grub-install"),
|
||||||
|
filepath.Join(rootDir, "/usr/bin/", "grub-install"),
|
||||||
|
filepath.Join(rootDir, "/sbin/", "grub-install"),
|
||||||
|
})
|
||||||
|
g.config.Logger.Logger.Debug().Str("command", grubBin).Msg("Found grub binary")
|
||||||
|
if grubBin == "" {
|
||||||
|
g.config.Logger.Logger.Error().Str("path", rootDir).Msg("Grub binary not found in path")
|
||||||
|
return fmt.Errorf("grub binary not found in path")
|
||||||
|
}
|
||||||
|
out, err := g.config.Runner.Run(grubBin, grubargs...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
g.config.Logger.Errorf(string(out))
|
g.config.Logger.Errorf(string(out))
|
||||||
return err
|
return err
|
||||||
@ -257,20 +280,62 @@ func (g Grub) Install(target, rootDir, bootDir, grubConf, tty string, efi bool,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetPersistentVariables sets the given vars into the given grubEnvFile for grub to read them
|
// findGrubDir will find the grub dir under the dir given if possible by searching for the modinfo.sh
|
||||||
func SetPersistentVariables(grubEnvFile string, vars map[string]string, fs v1.FS) error {
|
// And it will return the full dir path where the modinfo.sh is contained
|
||||||
|
func findGrubDir(vfs v1.FS, dir string) string {
|
||||||
|
var foundPath string
|
||||||
|
_ = fsutils.WalkDirFs(vfs, dir, func(path string, d fs.DirEntry, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if d.Name() == "modinfo.sh" && strings.Contains(path, "i386-pc") {
|
||||||
|
// We found the grub dir, return it
|
||||||
|
foundPath = filepath.Dir(path)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return foundPath
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetPersistentVariables(grubEnvFile string, vars map[string]string, c *agentConfig.Config) error {
|
||||||
var b bytes.Buffer
|
var b bytes.Buffer
|
||||||
|
// Write header
|
||||||
b.WriteString("# GRUB Environment Block\n")
|
b.WriteString("# GRUB Environment Block\n")
|
||||||
|
|
||||||
keys := make([]string, 0, len(vars))
|
// First we need to read the existing values from the grubenv file if they exist
|
||||||
for k := range vars {
|
finalVars, err := ReadPersistentVariables(grubEnvFile, c)
|
||||||
|
if err != nil {
|
||||||
|
if !os.IsNotExist(err) {
|
||||||
|
return fmt.Errorf("error reading existing grubenv file %s: %s", grubEnvFile, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check if we have a nil var
|
||||||
|
if len(finalVars) != 0 {
|
||||||
|
c.Logger.Logger.Debug().Interface("existingVars", finalVars).Msg("Existing grubenv variables")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge the existing vars with the new ones
|
||||||
|
// existing vars will be overridden by the new ones from vars if they match
|
||||||
|
for key, newValue := range vars {
|
||||||
|
if oldValue, exists := finalVars[key]; exists {
|
||||||
|
c.Logger.Logger.Warn().Str("key", key).Str("oldValue", oldValue).Str("newValue", newValue).Msg("Overriding existing grubenv variable")
|
||||||
|
}
|
||||||
|
finalVars[key] = newValue
|
||||||
|
}
|
||||||
|
|
||||||
|
keys := make([]string, 0, len(finalVars))
|
||||||
|
|
||||||
|
for k := range finalVars {
|
||||||
keys = append(keys, k)
|
keys = append(keys, k)
|
||||||
}
|
}
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
|
|
||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
if len(vars[k]) > 0 {
|
if len(finalVars[k]) > 0 {
|
||||||
b.WriteString(fmt.Sprintf("%s=%s\n", k, vars[k]))
|
b.WriteString(fmt.Sprintf("%s=%s\n", k, finalVars[k]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,7 +345,7 @@ func SetPersistentVariables(grubEnvFile string, vars map[string]string, fs v1.FS
|
|||||||
for i := 0; i < toBeFilled; i++ {
|
for i := 0; i < toBeFilled; i++ {
|
||||||
b.WriteByte('#')
|
b.WriteByte('#')
|
||||||
}
|
}
|
||||||
return fs.WriteFile(grubEnvFile, b.Bytes(), cnst.FilePerm)
|
return c.Fs.WriteFile(grubEnvFile, b.Bytes(), cnst.FilePerm)
|
||||||
}
|
}
|
||||||
|
|
||||||
// copyGrubFonts will try to finds and copy the needed grub fonts into the system
|
// copyGrubFonts will try to finds and copy the needed grub fonts into the system
|
||||||
@ -397,11 +462,12 @@ func (g Grub) copyGrub() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ReadPersistentVariables will read a grub env file and parse the values
|
// ReadPersistentVariables will read a grub env file and parse the values
|
||||||
func ReadPersistentVariables(grubEnvFile string, fs v1.FS) (map[string]string, error) {
|
func ReadPersistentVariables(grubEnvFile string, c *agentConfig.Config) (map[string]string, error) {
|
||||||
vars := make(map[string]string)
|
vars := make(map[string]string)
|
||||||
f, err := fs.ReadFile(grubEnvFile)
|
|
||||||
|
f, err := c.Fs.ReadFile(grubEnvFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return vars, err
|
||||||
}
|
}
|
||||||
for _, a := range strings.Split(string(f), "\n") {
|
for _, a := range strings.Split(string(f), "\n") {
|
||||||
// comment or fillup, so skip
|
// comment or fillup, so skip
|
||||||
@ -412,7 +478,7 @@ func ReadPersistentVariables(grubEnvFile string, fs v1.FS) (map[string]string, e
|
|||||||
if len(splitted) == 2 {
|
if len(splitted) == 2 {
|
||||||
vars[splitted[0]] = splitted[1]
|
vars[splitted[0]] = splitted[1]
|
||||||
} else {
|
} else {
|
||||||
return nil, fmt.Errorf("invalid format for %s", a)
|
return vars, fmt.Errorf("invalid format for %s", a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return vars, nil
|
return vars, nil
|
||||||
|
@ -691,6 +691,17 @@ var _ = Describe("Utils", Label("utils"), func() {
|
|||||||
|
|
||||||
err = fs.WriteFile(filepath.Join(rootDir, constants.GrubConf), []byte("console=tty1"), 0644)
|
err = fs.WriteFile(filepath.Join(rootDir, constants.GrubConf), []byte("console=tty1"), 0644)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
|
// Create fake grub dir in rootfs and fake grub binaries
|
||||||
|
err = fsutils.MkdirAll(fs, filepath.Join(rootDir, "sbin"), constants.DirPerm)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
f, err := fs.Create(filepath.Join(rootDir, "sbin", "grub2-install"))
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(f.Chmod(0755)).ToNot(HaveOccurred())
|
||||||
|
err = fsutils.MkdirAll(fs, filepath.Join(rootDir, "usr", "lib", "grub", "i386-pc"), constants.DirPerm)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
_, err = fs.Create(filepath.Join(rootDir, "usr", "lib", "grub", "i386-pc", "modinfo.sh"))
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
|
||||||
})
|
})
|
||||||
It("installs with default values", func() {
|
It("installs with default values", func() {
|
||||||
grub := utils.NewGrub(config)
|
grub := utils.NewGrub(config)
|
||||||
@ -741,6 +752,18 @@ var _ = Describe("Utils", Label("utils"), func() {
|
|||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
|
|
||||||
})
|
})
|
||||||
|
It("fails with bios if no grub2-install file exists", func() {
|
||||||
|
Expect(fs.RemoveAll(filepath.Join(rootDir, "sbin", "grub2-install"))).ToNot(HaveOccurred())
|
||||||
|
grub := utils.NewGrub(config)
|
||||||
|
err := grub.Install(target, rootDir, bootDir, constants.GrubConf, "", false, "")
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
It("fails with bios if no modules files exists", func() {
|
||||||
|
Expect(fs.RemoveAll(filepath.Join(rootDir, "usr", "lib", "grub", "i386-pc"))).ToNot(HaveOccurred())
|
||||||
|
grub := utils.NewGrub(config)
|
||||||
|
err := grub.Install(target, rootDir, bootDir, constants.GrubConf, "", false, "")
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
})
|
||||||
It("fails with efi if no modules files exist", Label("efi"), func() {
|
It("fails with efi if no modules files exist", Label("efi"), func() {
|
||||||
grub := utils.NewGrub(config)
|
grub := utils.NewGrub(config)
|
||||||
err := grub.Install(target, rootDir, bootDir, constants.GrubConf, "", true, "")
|
err := grub.Install(target, rootDir, bootDir, constants.GrubConf, "", true, "")
|
||||||
@ -804,9 +827,9 @@ var _ = Describe("Utils", Label("utils"), func() {
|
|||||||
defer os.Remove(temp.Name())
|
defer os.Remove(temp.Name())
|
||||||
Expect(utils.SetPersistentVariables(
|
Expect(utils.SetPersistentVariables(
|
||||||
temp.Name(), map[string]string{"key1": "value1", "key2": "value2"},
|
temp.Name(), map[string]string{"key1": "value1", "key2": "value2"},
|
||||||
config.Fs,
|
config,
|
||||||
)).To(BeNil())
|
)).To(BeNil())
|
||||||
readVars, err := utils.ReadPersistentVariables(temp.Name(), config.Fs)
|
readVars, err := utils.ReadPersistentVariables(temp.Name(), config)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
Expect(readVars["key1"]).To(Equal("value1"))
|
Expect(readVars["key1"]).To(Equal("value1"))
|
||||||
Expect(readVars["key2"]).To(Equal("value2"))
|
Expect(readVars["key2"]).To(Equal("value2"))
|
||||||
@ -814,10 +837,35 @@ var _ = Describe("Utils", Label("utils"), func() {
|
|||||||
It("Fails setting variables", func() {
|
It("Fails setting variables", func() {
|
||||||
e := utils.SetPersistentVariables(
|
e := utils.SetPersistentVariables(
|
||||||
"badfilenopath", map[string]string{"key1": "value1"},
|
"badfilenopath", map[string]string{"key1": "value1"},
|
||||||
config.Fs,
|
config,
|
||||||
)
|
)
|
||||||
Expect(e).NotTo(BeNil())
|
Expect(e).NotTo(BeNil())
|
||||||
})
|
})
|
||||||
|
It("respects existing variables", func() {
|
||||||
|
temp, err := os.CreateTemp("", "grub-*")
|
||||||
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
|
defer os.Remove(temp.Name())
|
||||||
|
Expect(utils.SetPersistentVariables(
|
||||||
|
temp.Name(), map[string]string{"key1": "value1", "key2": "value2"},
|
||||||
|
config,
|
||||||
|
)).To(BeNil())
|
||||||
|
readVars, err := utils.ReadPersistentVariables(temp.Name(), config)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(readVars["key1"]).To(Equal("value1"))
|
||||||
|
Expect(readVars["key2"]).To(Equal("value2"))
|
||||||
|
|
||||||
|
// Now we do it again with a different value
|
||||||
|
Expect(utils.SetPersistentVariables(
|
||||||
|
temp.Name(), map[string]string{"key1": "value3", "key3": "value4"},
|
||||||
|
config,
|
||||||
|
)).To(BeNil())
|
||||||
|
// Now there should be an extra key and key1 should be updated
|
||||||
|
readVars, err = utils.ReadPersistentVariables(temp.Name(), config)
|
||||||
|
Expect(err).To(BeNil())
|
||||||
|
Expect(readVars["key1"]).To(Equal("value3"))
|
||||||
|
Expect(readVars["key2"]).To(Equal("value2"))
|
||||||
|
Expect(readVars["key3"]).To(Equal("value4"))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
Describe("CreateSquashFS", Label("CreateSquashFS"), func() {
|
Describe("CreateSquashFS", Label("CreateSquashFS"), func() {
|
||||||
|
Loading…
Reference in New Issue
Block a user