226 lines
9.0 KiB
Markdown
226 lines
9.0 KiB
Markdown
# 📄 PVE Backup Report
|
|
|
|

|
|

|
|

|
|

|
|

|
|
|
|
Python tool to generate a daily backup report for Proxmox VE against Proxmox Backup Server.
|
|
|
|
## Documentation
|
|
|
|
- 🇫🇷 [French version](README.fr.md)
|
|
- 🇬🇧 Documentation: [architecture](docs/en/architecture.md), [configuration](docs/en/configuration.md), [PVE API](docs/en/api-pve.md), [PBS API](docs/en/api-pbs.md), [PDF report](docs/en/rapport-pdf.md), [operations](docs/en/exploitation.md)
|
|
- 🇫🇷 Documentation : [architecture](docs/architecture.md), [configuration](docs/configuration.md), [API PVE](docs/api-pve.md), [API PBS](docs/api-pbs.md), [rapport PDF](docs/rapport-pdf.md), [exploitation](docs/exploitation.md)
|
|
|
|
## ✨ 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.
|