biblio-uplift 0.1.0__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.
- biblio_uplift-0.1.0/LICENSE +21 -0
- biblio_uplift-0.1.0/PKG-INFO +348 -0
- biblio_uplift-0.1.0/README.md +308 -0
- biblio_uplift-0.1.0/pyproject.toml +90 -0
- biblio_uplift-0.1.0/setup.cfg +4 -0
- biblio_uplift-0.1.0/src/biblio_uplift/__init__.py +1 -0
- biblio_uplift-0.1.0/src/biblio_uplift/__main__.py +4 -0
- biblio_uplift-0.1.0/src/biblio_uplift/cli/__init__.py +0 -0
- biblio_uplift-0.1.0/src/biblio_uplift/cli/main.py +1167 -0
- biblio_uplift-0.1.0/src/biblio_uplift/config/__init__.py +3 -0
- biblio_uplift-0.1.0/src/biblio_uplift/config/loader.py +38 -0
- biblio_uplift-0.1.0/src/biblio_uplift/config/schema.py +105 -0
- biblio_uplift-0.1.0/src/biblio_uplift/core/__init__.py +0 -0
- biblio_uplift-0.1.0/src/biblio_uplift/core/pipeline.py +258 -0
- biblio_uplift-0.1.0/src/biblio_uplift/core/ssh.py +239 -0
- biblio_uplift-0.1.0/src/biblio_uplift/core/state.py +62 -0
- biblio_uplift-0.1.0/src/biblio_uplift/core/steps/__init__.py +36 -0
- biblio_uplift-0.1.0/src/biblio_uplift/core/steps/backup.py +145 -0
- biblio_uplift-0.1.0/src/biblio_uplift/core/steps/cleanup.py +267 -0
- biblio_uplift-0.1.0/src/biblio_uplift/core/steps/docker.py +72 -0
- biblio_uplift-0.1.0/src/biblio_uplift/core/steps/git.py +113 -0
- biblio_uplift-0.1.0/src/biblio_uplift/core/steps/healthcheck.py +104 -0
- biblio_uplift-0.1.0/src/biblio_uplift/core/steps/hooks.py +38 -0
- biblio_uplift-0.1.0/src/biblio_uplift/core/steps/preflight.py +134 -0
- biblio_uplift-0.1.0/src/biblio_uplift/core/steps/system.py +94 -0
- biblio_uplift-0.1.0/src/biblio_uplift/core/tools/__init__.py +42 -0
- biblio_uplift-0.1.0/src/biblio_uplift/core/tools/docker.py +551 -0
- biblio_uplift-0.1.0/src/biblio_uplift/core/tools/network.py +109 -0
- biblio_uplift-0.1.0/src/biblio_uplift/core/tools/security.py +75 -0
- biblio_uplift-0.1.0/src/biblio_uplift/core/tools/system.py +135 -0
- biblio_uplift-0.1.0/src/biblio_uplift/core/tools/users.py +119 -0
- biblio_uplift-0.1.0/src/biblio_uplift/examples/__init__.py +0 -0
- biblio_uplift-0.1.0/src/biblio_uplift/examples/example.yml +24 -0
- biblio_uplift-0.1.0/src/biblio_uplift/history/__init__.py +10 -0
- biblio_uplift-0.1.0/src/biblio_uplift/history/audit.py +376 -0
- biblio_uplift-0.1.0/src/biblio_uplift/paths.py +51 -0
- biblio_uplift-0.1.0/src/biblio_uplift/settings.py +180 -0
- biblio_uplift-0.1.0/src/biblio_uplift/tui/__init__.py +0 -0
- biblio_uplift-0.1.0/src/biblio_uplift/tui/app.py +113 -0
- biblio_uplift-0.1.0/src/biblio_uplift/tui/css/app.tcss +307 -0
- biblio_uplift-0.1.0/src/biblio_uplift/tui/screens/__init__.py +0 -0
- biblio_uplift-0.1.0/src/biblio_uplift/tui/screens/about.py +186 -0
- biblio_uplift-0.1.0/src/biblio_uplift/tui/screens/backups.py +177 -0
- biblio_uplift-0.1.0/src/biblio_uplift/tui/screens/cleanup.py +195 -0
- biblio_uplift-0.1.0/src/biblio_uplift/tui/screens/config_edit.py +456 -0
- biblio_uplift-0.1.0/src/biblio_uplift/tui/screens/dashboard.py +132 -0
- biblio_uplift-0.1.0/src/biblio_uplift/tui/screens/history.py +61 -0
- biblio_uplift-0.1.0/src/biblio_uplift/tui/screens/server_status.py +268 -0
- biblio_uplift-0.1.0/src/biblio_uplift/tui/screens/settings.py +138 -0
- biblio_uplift-0.1.0/src/biblio_uplift/tui/screens/tools.py +181 -0
- biblio_uplift-0.1.0/src/biblio_uplift/tui/screens/upgrade.py +226 -0
- biblio_uplift-0.1.0/src/biblio_uplift/tui/widgets/__init__.py +0 -0
- biblio_uplift-0.1.0/src/biblio_uplift/tui/widgets/sidebar.py +142 -0
- biblio_uplift-0.1.0/src/biblio_uplift.egg-info/PKG-INFO +348 -0
- biblio_uplift-0.1.0/src/biblio_uplift.egg-info/SOURCES.txt +70 -0
- biblio_uplift-0.1.0/src/biblio_uplift.egg-info/dependency_links.txt +1 -0
- biblio_uplift-0.1.0/src/biblio_uplift.egg-info/entry_points.txt +2 -0
- biblio_uplift-0.1.0/src/biblio_uplift.egg-info/requires.txt +17 -0
- biblio_uplift-0.1.0/src/biblio_uplift.egg-info/top_level.txt +1 -0
- biblio_uplift-0.1.0/tests/test_audit_sqlite.py +257 -0
- biblio_uplift-0.1.0/tests/test_cli.py +1303 -0
- biblio_uplift-0.1.0/tests/test_config.py +196 -0
- biblio_uplift-0.1.0/tests/test_coverage_gaps.py +1036 -0
- biblio_uplift-0.1.0/tests/test_history.py +54 -0
- biblio_uplift-0.1.0/tests/test_main_entry.py +8 -0
- biblio_uplift-0.1.0/tests/test_paths.py +53 -0
- biblio_uplift-0.1.0/tests/test_pipeline.py +312 -0
- biblio_uplift-0.1.0/tests/test_settings.py +43 -0
- biblio_uplift-0.1.0/tests/test_ssh.py +213 -0
- biblio_uplift-0.1.0/tests/test_state.py +33 -0
- biblio_uplift-0.1.0/tests/test_steps.py +457 -0
- biblio_uplift-0.1.0/tests/test_tools.py +90 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Cody Lusk
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: biblio-uplift
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: TUI and CLI tool for managing Docker Compose service upgrades on remote servers via SSH
|
|
5
|
+
Author: Cody Lusk
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/cody-bibliocommons/biblio-uplift
|
|
8
|
+
Project-URL: Repository, https://github.com/cody-bibliocommons/biblio-uplift
|
|
9
|
+
Project-URL: Issues, https://github.com/cody-bibliocommons/biblio-uplift/issues
|
|
10
|
+
Keywords: docker,compose,ssh,upgrade,tui,devops
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: System Administrators
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: System :: Systems Administration
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: textual==8.2.5
|
|
24
|
+
Requires-Dist: rich==15.0.0
|
|
25
|
+
Requires-Dist: click==8.3.3
|
|
26
|
+
Requires-Dist: pydantic==2.13.3
|
|
27
|
+
Requires-Dist: pyyaml==6.0.3
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest==9.0.3; extra == "dev"
|
|
30
|
+
Requires-Dist: pytest-cov==7.1.0; extra == "dev"
|
|
31
|
+
Requires-Dist: bandit==1.9.4; extra == "dev"
|
|
32
|
+
Requires-Dist: safety==3.7.0; extra == "dev"
|
|
33
|
+
Requires-Dist: mypy==1.20.2; extra == "dev"
|
|
34
|
+
Requires-Dist: ruff==0.15.12; extra == "dev"
|
|
35
|
+
Requires-Dist: types-PyYAML==6.0.12.20260408; extra == "dev"
|
|
36
|
+
Requires-Dist: yamllint>=1.35.0; extra == "dev"
|
|
37
|
+
Requires-Dist: mdformat>=0.7.0; extra == "dev"
|
|
38
|
+
Requires-Dist: freezegun>=1.5.0; extra == "dev"
|
|
39
|
+
Dynamic: license-file
|
|
40
|
+
|
|
41
|
+

|
|
42
|
+

|
|
43
|
+

|
|
44
|
+

|
|
45
|
+

|
|
46
|
+

|
|
47
|
+

|
|
48
|
+

|
|
49
|
+
|
|
50
|
+

|
|
51
|
+
|
|
52
|
+
# biblio-uplift
|
|
53
|
+
|
|
54
|
+
TUI and CLI tool for upgrading Docker Compose-based services on remote servers via SSH.
|
|
55
|
+
|
|
56
|
+
## Install
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pip install .
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Quick Start
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# Launch the interactive TUI
|
|
66
|
+
biblio-uplift
|
|
67
|
+
|
|
68
|
+
# Run an upgrade from the CLI
|
|
69
|
+
biblio-uplift run itops-vaultwarden
|
|
70
|
+
|
|
71
|
+
# Run non-interactively (for cron/automation)
|
|
72
|
+
biblio-uplift run itops-vaultwarden --non-interactive
|
|
73
|
+
|
|
74
|
+
# Dry run (simulate without executing)
|
|
75
|
+
biblio-uplift run itops-vaultwarden --dry-run
|
|
76
|
+
|
|
77
|
+
# Run cleanup (prune docker resources, old logs)
|
|
78
|
+
biblio-uplift cleanup itops-vaultwarden
|
|
79
|
+
|
|
80
|
+
# Check server status
|
|
81
|
+
biblio-uplift status itops-vaultwarden
|
|
82
|
+
|
|
83
|
+
# Restore from a backup
|
|
84
|
+
biblio-uplift restore itops-vaultwarden
|
|
85
|
+
biblio-uplift restore itops-vaultwarden --backup 20260501-030000
|
|
86
|
+
|
|
87
|
+
# Resume an upgrade after reboot (if session was lost)
|
|
88
|
+
biblio-uplift resume
|
|
89
|
+
|
|
90
|
+
# Run upgrades on all projects sequentially
|
|
91
|
+
biblio-uplift run-all --non-interactive
|
|
92
|
+
|
|
93
|
+
# List available backups
|
|
94
|
+
biblio-uplift backup list itops-vaultwarden
|
|
95
|
+
|
|
96
|
+
# Update a single service (pull repo + recreate)
|
|
97
|
+
biblio-uplift service-update my-project haproxy
|
|
98
|
+
|
|
99
|
+
# Check/upgrade Docker Compose install method
|
|
100
|
+
biblio-uplift tool run itops-vaultwarden compose-version
|
|
101
|
+
|
|
102
|
+
# List available tools
|
|
103
|
+
biblio-uplift tool list
|
|
104
|
+
|
|
105
|
+
# Run a tool against a project
|
|
106
|
+
biblio-uplift tool run itops-vaultwarden pending-security-updates
|
|
107
|
+
|
|
108
|
+
# Manage configs
|
|
109
|
+
biblio-uplift config edit itops-vaultwarden
|
|
110
|
+
biblio-uplift config validate itops-vaultwarden
|
|
111
|
+
biblio-uplift config create my-project --host myhost.example.com --project-dir /opt/docker/my-project
|
|
112
|
+
biblio-uplift config delete my-project
|
|
113
|
+
|
|
114
|
+
# View history
|
|
115
|
+
biblio-uplift history --last 10
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Screenshots
|
|
119
|
+
|
|
120
|
+
### Dashboard
|
|
121
|
+
|
|
122
|
+

|
|
123
|
+
|
|
124
|
+
### Upgrade Pipeline
|
|
125
|
+
|
|
126
|
+

|
|
127
|
+
|
|
128
|
+
### Tools
|
|
129
|
+
|
|
130
|
+

|
|
131
|
+
|
|
132
|
+
## Configuration
|
|
133
|
+
|
|
134
|
+
Project configs live in `configs/` as YAML files. Each config defines a remote server and its Docker Compose project.
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
# List configured projects
|
|
138
|
+
biblio-uplift config list
|
|
139
|
+
|
|
140
|
+
# Show a project's config
|
|
141
|
+
biblio-uplift config show itops-vaultwarden
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Config Fields
|
|
145
|
+
|
|
146
|
+
| Field | Default | Description |
|
|
147
|
+
|-------|---------|-------------|
|
|
148
|
+
| `name` | required | Project identifier |
|
|
149
|
+
| `ssh_host` | required | Remote server hostname |
|
|
150
|
+
| `ssh_user` | `ansible` | SSH username |
|
|
151
|
+
| `ssh_key` | `~/.ssh/id_ed25519` | Path to SSH private key (must not have a passphrase, or use ssh-agent) |
|
|
152
|
+
| `sudo` | `true` | Prefix remote commands with sudo |
|
|
153
|
+
| `project_dir` | required | Path to the Docker Compose project on the remote server |
|
|
154
|
+
| `compose_files` | `["docker-compose.yml"]` | Compose file(s) to use |
|
|
155
|
+
| `compose_profile` | `null` | Compose profile. Set to `hostname` to use `$(hostname -s)` on the remote |
|
|
156
|
+
| `compose_command` | `docker compose` | Compose binary |
|
|
157
|
+
| `backup_dir` | `/var/backups/itops` | Where to store backups on the remote server (local disk, not NFS) |
|
|
158
|
+
| `backup_retention` | `5` | Number of backups to keep |
|
|
159
|
+
| `volumes` | `[]` | Docker volume names to back up |
|
|
160
|
+
| `extra_backup_paths` | `[]` | Additional paths to include in file backup |
|
|
161
|
+
| `healthcheck_urls` | `[]` | HTTP(S) URLs to check after startup |
|
|
162
|
+
| `healthcheck_timeout` | `120` | Seconds to wait for containers to become healthy |
|
|
163
|
+
| `skip_os_update` | `false` | Skip OS package updates by default |
|
|
164
|
+
| `skip_reboot` | `false` | Skip reboot by default |
|
|
165
|
+
| `ssh_port` | `22` | SSH port |
|
|
166
|
+
| `git_branch` | `main` | Git branch to pull |
|
|
167
|
+
| `maintenance_window` | `null` | Allowed time window for runs (e.g. `"Sun 02:00-06:00"`) |
|
|
168
|
+
| `on_failure_cmd` | `null` | Shell command to run on failure (e.g. Slack webhook) |
|
|
169
|
+
| `on_success_cmd` | `null` | Shell command to run on success |
|
|
170
|
+
| `reboot_timeout` | `300` | Seconds to wait for SSH after reboot |
|
|
171
|
+
| `apt_timeout` | `600` | Seconds to wait for apt operations |
|
|
172
|
+
| `pre_upgrade_hooks` | `[]` | Shell commands to run before upgrade (executed as root via sudo) |
|
|
173
|
+
| `post_upgrade_hooks` | `[]` | Shell commands to run after upgrade |
|
|
174
|
+
|
|
175
|
+
### Hooks
|
|
176
|
+
|
|
177
|
+
Pre/post upgrade hooks are arbitrary shell commands executed on the remote server. They run as root (via sudo). Use them for things like:
|
|
178
|
+
|
|
179
|
+
```yaml
|
|
180
|
+
pre_upgrade_hooks:
|
|
181
|
+
- "systemctl stop ci-runner"
|
|
182
|
+
- "/opt/scripts/notify-slack.sh 'Starting upgrade'"
|
|
183
|
+
post_upgrade_hooks:
|
|
184
|
+
- "systemctl start ci-runner"
|
|
185
|
+
- "/opt/scripts/notify-slack.sh 'Upgrade complete'"
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
## Upgrade Pipeline
|
|
189
|
+
|
|
190
|
+
The upgrade runs these steps in order:
|
|
191
|
+
|
|
192
|
+
1. **Preflight** — SSH connectivity, disk space check, backup size estimation
|
|
193
|
+
1. **Pre-hooks** — Custom pre-upgrade commands
|
|
194
|
+
1. **Backup files** — Tar project dir + extra paths
|
|
195
|
+
1. **Backup volumes** — Export Docker volumes via alpine container
|
|
196
|
+
1. **Backup cleanup** — Remove old backups beyond retention count
|
|
197
|
+
1. **Docker down** — `docker compose down`
|
|
198
|
+
1. **Git pull** — Pull latest from remote
|
|
199
|
+
1. **Docker pull** — Pull latest images
|
|
200
|
+
1. **OS update** — `apt-get update && upgrade && autoremove --purge`
|
|
201
|
+
1. **Reboot** — Reboot and wait for SSH to come back
|
|
202
|
+
1. **Docker up** — `docker compose up -d`
|
|
203
|
+
1. **Health check** — Wait for containers healthy + HTTP checks
|
|
204
|
+
1. **Post-hooks** — Custom post-upgrade commands
|
|
205
|
+
|
|
206
|
+
On failure, completed steps are rolled back in reverse order (docker down → docker up, git pull → git checkout previous commit).
|
|
207
|
+
|
|
208
|
+
## Cleanup Pipeline
|
|
209
|
+
|
|
210
|
+
1. **Preflight** — SSH connectivity check
|
|
211
|
+
1. **Docker cleanup** — Prune stopped containers, dangling images, unused volumes, build cache
|
|
212
|
+
1. **Log cleanup** — Truncate configured log files, vacuum journald
|
|
213
|
+
|
|
214
|
+
Set `aggressive_prune: true` in the cleanup config to remove *all* unused images (not just dangling) during cleanup.
|
|
215
|
+
|
|
216
|
+
## TUI
|
|
217
|
+
|
|
218
|
+
Running `biblio-uplift` with no command launches the interactive terminal UI. It has 8 panels:
|
|
219
|
+
|
|
220
|
+
- **Dashboard** — Overview of all projects and their last run status
|
|
221
|
+
- **Upgrade** — Run upgrades interactively with live step progress
|
|
222
|
+
- **Cleanup** — Run cleanup pipelines with live output
|
|
223
|
+
- **Server Status** — View remote server health (disk, memory, uptime, containers)
|
|
224
|
+
- **Backups** — Browse and restore backups
|
|
225
|
+
- **Config Editor** — View and edit project configurations
|
|
226
|
+
- **History** — Browse past upgrade runs with filtering
|
|
227
|
+
- **Tools** — Security audits, log rotation, container management tools
|
|
228
|
+
|
|
229
|
+
## CLI Flags
|
|
230
|
+
|
|
231
|
+
```
|
|
232
|
+
biblio-uplift [--debug] [--version] COMMAND
|
|
233
|
+
|
|
234
|
+
Global:
|
|
235
|
+
--debug Write verbose logs to logs/debug.log
|
|
236
|
+
--version Show version and exit
|
|
237
|
+
|
|
238
|
+
run PROJECT:
|
|
239
|
+
--non-interactive Skip confirmation prompts
|
|
240
|
+
--skip-reboot Skip the reboot step
|
|
241
|
+
--skip-os-update Skip OS package updates
|
|
242
|
+
--skip-backup Skip all backup steps
|
|
243
|
+
--skip-git Skip git pull
|
|
244
|
+
--dry-run Simulate without executing
|
|
245
|
+
--no-hooks Skip pre/post hooks
|
|
246
|
+
--on-failure TEXT Shell command to run on failure (overrides config)
|
|
247
|
+
--start-from TEXT Skip steps before this one (e.g. docker_pull)
|
|
248
|
+
|
|
249
|
+
cleanup PROJECT:
|
|
250
|
+
--non-interactive Skip confirmation prompts
|
|
251
|
+
--dry-run Show what would be done
|
|
252
|
+
|
|
253
|
+
restore PROJECT:
|
|
254
|
+
--backup TEXT Backup timestamp to restore (defaults to latest)
|
|
255
|
+
--non-interactive Skip confirmation prompts
|
|
256
|
+
|
|
257
|
+
resume:
|
|
258
|
+
Resume an upgrade after reboot if the controlling session was lost.
|
|
259
|
+
No options.
|
|
260
|
+
|
|
261
|
+
status PROJECT:
|
|
262
|
+
Show current status of a project's remote server.
|
|
263
|
+
No options.
|
|
264
|
+
|
|
265
|
+
backup list PROJECT:
|
|
266
|
+
List available backups for a project.
|
|
267
|
+
No options.
|
|
268
|
+
|
|
269
|
+
service-update PROJECT SERVICE:
|
|
270
|
+
Pull repo and recreate a single service.
|
|
271
|
+
--non-interactive Skip confirmation prompts
|
|
272
|
+
|
|
273
|
+
tool list:
|
|
274
|
+
List available tools by category.
|
|
275
|
+
|
|
276
|
+
tool run PROJECT TOOL_NAME:
|
|
277
|
+
--dry-run Preview what would happen
|
|
278
|
+
--non-interactive Skip confirmation prompts
|
|
279
|
+
|
|
280
|
+
run-all:
|
|
281
|
+
--non-interactive Skip confirmation prompts
|
|
282
|
+
--skip-reboot Skip the reboot step
|
|
283
|
+
--skip-os-update Skip OS package updates
|
|
284
|
+
--dry-run Simulate without executing
|
|
285
|
+
--projects TEXT Comma-separated project names (defaults to all)
|
|
286
|
+
|
|
287
|
+
config:
|
|
288
|
+
config list List all project configurations
|
|
289
|
+
config show PROJECT Show configuration details for a project
|
|
290
|
+
config create NAME Create a new project configuration
|
|
291
|
+
--host TEXT SSH hostname (required)
|
|
292
|
+
--project-dir TEXT Remote project directory (required)
|
|
293
|
+
--ssh-user TEXT SSH username
|
|
294
|
+
--ssh-key TEXT Path to SSH key
|
|
295
|
+
config edit PROJECT Open config in $EDITOR
|
|
296
|
+
config validate PROJECT
|
|
297
|
+
Validate config by testing SSH, Docker, and paths
|
|
298
|
+
config delete PROJECT
|
|
299
|
+
Delete a project configuration
|
|
300
|
+
--non-interactive Skip confirmation prompts
|
|
301
|
+
|
|
302
|
+
history:
|
|
303
|
+
--project TEXT Filter by project
|
|
304
|
+
--last INTEGER Show last N entries (default: 20)
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
## Audit History
|
|
308
|
+
|
|
309
|
+
Every run is logged to `logs/history.jsonl` with timestamp, project, steps, outcomes, and duration. View with:
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
biblio-uplift history
|
|
313
|
+
biblio-uplift history --project my-project --last 5
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## Concurrent Run Protection
|
|
317
|
+
|
|
318
|
+
A file lock (`/tmp/biblio-uplift-<project>.lock`) prevents multiple upgrades of the same project from running simultaneously.
|
|
319
|
+
|
|
320
|
+
## Exit Codes
|
|
321
|
+
|
|
322
|
+
| Code | Meaning |
|
|
323
|
+
|------|---------|
|
|
324
|
+
| 0 | Success |
|
|
325
|
+
| 1 | Pipeline failed or error |
|
|
326
|
+
|
|
327
|
+
## Cron / Unattended Use
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
# Weekly upgrade of vaultwarden, Sundays at 3am
|
|
331
|
+
0 3 * * 0 cd /path/to/biblio-uplift && biblio-uplift run itops-vaultwarden --non-interactive --on-failure "curl -X POST https://hooks.slack.com/services/YOUR/WEBHOOK -d '{\"text\": \"Vaultwarden upgrade failed\"}' " >> logs/cron.log 2>&1
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
For unattended runs:
|
|
335
|
+
|
|
336
|
+
- Always use `--non-interactive` to skip confirmation prompts
|
|
337
|
+
- Set `on_failure_cmd` in config or use `--on-failure` for failure alerts
|
|
338
|
+
- Set `maintenance_window` in config to prevent accidental runs outside hours
|
|
339
|
+
- Monitor exit codes and `logs/history.jsonl` for audit trail
|
|
340
|
+
|
|
341
|
+
## Development
|
|
342
|
+
|
|
343
|
+
```bash
|
|
344
|
+
pipx install --force .
|
|
345
|
+
biblio-uplift --debug run itops-vaultwarden --dry-run
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
Set `ITOPS_UPGRADE_DIR` to override the project root directory detection.
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+

|
|
2
|
+

|
|
3
|
+

|
|
4
|
+

|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+
|
|
10
|
+

|
|
11
|
+
|
|
12
|
+
# biblio-uplift
|
|
13
|
+
|
|
14
|
+
TUI and CLI tool for upgrading Docker Compose-based services on remote servers via SSH.
|
|
15
|
+
|
|
16
|
+
## Install
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
pip install .
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Launch the interactive TUI
|
|
26
|
+
biblio-uplift
|
|
27
|
+
|
|
28
|
+
# Run an upgrade from the CLI
|
|
29
|
+
biblio-uplift run itops-vaultwarden
|
|
30
|
+
|
|
31
|
+
# Run non-interactively (for cron/automation)
|
|
32
|
+
biblio-uplift run itops-vaultwarden --non-interactive
|
|
33
|
+
|
|
34
|
+
# Dry run (simulate without executing)
|
|
35
|
+
biblio-uplift run itops-vaultwarden --dry-run
|
|
36
|
+
|
|
37
|
+
# Run cleanup (prune docker resources, old logs)
|
|
38
|
+
biblio-uplift cleanup itops-vaultwarden
|
|
39
|
+
|
|
40
|
+
# Check server status
|
|
41
|
+
biblio-uplift status itops-vaultwarden
|
|
42
|
+
|
|
43
|
+
# Restore from a backup
|
|
44
|
+
biblio-uplift restore itops-vaultwarden
|
|
45
|
+
biblio-uplift restore itops-vaultwarden --backup 20260501-030000
|
|
46
|
+
|
|
47
|
+
# Resume an upgrade after reboot (if session was lost)
|
|
48
|
+
biblio-uplift resume
|
|
49
|
+
|
|
50
|
+
# Run upgrades on all projects sequentially
|
|
51
|
+
biblio-uplift run-all --non-interactive
|
|
52
|
+
|
|
53
|
+
# List available backups
|
|
54
|
+
biblio-uplift backup list itops-vaultwarden
|
|
55
|
+
|
|
56
|
+
# Update a single service (pull repo + recreate)
|
|
57
|
+
biblio-uplift service-update my-project haproxy
|
|
58
|
+
|
|
59
|
+
# Check/upgrade Docker Compose install method
|
|
60
|
+
biblio-uplift tool run itops-vaultwarden compose-version
|
|
61
|
+
|
|
62
|
+
# List available tools
|
|
63
|
+
biblio-uplift tool list
|
|
64
|
+
|
|
65
|
+
# Run a tool against a project
|
|
66
|
+
biblio-uplift tool run itops-vaultwarden pending-security-updates
|
|
67
|
+
|
|
68
|
+
# Manage configs
|
|
69
|
+
biblio-uplift config edit itops-vaultwarden
|
|
70
|
+
biblio-uplift config validate itops-vaultwarden
|
|
71
|
+
biblio-uplift config create my-project --host myhost.example.com --project-dir /opt/docker/my-project
|
|
72
|
+
biblio-uplift config delete my-project
|
|
73
|
+
|
|
74
|
+
# View history
|
|
75
|
+
biblio-uplift history --last 10
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Screenshots
|
|
79
|
+
|
|
80
|
+
### Dashboard
|
|
81
|
+
|
|
82
|
+

|
|
83
|
+
|
|
84
|
+
### Upgrade Pipeline
|
|
85
|
+
|
|
86
|
+

|
|
87
|
+
|
|
88
|
+
### Tools
|
|
89
|
+
|
|
90
|
+

|
|
91
|
+
|
|
92
|
+
## Configuration
|
|
93
|
+
|
|
94
|
+
Project configs live in `configs/` as YAML files. Each config defines a remote server and its Docker Compose project.
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# List configured projects
|
|
98
|
+
biblio-uplift config list
|
|
99
|
+
|
|
100
|
+
# Show a project's config
|
|
101
|
+
biblio-uplift config show itops-vaultwarden
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Config Fields
|
|
105
|
+
|
|
106
|
+
| Field | Default | Description |
|
|
107
|
+
|-------|---------|-------------|
|
|
108
|
+
| `name` | required | Project identifier |
|
|
109
|
+
| `ssh_host` | required | Remote server hostname |
|
|
110
|
+
| `ssh_user` | `ansible` | SSH username |
|
|
111
|
+
| `ssh_key` | `~/.ssh/id_ed25519` | Path to SSH private key (must not have a passphrase, or use ssh-agent) |
|
|
112
|
+
| `sudo` | `true` | Prefix remote commands with sudo |
|
|
113
|
+
| `project_dir` | required | Path to the Docker Compose project on the remote server |
|
|
114
|
+
| `compose_files` | `["docker-compose.yml"]` | Compose file(s) to use |
|
|
115
|
+
| `compose_profile` | `null` | Compose profile. Set to `hostname` to use `$(hostname -s)` on the remote |
|
|
116
|
+
| `compose_command` | `docker compose` | Compose binary |
|
|
117
|
+
| `backup_dir` | `/var/backups/itops` | Where to store backups on the remote server (local disk, not NFS) |
|
|
118
|
+
| `backup_retention` | `5` | Number of backups to keep |
|
|
119
|
+
| `volumes` | `[]` | Docker volume names to back up |
|
|
120
|
+
| `extra_backup_paths` | `[]` | Additional paths to include in file backup |
|
|
121
|
+
| `healthcheck_urls` | `[]` | HTTP(S) URLs to check after startup |
|
|
122
|
+
| `healthcheck_timeout` | `120` | Seconds to wait for containers to become healthy |
|
|
123
|
+
| `skip_os_update` | `false` | Skip OS package updates by default |
|
|
124
|
+
| `skip_reboot` | `false` | Skip reboot by default |
|
|
125
|
+
| `ssh_port` | `22` | SSH port |
|
|
126
|
+
| `git_branch` | `main` | Git branch to pull |
|
|
127
|
+
| `maintenance_window` | `null` | Allowed time window for runs (e.g. `"Sun 02:00-06:00"`) |
|
|
128
|
+
| `on_failure_cmd` | `null` | Shell command to run on failure (e.g. Slack webhook) |
|
|
129
|
+
| `on_success_cmd` | `null` | Shell command to run on success |
|
|
130
|
+
| `reboot_timeout` | `300` | Seconds to wait for SSH after reboot |
|
|
131
|
+
| `apt_timeout` | `600` | Seconds to wait for apt operations |
|
|
132
|
+
| `pre_upgrade_hooks` | `[]` | Shell commands to run before upgrade (executed as root via sudo) |
|
|
133
|
+
| `post_upgrade_hooks` | `[]` | Shell commands to run after upgrade |
|
|
134
|
+
|
|
135
|
+
### Hooks
|
|
136
|
+
|
|
137
|
+
Pre/post upgrade hooks are arbitrary shell commands executed on the remote server. They run as root (via sudo). Use them for things like:
|
|
138
|
+
|
|
139
|
+
```yaml
|
|
140
|
+
pre_upgrade_hooks:
|
|
141
|
+
- "systemctl stop ci-runner"
|
|
142
|
+
- "/opt/scripts/notify-slack.sh 'Starting upgrade'"
|
|
143
|
+
post_upgrade_hooks:
|
|
144
|
+
- "systemctl start ci-runner"
|
|
145
|
+
- "/opt/scripts/notify-slack.sh 'Upgrade complete'"
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Upgrade Pipeline
|
|
149
|
+
|
|
150
|
+
The upgrade runs these steps in order:
|
|
151
|
+
|
|
152
|
+
1. **Preflight** — SSH connectivity, disk space check, backup size estimation
|
|
153
|
+
1. **Pre-hooks** — Custom pre-upgrade commands
|
|
154
|
+
1. **Backup files** — Tar project dir + extra paths
|
|
155
|
+
1. **Backup volumes** — Export Docker volumes via alpine container
|
|
156
|
+
1. **Backup cleanup** — Remove old backups beyond retention count
|
|
157
|
+
1. **Docker down** — `docker compose down`
|
|
158
|
+
1. **Git pull** — Pull latest from remote
|
|
159
|
+
1. **Docker pull** — Pull latest images
|
|
160
|
+
1. **OS update** — `apt-get update && upgrade && autoremove --purge`
|
|
161
|
+
1. **Reboot** — Reboot and wait for SSH to come back
|
|
162
|
+
1. **Docker up** — `docker compose up -d`
|
|
163
|
+
1. **Health check** — Wait for containers healthy + HTTP checks
|
|
164
|
+
1. **Post-hooks** — Custom post-upgrade commands
|
|
165
|
+
|
|
166
|
+
On failure, completed steps are rolled back in reverse order (docker down → docker up, git pull → git checkout previous commit).
|
|
167
|
+
|
|
168
|
+
## Cleanup Pipeline
|
|
169
|
+
|
|
170
|
+
1. **Preflight** — SSH connectivity check
|
|
171
|
+
1. **Docker cleanup** — Prune stopped containers, dangling images, unused volumes, build cache
|
|
172
|
+
1. **Log cleanup** — Truncate configured log files, vacuum journald
|
|
173
|
+
|
|
174
|
+
Set `aggressive_prune: true` in the cleanup config to remove *all* unused images (not just dangling) during cleanup.
|
|
175
|
+
|
|
176
|
+
## TUI
|
|
177
|
+
|
|
178
|
+
Running `biblio-uplift` with no command launches the interactive terminal UI. It has 8 panels:
|
|
179
|
+
|
|
180
|
+
- **Dashboard** — Overview of all projects and their last run status
|
|
181
|
+
- **Upgrade** — Run upgrades interactively with live step progress
|
|
182
|
+
- **Cleanup** — Run cleanup pipelines with live output
|
|
183
|
+
- **Server Status** — View remote server health (disk, memory, uptime, containers)
|
|
184
|
+
- **Backups** — Browse and restore backups
|
|
185
|
+
- **Config Editor** — View and edit project configurations
|
|
186
|
+
- **History** — Browse past upgrade runs with filtering
|
|
187
|
+
- **Tools** — Security audits, log rotation, container management tools
|
|
188
|
+
|
|
189
|
+
## CLI Flags
|
|
190
|
+
|
|
191
|
+
```
|
|
192
|
+
biblio-uplift [--debug] [--version] COMMAND
|
|
193
|
+
|
|
194
|
+
Global:
|
|
195
|
+
--debug Write verbose logs to logs/debug.log
|
|
196
|
+
--version Show version and exit
|
|
197
|
+
|
|
198
|
+
run PROJECT:
|
|
199
|
+
--non-interactive Skip confirmation prompts
|
|
200
|
+
--skip-reboot Skip the reboot step
|
|
201
|
+
--skip-os-update Skip OS package updates
|
|
202
|
+
--skip-backup Skip all backup steps
|
|
203
|
+
--skip-git Skip git pull
|
|
204
|
+
--dry-run Simulate without executing
|
|
205
|
+
--no-hooks Skip pre/post hooks
|
|
206
|
+
--on-failure TEXT Shell command to run on failure (overrides config)
|
|
207
|
+
--start-from TEXT Skip steps before this one (e.g. docker_pull)
|
|
208
|
+
|
|
209
|
+
cleanup PROJECT:
|
|
210
|
+
--non-interactive Skip confirmation prompts
|
|
211
|
+
--dry-run Show what would be done
|
|
212
|
+
|
|
213
|
+
restore PROJECT:
|
|
214
|
+
--backup TEXT Backup timestamp to restore (defaults to latest)
|
|
215
|
+
--non-interactive Skip confirmation prompts
|
|
216
|
+
|
|
217
|
+
resume:
|
|
218
|
+
Resume an upgrade after reboot if the controlling session was lost.
|
|
219
|
+
No options.
|
|
220
|
+
|
|
221
|
+
status PROJECT:
|
|
222
|
+
Show current status of a project's remote server.
|
|
223
|
+
No options.
|
|
224
|
+
|
|
225
|
+
backup list PROJECT:
|
|
226
|
+
List available backups for a project.
|
|
227
|
+
No options.
|
|
228
|
+
|
|
229
|
+
service-update PROJECT SERVICE:
|
|
230
|
+
Pull repo and recreate a single service.
|
|
231
|
+
--non-interactive Skip confirmation prompts
|
|
232
|
+
|
|
233
|
+
tool list:
|
|
234
|
+
List available tools by category.
|
|
235
|
+
|
|
236
|
+
tool run PROJECT TOOL_NAME:
|
|
237
|
+
--dry-run Preview what would happen
|
|
238
|
+
--non-interactive Skip confirmation prompts
|
|
239
|
+
|
|
240
|
+
run-all:
|
|
241
|
+
--non-interactive Skip confirmation prompts
|
|
242
|
+
--skip-reboot Skip the reboot step
|
|
243
|
+
--skip-os-update Skip OS package updates
|
|
244
|
+
--dry-run Simulate without executing
|
|
245
|
+
--projects TEXT Comma-separated project names (defaults to all)
|
|
246
|
+
|
|
247
|
+
config:
|
|
248
|
+
config list List all project configurations
|
|
249
|
+
config show PROJECT Show configuration details for a project
|
|
250
|
+
config create NAME Create a new project configuration
|
|
251
|
+
--host TEXT SSH hostname (required)
|
|
252
|
+
--project-dir TEXT Remote project directory (required)
|
|
253
|
+
--ssh-user TEXT SSH username
|
|
254
|
+
--ssh-key TEXT Path to SSH key
|
|
255
|
+
config edit PROJECT Open config in $EDITOR
|
|
256
|
+
config validate PROJECT
|
|
257
|
+
Validate config by testing SSH, Docker, and paths
|
|
258
|
+
config delete PROJECT
|
|
259
|
+
Delete a project configuration
|
|
260
|
+
--non-interactive Skip confirmation prompts
|
|
261
|
+
|
|
262
|
+
history:
|
|
263
|
+
--project TEXT Filter by project
|
|
264
|
+
--last INTEGER Show last N entries (default: 20)
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Audit History
|
|
268
|
+
|
|
269
|
+
Every run is logged to `logs/history.jsonl` with timestamp, project, steps, outcomes, and duration. View with:
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
biblio-uplift history
|
|
273
|
+
biblio-uplift history --project my-project --last 5
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## Concurrent Run Protection
|
|
277
|
+
|
|
278
|
+
A file lock (`/tmp/biblio-uplift-<project>.lock`) prevents multiple upgrades of the same project from running simultaneously.
|
|
279
|
+
|
|
280
|
+
## Exit Codes
|
|
281
|
+
|
|
282
|
+
| Code | Meaning |
|
|
283
|
+
|------|---------|
|
|
284
|
+
| 0 | Success |
|
|
285
|
+
| 1 | Pipeline failed or error |
|
|
286
|
+
|
|
287
|
+
## Cron / Unattended Use
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
# Weekly upgrade of vaultwarden, Sundays at 3am
|
|
291
|
+
0 3 * * 0 cd /path/to/biblio-uplift && biblio-uplift run itops-vaultwarden --non-interactive --on-failure "curl -X POST https://hooks.slack.com/services/YOUR/WEBHOOK -d '{\"text\": \"Vaultwarden upgrade failed\"}' " >> logs/cron.log 2>&1
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
For unattended runs:
|
|
295
|
+
|
|
296
|
+
- Always use `--non-interactive` to skip confirmation prompts
|
|
297
|
+
- Set `on_failure_cmd` in config or use `--on-failure` for failure alerts
|
|
298
|
+
- Set `maintenance_window` in config to prevent accidental runs outside hours
|
|
299
|
+
- Monitor exit codes and `logs/history.jsonl` for audit trail
|
|
300
|
+
|
|
301
|
+
## Development
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
pipx install --force .
|
|
305
|
+
biblio-uplift --debug run itops-vaultwarden --dry-run
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
Set `ITOPS_UPGRADE_DIR` to override the project root directory detection.
|