Skip to content

Commit

Permalink
Fix regression tests.
Browse files Browse the repository at this point in the history
orange now boots on btrfs snapshotter.
- grub configuration can now work without default subvolume
- moved kernel link relativize call
  • Loading branch information
rdesaintleger committed Oct 18, 2024
1 parent 009c677 commit e437f86
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 108 deletions.
11 changes: 6 additions & 5 deletions pkg/action/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,13 @@ func RunInit(cfg *types.RunConfig, spec *types.InitSpec) error {
cfg.Config.Logger.Errorf("failed creating kernel symlink")
return err
}
}

err = utils.RelativizeLink(cfg.Fs, constants.KernelPath)
if err != nil {
cfg.Config.Logger.Errorf("failed relativizing kernel symlink")
return err
}
// ensure kernel link is relativized if applicable
err = utils.RelativizeLink(cfg.Fs, constants.KernelPath)
if err != nil {
cfg.Config.Logger.Errorf("failed relativizing kernel symlink")
return err
}

cfg.Config.Logger.Info("Remove any pre-existing initrd")
Expand Down
20 changes: 15 additions & 5 deletions pkg/features/embedded/grub-config/etc/elemental/grub.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,23 @@ function source_bootargs {
## Defines the volume and image to boot from for active or passive boots
function set_volume {
if [ "${snapshotter}" == "btrfs" ]; then
set volume="${root}"
if [ -n "${1}" ]; then
set img="@/.snapshots/${1}/snapshot"
if [ -d "@/.snapshots/${active_snap}/snapshot" ]; then
set volume="${root}"
if [ -n "${1}" ]; then
set img="@/.snapshots/${1}/snapshot"
else
set img="@/.snapshots/${active_snap}/snapshot"
fi
set root_subpath="${img}/"
else
set img="@/.snapshots/${active_snap}/snapshot"
set btrfs_relative_path="y"
set volume="${root}"
set root_subpath=""
if [ -n "${1}" ]; then
set img="@/.snapshots/${1}/snapshot"
btrfs-mount-subvol ($root) / ${img}
fi
fi
set root_subpath="${img}/"
elif [ -z "${1}" ]; then
set root_subpath=""
set_loopdevice /.snapshots/active
Expand Down
137 changes: 39 additions & 98 deletions pkg/snapshotter/btrfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ type Btrfs struct {
cfg types.Config
snapshotterCfg types.SnapshotterConfig
btrfsCfg types.BtrfsConfig
device string
rootDir string
efiDir string
currentSnapshotID int
Expand Down Expand Up @@ -139,7 +138,6 @@ func (b *Btrfs) InitSnapshotter(state *types.Partition, efiDir string) error {
var ok bool

b.cfg.Logger.Infof("Initiate btrfs snapshotter at %s", state.MountPoint)
b.device = state.Path
b.rootDir = state.MountPoint
b.efiDir = efiDir

Expand Down Expand Up @@ -262,6 +260,7 @@ func (b *Btrfs) CloseTransactionOnError(snapshot *types.Snapshot) (err error) {

func (b *Btrfs) CloseTransaction(snapshot *types.Snapshot) (err error) {
var cmdOut []byte
var subvolID int

if !snapshot.InProgress {
b.cfg.Logger.Debugf("No transaction to close for snapshot %d workdir", snapshot.ID)
Expand Down Expand Up @@ -334,25 +333,15 @@ func (b *Btrfs) CloseTransaction(snapshot *types.Snapshot) (err error) {
return err
}

// locate mounted state directory
stateDir, err := findStatePath(b.cfg.Runner, b.device)
subvolID, err = b.findSubvolumeByPath(fmt.Sprintf(snapshotPathTmpl, snapshot.ID))
if err != nil {
b.cfg.Logger.Errorf("unable to locate state directory: %s", err.Error())
b.cfg.Logger.Error("failed finding subvolume")
return err
}

// Remove old symlink and create a new one
activeSnap := filepath.Join(stateDir, constants.ActiveSnapshot)
linkDst := fmt.Sprintf(snapshotPathTmpl, snapshot.ID)
b.cfg.Logger.Debugf("creating symlink %s to %s", activeSnap, linkDst)
_ = b.cfg.Fs.Remove(activeSnap)
err = b.cfg.Fs.Symlink(linkDst, activeSnap)
cmdOut, err = b.cfg.Runner.Run("btrfs", "subvolume", "set-default", strconv.Itoa(subvolID), snapshot.Path)
if err != nil {
b.cfg.Logger.Errorf("failed default snapshot image for snapshot %d: %v", snapshot.ID, err)
sErr := b.cfg.Fs.Symlink(fmt.Sprintf(snapshotPathTmpl, b.activeSnapshotID), activeSnap)
if sErr != nil {
b.cfg.Logger.Warnf("could not restore previous active link")
}
b.cfg.Logger.Errorf("failed setting read only property to snapshot %d: %s", snapshot.ID, string(cmdOut))
return err
}

Expand Down Expand Up @@ -484,25 +473,19 @@ func (b *Btrfs) getSubvolumes(rootDir string) (btrfsSubvolList, error) {
}

func (b *Btrfs) getActiveSnapshot() (int, error) {
stateDir, err := findStatePath(b.cfg.Runner, b.device)
out, err := b.cfg.Runner.Run("btrfs", "subvolume", "get-default", b.rootDir)
if err != nil {
b.cfg.Logger.Errorf("unable to locate state directory: %s", err.Error())
return 0, err
}

activeSnap := filepath.Join(stateDir, constants.ActiveSnapshot)
activePath, err := b.cfg.Fs.Readlink(activeSnap)
if err != nil {
b.cfg.Logger.Errorf("failed reading active symlink %s: %s", activeSnap, err.Error())
b.cfg.Logger.Errorf("failed listing btrfs subvolumes: %s", err.Error())
return 0, err
}
b.cfg.Logger.Debugf("active snapshot path is %s", activePath)

re := regexp.MustCompile(snapshotPathRegex)
match := re.FindStringSubmatch(activePath)
if match != nil {
id, _ := strconv.Atoi(match[1])
return id, nil
list := b.parseVolumes(strings.TrimSpace(string(out)))
for _, v := range list {
match := re.FindStringSubmatch(v.path)
if match != nil {
id, _ := strconv.Atoi(match[1])
return id, nil
}
}
return 0, nil
}
Expand Down Expand Up @@ -597,6 +580,23 @@ func (b *Btrfs) writeSnapperSnapshotXML(filepath string, snapshot SnapperSnapsho
return nil
}

func (b *Btrfs) findSubvolumeByPath(path string) (int, error) {
subvolumes, err := b.getSubvolumes(b.rootDir)
if err != nil {
b.cfg.Logger.Errorf("failed loading subvolumes: %v", err)
return 0, err
}

for _, subvol := range subvolumes {
if strings.Contains(subvol.path, path) {
return subvol.id, nil
}
}

b.cfg.Logger.Errorf("could not find subvolume with path '%s' in subvolumes list '%v'", path, subvolumes)
return 0, fmt.Errorf("can't find subvolume '%s'", path)
}

func (b *Btrfs) getPassiveSnapshots() ([]int, error) {
passives := []int{}

Expand Down Expand Up @@ -780,7 +780,7 @@ func (b *Btrfs) setBtrfsForFirstTime(state *types.Partition) error {
}

func (b *Btrfs) configureSnapperAndRootDir(state *types.Partition) error {
rootDir, stateMount, err := findSnapperStateAndRootMount(b.cfg.Runner, b.device)
rootDir, stateMount, err := findStateMount(b.cfg.Runner, state.Path)
if err != nil {
b.cfg.Logger.Errorf("failed setting snapper root and state partition mountpoint: %v", err)
return err
Expand All @@ -795,88 +795,29 @@ func (b *Btrfs) configureSnapperAndRootDir(state *types.Partition) error {
return nil
}

func findSnapperStateAndRootMount(runner types.Runner, device string) (rootDir string, stateMount string, err error) {
output, err := runner.Run("findmnt", "-lno", "SOURCE,TARGET,OPTIONS", device)
func findStateMount(runner types.Runner, device string) (rootDir string, stateMount string, err error) {
output, err := runner.Run("findmnt", "-lno", "SOURCE,TARGET", device)
if err != nil {
return "", "", err
}
rsnap := regexp.MustCompile(`@/.snapshots/\d+/snapshot`)
rvol := regexp.MustCompile(`subvol=/([^,]*)`)

var rootMount string
r := regexp.MustCompile(`@/.snapshots/\d+/snapshot`)

scanner := bufio.NewScanner(strings.NewReader(strings.TrimSpace(string(output))))
for scanner.Scan() {
lineFields := strings.Fields(scanner.Text())
if len(lineFields) != 3 {
if len(lineFields) != 2 {
continue
}

if rsnap.MatchString(lineFields[0]) {
if strings.Contains(lineFields[1], constants.RunningStateDir) {
stateMount = lineFields[1]
} else if r.MatchString(lineFields[0]) {
rootDir = lineFields[1]
} else {
volumeMatch := rvol.FindStringSubmatch(lineFields[2])

if len(volumeMatch) > 1 {
subvol := volumeMatch[1]

if subvol == "" {
rootMount = lineFields[1]
} else if subvol == rootSubvol {
stateMount = lineFields[1]
}
}
}
}

if stateMount == "" && rootMount != "" {
stateMount = filepath.Join(rootMount, rootSubvol)
}

if stateMount == "" || rootDir == "" {
err = fmt.Errorf("could not find expected mountpoints, findmnt output: %s", string(output))
}

return rootDir, stateMount, err
}

func findStatePath(runner types.Runner, device string) (statePath string, err error) {
output, err := runner.Run("findmnt", "-lno", "SOURCE,TARGET,OPTIONS", device)
if err != nil {
return "", err
}

rvol := regexp.MustCompile(`subvol=/([^,]*)`)

var rootMount string

scanner := bufio.NewScanner(strings.NewReader(strings.TrimSpace(string(output))))
for scanner.Scan() {
lineFields := strings.Fields(scanner.Text())
if len(lineFields) != 3 {
continue
}

volumeMatch := rvol.FindStringSubmatch(lineFields[2])

if len(volumeMatch) > 1 {
subvol := volumeMatch[1]

if subvol == "" {
rootMount = lineFields[1]
} else if subvol == rootSubvol {
statePath = lineFields[1]
}
}
}

if statePath == "" && rootMount != "" {
statePath = filepath.Join(rootMount, rootSubvol)
}

if statePath == "" {
err = fmt.Errorf("could not find state mountpoint, findmnt output: %s", string(output))
}

return statePath, err
}

0 comments on commit e437f86

Please sign in to comment.