#!/bin/bash source ~/.bashrc # Proxmox VM Helper Functions # Shared library for Proxmox VM operations with guest-agent IP discovery set -euo pipefail # Ensure we're on a Proxmox node if ! command -v qm >/dev/null 2>&1; then echo "[ERROR] qm command not found. Run this on a Proxmox host." >&2 exit 1 fi # Ensure jq is installed if ! command -v jq >/dev/null 2>&1; then echo "[ERROR] jq command not found. Install with: apt update && apt install -y jq" >&2 exit 1 fi # get_vm_ip_from_guest_agent # # Uses qemu-guest-agent to read network interfaces and returns the first # non-loopback IPv4 address. Requires: # - qemu-guest-agent installed in the guest # - Agent enabled in VM config: qm set --agent enabled=1 # # Returns: IP address or empty string if not available get_vm_ip_from_guest_agent() { local vmid="$1" # This will exit non-zero if guest agent is not running or not enabled qm guest cmd "$vmid" network-get-interfaces 2>/dev/null \ | jq -r ' .[]?."ip-addresses"[]? | select(.["ip-address-type"] == "ipv4" and ."ip-address" != "127.0.0.1") | ."ip-address" ' \ | head -n1 || echo "" } # Convenience wrapper that logs and optionally fails # get_vm_ip_or_warn # # Returns: IP address or empty string # Prints: Warning message if IP not available get_vm_ip_or_warn() { local vmid="$1" local name="$2" local ip ip="$(get_vm_ip_from_guest_agent "$vmid" || true)" if [[ -z "$ip" ]]; then echo "[WARN] No IP from guest agent for VM $vmid ($name)." >&2 echo " - Ensure qemu-guest-agent is installed in the guest" >&2 echo " - Ensure 'Agent' is enabled in VM options" >&2 echo " - VM must be powered on" >&2 return 1 fi echo "$ip" } # get_vm_ip_or_fallback # # Tries guest agent first, falls back to provided IP if agent not available # Useful for bootstrap scenarios get_vm_ip_or_fallback() { local vmid="$1" local name="$2" local fallback_ip="${3:-}" local ip ip="$(get_vm_ip_from_guest_agent "$vmid" || true)" if [[ -n "$ip" ]]; then echo "$ip" return 0 fi if [[ -n "$fallback_ip" ]]; then echo "[INFO] Guest agent not available for VM $vmid ($name), using fallback IP: $fallback_ip" >&2 echo "$fallback_ip" return 0 fi echo "[ERROR] No IP available for VM $vmid ($name) (no guest agent, no fallback)" >&2 return 1 } # ensure_guest_agent_enabled # # Ensures guest agent is enabled in VM config (doesn't install in guest) ensure_guest_agent_enabled() { local vmid="$1" qm set "$vmid" --agent enabled=1 >/dev/null 2>&1 || true } # check_vm_status # # Returns VM status (running, stopped, etc.) check_vm_status() { local vmid="$1" qm status "$vmid" 2>/dev/null | awk '{print $2}' || echo "unknown" } # wait_for_guest_agent # # Waits for guest agent to become available wait_for_guest_agent() { local vmid="$1" local timeout="${2:-60}" local elapsed=0 while [ $elapsed -lt $timeout ]; do if get_vm_ip_from_guest_agent "$vmid" >/dev/null 2>&1; then return 0 fi sleep 2 elapsed=$((elapsed + 2)) done return 1 }