176 lines
4.5 KiB
Bash
Executable File
176 lines
4.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# proxmox-api -- Make authenticated Proxmox API calls
|
|
#
|
|
# Usage: proxmox-api METHOD PATH [CURL_ARGS...]
|
|
#
|
|
# Handles the ! in automation@pve!deploy safely (no bash history expansion).
|
|
# Config: proxmox.yaml (host, api_token_id), env file (PROXMOX_TOKEN_SECRET)
|
|
#
|
|
# Outputs JSON response on stdout.
|
|
|
|
set -euo pipefail
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Usage
|
|
# ---------------------------------------------------------------------------
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage: proxmox-api METHOD PATH [CURL_ARGS...]
|
|
|
|
Make authenticated Proxmox API calls with proper token handling.
|
|
|
|
Arguments:
|
|
METHOD HTTP method (GET, POST, PUT, DELETE)
|
|
PATH API path (e.g., /nodes/pve/qemu)
|
|
CURL_ARGS Additional curl arguments (e.g., -d 'key=val')
|
|
|
|
Options:
|
|
--json Pretty-print JSON output
|
|
--help, -h Show this help
|
|
|
|
Environment:
|
|
PROXMOX_TOKEN_SECRET API token secret (from env file)
|
|
|
|
Config:
|
|
proxmox.yaml Proxmox host + api_token_id (auto-discovered)
|
|
|
|
Examples:
|
|
proxmox-api GET /nodes/pve/qemu
|
|
proxmox-api GET /nodes/pve/qemu/900/status/current --json
|
|
proxmox-api POST /nodes/pve/qemu/900/status/stop
|
|
proxmox-api GET /cluster/resources --json
|
|
EOF
|
|
exit 0
|
|
}
|
|
|
|
if [[ "${1:-}" == "--help" || "${1:-}" == "-h" ]]; then
|
|
usage
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Parse arguments
|
|
# ---------------------------------------------------------------------------
|
|
|
|
PRETTY=false
|
|
ARGS=()
|
|
for arg in "$@"; do
|
|
if [[ "$arg" == "--json" ]]; then
|
|
PRETTY=true
|
|
else
|
|
ARGS+=("$arg")
|
|
fi
|
|
done
|
|
|
|
if [[ ${#ARGS[@]} -lt 2 ]]; then
|
|
echo "Error: METHOD and PATH required. Usage: proxmox-api METHOD PATH [CURL_ARGS...]" >&2
|
|
exit 1
|
|
fi
|
|
|
|
METHOD="${ARGS[0]}"
|
|
API_PATH="${ARGS[1]}"
|
|
EXTRA_ARGS=("${ARGS[@]:2}")
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Load environment
|
|
# ---------------------------------------------------------------------------
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
|
load_env() {
|
|
local dir="$SCRIPT_DIR"
|
|
while [[ "$dir" != "/" ]]; do
|
|
if [[ -f "${dir}/env" ]]; then
|
|
# shellcheck disable=SC1091
|
|
source "${dir}/env"
|
|
return
|
|
fi
|
|
dir="$(dirname "$dir")"
|
|
done
|
|
}
|
|
load_env
|
|
|
|
if [[ -z "${PROXMOX_TOKEN_SECRET:-}" ]]; then
|
|
echo "Error: PROXMOX_TOKEN_SECRET not set. Create an env file or export it." >&2
|
|
exit 1
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Load proxmox.yaml
|
|
# ---------------------------------------------------------------------------
|
|
|
|
yaml_get() {
|
|
local file="$1" key="$2" default="${3:-}"
|
|
local val
|
|
val=$(awk -F': ' -v k="$key" '$1 == k {print $2; exit}' "$file" 2>/dev/null) || val=""
|
|
val="${val#\"}" ; val="${val%\"}"
|
|
val="${val#\'}" ; val="${val%\'}"
|
|
echo "${val:-$default}"
|
|
}
|
|
|
|
find_proxmox_yaml() {
|
|
local search_dirs=(
|
|
"${SCRIPT_DIR}/.."
|
|
"${SCRIPT_DIR}/../.."
|
|
"$(pwd)"
|
|
)
|
|
for dir in "${search_dirs[@]}"; do
|
|
if [[ -f "${dir}/proxmox.yaml" ]]; then
|
|
echo "${dir}/proxmox.yaml"
|
|
return
|
|
fi
|
|
if [[ -f "${dir}/incusos/proxmox.yaml" ]]; then
|
|
echo "${dir}/incusos/proxmox.yaml"
|
|
return
|
|
fi
|
|
done
|
|
echo ""
|
|
}
|
|
|
|
PROXMOX_YAML=$(find_proxmox_yaml)
|
|
if [[ -z "$PROXMOX_YAML" ]]; then
|
|
echo "Error: proxmox.yaml not found" >&2
|
|
exit 1
|
|
fi
|
|
|
|
PVE_HOST=$(yaml_get "$PROXMOX_YAML" "host")
|
|
PVE_TOKEN_ID=$(yaml_get "$PROXMOX_YAML" "api_token_id")
|
|
|
|
if [[ -z "$PVE_HOST" ]]; then
|
|
echo "Error: proxmox.yaml: 'host' is required" >&2
|
|
exit 1
|
|
fi
|
|
if [[ -z "$PVE_TOKEN_ID" ]]; then
|
|
echo "Error: proxmox.yaml: 'api_token_id' is required" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Make API call
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Build the full auth header in a variable (avoids ! expansion issues)
|
|
AUTH_HEADER="Authorization: PVEAPIToken=${PVE_TOKEN_ID}=${PROXMOX_TOKEN_SECRET}"
|
|
|
|
URL="https://${PVE_HOST}:8006/api2/json${API_PATH}"
|
|
|
|
CURL_CMD=(curl -fsSk -X "$METHOD" -H "$AUTH_HEADER")
|
|
|
|
if [[ ${#EXTRA_ARGS[@]} -gt 0 ]]; then
|
|
CURL_CMD+=("${EXTRA_ARGS[@]}")
|
|
fi
|
|
|
|
CURL_CMD+=("$URL")
|
|
|
|
RESPONSE=$("${CURL_CMD[@]}" 2>&1) || {
|
|
echo "Error: API call failed: $METHOD $API_PATH" >&2
|
|
echo "$RESPONSE" >&2
|
|
exit 1
|
|
}
|
|
|
|
if [[ "$PRETTY" == true ]]; then
|
|
echo "$RESPONSE" | python3 -m json.tool 2>/dev/null || echo "$RESPONSE"
|
|
else
|
|
echo "$RESPONSE"
|
|
fi
|