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