#!/bin/bash # check-cluster-status.sh # Checks the status of a Proxmox cluster set -euo pipefail # Load environment variables SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" if [ -f "${SCRIPT_DIR}/../.env" ]; then set -a source <(grep -v '^#' "${SCRIPT_DIR}/../.env" | grep -v '^$' | sed 's/^/export /') set +a fi # Colors GREEN='\033[0;32m' RED='\033[0;31m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' # Configuration CLUSTER_NAME="${1:-sankofa-sfv-01}" NODE1_IP="192.168.11.10" NODE1_NAME="ML110-01" NODE1_TOKEN="${PROXMOX_TOKEN_ML110_01:-}" NODE2_IP="192.168.11.11" NODE2_NAME="R630-01" NODE2_TOKEN="${PROXMOX_TOKEN_R630_01:-}" log() { echo -e "${GREEN}[INFO]${NC} $1" } error() { echo -e "${RED}[ERROR]${NC} $1" >&2 } warn() { echo -e "${YELLOW}[WARN]${NC} $1" } info() { echo -e "${BLUE}[INFO]${NC} $1" } check_cluster_status() { local endpoint=$1 local token=$2 local node_name=$3 echo "" info "=== ${node_name} Cluster Status ===" # Check cluster status local status_response=$(curl -k -s -H "Authorization: PVEAPIToken ${token}" \ "${endpoint}/api2/json/cluster/status" 2>/dev/null) if echo "$status_response" | jq -e '.data' >/dev/null 2>&1; then local cluster_name=$(echo "$status_response" | jq -r '.data[0].name // "unknown"') local node_count=$(echo "$status_response" | jq -r '.data | length') if [ "$cluster_name" != "null" ] && [ -n "$cluster_name" ]; then log "✓ Cluster found: ${cluster_name}" log " Node count: ${node_count}" echo "$status_response" | jq -r '.data[] | " • \(.name) - Type: \(.type) - Status: \(.status // "unknown")"' else warn "Cluster status endpoint accessible but no cluster data" fi else local error_msg=$(echo "$status_response" | jq -r '.message // "Unknown error"') if echo "$error_msg" | grep -q "Permission check failed"; then warn "Permission denied (may need Sys.Audit permission)" else warn "Not in cluster or cluster not accessible: ${error_msg}" fi fi } check_cluster_nodes() { local endpoint=$1 local token=$2 local node_name=$3 echo "" info "=== ${node_name} Cluster Nodes ===" local nodes_response=$(curl -k -s -H "Authorization: PVEAPIToken ${token}" \ "${endpoint}/api2/json/cluster/config/nodes" 2>/dev/null) if echo "$nodes_response" | jq -e '.data' >/dev/null 2>&1; then local node_count=$(echo "$nodes_response" | jq -r '.data | length') if [ "$node_count" -gt 0 ]; then log "✓ Cluster nodes found: ${node_count}" echo "$nodes_response" | jq -r '.data[] | " • Node: \(.node) - Node ID: \(.nodeid) - Votes: \(.votes)"' else warn "No nodes found in cluster configuration" fi else local error_msg=$(echo "$nodes_response" | jq -r '.message // "Unknown error"') if echo "$error_msg" | grep -q "Permission check failed"; then warn "Permission denied (may need Sys.Audit permission)" else warn "Cluster nodes not accessible: ${error_msg}" fi fi } check_cluster_config() { local endpoint=$1 local token=$2 local node_name=$3 echo "" info "=== ${node_name} Cluster Configuration ===" local config_response=$(curl -k -s -H "Authorization: PVEAPIToken ${token}" \ "${endpoint}/api2/json/cluster/config" 2>/dev/null) if echo "$config_response" | jq -e '.data' >/dev/null 2>&1; then local cluster_name=$(echo "$config_response" | jq -r '.data.clustername // "unknown"') if [ "$cluster_name" != "null" ] && [ -n "$cluster_name" ]; then log "✓ Cluster name: ${cluster_name}" if [ "$cluster_name" = "$CLUSTER_NAME" ]; then log " ✓ Matches expected cluster name: ${CLUSTER_NAME}" else warn " ⚠ Cluster name mismatch. Expected: ${CLUSTER_NAME}, Found: ${cluster_name}" fi else warn "Cluster config accessible but no cluster name found" fi else local error_msg=$(echo "$config_response" | jq -r '.message // "Unknown error"') if echo "$error_msg" | grep -q "Permission check failed"; then warn "Permission denied (may need Sys.Audit permission)" else warn "Cluster config not accessible: ${error_msg}" fi fi } main() { echo "" echo "╔══════════════════════════════════════════════════════════════╗" echo "║ Proxmox Cluster Status Check ║" echo "╚══════════════════════════════════════════════════════════════╝" echo "" info "Checking cluster: ${CLUSTER_NAME}" echo "" # Check Node 1 check_cluster_status "https://${NODE1_IP}:8006" "${NODE1_TOKEN}" "${NODE1_NAME}" check_cluster_nodes "https://${NODE1_IP}:8006" "${NODE1_TOKEN}" "${NODE1_NAME}" check_cluster_config "https://${NODE1_IP}:8006" "${NODE1_TOKEN}" "${NODE1_NAME}" # Check Node 2 check_cluster_status "https://${NODE2_IP}:8006" "${NODE2_TOKEN}" "${NODE2_NAME}" check_cluster_nodes "https://${NODE2_IP}:8006" "${NODE2_TOKEN}" "${NODE2_NAME}" check_cluster_config "https://${NODE2_IP}:8006" "${NODE2_TOKEN}" "${NODE2_NAME}" echo "" echo "╔══════════════════════════════════════════════════════════════╗" echo "║ Summary ║" echo "╚══════════════════════════════════════════════════════════════╝" echo "" # Try to determine overall status local node1_status=$(curl -k -s -H "Authorization: PVEAPIToken ${NODE1_TOKEN}" \ "https://${NODE1_IP}:8006/api2/json/cluster/status" 2>/dev/null | \ jq -r 'if .data then "in-cluster" else "standalone" end' 2>/dev/null || echo "unknown") local node2_status=$(curl -k -s -H "Authorization: PVEAPIToken ${NODE2_TOKEN}" \ "https://${NODE2_IP}:8006/api2/json/cluster/status" 2>/dev/null | \ jq -r 'if .data then "in-cluster" else "standalone" end' 2>/dev/null || echo "unknown") if [ "$node1_status" = "in-cluster" ] && [ "$node2_status" = "in-cluster" ]; then log "✓ Both nodes appear to be in a cluster" elif [ "$node1_status" = "standalone" ] && [ "$node2_status" = "standalone" ]; then warn "Both nodes are standalone (not clustered)" else warn "Mixed status: Node 1: ${node1_status}, Node 2: ${node2_status}" fi echo "" info "Note: Some checks may require additional API permissions (Sys.Audit)" info "For full cluster status, use Proxmox web UI or SSH: pvecm status" echo "" } main "$@"