initial commit

This commit is contained in:
2026-05-17 19:02:44 +02:00
commit 4930f5c75c
5 changed files with 379 additions and 0 deletions

3
.env-sample Normal file
View File

@@ -0,0 +1,3 @@
PM_HOST="https://proxmox.example.com:8006"
PM_USER="root@pam"
PM_PASS="super-secret-password"

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.env
/output/

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Marco Mooij
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

84
README.md Normal file
View File

@@ -0,0 +1,84 @@
# Proxmox to Sentri
Proxmox to Sentri is a utility script that retrieves all virtual machines from a Proxmox cluster and imports them into Sentri as servers.
The script collects information such as:
- VM name
- Power state
- CPU and memory allocation
- Disk configuration
- IPv4 and IPv6 addresses
- Snapshot count
- Backup availability
- Operating system information
- VM descriptions/notes
---
# Requirements
## System Requirements
The machine running this script must:
- Have network access to the Proxmox web interface/API
- Have the following packages installed:
- `curl`
- `jq`
- `git` (required for installation)
## Proxmox Requirements
A Proxmox user account with permission to view VMs and storage information is required.
Recommended role:
- `PVEAuditor`
## Optional: Guest IP Address Collection
To collect IPv4, IPv6, and operating system information from virtual machines, install the QEMU Guest Agent inside each VM.
Example for AlmaLinux/RHEL:
```bash
sudo dnf install -y qemu-guest-agent
sudo systemctl enable --now qemu-guest-agent
```
Then enable the QEMU Guest Agent in Proxmox:
```
qm set <VMID> --agent enabled=1
```
---
# Installation
Clone the repository and configure the environment file:
```
cd /optgit clone https://gitea.mooij.me/meteo/proxmox-to-sentri.gitcd proxmox-to-sentricp .env-sample .envchmod 600 .envchmod 740 proxmox-to-sentri.sh
```
Optional: Create a global command:
```
ln -sf /opt/proxmox-to-sentri/proxmox-to-sentri.sh /usr/bin/proxmox-to-sentri
```
---
# Configuration
Edit the `.env` file and configure the Proxmox connection settings:
```
PM_HOST="https://proxmox.example.com:8006"
PM_USER="root@pam"
PM_PASS="your-password"
```
---
# Running the Script
Run the script directly:
```
./proxmox-to-sentri.sh
```
Or, if you created the symlink:
```
proxmox-to-sentri
```
---
# Output
Generated JSON files are written to:
```
/opt/proxmox-to-sentri/output/
```
One JSON file is generated per VM.

269
proxmox-to-sentri.sh Executable file
View File

@@ -0,0 +1,269 @@
#!/usr/bin/env bash
set -euo pipefail
# -----------------------------------------------------------------------------
# Proxmox VM Inventory Exporter
#
# Exports one JSON object per VM with:
# - CPU / RAM
# - Network IPs
# - Snapshots
# - Backup detection
# - VM notes
# - Disk information
#
# Requirements:
# - curl
# - jq
# - for ipv4 and ipv6 collection install the proxmox agent on the VM
#
# Files:
# .env
#
# Example .env:
# PM_HOST="https://proxmox.example.com:8006"
# PM_USER="root@pam"
# PM_PASS="password"
#
# Output:
# ./output/<vmid>.json
# -----------------------------------------------------------------------------
SCRIPT_PATH="$(readlink -f "${BASH_SOURCE[0]}")"
SCRIPT_DIR="$(cd "$(dirname "$SCRIPT_PATH")" && pwd)"
OUTPUT_DIR="${SCRIPT_DIR}/output"
mkdir -p "$OUTPUT_DIR"
ENV_FILE="${SCRIPT_DIR}/.env"
# Load environment variables
if [[ -f "$ENV_FILE" ]]; then
set -a
source "$ENV_FILE"
set +a
else
echo ".env file missing: $ENV_FILE"
exit 1
fi
# Validate vars
: "${PM_HOST:?Missing PM_HOST}"
: "${PM_USER:?Missing PM_USER}"
: "${PM_PASS:?Missing PM_PASS}"
# Authenticate
AUTH_RESPONSE=$(curl -sk \
--data-urlencode "username=${PM_USER}" \
--data-urlencode "password=${PM_PASS}" \
"${PM_HOST}/api2/json/access/ticket")
TICKET=$(echo "$AUTH_RESPONSE" | jq -r '.data.ticket // empty')
CSRF=$(echo "$AUTH_RESPONSE" | jq -r '.data.CSRFPreventionToken // empty')
if [[ "$TICKET" == "null" || -z "$TICKET" ]]; then
echo "Authentication failed"
exit 1
fi
api_get() {
local endpoint="$1"
curl -sk \
-H "Cookie: PVEAuthCookie=${TICKET}" \
-H "CSRFPreventionToken: ${CSRF}" \
"${PM_HOST}${endpoint}"
}
echo "Collecting VMs..."
VMS=$(api_get "/api2/json/cluster/resources?type=vm")
echo "$VMS" | jq -c '.data[]' | while read -r VM; do
VMID=$(echo "$VM" | jq -r '.vmid')
NODE=$(echo "$VM" | jq -r '.node')
NAME=$(echo "$VM" | jq -r '.name')
STATUS=$(echo "$VM" | jq -r '.status')
CPU=$(echo "$VM" | jq -r '.maxcpu')
MEMORY_MB=$(echo "$VM" | jq -r '.maxmem / 1024 / 1024 | floor')
echo "Processing VM ${VMID} (${NAME})"
# VM Config
CONFIG=$(api_get "/api2/json/nodes/${NODE}/qemu/${VMID}/config")
DESCRIPTION=$(echo "$CONFIG" | jq -r '.data.description // empty')
# Try to detect OS
OS_INFO=$(api_get "/api2/json/nodes/${NODE}/qemu/${VMID}/agent/get-osinfo" || true)
OS=$(echo "$OS_INFO" | jq -r '
.data["pretty-name"] // empty
')
# Snapshot count
SNAPSHOTS=$(api_get "/api2/json/nodes/${NODE}/qemu/${VMID}/snapshot")
SNAPSHOT_COUNT=$(echo "$SNAPSHOTS" | jq '.data | length - 1')
# Backup detection
BACKUP_ENABLED="no"
STORAGES=$(api_get "/api2/json/storage" | jq -r '.data[].storage')
for STORAGE in $STORAGES; do
CONTENT=$(api_get "/api2/json/nodes/${NODE}/storage/${STORAGE}/content" || true)
if echo "$CONTENT" | jq -e --arg VMID "$VMID" '
.data[]?
| select(
.volid
| test("vzdump-qemu-" + $VMID + "-")
)
' >/dev/null; then
BACKUP_ENABLED="yes"
break
fi
done
# Network interfaces
IPV4=()
IPV6=()
AGENT=$(api_get "/api2/json/nodes/${NODE}/qemu/${VMID}/agent/network-get-interfaces" || true)
if echo "$AGENT" | jq -e '.data.result' >/dev/null 2>&1; then
while read -r IP; do
IPV4+=("$IP")
done < <(
echo "$AGENT" | jq -r '
.data.result[]."ip-addresses"[]?
| select(."ip-address-type" == "ipv4")
| ."ip-address"
' \
| grep -v '^127\.' \
| grep -v '^172\.17\.' \
| grep -v '^172\.18\.' \
| grep -v '^172\.19\.' \
| grep -v '^172\.20\.' \
| grep -v '^172\.21\.' \
| grep -v '^172\.22\.' \
| grep -v '^172\.30\.'
)
while read -r IP; do
IPV6+=("$IP")
done < <(
echo "$AGENT" | jq -r '
.data.result[]."ip-addresses"[]?
| select(."ip-address-type" == "ipv6")
| ."ip-address"
' \
| grep -v '^::1' \
| grep -v '^fe80:'
)
fi
# MAC Address
MAC=$(echo "$CONFIG" | jq -r '
.data.net0 // ""
' | sed -n 's/.*virtio=\([^,]*\).*/\1/p' \
| tr '[:upper:]' '[:lower:]' \
| tr -d ':')
# Disks
DISKS_JSON="[]"
while read -r DISKKEY; do
DISKCONF=$(echo "$CONFIG" | jq -r ".data.${DISKKEY}")
STORAGE=$(echo "$DISKCONF" | cut -d':' -f1)
DISK_LOCATION=$(echo "$DISKCONF" | cut -d',' -f1)
SIZE=$(echo "$DISKCONF" | sed -n 's/.*size=\([^,]*\).*/\1/p')
DISKS_JSON=$(echo "$DISKS_JSON" | jq \
--arg name "$DISKKEY" \
--arg size "$SIZE" \
--arg used "$SIZE" \
--arg location "$DISK_LOCATION" \
'. += [{
"disk_name": $name,
"disk_space": $size,
"disk_used": $used,
"disk_location": $location
}]'
)
done < <(
echo "$CONFIG" | jq -r '
.data
| keys[]
| select(test("^(virtio|scsi|sata|ide)[0-9]+$"))
'
)
# Build JSON
jq -n \
--arg vmid "$MAC" \
--arg vmhost "$NAME" \
--arg power "$STATUS" \
--arg hostname "$NAME" \
--arg os "$OS" \
--argjson cpu "$CPU" \
--argjson memory "$MEMORY_MB" \
--argjson snapshot "$SNAPSHOT_COUNT" \
--arg description "$DESCRIPTION" \
--argjson disks "$DISKS_JSON" \
--argjson ipv4 "$(printf '%s\n' "${IPV4[@]}" | jq -R . | jq -s .)" \
--argjson ipv6 "$(printf '%s\n' "${IPV6[@]}" | jq -R . | jq -s .)" \
--arg backup "$BACKUP_ENABLED" '
{
"server_vm_id": $vmid,
"server_vm_host_name": $vmhost,
"server_power_state": $power,
"server_state": "new",
"server_hostname": $hostname
}
+
(
if $os != "" then
{ "server_os": $os }
else
{}
end
)
+
{
"server_cpu": $cpu,
"server_memory": $memory,
"server_memory_demand": $memory,
"server_disks": $disks,
"server_ipv4": $ipv4,
"server_ipv6": $ipv6,
"server_vm_snapshot": $snapshot,
"server_backup":
(
if $backup == "yes" then
[{"+proxmox":"yes"}]
else
[]
end
),
"server_description": $description
}
' > "${OUTPUT_DIR}/${VMID}.json"
done
echo
echo "Done."
echo "JSON files written to: ${OUTPUT_DIR}/"