224 lines
7.3 KiB
Bash
224 lines
7.3 KiB
Bash
|
|
#!/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 <vmid1> [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
|