2023-10-03 09:15:17 +00:00
|
|
|
package uki
|
|
|
|
|
|
|
|
import (
|
2023-12-18 15:09:55 +00:00
|
|
|
"github.com/Masterminds/semver/v3"
|
2023-10-03 09:15:17 +00:00
|
|
|
"github.com/kairos-io/kairos-agent/v2/pkg/config"
|
2023-12-18 10:38:26 +00:00
|
|
|
"github.com/kairos-io/kairos-agent/v2/pkg/constants"
|
|
|
|
"github.com/kairos-io/kairos-agent/v2/pkg/elemental"
|
2023-10-03 09:15:17 +00:00
|
|
|
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
|
|
|
|
elementalUtils "github.com/kairos-io/kairos-agent/v2/pkg/utils"
|
|
|
|
events "github.com/kairos-io/kairos-sdk/bus"
|
2023-12-18 10:38:26 +00:00
|
|
|
"github.com/kairos-io/kairos-sdk/utils"
|
2023-12-18 15:09:55 +00:00
|
|
|
"github.com/sanity-io/litter"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
2023-10-03 09:15:17 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type UpgradeAction struct {
|
|
|
|
cfg *config.Config
|
|
|
|
spec *v1.UpgradeUkiSpec
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewUpgradeAction(cfg *config.Config, spec *v1.UpgradeUkiSpec) *UpgradeAction {
|
|
|
|
return &UpgradeAction{cfg: cfg, spec: spec}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i *UpgradeAction) Run() (err error) {
|
2023-12-18 10:38:26 +00:00
|
|
|
e := elemental.NewElemental(i.cfg)
|
|
|
|
cleanup := utils.NewCleanStack()
|
|
|
|
defer func() { err = cleanup.Cleanup(err) }()
|
2023-10-03 09:15:17 +00:00
|
|
|
// Run pre-install stage
|
|
|
|
_ = elementalUtils.RunStage(i.cfg, "kairos-uki-upgrade.pre")
|
|
|
|
_ = events.RunHookScript("/usr/bin/kairos-agent.uki.upgrade.pre.hook")
|
|
|
|
|
2023-12-18 10:38:26 +00:00
|
|
|
// REMOUNT /efi as RW (its RO by default)
|
|
|
|
umount, err := e.MountRWPartition(i.spec.EfiPartition)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cleanup.Push(umount)
|
|
|
|
// TODO: Check number of existing UKI files
|
2023-12-18 15:09:55 +00:00
|
|
|
efiFiles, err := i.getEfiFiles()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
i.cfg.Logger.Infof("Found %d UKI files", len(efiFiles))
|
|
|
|
if len(efiFiles) > i.cfg.UkiMaxEntries && i.cfg.UkiMaxEntries > 0 {
|
|
|
|
i.cfg.Logger.Infof("Found %d UKI files, which is over max entries allowed(%d) removing the oldest one", len(efiFiles), i.cfg.UkiMaxEntries)
|
|
|
|
versionList := semver.Collection{}
|
|
|
|
for _, f := range efiFiles {
|
|
|
|
versionList = append(versionList, semver.MustParse(f))
|
|
|
|
}
|
|
|
|
// Sort it so the oldest one is first
|
|
|
|
sort.Sort(versionList)
|
|
|
|
i.cfg.Logger.Debugf("All versions found: %s", litter.Sdump(versionList))
|
|
|
|
// Remove the oldest one
|
|
|
|
i.cfg.Logger.Infof("Removing: %s", filepath.Join(i.spec.EfiPartition.MountPoint, "EFI", "kairos", versionList[0].Original()))
|
|
|
|
err = i.cfg.Fs.Remove(filepath.Join(i.spec.EfiPartition.MountPoint, "EFI", "kairos", versionList[0].Original()))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// Remove the conf file as well
|
|
|
|
i.cfg.Logger.Infof("Removing: %s", filepath.Join(i.spec.EfiPartition.MountPoint, "loader", "entries", versionList[0].String()+".conf"))
|
|
|
|
// Don't care about errors here, systemd-boot will ignore any configs if it cant find the efi file mentioned in it
|
|
|
|
e := i.cfg.Fs.Remove(filepath.Join(i.spec.EfiPartition.MountPoint, "loader", "entries", versionList[0].String()+".conf"))
|
|
|
|
if e != nil {
|
|
|
|
i.cfg.Logger.Warnf("Failed to remove conf file: %s", e)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
i.cfg.Logger.Infof("Found %d UKI files, which is under max entries allowed(%d) not removing any", len(efiFiles), i.cfg.UkiMaxEntries)
|
|
|
|
}
|
|
|
|
|
2023-12-18 10:38:26 +00:00
|
|
|
// Dump artifact to efi dir
|
|
|
|
_, err = e.DumpSource(constants.UkiEfiDir, i.spec.Active.Source)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-12-18 15:09:55 +00:00
|
|
|
|
2023-10-03 09:15:17 +00:00
|
|
|
_ = elementalUtils.RunStage(i.cfg, "kairos-uki-upgrade.after")
|
|
|
|
_ = events.RunHookScript("/usr/bin/kairos-agent.uki.upgrade.after.hook") //nolint:errcheck
|
|
|
|
|
2024-02-02 12:20:06 +00:00
|
|
|
return nil
|
2023-10-03 09:15:17 +00:00
|
|
|
}
|
2023-12-18 15:09:55 +00:00
|
|
|
|
|
|
|
func (i *UpgradeAction) getEfiFiles() ([]string, error) {
|
|
|
|
var efiFiles []string
|
|
|
|
files, err := os.ReadDir(filepath.Join(i.spec.EfiPartition.MountPoint, "EFI", "kairos"))
|
|
|
|
if err != nil {
|
|
|
|
return efiFiles, err
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, file := range files {
|
|
|
|
if !file.IsDir() && strings.HasSuffix(file.Name(), ".efi") {
|
|
|
|
efiFiles = append(efiFiles, file.Name())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return efiFiles, nil
|
|
|
|
}
|