# ๐Ÿ“„ 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_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_*` 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 ``` 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 ``` 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 ``` 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_*` | 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 ` 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.