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.
Files changed (130) hide show
  1. astrapi_backup-26.4.6/.claude-memory.md +121 -0
  2. astrapi_backup-26.4.6/.github/workflows/publish.yml +31 -0
  3. astrapi_backup-26.4.6/.gitignore +39 -0
  4. astrapi_backup-26.4.6/.gitlab-ci.yml +24 -0
  5. astrapi_backup-26.4.6/CLAUDE.md +3 -0
  6. astrapi_backup-26.4.6/PKG-INFO +18 -0
  7. astrapi_backup-26.4.6/README.md +80 -0
  8. astrapi_backup-26.4.6/astrapi_backup/__init__.py +1 -0
  9. astrapi_backup-26.4.6/astrapi_backup/_app.py +63 -0
  10. astrapi_backup-26.4.6/astrapi_backup/_cli.py +15 -0
  11. astrapi_backup-26.4.6/astrapi_backup/_paths.py +9 -0
  12. astrapi_backup-26.4.6/astrapi_backup/api/fastapi_app.py +48 -0
  13. astrapi_backup-26.4.6/astrapi_backup/api/routers/__init__.py +0 -0
  14. astrapi_backup-26.4.6/astrapi_backup/api/routers/run.py +249 -0
  15. astrapi_backup-26.4.6/astrapi_backup/api/storage.py +129 -0
  16. astrapi_backup-26.4.6/astrapi_backup/api/templates.py +100 -0
  17. astrapi_backup-26.4.6/astrapi_backup/app.yaml +2 -0
  18. astrapi_backup-26.4.6/astrapi_backup/modules/borg/__init__.py +14 -0
  19. astrapi_backup-26.4.6/astrapi_backup/modules/borg/api.py +488 -0
  20. astrapi_backup-26.4.6/astrapi_backup/modules/borg/cache.py +120 -0
  21. astrapi_backup-26.4.6/astrapi_backup/modules/borg/icon-outline.svg +1 -0
  22. astrapi_backup-26.4.6/astrapi_backup/modules/borg/icon.svg +1 -0
  23. astrapi_backup-26.4.6/astrapi_backup/modules/borg/jobs.py +334 -0
  24. astrapi_backup-26.4.6/astrapi_backup/modules/borg/modul.yaml +19 -0
  25. astrapi_backup-26.4.6/astrapi_backup/modules/borg/schema.yaml +61 -0
  26. astrapi_backup-26.4.6/astrapi_backup/modules/borg/settings.yaml +112 -0
  27. astrapi_backup-26.4.6/astrapi_backup/modules/borg/storage.py +215 -0
  28. astrapi_backup-26.4.6/astrapi_backup/modules/borg/templates/modals/archives.html +56 -0
  29. astrapi_backup-26.4.6/astrapi_backup/modules/borg/templates/modals/stats.html +55 -0
  30. astrapi_backup-26.4.6/astrapi_backup/modules/borg/templates/partials/archives_list.html +73 -0
  31. astrapi_backup-26.4.6/astrapi_backup/modules/borg/templates/partials/browse.html +290 -0
  32. astrapi_backup-26.4.6/astrapi_backup/modules/borg/templates/partials/card_body.html +9 -0
  33. astrapi_backup-26.4.6/astrapi_backup/modules/borg/templates/partials/list_header.html +2 -0
  34. astrapi_backup-26.4.6/astrapi_backup/modules/borg/templates/partials/list_row.html +6 -0
  35. astrapi_backup-26.4.6/astrapi_backup/modules/borg/templates/partials/stats_content.html +129 -0
  36. astrapi_backup-26.4.6/astrapi_backup/modules/borg/ui.py +58 -0
  37. astrapi_backup-26.4.6/astrapi_backup/modules/borg/utils.py +51 -0
  38. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/__init__.py +14 -0
  39. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/api.py +21 -0
  40. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/icon-outline.svg +1 -0
  41. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/icon.svg +1 -0
  42. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/jobs.py +182 -0
  43. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/modul.yaml +15 -0
  44. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/schema.yaml +9 -0
  45. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/settings.yaml +29 -0
  46. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/templates/modals/no_hosts.html +19 -0
  47. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/templates/partials/card_body.html +9 -0
  48. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/templates/partials/list_header.html +0 -0
  49. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/templates/partials/list_row.html +0 -0
  50. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_hosts/ui.py +174 -0
  51. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/__init__.py +16 -0
  52. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/api.py +81 -0
  53. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/icon-outline.svg +1 -0
  54. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/icon.svg +1 -0
  55. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/jobs.py +186 -0
  56. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/modul.yaml +15 -0
  57. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/schema.yaml +26 -0
  58. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/settings.yaml +3 -0
  59. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/templates/modals/create.html +53 -0
  60. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/templates/partials/available_select.html +24 -0
  61. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/templates/partials/card_body.html +6 -0
  62. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/templates/partials/list_header.html +2 -0
  63. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/templates/partials/list_row.html +16 -0
  64. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_jobs/ui.py +65 -0
  65. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/__init__.py +14 -0
  66. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/api.py +95 -0
  67. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/icon-outline.svg +1 -0
  68. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/icon.svg +1 -0
  69. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/jobs.py +229 -0
  70. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/modul.yaml +15 -0
  71. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/schema.yaml +23 -0
  72. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/settings.yaml +35 -0
  73. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/templates/modals/create.html +53 -0
  74. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/templates/partials/available_select.html +24 -0
  75. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/templates/partials/card_body.html +6 -0
  76. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/templates/partials/list_header.html +2 -0
  77. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/templates/partials/list_row.html +3 -0
  78. astrapi_backup-26.4.6/astrapi_backup/modules/proxmox_lxc/ui.py +97 -0
  79. astrapi_backup-26.4.6/astrapi_backup/modules/remotes/__init__.py +33 -0
  80. astrapi_backup-26.4.6/astrapi_backup/modules/remotes/api.py +152 -0
  81. astrapi_backup-26.4.6/astrapi_backup/modules/remotes/engine.py +73 -0
  82. astrapi_backup-26.4.6/astrapi_backup/modules/remotes/icon-outline.svg +1 -0
  83. astrapi_backup-26.4.6/astrapi_backup/modules/remotes/icon.svg +1 -0
  84. astrapi_backup-26.4.6/astrapi_backup/modules/remotes/jobs.py +152 -0
  85. astrapi_backup-26.4.6/astrapi_backup/modules/remotes/modul.yaml +7 -0
  86. astrapi_backup-26.4.6/astrapi_backup/modules/remotes/schema.yaml +116 -0
  87. astrapi_backup-26.4.6/astrapi_backup/modules/remotes/templates/modals/power_check.html +24 -0
  88. astrapi_backup-26.4.6/astrapi_backup/modules/remotes/templates/modals/ssh_check_results.html +32 -0
  89. astrapi_backup-26.4.6/astrapi_backup/modules/remotes/templates/partials/card_body.html +39 -0
  90. astrapi_backup-26.4.6/astrapi_backup/modules/remotes/templates/partials/extra_actions.html +9 -0
  91. astrapi_backup-26.4.6/astrapi_backup/modules/remotes/templates/partials/list_header.html +3 -0
  92. astrapi_backup-26.4.6/astrapi_backup/modules/remotes/templates/partials/list_row.html +24 -0
  93. astrapi_backup-26.4.6/astrapi_backup/modules/remotes/templates/partials/page_actions.html +6 -0
  94. astrapi_backup-26.4.6/astrapi_backup/modules/remotes/templates/partials/power_confirm.html +16 -0
  95. astrapi_backup-26.4.6/astrapi_backup/modules/remotes/templates/partials/ssh_check_spinner.html +14 -0
  96. astrapi_backup-26.4.6/astrapi_backup/modules/remotes/templates/partials/ssh_check_table.html +37 -0
  97. astrapi_backup-26.4.6/astrapi_backup/modules/remotes/ui.py +137 -0
  98. astrapi_backup-26.4.6/astrapi_backup/modules/rsync/__init__.py +15 -0
  99. astrapi_backup-26.4.6/astrapi_backup/modules/rsync/api.py +11 -0
  100. astrapi_backup-26.4.6/astrapi_backup/modules/rsync/icon-outline.svg +1 -0
  101. astrapi_backup-26.4.6/astrapi_backup/modules/rsync/icon.svg +1 -0
  102. astrapi_backup-26.4.6/astrapi_backup/modules/rsync/jobs.py +178 -0
  103. astrapi_backup-26.4.6/astrapi_backup/modules/rsync/modul.yaml +15 -0
  104. astrapi_backup-26.4.6/astrapi_backup/modules/rsync/schema.yaml +59 -0
  105. astrapi_backup-26.4.6/astrapi_backup/modules/rsync/settings.yaml +14 -0
  106. astrapi_backup-26.4.6/astrapi_backup/modules/rsync/templates/partials/card_body.html +21 -0
  107. astrapi_backup-26.4.6/astrapi_backup/modules/rsync/templates/partials/list_header.html +3 -0
  108. astrapi_backup-26.4.6/astrapi_backup/modules/rsync/templates/partials/list_row.html +13 -0
  109. astrapi_backup-26.4.6/astrapi_backup/modules/rsync/ui.py +66 -0
  110. astrapi_backup-26.4.6/astrapi_backup/navigation.yaml +29 -0
  111. astrapi_backup-26.4.6/astrapi_backup/overrides/system.py +76 -0
  112. astrapi_backup-26.4.6/astrapi_backup/runner.py +131 -0
  113. astrapi_backup-26.4.6/astrapi_backup/settings.py +1 -0
  114. astrapi_backup-26.4.6/astrapi_backup.egg-info/PKG-INFO +18 -0
  115. astrapi_backup-26.4.6/astrapi_backup.egg-info/SOURCES.txt +128 -0
  116. astrapi_backup-26.4.6/astrapi_backup.egg-info/dependency_links.txt +1 -0
  117. astrapi_backup-26.4.6/astrapi_backup.egg-info/entry_points.txt +2 -0
  118. astrapi_backup-26.4.6/astrapi_backup.egg-info/requires.txt +13 -0
  119. astrapi_backup-26.4.6/astrapi_backup.egg-info/top_level.txt +1 -0
  120. astrapi_backup-26.4.6/doku/app-db-schema.md +294 -0
  121. astrapi_backup-26.4.6/doku/tabellen-struktur.md +118 -0
  122. astrapi_backup-26.4.6/pyproject.toml +42 -0
  123. astrapi_backup-26.4.6/requirements.txt +43 -0
  124. astrapi_backup-26.4.6/setup.cfg +4 -0
  125. astrapi_backup-26.4.6/tests/e2e/conftest.py +69 -0
  126. astrapi_backup-26.4.6/tests/e2e/test_modal_close.py +197 -0
  127. astrapi_backup-26.4.6/tests/unit/__init__.py +0 -0
  128. astrapi_backup-26.4.6/tests/unit/conftest.py +65 -0
  129. astrapi_backup-26.4.6/tests/unit/test_scheduler_engine.py +448 -0
  130. 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,3 @@
1
+ # astrapi-backup
2
+
3
+ @.claude-memory.md
@@ -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