#!/usr/bin/env bash # Recreate containers from their configurations # This script recreates containers that lost data during RAID expansion 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 NODE="r630-01" NODE_IP="${PROXMOX_HOST_R630_01:-192.168.11.11}" NODE_PASS="password" # Colors GREEN='\033[0;32m' RED='\033[0;31m' 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_error() { echo -e "${RED}[✗]${NC} $1"; } log_warn() { echo -e "${YELLOW}[⚠]${NC} $1"; } log_header() { echo -e "${CYAN}=== $1 ===${NC}"; } ssh_node() { sshpass -p "$NODE_PASS" ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 root@"$NODE_IP" "$@" 2>&1 } # Get container configuration get_container_config() { local vmid="$1" ssh_node "pct config $vmid 2>/dev/null" } # Extract configuration values extract_config_value() { local config="$1" local key="$2" echo "$config" | grep "^$key:" | awk '{print $2}' } # Recreate container from template recreate_container() { local vmid="$1" local config=$(get_container_config "$vmid") if [ -z "$config" ]; then log_error "Container $vmid configuration not found" return 1 fi log_header "Recreating Container $vmid" # Extract configuration local hostname=$(extract_config_value "$config" "hostname") local rootfs=$(extract_config_value "$config" "rootfs") local memory=$(extract_config_value "$config" "memory") local swap=$(extract_config_value "$config" "swap" || echo "512") local cores=$(extract_config_value "$config" "cores") local net0=$(extract_config_value "$config" "net0") # Parse rootfs local storage=$(echo "$rootfs" | cut -d: -f1) local volume=$(echo "$rootfs" | cut -d: -f2 | cut -d, -f1) local size_raw=$(echo "$rootfs" | grep -oP 'size=\K[^,]+' || echo "10G") # Extract numeric size (remove G/M suffix for pct create) local size=$(echo "$size_raw" | sed 's/G$//' | sed 's/M$//') local size_unit=$(echo "$size_raw" | grep -oE '[GM]$' || echo "G") log_info "Hostname: $hostname" log_info "Storage: $storage" log_info "Size: $size" log_info "Memory: ${memory}MB" log_info "Cores: $cores" # Check if container already exists if ssh_node "pct list 2>/dev/null | grep -q '^$vmid'"; then log_warn "Container $vmid already exists" log_info "Checking if it's empty..." local volume_usage=$(ssh_node "lvs pve | grep $volume | awk '{print \$6}'" | grep -oP '^\d+\.\d+' || echo "0") if [ "$(echo "$volume_usage > 0" | bc 2>/dev/null || echo "0")" = "1" ]; then log_warn "Container $vmid has data (${volume_usage}% used), skipping..." return 0 else log_info "Container $vmid is empty, will recreate..." ssh_node "pct destroy $vmid --force" || log_warn "Failed to destroy container" sleep 2 fi fi # Determine template (default to ubuntu-22.04) local template="ubuntu-22.04-standard_22.04-1_amd64.tar.zst" # Check if template exists if ! ssh_node "test -f /var/lib/vz/template/cache/$template"; then log_warn "Template $template not found, checking available templates..." local available_template=$(ssh_node "ls /var/lib/vz/template/cache/*.tar.zst 2>/dev/null | head -1" | xargs basename) if [ -n "$available_template" ]; then template="$available_template" log_info "Using template: $template" else log_error "No templates found. Please download a template first." log_info "Download template: pveam download local ubuntu-22.04-standard_22.04-1_amd64.tar.zst" return 1 fi fi # Map storage names (local-lvm maps to data pool) local target_storage="$storage" if [ "$storage" = "local-lvm" ]; then target_storage="data" fi # Build pct create command local create_cmd="pct create $vmid /var/lib/vz/template/cache/$template" create_cmd="$create_cmd --storage $target_storage --rootfs $target_storage:$size" create_cmd="$create_cmd --hostname $hostname" create_cmd="$create_cmd --memory $memory --swap $swap --cores $cores" # Add network configuration if [ -n "$net0" ]; then create_cmd="$create_cmd --net0 $net0" else create_cmd="$create_cmd --net0 name=eth0,bridge=vmbr0" fi # Add mount points if any local mp_count=0 while echo "$config" | grep -q "^mp$mp_count:"; do local mp=$(extract_config_value "$config" "mp$mp_count") create_cmd="$create_cmd --mp$mp_count $mp" mp_count=$((mp_count + 1)) done log_info "Creating container with command:" log_info "$create_cmd" # Create container if ssh_node "$create_cmd"; then log_success "Container $vmid created successfully" # Restore additional configuration log_info "Restoring additional configuration..." # Copy config file and restore non-standard settings ssh_node "pct config $vmid > /tmp/vmid_${vmid}_new.conf" || true # Restore any custom settings from old config # (This would need to be customized based on specific needs) log_success "Container $vmid recreation completed" return 0 else log_error "Failed to create container $vmid" return 1 fi } # Main function main() { log_header "Container Recreation from Configurations" echo "" # Get list of containers to recreate (empty volumes) log_info "Finding containers with empty volumes..." local empty_containers=$(ssh_node "lvs pve | grep 'vm-.*-disk-0' | awk '\$6==\"0.00\" {print \$1}' | sed 's/vm-\([0-9]*\)-disk-0/\1/' | sort -n | head -20") if [ -z "$empty_containers" ]; then log_warn "No containers with empty volumes found" log_info "You can specify VMIDs manually: $0 [vmid2] ..." exit 0 fi log_info "Found containers with empty volumes:" echo "$empty_containers" | while read vmid; do local name=$(ssh_node "pct config $vmid 2>/dev/null | grep '^hostname:' | awk '{print \$2}'" || echo "unknown") echo " - $vmid: $name" done echo "" # Confirm log_warn "This will recreate containers from templates" log_warn "All data in these containers will be lost (they're already empty)" log_info "Press Enter to continue or Ctrl+C to cancel..." read -r # Recreate each container local success=0 local failed=0 for vmid in $empty_containers; do if recreate_container "$vmid"; then success=$((success + 1)) else failed=$((failed + 1)) fi echo "" done # Summary echo "" log_header "Recreation Summary" log_success "Successfully recreated: $success" if [ $failed -gt 0 ]; then log_error "Failed recreations: $failed" fi } # If VMIDs provided as arguments, use those instead if [ $# -gt 0 ]; then for vmid in "$@"; do recreate_container "$vmid" echo "" done else main "$@" fi