#!/bin/bash # verify-guest-agent.sh # Verify guest agent status on all VMs via Proxmox API set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" # Load environment if [ -f "${PROJECT_ROOT}/.env" ]; then set -a source "${PROJECT_ROOT}/.env" set +a fi # Try API tokens first, fall back to password PROXMOX_1_TOKEN="${PROXMOX_TOKEN_ML110_01:-}" PROXMOX_2_TOKEN="${PROXMOX_TOKEN_R630_01:-}" PROXMOX_PASS="${PROXMOX_ROOT_PASS:-L@kers2010}" PROXMOX_1_URL="https://192.168.11.10:8006" PROXMOX_2_URL="https://192.168.11.11:8006" # Colors GREEN='\033[0;32m' BLUE='\033[0;34m' RED='\033[0;31m' YELLOW='\033[1;33m' NC='\033[0m' log() { echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $*" } log_success() { echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] ✅${NC} $*" } log_error() { echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ❌${NC} $*" } log_warning() { echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] ⚠️${NC} $*" } # Get auth - try API token first, fall back to password get_auth() { local api_url=$1 local api_token=$2 local response # Try API token authentication first if [ -n "${api_token}" ]; then response=$(curl -k -s -X GET \ -H "Authorization: PVEAuthCookie=${api_token}" \ "${api_url}/api2/json/version" 2>/dev/null) if echo "${response}" | grep -q "data\|version"; then echo "${api_token}|TOKEN" return 0 fi fi # Fall back to password authentication response=$(curl -k -s -X POST \ -d "username=root@pam&password=${PROXMOX_PASS}" \ "${api_url}/api2/json/access/ticket" 2>/dev/null) if echo "${response}" | grep -q "authentication failure"; then echo "" return 1 fi local ticket csrf if command -v jq &> /dev/null; then ticket=$(echo "${response}" | jq -r '.data.ticket // empty' 2>/dev/null) csrf=$(echo "${response}" | jq -r '.data.CSRFPreventionToken // empty' 2>/dev/null) else ticket=$(echo "${response}" | grep -o '"ticket":"[^"]*' | head -1 | cut -d'"' -f4) csrf=$(echo "${response}" | grep -o '"CSRFPreventionToken":"[^"]*' | head -1 | cut -d'"' -f4) fi if [ -z "${ticket}" ] || [ -z "${csrf}" ]; then echo "" return 1 fi echo "${ticket}|${csrf}" } # List all nodes in the cluster list_nodes() { local api_url=$1 local auth_token=$2 local auth_type=$3 local response if [ "${auth_type}" = "TOKEN" ]; then response=$(curl -k -s -X GET \ -H "Authorization: PVEAuthCookie=${auth_token}" \ "${api_url}/api2/json/nodes" 2>/dev/null) else local ticket csrf IFS='|' read -r ticket csrf <<< "${auth_token}" response=$(curl -k -s -X GET \ -H "CSRFPreventionToken: ${csrf}" \ -b "PVEAuthCookie=${ticket}" \ "${api_url}/api2/json/nodes" 2>/dev/null) fi if command -v jq &> /dev/null; then echo "${response}" | jq -r '.data[]?.node // empty' 2>/dev/null | grep -v '^$' | sort else echo "${response}" | grep -o '"node":"[^"]*' | cut -d'"' -f4 | sort | uniq fi } # List all VMs on a node list_vms() { local api_url=$1 local node=$2 local auth_token=$3 local auth_type=$4 local response if [ "${auth_type}" = "TOKEN" ]; then response=$(curl -k -s -X GET \ -H "Authorization: PVEAuthCookie=${auth_token}" \ "${api_url}/api2/json/nodes/${node}/qemu" 2>/dev/null) else local ticket csrf IFS='|' read -r ticket csrf <<< "${auth_token}" response=$(curl -k -s -X GET \ -H "CSRFPreventionToken: ${csrf}" \ -b "PVEAuthCookie=${ticket}" \ "${api_url}/api2/json/nodes/${node}/qemu" 2>/dev/null) fi if command -v jq &> /dev/null; then echo "${response}" | jq -r '.data[]?.vmid // empty' 2>/dev/null | grep -v '^$' | sort -n else echo "${response}" | grep -o '"vmid":[0-9]*' | grep -o '[0-9]*' | sort -n | uniq fi } # Get VM name get_vm_name() { local api_url=$1 local node=$2 local vmid=$3 local auth_token=$4 local auth_type=$5 local response if [ "${auth_type}" = "TOKEN" ]; then response=$(curl -k -s -X GET \ -H "Authorization: PVEAuthCookie=${auth_token}" \ "${api_url}/api2/json/nodes/${node}/qemu/${vmid}/config" 2>/dev/null) else local ticket csrf IFS='|' read -r ticket csrf <<< "${auth_token}" response=$(curl -k -s -X GET \ -H "CSRFPreventionToken: ${csrf}" \ -b "PVEAuthCookie=${ticket}" \ "${api_url}/api2/json/nodes/${node}/qemu/${vmid}/config" 2>/dev/null) fi if command -v jq &> /dev/null; then echo "${response}" | jq -r '.data.name // "unnamed"' 2>/dev/null else echo "${response}" | grep -o '"name":"[^"]*' | head -1 | cut -d'"' -f4 || echo "unnamed" fi } # Check guest agent status check_guest_agent() { local api_url=$1 local node=$2 local vmid=$3 local auth_token=$4 local auth_type=$5 local response if [ "${auth_type}" = "TOKEN" ]; then response=$(curl -k -s -X GET \ -H "Authorization: PVEAuthCookie=${auth_token}" \ "${api_url}/api2/json/nodes/${node}/qemu/${vmid}/config" 2>/dev/null) else local ticket csrf IFS='|' read -r ticket csrf <<< "${auth_token}" response=$(curl -k -s -X GET \ -H "CSRFPreventionToken: ${csrf}" \ -b "PVEAuthCookie=${ticket}" \ "${api_url}/api2/json/nodes/${node}/qemu/${vmid}/config" 2>/dev/null) fi # Check if agent is enabled if echo "${response}" | grep -q '"agent"[[:space:]]*:[[:space:]]*"1"'; then return 0 # Enabled fi return 1 # Not enabled } verify_node() { local api_url=$1 local node=$2 local auth_token=$3 local auth_type=$4 log "Verifying node: ${node}" local vmids vmids=$(list_vms "${api_url}" "${node}" "${auth_token}" "${auth_type}") if [ -z "${vmids}" ]; then log_warning " No VMs found on ${node}" return 0 fi local enabled_count=0 local disabled_count=0 printf " %-8s %-30s %-10s\n" "VMID" "Name" "Status" printf " %-8s %-30s %-10s\n" "----" "----" "------" while IFS= read -r vmid; do [ -z "${vmid}" ] && continue local vm_name vm_name=$(get_vm_name "${api_url}" "${node}" "${vmid}" "${auth_token}" "${auth_type}") if check_guest_agent "${api_url}" "${node}" "${vmid}" "${auth_token}" "${auth_type}"; then printf " %-8s %-30s ${GREEN}%-10s${NC}\n" "${vmid}" "${vm_name}" "ENABLED" enabled_count=$((enabled_count + 1)) else printf " %-8s %-30s ${RED}%-10s${NC}\n" "${vmid}" "${vm_name}" "DISABLED" disabled_count=$((disabled_count + 1)) fi done <<< "${vmids}" log "" log " Summary: ${enabled_count} enabled, ${disabled_count} disabled" log "" } verify_site() { local api_url=$1 local site_name=$2 local auth_token=$3 local auth_type=$4 log "==========================================" log "Site: ${site_name}" log "==========================================" local nodes nodes=$(list_nodes "${api_url}" "${auth_token}" "${auth_type}") if [ -z "${nodes}" ]; then log_error "Failed to discover nodes on ${site_name}" return 1 fi log_success "Discovered nodes: $(echo "${nodes}" | tr '\n' ' ')" log "" while IFS= read -r node; do [ -z "${node}" ] && continue verify_node "${api_url}" "${node}" "${auth_token}" "${auth_type}" done <<< "${nodes}" } main() { log "==========================================" log "Verify Guest Agent Status on All VMs" log "==========================================" log "" # Site 1 local auth1 auth1=$(get_auth "${PROXMOX_1_URL}" "${PROXMOX_1_TOKEN}") if [ -z "${auth1}" ]; then log_error "Failed to authenticate to Site 1" else IFS='|' read -r auth_token1 auth_type1 <<< "${auth1}" log_success "Authenticated to Site 1" log "" verify_site "${PROXMOX_1_URL}" "Site 1" "${auth_token1}" "${auth_type1}" fi # Site 2 local auth2 auth2=$(get_auth "${PROXMOX_2_URL}" "${PROXMOX_2_TOKEN}") if [ -z "${auth2}" ]; then log_error "Failed to authenticate to Site 2" else IFS='|' read -r auth_token2 auth_type2 <<< "${auth2}" log_success "Authenticated to Site 2" log "" verify_site "${PROXMOX_2_URL}" "Site 2" "${auth_token2}" "${auth_type2}" fi log "==========================================" log_success "Verification complete!" log "==========================================" } main "$@"