astrapi-backup 26.4.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- astrapi_backup-26.4.6/.claude-memory.md +121 -0
- astrapi_backup-26.4.6/.github/workflows/publish.yml +31 -0
- astrapi_backup-26.4.6/.gitignore +39 -0
- astrapi_backup-26.4.6/.gitlab-ci.yml +24 -0
- astrapi_backup-26.4.6/CLAUDE.md +3 -0
- astrapi_backup-26.4.6/PKG-INFO +18 -0
- astrapi_backup-26.4.6/README.md +80 -0
- astrapi_backup-26.4.6/astrapi_backup/__init__.py +1 -0
- astrapi_backup-26.4.6/astrapi_backup/_app.py +63 -0
- astrapi_backup-26.4.6/astrapi_backup/_cli.py +15 -0
- astrapi_backup-26.4.6/astrapi_backup/_paths.py +9 -0
- astrapi_backup-26.4.6/astrapi_backup/api/fastapi_app.py +48 -0
- astrapi_backup-26.4.6/astrapi_backup/api/routers/__init__.py +0 -0
- astrapi_backup-26.4.6/astrapi_backup/api/routers/run.py +249 -0
- astrapi_backup-26.4.6/astrapi_backup/api/storage.py +129 -0
- astrapi_backup-26.4.6/astrapi_backup/api/templates.py +100 -0
- astrapi_backup-26.4.6/astrapi_backup/app.yaml +2 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/borg/__init__.py +14 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/borg/api.py +488 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/borg/cache.py +120 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/borg/icon-outline.svg +1 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/borg/icon.svg +1 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/borg/jobs.py +334 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/borg/modul.yaml +19 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/borg/schema.yaml +61 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/borg/settings.yaml +112 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/borg/storage.py +215 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/borg/templates/modals/archives.html +56 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/borg/templates/modals/stats.html +55 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/borg/templates/partials/archives_list.html +73 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/borg/templates/partials/browse.html +290 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/borg/templates/partials/card_body.html +9 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/borg/templates/partials/list_header.html +2 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/borg/templates/partials/list_row.html +6 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/borg/templates/partials/stats_content.html +129 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/borg/ui.py +58 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/borg/utils.py +51 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/__init__.py +14 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/api.py +21 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/icon-outline.svg +1 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/icon.svg +1 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/jobs.py +182 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/modul.yaml +15 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/schema.yaml +9 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/settings.yaml +29 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/templates/modals/no_hosts.html +19 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/templates/partials/card_body.html +9 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/templates/partials/list_header.html +0 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/templates/partials/list_row.html +0 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/ui.py +174 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/__init__.py +16 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/api.py +81 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/icon-outline.svg +1 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/icon.svg +1 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/jobs.py +186 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/modul.yaml +15 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/schema.yaml +26 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/settings.yaml +3 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/templates/modals/create.html +53 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/templates/partials/available_select.html +24 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/templates/partials/card_body.html +6 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/templates/partials/list_header.html +2 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/templates/partials/list_row.html +16 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/ui.py +65 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/__init__.py +14 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/api.py +95 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/icon-outline.svg +1 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/icon.svg +1 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/jobs.py +229 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/modul.yaml +15 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/schema.yaml +23 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/settings.yaml +35 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/templates/modals/create.html +53 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/templates/partials/available_select.html +24 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/templates/partials/card_body.html +6 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/templates/partials/list_header.html +2 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/templates/partials/list_row.html +3 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/ui.py +97 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/remotes/__init__.py +33 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/remotes/api.py +152 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/remotes/engine.py +73 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/remotes/icon-outline.svg +1 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/remotes/icon.svg +1 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/remotes/jobs.py +152 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/remotes/modul.yaml +7 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/remotes/schema.yaml +116 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/remotes/templates/modals/power_check.html +24 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/remotes/templates/modals/ssh_check_results.html +32 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/remotes/templates/partials/card_body.html +39 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/remotes/templates/partials/extra_actions.html +9 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/remotes/templates/partials/list_header.html +3 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/remotes/templates/partials/list_row.html +24 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/remotes/templates/partials/page_actions.html +6 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/remotes/templates/partials/power_confirm.html +16 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/remotes/templates/partials/ssh_check_spinner.html +14 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/remotes/templates/partials/ssh_check_table.html +37 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/remotes/ui.py +137 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/rsync/__init__.py +15 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/rsync/api.py +11 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/rsync/icon-outline.svg +1 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/rsync/icon.svg +1 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/rsync/jobs.py +178 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/rsync/modul.yaml +15 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/rsync/schema.yaml +59 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/rsync/settings.yaml +14 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/rsync/templates/partials/card_body.html +21 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/rsync/templates/partials/list_header.html +3 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/rsync/templates/partials/list_row.html +13 -0
- astrapi_backup-26.4.6/astrapi_backup/modules/rsync/ui.py +66 -0
- astrapi_backup-26.4.6/astrapi_backup/navigation.yaml +29 -0
- astrapi_backup-26.4.6/astrapi_backup/overrides/system.py +76 -0
- astrapi_backup-26.4.6/astrapi_backup/runner.py +131 -0
- astrapi_backup-26.4.6/astrapi_backup/settings.py +1 -0
- astrapi_backup-26.4.6/astrapi_backup.egg-info/PKG-INFO +18 -0
- astrapi_backup-26.4.6/astrapi_backup.egg-info/SOURCES.txt +128 -0
- astrapi_backup-26.4.6/astrapi_backup.egg-info/dependency_links.txt +1 -0
- astrapi_backup-26.4.6/astrapi_backup.egg-info/entry_points.txt +2 -0
- astrapi_backup-26.4.6/astrapi_backup.egg-info/requires.txt +13 -0
- astrapi_backup-26.4.6/astrapi_backup.egg-info/top_level.txt +1 -0
- astrapi_backup-26.4.6/doku/app-db-schema.md +294 -0
- astrapi_backup-26.4.6/doku/tabellen-struktur.md +118 -0
- astrapi_backup-26.4.6/pyproject.toml +42 -0
- astrapi_backup-26.4.6/requirements.txt +43 -0
- astrapi_backup-26.4.6/setup.cfg +4 -0
- astrapi_backup-26.4.6/tests/e2e/conftest.py +69 -0
- astrapi_backup-26.4.6/tests/e2e/test_modal_close.py +197 -0
- astrapi_backup-26.4.6/tests/unit/__init__.py +0 -0
- astrapi_backup-26.4.6/tests/unit/conftest.py +65 -0
- astrapi_backup-26.4.6/tests/unit/test_scheduler_engine.py +448 -0
- astrapi_backup-26.4.6/tests/unit/test_template_resolution.py +119 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# astrapi-backup – Claude Memory
|
|
2
|
+
|
|
3
|
+
Projektkontext für Claude Code. Wird im Repo versioniert, damit es auf jedem PC verfügbar ist.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Was ist astrapi-backup?
|
|
8
|
+
|
|
9
|
+
Web-UI zur zentralen Verwaltung von Backup-Jobs (Borg, Rsync, Proxmox, Remote-Geräte).
|
|
10
|
+
Basiert auf **astrapi-core** (FastAPI + Flask + HTMX + Jinja2).
|
|
11
|
+
PyPI-Paketname: `astrapi-backup`, Python-Paket: `astrapi_backup`.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Stack
|
|
16
|
+
|
|
17
|
+
| Komponente | Details |
|
|
18
|
+
|---|---|
|
|
19
|
+
| Framework | astrapi-core (FastAPI + HTMX) |
|
|
20
|
+
| API | FastAPI (`/api/...`) |
|
|
21
|
+
| UI | FastAPI + HTMX + Jinja2 (`/`) – kein Flask mehr! |
|
|
22
|
+
| Persistenz | SQLite (über astrapi-core) |
|
|
23
|
+
| Verschlüsselung | Fernet (Secrets via astrapi-core) |
|
|
24
|
+
| Python | ≥ 3.11 |
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Verzeichnisstruktur
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
astrapi_backup/
|
|
32
|
+
├── _app.py # ASGI-App-Factory (uvicorn-Einstiegspunkt)
|
|
33
|
+
├── _cli.py # Console-Script: astrapi-backup
|
|
34
|
+
├── _paths.py # package_dir(), work_dir(), db_path(), log_dir()
|
|
35
|
+
├── app.yaml # name: astrapi-backup, display_name: Backup Control
|
|
36
|
+
├── navigation.yaml # App-Navigation (Borg, Rsync, Proxmox, Remotes)
|
|
37
|
+
├── runner.py # Job-Dispatcher
|
|
38
|
+
├── api/
|
|
39
|
+
│ ├── fastapi_app.py # FastAPI-Factory, Run-Router-Registrierung
|
|
40
|
+
│ ├── storage.py # SQLite-Tabellen (borg, rsync, proxmox_*, remotes)
|
|
41
|
+
│ ├── templates.py # Jinja2-ChoiceLoader
|
|
42
|
+
│ └── routers/
|
|
43
|
+
│ └── run.py # Generischer Run/Log/SSE-Router pro Modul
|
|
44
|
+
├── modules/
|
|
45
|
+
│ ├── borg/ # Borg-Backup-Modul
|
|
46
|
+
│ ├── rsync/ # Rsync-Modul
|
|
47
|
+
│ ├── proxmox_lxc/ # Proxmox LXC-Container
|
|
48
|
+
│ ├── proxmox_hosts/ # Proxmox-Host-Backups
|
|
49
|
+
│ ├── proxmox_jobs/ # Proxmox-Job-Verwaltung
|
|
50
|
+
│ └── remotes/ # Remote-Geräte (WoL, SSH)
|
|
51
|
+
└── overrides/
|
|
52
|
+
└── sysinfo.py # App-spezifische Sysinfo-Konfiguration
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## App-Start
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
astrapi-backup --work-dir /opt/astrapi-backup --port 5001
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
- `_configure_paths("astrapi-backup")` setzt Runtime-Pfade
|
|
64
|
+
- `configure_updater(_pkg)` registriert `astrapi-backup` + `astrapi-core` im Updater
|
|
65
|
+
- Secrets-Key: `/var/lib/backupadm/secret.key` (Prod), `astrapi_backup/secret.key` (Dev)
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Template-Struktur (Modul-Konvention)
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
templates/
|
|
73
|
+
├── content.html # Vollständiger Modul-Inhalt (page-header + Listenbereich)
|
|
74
|
+
├── partials/
|
|
75
|
+
│ ├── card_body.html # Card-Body-Snippet für list_wrapper_inner (content_template)
|
|
76
|
+
│ ├── list_header.html # Tabellen-Header-Spalten
|
|
77
|
+
│ ├── list_row.html # Tabellen-Zeilen-Spalten
|
|
78
|
+
│ └── ... # Weitere kleine HTMX-Fragmente
|
|
79
|
+
└── modals/
|
|
80
|
+
├── edit.html # Create/Edit-Dialog (falls modul-spezifisch)
|
|
81
|
+
├── create.html # Nur-Create-Dialog (z.B. proxmox_lxc, proxmox_jobs)
|
|
82
|
+
├── log.html # Log-Viewer
|
|
83
|
+
└── ... # Weitere modul-spezifische Dialoge
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Modul-Konvention (Run-Module)
|
|
89
|
+
|
|
90
|
+
Run-Module (borg, rsync, proxmox_lxc, proxmox_hosts, proxmox_jobs) haben zusätzlich:
|
|
91
|
+
|
|
92
|
+
| Datei | Inhalt |
|
|
93
|
+
|---|---|
|
|
94
|
+
| `jobs.py` | `run_single(item_id)` – wird von `run.py` aufgerufen |
|
|
95
|
+
| `api.py` | Zusätzliche FastAPI-Endpunkte (preview, archives, stats, …) |
|
|
96
|
+
|
|
97
|
+
Run-Router: `POST /api/{module}/{item_id}/run`, `GET /api/{module}/{item_id}/logs`
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Datenbank
|
|
102
|
+
|
|
103
|
+
Tabellen in `astrapi_backup/api/storage.py`: `borg`, `rsync`, `proxmox_lxc`, `proxmox_hosts`, `proxmox_jobs`, `remotes`.
|
|
104
|
+
YAML-Migration beim ersten Zugriff automatisch.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Versionsschema
|
|
109
|
+
|
|
110
|
+
CalVer: `YY.MM.patch.devN` – gesteuert via setuptools-scm + Git-Tags.
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Tests
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
pytest tests/unit/
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
- `conftest.py`: frische SQLite-DB je Test, isolierter Scheduler
|
|
121
|
+
- `test_template_resolution.py`: prüft alle `TemplateResponse`-Referenzen auf Auflösbarkeit
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
permissions:
|
|
12
|
+
id-token: write
|
|
13
|
+
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
with:
|
|
17
|
+
fetch-depth: 0 # nötig für setuptools-scm
|
|
18
|
+
|
|
19
|
+
- uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.12"
|
|
22
|
+
|
|
23
|
+
- name: Build
|
|
24
|
+
run: |
|
|
25
|
+
pip install --quiet build
|
|
26
|
+
python -m build --wheel --sdist
|
|
27
|
+
|
|
28
|
+
- name: Publish to PyPI
|
|
29
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
30
|
+
with:
|
|
31
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
|
|
6
|
+
# Virtuelle Umgebungen
|
|
7
|
+
.venv/
|
|
8
|
+
venv/
|
|
9
|
+
env/
|
|
10
|
+
|
|
11
|
+
# Build & Distribution
|
|
12
|
+
build/
|
|
13
|
+
dist/
|
|
14
|
+
*.zip
|
|
15
|
+
|
|
16
|
+
# Tests & Coverage
|
|
17
|
+
.pytest_cache/
|
|
18
|
+
.coverage
|
|
19
|
+
htmlcov/
|
|
20
|
+
|
|
21
|
+
# Laufzeitdaten (Dev: ./data/, ./logs/ – Prod: /var/lib/backupctl/)
|
|
22
|
+
data/
|
|
23
|
+
logs/
|
|
24
|
+
|
|
25
|
+
# Logs
|
|
26
|
+
*.log
|
|
27
|
+
|
|
28
|
+
# Secrets
|
|
29
|
+
.env
|
|
30
|
+
.env.*
|
|
31
|
+
*.key
|
|
32
|
+
|
|
33
|
+
# IDE
|
|
34
|
+
.idea/
|
|
35
|
+
.vscode/
|
|
36
|
+
|
|
37
|
+
# backupctl-spezifisch
|
|
38
|
+
.borg/
|
|
39
|
+
.release.env
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
stages:
|
|
2
|
+
- publish
|
|
3
|
+
|
|
4
|
+
publish:
|
|
5
|
+
stage: publish
|
|
6
|
+
image: python:3.12-slim
|
|
7
|
+
rules:
|
|
8
|
+
- if: '$CI_COMMIT_TAG =~ /^v/'
|
|
9
|
+
before_script:
|
|
10
|
+
- apt-get update -qq && apt-get install -y -qq git
|
|
11
|
+
- git fetch --tags
|
|
12
|
+
script:
|
|
13
|
+
- pip install --quiet build twine
|
|
14
|
+
- python -m build --wheel --sdist
|
|
15
|
+
- twine upload
|
|
16
|
+
--repository-url "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/pypi"
|
|
17
|
+
--username "__token__"
|
|
18
|
+
--password "$GITLAB_TOKEN_SECRET"
|
|
19
|
+
dist/*
|
|
20
|
+
- twine upload
|
|
21
|
+
--repository-url "https://gitlab.com/api/v4/projects/81004951/packages/pypi"
|
|
22
|
+
--username "__token__"
|
|
23
|
+
--password "$GITLAB_TOKEN_SECRET"
|
|
24
|
+
dist/*
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: astrapi-backup
|
|
3
|
+
Version: 26.4.6
|
|
4
|
+
Summary: Backup Control – Web-UI für Borg, Rsync, Proxmox
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Requires-Dist: fastapi>=0.115
|
|
7
|
+
Requires-Dist: uvicorn[standard]>=0.30
|
|
8
|
+
Requires-Dist: jinja2>=3.1
|
|
9
|
+
Requires-Dist: APScheduler>=3.10
|
|
10
|
+
Requires-Dist: pyyaml>=6.0
|
|
11
|
+
Requires-Dist: python-multipart>=0.0.9
|
|
12
|
+
Requires-Dist: cryptography>=42.0
|
|
13
|
+
Requires-Dist: requests>=2.32
|
|
14
|
+
Requires-Dist: urllib3>=2.2
|
|
15
|
+
Requires-Dist: psutil>=6.0
|
|
16
|
+
Requires-Dist: apispec>=6.0
|
|
17
|
+
Requires-Dist: astrapi-core>=26.4.15
|
|
18
|
+
Requires-Dist: borgbackup>=1.4.4
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# backupctl
|
|
2
|
+
|
|
3
|
+
Web-UI zur zentralen Verwaltung von Backup-Jobs (Borg, Rsync, Proxmox, Remote-Geräte).
|
|
4
|
+
|
|
5
|
+
## Dokumentation
|
|
6
|
+
|
|
7
|
+
- Deutsche Benutzeranleitung: [Benutzeranleitung.md](Benutzeranleitung.md)
|
|
8
|
+
|
|
9
|
+
## Voraussetzungen
|
|
10
|
+
|
|
11
|
+
- Python >= 3.11
|
|
12
|
+
- `astrapi-core` (lokales Repo, muss parallel geklont sein)
|
|
13
|
+
|
|
14
|
+
### Systemabhängigkeiten
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
apt install borgbackup wakeonlan openssh-client
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
> Borg wird unter `/var/lib/backupadm/.venv/bin/borg` erwartet.
|
|
21
|
+
|
|
22
|
+
## Setup nach dem Klonen
|
|
23
|
+
|
|
24
|
+
1. Virtuelles Environment erstellen und aktivieren:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
python -m venv .venv
|
|
28
|
+
source .venv/bin/activate
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
2. `astrapi-core` installieren (liegt als Schwesterprojekt neben diesem Repo):
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install -e ../astrapi-core
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
3. `backupctl` selbst installieren:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install -e .
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Starten
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
backupctl --work-dir data --port 9999
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**Mit Auto-Reload (Entwicklung):**
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
backupctl --work-dir data --port 9999 --reload
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
| Parameter | Standard | Beschreibung |
|
|
56
|
+
|--------------|-------------|-----------------------------------------|
|
|
57
|
+
| `--work-dir` | (Pflicht) | Datenpfad für SQLite-DB und Laufzeitdaten |
|
|
58
|
+
| `--port` | `5001` | HTTP-Port |
|
|
59
|
+
| `--host` | `0.0.0.0` | Bind-Adresse |
|
|
60
|
+
| `--reload` | – | Auto-Reload bei Dateiänderungen |
|
|
61
|
+
|
|
62
|
+
Die Web-Oberfläche ist danach erreichbar unter: `http://localhost:9999`
|
|
63
|
+
|
|
64
|
+
## Projektstruktur
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
backupctl/
|
|
68
|
+
├── _cli.py # Einstiegspunkt (CLI)
|
|
69
|
+
├── _app.py # ASGI-App-Factory
|
|
70
|
+
├── _paths.py # Pfad-Utilities
|
|
71
|
+
├── runner.py # Job-Executor (Borg, Rsync, Proxmox)
|
|
72
|
+
├── api/ # FastAPI-Router und SQLite-Backend
|
|
73
|
+
└── modules/ # Feature-Module
|
|
74
|
+
├── borg/
|
|
75
|
+
├── rsync/
|
|
76
|
+
├── proxmox_lxc/
|
|
77
|
+
├── proxmox_hosts/
|
|
78
|
+
├── proxmox_jobs/
|
|
79
|
+
└── remotes/
|
|
80
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# astrapi_backup
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""astrapi_backup._app – ASGI-App-Factory.
|
|
2
|
+
|
|
3
|
+
Wird von astrapi_backup._cli (Console-Script) und direkt von uvicorn importiert:
|
|
4
|
+
uvicorn astrapi_backup._app:app
|
|
5
|
+
"""
|
|
6
|
+
import time
|
|
7
|
+
|
|
8
|
+
from astrapi_core.system.paths import configure as _configure_paths
|
|
9
|
+
_configure_paths("astrapi-backup")
|
|
10
|
+
|
|
11
|
+
from fastapi import FastAPI
|
|
12
|
+
from fastapi.staticfiles import StaticFiles
|
|
13
|
+
|
|
14
|
+
from astrapi_core.ui import create as create_ui
|
|
15
|
+
from astrapi_core.ui.module_registry import load_modules
|
|
16
|
+
from astrapi_core.ui.settings_registry import init as settings_init
|
|
17
|
+
from astrapi_core.system.health import register_health
|
|
18
|
+
from astrapi_core.system.systemd import sd_notify, start_watchdog
|
|
19
|
+
from astrapi_core.system.version import get_display_name
|
|
20
|
+
from astrapi_core.modules.settings.engine import configure as configure_settings
|
|
21
|
+
from astrapi_core.modules.system.updater import configure as configure_updater
|
|
22
|
+
|
|
23
|
+
from astrapi_backup._paths import package_dir, work_dir
|
|
24
|
+
from astrapi_backup.api.fastapi_app import create as create_api
|
|
25
|
+
|
|
26
|
+
_START_TIME = time.time()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _db_check() -> tuple[bool, dict]:
|
|
30
|
+
from astrapi_core.system.db import _conn
|
|
31
|
+
try:
|
|
32
|
+
_conn().execute("SELECT 1").fetchone()
|
|
33
|
+
return True, {"db": True}
|
|
34
|
+
except Exception:
|
|
35
|
+
return False, {"db": False}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def create_app() -> FastAPI:
|
|
39
|
+
_pkg = package_dir()
|
|
40
|
+
configure_settings(health_fn=_db_check, app_name=get_display_name(_pkg))
|
|
41
|
+
configure_updater(_pkg)
|
|
42
|
+
|
|
43
|
+
from astrapi_backup.api.storage import init_db
|
|
44
|
+
init_db()
|
|
45
|
+
|
|
46
|
+
settings_init(work_dir())
|
|
47
|
+
modules, _ = load_modules(_pkg)
|
|
48
|
+
api = create_api(modules=modules)
|
|
49
|
+
|
|
50
|
+
import astrapi_core.ui
|
|
51
|
+
from pathlib import Path
|
|
52
|
+
core_static = Path(astrapi_core.ui.__file__).parent / "static"
|
|
53
|
+
api.mount("/static", StaticFiles(directory=str(core_static)), name="static")
|
|
54
|
+
|
|
55
|
+
create_ui(api, app_root=_pkg, modules=modules)
|
|
56
|
+
|
|
57
|
+
register_health(api, check_fn=_db_check, start_time=_START_TIME)
|
|
58
|
+
start_watchdog(check_fn=lambda: _db_check()[0])
|
|
59
|
+
sd_notify("READY=1")
|
|
60
|
+
return api
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
app = create_app()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""astrapi_backup._cli – Console-Script-Einstiegspunkt.
|
|
2
|
+
|
|
3
|
+
Start:
|
|
4
|
+
astrapi-backup --work-dir /opt/astrapi-backup --port 5001
|
|
5
|
+
astrapi-backup --work-dir /opt/astrapi-backup --port 5001 --debug # Debug-Modus (inkl. reload)
|
|
6
|
+
"""
|
|
7
|
+
from astrapi_core.system.paths import run_app
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def main() -> None:
|
|
11
|
+
run_app("astrapi_backup._app:app", "astrapi-backup", default_port=5001)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
if __name__ == "__main__":
|
|
15
|
+
main()
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# astrapi_backup/_paths.py
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from astrapi_core.system.paths import work_dir, db_path, log_dir # noqa: F401 – re-export
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def package_dir() -> Path:
|
|
8
|
+
"""Pfad zum installierten Package – für app.yaml, Templates, Modul-YAMLs."""
|
|
9
|
+
return Path(__file__).resolve().parent
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""astrapi_backup.api.fastapi_app – FastAPI-Factory."""
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from fastapi import FastAPI
|
|
4
|
+
from astrapi_core.system.version import get_app_version
|
|
5
|
+
|
|
6
|
+
from astrapi_backup._paths import package_dir, log_dir
|
|
7
|
+
|
|
8
|
+
APP_ROOT = package_dir()
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def create(modules: list | None = None) -> FastAPI:
|
|
12
|
+
"""Erstellt die FastAPI-Anwendung.
|
|
13
|
+
|
|
14
|
+
modules: Vorgeladene Modulliste (z.B. aus _app.py). Wird nicht neu geladen
|
|
15
|
+
wenn angegeben – verhindert doppelten Modulaufruf.
|
|
16
|
+
"""
|
|
17
|
+
_version = get_app_version(APP_ROOT, default="1.0.0")
|
|
18
|
+
app = FastAPI(
|
|
19
|
+
title="BackupCtl API",
|
|
20
|
+
version=_version,
|
|
21
|
+
docs_url="/api/docs",
|
|
22
|
+
redoc_url="/api/redoc",
|
|
23
|
+
openapi_url="/api/openapi.json",
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
from astrapi_core.system.logger import configure_log_root
|
|
27
|
+
configure_log_root(log_dir())
|
|
28
|
+
|
|
29
|
+
from astrapi_core.system.secrets import configure as configure_secrets
|
|
30
|
+
configure_secrets(
|
|
31
|
+
key_path = Path("/var/lib/backupadm/secret.key"),
|
|
32
|
+
dev_key_path = package_dir() / "secret.key",
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
# ── Modul-Router registrieren (nur laden wenn nicht übergeben) ────────────────────
|
|
36
|
+
from astrapi_core.ui.module_registry import load_modules, register_fastapi_modules
|
|
37
|
+
if modules is None:
|
|
38
|
+
modules, _ = load_modules(APP_ROOT)
|
|
39
|
+
register_fastapi_modules(app, modules)
|
|
40
|
+
|
|
41
|
+
# ── Run/Log-Router pro Modul (Framework-Standard: /api/{module}/{item}/run) ─
|
|
42
|
+
from astrapi_backup.api.routers.run import make_run_router
|
|
43
|
+
_RUN_MODULES = ["borg", "rsync", "proxmox_lxc", "proxmox_hosts", "proxmox_jobs"]
|
|
44
|
+
for _mod_key in _RUN_MODULES:
|
|
45
|
+
app.include_router(make_run_router(_mod_key), prefix=f"/api/{_mod_key}")
|
|
46
|
+
app.include_router(make_run_router(_mod_key), prefix=f"/ui/{_mod_key}")
|
|
47
|
+
|
|
48
|
+
return app
|
|
File without changes
|