Skip to content

Commit

Permalink
Merge pull request #446 from kairos-io/2385-upgrade-single-entries
Browse files Browse the repository at this point in the history
2385 upgrade single entries
  • Loading branch information
jimmykarily authored Aug 26, 2024
2 parents b172603 + 332d516 commit 390bc6a
Show file tree
Hide file tree
Showing 11 changed files with 110 additions and 53 deletions.
26 changes: 12 additions & 14 deletions internal/agent/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,18 @@ func ListNewerReleases(includePrereleases bool) ([]string, error) {
}

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()

if internalutils.UkiBootMode() == internalutils.UkiHDD {
return upgradeUki(source, dirs, strictValidations, upgradeRecovery)
return upgradeUki(source, dirs, upgradeEntry, strictValidations)
} 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 {
upgradeSpec, c, err := generateUpgradeSpec(source, force, strictValidations, dirs, preReleases, upgradeRecovery)
func upgrade(source string, force, strictValidations bool, dirs []string, upgradeEntry string, preReleases bool) error {
upgradeSpec, c, err := generateUpgradeSpec(source, force, strictValidations, dirs, upgradeEntry, preReleases)
if err != nil {
return err
}
Expand Down Expand Up @@ -135,12 +135,10 @@ func newerReleases() (versioneer.TagList, error) {

// generateUpgradeConfForCLIArgs creates a kairos configuration for `--source` and `--recovery`
// 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{}

if upgradeRecovery {
upgradeConfig.Upgrade.Recovery = true
}
upgradeConfig.Upgrade.Entry = upgradeEntry

// 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.
Expand All @@ -157,8 +155,8 @@ func generateUpgradeConfForCLIArgs(source string, upgradeRecovery bool) (string,
return string(d), err
}

func generateUpgradeSpec(sourceImageURL string, force, strictValidations bool, dirs []string, preReleases, upgradeRecovery bool) (*v1.UpgradeSpec, *config.Config, error) {
cliConf, err := generateUpgradeConfForCLIArgs(sourceImageURL, upgradeRecovery)
func generateUpgradeSpec(sourceImageURL string, force, strictValidations bool, dirs []string, upgradeEntry string, preReleases bool) (*v1.UpgradeSpec, *config.Config, error) {
cliConf, err := generateUpgradeConfForCLIArgs(sourceImageURL, upgradeEntry)
if err != nil {
return nil, nil, err
}
Expand Down Expand Up @@ -201,8 +199,8 @@ func getReleasesFromProvider(includePrereleases bool) ([]string, error) {
return result, nil
}

func upgradeUki(source string, dirs []string, strictValidations, upgradeRecovery bool) error {
cliConf, err := generateUpgradeConfForCLIArgs(source, upgradeRecovery)
func upgradeUki(source string, dirs []string, upgradeEntry string, strictValidations bool) error {
cliConf, err := generateUpgradeConfForCLIArgs(source, upgradeEntry)
if err != nil {
return err
}
Expand Down Expand Up @@ -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
type ExtraConfigUpgrade struct {
Upgrade struct {
Recovery bool `json:"recovery,omitempty"`
Entry string `json:"entry,omitempty"`
RecoverySystem struct {
URI string `json:"uri,omitempty"`
} `json:"recovery-system,omitempty"`
Expand Down
14 changes: 13 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ var cmds = []*cli.Command{
Usage: "[DEPRECATED] Specify a full image reference, e.g.: quay.io/some/image:tag",
},
&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: "recovery", Usage: "Upgrade recovery"},
},
Expand Down Expand Up @@ -185,9 +186,20 @@ See https://kairos.io/docs/upgrade/manual/ for documentation.
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"),
c.Bool("strict-validation"), constants.GetConfigScanDirs(),
c.Bool("pre"), c.Bool("recovery"),
upgradeEntry, c.Bool("pre"),
)
},
},
Expand Down
9 changes: 6 additions & 3 deletions pkg/action/bootentries.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ func systemdConfToBootName(conf string) (string, error) {
return bootName, nil
}

return "", fmt.Errorf("unknown systemd-boot conf: %s", conf)
return strings.ReplaceAll(fileName, "_", " "), nil
}

func bootNameToSystemdConf(name string) (string, error) {
Expand Down Expand Up @@ -253,10 +253,9 @@ func bootNameToSystemdConf(name string) (string, error) {
differenciator = "_" + strings.TrimPrefix(name, "statereset ")
}
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
Expand Down Expand Up @@ -320,6 +319,10 @@ func listBootEntriesSystemd(cfg *config.Config) error {
func listSystemdEntries(cfg *config.Config, efiPartition *v1.Partition) ([]string, error) {
var entries []string
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)
if info == nil {
return nil
Expand Down
12 changes: 6 additions & 6 deletions pkg/action/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (
"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"
fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"
"github.com/kairos-io/kairos-sdk/state"
)

Expand Down Expand Up @@ -90,7 +90,7 @@ func (u *UpgradeAction) upgradeInstallStateYaml(meta interface{}, img v1.Image)
Label: img.Label,
FS: img.FS,
}
if u.spec.RecoveryUpgrade {
if u.spec.RecoveryUpgrade() {
recoveryPart := u.spec.State.Partitions[constants.RecoveryPartName]
if recoveryPart == nil {
recoveryPart = &v1.PartitionState{
Expand Down Expand Up @@ -137,7 +137,7 @@ func (u *UpgradeAction) Run() (err error) {

e := elemental.NewElemental(u.config)

if u.spec.RecoveryUpgrade {
if u.spec.RecoveryUpgrade() {
upgradeImg = u.spec.Recovery
if upgradeImg.FS == constants.SquashFs {
finalImageFile = filepath.Join(u.spec.Partitions.Recovery.MountPoint, "cOS", constants.RecoverySquashFile)
Expand Down Expand Up @@ -227,7 +227,7 @@ func (u *UpgradeAction) Run() (err error) {
}

// Only apply rebrand stage for system upgrades
if !u.spec.RecoveryUpgrade {
if !u.spec.RecoveryUpgrade() {
u.Info("rebranding")
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")
Expand All @@ -244,7 +244,7 @@ func (u *UpgradeAction) Run() (err error) {
// 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 {
if !u.spec.RecoveryUpgrade() && 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)
Expand Down Expand Up @@ -289,7 +289,7 @@ func (u *UpgradeAction) Run() (err error) {
}

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" +
"See more info about this on https://kairos.io/docs/upgrade/")
}
Expand Down
9 changes: 4 additions & 5 deletions pkg/action/upgrade_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ package action_test
import (
"bytes"
"fmt"
sdkTypes "github.com/kairos-io/kairos-sdk/types"
"path/filepath"

sdkTypes "github.com/kairos-io/kairos-sdk/types"

agentConfig "github.com/kairos-io/kairos-agent/v2/pkg/config"
fsutils "github.com/kairos-io/kairos-agent/v2/pkg/utils/fs"

Expand Down Expand Up @@ -449,8 +450,7 @@ var _ = Describe("Runtime Actions", func() {
spec.Active.Size = 10
spec.Passive.Size = 10
spec.Recovery.Size = 10

spec.RecoveryUpgrade = true
spec.Entry = constants.BootEntryRecovery

err = fsutils.MkdirAll(config.Fs, "/proc", constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred())
Expand Down Expand Up @@ -542,8 +542,7 @@ var _ = Describe("Runtime Actions", func() {
spec.Active.Size = 10
spec.Passive.Size = 10
spec.Recovery.Size = 10

spec.RecoveryUpgrade = true
spec.Entry = constants.BootEntryRecovery

err = fsutils.MkdirAll(config.Fs, "/proc", constants.DirPerm)
Expect(err).ShouldNot(HaveOccurred())
Expand Down
17 changes: 16 additions & 1 deletion pkg/config/spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"reflect"
"strings"

"github.com/kairos-io/kairos-sdk/collector"
sdkTypes "github.com/kairos-io/kairos-sdk/types"

"github.com/google/go-containerregistry/pkg/crane"
Expand Down Expand Up @@ -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{
Entry: entry,
Active: active,
Recovery: recovery,
Passive: passive,
Expand All @@ -346,7 +361,7 @@ func setUpgradeSourceSize(cfg *Config, spec *v1.UpgradeSpec) error {
var err error

var targetSpec *v1.Image
if spec.RecoveryUpgrade {
if spec.RecoveryUpgrade() {
targetSpec = &(spec.Recovery)
} else {
targetSpec = &(spec.Active)
Expand Down
7 changes: 4 additions & 3 deletions pkg/config/spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ package config_test

import (
"fmt"
sdkTypes "github.com/kairos-io/kairos-sdk/types"
"github.com/rs/zerolog"
"os"
"path/filepath"

sdkTypes "github.com/kairos-io/kairos-sdk/types"
"github.com/rs/zerolog"

"github.com/jaypipes/ghw/pkg/block"
config "github.com/kairos-io/kairos-agent/v2/pkg/config"
"github.com/kairos-io/kairos-agent/v2/pkg/constants"
Expand Down Expand Up @@ -587,7 +588,7 @@ cloud-init-paths:
spec, err := config.ReadSpecFromCloudConfig(cfg, "upgrade")
Expect(err).ToNot(HaveOccurred())
upgradeSpec := spec.(*v1.UpgradeSpec)
Expect(upgradeSpec.RecoveryUpgrade).To(BeTrue())
Expect(upgradeSpec.RecoveryUpgrade()).To(BeTrue())
})
It("Fails when a wrong action is read", func() {
cfg, err := config.Scan(collector.Directories([]string{dir}...), collector.NoLogs)
Expand Down
1 change: 1 addition & 0 deletions pkg/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ const (
GPT = "gpt"
UsrLocalPath = "/usr/local"
OEMPath = "/oem"
BootEntryRecovery = "recovery"

// SELinux targeted policy paths
SELinuxTargetedPath = "/etc/selinux/targeted"
Expand Down
22 changes: 15 additions & 7 deletions pkg/types/v1/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ func (r *ResetSpec) ShouldReboot() bool { return r.Reboot }
func (r *ResetSpec) ShouldShutdown() bool { return r.PowerOff }

type UpgradeSpec struct {
RecoveryUpgrade bool `yaml:"recovery,omitempty" mapstructure:"recovery"`
Entry string `yaml:"entry,omitempty" mapstructure:"entry"`
Active Image `yaml:"system,omitempty" mapstructure:"system"`
Recovery Image `yaml:"recovery-system,omitempty" mapstructure:"recovery-system"`
GrubDefEntry string `yaml:"grub-entry-name,omitempty" mapstructure:"grub-entry-name"`
Expand All @@ -182,10 +182,14 @@ type UpgradeSpec struct {
State *InstallState
}

func (u *UpgradeSpec) RecoveryUpgrade() bool {
return u.Entry == constants.BootEntryRecovery
}

// Sanitize checks the consistency of the struct, returns error
// if unsolvable inconsistencies are found
func (u *UpgradeSpec) Sanitize() error {
if u.RecoveryUpgrade {
if u.RecoveryUpgrade() {
if u.Recovery.Source.IsEmpty() {
return fmt.Errorf(constants.UpgradeNoSourceError)
}
Expand Down Expand Up @@ -528,11 +532,15 @@ func (i *InstallUkiSpec) GetPartitions() ElementalPartitions { return i.Partitio
func (i *InstallUkiSpec) GetExtraPartitions() PartitionList { return i.ExtraPartitions }

type UpgradeUkiSpec struct {
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"`
Entry string `yaml:"entry,omitempty" mapstructure:"entry"`
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) RecoveryUpgrade() bool {
return i.Entry == constants.BootEntryRecovery
}

func (i *UpgradeUkiSpec) Sanitize() error {
Expand Down
5 changes: 3 additions & 2 deletions pkg/types/v1/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ limitations under the License.
package v1_test

import (
"path/filepath"

"github.com/kairos-io/kairos-agent/v2/pkg/constants"
v1 "github.com/kairos-io/kairos-agent/v2/pkg/types/v1"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"path/filepath"
)

var _ = Describe("Types", Label("types", "config"), func() {
Expand Down Expand Up @@ -444,7 +445,7 @@ var _ = Describe("Types", Label("types", "config"), func() {
})
Describe("Recovery upgrade", func() {
BeforeEach(func() {
spec.RecoveryUpgrade = true
spec.Entry = constants.BootEntryRecovery
})
It("fails with empty source", func() {
err := spec.Sanitize()
Expand Down
Loading

0 comments on commit 390bc6a

Please sign in to comment.