Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/bin/bash
- set -euo pipefail
- # Configuration - MODIFY THESE VALUES FOR YOUR SETUP
- DISK="/dev/nvme1n1"
- EXT4_PART="${DISK}p1"
- ZFS_PART="${DISK}p2"
- MOUNTPOINT="/mnt/pve/vm-data"
- ZFS_POOL="zfs-vm"
- EXT4_RESIZE="864G"
- PARTITION_END="872GiB"
- # Colors for better output readability (because we're fancy like that)
- RED='\033[0;31m'
- GREEN='\033[0;32m'
- YELLOW='\033[1;33m'
- BLUE='\033[0;34m'
- NC='\033[0m' # No Color
- abort() {
- echo -e "${RED}❌ ERROR: $1${NC}"
- exit 1
- }
- info() {
- echo -e "${BLUE}ℹ️ INFO: $1${NC}"
- }
- warn() {
- echo -e "${YELLOW}⚠️ WARNING: $1${NC}"
- }
- success() {
- echo -e "${GREEN}✅ SUCCESS: $1${NC}"
- }
- check_cmd() {
- "$@" || abort "Command failed: $*"
- }
- check_mount_absent() {
- mountpoint -q "$1" && abort "$1 is still mounted, aborting."
- }
- check_partition_exists() {
- lsblk -no NAME "$1" | grep -q "$(basename "$2")" || abort "Expected partition $2 not found on $1."
- }
- check_partition_absent() {
- lsblk -no NAME "$1" | grep -q "$(basename "$2")" && abort "Partition $2 already exists on $1."
- }
- # Pre-flight checks (because nobody likes surprises)
- info "Starting pre-flight checks..."
- # Check if running as root
- [[ $EUID -eq 0 ]] || abort "This script must be run as root (sudo)"
- # Check if disk exists
- [[ -b "$DISK" ]] || abort "Disk $DISK does not exist or is not a block device"
- # Check if partition 1 exists
- check_partition_exists "$DISK" "$EXT4_PART"
- # Check if partition 2 doesn't exist yet
- check_partition_absent "$DISK" "$ZFS_PART"
- # Verify current filesystem is ext4
- FSTYPE=$(lsblk -no FSTYPE "$EXT4_PART")
- [[ "$FSTYPE" == "ext4" ]] || abort "Partition $EXT4_PART is not ext4 (found: $FSTYPE)"
- # Get disk size and verify it makes sense
- DISK_SIZE=$(lsblk -bno SIZE "$DISK")
- DISK_SIZE_GB=$((DISK_SIZE / 1024 / 1024 / 1024))
- info "Disk size: ${DISK_SIZE_GB}GB"
- # Verify sizes make sense (rough check)
- if [[ $DISK_SIZE_GB -lt 900 ]]; then
- abort "Disk appears too small (${DISK_SIZE_GB}GB) for the configured partition sizes"
- fi
- # Get current filesystem usage
- FS_USAGE=$(df -BG "$MOUNTPOINT" | awk 'NR==2 {print $3}' | sed 's/G//')
- info "Current filesystem usage: ${FS_USAGE}GB"
- # Verify we have enough space for the shrink
- if [[ $FS_USAGE -gt 850 ]]; then
- abort "Filesystem usage (${FS_USAGE}GB) is too high to shrink to 864GB safely"
- fi
- # Get current partition table
- info "Current partition layout:"
- lsblk "$DISK"
- # Final confirmation (because YOLO isn't a backup strategy)
- echo
- warn "This will:"
- warn " 1. Shutdown all VMs"
- warn " 2. Unmount $MOUNTPOINT"
- warn " 3. Shrink ext4 filesystem to 864GB"
- warn " 4. Shrink partition 1 to 872GiB"
- warn " 5. Create new ZFS partition from 872GiB to end of disk"
- warn " 6. Create ZFS pool '$ZFS_POOL'"
- echo
- read -p "Are you absolutely sure you want to continue? (type 'YES' to proceed): " confirm
- if [[ "$confirm" != "YES" ]]; then
- abort "Operation cancelled by user. Smart move! 🧠"
- fi
- # The actual work begins here
- success "Pre-flight checks completed. Starting partition resize..."
- echo
- info "Checking if $EXT4_PART is mounted..."
- check_mount_absent "$MOUNTPOINT"
- info "Stopping all running VMs..."
- VM_COUNT=$(qm list | awk 'NR>1 {print $1}' | wc -l)
- if [[ $VM_COUNT -gt 0 ]]; then
- info "Found $VM_COUNT VMs to shutdown"
- qm list | awk 'NR>1 {print $1}' | xargs -r -n1 qm shutdown
- info "Waiting 30 seconds for VMs to shutdown gracefully..."
- sleep 30
- # Force stop any remaining running VMs
- RUNNING_VMS=$(qm list | awk 'NR>1 && $3=="running" {print $1}')
- if [[ -n "$RUNNING_VMS" ]]; then
- warn "Some VMs are still running, forcing stop..."
- echo "$RUNNING_VMS" | xargs -r -n1 qm stop
- sleep 5
- fi
- else
- info "No running VMs found"
- fi
- info "Unmounting $EXT4_PART from $MOUNTPOINT..."
- check_cmd umount "$MOUNTPOINT"
- info "Verifying ext4 filesystem on $EXT4_PART..."
- check_cmd e2fsck -f "$EXT4_PART"
- info "Shrinking ext4 filesystem to $EXT4_RESIZE..."
- info "This may take several minutes depending on data amount..."
- check_cmd resize2fs "$EXT4_PART" "$EXT4_RESIZE"
- info "Resizing partition 1 to $PARTITION_END..."
- check_cmd parted -s "$DISK" unit GiB resizepart 1 "$PARTITION_END"
- info "Verifying filesystem after partition resize..."
- check_cmd e2fsck -f "$EXT4_PART"
- info "Remounting $EXT4_PART..."
- check_cmd mount "$EXT4_PART" "$MOUNTPOINT"
- info "Creating new ZFS partition after $PARTITION_END..."
- check_cmd parted -s "$DISK" -- mkpart primary "$PARTITION_END" 100%
- info "Waiting for kernel to detect new partition..."
- sleep 5
- partprobe "$DISK"
- udevadm settle
- sleep 2
- check_partition_exists "$DISK" "$ZFS_PART"
- info "Creating ZFS pool: $ZFS_POOL..."
- check_cmd zpool create "$ZFS_POOL" "$ZFS_PART"
- info "Checking ZFS pool status..."
- zpool status "$ZFS_POOL" || abort "ZFS pool creation failed."
- info "Adding ZFS pool to Proxmox storage config..."
- check_cmd pvesm add zfspool "$ZFS_POOL" -pool "$ZFS_POOL"
- # Final status check
- echo
- success "All steps completed successfully! 🎉"
- echo
- info "Final partition layout:"
- lsblk "$DISK"
- echo
- info "ZFS pool status:"
- zpool status "$ZFS_POOL"
- echo
- info "Storage configuration:"
- pvesm status
- success "Your disk surgery was successful! No patients were harmed in the making of this partition. 🏥"
Advertisement
Add Comment
Please, Sign In to add comment