- proxmox-inventory.sh: text inventory (RAM/CPU/Swap/Disk/IP/Gateway/Subnetz) - proxmox-inventory-json.sh: JSON variant with n8n webhook push, --vmids filter, --dry-run - n8n workflow: automated fact-sync between Proxmox and Outline docs, auto-creates pages for new VMIDs, ntfy summary notification - credentials (Outline/NTFY bearer tokens) intentionally excluded, see README
180 lines
6.3 KiB
Bash
180 lines
6.3 KiB
Bash
#!/usr/bin/env bash
|
|
#
|
|
# proxmox-inventory.sh
|
|
#
|
|
# Liest alle LXC-Container und VMs auf diesem Proxmox-Host aus und gibt
|
|
# eine strukturierte Übersicht aus (VMID, Name, Status, Ressourcen, Netzwerk
|
|
# inkl. Subnetzmaske und Gateway).
|
|
#
|
|
# Ausführen als root auf dem Proxmox-Host:
|
|
# chmod +x proxmox-inventory.sh
|
|
# ./proxmox-inventory.sh
|
|
#
|
|
# Die Ausgabe kannst du 1:1 kopieren und zurückgeben, um die Outline-Doku
|
|
# aktualisieren zu lassen. Optional: Ausgabe in Datei umleiten:
|
|
# ./proxmox-inventory.sh > inventory.txt
|
|
#
|
|
set -euo pipefail
|
|
separator() { printf '%s\n' "----------------------------------------------------------------------"; }
|
|
|
|
# Wandelt eine CIDR-Prefixlänge (z. B. 24) in eine Subnetzmaske (255.255.255.0) um.
|
|
cidr_to_netmask() {
|
|
local cidr="$1"
|
|
if ! [[ "$cidr" =~ ^[0-9]+$ ]] || [ "$cidr" -lt 0 ] || [ "$cidr" -gt 32 ]; then
|
|
echo "-"
|
|
return
|
|
fi
|
|
local mask=0
|
|
if [ "$cidr" -gt 0 ]; then
|
|
mask=$(( 0xffffffff ^ ((1 << (32 - cidr)) - 1) ))
|
|
else
|
|
mask=0
|
|
fi
|
|
printf "%d.%d.%d.%d\n" \
|
|
"$(( (mask >> 24) & 255 ))" \
|
|
"$(( (mask >> 16) & 255 ))" \
|
|
"$(( (mask >> 8) & 255 ))" \
|
|
"$(( mask & 255 ))"
|
|
}
|
|
|
|
echo "########################################"
|
|
echo "# Proxmox Inventar - $(hostname) - $(date '+%Y-%m-%d %H:%M:%S')"
|
|
echo "########################################"
|
|
echo
|
|
# ---------------------------------------------------------------------------
|
|
# LXC Container
|
|
# ---------------------------------------------------------------------------
|
|
echo "=========================================="
|
|
echo " LXC CONTAINER"
|
|
echo "=========================================="
|
|
echo
|
|
|
|
for VMID in $(pct list | awk 'NR>1 {print $1}'); do
|
|
separator
|
|
echo "VMID: $VMID"
|
|
pct list | awk -v id="$VMID" '$1==id {print "Status: " $2; print "Name (pct list): " $3}'
|
|
|
|
CONFIG=$(pct config "$VMID" 2>/dev/null || true)
|
|
HOSTNAME=$(echo "$CONFIG" | grep -E '^hostname:' | cut -d' ' -f2- || echo "-")
|
|
CORES=$(echo "$CONFIG" | grep -E '^cores:' | cut -d' ' -f2- || echo "-")
|
|
MEMORY=$(echo "$CONFIG" | grep -E '^memory:' | cut -d' ' -f2- || echo "-")
|
|
SWAP=$(echo "$CONFIG" | grep -E '^swap:' | cut -d' ' -f2- || echo "-")
|
|
ROOTFS=$(echo "$CONFIG" | grep -E '^rootfs:' | cut -d' ' -f2- || echo "-")
|
|
echo "Hostname (config): $HOSTNAME"
|
|
echo "Cores: $CORES"
|
|
echo "Memory (MB): $MEMORY"
|
|
echo "Swap (MB): $SWAP"
|
|
echo "Rootfs/Storage: $ROOTFS"
|
|
|
|
echo "Netzwerk-Konfiguration:"
|
|
echo "$CONFIG" | grep -E '^net[0-9]+:' | while read -r LINE; do
|
|
echo " $LINE"
|
|
done
|
|
|
|
# Gateway und CIDR-Prefix aus der net0-Zeile der Config extrahieren (statische Konfiguration)
|
|
NET0_LINE=$(echo "$CONFIG" | grep -E '^net0:' || true)
|
|
CFG_GW=$(echo "$NET0_LINE" | grep -oP 'gw=\K[0-9.]+' || echo "")
|
|
CFG_CIDR=$(echo "$NET0_LINE" | grep -oP 'ip=[0-9.]+/\K[0-9]+' || echo "")
|
|
|
|
# Tatsächlich zugewiesene IP + Prefix (falls Container läuft und Tools installiert sind)
|
|
LIVE_GW=""
|
|
LIVE_CIDR=""
|
|
if pct status "$VMID" 2>/dev/null | grep -q running; then
|
|
IP=$(pct exec "$VMID" -- ip -4 -o addr show scope global 2>/dev/null | awk '{print $4}' | paste -sd ', ' || echo "n/a")
|
|
echo "Live-IP(s): $IP"
|
|
LIVE_CIDR=$(pct exec "$VMID" -- ip -4 -o addr show scope global 2>/dev/null | head -1 | awk '{print $4}' | cut -d/ -f2 || echo "")
|
|
LIVE_GW=$(pct exec "$VMID" -- ip -4 route show default 2>/dev/null | awk '{print $3}' | head -1 || echo "")
|
|
else
|
|
echo "Live-IP(s): (Container gestoppt)"
|
|
fi
|
|
|
|
# Gateway: bevorzugt live ermittelt, sonst aus Config
|
|
GW="${LIVE_GW:-${CFG_GW:-"-"}}"
|
|
[ -z "$GW" ] && GW="-"
|
|
echo "Gateway: $GW"
|
|
|
|
# Subnetzmaske: bevorzugt live ermittelter Prefix, sonst Config-Prefix
|
|
CIDR="${LIVE_CIDR:-${CFG_CIDR:-""}}"
|
|
if [ -n "$CIDR" ]; then
|
|
NETMASK=$(cidr_to_netmask "$CIDR")
|
|
echo "Subnetzmaske: $NETMASK (/$CIDR)"
|
|
else
|
|
echo "Subnetzmaske: -"
|
|
fi
|
|
|
|
echo
|
|
done
|
|
|
|
echo
|
|
echo "=========================================="
|
|
echo " VIRTUELLE MASCHINEN (QEMU/KVM)"
|
|
echo "=========================================="
|
|
echo
|
|
|
|
for VMID in $(qm list | awk 'NR>1 {print $1}'); do
|
|
separator
|
|
echo "VMID: $VMID"
|
|
qm list | awk -v id="$VMID" '$1==id {print "Name (qm list): " $2; print "Status: " $3}'
|
|
|
|
CONFIG=$(qm config "$VMID" 2>/dev/null || true)
|
|
CORES=$(echo "$CONFIG" | grep -E '^cores:' | cut -d' ' -f2- || echo "-")
|
|
SOCKETS=$(echo "$CONFIG"| grep -E '^sockets:'| cut -d' ' -f2- || echo "-")
|
|
MEMORY=$(echo "$CONFIG" | grep -E '^memory:' | cut -d' ' -f2- || echo "-")
|
|
echo "Cores: $CORES"
|
|
echo "Sockets: $SOCKETS"
|
|
echo "Memory (MB): $MEMORY"
|
|
echo "Disks:"
|
|
echo "$CONFIG" | grep -E '^(scsi|sata|virtio|ide)[0-9]+:' | while read -r LINE; do
|
|
echo " $LINE"
|
|
done
|
|
echo "Netzwerk-Konfiguration:"
|
|
echo "$CONFIG" | grep -E '^net[0-9]+:' | while read -r LINE; do
|
|
echo " $LINE"
|
|
done
|
|
|
|
# Cloud-Init-Netzwerkdaten (falls vorhanden): ipconfig0: ip=X.X.X.X/24,gw=Y.Y.Y.Y
|
|
IPCONFIG_LINE=$(echo "$CONFIG" | grep -E '^ipconfig0:' || true)
|
|
CFG_GW=$(echo "$IPCONFIG_LINE" | grep -oP 'gw=\K[0-9.]+' || echo "")
|
|
CFG_CIDR=$(echo "$IPCONFIG_LINE" | grep -oP 'ip=[0-9.]+/\K[0-9]+' || echo "")
|
|
|
|
LIVE_CIDR=""
|
|
# QEMU-Guest-Agent IP/Prefix, falls installiert & VM läuft
|
|
if qm status "$VMID" 2>/dev/null | grep -q running; then
|
|
AGENT_JSON=$(qm guest cmd "$VMID" network-get-interfaces 2>/dev/null || echo "")
|
|
IP=$(echo "$AGENT_JSON" \
|
|
| grep -o '"ip-address":"[^"]*"' \
|
|
| grep -v '127.0.0.1' \
|
|
| cut -d'"' -f4 \
|
|
| paste -sd ', ' || echo "")
|
|
if [ -n "$IP" ]; then
|
|
echo "Live-IP(s) via Guest-Agent: $IP"
|
|
# Prefix der ersten nicht-lokalen Adresse ermitteln
|
|
LIVE_CIDR=$(echo "$AGENT_JSON" | grep -oP '"prefix":\K[0-9]+' | head -1 || echo "")
|
|
else
|
|
echo "Live-IP(s) via Guest-Agent: n/a (kein Guest-Agent?)"
|
|
fi
|
|
else
|
|
echo "Live-IP(s): (VM gestoppt)"
|
|
fi
|
|
|
|
# Gateway: nur über Cloud-Init-Config ermittelbar (Guest-Agent liefert kein Gateway)
|
|
GW="${CFG_GW:-"-"}"
|
|
[ -z "$GW" ] && GW="-"
|
|
echo "Gateway: $GW"
|
|
|
|
CIDR="${LIVE_CIDR:-${CFG_CIDR:-""}}"
|
|
if [ -n "$CIDR" ]; then
|
|
NETMASK=$(cidr_to_netmask "$CIDR")
|
|
echo "Subnetzmaske: $NETMASK (/$CIDR)"
|
|
else
|
|
echo "Subnetzmaske: - (nicht ermittelbar ohne Cloud-Init-Config oder Guest-Agent-Prefix)"
|
|
fi
|
|
|
|
echo
|
|
done
|
|
|
|
echo
|
|
echo "########################################"
|
|
echo "# Ende der Ausgabe"
|
|
echo "########################################"
|