Files
PFVCluster/validate-vms.sh
mrcharles 422999bf3c chore: initialize repo with full project state
Performance optimization engagement for a 7-host Proxmox R&D cluster.
Captures the accumulated work across host tuning, network analysis,
fleet assessment, and kubernetes architecture planning.

Contents:
- Host-side tunings (scripts/): CPU governor, swappiness, BBR, NFS
  nconnect, tuned profiles -- complete on 5 of 7 hosts
- Validation + benchmarking scripts: iperf matrix, bond/NFS fixes
- Collected host data (returned-logs/): check.sh output from all 7
  hosts + iperf results, including newly-validated pfv-tsys9
- AGENTS.md: operating context for AI agents
- PROJECT.md: board-ready fleet assessment with VM placement and
  storage redundancy analysis (40 VMs across 7 hosts)
- K8S.md: kubernetes architecture deep-dive covering cnode/wnode
  distribution, StorageClass design, and ETL/HPC workload planning

💘 Generated with Crush

Assisted-by: Crush:glm-5.2
2026-07-27 11:31:29 -05:00

133 lines
4.8 KiB
Bash
Executable File

#!/bin/bash
###############################################################################
# validate-vms.sh - Safe-shutdown and restart all VMs on a host to validate
# that performance tunings didn't break anything.
#
# For each VM:
# 1. qm shutdown <vmid> --timeout 120 (ACPI safe shutdown)
# 2. Wait for stopped state
# 3. qm start <vmid>
# 4. Wait for running state
# 5. Check qm agent responds (if agent enabled)
#
# Usage: bash validate-vms.sh <host> [host...]
###############################################################################
set -uo pipefail
SSH_OPTS=(-o BatchMode=yes -o ConnectTimeout=8 -o ServerAliveInterval=10 -o StrictHostKeyChecking=accept-new)
for HOST in "$@"; do
echo "================================================================"
echo "[$HOST] VM SAFE-SHUTDOWN/RESTART VALIDATION"
echo "================================================================"
echo ""
if ! ssh "${SSH_OPTS[@]}" "root@$HOST" 'echo ok' >/dev/null 2>&1; then
echo " UNREACHABLE — skipping"
continue
fi
# Get list of running VMs
VM_LIST=$(ssh "${SSH_OPTS[@]}" "root@$HOST" 'qm list 2>/dev/null | awk "NR>1 && \$3==\"running\"{print \$1}"')
if [ -z "$VM_LIST" ]; then
echo " No running VMs — nothing to validate"
continue
fi
VM_COUNT=$(echo "$VM_LIST" | wc -w)
echo " Found $VM_COUNT running VM(s): $(echo "$VM_LIST" | tr '\n' ' ')"
echo ""
# --- Phase 1: Safe shutdown all VMs ---
echo "--- PHASE 1: Safe shutdown all VMs (120s timeout each) ---"
for vmid in $VM_LIST; do
name=$(ssh "${SSH_OPTS[@]}" "root@$HOST" "qm config $vmid 2>/dev/null | awk -F: '/^name:/{gsub(/^ /,\"\");print \$2}'")
echo -n " [$vmid $name] shutting down... "
ssh "${SSH_OPTS[@]}" "root@$HOST" "qm shutdown $vmid --timeout 120 --forceStop 1" 2>&1 | head -1
done
# Wait for all to stop (max 180s total)
echo ""
echo -n " Waiting for all VMs to stop"
WAIT_DEADLINE=$(( $(date +%s) + 180 ))
while [ "$(date +%s)" -lt "$WAIT_DEADLINE" ]; do
echo -n "."
all_stopped=1
for vmid in $VM_LIST; do
status=$(ssh "${SSH_OPTS[@]}" "root@$HOST" "qm status $vmid 2>/dev/null | awk '{print \$2}'")
if [ "$status" = "running" ]; then
all_stopped=0
break
fi
done
[ "$all_stopped" = "1" ] && break
sleep 5
done
echo " done"
echo ""
# Show stopped state
echo "--- VM status after shutdown ---"
ssh "${SSH_OPTS[@]}" "root@$HOST" 'qm list'
echo ""
# --- Phase 2: Start all VMs ---
echo "--- PHASE 2: Start all VMs ---"
for vmid in $VM_LIST; do
name=$(ssh "${SSH_OPTS[@]}" "root@$HOST" "qm config $vmid 2>/dev/null | awk -F: '/^name:/{gsub(/^ /,\"\");print \$2}'")
echo -n " [$vmid $name] starting... "
start_output=$(ssh "${SSH_OPTS[@]}" "root@$HOST" "qm start $vmid" 2>&1)
if [ $? -eq 0 ]; then
echo "OK"
else
echo "FAILED: $start_output"
fi
done
# Wait 20s for VMs to fully start
echo ""
echo " Waiting 20s for VMs to boot..."
sleep 20
# --- Phase 3: Verify all VMs running ---
echo ""
echo "--- PHASE 3: Verification ---"
ssh "${SSH_OPTS[@]}" "root@$HOST" 'qm list'
echo ""
# Check NFS mounts still healthy
echo "--- NFS mount health ---"
ssh "${SSH_OPTS[@]}" "root@$HOST" '
mount_count=$(nfsstat -m 2>/dev/null | grep -c "^/mnt")
conn_count=$(ss -tn state established "( dport = :2049 )" 2>/dev/null | tail -n +2 | wc -l)
echo " NFS mounts: $mount_count"
echo " NFS TCP connections: $conn_count"
if [ "$mount_count" -gt 0 ]; then
echo " First mount options:"
nfsstat -m 2>/dev/null | head -2 | tail -1 | sed "s/^/ /"
fi
'
echo ""
# Check guest agent responsiveness (if agent enabled)
echo "--- Guest agent check (VMs with agent:1) ---"
for vmid in $VM_LIST; do
agent=$(ssh "${SSH_OPTS[@]}" "root@$HOST" "qm config $vmid 2>/dev/null | grep -c '^agent: 1'")
if [ "$agent" = "1" ]; then
name=$(ssh "${SSH_OPTS[@]}" "root@$HOST" "qm config $vmid 2>/dev/null | awk -F: '/^name:/{gsub(/^ /,\"\");print \$2}'")
echo -n " [$vmid $name] agent ping... "
result=$(ssh "${SSH_OPTS[@]}" "root@$HOST" "timeout 10 qm agent $vmid ping 2>&1")
if [ $? -eq 0 ]; then
echo "OK"
else
echo "no response (VM may still be booting)"
fi
fi
done
echo ""
echo "================================================================"
echo "[$HOST] VALIDATION COMPLETE"
echo "================================================================"
echo ""
done