diff --git a/go.mod b/go.mod index eb1d20c..84c452b 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/hashicorp/go-multierror v1.1.1 github.com/jaypipes/ghw v0.12.0 github.com/joho/godotenv v1.5.1 - github.com/kairos-io/kairos-sdk v0.0.13 + github.com/kairos-io/kairos-sdk v0.0.14 github.com/labstack/echo/v4 v4.11.1 github.com/mitchellh/mapstructure v1.5.0 github.com/mudler/go-nodepair v0.0.0-20221223092639-ba399a66fdfb diff --git a/go.sum b/go.sum index 8fad03d..7927e0f 100644 --- a/go.sum +++ b/go.sum @@ -358,6 +358,8 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kairos-io/kairos-sdk v0.0.13 h1:YI+ETmlk86+mHTQYBNPmVTiO2Ux63HmkRzxhAJRr9JI= github.com/kairos-io/kairos-sdk v0.0.13/go.mod h1:+fhVoCEA2hD7OFTmhDmy4pP3uC9q84OYhDa7irkEVWQ= +github.com/kairos-io/kairos-sdk v0.0.14 h1:yVKaay70cjmAUY6m4uLoV9UguBv3Dx3JxAh2faRlUZo= +github.com/kairos-io/kairos-sdk v0.0.14/go.mod h1:+fhVoCEA2hD7OFTmhDmy4pP3uC9q84OYhDa7irkEVWQ= github.com/kbinani/screenshot v0.0.0-20210720154843-7d3a670d8329 h1:qq2nCpSrXrmvDGRxW0ruW9BVEV1CN2a9YDOExdt+U0o= github.com/kbinani/screenshot v0.0.0-20210720154843-7d3a670d8329/go.mod h1:2VPVQDR4wO7KXHwP+DAypEy67rXf+okUx2zjgpCxZw4= github.com/kendru/darwin/go/depgraph v0.0.0-20221105232959-877d6a81060c h1:eKb4PqwAMhlqwXw0W3atpKaYaPGlXE/Fwh+xpCEYaPk= diff --git a/pkg/action/upgrade.go b/pkg/action/upgrade.go index 59c1104..7bc3f10 100644 --- a/pkg/action/upgrade.go +++ b/pkg/action/upgrade.go @@ -18,15 +18,16 @@ package action import ( "fmt" - agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config" - "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs" "path/filepath" "time" + agentConfig "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/elemental" 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/fs" + "github.com/kairos-io/kairos-sdk/state" ) // UpgradeAction represents the struct that will run the upgrade from start to finish @@ -121,6 +122,16 @@ func (u *UpgradeAction) Run() (err error) { var upgradeImg v1.Image var finalImageFile string + // Track where we booted from to have a different workflow + // Booted from active: backup active into passive, upgrade active + // Booted from passive: Upgrade active, leave passive as is + var bootedFrom state.Boot + + bootedFrom, err = state.DetectBootWithVFS(u.config.Fs) + if err != nil { + u.config.Logger.Warnf("error detecting boot: %s", err) + } + cleanup := utils.NewCleanStack() defer func() { err = cleanup.Cleanup(err) }() @@ -230,9 +241,10 @@ func (u *UpgradeAction) Run() (err error) { return err } - // If not upgrading recovery, backup active into passive - if !u.spec.RecoveryUpgrade { - //TODO this step could be part of elemental package + // 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 + // be overriding a working passive with a broken/unknown active + if u.spec.RecoveryUpgrade == false && bootedFrom != state.Passive { // backup current active.img to passive.img before overwriting the active.img u.Info("Backing up current active image") source := filepath.Join(u.spec.Partitions.State.MountPoint, "cOS", constants.ActiveImgFile) diff --git a/pkg/action/upgrade_test.go b/pkg/action/upgrade_test.go index 4bdc879..7ebc13e 100644 --- a/pkg/action/upgrade_test.go +++ b/pkg/action/upgrade_test.go @@ -149,6 +149,13 @@ var _ = Describe("Runtime Actions", func() { err = fsutils.MkdirAll(config.Fs, filepath.Join(spec.Active.MountPoint, "etc"), constants.DirPerm) Expect(err).ShouldNot(HaveOccurred()) + err = fsutils.MkdirAll(config.Fs, "/proc", constants.DirPerm) + Expect(err).ShouldNot(HaveOccurred()) + + // Write proc/cmdline so we can detect what we booted from + err = fs.WriteFile("/proc/cmdline", []byte(constants.ActiveLabel), constants.FilePerm) + Expect(err).ShouldNot(HaveOccurred()) + err = fs.WriteFile( filepath.Join(spec.Active.MountPoint, "etc", "os-release"), []byte("GRUB_ENTRY_NAME=TESTOS"), @@ -161,9 +168,6 @@ var _ = Describe("Runtime Actions", func() { spec.Recovery.Size = 10 runner.SideEffect = func(command string, args ...string) ([]byte, error) { - if command == "cat" && args[0] == "/proc/cmdline" { - return []byte(constants.ActiveLabel), nil - } if command == "mv" && args[0] == "-f" && args[1] == activeImg && args[2] == passiveImg { // we doing backup, do the "move" source, _ := fs.ReadFile(activeImg) @@ -359,6 +363,13 @@ var _ = Describe("Runtime Actions", func() { ) Expect(err).ShouldNot(HaveOccurred()) + err = fsutils.MkdirAll(config.Fs, "/proc", constants.DirPerm) + Expect(err).ShouldNot(HaveOccurred()) + + // Write proc/cmdline so we can detect what we booted from + err = fs.WriteFile("/proc/cmdline", []byte(constants.PassiveLabel), constants.FilePerm) + Expect(err).ShouldNot(HaveOccurred()) + spec.Active.Size = 10 spec.Passive.Size = 10 spec.Recovery.Size = 10 @@ -373,6 +384,10 @@ var _ = Describe("Runtime Actions", func() { _ = fs.WriteFile(activeImg, source, constants.FilePerm) _ = fs.RemoveAll(spec.Active.File) } + if command == "mv" && args[0] == "-f" && args[1] == activeImg && args[2] == passiveImg { + // If this command was called then its a complete failure as it tried to copy active into passive + StopTrying("Passive was overwritten").Now() + } return []byte{}, nil } config.Runner = runner @@ -436,6 +451,13 @@ var _ = Describe("Runtime Actions", func() { spec.RecoveryUpgrade = true + err = fsutils.MkdirAll(config.Fs, "/proc", constants.DirPerm) + Expect(err).ShouldNot(HaveOccurred()) + + // Write proc/cmdline so we can detect what we booted from + err = fs.WriteFile("/proc/cmdline", []byte(constants.RecoveryLabel), constants.FilePerm) + Expect(err).ShouldNot(HaveOccurred()) + runner.SideEffect = func(command string, args ...string) ([]byte, error) { if command == "cat" && args[0] == "/proc/cmdline" { return []byte(constants.RecoveryLabel), nil @@ -522,6 +544,13 @@ var _ = Describe("Runtime Actions", func() { spec.RecoveryUpgrade = true + err = fsutils.MkdirAll(config.Fs, "/proc", constants.DirPerm) + Expect(err).ShouldNot(HaveOccurred()) + + // Write proc/cmdline so we can detect what we booted from + err = fs.WriteFile("/proc/cmdline", []byte(constants.RecoveryLabel), constants.FilePerm) + Expect(err).ShouldNot(HaveOccurred()) + runner.SideEffect = func(command string, args ...string) ([]byte, error) { if command == "cat" && args[0] == "/proc/cmdline" { return []byte(constants.RecoveryLabel), nil