Files
PVE-Backup-Report/README.md
T

220 lines
8.5 KiB
Markdown

# 📄 PVE Backup Report
![Version](https://img.shields.io/badge/version-1.0.0-blue)
![Python](https://img.shields.io/badge/python-3.11%2B-green)
![License](https://img.shields.io/badge/license-Apache--2.0-orange)
![Docker](https://img.shields.io/badge/docker-ready-2496ED)
![Security](https://img.shields.io/badge/security-no_PVE%2FPBS_writes-brightgreen)
Python tool to generate a daily backup report for Proxmox VE against Proxmox Backup Server.
## ✨ Features
- 📄 Timestamped daily PDF report, without overwriting previous reports.
- 🧭 Inventory of PBS storages declared in Proxmox VE.
- ✅ Coverage analysis for QEMU VMs and LXC containers.
- 📝 PVE VM/CT notes included in the report.
- 🕒 Retrieval of the latest known backups via PVE tasks and `vzdump` logs.
- 🗄️ Optional collection of PBS datastores, namespaces, prune jobs, snapshots and storage usage.
- 🔐 Audit of PBS backup accounts and effective permissions.
- 📊 PBS retention with expected version counts, delta and PVE state for VM/CT entries.
- ⚠️ Anomalies section for errors or partial collection data.
- 🐳 Recommended execution with Docker, or direct CLI execution.
## 🔐 Prerequisites
Create dedicated API users or tokens for this reporting application. They must be limited to audit/read-only permissions:
- Proxmox VE: assign only the `PVEAuditor` role to the user or API token used by `PVE_API_TOKEN_ID`.
- Proxmox Backup Server: assign only the `Audit` role to the user or API token used by each `PBS<number>_API_TOKEN_ID`.
Do not use administrator or write-enabled accounts. The application only needs to read inventory, backup jobs, tasks, datastores, namespaces, snapshots and retention data.
## 🐳 Usage with Docker
Docker is the recommended execution mode. The image includes the Python dependencies and system libraries required by WeasyPrint.
### 📦 Setup
```sh
cp .env.example .env
mkdir -p reports
```
Then edit `.env` with your PVE cluster and PBS connection details.
In Docker, keep:
```env
REPORT_OUTPUT_DIR=/reports
```
The `compose.yaml` file mounts the local `./reports` directory into the container at `/reports`. Generated PDFs are therefore visible on the host in `./reports/`.
### ⚙️ Minimal configuration
```env
PVE_API_URL=https://pve.example.invalid:8006
PVE_API_TOKEN_ID=backup-report@pve!report
PVE_API_TOKEN_SECRET=change-me
REPORT_OUTPUT_DIR=/reports
REPORT_TIMEZONE=Europe/Paris
REPORT_LANGUAGE=fr
PVE_VERIFY_TLS=true
```
To enable PBS collection, provide the URL, token ID and secret for the relevant PBS. An incomplete configuration does not enable PBS collection.
Example with one PBS:
```env
PBS01_NAME=nom-affiche
PBS01_API_URL=https://backup.example.invalid:8007
PBS01_API_TOKEN_ID=
PBS01_API_TOKEN_SECRET=
```
One or more PBS servers can be configured. To add a server, duplicate the block and increment the prefix number: `PBS02_*`, `PBS03_*`, `PBS04_*`, etc. The application automatically detects all `PBS<number>_*` blocks present in the environment.
### 🏗️ Build
```sh
docker compose build
```
### ✅ Verification
```sh
docker compose run --rm pve-backup-report --check-config
docker compose run --rm pve-backup-report --check-api
```
`--check-api` tests the main PVE endpoints. If `/cluster/backup` returns `HTTP 403 - Permission check failed (/, Sys.Audit)`, the token works but is missing the `Sys.Audit` privilege on `/`.
### 📄 Generating the report
```sh
docker compose run --rm pve-backup-report --generate-pdf
```
The PDF report is written to `./reports/` with a timestamped filename and never overwrites a previous report.
### 🧪 Docker diagnostic commands
```sh
docker compose run --rm pve-backup-report --dump-inventory
docker compose run --rm pve-backup-report --dump-coverage
docker compose run --rm pve-backup-report --dump-report-data
docker compose run --rm pve-backup-report --dump-pbs-storage-usages
docker compose run --rm pve-backup-report --dump-pbs-users
docker compose run --rm pve-backup-report --debug-last-backup-vmid <VMID>
```
Running the container without arguments only executes the default `pve-backup-report` command. To generate a PDF, use `--generate-pdf` explicitly.
### 🕒 Scheduling with cron and Docker
Example crontab on the host to run the report every day at 02:00:
```cron
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
0 2 * * * cd /srv/pve-backup-report && /usr/bin/flock -n /tmp/pve-backup-report.lock /usr/bin/docker compose run --rm pve-backup-report --generate-pdf >> /var/log/pve-backup-report.log 2>&1
```
Replace `/srv/pve-backup-report` with the actual path to the repository. The `cd` is important: Docker Compose finds `compose.yaml` there and the application loads `.env` from it.
## 💻 Direct command-line usage
This mode is useful for development or diagnostics outside a container. The host must have Python, the project's Python dependencies and the system libraries required by WeasyPrint.
### 📦 Local installation
```sh
python3 -m venv .venv
. .venv/bin/activate
python -m ensurepip --upgrade
pip install -r requirements.txt
pip install -e .
```
To run the tests:
```sh
pip install -e ".[dev]"
pytest
```
### 🧰 Installed commands
```sh
pve-backup-report --check-config
pve-backup-report --check-api
pve-backup-report --dump-inventory
pve-backup-report --dump-coverage
pve-backup-report --dump-report-data
pve-backup-report --dump-pbs-storage-usages
pve-backup-report --dump-pbs-users
pve-backup-report --generate-pdf
pve-backup-report --debug-last-backup-vmid <VMID>
```
Without an editable install, from the repository:
```sh
PYTHONPATH=src python3 -m pve_backup_report --check-config
PYTHONPATH=src python3 -m pve_backup_report --check-api
PYTHONPATH=src python3 -m pve_backup_report --dump-inventory
PYTHONPATH=src python3 -m pve_backup_report --dump-coverage
PYTHONPATH=src python3 -m pve_backup_report --dump-report-data
PYTHONPATH=src python3 -m pve_backup_report --dump-pbs-storage-usages
PYTHONPATH=src python3 -m pve_backup_report --dump-pbs-users
PYTHONPATH=src python3 -m pve_backup_report --generate-pdf
PYTHONPATH=src python3 -m pve_backup_report --debug-last-backup-vmid <VMID>
```
In direct local execution, `REPORT_OUTPUT_DIR` can remain `reports/` or point to any other directory writable by the current user.
The same `.env` file can be used in Docker and in local execution. If `REPORT_OUTPUT_DIR=/reports` is kept outside Docker and `/reports` is not accessible, the application automatically falls back to the local `reports/` directory and logs the fallback.
### 🕒 Scheduling with cron without Docker
Example using the project's virtual environment:
```cron
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
0 2 * * * cd /srv/pve-backup-report && /usr/bin/flock -n /tmp/pve-backup-report.lock /srv/pve-backup-report/.venv/bin/pve-backup-report --generate-pdf >> /var/log/pve-backup-report.log 2>&1
```
The user running the crontab must have read access to `.env` and write access to `REPORT_OUTPUT_DIR`.
## 🔧 Key variables
| Variable | Description |
| --- | --- |
| `PVE_API_URL` | URL of a reachable PVE node, e.g. `https://pve.example.invalid:8006`. |
| `PVE_API_TOKEN_ID` | Full token identifier, e.g. `backup-report@pve!report`. |
| `PVE_API_TOKEN_SECRET` | Token secret. |
| `REPORT_LANGUAGE` | PDF report language, `fr` or `en`. Default: `fr`. |
| `PVE_VERIFY_TLS` | Keep `true` in production; use `PVE_CA_BUNDLE` for an internal CA. |
| `PVE_TASK_HISTORY_LIMIT` | Number of recent PVE tasks inspected to find the latest backup. |
| `PVE_TASK_LOG_LIMIT` | Number of lines retrieved per `vzdump` log to extract per-VM/CT detail. |
| `PBS_HOSTNAMES` | Optional manual mapping of PBS servers as `address=display-name,address2=display-name2`. |
| `PBS<number>_*` | Optional PBS API configurations, e.g. `PBS01_*`, `PBS02_*`, `PBS10_*`. |
| `REPORT_FILENAME_PREFIX` | Prefix for the generated PDF filename. |
## 📄 PDF output
`--generate-pdf` generates a timestamped PDF in `REPORT_OUTPUT_DIR`. The `Last backup` column shows the status, date, time and duration when PVE provides that information. The `PBS VM/CT backup retention <PBS>` tables are split by namespace and show the datastore, the number of PBS versions, and the oldest and most recent backup visible on each configured PBS.
🤖 AI Usage
The application was entirely coded using Codex and Claude Code. I would never have had enough time to build the application on my own in such a short period of time.
## ⚖️ License
This project is distributed under the Apache License 2.0. See the `LICENSE` file.