Files
Sankofa/scripts/enable-guest-agent-existing-vms.sh

430 lines
13 KiB
Bash
Raw Normal View History

#!/bin/bash
# enable-guest-agent-existing-vms.sh
# Enable QEMU guest agent on existing 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
# Parse token format: root@pam!sankofa-instance-1-api-token=73c7e1a2-c969-409c-ae5b-68e83f012ee9
# For Proxmox API tokens, we use the full token string in Authorization header
response=$(curl -k -s -X GET \
-H "Authorization: PVEAuthCookie=${api_token}" \
"${api_url}/api2/json/version" 2>/dev/null)
# If token auth works (we get version info), return token for direct use
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
# Extract node names from response
if command -v jq &> /dev/null; then
echo "${response}" | jq -r '.data[]?.node // empty' 2>/dev/null | grep -v '^$' | sort
else
# Fallback: extract node names using grep/sed
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
# Use API token directly
response=$(curl -k -s -X GET \
-H "Authorization: PVEAuthCookie=${auth_token}" \
"${api_url}/api2/json/nodes/${node}/qemu" 2>/dev/null)
else
# Use ticket and CSRF token
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
# Extract VMIDs from response
if command -v jq &> /dev/null; then
echo "${response}" | jq -r '.data[]?.vmid // empty' 2>/dev/null | grep -v '^$' | sort -n
else
# Fallback: extract VMIDs using grep/sed
echo "${response}" | grep -o '"vmid":[0-9]*' | grep -o '[0-9]*' | sort -n | uniq
fi
}
# Check if guest agent is already enabled
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 already enabled
if echo "${response}" | grep -q '"agent"[[:space:]]*:[[:space:]]*"1"'; then
return 0 # Already enabled
fi
return 1 # Not enabled
}
# Enable guest agent
enable_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
# Use API token directly
response=$(curl -k -s -X PUT \
-H "Authorization: PVEAuthCookie=${auth_token}" \
-d "agent=1" \
"${api_url}/api2/json/nodes/${node}/qemu/${vmid}/config" 2>/dev/null)
else
# Use ticket and CSRF token
local ticket csrf
IFS='|' read -r ticket csrf <<< "${auth_token}"
response=$(curl -k -s -X PUT \
-H "CSRFPreventionToken: ${csrf}" \
-b "PVEAuthCookie=${ticket}" \
-d "agent=1" \
"${api_url}/api2/json/nodes/${node}/qemu/${vmid}/config" 2>/dev/null)
fi
if echo "${response}" | grep -q '"data":null'; then
return 0
fi
# Check if already enabled
if echo "${response}" | grep -q "already"; then
return 0
fi
return 1
}
process_node() {
local api_url=$1
local node=$2
local auth_token=$3
local auth_type=$4
log "Processing node: ${node}"
# Discover all VMs on this 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 vm_count=0
local enabled_count=0
local skipped_count=0
local failed_count=0
while IFS= read -r vmid; do
[ -z "${vmid}" ] && continue
vm_count=$((vm_count + 1))
# Check if already enabled
if check_guest_agent "${api_url}" "${node}" "${vmid}" "${auth_token}" "${auth_type}"; then
log " VMID ${vmid}: guest agent already enabled"
skipped_count=$((skipped_count + 1))
continue
fi
log " Enabling guest agent on VMID ${vmid}..."
if enable_guest_agent "${api_url}" "${node}" "${vmid}" "${auth_token}" "${auth_type}"; then
log_success " VMID ${vmid} guest agent enabled"
enabled_count=$((enabled_count + 1))
else
log_error " Failed to enable guest agent on VMID ${vmid}"
failed_count=$((failed_count + 1))
fi
sleep 0.3
done <<< "${vmids}"
log " Summary for ${node}: ${vm_count} total, ${enabled_count} enabled, ${skipped_count} already enabled, ${failed_count} failed"
# Return counts via global variables or echo
echo "${vm_count}|${enabled_count}|${skipped_count}|${failed_count}"
}
process_site() {
local api_url=$1
local site_name=$2
local auth_token=$3
local auth_type=$4
log "=========================================="
log "Site: ${site_name}"
log "=========================================="
# Discover all nodes on this site
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 ""
local site_vm_count=0
local site_enabled_count=0
local site_skipped_count=0
local site_failed_count=0
# Process each node
while IFS= read -r node; do
[ -z "${node}" ] && continue
local result
result=$(process_node "${api_url}" "${node}" "${auth_token}" "${auth_type}")
if [ -n "${result}" ]; then
IFS='|' read -r vm_count enabled_count skipped_count failed_count <<< "${result}"
site_vm_count=$((site_vm_count + vm_count))
site_enabled_count=$((site_enabled_count + enabled_count))
site_skipped_count=$((site_skipped_count + skipped_count))
site_failed_count=$((site_failed_count + failed_count))
fi
log ""
done <<< "${nodes}"
log "Site Summary for ${site_name}:"
log " Total VMs: ${site_vm_count}"
log " Enabled: ${site_enabled_count}"
log " Already enabled: ${site_skipped_count}"
log " Failed: ${site_failed_count}"
log ""
echo "${site_vm_count}|${site_enabled_count}|${site_skipped_count}|${site_failed_count}"
}
main() {
log "=========================================="
log "Enable QEMU Guest Agent on All VMs"
log "=========================================="
log ""
log "This script will:"
log "1. Discover all nodes on each Proxmox site"
log "2. Discover all VMs on each node"
log "3. Check if guest agent is already enabled"
log "4. Enable guest agent on VMs that need it"
log ""
local total_vm_count=0
local total_enabled=0
local total_skipped=0
local total_failed=0
# 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 ""
local result1
result1=$(process_site "${PROXMOX_1_URL}" "Site 1" "${auth_token1}" "${auth_type1}")
if [ -n "${result1}" ]; then
IFS='|' read -r vm_count enabled_count skipped_count failed_count <<< "${result1}"
total_vm_count=$((total_vm_count + vm_count))
total_enabled=$((total_enabled + enabled_count))
total_skipped=$((total_skipped + skipped_count))
total_failed=$((total_failed + failed_count))
fi
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 ""
local result2
result2=$(process_site "${PROXMOX_2_URL}" "Site 2" "${auth_token2}" "${auth_type2}")
if [ -n "${result2}" ]; then
IFS='|' read -r vm_count enabled_count skipped_count failed_count <<< "${result2}"
total_vm_count=$((total_vm_count + vm_count))
total_enabled=$((total_enabled + enabled_count))
total_skipped=$((total_skipped + skipped_count))
total_failed=$((total_failed + failed_count))
fi
fi
log ""
log "=========================================="
log "Overall Summary"
log "=========================================="
log "Total VMs processed: ${total_vm_count}"
log_success "Guest agent enabled: ${total_enabled}"
log "Already enabled: ${total_skipped}"
if [ "${total_failed}" -gt 0 ]; then
log_error "Failed: ${total_failed}"
else
log_success "Failed: ${total_failed}"
fi
log ""
log "=========================================="
log_success "Guest agent enablement complete!"
log "=========================================="
log ""
log_warning "IMPORTANT: Guest agent must also be installed in the OS."
log ""
log "For existing VMs, you need to:"
log "1. Wait for VMs to get IP addresses"
log "2. SSH into each VM: ssh admin@<vm-ip>"
log "3. Install and enable guest agent:"
log " sudo apt-get update"
log " sudo apt-get install -y qemu-guest-agent"
log " sudo systemctl enable qemu-guest-agent"
log " sudo systemctl start qemu-guest-agent"
log ""
log "Note: New VMs created with the updated Crossplane provider will"
log "automatically have guest agent enabled in Proxmox config."
log ""
}
main "$@"