#!/bin/bash
# ============================================================
# EzScale Hypervisor Discovery Script
# ============================================================
# Run from your JumpHost. Connects to each node via SSH as root
# and collects hardware, storage, network, and VM info.
#
# Usage:
#   chmod +x ezscale-discover.sh
#   ./ezscale-discover.sh
#
# Output: Creates a report file per node + combined summary
# ============================================================

set -euo pipefail

NODES=("vf-node-01" "vf-node-02" "vf-node-03")
SSH_USER="root"
SSH_OPTS="-o ConnectTimeout=10 -o StrictHostKeyChecking=accept-new"
OUTPUT_DIR="./ezscale-discovery-$(date +%Y%m%d-%H%M%S)"
SUMMARY_FILE="$OUTPUT_DIR/00-SUMMARY.txt"

mkdir -p "$OUTPUT_DIR"

# Colors for terminal output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'

echo -e "${CYAN}=========================================${NC}"
echo -e "${CYAN} EzScale Hypervisor Discovery${NC}"
echo -e "${CYAN}=========================================${NC}"
echo ""

# Remote command block — runs on each node
read -r -d '' REMOTE_SCRIPT << 'REMOTECMD' || true
#!/bin/bash

echo "===== SYSTEM INFO ====="
echo "--- Hostname ---"
hostname -f 2>/dev/null || hostname
echo ""
echo "--- OS ---"
cat /etc/os-release 2>/dev/null | grep -E "^(NAME|VERSION|PRETTY)" || echo "Unknown OS"
echo ""
echo "--- Kernel ---"
uname -r
echo ""
echo "--- Uptime ---"
uptime
echo ""

echo "===== CPU ====="
echo "--- Model ---"
grep "model name" /proc/cpuinfo | head -1 | cut -d: -f2 | xargs
echo ""
echo "--- Physical CPUs ---"
grep "physical id" /proc/cpuinfo | sort -u | wc -l
echo ""
echo "--- Cores per CPU ---"
grep "cpu cores" /proc/cpuinfo | head -1 | cut -d: -f2 | xargs
echo ""
echo "--- Total Threads ---"
nproc
echo ""
echo "--- CPU Flags (virt) ---"
grep -oE '(vmx|svm|ept|npt)' /proc/cpuinfo | sort -u | tr '\n' ' '
echo ""
echo ""
echo "--- lscpu summary ---"
lscpu | grep -E "(Model name|Socket|Core|Thread|CPU\(s\)|MHz|cache)" 2>/dev/null
echo ""

echo "===== MEMORY ====="
echo "--- Total / Used / Free ---"
free -h
echo ""
echo "--- DIMM Details ---"
dmidecode -t memory 2>/dev/null | grep -E "(Size|Speed|Type|Locator)" | grep -v "No Module" | head -40 || echo "dmidecode not available or no permission"
echo ""

echo "===== STORAGE - BLOCK DEVICES ====="
echo "--- lsblk ---"
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT,ROTA,MODEL 2>/dev/null || lsblk
echo ""
echo "--- Disk Models ---"
lsblk -d -o NAME,SIZE,MODEL,ROTA,TRAN 2>/dev/null || echo "N/A"
echo ""

echo "===== STORAGE - FILESYSTEM ====="
echo "--- df -h ---"
df -h | grep -v tmpfs | grep -v udev
echo ""

echo "===== STORAGE - ZFS ====="
if command -v zpool &>/dev/null; then
    echo "--- ZFS Pools ---"
    zpool list -v 2>/dev/null || echo "No ZFS pools"
    echo ""
    echo "--- ZFS Pool Status ---"
    zpool status 2>/dev/null || echo "N/A"
    echo ""
    echo "--- ZFS Datasets ---"
    zfs list -o name,used,avail,refer,mountpoint 2>/dev/null || echo "N/A"
    echo ""
    echo "--- ZFS Properties (compression, ashift, recordsize) ---"
    zfs get compression,ashift,recordsize -t filesystem 2>/dev/null | head -30 || echo "N/A"
    echo ""
else
    echo "ZFS not installed"
    echo ""
fi

echo "===== STORAGE - LVM ====="
if command -v pvs &>/dev/null; then
    echo "--- Physical Volumes ---"
    pvs 2>/dev/null || echo "No LVM PVs"
    echo ""
    echo "--- Volume Groups ---"
    vgs 2>/dev/null || echo "No LVM VGs"
    echo ""
    echo "--- Logical Volumes ---"
    lvs -o lv_name,vg_name,lv_size,lv_attr 2>/dev/null || echo "No LVM LVs"
    echo ""
else
    echo "LVM not installed"
    echo ""
fi

echo "===== STORAGE - MDADM (Software RAID) ====="
if [ -f /proc/mdstat ]; then
    cat /proc/mdstat
else
    echo "No mdadm RAID"
fi
echo ""

echo "===== NETWORK ====="
echo "--- Interfaces ---"
ip -br addr show 2>/dev/null || ifconfig -a 2>/dev/null
echo ""
echo "--- Interface Speeds ---"
for iface in $(ls /sys/class/net/ | grep -v lo); do
    speed=$(cat /sys/class/net/$iface/speed 2>/dev/null || echo "N/A")
    driver=$(ethtool -i $iface 2>/dev/null | grep driver | awk '{print $2}' || echo "N/A")
    echo "  $iface: ${speed}Mbps (driver: $driver)"
done
echo ""
echo "--- Default Route ---"
ip route | grep default
echo ""
echo "--- Bridge / Bond Config ---"
if command -v brctl &>/dev/null; then
    brctl show 2>/dev/null || echo "No bridges"
fi
ip link show type bridge 2>/dev/null | grep -E "^[0-9]" || echo ""
ip link show type bond 2>/dev/null | grep -E "^[0-9]" || echo ""
echo ""

echo "===== LIBVIRT / KVM ====="
if command -v virsh &>/dev/null; then
    echo "--- Libvirt Version ---"
    virsh version --daemon 2>/dev/null || virsh version 2>/dev/null
    echo ""
    echo "--- All VMs (running + stopped) ---"
    virsh list --all
    echo ""
    echo "--- Running VM Count ---"
    echo "$(virsh list --state-running --name | grep -c .)"
    echo ""
    echo "--- VM Resource Usage ---"
    echo "VM_NAME | vCPUs | RAM_MAX | STATE"
    echo "--------|-------|---------|------"
    for vm in $(virsh list --name --state-running 2>/dev/null); do
        vcpus=$(virsh dominfo "$vm" 2>/dev/null | grep "CPU(s)" | awk '{print $2}')
        maxmem=$(virsh dominfo "$vm" 2>/dev/null | grep "Max memory" | awk '{print $3, $4}')
        state=$(virsh dominfo "$vm" 2>/dev/null | grep "State" | cut -d: -f2 | xargs)
        echo "$vm | $vcpus | $maxmem | $state"
    done
    echo ""
    echo "--- Total Allocated vCPUs (running VMs) ---"
    total_vcpus=0
    for vm in $(virsh list --name --state-running 2>/dev/null); do
        v=$(virsh dominfo "$vm" 2>/dev/null | grep "CPU(s)" | awk '{print $2}')
        total_vcpus=$((total_vcpus + v))
    done
    echo "$total_vcpus"
    echo ""
    echo "--- Total Allocated RAM (running VMs) ---"
    total_ram=0
    for vm in $(virsh list --name --state-running 2>/dev/null); do
        r=$(virsh dominfo "$vm" 2>/dev/null | grep "Max memory" | awk '{print $3}')
        total_ram=$((total_ram + r))
    done
    echo "$((total_ram / 1024)) MB ($((total_ram / 1024 / 1024)) GB)"
    echo ""
    echo "--- VM Disk Locations ---"
    for vm in $(virsh list --name --all 2>/dev/null); do
        echo "[$vm]"
        virsh domblklist "$vm" --details 2>/dev/null | grep -E "file.*disk" || echo "  (no disks found)"
    done
    echo ""
    echo "--- Storage Pools ---"
    virsh pool-list --all 2>/dev/null || echo "No storage pools"
    echo ""
    for pool in $(virsh pool-list --name 2>/dev/null); do
        echo "--- Pool: $pool ---"
        virsh pool-info "$pool" 2>/dev/null
        echo ""
    done
else
    echo "libvirt/virsh not installed"
    echo ""
fi

echo "===== QEMU ====="
if command -v qemu-system-x86_64 &>/dev/null; then
    echo "--- QEMU Version ---"
    qemu-system-x86_64 --version 2>/dev/null | head -1
elif command -v kvm &>/dev/null; then
    echo "--- KVM Version ---"
    kvm --version 2>/dev/null | head -1
else
    echo "QEMU binary not found in PATH"
fi
echo ""

echo "===== DISK USAGE BY VM IMAGES ====="
echo "--- qcow2 files ---"
find / -name "*.qcow2" -type f 2>/dev/null | while read f; do
    size=$(du -h "$f" 2>/dev/null | awk '{print $1}')
    virtual=$(qemu-img info "$f" 2>/dev/null | grep "virtual size" | awk '{print $3, $4}' || echo "N/A")
    echo "  $f  (actual: $size, virtual: $virtual)"
done
echo ""
echo "--- raw disk files ---"
find / -name "*.raw" -type f 2>/dev/null | while read f; do
    size=$(du -h "$f" 2>/dev/null | awk '{print $1}')
    echo "  $f  (actual: $size)"
done
echo ""

echo "===== SERVICES ====="
echo "--- Key Services Status ---"
for svc in libvirtd qemu-guest-agent virtfusion virtfusion-agent zfs-zed zfs-import-cache zfs-mount; do
    status=$(systemctl is-active "$svc" 2>/dev/null || echo "not-found")
    echo "  $svc: $status"
done
echo ""

echo "===== RESOURCE SUMMARY ====="
echo "--- CPU ---"
total_threads=$(nproc)
allocated_vcpus=$total_vcpus
echo "  Total threads: $total_threads"
echo "  Allocated vCPUs: $allocated_vcpus"
echo "  Overcommit ratio: $(echo "scale=2; $allocated_vcpus / $total_threads" | bc 2>/dev/null || echo 'N/A')"
echo ""
echo "--- RAM ---"
total_ram_mb=$(free -m | awk '/Mem:/ {print $2}')
echo "  Total RAM: ${total_ram_mb} MB ($((total_ram_mb / 1024)) GB)"
echo "  Allocated to VMs: $((total_ram / 1024)) MB ($((total_ram / 1024 / 1024)) GB)"
echo "  Free for host/new VMs: $((total_ram_mb - total_ram / 1024)) MB"
echo "  Utilization: $(echo "scale=1; $total_ram / 1024 / $total_ram_mb * 100" | bc 2>/dev/null || echo 'N/A')%"
echo ""

echo "===== END ====="
REMOTECMD

# Run on each node
for node in "${NODES[@]}"; do
    report_file="$OUTPUT_DIR/${node}.txt"
    echo -e "${YELLOW}Connecting to ${node}...${NC}"

    if ssh $SSH_OPTS ${SSH_USER}@${node} "echo ok" &>/dev/null; then
        echo -e "${GREEN}  Connected. Gathering data...${NC}"
        ssh $SSH_OPTS ${SSH_USER}@${node} "$REMOTE_SCRIPT" > "$report_file" 2>&1
        echo -e "${GREEN}  Done → ${report_file}${NC}"
    else
        echo -e "${RED}  FAILED to connect to ${node}${NC}"
        echo "CONNECTION FAILED" > "$report_file"
    fi
    echo ""
done

# Build combined summary
echo -e "${CYAN}Building summary...${NC}"
{
    echo "============================================"
    echo " EzScale Infrastructure Discovery Summary"
    echo " Generated: $(date)"
    echo "============================================"
    echo ""

    for node in "${NODES[@]}"; do
        report_file="$OUTPUT_DIR/${node}.txt"
        if [ -f "$report_file" ] && ! grep -q "CONNECTION FAILED" "$report_file"; then
            echo "============================================"
            echo " NODE: ${node}"
            echo "============================================"

            # Extract key metrics — use "-- PATTERN" so grep doesn't
            # interpret leading dashes as options
            echo ""
            echo "  OS:       $(grep -A1 -- '--- OS ---' "$report_file" | grep 'PRETTY' | cut -d= -f2 | tr -d '"')"
            echo "  Kernel:   $(grep -A1 -- '--- Kernel ---' "$report_file" | tail -1)"
            echo "  CPU:      $(grep -A1 -- '--- Model ---' "$report_file" | tail -1)"
            echo "  Sockets:  $(grep -A1 -- '--- Physical CPUs ---' "$report_file" | tail -1)"
            echo "  Cores:    $(grep -A1 -- '--- Cores per CPU ---' "$report_file" | tail -1)"
            echo "  Threads:  $(grep -A1 -- '--- Total Threads ---' "$report_file" | tail -1)"

            # RAM
            total_ram=$(grep -A2 -- '--- Total / Used / Free ---' "$report_file" | grep 'Mem:' | awk '{print $2}')
            used_ram=$(grep -A2 -- '--- Total / Used / Free ---' "$report_file" | grep 'Mem:' | awk '{print $3}')
            echo "  RAM:      ${total_ram} total, ${used_ram} used"

            # VM counts
            running=$(grep -A1 -- '--- Running VM Count ---' "$report_file" | tail -1)
            echo "  VMs:      ${running} running"

            # Allocated resources
            alloc_vcpus=$(grep -A1 -- '--- Total Allocated vCPUs' "$report_file" | tail -1)
            alloc_ram=$(grep -A1 -- '--- Total Allocated RAM' "$report_file" | tail -1)
            echo "  Alloc:    ${alloc_vcpus} vCPUs, ${alloc_ram} RAM"

            # Overcommit
            overcommit=$(grep -A5 -- '--- CPU ---' "$report_file" | grep 'Overcommit' | awk '{print $NF}')
            ram_util=$(grep -A8 -- '--- RAM ---' "$report_file" | grep 'Utilization' | awk '{print $NF}')
            echo "  CPU overcommit: ${overcommit}x"
            echo "  RAM utilization: ${ram_util}"

            echo ""
        else
            echo "============================================"
            echo " NODE: ${node} — CONNECTION FAILED"
            echo "============================================"
            echo ""
        fi
    done
} > "$SUMMARY_FILE"

echo -e "${GREEN}Summary → ${SUMMARY_FILE}${NC}"
echo ""
echo -e "${CYAN}=========================================${NC}"
echo -e "${CYAN} Discovery Complete${NC}"
echo -e "${CYAN}=========================================${NC}"
echo ""
echo "Full reports:  ${OUTPUT_DIR}/"
echo "Summary:       ${SUMMARY_FILE}"
echo ""
echo "Next step: Share the contents of ${OUTPUT_DIR}/ and I can"
echo "analyze your capacity and finalize the product line."
