1
0
mirror of https://gitlab.alpinelinux.org/alpine/cloud/tiny-cloud.git synced 2026-06-21 00:07:16 +03:00

add LVM support for root partition

This commit is contained in:
Leonardo Arena 2026-03-17 17:41:34 +01:00
parent b732566c65
commit 9cf6da5147
6 changed files with 117 additions and 8 deletions

View File

@ -49,6 +49,7 @@ IMDS data.
As Tiny Cloud is meant to be tiny, it has few dependencies:
* Busybox (`ash`, `wget`, etc.)
* `e2fsprogs-extra` (for `resize2fs`)
* `lvm2` (for resizing LVM volumes)
* `openssh-server`
* `partx`
* `sfdisk`

View File

@ -20,7 +20,7 @@
* Support for `#network-config`?
* Support LVM partitioning and non-`ext[234]` filesystems?
* Support non-`ext[234]` filesystems?
* Support other cloud providers...
* IBM

View File

@ -51,6 +51,10 @@ Blank lines and shell comments are ignored.
*TINY_CLOUD_LOGS*=<path>
Log directory used by tiny-cloud. The default is _/var/log_.
*TINY_CLOUD_LV_ALLOCATE*=<percentage>
How much space to allocate when expanding the "/" LVM logical volume in
percentage. The default is 85 percent of the volume group's space.
*SKIP_INIT_ACTIONS*=<action> ...
Whitespace-separated list of init actions to skip during phase execution.

View File

@ -45,14 +45,43 @@ init__expand_root() {
*) return;;
esac
if [ -n "$partition" ]; then
# it's a partition, resize it
local volume=$(readlink -f "$SYS/class/block/${dev#/dev/}/..")
volume="/dev/${volume##*/}"
echo ", +" | $MOCK sfdisk -q --no-reread -N "$partition" "$volume"
$MOCK partx -u "$volume"
# check if this is an LVM logical volume
if lvs --noheadings -o lv_name "$dev" >/dev/null 2>&1; then
# LVM volume detected
# find the physical volume backing this LV
local vg_name=$(lvs --noheadings -o vg_name "$dev" 2>/dev/null | tr -d ' ')
local pv_dev=$(pvs --noheadings -o pv_name -S "vg_name=$vg_name" 2>/dev/null | tr -d ' ' | head -n1)
# get the partition number if PV is on a partition
local pv_partition=$(cat "$SYS/class/block/${pv_dev#/dev/}/partition" 2>/dev/null)
# only resize partition if PV is on a partition (not whole disk)
if [ -n "$pv_partition" ]; then
# resize the partition containing the PV
local pv_volume=$(readlink -f "$SYS/class/block/${pv_dev#/dev/}/..")
pv_volume="/dev/${pv_volume##*/}"
echo ", +" | $MOCK sfdisk -q --no-reread -N "$pv_partition" "$pv_volume"
$MOCK partx -u "$pv_volume"
fi
# resize the physical volume (works for both partition and whole disk)
$MOCK pvresize "$pv_dev"
# extend the logical volume
# default leave 15% for snapshots
$MOCK lvextend -l +${TINY_CLOUD_LV_ALLOCATE:-85}%VG "$dev"
else
# standard partition handling (non-LVM)
if [ -n "$partition" ]; then
# it's a partition, resize it
local volume=$(readlink -f "$SYS/class/block/${dev#/dev/}/..")
volume="/dev/${volume##*/}"
echo ", +" | $MOCK sfdisk -q --no-reread -N "$partition" "$volume"
$MOCK partx -u "$volume"
fi
fi
# resize filesystem
# resize filesystem (common for both LVM and non-LVM)
if [ -e "$dev" ] || [ -n "$MOCK" ]; then
$MOCK resize2fs "$dev"
fi

View File

@ -26,6 +26,10 @@
# Location of log directory
#TINY_CLOUD_LOGS=/var/log
# How much space to allocate when expanding the "/" LVM logical volume in percentage
# Default: leave 15% unallocated for snapshots
#TINY_CLOUD_LV_ALLOCATE=85
# Explicitly skip these (whitespace delimited) things during init
# examples: expand_root set_hostname set_ssh_keys save_userdata
# decompress_userdata run_userdata

View File

@ -11,6 +11,8 @@ lib="$srcdir"/lib/tiny-cloud/init
init_tests \
expand_root \
expand_root_partition \
expand_root_lvm_partition \
expand_root_lvm_whole_disk \
ethernets \
find_first_interface_up \
auto_detect_ethernet_interface \
@ -69,6 +71,75 @@ expand_root_partition_body() {
done
}
expand_root_lvm_partition_body() {
# Test LVM on a partition (e.g., /dev/sda2 -> PV -> VG -> LV)
mkdir -p proc sys/class/block \
sys/devices/pci0000:00/0000:00:05.0/virtio2/block/vda/vda2 \
sys/devices/pci0000:00/0000:00:05.0/virtio2/block/vda/device \
dev/mapper
ln -s ../../devices/pci0000:00/0000:00:05.0/virtio2/block/vda sys/class/block/vda
ln -s ../../devices/pci0000:00/0000:00:05.0/virtio2/block/vda/vda2 sys/class/block/vda2
echo 2 > sys/class/block/vda2/partition
# Create fake LVM device
mkdir -p sys/class/block/dm-0
ln -s /dev/mapper/vg0-root dev/mapper/vg0-root
# Mock LVM commands
fake_bin lvs <<-EOF
#!/bin/sh
echo " vg0"
EOF
fake_bin pvs <<-EOF
#!/bin/sh
echo " /dev/vda2"
EOF
echo "/dev/mapper/vg0-root / ext4 rw,noatime 0 0" > proc/mounts
for provider in $PROVIDERS; do
CLOUD="$provider" atf_check \
-o match:"sfdisk .*/dev/vda" \
-o match:"partx .*/dev/vda" \
-o match:"pvresize /dev/vda2" \
-o match:"lvextend -l \\+85%VG /dev/mapper/vg0-root" \
-o match:"resize2fs /dev/mapper/vg0-root" \
sh -c ". $lib; init__expand_root"
done
}
expand_root_lvm_whole_disk_body() {
# Test LVM on whole disk (e.g., /dev/sdb -> PV -> VG -> LV, no partition)
mkdir -p proc sys/class/block \
sys/devices/pci0000:00/0000:00:05.0/virtio3/block/vdb/device \
dev/mapper
ln -s ../../devices/pci0000:00/0000:00:05.0/virtio3/block/vdb sys/class/block/vdb
# Create fake LVM device
mkdir -p sys/class/block/dm-1
ln -s /dev/mapper/vg1-root dev/mapper/vg1-root
# Mock LVM commands - PV is on whole disk (no partition)
fake_bin lvs <<-EOF
#!/bin/sh
echo " vg1"
EOF
fake_bin pvs <<-EOF
#!/bin/sh
echo " /dev/vdb"
EOF
echo "/dev/mapper/vg1-root / ext4 rw,noatime 0 0" > proc/mounts
for provider in $PROVIDERS; do
CLOUD="$provider" atf_check \
-o match:"pvresize /dev/vdb" \
-o match:"lvextend -l \\+85%VG /dev/mapper/vg1-root" \
-o match:"resize2fs /dev/mapper/vg1-root" \
-o not-match:"sfdisk" \
-o not-match:"partx" \
sh -c ". $lib; init__expand_root"
done
}
ethernets_body() {
fake_interfaces lo br0 eth0 eth2 eth11