From 88454bdda45f2b27da95c2c696fbb1b30ce02624 Mon Sep 17 00:00:00 2001 From: Dimitris Karakasilis Date: Tue, 20 Feb 2024 13:16:06 +0200 Subject: [PATCH] Implement uki "kairos-agent upgrade --recovery" Signed-off-by: Dimitris Karakasilis --- internal/agent/upgrade.go | 8 ++++---- pkg/config/spec.go | 4 ++-- pkg/types/v1/config.go | 9 +++++---- pkg/uki/upgrade.go | 42 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 53 insertions(+), 10 deletions(-) diff --git a/internal/agent/upgrade.go b/internal/agent/upgrade.go index b299936..774692e 100644 --- a/internal/agent/upgrade.go +++ b/internal/agent/upgrade.go @@ -69,7 +69,7 @@ func Upgrade( bus.Manager.Initialize() if internalutils.UkiBootMode() == internalutils.UkiHDD { - return upgradeUki(source, dirs, strictValidations) + return upgradeUki(source, dirs, strictValidations, upgradeRecovery) } else { return upgrade(source, force, strictValidations, dirs, preReleases, upgradeRecovery) } @@ -201,8 +201,8 @@ func getReleasesFromProvider(includePrereleases bool) ([]string, error) { return result, nil } -func upgradeUki(source string, dirs []string, strictValidations bool) error { - cliConf, err := generateUpgradeConfForCLIArgs(source, false) +func upgradeUki(source string, dirs []string, strictValidations, upgradeRecovery bool) error { + cliConf, err := generateUpgradeConfForCLIArgs(source, upgradeRecovery) if err != nil { return err } @@ -217,7 +217,7 @@ func upgradeUki(source string, dirs []string, strictValidations bool) error { utils.SetEnv(c.Env) // Load the upgrade Config from the system - upgradeSpec, err := config.ReadUkiUpgradeFromConfig(c) + upgradeSpec, err := config.ReadUkiUpgradeSpecFromConfig(c) if err != nil { return err } diff --git a/pkg/config/spec.go b/pkg/config/spec.go index 4044c0a..8526583 100644 --- a/pkg/config/spec.go +++ b/pkg/config/spec.go @@ -706,8 +706,8 @@ func NewUkiUpgradeSpec(cfg *Config) (*v1.UpgradeUkiSpec, error) { return spec, err } -// ReadUkiUpgradeFromConfig will return a proper v1.UpgradeUkiSpec based on an agent Config -func ReadUkiUpgradeFromConfig(c *Config) (*v1.UpgradeUkiSpec, error) { +// ReadUkiUpgradeSpecFromConfig will return a proper v1.UpgradeUkiSpec based on an agent Config +func ReadUkiUpgradeSpecFromConfig(c *Config) (*v1.UpgradeUkiSpec, error) { sp, err := ReadSpecFromCloudConfig(c, "upgrade-uki") if err != nil { return &v1.UpgradeUkiSpec{}, err diff --git a/pkg/types/v1/config.go b/pkg/types/v1/config.go index 7e29666..9553a78 100644 --- a/pkg/types/v1/config.go +++ b/pkg/types/v1/config.go @@ -527,10 +527,11 @@ func (i *InstallUkiSpec) GetPartitions() ElementalPartitions { return i.Partitio func (i *InstallUkiSpec) GetExtraPartitions() PartitionList { return i.ExtraPartitions } type UpgradeUkiSpec struct { - Active Image `yaml:"system,omitempty" mapstructure:"system"` - Reboot bool `yaml:"reboot,omitempty" mapstructure:"reboot"` - PowerOff bool `yaml:"poweroff,omitempty" mapstructure:"poweroff"` - EfiPartition *Partition `yaml:"efi-partition,omitempty" mapstructure:"efi-partition"` + RecoveryUpgrade bool `yaml:"recovery,omitempty" mapstructure:"recovery"` + Active Image `yaml:"system,omitempty" mapstructure:"system"` + Reboot bool `yaml:"reboot,omitempty" mapstructure:"reboot"` + PowerOff bool `yaml:"poweroff,omitempty" mapstructure:"poweroff"` + EfiPartition *Partition `yaml:"efi-partition,omitempty" mapstructure:"efi-partition"` } func (i *UpgradeUkiSpec) Sanitize() error { diff --git a/pkg/uki/upgrade.go b/pkg/uki/upgrade.go index 4e2a243..79e7745 100644 --- a/pkg/uki/upgrade.go +++ b/pkg/uki/upgrade.go @@ -2,6 +2,7 @@ package uki import ( "fmt" + "os" "path/filepath" "github.com/kairos-io/kairos-agent/v2/pkg/config" @@ -42,6 +43,13 @@ func (i *UpgradeAction) Run() (err error) { // If we decide to first copy and then rotate, we need ~4 times the size of // the artifact set [TBD] + // When upgrading recovery, we don't want to replace loader.conf or any other + // files, thus we take a simpler approach and only install the new efi file + // and the relevant conf + if i.spec.RecoveryUpgrade { + return i.installRecovery(i.cfg.Logger) + } + // Dump artifact to efi dir _, err = e.DumpSource(constants.UkiEfiDir, i.spec.Active.Source) if err != nil { @@ -74,3 +82,37 @@ func (i *UpgradeAction) Run() (err error) { return nil } + +// installRecovery replaces the "recovery" role efi and conf files with +// the UnassignedArtifactRole efi and loader files from dir +func (i *UpgradeAction) installRecovery(logger v1.Logger) error { + tmpDir, err := os.MkdirTemp("", "") + if err != nil { + return fmt.Errorf("creating a tmp dir: %w", err) + } + defer os.RemoveAll(tmpDir) + + // Dump artifact to tmp dir + e := elemental.NewElemental(i.cfg) + _, err = e.DumpSource(tmpDir, i.spec.Active.Source) + if err != nil { + return err + } + + err = copyFile( + filepath.Join(tmpDir, "EFI", "kairos", UnassignedArtifactRole+".efi"), + filepath.Join(constants.UkiEfiDir, "EFI", "kairos", "recovery.efi")) + if err != nil { + return err + } + + targetConfPath := filepath.Join(constants.UkiEfiDir, "loader", "entries", "recovery.conf") + err = copyFile( + filepath.Join(tmpDir, "loader", "entries", UnassignedArtifactRole+".conf"), + targetConfPath) + if err != nil { + return err + } + + return replaceRoleInKey(targetConfPath, "efi", UnassignedArtifactRole, "recovery", logger) +}