Skip to content

Commit 478e60c

Browse files
committed
PE-7936 Add ubuntu and content partition reclaim logic.
1 parent c4e007a commit 478e60c

File tree

4 files changed

+285
-50
lines changed

4 files changed

+285
-50
lines changed

Earthfile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -888,11 +888,13 @@ iso-image:
888888
RUN chmod 644 /etc/logrotate.d/stylus.conf
889889
END
890890

891-
# For MAAS builds, install maas-content.sh script and handle local-ui
891+
# For MAAS builds, install maas-content.sh and maas-extend-persistent.sh scripts and handle local-ui
892892
IF [ "$IS_MAAS" = "true" ]
893893
RUN mkdir -p /opt/spectrocloud/scripts
894894
COPY cloudconfigs/maas-content.sh /opt/spectrocloud/scripts/maas-content.sh
895895
RUN chmod 755 /opt/spectrocloud/scripts/maas-content.sh
896+
COPY cloudconfigs/maas-extend-persistent.sh /opt/spectrocloud/scripts/maas-extend-persistent.sh
897+
RUN chmod 755 /opt/spectrocloud/scripts/maas-extend-persistent.sh
896898

897899
# Add local-ui if provided (extract it directly to the image)
898900
COPY --if-exists local-ui.tar /opt/spectrocloud/

cloudconfigs/80_stylus_maas.yaml

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,22 @@ stages:
99
if [ -n "$UBUNTU_PARTITION" ]; then
1010
echo "Found Ubuntu rootfs partition: $UBUNTU_PARTITION"
1111
# Get the partition number
12-
# Handle both standard (/dev/sda5) and NVMe (/dev/nvme0n1p5) formats
12+
# Handle various disk device types:
13+
# - NVMe: /dev/nvme0n1p5
14+
# - Virtio (KVM/QEMU/LXD): /dev/vda5
15+
# - Xen: /dev/xvda5
16+
# - SCSI/SATA (physical or VM): /dev/sda5
1317
if [[ "$UBUNTU_PARTITION" =~ ^/dev/nvme[0-9]+n[0-9]+p[0-9]+$ ]]; then
1418
# NVMe format: /dev/nvme0n1p5
1519
UBUNTU_PART_NUM=$(echo "$UBUNTU_PARTITION" | grep -oE '[0-9]+$')
1620
DISK_DEV=$(echo "$UBUNTU_PARTITION" | sed 's/p[0-9]*$//')
17-
else
18-
# Standard format: /dev/sda5
21+
elif [[ "$UBUNTU_PARTITION" =~ ^/dev/vd[a-z][0-9]+$ ]] || [[ "$UBUNTU_PARTITION" =~ ^/dev/xvd[a-z][0-9]+$ ]] || [[ "$UBUNTU_PARTITION" =~ ^/dev/[a-z]+[0-9]+$ ]]; then
22+
# Virtio, Xen, or standard format: /dev/vda5, /dev/xvda5, /dev/sda5
1923
UBUNTU_PART_NUM=$(echo "$UBUNTU_PARTITION" | grep -oE '[0-9]+$')
2024
DISK_DEV=$(echo "$UBUNTU_PARTITION" | sed 's/[0-9]*$//')
25+
else
26+
echo "Error: Unknown disk device format: $UBUNTU_PARTITION"
27+
exit 1
2128
fi
2229
2330
echo "Wiping filesystem signatures from Ubuntu partition: $UBUNTU_PARTITION"
@@ -29,14 +36,27 @@ stages:
2936
fi
3037
3138
echo "Removing Ubuntu partition $UBUNTU_PART_NUM from $DISK_DEV"
32-
# Remove the Ubuntu partition - Kairos will handle the remaining space allocation
33-
parted -s "$DISK_DEV" rm "$UBUNTU_PART_NUM" || echo "Failed to remove partition $UBUNTU_PART_NUM"
34-
echo "Ubuntu rootfs partition removed - Kairos will create state and persistent partitions with remaining space"
39+
# Get the Ubuntu partition size before removal (for logging)
40+
UBUNTU_PART_INFO=$(parted -s "$DISK_DEV" unit MiB print | grep "^[[:space:]]*${UBUNTU_PART_NUM}[[:space:]]" || true)
41+
if [ -n "$UBUNTU_PART_INFO" ]; then
42+
UBUNTU_PART_START=$(echo "$UBUNTU_PART_INFO" | awk '{print $2}' | sed 's/MiB//')
43+
UBUNTU_PART_END=$(echo "$UBUNTU_PART_INFO" | awk '{print $3}' | sed 's/MiB//')
44+
echo "Ubuntu partition: ${UBUNTU_PART_START}MiB to ${UBUNTU_PART_END}MiB"
45+
fi
46+
47+
# Remove the Ubuntu partition
48+
# Note: Partition extension will be handled by maas-extend-persistent.sh after content extraction
49+
parted -s "$DISK_DEV" rm "$UBUNTU_PART_NUM" || { echo "Failed to remove partition $UBUNTU_PART_NUM"; exit 1; }
50+
echo "Ubuntu rootfs partition removed (will be extended to persistent partition after content extraction)"
3551
else
3652
echo "No Ubuntu rootfs partition found with label UBUNTU_ROOTFS"
3753
fi
3854
network:
3955
- if: '[ -f "/run/cos/active_mode" ]'
4056
name: "extract content from content partition"
4157
commands:
42-
- bash /opt/spectrocloud/scripts/maas-content.sh
58+
- bash /opt/spectrocloud/scripts/maas-content.sh
59+
- if: '[ -f "/run/cos/active_mode" ]'
60+
name: "extend persistent partition and reclaim space"
61+
commands:
62+
- bash /opt/spectrocloud/scripts/maas-extend-persistent.sh

cloudconfigs/maas-content.sh

Lines changed: 1 addition & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -187,49 +187,8 @@ umount "$CONTENT_MOUNT" || {
187187
rmdir "$CONTENT_MOUNT" || true
188188
log "Successfully unmounted content partition"
189189

190-
# Delete the content partition after successful extraction
191-
log "Deleting content partition: $CONTENT_PARTITION"
192-
# Get the disk device and partition number
193-
# For /dev/sda5 -> DISK_DEVICE=/dev/sda, PARTITION_NUM=5
194-
# For /dev/nvme0n1p5 -> DISK_DEVICE=/dev/nvme0n1, PARTITION_NUM=5
195-
# Extract partition number (last sequence of digits)
196-
PARTITION_NUM=$(echo "$CONTENT_PARTITION" | grep -oE '[0-9]+$')
197-
# Extract disk device by removing the partition number
198-
if [[ "$CONTENT_PARTITION" =~ ^(/dev/nvme[0-9]+n[0-9]+)p[0-9]+$ ]]; then
199-
# NVMe format: /dev/nvme0n1p5
200-
DISK_DEVICE=$(echo "$CONTENT_PARTITION" | sed 's/p[0-9]*$//')
201-
else
202-
# Standard format: /dev/sda5
203-
DISK_DEVICE=$(echo "$CONTENT_PARTITION" | sed 's/[0-9]*$//')
204-
fi
205-
206-
if [ -n "$DISK_DEVICE" ] && [ -n "$PARTITION_NUM" ]; then
207-
log "Disk device: $DISK_DEVICE, Partition number: $PARTITION_NUM"
208-
209-
# Wipe filesystem signatures from the partition
210-
if command -v wipefs >/dev/null 2>&1; then
211-
log "Wiping filesystem signatures from partition"
212-
wipefs -a "$CONTENT_PARTITION" 2>>"$LOG_FILE" || {
213-
log_error "Failed to wipe filesystem signatures"
214-
}
215-
fi
216-
217-
# Delete the partition from the partition table using parted
218-
if command -v parted >/dev/null 2>&1; then
219-
log "Deleting partition $PARTITION_NUM from $DISK_DEVICE"
220-
if parted -s "$DISK_DEVICE" rm "$PARTITION_NUM" 2>>"$LOG_FILE"; then
221-
log "Successfully deleted partition $PARTITION_NUM from partition table"
222-
else
223-
log_error "Failed to delete partition from partition table (this may be expected if partition is in use)"
224-
fi
225-
else
226-
log "parted command not found, skipping partition table deletion"
227-
fi
228-
else
229-
log_error "Could not determine disk device or partition number from $CONTENT_PARTITION"
230-
fi
231-
232190
log "Content extraction completed successfully"
191+
log "Note: Content partition deletion and persistent partition extension will be handled by maas-extend-persistent.sh"
233192
log "Content files in $CONTENT_DEST:"
234193
ls -lh "$CONTENT_DEST" >> "$LOG_FILE" 2>&1 || true
235194

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
4+
# Script to extend the persistent partition by reclaiming space from:
5+
# 1. Ubuntu rootfs partition (UBUNTU_ROOTFS) - removed during boot
6+
# 2. Content partition (COS_CONTENT) - removed after content extraction
7+
#
8+
# This script should be run after content extraction is complete
9+
10+
# Log file path
11+
LOG_FILE="/var/log/stylus-maas-extend-persistent.log"
12+
13+
# Function to log messages to both stdout and log file
14+
log() {
15+
local message="[$(date '+%Y-%m-%d %H:%M:%S')] $*"
16+
echo "$message"
17+
echo "$message" >> "$LOG_FILE" 2>&1 || true
18+
}
19+
20+
# Function to log errors
21+
log_error() {
22+
local message="[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: $*"
23+
echo "$message" >&2
24+
echo "$message" >> "$LOG_FILE" 2>&1 || true
25+
}
26+
27+
# Create log file directory if it doesn't exist
28+
mkdir -p "$(dirname "$LOG_FILE")" || true
29+
30+
log "Starting persistent partition extension script"
31+
32+
# Find the persistent partition
33+
PERSISTENT_PARTITION=$(blkid -L COS_PERSISTENT 2>/dev/null || true)
34+
if [ -z "$PERSISTENT_PARTITION" ]; then
35+
log_error "Persistent partition (COS_PERSISTENT) not found, cannot extend"
36+
exit 1
37+
fi
38+
39+
log "Found persistent partition: $PERSISTENT_PARTITION"
40+
41+
# Get partition number and disk device for persistent partition
42+
# Handle various disk device types:
43+
# - NVMe: /dev/nvme0n1p5
44+
# - Virtio (KVM/QEMU/LXD): /dev/vda5
45+
# - Xen: /dev/xvda5
46+
# - SCSI/SATA (physical or VM): /dev/sda5
47+
if [[ "$PERSISTENT_PARTITION" =~ ^/dev/nvme[0-9]+n[0-9]+p[0-9]+$ ]]; then
48+
# NVMe format: /dev/nvme0n1p5
49+
PERSISTENT_PART_NUM=$(echo "$PERSISTENT_PARTITION" | grep -oE '[0-9]+$')
50+
DISK_DEV=$(echo "$PERSISTENT_PARTITION" | sed 's/p[0-9]*$//')
51+
DISK_TYPE="NVMe"
52+
elif [[ "$PERSISTENT_PARTITION" =~ ^/dev/vd[a-z][0-9]+$ ]]; then
53+
# Virtio format: /dev/vda5
54+
PERSISTENT_PART_NUM=$(echo "$PERSISTENT_PARTITION" | grep -oE '[0-9]+$')
55+
DISK_DEV=$(echo "$PERSISTENT_PARTITION" | sed 's/[0-9]*$//')
56+
DISK_TYPE="Virtio (KVM/QEMU/LXD)"
57+
elif [[ "$PERSISTENT_PARTITION" =~ ^/dev/xvd[a-z][0-9]+$ ]]; then
58+
# Xen format: /dev/xvda5
59+
PERSISTENT_PART_NUM=$(echo "$PERSISTENT_PARTITION" | grep -oE '[0-9]+$')
60+
DISK_DEV=$(echo "$PERSISTENT_PARTITION" | sed 's/[0-9]*$//')
61+
DISK_TYPE="Xen"
62+
elif [[ "$PERSISTENT_PARTITION" =~ ^/dev/[a-z]+[0-9]+$ ]]; then
63+
# Standard format: /dev/sda5, /dev/hda5, etc.
64+
PERSISTENT_PART_NUM=$(echo "$PERSISTENT_PARTITION" | grep -oE '[0-9]+$')
65+
DISK_DEV=$(echo "$PERSISTENT_PARTITION" | sed 's/[0-9]*$//')
66+
DISK_TYPE="SCSI/SATA"
67+
else
68+
log_error "Unknown disk device format: $PERSISTENT_PARTITION"
69+
exit 1
70+
fi
71+
72+
log "Disk type: $DISK_TYPE"
73+
log "Disk device: $DISK_DEV, Persistent partition number: $PERSISTENT_PART_NUM"
74+
75+
# Get current partition info
76+
PERSISTENT_PART_INFO=$(parted -s "$DISK_DEV" unit MiB print | grep "^[[:space:]]*${PERSISTENT_PART_NUM}[[:space:]]" || true)
77+
if [ -z "$PERSISTENT_PART_INFO" ]; then
78+
log_error "Could not get persistent partition information"
79+
exit 1
80+
fi
81+
82+
PERSISTENT_PART_START=$(echo "$PERSISTENT_PART_INFO" | awk '{print $2}' | sed 's/MiB//')
83+
PERSISTENT_PART_END=$(echo "$PERSISTENT_PART_INFO" | awk '{print $3}' | sed 's/MiB//')
84+
log "Current persistent partition: ${PERSISTENT_PART_START}MiB to ${PERSISTENT_PART_END}MiB"
85+
86+
# Get disk size
87+
DISK_SIZE=$(parted -s "$DISK_DEV" unit MiB print | grep "^Disk /" | awk '{print $3}' | sed 's/MiB//')
88+
log "Disk size: ${DISK_SIZE}MiB"
89+
90+
# Check for partitions that should be removed (if they still exist)
91+
PARTITIONS_TO_REMOVE=()
92+
93+
# Check for Ubuntu rootfs partition
94+
UBUNTU_PARTITION=$(blkid -L UBUNTU_ROOTFS 2>/dev/null || true)
95+
if [ -n "$UBUNTU_PARTITION" ]; then
96+
log "Found Ubuntu rootfs partition that should be removed: $UBUNTU_PARTITION"
97+
PARTITIONS_TO_REMOVE+=("$UBUNTU_PARTITION")
98+
fi
99+
100+
# Check for content partition
101+
CONTENT_PARTITION=$(blkid -L COS_CONTENT 2>/dev/null || true)
102+
if [ -n "$CONTENT_PARTITION" ]; then
103+
log "Found content partition that should be removed: $CONTENT_PARTITION"
104+
PARTITIONS_TO_REMOVE+=("$CONTENT_PARTITION")
105+
fi
106+
107+
# Remove partitions if they still exist
108+
for PARTITION in "${PARTITIONS_TO_REMOVE[@]}"; do
109+
log "Processing partition for removal: $PARTITION"
110+
111+
# Get partition number (same logic as persistent partition)
112+
if [[ "$PARTITION" =~ ^/dev/nvme[0-9]+n[0-9]+p[0-9]+$ ]]; then
113+
# NVMe format
114+
PART_NUM=$(echo "$PARTITION" | grep -oE '[0-9]+$')
115+
elif [[ "$PARTITION" =~ ^/dev/vd[a-z][0-9]+$ ]] || [[ "$PARTITION" =~ ^/dev/xvd[a-z][0-9]+$ ]] || [[ "$PARTITION" =~ ^/dev/[a-z]+[0-9]+$ ]]; then
116+
# Virtio, Xen, or standard format
117+
PART_NUM=$(echo "$PARTITION" | grep -oE '[0-9]+$')
118+
else
119+
log_error "Unknown partition format: $PARTITION"
120+
continue
121+
fi
122+
123+
log "Partition number: $PART_NUM"
124+
125+
# Wipe filesystem signatures
126+
if command -v wipefs >/dev/null 2>&1; then
127+
log "Wiping filesystem signatures from $PARTITION"
128+
wipefs -a "$PARTITION" 2>>"$LOG_FILE" || log "Warning: Failed to wipe filesystem signatures"
129+
fi
130+
131+
# Remove partition from partition table
132+
log "Removing partition $PART_NUM from $DISK_DEV"
133+
if parted -s "$DISK_DEV" rm "$PART_NUM" 2>>"$LOG_FILE"; then
134+
log "Successfully removed partition $PART_NUM"
135+
else
136+
log "Warning: Failed to remove partition $PART_NUM (may already be removed or in use)"
137+
fi
138+
done
139+
140+
# Force re-read of partition table after removals
141+
if [ ${#PARTITIONS_TO_REMOVE[@]} -gt 0 ]; then
142+
log "Re-reading partition table after partition removals"
143+
partprobe "$DISK_DEV" 2>/dev/null || true
144+
sleep 2
145+
146+
# Re-read persistent partition info after removals
147+
PERSISTENT_PART_INFO=$(parted -s "$DISK_DEV" unit MiB print | grep "^[[:space:]]*${PERSISTENT_PART_NUM}[[:space:]]" || true)
148+
if [ -n "$PERSISTENT_PART_INFO" ]; then
149+
PERSISTENT_PART_END=$(echo "$PERSISTENT_PART_INFO" | awk '{print $3}' | sed 's/MiB//')
150+
log "Persistent partition end after removals: ${PERSISTENT_PART_END}MiB"
151+
fi
152+
fi
153+
154+
# Find the next partition after persistent (if any)
155+
NEXT_PART_NUM=$(parted -s "$DISK_DEV" unit MiB print | awk -v pnum="$PERSISTENT_PART_NUM" '/^[[:space:]]*[0-9]+[[:space:]]/ {if ($1 > pnum && $1 != pnum) {print $1; exit}}')
156+
157+
if [ -n "$NEXT_PART_NUM" ]; then
158+
# There's a partition after persistent, extend to just before it
159+
NEXT_PART_INFO=$(parted -s "$DISK_DEV" unit MiB print | grep "^[[:space:]]*${NEXT_PART_NUM}[[:space:]]" || true)
160+
if [ -n "$NEXT_PART_INFO" ]; then
161+
NEXT_PART_START=$(echo "$NEXT_PART_INFO" | awk '{print $2}' | sed 's/MiB//')
162+
NEW_PERSISTENT_END=$NEXT_PART_START
163+
log "Next partition starts at ${NEXT_PART_START}MiB, extending persistent to ${NEW_PERSISTENT_END}MiB"
164+
else
165+
# Fallback: extend to end of disk
166+
NEW_PERSISTENT_END=$DISK_SIZE
167+
log "Could not determine next partition, extending persistent to end of disk: ${NEW_PERSISTENT_END}MiB"
168+
fi
169+
else
170+
# No partition after persistent, extend to end of disk
171+
NEW_PERSISTENT_END=$DISK_SIZE
172+
log "No partition after persistent, extending to end of disk: ${NEW_PERSISTENT_END}MiB"
173+
fi
174+
175+
# Check if we actually need to extend
176+
if [ "$PERSISTENT_PART_END" -ge "$NEW_PERSISTENT_END" ]; then
177+
log "Persistent partition is already at maximum size (${PERSISTENT_PART_END}MiB >= ${NEW_PERSISTENT_END}MiB), no extension needed"
178+
exit 0
179+
fi
180+
181+
# Check if partition is mounted
182+
MOUNT_POINT=$(mount | grep "$PERSISTENT_PARTITION" | awk '{print $3}' | head -n1 || true)
183+
IS_MOUNTED=false
184+
if [ -n "$MOUNT_POINT" ]; then
185+
IS_MOUNTED=true
186+
log "Persistent partition is mounted at: $MOUNT_POINT"
187+
else
188+
log "Persistent partition is not mounted"
189+
fi
190+
191+
# Resize the partition (this works even if mounted - it just updates the partition table)
192+
log "Resizing persistent partition from ${PERSISTENT_PART_END}MiB to ${NEW_PERSISTENT_END}MiB"
193+
if ! parted -s "$DISK_DEV" unit MiB resizepart "$PERSISTENT_PART_NUM" "$NEW_PERSISTENT_END" 2>>"$LOG_FILE"; then
194+
log_error "Failed to resize persistent partition"
195+
exit 1
196+
fi
197+
198+
# Resize the filesystem
199+
log "Resizing filesystem on $PERSISTENT_PARTITION"
200+
# Force a re-read of the partition table
201+
partprobe "$DISK_DEV" 2>/dev/null || true
202+
sleep 2
203+
204+
# Check filesystem type and resize accordingly
205+
FS_TYPE=$(blkid -o value -s TYPE "$PERSISTENT_PARTITION" 2>/dev/null || echo "")
206+
if [ "$FS_TYPE" = "ext4" ] || [ "$FS_TYPE" = "ext2" ] || [ "$FS_TYPE" = "ext3" ]; then
207+
# Resize ext2/3/4 filesystem
208+
if [ "$IS_MOUNTED" = "true" ]; then
209+
# Online resize for mounted ext4 filesystems (ext4 supports online grow)
210+
log "Performing online resize of mounted ext4 filesystem"
211+
if ! resize2fs "$PERSISTENT_PARTITION" 2>>"$LOG_FILE"; then
212+
log_error "Failed to resize mounted filesystem"
213+
exit 1
214+
fi
215+
else
216+
# Offline resize - can run e2fsck first for safety
217+
log "Performing offline resize of unmounted ext4 filesystem"
218+
e2fsck -f -y "$PERSISTENT_PARTITION" 2>>"$LOG_FILE" || log "Warning: e2fsck had issues, continuing anyway"
219+
if ! resize2fs "$PERSISTENT_PARTITION" 2>>"$LOG_FILE"; then
220+
log_error "Failed to resize filesystem"
221+
exit 1
222+
fi
223+
fi
224+
log "✅ Persistent partition extended successfully"
225+
elif [ "$FS_TYPE" = "xfs" ]; then
226+
# Resize XFS filesystem (xfs_growfs supports online resize)
227+
if [ "$IS_MOUNTED" = "true" ]; then
228+
# xfs_growfs works on mounted filesystems, but needs the mount point
229+
log "Performing online resize of mounted XFS filesystem"
230+
if ! xfs_growfs "$MOUNT_POINT" 2>>"$LOG_FILE"; then
231+
log_error "Failed to resize mounted XFS filesystem"
232+
exit 1
233+
fi
234+
else
235+
log "Performing offline resize of unmounted XFS filesystem"
236+
if ! xfs_growfs "$PERSISTENT_PARTITION" 2>>"$LOG_FILE"; then
237+
log_error "Failed to resize XFS filesystem"
238+
exit 1
239+
fi
240+
fi
241+
log "✅ Persistent partition extended successfully"
242+
else
243+
log_error "Unknown filesystem type '$FS_TYPE', skipping filesystem resize"
244+
log "Partition was resized, but filesystem resize may be needed manually"
245+
exit 1
246+
fi
247+
248+
# Verify the new size
249+
NEW_SIZE=$(df -h "$PERSISTENT_PARTITION" 2>/dev/null | tail -1 | awk '{print $2}' || echo "unknown")
250+
log "Persistent partition new size: $NEW_SIZE"
251+
252+
log "Persistent partition extension completed successfully"
253+
exit 0
254+

0 commit comments

Comments
 (0)