#!/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 "########################################"