From 69756e30209dcd60bd90949ea99ae30a2580b774 Mon Sep 17 00:00:00 2001 From: Mauro Morales Date: Fri, 29 Mar 2024 12:49:07 +0100 Subject: [PATCH] Fix bootentry (#277) * Fix bootentry Signed-off-by: Mauro Morales * Use same naming as in GRUB Signed-off-by: Mauro Morales --------- Signed-off-by: Mauro Morales --- pkg/action/bootentries.go | 20 +++---- pkg/action/bootentries_test.go | 97 +++++++++++++++++++++++++++++++++- pkg/constants/constants.go | 19 ++++--- pkg/uki/install.go | 5 +- 4 files changed, 121 insertions(+), 20 deletions(-) diff --git a/pkg/action/bootentries.go b/pkg/action/bootentries.go index 82481074..abc63aef 100644 --- a/pkg/action/bootentries.go +++ b/pkg/action/bootentries.go @@ -83,9 +83,9 @@ func selectBootEntrySystemd(cfg *config.Config, entry string) error { } originalEntries := entries - // when there are only 3 entries, we can assume they are either cos (which will be replaced eventually), fallback or recovery - if len(entries) == 3 { - entries = []string{"cos", "fallback", "recovery", "autoreset"} + // when there are only 4 entries, we can assume they are either cos (which will be replaced eventually), fallback, recovery or autoreset + if len(entries) == len(cnst.UkiDefaultMenuEntries()) { + entries = cnst.UkiDefaultMenuEntries() } // Check that entry exists in the entries list @@ -203,9 +203,9 @@ func systemdConfToBootName(conf string) (string, error) { return bootName, nil } - if strings.HasPrefix(conf, "autoreset") { - bootName := "auto reset" - confName := strings.TrimPrefix(fileName, "autoreset") + if strings.HasPrefix(conf, "statereset") { + bootName := "statereset" + confName := strings.TrimPrefix(fileName, "statereset") if confName != "" { bootName = bootName + " " + strings.Trim(confName, "_") @@ -248,11 +248,11 @@ func bootNameToSystemdConf(name string) (string, error) { return "recovery" + differenciator + ".conf", nil } - if strings.HasPrefix(name, "autoreset") { - if name != "autoreset" { - differenciator = "_" + strings.TrimPrefix(name, "autoreset ") + if strings.HasPrefix(name, "statereset") { + if name != "statereset" { + differenciator = "_" + strings.TrimPrefix(name, "statereset ") } - return "autoreset" + differenciator + ".conf", nil + return "statereset" + differenciator + ".conf", nil } diff --git a/pkg/action/bootentries_test.go b/pkg/action/bootentries_test.go index 66caf798..6cb304da 100644 --- a/pkg/action/bootentries_test.go +++ b/pkg/action/bootentries_test.go @@ -114,13 +114,16 @@ var _ = Describe("Bootentries tests", Label("bootentry"), func() { Expect(err).ToNot(HaveOccurred()) err = fs.WriteFile("/efi/loader/entries/recovery.conf", []byte("title kairos recovery\nefi /EFI/kairos/recovery.efi\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) + err = fs.WriteFile("/efi/loader/entries/statereset.conf", []byte("title kairos state reset (auto)\nefi /EFI/kairos/statereset.efi\n"), os.ModePerm) + Expect(err).ToNot(HaveOccurred()) entries, err := listSystemdEntries(config, &v1.Partition{MountPoint: "/efi"}) Expect(err).ToNot(HaveOccurred()) - Expect(entries).To(HaveLen(3)) + Expect(entries).To(HaveLen(4)) Expect(entries).To(ContainElement("cos")) Expect(entries).To(ContainElement("fallback")) Expect(entries).To(ContainElement("recovery")) + Expect(entries).To(ContainElement("statereset")) }) It("list empty boot entries if there is none", func() { @@ -143,6 +146,8 @@ var _ = Describe("Bootentries tests", Label("bootentry"), func() { Expect(err).ToNot(HaveOccurred()) err = fs.WriteFile("/efi/loader/entries/recovery.conf", []byte("title kairos recovery\nefi /EFI/kairos/recovery.efi\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) + err = fs.WriteFile("/efi/loader/entries/statereset.conf", []byte("title kairos state reset (auto)\nefi /EFI/kairos/statereset.efi\n"), os.ModePerm) + Expect(err).ToNot(HaveOccurred()) err = fs.WriteFile("/efi/loader/loader.conf", []byte(""), os.ModePerm) Expect(err).ToNot(HaveOccurred()) @@ -188,6 +193,27 @@ var _ = Describe("Bootentries tests", Label("bootentry"), func() { syscall.MS_REMOUNT|syscall.MS_RDONLY, "")).To(BeTrue()) + err = SelectBootEntry(config, "statereset") + Expect(err).ToNot(HaveOccurred()) + Expect(memLog.String()).To(ContainSubstring("Default boot entry set to statereset")) + reader, err = utils.SystemdBootConfReader(fs, "/efi/loader/loader.conf") + Expect(err).ToNot(HaveOccurred()) + Expect(reader["default"]).To(Equal("statereset.conf")) + // Should have called a remount to make it RW + Expect(syscallMock.WasMountCalledWith( + "", + "/efi", + "", + syscall.MS_REMOUNT, + "")).To(BeTrue()) + // Should have called a remount to make it RO + Expect(syscallMock.WasMountCalledWith( + "", + "/efi", + "", + syscall.MS_REMOUNT|syscall.MS_RDONLY, + "")).To(BeTrue()) + err = SelectBootEntry(config, "cos") Expect(err).ToNot(HaveOccurred()) Expect(memLog.String()).To(ContainSubstring("Default boot entry set to cos")) @@ -239,6 +265,8 @@ var _ = Describe("Bootentries tests", Label("bootentry"), func() { Expect(err).ToNot(HaveOccurred()) err = fs.WriteFile("/efi/loader/entries/recovery_install-mode_awesomeos.conf", []byte("title awesomeos recovery\nefi /EFI/kairos/recovery_install-mode_awesomeos.efi\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) + err = fs.WriteFile("/efi/loader/entries/statereset_install-mode_awesomeos.conf", []byte("title awesomeos state reset (auto)\nefi /EFI/kairos/statereset_install-mode_awesomeos.efi\n"), os.ModePerm) + Expect(err).ToNot(HaveOccurred()) err = fs.WriteFile("/efi/loader/loader.conf", []byte(""), os.ModePerm) Expect(err).ToNot(HaveOccurred()) @@ -284,6 +312,27 @@ var _ = Describe("Bootentries tests", Label("bootentry"), func() { syscall.MS_REMOUNT|syscall.MS_RDONLY, "")).To(BeTrue()) + err = SelectBootEntry(config, "statereset") + Expect(err).ToNot(HaveOccurred()) + Expect(memLog.String()).To(ContainSubstring("Default boot entry set to statereset")) + reader, err = utils.SystemdBootConfReader(fs, "/efi/loader/loader.conf") + Expect(err).ToNot(HaveOccurred()) + Expect(reader["default"]).To(Equal("statereset_install-mode_awesomeos.conf")) + // Should have called a remount to make it RW + Expect(syscallMock.WasMountCalledWith( + "", + "/efi", + "", + syscall.MS_REMOUNT, + "")).To(BeTrue()) + // Should have called a remount to make it RO + Expect(syscallMock.WasMountCalledWith( + "", + "/efi", + "", + syscall.MS_REMOUNT|syscall.MS_RDONLY, + "")).To(BeTrue()) + err = SelectBootEntry(config, "cos") Expect(err).ToNot(HaveOccurred()) Expect(memLog.String()).To(ContainSubstring("Default boot entry set to cos")) @@ -341,6 +390,10 @@ var _ = Describe("Bootentries tests", Label("bootentry"), func() { Expect(err).ToNot(HaveOccurred()) err = fs.WriteFile("/efi/loader/entries/recovery_foobar.conf", []byte("title Kairos recovery\nefi /EFI/kairos/recovery_foobar.efi\n"), os.ModePerm) Expect(err).ToNot(HaveOccurred()) + err = fs.WriteFile("/efi/loader/entries/statereset.conf", []byte("title Kairos state reset (auto)\nefi /EFI/kairos/statereset.efi\n"), os.ModePerm) + Expect(err).ToNot(HaveOccurred()) + err = fs.WriteFile("/efi/loader/entries/statereset_foobar.conf", []byte("title Kairos state reset (auto)\nefi /EFI/kairos/state_reset_foobar.efi\n"), os.ModePerm) + Expect(err).ToNot(HaveOccurred()) err = fs.WriteFile("/efi/loader/loader.conf", []byte(""), os.ModePerm) Expect(err).ToNot(HaveOccurred()) @@ -428,6 +481,48 @@ var _ = Describe("Bootentries tests", Label("bootentry"), func() { syscall.MS_REMOUNT|syscall.MS_RDONLY, "")).To(BeTrue()) + err = SelectBootEntry(config, "statereset") + Expect(err).ToNot(HaveOccurred()) + Expect(memLog.String()).To(ContainSubstring("Default boot entry set to statereset")) + reader, err = utils.SystemdBootConfReader(fs, "/efi/loader/loader.conf") + Expect(err).ToNot(HaveOccurred()) + Expect(reader["default"]).To(Equal("statereset.conf")) + // Should have called a remount to make it RW + Expect(syscallMock.WasMountCalledWith( + "", + "/efi", + "", + syscall.MS_REMOUNT, + "")).To(BeTrue()) + // Should have called a remount to make it RO + Expect(syscallMock.WasMountCalledWith( + "", + "/efi", + "", + syscall.MS_REMOUNT|syscall.MS_RDONLY, + "")).To(BeTrue()) + + err = SelectBootEntry(config, "statereset foobar") + Expect(err).ToNot(HaveOccurred()) + Expect(memLog.String()).To(ContainSubstring("Default boot entry set to statereset foobar")) + reader, err = utils.SystemdBootConfReader(fs, "/efi/loader/loader.conf") + Expect(err).ToNot(HaveOccurred()) + Expect(reader["default"]).To(Equal("statereset_foobar.conf")) + // Should have called a remount to make it RW + Expect(syscallMock.WasMountCalledWith( + "", + "/efi", + "", + syscall.MS_REMOUNT, + "")).To(BeTrue()) + // Should have called a remount to make it RO + Expect(syscallMock.WasMountCalledWith( + "", + "/efi", + "", + syscall.MS_REMOUNT|syscall.MS_RDONLY, + "")).To(BeTrue()) + err = SelectBootEntry(config, "cos") Expect(err).ToNot(HaveOccurred()) Expect(memLog.String()).To(ContainSubstring("Default boot entry set to cos")) diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index 2b4e3807..abde5709 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -83,7 +83,7 @@ const ( ActiveImgName = "active" PassiveImgName = "passive" RecoveryImgName = "recovery" - AutoResetEntryName = "autoreset" + StateResetImgName = "statereset" GPT = "gpt" UsrLocalPath = "/usr/local" OEMPath = "/oem" @@ -117,10 +117,15 @@ const ( UkiMaxEntries = 3 // Boot labeling - PassiveBootSuffix = " (fallback)" - RecoveryBootSuffix = " recovery" + PassiveBootSuffix = " (fallback)" + RecoveryBootSuffix = " recovery" + StateResetBootSuffix = " state reset (auto)" ) +func UkiDefaultMenuEntries() []string { + return []string{"cos", "fallback", "recovery", "statereset"} +} + func UkiDefaultSkipEntries() []string { return []string{"interactive-install", "install-mode-interactive"} } @@ -173,8 +178,8 @@ func BaseBootTitle(title string) string { return strings.TrimSuffix(title, RecoveryBootSuffix) } else if strings.HasSuffix(title, PassiveBootSuffix) { return strings.TrimSuffix(title, PassiveBootSuffix) - } else if strings.HasSuffix(title, AutoResetEntryName) { - return strings.TrimSuffix(title, AutoResetEntryName) + } else if strings.HasSuffix(title, StateResetBootSuffix) { + return strings.TrimSuffix(title, StateResetBootSuffix) } return title } @@ -187,8 +192,8 @@ func BootTitleForRole(role, title string) (string, error) { return BaseBootTitle(title) + PassiveBootSuffix, nil case RecoveryImgName: return BaseBootTitle(title) + RecoveryBootSuffix, nil - case AutoResetEntryName: - return BaseBootTitle(title) + " " + AutoResetEntryName, nil + case StateResetImgName: + return BaseBootTitle(title) + StateResetBootSuffix, nil default: return "", errors.New("invalid role") } diff --git a/pkg/uki/install.go b/pkg/uki/install.go index 4c96c387..e54d840d 100644 --- a/pkg/uki/install.go +++ b/pkg/uki/install.go @@ -2,11 +2,12 @@ package uki import ( "fmt" - "github.com/kairos-io/kairos-agent/v2/pkg/action" "os" "path/filepath" "strings" + "github.com/kairos-io/kairos-agent/v2/pkg/action" + hook "github.com/kairos-io/kairos-agent/v2/internal/agent/hooks" "github.com/kairos-io/kairos-agent/v2/pkg/config" "github.com/kairos-io/kairos-agent/v2/pkg/constants" @@ -142,7 +143,7 @@ func (i *InstallAction) Run() (err error) { return err } - for _, role := range []string{"active", "passive", "recovery", "autoreset"} { + for _, role := range constants.UkiDefaultMenuEntries() { if err = copyArtifactSetRole(i.cfg.Fs, i.spec.Partitions.EFI.MountPoint, UnassignedArtifactRole, role, i.cfg.Logger); err != nil { i.cfg.Logger.Errorf("installing the new artifact set as %s: %s", role, err.Error()) return fmt.Errorf("installing the new artifact set as %s: %w", role, err)