Skip to content

Commit

Permalink
Make RAW disks recovery partition expandable (#2159)
Browse files Browse the repository at this point in the history
Signed-off-by: David Cassany <[email protected]>
  • Loading branch information
davidcassany authored Aug 8, 2024
1 parent 44b2e7b commit b1cc863
Show file tree
Hide file tree
Showing 10 changed files with 75 additions and 23 deletions.
24 changes: 22 additions & 2 deletions pkg/action/build-disk.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const (
GB = 1024 * MB
rootSuffix = ".root"
layoutSetStage = "rootfs.before"
expandStage = "pre-rootfs.before"
deployStage = "network"
postResetHook = "post-reset"
cloudinitFile = "00_disk_layout_setup.yaml"
Expand Down Expand Up @@ -353,6 +354,9 @@ func (b *BuildDiskAction) CreatePartitionImages() ([]*types.Image, error) {
for _, part := range []*types.Partition{b.spec.Partitions.OEM, b.spec.Partitions.Recovery} {
b.cfg.Logger.Infof("Creating %s partition image", part.Name)
img = part.ToImage()
if part.Name == constants.RecoveryPartName && b.spec.Expandable {
img.Size = 0
}
err = elemental.CreateImageFromTree(
b.cfg.Config, img, b.roots[part.Name], b.spec.Expandable,
func() error { return b.cfg.Fs.RemoveAll(b.roots[part.Name]) },
Expand Down Expand Up @@ -674,7 +678,11 @@ func (b *BuildDiskAction) CreateDiskPartitionTable(disk string) error {
// reuse startS and SizeS from previous partition
startS = startS + sizeS
}
sizeS = partitioner.MiBToSectors(part.Size, secSize)
if part.Name == constants.RecoveryPartName && b.spec.Expandable {
sizeS = 0
} else {
sizeS = partitioner.MiBToSectors(part.Size, secSize)
}
var gdPart = partitioner.Partition{
Number: i + 1,
StartS: startS,
Expand Down Expand Up @@ -769,7 +777,19 @@ func (b *BuildDiskAction) SetExpandableCloudInitStage() error {
conf := &schema.YipConfig{
Name: "Expand disk layout",
Stages: map[string][]schema.Stage{
layoutSetStage: {
expandStage: {
schema.Stage{
Name: "Expand recovery",
Layout: schema.Layout{
Device: &schema.Device{
Label: b.spec.Partitions.Recovery.FilesystemLabel,
},
Expand: &schema.Expand{
Size: b.spec.Partitions.Recovery.Size,
},
},
},
}, layoutSetStage: {
schema.Stage{
Name: "Add state partition",
Layout: schema.Layout{
Expand Down
4 changes: 2 additions & 2 deletions pkg/action/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ var _ = Describe("Build Actions", func() {
{"losetup", "--show", "-f", "/tmp/test/build/recovery.part"},
{"mkfs.ext4", "-L", "COS_PERSISTENT"},
{"losetup", "--show", "-f", "/tmp/test/build/persistent.part"},
{"sgdisk", "-p", "/tmp/test/elemental.raw"},
{"sgdisk", "-p", "-v", "/tmp/test/elemental.raw"},
{"partx", "-u", "/tmp/test/elemental.raw"},
})).To(Succeed())
})
Expand All @@ -259,7 +259,7 @@ var _ = Describe("Build Actions", func() {
{"mkfs.vfat", "-n", "COS_GRUB"},
{"mkfs.ext4", "-L", "COS_OEM"},
{"mkfs.ext4", "-L", "COS_RECOVERY"},
{"sgdisk", "-p", "/tmp/test/elemental.raw"},
{"sgdisk", "-p", "-v", "/tmp/test/elemental.raw"},
{"partx", "-u", "/tmp/test/elemental.raw"},
})).To(Succeed())
})
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[Unit]
Description=Elemental system pre-rootfs setup
DefaultDependencies=no
After=basic.target
Requires=basic.target
Before=initrd-root-device.target
After=oem.mount
Wants=oem.mount
Conflicts=initrd-switch-root.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/elemental run-stage pre-rootfs

[Install]
WantedBy=initrd-root-device.target
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ Description=Elemental system early rootfs setup
DefaultDependencies=no
After=sysroot.mount
Requires=sysroot.mount
After=oem.mount
Wants=oem.mount
Before=initrd-root-fs.target
Conflicts=initrd-switch-root.target

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ install() {
inst_script "${moddir}/oem-generator.sh" \
"${systemdutildir}/system-generators/dracut-elemental-oem-generator"

inst_simple "/etc/systemd/system/elemental-setup-pre-rootfs.service" \
"${systemdsystemunitdir}/elemental-setup-pre-rootfs.service"
mkdir -p "${initdir}/${systemdsystemunitdir}/initrd-root-device.target.wants"
ln_r "../elemental-setup-pre-rootfs.service" \
"${systemdsystemunitdir}/initrd-root-device.target.wants/elemental-setup-pre-rootfs.service"

inst_simple "/etc/systemd/system/elemental-setup-rootfs.service" \
"${systemdsystemunitdir}/elemental-setup-rootfs.service"
mkdir -p "${initdir}/${systemdsystemunitdir}/initrd-root-fs.target.wants"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,8 @@ if [ -n "${oem_label}" ]; then
{
echo "[Unit]"
echo "DefaultDependencies=no"
echo "Before=elemental-setup-rootfs.service"
echo "After=dracut-initqueue.service"
echo "Wants=dracut-initqueue.service"
echo "After=basic.target"
echo "Wants=basic.target"
echo "PartOf=initrd.target"
echo "[Mount]"
echo "Where=/oem"
Expand All @@ -34,12 +33,12 @@ if [ -n "${oem_label}" ]; then
mkdir -p "$GENERATOR_DIR/$dev.device.d"
{
echo "[Unit]"
echo "Before=initrd-root-fs.target"
echo "Before=initrd-root-device.target"
echo "JobRunningTimeoutSec=${oem_timeout}"
} > "$GENERATOR_DIR/$dev.device.d/timeout.conf"

mkdir -p "$GENERATOR_DIR"/initrd-root-fs.target.wants
mkdir -p "$GENERATOR_DIR"/initrd-root-device.target.wants
ln -s "$GENERATOR_DIR"/"$dev".device \
"$GENERATOR_DIR"/initrd-root-fs.target.wants/"$dev".device
"$GENERATOR_DIR"/initrd-root-device.target.wants/"$dev".device
fi

Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ if [ "${snapshotter}" == "btrfs" ]; then
echo "[Unit]"
echo "Before=initrd-root-fs.target"
echo "DefaultDependencies=no"
echo "After=dracut-initqueue.service"
echo "Wants=dracut-initqueue.service"
echo "After=initrd-root-device.target"
echo "Wants=initrd-root-device.target"
echo "[Mount]"
echo "Where=/sysroot"
echo "What=${root}"
Expand Down Expand Up @@ -112,8 +112,8 @@ else
echo "[Unit]"
echo "Before=initrd-root-fs.target"
echo "DefaultDependencies=no"
echo "After=dracut-initqueue.service"
echo "Wants=dracut-initqueue.service"
echo "After=initrd-root-device.target"
echo "Wants=initrd-root-device.target"
echo "[Mount]"
echo "Where=${root_part_mnt}"
echo "What=${root}"
Expand Down
5 changes: 3 additions & 2 deletions pkg/partitioner/disk.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,11 @@ import (
const (
partitionTries = 10
// Parted warning substring for expanded disks without fixing GPT headers
partedWarn = "Not all of the space available"
partedWarn = "Not all of the space available"
sgdiskProblem = "Problem: The secondary header"
)

var unallocatedRegexp = regexp.MustCompile(partedWarn)
var unallocatedRegexp = regexp.MustCompile(fmt.Sprintf("(%s|%s)", partedWarn, sgdiskProblem))

type Disk struct {
device string
Expand Down
13 changes: 12 additions & 1 deletion pkg/partitioner/partitioner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ var _ = Describe("Partitioner", Label("disk", "partition", "partitioner"), func(
Expect(runner.CmdsMatch(cmds)).To(BeNil())
})
It("Prints partition table info", func() {
cmd := []string{"sgdisk", "-p", "/dev/device"}
cmd := []string{"sgdisk", "-p", "-v", "/dev/device"}
_, err := gc.Print()
Expect(err).To(BeNil())
Expect(runner.CmdsMatch([][]string{cmd})).To(BeNil())
Expand Down Expand Up @@ -408,13 +408,24 @@ var _ = Describe("Partitioner", Label("disk", "partition", "partitioner"), func(
Expect(dev.GetLabel()).To(Equal("msdos"))
})
It("It fixes GPT headers if the disk was expanded", func() {
// for parted regex
runner.ReturnValue = []byte("Warning: Not all of the space available to /dev/loop0...\n" + partedPrint)
Expect(dev.Reload()).To(BeNil())
Expect(runner.MatchMilestones([][]string{
{"parted", "--script", "--machine", "--", "/dev/device", "unit", "s", "print"},
{"sgdisk", "-e", "/dev/device"},
{"parted", "--script", "--machine", "--", "/dev/device", "unit", "s", "print"},
})).To(BeNil())
// for sgdisk regex
dev = part.NewDisk("/dev/device", part.WithRunner(runner), part.WithFS(fs), part.WithMounter(mounter), part.WithGdisk())
runner.ReturnValue = []byte(sgdiskPrint + "\nProblem: The secondary header's self-pointer indicates that...\n")
runner.ClearCmds()
Expect(dev.Reload()).To(BeNil())
Expect(runner.MatchMilestones([][]string{
{"sgdisk", "-p", "-v", "/dev/device"},
{"sgdisk", "-e", "/dev/device"},
{"sgdisk", "-p", "-v", "/dev/device"},
})).To(BeNil())
})
})
Describe("Modify disk", func() {
Expand Down
8 changes: 4 additions & 4 deletions pkg/partitioner/sgdisk.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func (gd *gdiskCall) WriteChanges() (string, error) {

func (gd *gdiskCall) SetPartitionTableLabel(label string) error {
if label != "gpt" {
return fmt.Errorf("Invalid partition table type (%s), only GPT is supported by sgdisk", label)
return fmt.Errorf("invalid partition table type (%s), only GPT is supported by sgdisk", label)
}
return nil
}
Expand All @@ -147,7 +147,7 @@ func (gd *gdiskCall) WipeTable(wipe bool) {
}

func (gd gdiskCall) Print() (string, error) {
out, err := gd.runner.Run("sgdisk", "-p", gd.dev)
out, err := gd.runner.Run("sgdisk", "-p", "-v", gd.dev)
return string(out), err
}

Expand All @@ -159,7 +159,7 @@ func (gd gdiskCall) GetLastSector(printOut string) (uint, error) {
endS, err := strconv.ParseUint(match[1], 10, 0)
return uint(endS), err
}
return 0, errors.New("Could not determine last usable sector")
return 0, errors.New("could not determine last usable sector")
}

// Parses the output of a gdiskCall.Print call
Expand All @@ -170,7 +170,7 @@ func (gd gdiskCall) GetSectorSize(printOut string) (uint, error) {
size, err := strconv.ParseUint(match[1], 10, 0)
return uint(size), err
}
return 0, errors.New("Could not determine sector size")
return 0, errors.New("could not determine sector size")
}

// TODO parse printOut from a non gpt disk and return error here
Expand Down

0 comments on commit b1cc863

Please sign in to comment.