mirror of
https://github.com/kairos-io/kairos-agent.git
synced 2025-06-23 22:57:08 +00:00
Merge pull request #446 from kairos-io/2385-upgrade-single-entries
2385 upgrade single entries
This commit is contained in:
commit
390bc6a7b4
@ -65,18 +65,18 @@ func ListNewerReleases(includePrereleases bool) ([]string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Upgrade(
|
func Upgrade(
|
||||||
source string, force, strictValidations bool, dirs []string, preReleases, upgradeRecovery bool) error {
|
source string, force, strictValidations bool, dirs []string, upgradeEntry string, preReleases bool) error {
|
||||||
bus.Manager.Initialize()
|
bus.Manager.Initialize()
|
||||||
|
|
||||||
if internalutils.UkiBootMode() == internalutils.UkiHDD {
|
if internalutils.UkiBootMode() == internalutils.UkiHDD {
|
||||||
return upgradeUki(source, dirs, strictValidations, upgradeRecovery)
|
return upgradeUki(source, dirs, upgradeEntry, strictValidations)
|
||||||
} else {
|
} else {
|
||||||
return upgrade(source, force, strictValidations, dirs, preReleases, upgradeRecovery)
|
return upgrade(source, force, strictValidations, dirs, upgradeEntry, preReleases)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func upgrade(source string, force, strictValidations bool, dirs []string, preReleases, upgradeRecovery bool) error {
|
func upgrade(source string, force, strictValidations bool, dirs []string, upgradeEntry string, preReleases bool) error {
|
||||||
upgradeSpec, c, err := generateUpgradeSpec(source, force, strictValidations, dirs, preReleases, upgradeRecovery)
|
upgradeSpec, c, err := generateUpgradeSpec(source, force, strictValidations, dirs, upgradeEntry, preReleases)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -135,12 +135,10 @@ func newerReleases() (versioneer.TagList, error) {
|
|||||||
|
|
||||||
// generateUpgradeConfForCLIArgs creates a kairos configuration for `--source` and `--recovery`
|
// generateUpgradeConfForCLIArgs creates a kairos configuration for `--source` and `--recovery`
|
||||||
// command line arguments. It will be added to the rest of the configurations.
|
// command line arguments. It will be added to the rest of the configurations.
|
||||||
func generateUpgradeConfForCLIArgs(source string, upgradeRecovery bool) (string, error) {
|
func generateUpgradeConfForCLIArgs(source, upgradeEntry string) (string, error) {
|
||||||
upgradeConfig := ExtraConfigUpgrade{}
|
upgradeConfig := ExtraConfigUpgrade{}
|
||||||
|
|
||||||
if upgradeRecovery {
|
upgradeConfig.Upgrade.Entry = upgradeEntry
|
||||||
upgradeConfig.Upgrade.Recovery = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set uri both for active and recovery because we don't know what we are
|
// Set uri both for active and recovery because we don't know what we are
|
||||||
// actually upgrading. The "upgradeRecovery" is just the command line argument.
|
// actually upgrading. The "upgradeRecovery" is just the command line argument.
|
||||||
@ -157,8 +155,8 @@ func generateUpgradeConfForCLIArgs(source string, upgradeRecovery bool) (string,
|
|||||||
return string(d), err
|
return string(d), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateUpgradeSpec(sourceImageURL string, force, strictValidations bool, dirs []string, preReleases, upgradeRecovery bool) (*v1.UpgradeSpec, *config.Config, error) {
|
func generateUpgradeSpec(sourceImageURL string, force, strictValidations bool, dirs []string, upgradeEntry string, preReleases bool) (*v1.UpgradeSpec, *config.Config, error) {
|
||||||
cliConf, err := generateUpgradeConfForCLIArgs(sourceImageURL, upgradeRecovery)
|
cliConf, err := generateUpgradeConfForCLIArgs(sourceImageURL, upgradeEntry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@ -201,8 +199,8 @@ func getReleasesFromProvider(includePrereleases bool) ([]string, error) {
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func upgradeUki(source string, dirs []string, strictValidations, upgradeRecovery bool) error {
|
func upgradeUki(source string, dirs []string, upgradeEntry string, strictValidations bool) error {
|
||||||
cliConf, err := generateUpgradeConfForCLIArgs(source, upgradeRecovery)
|
cliConf, err := generateUpgradeConfForCLIArgs(source, upgradeEntry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -240,7 +238,7 @@ func upgradeUki(source string, dirs []string, strictValidations, upgradeRecovery
|
|||||||
// ExtraConfigUpgrade is the struct that holds the upgrade options that come from flags and events
|
// ExtraConfigUpgrade is the struct that holds the upgrade options that come from flags and events
|
||||||
type ExtraConfigUpgrade struct {
|
type ExtraConfigUpgrade struct {
|
||||||
Upgrade struct {
|
Upgrade struct {
|
||||||
Recovery bool `json:"recovery,omitempty"`
|
Entry string `json:"entry,omitempty"`
|
||||||
RecoverySystem struct {
|
RecoverySystem struct {
|
||||||
URI string `json:"uri,omitempty"`
|
URI string `json:"uri,omitempty"`
|
||||||
} `json:"recovery-system,omitempty"`
|
} `json:"recovery-system,omitempty"`
|
||||||
|
14
main.go
14
main.go
@ -69,6 +69,7 @@ var cmds = []*cli.Command{
|
|||||||
Usage: "[DEPRECATED] Specify a full image reference, e.g.: quay.io/some/image:tag",
|
Usage: "[DEPRECATED] Specify a full image reference, e.g.: quay.io/some/image:tag",
|
||||||
},
|
},
|
||||||
&sourceFlag,
|
&sourceFlag,
|
||||||
|
&cli.StringFlag{Name: "boot-entry", Usage: "Specify a systemd-boot entry to upgrade (other than active/passive/recovery). The value should match the name of the '.efi' file."},
|
||||||
&cli.BoolFlag{Name: "pre", Usage: "Include pre-releases (rc, beta, alpha)"},
|
&cli.BoolFlag{Name: "pre", Usage: "Include pre-releases (rc, beta, alpha)"},
|
||||||
&cli.BoolFlag{Name: "recovery", Usage: "Upgrade recovery"},
|
&cli.BoolFlag{Name: "recovery", Usage: "Upgrade recovery"},
|
||||||
},
|
},
|
||||||
@ -185,9 +186,20 @@ See https://kairos.io/docs/upgrade/manual/ for documentation.
|
|||||||
source = fmt.Sprintf("oci:%s", image)
|
source = fmt.Sprintf("oci:%s", image)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.Bool("recovery") && c.String("boot-entry") != "" {
|
||||||
|
return fmt.Errorf("only one of '--recovery' and '--boot-entry' can be set")
|
||||||
|
}
|
||||||
|
|
||||||
|
upgradeEntry := ""
|
||||||
|
if c.Bool("recovery") {
|
||||||
|
upgradeEntry = constants.BootEntryRecovery
|
||||||
|
} else if c.String("boot-entry") != "" {
|
||||||
|
upgradeEntry = c.String("boot-entry")
|
||||||
|
}
|
||||||
|
|
||||||
return agent.Upgrade(source, c.Bool("force"),
|
return agent.Upgrade(source, c.Bool("force"),
|
||||||
c.Bool("strict-validation"), constants.GetConfigScanDirs(),
|
c.Bool("strict-validation"), constants.GetConfigScanDirs(),
|
||||||
c.Bool("pre"), c.Bool("recovery"),
|
upgradeEntry, c.Bool("pre"),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -214,7 +214,7 @@ func systemdConfToBootName(conf string) (string, error) {
|
|||||||
return bootName, nil
|
return bootName, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", fmt.Errorf("unknown systemd-boot conf: %s", conf)
|
return strings.ReplaceAll(fileName, "_", " "), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func bootNameToSystemdConf(name string) (string, error) {
|
func bootNameToSystemdConf(name string) (string, error) {
|
||||||
@ -253,10 +253,9 @@ func bootNameToSystemdConf(name string) (string, error) {
|
|||||||
differenciator = "_" + strings.TrimPrefix(name, "statereset ")
|
differenciator = "_" + strings.TrimPrefix(name, "statereset ")
|
||||||
}
|
}
|
||||||
return "statereset" + differenciator + ".conf", nil
|
return "statereset" + differenciator + ".conf", nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return "", fmt.Errorf("unknown boot name: %s", name)
|
return strings.ReplaceAll(name, " ", "_") + ".conf", 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
|
||||||
@ -320,6 +319,10 @@ func listBootEntriesSystemd(cfg *config.Config) error {
|
|||||||
func listSystemdEntries(cfg *config.Config, efiPartition *v1.Partition) ([]string, error) {
|
func listSystemdEntries(cfg *config.Config, efiPartition *v1.Partition) ([]string, error) {
|
||||||
var entries []string
|
var entries []string
|
||||||
err := fsutils.WalkDirFs(cfg.Fs, filepath.Join(efiPartition.MountPoint, "loader/entries/"), func(path string, info os.DirEntry, err error) error {
|
err := fsutils.WalkDirFs(cfg.Fs, filepath.Join(efiPartition.MountPoint, "loader/entries/"), func(path string, info os.DirEntry, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
cfg.Logger.Errorf("Walking the dir %s", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
cfg.Logger.Debugf("Checking file %s", path)
|
cfg.Logger.Debugf("Checking file %s", path)
|
||||||
if info == nil {
|
if info == nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -26,7 +26,7 @@ import (
|
|||||||
"github.com/kairos-io/kairos-agent/v2/pkg/elemental"
|
"github.com/kairos-io/kairos-agent/v2/pkg/elemental"
|
||||||
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"
|
"github.com/kairos-io/kairos-agent/v2/pkg/utils"
|
||||||
"github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
|
fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
|
||||||
"github.com/kairos-io/kairos-sdk/state"
|
"github.com/kairos-io/kairos-sdk/state"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ func (u *UpgradeAction) upgradeInstallStateYaml(meta interface{}, img v1.Image)
|
|||||||
Label: img.Label,
|
Label: img.Label,
|
||||||
FS: img.FS,
|
FS: img.FS,
|
||||||
}
|
}
|
||||||
if u.spec.RecoveryUpgrade {
|
if u.spec.RecoveryUpgrade() {
|
||||||
recoveryPart := u.spec.State.Partitions[constants.RecoveryPartName]
|
recoveryPart := u.spec.State.Partitions[constants.RecoveryPartName]
|
||||||
if recoveryPart == nil {
|
if recoveryPart == nil {
|
||||||
recoveryPart = &v1.PartitionState{
|
recoveryPart = &v1.PartitionState{
|
||||||
@ -137,7 +137,7 @@ func (u *UpgradeAction) Run() (err error) {
|
|||||||
|
|
||||||
e := elemental.NewElemental(u.config)
|
e := elemental.NewElemental(u.config)
|
||||||
|
|
||||||
if u.spec.RecoveryUpgrade {
|
if u.spec.RecoveryUpgrade() {
|
||||||
upgradeImg = u.spec.Recovery
|
upgradeImg = u.spec.Recovery
|
||||||
if upgradeImg.FS == constants.SquashFs {
|
if upgradeImg.FS == constants.SquashFs {
|
||||||
finalImageFile = filepath.Join(u.spec.Partitions.Recovery.MountPoint, "cOS", constants.RecoverySquashFile)
|
finalImageFile = filepath.Join(u.spec.Partitions.Recovery.MountPoint, "cOS", constants.RecoverySquashFile)
|
||||||
@ -227,7 +227,7 @@ func (u *UpgradeAction) Run() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Only apply rebrand stage for system upgrades
|
// Only apply rebrand stage for system upgrades
|
||||||
if !u.spec.RecoveryUpgrade {
|
if !u.spec.RecoveryUpgrade() {
|
||||||
u.Info("rebranding")
|
u.Info("rebranding")
|
||||||
if rebrandingErr := e.SetDefaultGrubEntry(u.spec.Partitions.State.MountPoint, upgradeImg.MountPoint, u.spec.GrubDefEntry); rebrandingErr != nil {
|
if rebrandingErr := e.SetDefaultGrubEntry(u.spec.Partitions.State.MountPoint, upgradeImg.MountPoint, u.spec.GrubDefEntry); rebrandingErr != nil {
|
||||||
u.config.Logger.Warn("failure while rebranding GRUB default entry (ignoring), run with --debug to see more details")
|
u.config.Logger.Warn("failure while rebranding GRUB default entry (ignoring), run with --debug to see more details")
|
||||||
@ -244,7 +244,7 @@ func (u *UpgradeAction) Run() (err error) {
|
|||||||
// If not upgrading recovery and booting from non passive, backup active into passive
|
// If not upgrading recovery and booting from non passive, backup active into passive
|
||||||
// We dont want to overwrite passive if we are booting from passive as it could mean that active is broken and we would
|
// We dont want to overwrite passive if we are booting from passive as it could mean that active is broken and we would
|
||||||
// be overriding a working passive with a broken/unknown active
|
// be overriding a working passive with a broken/unknown active
|
||||||
if u.spec.RecoveryUpgrade == false && bootedFrom != state.Passive {
|
if !u.spec.RecoveryUpgrade() && bootedFrom != state.Passive {
|
||||||
// backup current active.img to passive.img before overwriting the active.img
|
// backup current active.img to passive.img before overwriting the active.img
|
||||||
u.Info("Backing up current active image")
|
u.Info("Backing up current active image")
|
||||||
source := filepath.Join(u.spec.Partitions.State.MountPoint, "cOS", constants.ActiveImgFile)
|
source := filepath.Join(u.spec.Partitions.State.MountPoint, "cOS", constants.ActiveImgFile)
|
||||||
@ -289,7 +289,7 @@ func (u *UpgradeAction) Run() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
u.Info("Upgrade completed")
|
u.Info("Upgrade completed")
|
||||||
if !u.spec.RecoveryUpgrade {
|
if !u.spec.RecoveryUpgrade() {
|
||||||
u.config.Logger.Warn("Remember that recovery is upgraded separately by passing the --recovery flag to the upgrade command!\n" +
|
u.config.Logger.Warn("Remember that recovery is upgraded separately by passing the --recovery flag to the upgrade command!\n" +
|
||||||
"See more info about this on https://kairos.io/docs/upgrade/")
|
"See more info about this on https://kairos.io/docs/upgrade/")
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,10 @@ package action_test
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
sdkTypes "github.com/kairos-io/kairos-sdk/types"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
sdkTypes "github.com/kairos-io/kairos-sdk/types"
|
||||||
|
|
||||||
agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config"
|
agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config"
|
||||||
fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
|
fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
|
||||||
|
|
||||||
@ -449,8 +450,7 @@ var _ = Describe("Runtime Actions", func() {
|
|||||||
spec.Active.Size = 10
|
spec.Active.Size = 10
|
||||||
spec.Passive.Size = 10
|
spec.Passive.Size = 10
|
||||||
spec.Recovery.Size = 10
|
spec.Recovery.Size = 10
|
||||||
|
spec.Entry = constants.BootEntryRecovery
|
||||||
spec.RecoveryUpgrade = true
|
|
||||||
|
|
||||||
err = fsutils.MkdirAll(config.Fs, "/proc", constants.DirPerm)
|
err = fsutils.MkdirAll(config.Fs, "/proc", constants.DirPerm)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
@ -542,8 +542,7 @@ var _ = Describe("Runtime Actions", func() {
|
|||||||
spec.Active.Size = 10
|
spec.Active.Size = 10
|
||||||
spec.Passive.Size = 10
|
spec.Passive.Size = 10
|
||||||
spec.Recovery.Size = 10
|
spec.Recovery.Size = 10
|
||||||
|
spec.Entry = constants.BootEntryRecovery
|
||||||
spec.RecoveryUpgrade = true
|
|
||||||
|
|
||||||
err = fsutils.MkdirAll(config.Fs, "/proc", constants.DirPerm)
|
err = fsutils.MkdirAll(config.Fs, "/proc", constants.DirPerm)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
|
@ -24,6 +24,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/kairos-io/kairos-sdk/collector"
|
||||||
sdkTypes "github.com/kairos-io/kairos-sdk/types"
|
sdkTypes "github.com/kairos-io/kairos-sdk/types"
|
||||||
|
|
||||||
"github.com/google/go-containerregistry/pkg/crane"
|
"github.com/google/go-containerregistry/pkg/crane"
|
||||||
@ -323,7 +324,21 @@ func NewUpgradeSpec(cfg *Config) (*v1.UpgradeSpec, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deep look to see if upgrade.recovery == true in the config
|
||||||
|
// if yes, we set the upgrade spec "Entry" to "recovery"
|
||||||
|
entry := ""
|
||||||
|
_, ok := cfg.Config["upgrade"]
|
||||||
|
if ok {
|
||||||
|
_, ok = cfg.Config["upgrade"].(collector.Config)["recovery"]
|
||||||
|
if ok {
|
||||||
|
if cfg.Config["upgrade"].(collector.Config)["recovery"].(bool) {
|
||||||
|
entry = constants.BootEntryRecovery
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
spec := &v1.UpgradeSpec{
|
spec := &v1.UpgradeSpec{
|
||||||
|
Entry: entry,
|
||||||
Active: active,
|
Active: active,
|
||||||
Recovery: recovery,
|
Recovery: recovery,
|
||||||
Passive: passive,
|
Passive: passive,
|
||||||
@ -346,7 +361,7 @@ func setUpgradeSourceSize(cfg *Config, spec *v1.UpgradeSpec) error {
|
|||||||
var err error
|
var err error
|
||||||
|
|
||||||
var targetSpec *v1.Image
|
var targetSpec *v1.Image
|
||||||
if spec.RecoveryUpgrade {
|
if spec.RecoveryUpgrade() {
|
||||||
targetSpec = &(spec.Recovery)
|
targetSpec = &(spec.Recovery)
|
||||||
} else {
|
} else {
|
||||||
targetSpec = &(spec.Active)
|
targetSpec = &(spec.Active)
|
||||||
|
@ -18,11 +18,12 @@ package config_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
sdkTypes "github.com/kairos-io/kairos-sdk/types"
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
sdkTypes "github.com/kairos-io/kairos-sdk/types"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
|
||||||
"github.com/jaypipes/ghw/pkg/block"
|
"github.com/jaypipes/ghw/pkg/block"
|
||||||
config "github.com/kairos-io/kairos-agent/v2/pkg/config"
|
config "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"
|
||||||
@ -587,7 +588,7 @@ cloud-init-paths:
|
|||||||
spec, err := config.ReadSpecFromCloudConfig(cfg, "upgrade")
|
spec, err := config.ReadSpecFromCloudConfig(cfg, "upgrade")
|
||||||
Expect(err).ToNot(HaveOccurred())
|
Expect(err).ToNot(HaveOccurred())
|
||||||
upgradeSpec := spec.(*v1.UpgradeSpec)
|
upgradeSpec := spec.(*v1.UpgradeSpec)
|
||||||
Expect(upgradeSpec.RecoveryUpgrade).To(BeTrue())
|
Expect(upgradeSpec.RecoveryUpgrade()).To(BeTrue())
|
||||||
})
|
})
|
||||||
It("Fails when a wrong action is read", func() {
|
It("Fails when a wrong action is read", func() {
|
||||||
cfg, err := config.Scan(collector.Directories([]string{dir}...), collector.NoLogs)
|
cfg, err := config.Scan(collector.Directories([]string{dir}...), collector.NoLogs)
|
||||||
|
@ -88,6 +88,7 @@ const (
|
|||||||
GPT = "gpt"
|
GPT = "gpt"
|
||||||
UsrLocalPath = "/usr/local"
|
UsrLocalPath = "/usr/local"
|
||||||
OEMPath = "/oem"
|
OEMPath = "/oem"
|
||||||
|
BootEntryRecovery = "recovery"
|
||||||
|
|
||||||
// SELinux targeted policy paths
|
// SELinux targeted policy paths
|
||||||
SELinuxTargetedPath = "/etc/selinux/targeted"
|
SELinuxTargetedPath = "/etc/selinux/targeted"
|
||||||
|
@ -170,7 +170,7 @@ func (r *ResetSpec) ShouldReboot() bool { return r.Reboot }
|
|||||||
func (r *ResetSpec) ShouldShutdown() bool { return r.PowerOff }
|
func (r *ResetSpec) ShouldShutdown() bool { return r.PowerOff }
|
||||||
|
|
||||||
type UpgradeSpec struct {
|
type UpgradeSpec struct {
|
||||||
RecoveryUpgrade bool `yaml:"recovery,omitempty" mapstructure:"recovery"`
|
Entry string `yaml:"entry,omitempty" mapstructure:"entry"`
|
||||||
Active Image `yaml:"system,omitempty" mapstructure:"system"`
|
Active Image `yaml:"system,omitempty" mapstructure:"system"`
|
||||||
Recovery Image `yaml:"recovery-system,omitempty" mapstructure:"recovery-system"`
|
Recovery Image `yaml:"recovery-system,omitempty" mapstructure:"recovery-system"`
|
||||||
GrubDefEntry string `yaml:"grub-entry-name,omitempty" mapstructure:"grub-entry-name"`
|
GrubDefEntry string `yaml:"grub-entry-name,omitempty" mapstructure:"grub-entry-name"`
|
||||||
@ -182,10 +182,14 @@ type UpgradeSpec struct {
|
|||||||
State *InstallState
|
State *InstallState
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *UpgradeSpec) RecoveryUpgrade() bool {
|
||||||
|
return u.Entry == constants.BootEntryRecovery
|
||||||
|
}
|
||||||
|
|
||||||
// Sanitize checks the consistency of the struct, returns error
|
// Sanitize checks the consistency of the struct, returns error
|
||||||
// if unsolvable inconsistencies are found
|
// if unsolvable inconsistencies are found
|
||||||
func (u *UpgradeSpec) Sanitize() error {
|
func (u *UpgradeSpec) Sanitize() error {
|
||||||
if u.RecoveryUpgrade {
|
if u.RecoveryUpgrade() {
|
||||||
if u.Recovery.Source.IsEmpty() {
|
if u.Recovery.Source.IsEmpty() {
|
||||||
return fmt.Errorf(constants.UpgradeNoSourceError)
|
return fmt.Errorf(constants.UpgradeNoSourceError)
|
||||||
}
|
}
|
||||||
@ -528,13 +532,17 @@ func (i *InstallUkiSpec) GetPartitions() ElementalPartitions { return i.Partitio
|
|||||||
func (i *InstallUkiSpec) GetExtraPartitions() PartitionList { return i.ExtraPartitions }
|
func (i *InstallUkiSpec) GetExtraPartitions() PartitionList { return i.ExtraPartitions }
|
||||||
|
|
||||||
type UpgradeUkiSpec struct {
|
type UpgradeUkiSpec struct {
|
||||||
RecoveryUpgrade bool `yaml:"recovery,omitempty" mapstructure:"recovery"`
|
Entry string `yaml:"entry,omitempty" mapstructure:"entry"`
|
||||||
Active Image `yaml:"system,omitempty" mapstructure:"system"`
|
Active Image `yaml:"system,omitempty" mapstructure:"system"`
|
||||||
Reboot bool `yaml:"reboot,omitempty" mapstructure:"reboot"`
|
Reboot bool `yaml:"reboot,omitempty" mapstructure:"reboot"`
|
||||||
PowerOff bool `yaml:"poweroff,omitempty" mapstructure:"poweroff"`
|
PowerOff bool `yaml:"poweroff,omitempty" mapstructure:"poweroff"`
|
||||||
EfiPartition *Partition `yaml:"efi-partition,omitempty" mapstructure:"efi-partition"`
|
EfiPartition *Partition `yaml:"efi-partition,omitempty" mapstructure:"efi-partition"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *UpgradeUkiSpec) RecoveryUpgrade() bool {
|
||||||
|
return i.Entry == constants.BootEntryRecovery
|
||||||
|
}
|
||||||
|
|
||||||
func (i *UpgradeUkiSpec) Sanitize() error {
|
func (i *UpgradeUkiSpec) Sanitize() error {
|
||||||
var err error
|
var err error
|
||||||
return err
|
return err
|
||||||
|
@ -17,11 +17,12 @@ limitations under the License.
|
|||||||
package v1_test
|
package v1_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"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/onsi/ginkgo/v2"
|
. "github.com/onsi/ginkgo/v2"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"path/filepath"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = Describe("Types", Label("types", "config"), func() {
|
var _ = Describe("Types", Label("types", "config"), func() {
|
||||||
@ -444,7 +445,7 @@ var _ = Describe("Types", Label("types", "config"), func() {
|
|||||||
})
|
})
|
||||||
Describe("Recovery upgrade", func() {
|
Describe("Recovery upgrade", func() {
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
spec.RecoveryUpgrade = true
|
spec.Entry = constants.BootEntryRecovery
|
||||||
})
|
})
|
||||||
It("fails with empty source", func() {
|
It("fails with empty source", func() {
|
||||||
err := spec.Sanitize()
|
err := spec.Sanitize()
|
||||||
|
@ -51,13 +51,20 @@ func (i *UpgradeAction) Run() (err error) {
|
|||||||
// If we decide to first copy and then rotate, we need ~4 times the size of
|
// If we decide to first copy and then rotate, we need ~4 times the size of
|
||||||
// the artifact set [TBD]
|
// the artifact set [TBD]
|
||||||
|
|
||||||
// When upgrading recovery, we don't want to replace loader.conf or any other
|
// When upgrading recovery or single entries, 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
|
// files, thus we take a simpler approach and only install the new efi file
|
||||||
// and the relevant conf
|
// and the relevant conf
|
||||||
if i.spec.RecoveryUpgrade {
|
if i.spec.RecoveryUpgrade() {
|
||||||
|
i.cfg.Logger.Infof("installing entry: recovery")
|
||||||
return i.installRecovery()
|
return i.installRecovery()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if i.spec.Entry != "" { // single entry upgrade
|
||||||
|
i.cfg.Logger.Infof("installing entry: %s", i.spec.Entry)
|
||||||
|
return i.installEntry(i.spec.Entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
i.cfg.Logger.Infof("installing entry: active")
|
||||||
// Dump artifact to efi dir
|
// Dump artifact to efi dir
|
||||||
_, err = e.DumpSource(constants.UkiEfiDir, i.spec.Active.Source)
|
_, err = e.DumpSource(constants.UkiEfiDir, i.spec.Active.Source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -122,9 +129,12 @@ func (i *UpgradeAction) Run() (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// installRecovery replaces the "recovery" role efi and conf files with
|
func (i *UpgradeAction) installEntry(entry string) error {
|
||||||
// the UnassignedArtifactRole efi and loader files from dir
|
targetEntryFile := filepath.Join(constants.UkiEfiDir, "EFI", "kairos", fmt.Sprintf("%s.efi", entry))
|
||||||
func (i *UpgradeAction) installRecovery() error {
|
if _, err := os.Stat(targetEntryFile); err != nil {
|
||||||
|
return fmt.Errorf("could not stat target efi file for entry %s: %s", entry, err)
|
||||||
|
}
|
||||||
|
|
||||||
tmpDir, err := os.MkdirTemp("", "")
|
tmpDir, err := os.MkdirTemp("", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
i.cfg.Logger.Errorf("creating a tmp dir: %s", err.Error())
|
i.cfg.Logger.Errorf("creating a tmp dir: %s", err.Error())
|
||||||
@ -140,15 +150,13 @@ func (i *UpgradeAction) installRecovery() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = copyFile(
|
err = copyFile(filepath.Join(tmpDir, "EFI", "kairos", UnassignedArtifactRole+".efi"), targetEntryFile)
|
||||||
filepath.Join(tmpDir, "EFI", "kairos", UnassignedArtifactRole+".efi"),
|
|
||||||
filepath.Join(constants.UkiEfiDir, "EFI", "kairos", "recovery.efi"))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
i.cfg.Logger.Errorf("copying efi files: %s", err.Error())
|
i.cfg.Logger.Errorf("copying efi files: %s", err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
targetConfPath := filepath.Join(constants.UkiEfiDir, "loader", "entries", "recovery.conf")
|
targetConfPath := filepath.Join(constants.UkiEfiDir, "loader", "entries", fmt.Sprintf("%s.conf", entry))
|
||||||
err = copyFile(
|
err = copyFile(
|
||||||
filepath.Join(tmpDir, "loader", "entries", UnassignedArtifactRole+".conf"),
|
filepath.Join(tmpDir, "loader", "entries", UnassignedArtifactRole+".conf"),
|
||||||
targetConfPath)
|
targetConfPath)
|
||||||
@ -156,13 +164,24 @@ func (i *UpgradeAction) installRecovery() error {
|
|||||||
i.cfg.Logger.Errorf("copying conf files: %s", err.Error())
|
i.cfg.Logger.Errorf("copying conf files: %s", err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = replaceRoleInKey(targetConfPath, "efi", UnassignedArtifactRole, "recovery", i.cfg.Logger)
|
err = replaceRoleInKey(targetConfPath, "efi", UnassignedArtifactRole, entry, i.cfg.Logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
i.cfg.Logger.Errorf("replacing role in in key %s: %s", "efi", err.Error())
|
i.cfg.Logger.Errorf("replacing role in in key %s: %s", "efi", err.Error())
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = replaceConfTitle(targetConfPath, "recovery")
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// installRecovery replaces the "recovery" role efi and conf files with
|
||||||
|
// the UnassignedArtifactRole efi and loader files from dir
|
||||||
|
func (i *UpgradeAction) installRecovery() error {
|
||||||
|
if err := i.installEntry("recovery"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
targetConfPath := filepath.Join(constants.UkiEfiDir, "loader", "entries", "recovery.conf")
|
||||||
|
err := replaceConfTitle(targetConfPath, "recovery")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
i.cfg.Logger.Errorf("replacing conf title: %s", err.Error())
|
i.cfg.Logger.Errorf("replacing conf title: %s", err.Error())
|
||||||
return err
|
return err
|
||||||
|
Loading…
Reference in New Issue
Block a user