djaploy 1.3.0__tar.gz → 1.3.2__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.
- {djaploy-1.3.0 → djaploy-1.3.2}/PKG-INFO +1 -1
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/rclone/infra/djaploy_hooks.py +48 -23
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/bin/django_pyinfra.py +17 -0
- djaploy-1.3.2/djaploy/version.py +1 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy.egg-info/PKG-INFO +1 -1
- {djaploy-1.3.0 → djaploy-1.3.2}/pyproject.toml +1 -1
- djaploy-1.3.0/djaploy/version.py +0 -1
- {djaploy-1.3.0 → djaploy-1.3.2}/LICENSE +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/README.md +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/__init__.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/app.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/__init__.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/borg/__init__.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/borg/infra/__init__.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/borg/infra/djaploy_hooks.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/janitor/__init__.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/janitor/apps.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/janitor/infra/__init__.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/janitor/infra/commands/createjanitoruser.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/janitor/infra/djaploy_hooks.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/nginx/__init__.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/nginx/apps.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/nginx/infra/__init__.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/nginx/infra/djaploy_hooks.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/rclone/__init__.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/rclone/apps.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/rclone/infra/__init__.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/sync_certs/__init__.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/sync_certs/apps.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/sync_certs/infra/__init__.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/sync_certs/infra/djaploy_hooks.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/systemd/__init__.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/systemd/apps.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/systemd/infra/__init__.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/systemd/infra/djaploy_hooks.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/tailscale/__init__.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/tailscale/apps.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/tailscale/infra/__init__.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/tailscale/infra/djaploy_hooks.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/versioning/__init__.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/versioning/apps.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/versioning/infra/__init__.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/apps/versioning/infra/djaploy_hooks.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/artifact.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/bin/__init__.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/bin/gunicornherder.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/builtin_hooks.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/certificates.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/changelog.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/commands/__init__.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/commands/_utils.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/commands/activate.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/commands/configure.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/commands/deploy.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/commands/restore.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/commands/rollback.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/commands/status.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/commands/sync_certs.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/config.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/deploy.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/discovery.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/hooks.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/infra/__init__.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/infra/bluegreen.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/infra/djaploy_hooks.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/infra/templates.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/infra/utils.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/management/__init__.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/management/commands/__init__.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/management/commands/djaploy.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/management/commands/restore_backup.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/management/commands/sync_certs.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/management/commands/update_certs.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/management/commands/verify.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/management/utils.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/notifications.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/utils.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy/versioning.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy.egg-info/SOURCES.txt +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy.egg-info/dependency_links.txt +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy.egg-info/entry_points.txt +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy.egg-info/requires.txt +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/djaploy.egg-info/top_level.txt +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/setup.cfg +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/tests/test_bluegreen.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/tests/test_borg.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/tests/test_config.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/tests/test_deploy_scripts.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/tests/test_discovery.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/tests/test_gunicornherder.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/tests/test_hooks.py +0 -0
- {djaploy-1.3.0 → djaploy-1.3.2}/tests/test_versioning.py +0 -0
|
@@ -162,9 +162,17 @@ cleanup() {{
|
|
|
162
162
|
# Set trap to cleanup on exit
|
|
163
163
|
trap cleanup EXIT
|
|
164
164
|
|
|
165
|
+
# Retention enforcement (defined here, run before the dump so it still
|
|
166
|
+
# executes even if a later backup step fails)
|
|
167
|
+
{_generate_retention_function(retention_days, host_name)}
|
|
168
|
+
|
|
165
169
|
# Start backup
|
|
166
170
|
log_message "Starting backup for {host_name}"
|
|
167
171
|
|
|
172
|
+
# Enforce retention up front so stale backups are pruned on every run,
|
|
173
|
+
# independent of whether the dump/upload below succeeds.
|
|
174
|
+
enforce_retention || true
|
|
175
|
+
|
|
168
176
|
# Create temporary backup directory
|
|
169
177
|
mkdir -p "$TEMP_BACKUP_DIR"
|
|
170
178
|
|
|
@@ -174,6 +182,23 @@ log_message "Creating consistent database backups"
|
|
|
174
182
|
# List of databases to backup
|
|
175
183
|
DATABASES=({db_array})
|
|
176
184
|
|
|
185
|
+
# Fail fast (with a clear message) if there isn't enough scratch space. VACUUM
|
|
186
|
+
# INTO writes a full copy of every DB, then those are tarred — so we need room
|
|
187
|
+
# for roughly the total DB size plus the archive. The threshold scales from the
|
|
188
|
+
# live DB sizes (1.5x), so it is correct on any host without a hard-coded value.
|
|
189
|
+
REQUIRED_KB=0
|
|
190
|
+
for DB in "${{DATABASES[@]}}"; do
|
|
191
|
+
if [ -f "$DB_DIR/$DB" ]; then
|
|
192
|
+
REQUIRED_KB=$((REQUIRED_KB + $(du -k "$DB_DIR/$DB" | cut -f1)))
|
|
193
|
+
fi
|
|
194
|
+
done
|
|
195
|
+
REQUIRED_KB=$((REQUIRED_KB * 3 / 2))
|
|
196
|
+
AVAIL_KB=$(df --output=avail "$(dirname "$TEMP_BACKUP_DIR")" | tail -1)
|
|
197
|
+
if [ "${{AVAIL_KB:-0}}" -lt "$REQUIRED_KB" ]; then
|
|
198
|
+
log_message "ERROR: only $((AVAIL_KB/1024))MB free, need ~$((REQUIRED_KB/1024))MB for backup scratch space — aborting DB dump"
|
|
199
|
+
exit 1
|
|
200
|
+
fi
|
|
201
|
+
|
|
177
202
|
for DB in "${{DATABASES[@]}}"; do
|
|
178
203
|
if [ -f "$DB_DIR/$DB" ]; then
|
|
179
204
|
log_message "Backing up database: $DB"
|
|
@@ -296,36 +321,36 @@ else
|
|
|
296
321
|
log_message "Media directory not found or empty at $MEDIA_DIR, skipping media backup"
|
|
297
322
|
fi
|
|
298
323
|
|
|
299
|
-
#
|
|
300
|
-
{_generate_retention_cleanup(retention_days, host_name)}
|
|
324
|
+
# (Retention was already enforced at the start of this run via enforce_retention.)
|
|
301
325
|
|
|
302
326
|
log_message "Backup completed successfully for {host_name}"
|
|
303
327
|
'''
|
|
304
328
|
|
|
305
329
|
|
|
306
|
-
def
|
|
307
|
-
"""Generate
|
|
330
|
+
def _generate_retention_function(retention_days: int, host_name: str) -> str:
|
|
331
|
+
"""Generate an ``enforce_retention()`` shell function for the backup script.
|
|
332
|
+
|
|
333
|
+
Defined near the top of the script and invoked *before* the database dump
|
|
334
|
+
so retention runs on every invocation even if a later step fails. Previously
|
|
335
|
+
the cleanup was the final step, guarded by ``set -e`` and multiple ``exit 1``
|
|
336
|
+
branches, so any dump/upload failure skipped it and old backups accumulated
|
|
337
|
+
without bound (this is what filled the linnahovi disk).
|
|
338
|
+
"""
|
|
308
339
|
if retention_days <= 0:
|
|
309
|
-
return ""
|
|
340
|
+
return "enforce_retention() { :; } # retention disabled (retention_days<=0)"
|
|
310
341
|
return (
|
|
311
|
-
'
|
|
312
|
-
'\n'
|
|
313
|
-
'
|
|
314
|
-
'
|
|
315
|
-
'\n'
|
|
316
|
-
'
|
|
317
|
-
'
|
|
318
|
-
'
|
|
319
|
-
'
|
|
320
|
-
'\n'
|
|
321
|
-
'
|
|
322
|
-
'
|
|
323
|
-
' log_message "Deleting old backup folder: $folder_name"\n'
|
|
324
|
-
' rclone purge "${{REMOTE_NAME}}:{host}/$folder_name" --config "$RCLONE_CONFIG" --quiet\n'
|
|
325
|
-
' fi\n'
|
|
326
|
-
'done\n'
|
|
327
|
-
'\n'
|
|
328
|
-
'log_message "Cleanup completed"'
|
|
342
|
+
'enforce_retention() {{\n'
|
|
343
|
+
' log_message "Enforcing retention: removing remote folders older than {days} days"\n'
|
|
344
|
+
' local cutoff; cutoff=$(date -d "{days} days ago" +"%Y-%m-%d")\n'
|
|
345
|
+
' rclone lsf "${{REMOTE_NAME}}:{host}/" --dirs-only --config "$RCLONE_CONFIG" 2>>"$LOG_FILE" | while read -r folder; do\n'
|
|
346
|
+
' local name="${{folder%/}}"\n'
|
|
347
|
+
' if [[ "$name" =~ ^[0-9]{{4}}-[0-9]{{2}}-[0-9]{{2}}$ ]] && [[ "$name" < "$cutoff" ]]; then\n'
|
|
348
|
+
' log_message "Deleting old backup folder: $name"\n'
|
|
349
|
+
' rclone purge "${{REMOTE_NAME}}:{host}/$name" --config "$RCLONE_CONFIG" --quiet 2>>"$LOG_FILE" \\\n'
|
|
350
|
+
' || log_message "WARN: purge failed for $name"\n'
|
|
351
|
+
' fi\n'
|
|
352
|
+
' done\n'
|
|
353
|
+
'}}'
|
|
329
354
|
).format(days=retention_days, host=host_name)
|
|
330
355
|
|
|
331
356
|
|
|
@@ -7,6 +7,23 @@ This script sets up Django environment before running pyinfra,
|
|
|
7
7
|
allowing inventory files to use Django models and settings.
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
+
# Monkey-patch before anything else is imported. pyinfra_cli does this in its
|
|
11
|
+
# own __init__, but by then Django has been set up and ssl/threading are already
|
|
12
|
+
# imported — gevent warns about exactly that ("Monkey-patching ssl after ssl has
|
|
13
|
+
# already been imported ... may silently lead to incorrect behaviour"), which is
|
|
14
|
+
# not a warning to live with in a tool that exists to open SSH connections.
|
|
15
|
+
#
|
|
16
|
+
# It also breaks Django projects outright. Patching walks every live object and
|
|
17
|
+
# isinstance()-checks it; that resolves any LazyObject it touches. Django's
|
|
18
|
+
# `django.contrib.admin.sites.site` is one, and it exists whenever anything has
|
|
19
|
+
# imported `django.contrib.admin` — Wagtail does, via
|
|
20
|
+
# `wagtail/admin/admin_url_finder.py`. If the project doesn't have the admin app
|
|
21
|
+
# in INSTALLED_APPS, resolving it raises `LookupError: No installed app with
|
|
22
|
+
# label 'admin'` before pyinfra has connected to anything.
|
|
23
|
+
from gevent import monkey
|
|
24
|
+
|
|
25
|
+
monkey.patch_all()
|
|
26
|
+
|
|
10
27
|
import os
|
|
11
28
|
import sys
|
|
12
29
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.3.1"
|
djaploy-1.3.0/djaploy/version.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.3.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|