197 lines
7.2 KiB
Bash
197 lines
7.2 KiB
Bash
|
|
#!/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 "$@"
|
||
|
|
|