#!/usr/bin/env bash # Enable LVM Thin Storage on pve for migrations # Creates volume group and thin pool from available disk set -euo pipefail # Load IP configuration SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true # Configuration PROXMOX_HOST_PVE="${PROXMOX_HOST_R630_01}" PVE_PASS="password" STORAGE_NAME="thin1" VG_NAME="pve" # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' log_info() { echo -e "${BLUE}[INFO]${NC} $1"; } log_success() { echo -e "${GREEN}[✓]${NC} $1"; } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } log_error() { echo -e "${RED}[ERROR]${NC} $1"; } log_header() { echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"; } # SSH helper ssh_pve() { sshpass -p "$PVE_PASS" ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=accept-new root@"$PROXMOX_HOST_PVE" "$@" 2>&1 } # Find available disk find_available_disk() { # Check unpartitioned disks (sdc-sdh) for disk in sdc sdd sde sdf sdg sdh; do # Check if disk exists if ! ssh_pve "test -b /dev/$disk" 2>/dev/null; then continue fi # Check if already a PV if ssh_pve "pvdisplay /dev/$disk 2>/dev/null | grep -q 'PV Name'"; then continue fi # Check if has partitions local has_partitions=$(ssh_pve "lsblk /dev/$disk 2>/dev/null | grep -q 'part' && echo 'yes' || echo 'no'") if [ "$has_partitions" == "yes" ]; then continue fi echo "/dev/$disk" return 0 done return 1 } # Create physical volume create_physical_volume() { local disk=$1 log_info "Creating physical volume on $disk..." # Check if already a PV if ssh_pve "pvdisplay $disk 2>/dev/null | grep -q 'PV Name'"; then log_warn "$disk is already a physical volume" return 0 fi # Wipe disk first (remove any existing signatures) log_info "Wiping disk $disk..." ssh_pve "wipefs -a $disk 2>/dev/null" || true # Create PV (force if needed) if ssh_pve "pvcreate -f $disk 2>&1"; then log_success "Physical volume created on $disk" return 0 else log_error "Failed to create physical volume" return 1 fi } # Create volume group create_volume_group() { local vg_name=$1 local disk=$2 log_info "Creating volume group '$vg_name'..." # Check if VG already exists if ssh_pve "vgs $vg_name 2>/dev/null | grep -q $vg_name"; then log_warn "Volume group '$vg_name' already exists" # Check if we can extend it if ssh_pve "vgextend $vg_name $disk 2>/dev/null"; then log_success "Extended volume group '$vg_name' with $disk" return 0 else log_info "Volume group exists, using existing" return 0 fi fi # Create VG if ssh_pve "vgcreate $vg_name $disk"; then log_success "Volume group '$vg_name' created" return 0 else log_error "Failed to create volume group" return 1 fi } # Create thin pool create_thin_pool() { local vg_name=$1 local pool_name=$2 log_info "Creating thin pool '$pool_name' in volume group '$vg_name'..." # Check if pool already exists if ssh_pve "lvs $vg_name/$pool_name 2>/dev/null | grep -q $pool_name"; then log_warn "Thin pool '$vg_name/$pool_name' already exists" return 0 fi # Get available space local vg_free=$(ssh_pve "vgs -o vg_free --noheadings --units g $vg_name 2>/dev/null | awk '{print int(\$1)}'" || echo "0") if [ "$vg_free" -lt 10 ]; then log_error "Not enough free space in $vg_name (${vg_free}G available)" return 1 fi # Use 90% of available space for thin pool local pool_size=$((vg_free * 90 / 100)) log_info "Creating thin pool with ${pool_size}G (90% of ${vg_free}G free)" # Create thin pool if ssh_pve </dev/null | grep -q '^$storage_name'"; then local status=$(ssh_pve "pvesm status 2>/dev/null | grep '^$storage_name' | awk '{print \$3}'") if [ "$status" == "active" ] || [ "$status" == "enabled" ]; then log_success "Storage '$storage_name' already exists and is active" return 0 else log_info "Storage '$storage_name' exists but is inactive, removing..." ssh_pve "pvesm remove $storage_name 2>/dev/null" || true sleep 2 fi fi # Add storage if ssh_pve <&1 EOF then log_success "Storage '$storage_name' added to Proxmox" return 0 else log_warn "Storage add command had issues, checking if it was created..." sleep 2 if ssh_pve "pvesm status 2>/dev/null | grep -q '^$storage_name'"; then log_success "Storage '$storage_name' exists (may have been created)" return 0 else log_error "Failed to add storage to Proxmox" return 1 fi fi } # Main execution main() { echo "" log_header log_info "Enable LVM Thin Storage on pve" log_header echo "" log_info "This script will:" log_info " 1. Find an available disk on pve" log_info " 2. Create a physical volume" log_info " 3. Create volume group '$VG_NAME'" log_info " 4. Create thin pool '$STORAGE_NAME'" log_info " 5. Add storage to Proxmox configuration" echo "" # Check for non-interactive mode if [[ "${NON_INTERACTIVE:-}" != "1" ]] && [[ -t 0 ]]; then read -p "Continue? (y/N): " -n 1 -r echo "" if [[ ! $REPLY =~ ^[Yy]$ ]]; then log_info "Operation cancelled" exit 0 fi fi echo "" # Find available disk log_info "Finding available disk for LVM..." local disk=$(find_available_disk) if [ -z "$disk" ]; then log_error "Cannot proceed without an available disk" exit 1 fi log_success "Found available disk: $disk" log_warn "WARNING: This will use $disk for LVM storage" log_warn "Any existing data on $disk will be lost!" echo "" if [[ "${NON_INTERACTIVE:-}" != "1" ]] && [[ -t 0 ]]; then read -p "Proceed with using $disk? (y/N): " -n 1 -r echo "" if [[ ! $REPLY =~ ^[Yy]$ ]]; then log_info "Operation cancelled" exit 0 fi fi echo "" # Create physical volume if ! create_physical_volume "$disk"; then log_error "Failed to create physical volume" exit 1 fi echo "" # Create volume group if ! create_volume_group "$VG_NAME" "$disk"; then log_error "Failed to create volume group" exit 1 fi echo "" # Create thin pool if ! create_thin_pool "$VG_NAME" "$STORAGE_NAME"; then log_error "Failed to create thin pool" exit 1 fi echo "" # Add to Proxmox if ! add_proxmox_storage "$STORAGE_NAME" "$VG_NAME" "$STORAGE_NAME"; then log_error "Failed to add storage to Proxmox" exit 1 fi echo "" # Final verification log_header log_info "Verification" log_header echo "" log_info "Volume groups:" ssh_pve "vgs" || true echo "" log_info "Thin pools:" ssh_pve "lvs $VG_NAME" || true echo "" log_info "Storage status:" ssh_pve "pvesm status | grep -E '(thin1|local)'" || true echo "" log_success "LVM thin storage enabled on pve!" log_info "" log_info "You can now migrate VMs to pve using '$STORAGE_NAME' storage:" log_info " pct migrate pve --storage $STORAGE_NAME" echo "" } main "$@"