mirror of
https://github.com/kairos-io/kairos-agent.git
synced 2025-08-20 01:07:02 +00:00
Add boot assesment for install and bootentry (#604)
This commit is contained in:
parent
8516a19ff9
commit
7be897c1d5
@ -129,10 +129,16 @@ func selectBootEntrySystemd(cfg *config.Config, entry string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bootName, err := bootNameToSystemdConf(entry)
|
bootFileName, err := bootNameToSystemdConf(entry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
assessment, err := utils.ReadAssessmentFromEntry(cfg.Fs, bootFileName, cfg.Logger)
|
||||||
|
if err != nil {
|
||||||
|
cfg.Logger.Logger.Err(err).Str("entry", entry).Str("boot file name", bootFileName).Msg("could not read assessment from entry")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
bootName := fmt.Sprintf("%s%s.conf", bootFileName, assessment)
|
||||||
// Set the default entry to the selected entry
|
// Set the default entry to the selected entry
|
||||||
systemdConf["default"] = bootName
|
systemdConf["default"] = bootName
|
||||||
err = utils.SystemdBootConfWriter(cfg.Fs, filepath.Join(efiPartition.MountPoint, "loader/loader.conf"), systemdConf)
|
err = utils.SystemdBootConfWriter(cfg.Fs, filepath.Join(efiPartition.MountPoint, "loader/loader.conf"), systemdConf)
|
||||||
@ -173,6 +179,10 @@ func systemdConfToBootName(conf string) (string, error) {
|
|||||||
|
|
||||||
fileName := strings.TrimSuffix(conf, ".conf")
|
fileName := strings.TrimSuffix(conf, ".conf")
|
||||||
|
|
||||||
|
// Remove the boot assesment from the name we show
|
||||||
|
re := regexp.MustCompile(`\+\d+(-\d+)?$`)
|
||||||
|
fileName = re.ReplaceAllString(fileName, "")
|
||||||
|
|
||||||
if strings.HasPrefix(fileName, "active") {
|
if strings.HasPrefix(fileName, "active") {
|
||||||
bootName := "cos"
|
bootName := "cos"
|
||||||
confName := strings.TrimPrefix(fileName, "active")
|
confName := strings.TrimPrefix(fileName, "active")
|
||||||
@ -220,6 +230,8 @@ func systemdConfToBootName(conf string) (string, error) {
|
|||||||
return strings.ReplaceAll(fileName, "_", " "), nil
|
return strings.ReplaceAll(fileName, "_", " "), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bootNameToSystemdConf converts a boot name to a systemd-boot conf file name
|
||||||
|
// skips the .conf extension
|
||||||
func bootNameToSystemdConf(name string) (string, error) {
|
func bootNameToSystemdConf(name string) (string, error) {
|
||||||
differenciator := ""
|
differenciator := ""
|
||||||
|
|
||||||
@ -227,38 +239,38 @@ func bootNameToSystemdConf(name string) (string, error) {
|
|||||||
if name != "cos" {
|
if name != "cos" {
|
||||||
differenciator = "_" + strings.TrimPrefix(name, "cos ")
|
differenciator = "_" + strings.TrimPrefix(name, "cos ")
|
||||||
}
|
}
|
||||||
return "active" + differenciator + ".conf", nil
|
return "active" + differenciator, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(name, "active") {
|
if strings.HasPrefix(name, "active") {
|
||||||
if name != "active" {
|
if name != "active" {
|
||||||
differenciator = "_" + strings.TrimPrefix(name, "active ")
|
differenciator = "_" + strings.TrimPrefix(name, "active ")
|
||||||
}
|
}
|
||||||
return "active" + differenciator + ".conf", nil
|
return "active" + differenciator, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(name, "fallback") {
|
if strings.HasPrefix(name, "fallback") {
|
||||||
if name != "fallback" {
|
if name != "fallback" {
|
||||||
differenciator = "_" + strings.TrimPrefix(name, "fallback ")
|
differenciator = "_" + strings.TrimPrefix(name, "fallback ")
|
||||||
}
|
}
|
||||||
return "passive" + differenciator + ".conf", nil
|
return "passive" + differenciator, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(name, "recovery") {
|
if strings.HasPrefix(name, "recovery") {
|
||||||
if name != "recovery" {
|
if name != "recovery" {
|
||||||
differenciator = "_" + strings.TrimPrefix(name, "recovery ")
|
differenciator = "_" + strings.TrimPrefix(name, "recovery ")
|
||||||
}
|
}
|
||||||
return "recovery" + differenciator + ".conf", nil
|
return "recovery" + differenciator, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(name, "statereset") {
|
if strings.HasPrefix(name, "statereset") {
|
||||||
if name != "statereset" {
|
if name != "statereset" {
|
||||||
differenciator = "_" + strings.TrimPrefix(name, "statereset ")
|
differenciator = "_" + strings.TrimPrefix(name, "statereset ")
|
||||||
}
|
}
|
||||||
return "statereset" + differenciator + ".conf", nil
|
return "statereset" + differenciator, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return strings.ReplaceAll(name, " ", "_") + ".conf", nil
|
return strings.ReplaceAll(name, " ", "_"), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// listBootEntriesSystemd lists the boot entries available in the systemd-boot config files
|
// listBootEntriesSystemd lists the boot entries available in the systemd-boot config files
|
||||||
|
@ -138,14 +138,42 @@ var _ = Describe("Bootentries tests", Label("bootentry"), func() {
|
|||||||
Expect(err).To(HaveOccurred())
|
Expect(err).To(HaveOccurred())
|
||||||
Expect(err.Error()).To(ContainSubstring("does not exist"))
|
Expect(err.Error()).To(ContainSubstring("does not exist"))
|
||||||
})
|
})
|
||||||
It("selects the boot entry in a default installation", func() {
|
It("works without boot assessment", func() {
|
||||||
err := fs.WriteFile("/efi/loader/entries/active.conf", []byte("title kairos\nefi /EFI/kairos/active.efi\n"), os.ModePerm)
|
err := fs.WriteFile("/efi/loader/entries/active.conf", []byte("title kairos\nefi /EFI/kairos/active.efi\n"), os.ModePerm)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
err = fs.WriteFile("/efi/loader/entries/passive.conf", []byte("title kairos (fallback)\nefi /EFI/kairos/passive.efi\n"), os.ModePerm)
|
err = fs.WriteFile("/efi/loader/loader.conf", []byte("default active.conf"), os.ModePerm)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
err = fs.WriteFile("/efi/loader/entries/recovery.conf", []byte("title kairos recovery\nefi /EFI/kairos/recovery.efi\n"), os.ModePerm)
|
|
||||||
|
err = SelectBootEntry(config, "active")
|
||||||
Expect(err).ToNot(HaveOccurred())
|
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(memLog.String()).To(ContainSubstring("Default boot entry set to active"))
|
||||||
|
reader, err := utils.SystemdBootConfReader(fs, "/efi/loader/loader.conf")
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(reader["default"]).To(Equal("active.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())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("selects the boot entry in a default installation", func() {
|
||||||
|
err := fs.WriteFile("/efi/loader/entries/active+2-1.conf", []byte("title kairos\nefi /EFI/kairos/active.efi\n"), os.ModePerm)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = fs.WriteFile("/efi/loader/entries/passive+3.conf", []byte("title kairos (fallback)\nefi /EFI/kairos/passive.efi\n"), os.ModePerm)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = fs.WriteFile("/efi/loader/entries/recovery+1-2.conf", []byte("title kairos recovery\nefi /EFI/kairos/recovery.efi\n"), os.ModePerm)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = fs.WriteFile("/efi/loader/entries/statereset+2-1.conf", []byte("title kairos state reset (auto)\nefi /EFI/kairos/statereset.efi\n"), os.ModePerm)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
err = fs.WriteFile("/efi/loader/loader.conf", []byte(""), os.ModePerm)
|
err = fs.WriteFile("/efi/loader/loader.conf", []byte(""), os.ModePerm)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
@ -155,7 +183,7 @@ var _ = Describe("Bootentries tests", Label("bootentry"), func() {
|
|||||||
Expect(memLog.String()).To(ContainSubstring("Default boot entry set to fallback"))
|
Expect(memLog.String()).To(ContainSubstring("Default boot entry set to fallback"))
|
||||||
reader, err := utils.SystemdBootConfReader(fs, "/efi/loader/loader.conf")
|
reader, err := utils.SystemdBootConfReader(fs, "/efi/loader/loader.conf")
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(reader["default"]).To(Equal("passive.conf"))
|
Expect(reader["default"]).To(Equal("passive+3.conf"))
|
||||||
// Should have called a remount to make it RW
|
// Should have called a remount to make it RW
|
||||||
Expect(syscallMock.WasMountCalledWith(
|
Expect(syscallMock.WasMountCalledWith(
|
||||||
"",
|
"",
|
||||||
@ -176,7 +204,7 @@ var _ = Describe("Bootentries tests", Label("bootentry"), func() {
|
|||||||
Expect(memLog.String()).To(ContainSubstring("Default boot entry set to recovery"))
|
Expect(memLog.String()).To(ContainSubstring("Default boot entry set to recovery"))
|
||||||
reader, err = utils.SystemdBootConfReader(fs, "/efi/loader/loader.conf")
|
reader, err = utils.SystemdBootConfReader(fs, "/efi/loader/loader.conf")
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(reader["default"]).To(Equal("recovery.conf"))
|
Expect(reader["default"]).To(Equal("recovery+1-2.conf"))
|
||||||
// Should have called a remount to make it RW
|
// Should have called a remount to make it RW
|
||||||
Expect(syscallMock.WasMountCalledWith(
|
Expect(syscallMock.WasMountCalledWith(
|
||||||
"",
|
"",
|
||||||
@ -197,7 +225,7 @@ var _ = Describe("Bootentries tests", Label("bootentry"), func() {
|
|||||||
Expect(memLog.String()).To(ContainSubstring("Default boot entry set to statereset"))
|
Expect(memLog.String()).To(ContainSubstring("Default boot entry set to statereset"))
|
||||||
reader, err = utils.SystemdBootConfReader(fs, "/efi/loader/loader.conf")
|
reader, err = utils.SystemdBootConfReader(fs, "/efi/loader/loader.conf")
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(reader["default"]).To(Equal("statereset.conf"))
|
Expect(reader["default"]).To(Equal("statereset+2-1.conf"))
|
||||||
// Should have called a remount to make it RW
|
// Should have called a remount to make it RW
|
||||||
Expect(syscallMock.WasMountCalledWith(
|
Expect(syscallMock.WasMountCalledWith(
|
||||||
"",
|
"",
|
||||||
@ -218,7 +246,7 @@ var _ = Describe("Bootentries tests", Label("bootentry"), func() {
|
|||||||
Expect(memLog.String()).To(ContainSubstring("Default boot entry set to cos"))
|
Expect(memLog.String()).To(ContainSubstring("Default boot entry set to cos"))
|
||||||
reader, err = utils.SystemdBootConfReader(fs, "/efi/loader/loader.conf")
|
reader, err = utils.SystemdBootConfReader(fs, "/efi/loader/loader.conf")
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(reader["default"]).To(Equal("active.conf"))
|
Expect(reader["default"]).To(Equal("active+2-1.conf"))
|
||||||
// Should have called a remount to make it RW
|
// Should have called a remount to make it RW
|
||||||
Expect(syscallMock.WasMountCalledWith(
|
Expect(syscallMock.WasMountCalledWith(
|
||||||
"",
|
"",
|
||||||
@ -240,7 +268,7 @@ var _ = Describe("Bootentries tests", Label("bootentry"), func() {
|
|||||||
Expect(memLog.String()).To(ContainSubstring("Default boot entry set to active"))
|
Expect(memLog.String()).To(ContainSubstring("Default boot entry set to active"))
|
||||||
reader, err = utils.SystemdBootConfReader(fs, "/efi/loader/loader.conf")
|
reader, err = utils.SystemdBootConfReader(fs, "/efi/loader/loader.conf")
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(reader["default"]).To(Equal("active.conf"))
|
Expect(reader["default"]).To(Equal("active+2-1.conf"))
|
||||||
// Should have called a remount to make it RW
|
// Should have called a remount to make it RW
|
||||||
Expect(syscallMock.WasMountCalledWith(
|
Expect(syscallMock.WasMountCalledWith(
|
||||||
"",
|
"",
|
||||||
@ -260,7 +288,7 @@ var _ = Describe("Bootentries tests", Label("bootentry"), func() {
|
|||||||
It("selects the boot entry in a extend-cmdline installation with boot branding", func() {
|
It("selects the boot entry in a extend-cmdline installation with boot branding", func() {
|
||||||
err := fs.WriteFile("/efi/loader/entries/active_install-mode_awesomeos.conf", []byte("title awesomeos\nefi /EFI/kairos/active_install-mode_awesomeos.efi\n"), os.ModePerm)
|
err := fs.WriteFile("/efi/loader/entries/active_install-mode_awesomeos.conf", []byte("title awesomeos\nefi /EFI/kairos/active_install-mode_awesomeos.efi\n"), os.ModePerm)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
err = fs.WriteFile("/efi/loader/entries/passive_install-mode_awesomeos.conf", []byte("title awesomeos (fallback)\nefi /EFI/kairos/passive_install-mode_awesomeos.efi\n"), os.ModePerm)
|
err = fs.WriteFile("/efi/loader/entries/passive_install-mode_awesomeos+3.conf", []byte("title awesomeos (fallback)\nefi /EFI/kairos/passive_install-mode_awesomeos.efi\n"), os.ModePerm)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
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)
|
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())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
@ -274,7 +302,7 @@ var _ = Describe("Bootentries tests", Label("bootentry"), func() {
|
|||||||
Expect(memLog.String()).To(ContainSubstring("Default boot entry set to fallback"))
|
Expect(memLog.String()).To(ContainSubstring("Default boot entry set to fallback"))
|
||||||
reader, err := utils.SystemdBootConfReader(fs, "/efi/loader/loader.conf")
|
reader, err := utils.SystemdBootConfReader(fs, "/efi/loader/loader.conf")
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(reader["default"]).To(Equal("passive_install-mode_awesomeos.conf"))
|
Expect(reader["default"]).To(Equal("passive_install-mode_awesomeos+3.conf"))
|
||||||
// Should have called a remount to make it RW
|
// Should have called a remount to make it RW
|
||||||
Expect(syscallMock.WasMountCalledWith(
|
Expect(syscallMock.WasMountCalledWith(
|
||||||
"",
|
"",
|
||||||
@ -381,11 +409,11 @@ var _ = Describe("Bootentries tests", Label("bootentry"), func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
err = fs.WriteFile("/efi/loader/entries/active_foobar.conf", []byte("title Kairos\nefi /EFI/kairos/active_foobar.efi\n"), os.ModePerm)
|
err = fs.WriteFile("/efi/loader/entries/active_foobar.conf", []byte("title Kairos\nefi /EFI/kairos/active_foobar.efi\n"), os.ModePerm)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
err = fs.WriteFile("/efi/loader/entries/passive.conf", []byte("title Kairos (fallback)\nefi /EFI/kairos/passive.efi\n"), os.ModePerm)
|
err = fs.WriteFile("/efi/loader/entries/passive+3.conf", []byte("title Kairos (fallback)\nefi /EFI/kairos/passive.efi\n"), os.ModePerm)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
err = fs.WriteFile("/efi/loader/entries/passive_foobar.conf", []byte("title Kairos (fallback)\nefi /EFI/kairos/passive_foobar.efi\n"), os.ModePerm)
|
err = fs.WriteFile("/efi/loader/entries/passive_foobar.conf", []byte("title Kairos (fallback)\nefi /EFI/kairos/passive_foobar.efi\n"), os.ModePerm)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
err = fs.WriteFile("/efi/loader/entries/recovery.conf", []byte("title Kairos recovery\nefi /EFI/kairos/recovery.efi\n"), os.ModePerm)
|
err = fs.WriteFile("/efi/loader/entries/recovery+3.conf", []byte("title Kairos recovery\nefi /EFI/kairos/recovery.efi\n"), os.ModePerm)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
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)
|
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())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
@ -393,7 +421,7 @@ var _ = Describe("Bootentries tests", Label("bootentry"), func() {
|
|||||||
Expect(err).ToNot(HaveOccurred())
|
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)
|
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())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
err = fs.WriteFile("/efi/loader/loader.conf", []byte(""), os.ModePerm)
|
err = fs.WriteFile("/efi/loader/loader.conf", []byte("default active.conf"), os.ModePerm)
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
err = SelectBootEntry(config, "fallback")
|
err = SelectBootEntry(config, "fallback")
|
||||||
@ -401,7 +429,7 @@ var _ = Describe("Bootentries tests", Label("bootentry"), func() {
|
|||||||
Expect(memLog.String()).To(ContainSubstring("Default boot entry set to fallback"))
|
Expect(memLog.String()).To(ContainSubstring("Default boot entry set to fallback"))
|
||||||
reader, err := utils.SystemdBootConfReader(fs, "/efi/loader/loader.conf")
|
reader, err := utils.SystemdBootConfReader(fs, "/efi/loader/loader.conf")
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(reader["default"]).To(Equal("passive.conf"))
|
Expect(reader["default"]).To(Equal("passive+3.conf"))
|
||||||
// Should have called a remount to make it RW
|
// Should have called a remount to make it RW
|
||||||
Expect(syscallMock.WasMountCalledWith(
|
Expect(syscallMock.WasMountCalledWith(
|
||||||
"",
|
"",
|
||||||
@ -443,7 +471,7 @@ var _ = Describe("Bootentries tests", Label("bootentry"), func() {
|
|||||||
Expect(memLog.String()).To(ContainSubstring("Default boot entry set to recovery"))
|
Expect(memLog.String()).To(ContainSubstring("Default boot entry set to recovery"))
|
||||||
reader, err = utils.SystemdBootConfReader(fs, "/efi/loader/loader.conf")
|
reader, err = utils.SystemdBootConfReader(fs, "/efi/loader/loader.conf")
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
Expect(reader["default"]).To(Equal("recovery.conf"))
|
Expect(reader["default"]).To(Equal("recovery+3.conf"))
|
||||||
// Should have called a remount to make it RW
|
// Should have called a remount to make it RW
|
||||||
Expect(syscallMock.WasMountCalledWith(
|
Expect(syscallMock.WasMountCalledWith(
|
||||||
"",
|
"",
|
||||||
|
@ -126,7 +126,9 @@ const (
|
|||||||
StateResetBootSuffix = " state reset (auto)"
|
StateResetBootSuffix = " state reset (auto)"
|
||||||
|
|
||||||
// Error
|
// Error
|
||||||
UpgradeNoSourceError = "Could not find a proper source for the upgrade.\nThis can be configured in the cloud config files under the 'upgrade.system.uri' key or via cmdline using the '--source' flag."
|
UpgradeNoSourceError = "Could not find a proper source for the upgrade.\nThis can be configured in the cloud config files under the 'upgrade.system.uri' key or via cmdline using the '--source' flag."
|
||||||
|
MultipleEntriesAssessmentError = "multiple boot entries found for %s"
|
||||||
|
NoBootAssessmentWarning = "No boot assessment found in current boot entry config file"
|
||||||
)
|
)
|
||||||
|
|
||||||
func UkiDefaultMenuEntries() []string {
|
func UkiDefaultMenuEntries() []string {
|
||||||
|
@ -181,6 +181,12 @@ func (i *InstallAction) Run() (err error) {
|
|||||||
return fmt.Errorf("removing artifact set with role %s: %w", UnassignedArtifactRole, err)
|
return fmt.Errorf("removing artifact set with role %s: %w", UnassignedArtifactRole, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add boot assessment to files by appending +3 to the name
|
||||||
|
err = utils.AddBootAssessment(i.cfg.Fs, i.spec.Partitions.EFI.MountPoint, i.cfg.Logger)
|
||||||
|
if err != nil {
|
||||||
|
i.cfg.Logger.Warnf("adding boot assesment: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
// SelectBootEntry sets the default boot entry to the selected entry
|
// SelectBootEntry sets the default boot entry to the selected entry
|
||||||
err = action.SelectBootEntry(i.cfg, "cos")
|
err = action.SelectBootEntry(i.cfg, "cos")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -80,6 +80,13 @@ func (r *ResetAction) Run() (err error) {
|
|||||||
r.cfg.Logger.Errorf("copying recovery to active: %s", err.Error())
|
r.cfg.Logger.Errorf("copying recovery to active: %s", err.Error())
|
||||||
return fmt.Errorf("copying recovery to active: %w", err)
|
return fmt.Errorf("copying recovery to active: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add boot assessment to files by appending +3 to the name
|
||||||
|
err = elementalUtils.AddBootAssessment(r.cfg.Fs, r.spec.Partitions.EFI.MountPoint, r.cfg.Logger)
|
||||||
|
if err != nil {
|
||||||
|
r.cfg.Logger.Warnf("adding boot assesment: %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
// SelectBootEntry sets the default boot entry to the selected entry
|
// SelectBootEntry sets the default boot entry to the selected entry
|
||||||
err = action.SelectBootEntry(r.cfg, "cos")
|
err = action.SelectBootEntry(r.cfg, "cos")
|
||||||
// Should we fail? Or warn?
|
// Should we fail? Or warn?
|
||||||
|
@ -109,7 +109,11 @@ func (i *UpgradeAction) Run() (err error) {
|
|||||||
i.cfg.Logger.Errorf("removing artifact set: %s", err.Error())
|
i.cfg.Logger.Errorf("removing artifact set: %s", err.Error())
|
||||||
return fmt.Errorf("removing artifact set: %w", err)
|
return fmt.Errorf("removing artifact set: %w", err)
|
||||||
}
|
}
|
||||||
|
// Add boot assessment to files by appending +3 to the name
|
||||||
|
err = elementalUtils.AddBootAssessment(i.cfg.Fs, i.spec.EfiPartition.MountPoint, i.cfg.Logger)
|
||||||
|
if err != nil {
|
||||||
|
i.cfg.Logger.Warnf("adding boot assesment: %s", err.Error())
|
||||||
|
}
|
||||||
// SelectBootEntry sets the default boot entry to the selected entry
|
// SelectBootEntry sets the default boot entry to the selected entry
|
||||||
err = action.SelectBootEntry(i.cfg, "cos")
|
err = action.SelectBootEntry(i.cfg, "cos")
|
||||||
// Should we fail? Or warn?
|
// Should we fail? Or warn?
|
||||||
|
@ -28,6 +28,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -614,3 +615,72 @@ func CheckFailedInstallation(stateFile string) (bool, error) {
|
|||||||
}
|
}
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddBootAssessment adds boot assessment to files by appending +3 to the name
|
||||||
|
// Only for files that dont have it already as those are the ones upgraded
|
||||||
|
// Existing files that have a boot assessment will be left as is
|
||||||
|
// This should be called during install, upgrade and reset
|
||||||
|
// Mainly everything that updates the config files to point to a new artifact we need to reset the boot assessment
|
||||||
|
// as its a new artifact that needs to be assessed
|
||||||
|
func AddBootAssessment(fs v1.FS, artifactDir string, logger sdkTypes.KairosLogger) error {
|
||||||
|
return fsutils.WalkDirFs(fs, artifactDir, func(path string, info os.DirEntry, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Only do files that are conf files but dont match the loader.conf
|
||||||
|
if !info.IsDir() && filepath.Ext(path) == ".conf" && !strings.Contains(info.Name(), "loader.conf") {
|
||||||
|
dir := filepath.Dir(path)
|
||||||
|
ext := filepath.Ext(path)
|
||||||
|
base := strings.TrimSuffix(filepath.Base(path), ext)
|
||||||
|
// Lets check if the file has a boot assessment already. If it does, we dont need to do anything
|
||||||
|
// If it matches continue
|
||||||
|
re := regexp.MustCompile(`\+\d+(-\d+)?$`)
|
||||||
|
if re.MatchString(base) {
|
||||||
|
logger.Logger.Debug().Str("file", path).Msg("Boot assessment already present in file")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
newBase := fmt.Sprintf("%s+3%s", base, ext)
|
||||||
|
newPath := filepath.Join(dir, newBase)
|
||||||
|
logger.Logger.Debug().Str("from", path).Str("to", newPath).Msg("Enabling boot assessment")
|
||||||
|
err = fs.Rename(path, newPath)
|
||||||
|
if err != nil {
|
||||||
|
logger.Logger.Err(err).Str("from", path).Str("to", newPath).Msg("Error renaming file")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadAssessmentFromEntry(fs v1.FS, entry string, logger sdkTypes.KairosLogger) (string, error) {
|
||||||
|
// Read current config for boot assessment from current config. We should already have the final config name
|
||||||
|
// Fix fallback and cos pointing to passive and active
|
||||||
|
if strings.HasPrefix(entry, "fallback") {
|
||||||
|
entry = strings.Replace(entry, "fallback", "passive", 1)
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(entry, "cos") {
|
||||||
|
entry = strings.Replace(entry, "cos", "active", 1)
|
||||||
|
}
|
||||||
|
efiPart, err := partitions.GetEfiPartition(&logger)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
// We only want the ones that match the assessment
|
||||||
|
currentfile, err := fsutils.GlobFs(fs, filepath.Join(efiPart.MountPoint, "loader/entries", entry+"+*.conf"))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if len(currentfile) == 0 {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
if len(currentfile) > 1 {
|
||||||
|
return "", fmt.Errorf(cnst.MultipleEntriesAssessmentError, entry)
|
||||||
|
}
|
||||||
|
re := regexp.MustCompile(`(\+\d+(-\d+)?)\.conf$`)
|
||||||
|
if !re.MatchString(currentfile[0]) {
|
||||||
|
logger.Logger.Debug().Str("file", currentfile[0]).Msg(cnst.NoBootAssessmentWarning)
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
return re.FindStringSubmatch(currentfile[0])[1], nil
|
||||||
|
}
|
||||||
|
@ -273,3 +273,38 @@ func Copy(fs v1.FS, src, dst string) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GlobFs returns the names of all files matching pattern or nil if there is no matching file.
|
||||||
|
// Only consider the names of files in the directory included in the pattern, not in subdirectories.
|
||||||
|
// So the pattern "dir/*" will return only the files in the directory "dir", not in "dir/subdir".
|
||||||
|
func GlobFs(fs v1.FS, pattern string) ([]string, error) {
|
||||||
|
var matches []string
|
||||||
|
|
||||||
|
// Check if the pattern is well formed.
|
||||||
|
if _, err := filepath.Match(pattern, ""); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split the pattern into directory and file parts.
|
||||||
|
dir, file := filepath.Split(pattern)
|
||||||
|
if dir == "" {
|
||||||
|
dir = "."
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the directory.
|
||||||
|
entries, err := fs.ReadDir(dir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match the entries against the pattern.
|
||||||
|
for _, entry := range entries {
|
||||||
|
if matched, err := filepath.Match(file, entry.Name()); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if matched {
|
||||||
|
matches = append(matches, filepath.Join(dir, entry.Name()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matches, nil
|
||||||
|
}
|
||||||
|
@ -32,6 +32,7 @@ import (
|
|||||||
"github.com/kairos-io/kairos-agent/v2/pkg/utils"
|
"github.com/kairos-io/kairos-agent/v2/pkg/utils"
|
||||||
"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-agent/v2/pkg/utils/partitions"
|
"github.com/kairos-io/kairos-agent/v2/pkg/utils/partitions"
|
||||||
|
"github.com/kairos-io/kairos-agent/v2/tests/matchers"
|
||||||
v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks"
|
v1mock "github.com/kairos-io/kairos-agent/v2/tests/mocks"
|
||||||
ghwMock "github.com/kairos-io/kairos-sdk/ghw/mocks"
|
ghwMock "github.com/kairos-io/kairos-sdk/ghw/mocks"
|
||||||
sdkTypes "github.com/kairos-io/kairos-sdk/types"
|
sdkTypes "github.com/kairos-io/kairos-sdk/types"
|
||||||
@ -1062,4 +1063,206 @@ var _ = Describe("Utils", Label("utils"), func() {
|
|||||||
Expect(utils.IsUkiWithFs(fs)).To(BeFalse())
|
Expect(utils.IsUkiWithFs(fs)).To(BeFalse())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
Describe("AddBootAssessment", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
Expect(fsutils.MkdirAll(fs, "/efi/loader/entries", os.ModePerm)).ToNot(HaveOccurred())
|
||||||
|
})
|
||||||
|
It("adds the boot assessment to a file", func() {
|
||||||
|
err := fs.WriteFile("/efi/loader/entries/test.conf", []byte(""), os.ModePerm)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = utils.AddBootAssessment(fs, "/efi/loader/entries", logger)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect("/efi/loader/entries/test.conf").ToNot(matchers.BeAnExistingFileFs(fs))
|
||||||
|
// Should match with the +3
|
||||||
|
Expect("/efi/loader/entries/test+3.conf").To(matchers.BeAnExistingFileFs(fs))
|
||||||
|
})
|
||||||
|
It("adds the boot assessment to several files", func() {
|
||||||
|
err := fs.WriteFile("/efi/loader/entries/test1.conf", []byte(""), os.ModePerm)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = fs.WriteFile("/efi/loader/entries/test2.conf", []byte(""), os.ModePerm)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = fs.WriteFile("/efi/loader/entries/test3.conf", []byte(""), os.ModePerm)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = utils.AddBootAssessment(fs, "/efi/loader/entries", logger)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect("/efi/loader/entries/test1.conf").ToNot(matchers.BeAnExistingFileFs(fs))
|
||||||
|
Expect("/efi/loader/entries/test2.conf").ToNot(matchers.BeAnExistingFileFs(fs))
|
||||||
|
Expect("/efi/loader/entries/test3.conf").ToNot(matchers.BeAnExistingFileFs(fs))
|
||||||
|
// Should match with the +3
|
||||||
|
Expect("/efi/loader/entries/test1+3.conf").To(matchers.BeAnExistingFileFs(fs))
|
||||||
|
Expect("/efi/loader/entries/test2+3.conf").To(matchers.BeAnExistingFileFs(fs))
|
||||||
|
Expect("/efi/loader/entries/test3+3.conf").To(matchers.BeAnExistingFileFs(fs))
|
||||||
|
})
|
||||||
|
It("leaves assessment in place for existing files", func() {
|
||||||
|
err := fs.WriteFile("/efi/loader/entries/test1.conf", []byte(""), os.ModePerm)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = fs.WriteFile("/efi/loader/entries/test2+3.conf", []byte(""), os.ModePerm)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = fs.WriteFile("/efi/loader/entries/test3+1-2.conf", []byte(""), os.ModePerm)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = utils.AddBootAssessment(fs, "/efi/loader/entries", logger)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect("/efi/loader/entries/test1.conf").ToNot(matchers.BeAnExistingFileFs(fs))
|
||||||
|
Expect("/efi/loader/entries/test3+3.conf").ToNot(matchers.BeAnExistingFileFs(fs))
|
||||||
|
// Should match with the +3 and the existing ones left in place
|
||||||
|
Expect("/efi/loader/entries/test1+3.conf").To(matchers.BeAnExistingFileFs(fs))
|
||||||
|
Expect("/efi/loader/entries/test2+3.conf").To(matchers.BeAnExistingFileFs(fs))
|
||||||
|
Expect("/efi/loader/entries/test3+1-2.conf").To(matchers.BeAnExistingFileFs(fs))
|
||||||
|
})
|
||||||
|
It("fails to write the boot assessment in non existing dir", func() {
|
||||||
|
err := utils.AddBootAssessment(fs, "/fake", logger)
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
Describe("ReadAssessmentFromEntry", func() {
|
||||||
|
var ghwTest ghwMock.GhwMock
|
||||||
|
BeforeEach(func() {
|
||||||
|
Expect(fsutils.MkdirAll(fs, "/efi/loader/entries", os.ModePerm)).ToNot(HaveOccurred())
|
||||||
|
mainDisk := sdkTypes.Disk{
|
||||||
|
Name: "device",
|
||||||
|
Partitions: []*sdkTypes.Partition{
|
||||||
|
{
|
||||||
|
Name: "device1",
|
||||||
|
FilesystemLabel: "COS_GRUB",
|
||||||
|
FS: "ext4",
|
||||||
|
MountPoint: "/efi",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
ghwTest = ghwMock.GhwMock{}
|
||||||
|
ghwTest.AddDisk(mainDisk)
|
||||||
|
ghwTest.CreateDevices()
|
||||||
|
})
|
||||||
|
AfterEach(func() {
|
||||||
|
ghwTest.Clean()
|
||||||
|
})
|
||||||
|
It("reads the assessment from a file", func() {
|
||||||
|
err := fs.WriteFile("/efi/loader/entries/test+2-1.conf", []byte(""), os.ModePerm)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
entry, err := utils.ReadAssessmentFromEntry(fs, "test", logger)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(entry).To(Equal("+2-1"))
|
||||||
|
})
|
||||||
|
It("reads passive when using fallback", func() {
|
||||||
|
err := fs.WriteFile("/efi/loader/entries/passive+2-1.conf", []byte(""), os.ModePerm)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
// fallback should point to passive
|
||||||
|
entry, err := utils.ReadAssessmentFromEntry(fs, "fallback", logger)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(entry).To(Equal("+2-1"))
|
||||||
|
|
||||||
|
// Should find the passive entry as well directly
|
||||||
|
entry, err = utils.ReadAssessmentFromEntry(fs, "passive", logger)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(entry).To(Equal("+2-1"))
|
||||||
|
})
|
||||||
|
It("reads active when using cos", func() {
|
||||||
|
err := fs.WriteFile("/efi/loader/entries/active+1-2.conf", []byte(""), os.ModePerm)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
// cos should point to active
|
||||||
|
entry, err := utils.ReadAssessmentFromEntry(fs, "cos", logger)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(entry).To(Equal("+1-2"))
|
||||||
|
|
||||||
|
// Should find the active entry as well directly
|
||||||
|
entry, err = utils.ReadAssessmentFromEntry(fs, "active", logger)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(entry).To(Equal("+1-2"))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("empty assessment if it doesnt match", func() {
|
||||||
|
entry, err := utils.ReadAssessmentFromEntry(fs, "cos", logger)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(entry).To(Equal(""))
|
||||||
|
|
||||||
|
// Should find the active entry as well directly
|
||||||
|
entry, err = utils.ReadAssessmentFromEntry(fs, "active", logger)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(entry).To(Equal(""))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("fails with no EFI partition", func() {
|
||||||
|
ghwTest.Clean()
|
||||||
|
entry, err := utils.ReadAssessmentFromEntry(fs, "cos", logger)
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(entry).To(Equal(""))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("errors if more than one file matches", func() {
|
||||||
|
err := fs.WriteFile("/efi/loader/entries/active+1-2.conf", []byte(""), os.ModePerm)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = fs.WriteFile("/efi/loader/entries/active+3-2.conf", []byte(""), os.ModePerm)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
entry, err := utils.ReadAssessmentFromEntry(fs, "active", logger)
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(entry).To(Equal(""))
|
||||||
|
Expect(err.Error()).To(Equal(fmt.Sprintf(constants.MultipleEntriesAssessmentError, "active")))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("errors if dir doesn't exist", func() {
|
||||||
|
// Remove all dirs
|
||||||
|
cleanup()
|
||||||
|
entry, err := utils.ReadAssessmentFromEntry(fs, "active", logger)
|
||||||
|
Expect(err).To(HaveOccurred())
|
||||||
|
Expect(entry).To(Equal(""))
|
||||||
|
// Check that error is os.ErrNotExist
|
||||||
|
Expect(errors.Is(err, os.ErrNotExist)).To(BeTrue())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("matches with weird but valid format", func() {
|
||||||
|
// This are valid values, after all the asessment is just a string at the end that starts with + and has
|
||||||
|
// and number and an optional dash after that. It has to be before the .conf so this are valid values
|
||||||
|
// even if they are weird or stupid.
|
||||||
|
// potentially the name can be this if someone is rebuilding efi files and adding the + to indicate the build number
|
||||||
|
// for example.
|
||||||
|
// We dont use this but still want to check if these are valid.
|
||||||
|
err := fs.WriteFile("/efi/loader/entries/test1++++++5.conf", []byte(""), os.ModePerm)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = fs.WriteFile("/efi/loader/entries/test2+3+3-1.conf", []byte(""), os.ModePerm)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
entry, err := utils.ReadAssessmentFromEntry(fs, "test1", logger)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(entry).To(Equal("+5"))
|
||||||
|
entry, err = utils.ReadAssessmentFromEntry(fs, "test2", logger)
|
||||||
|
// It actually does not error but just doesn't match
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(entry).To(Equal("+3-1"))
|
||||||
|
})
|
||||||
|
It("doesn't match assessment if format is wrong", func() {
|
||||||
|
err := fs.WriteFile("/efi/loader/entries/test1+1djnfsdjknfsdajf2.conf", []byte(""), os.ModePerm)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = fs.WriteFile("/efi/loader/entries/test2+1-sadfsbauhdfkj.conf", []byte(""), os.ModePerm)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = fs.WriteFile("/efi/loader/entries/test3+asdasd.conf", []byte(""), os.ModePerm)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = fs.WriteFile("/efi/loader/entries/test4+-2.conf", []byte(""), os.ModePerm)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
err = fs.WriteFile("/efi/loader/entries/test5+3&4.conf", []byte(""), os.ModePerm)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
||||||
|
entry, err := utils.ReadAssessmentFromEntry(fs, "test1", logger)
|
||||||
|
// It actually does not error but just doesn't match
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(entry).To(Equal(""))
|
||||||
|
entry, err = utils.ReadAssessmentFromEntry(fs, "test2", logger)
|
||||||
|
// It actually does not error but just doesn't match
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(entry).To(Equal(""))
|
||||||
|
entry, err = utils.ReadAssessmentFromEntry(fs, "test3", logger)
|
||||||
|
// It actually does not error but just doesn't match
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(entry).To(Equal(""))
|
||||||
|
entry, err = utils.ReadAssessmentFromEntry(fs, "test4", logger)
|
||||||
|
// It actually does not error but just doesn't match
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(entry).To(Equal(""))
|
||||||
|
entry, err = utils.ReadAssessmentFromEntry(fs, "test5", logger)
|
||||||
|
// It actually does not error but just doesn't match
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(entry).To(Equal(""))
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
44
tests/matchers/fs.go
Normal file
44
tests/matchers/fs.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
package matchers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/onsi/gomega/format"
|
||||||
|
"github.com/onsi/gomega/types"
|
||||||
|
"github.com/twpayne/go-vfs/v5"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BeAnExistingFileFs returns a matcher that checks if a file exists in the given vfs.
|
||||||
|
func BeAnExistingFileFs(fs vfs.FS) types.GomegaMatcher {
|
||||||
|
return &beAnExistingFileFsMatcher{
|
||||||
|
fs: fs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type beAnExistingFileFsMatcher struct {
|
||||||
|
fs vfs.FS
|
||||||
|
}
|
||||||
|
|
||||||
|
func (matcher *beAnExistingFileFsMatcher) Match(actual interface{}) (success bool, err error) {
|
||||||
|
actualFilename, ok := actual.(string)
|
||||||
|
if !ok {
|
||||||
|
return false, fmt.Errorf("BeAnExistingFileFs matcher expects a file path")
|
||||||
|
}
|
||||||
|
// Here is the magic, check existence against a vfs
|
||||||
|
if _, err = matcher.fs.Stat(actualFilename); err != nil {
|
||||||
|
if os.IsNotExist(err) {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (matcher *beAnExistingFileFsMatcher) FailureMessage(actual interface{}) (message string) {
|
||||||
|
return format.Message(actual, "to exist")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (matcher *beAnExistingFileFsMatcher) NegatedFailureMessage(actual interface{}) (message string) {
|
||||||
|
return format.Message(actual, "not to exist")
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user