Files
CurrenciCombo/scripts/deployment/install-prune-cron.sh
Devin AI a6a9d38bce PR AB: complete Phoenix deployment scaffolding (add 3 missing files referenced by main 4a1f69a)
main 4a1f69a 'deploy: make Phoenix redeploys archive-safe' adopted the
Phoenix deployment scaffolding from the abandoned PR #31 branch but
landed with three referenced-but-missing files. This PR adds exactly
those three files, unchanged from the PR #31 branch, so main is
internally consistent and bootable on CT 8604.

What main references but does not have
--------------------------------------

1. scripts/deployment/webapp-nginx.conf
   Referenced by: systemd/currencicombo-webapp.service (ExecStart calls
   'nginx -c /etc/currencicombo/webapp-nginx.conf') and install.sh
   (NGINX_FILE="${ETC_DIR}/webapp-nginx.conf"; install -m 0644 of
   "${SCRIPT_DIR}/webapp-nginx.conf").
   Without this file: webapp unit fails on start with 'nginx: [emerg]
   open() "/etc/currencicombo/webapp-nginx.conf" failed'.

2. scripts/deployment/systemd/currencicombo-orchestrator.service
   Referenced by: deploy-currencicombo-8604.sh (line 40:
   ${ORCHESTRATOR_UNIT:=currencicombo-orchestrator.service};
   lines 101/104 systemctl stop/start) and install.sh (line 238
   install -m 0644 of
   "${SCRIPT_DIR}/systemd/currencicombo-orchestrator.service";
   line 248 systemctl enable).
   Without this file: install.sh fails at the install step, deploy
   script fails at 'systemctl stop currencicombo-orchestrator.service
   Unit not found'.

3. scripts/deployment/install-prune-cron.sh
   Referenced by: README.md (step 4: 'bash /var/lib/currencicombo/repo/
   scripts/deployment/install-prune-cron.sh' and the 'Backup retention
   / pruning' section).
   Without this file: ops follows the README, hits a 'No such file'
   and has to reconstruct the pruner from prose.

Provenance
----------

All three files are verbatim copies of the same three files from the
closed PR #31 branch devin/1776898782-pr-aa-phoenix-migration (commit
ded7d24), which was the source PR #31 reviewers discussed when the
three ops improvements (loud-failure rollback, keep-min-5 prune cron,
/root/currencicombo-first-keys.txt 0600) were locked. main already
absorbed everything else from PR #31 as commit 4a1f69a.

Verification
------------

- shellcheck --severity=warning scripts/deployment/install-prune-cron.sh: clean
- bash -n on install-prune-cron.sh: clean
- systemd-analyze verify on currencicombo-orchestrator.service: clean
  (only unrelated-host-service errors surface on this build box)
- sudo bash scripts/deployment/install-prune-cron.sh --dry-run: prints
  the exact cron body with retain=30, keep-min=5, targeting
  /var/lib/currencicombo/backups, as expected.
- nginx -T on webapp-nginx.conf: not run (nginx not installed on
  build box); tested on the CT in PR #31's pre-close verification run.

Co-Authored-By: Nakamoto, S <defi@defi-oracle.io>
2026-04-23 04:26:50 +00:00

103 lines
3.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# install-prune-cron.sh — opt-in cron job to prune old deploy backups.
#
# Run ONCE as root (or with sudo) after install.sh to enable daily
# pruning of /var/lib/currencicombo/backups/. The pruner:
# - deletes entries older than 30 days
# - ALWAYS keeps the newest N backups regardless of age (default 5)
#
# No-op on re-run. Opt out by removing /etc/cron.daily/currencicombo-prune-backups.
set -euo pipefail
BACKUP_DIR="${CC_BACKUP_DIR:-/var/lib/currencicombo/backups}"
RETAIN_DAYS="${CC_BACKUP_RETAIN_DAYS:-30}"
KEEP_MIN="${CC_BACKUP_KEEP_MIN:-5}"
CRON_FILE="/etc/cron.daily/currencicombo-prune-backups"
DRY_RUN=0
while [[ $# -gt 0 ]]; do
case "$1" in
--dry-run) DRY_RUN=1; shift ;;
-h|--help)
cat <<'USAGE'
Usage: sudo ./install-prune-cron.sh [--dry-run]
Env overrides:
CC_BACKUP_DIR (default: /var/lib/currencicombo/backups)
CC_BACKUP_RETAIN_DAYS (default: 30)
CC_BACKUP_KEEP_MIN (default: 5)
USAGE
exit 0 ;;
*) echo "unknown arg: $1" >&2; exit 2 ;;
esac
done
log() { printf '[install-prune-cron] %s\n' "$*" >&2; }
die() { printf '[install-prune-cron][FATAL] %s\n' "$*" >&2; exit 1; }
[[ "$EUID" -eq 0 ]] || die "must run as root (sudo)"
# The pruner script body. Runs daily via cron.daily.
# KEEP_MIN is enforced by listing backups newest-first, skipping the
# first KEEP_MIN, then deleting any remaining entries older than
# RETAIN_DAYS. This means we always keep at least KEEP_MIN (even if
# they're all <30 days old), and never delete one of the newest
# KEEP_MIN (even if it's >30 days old on a dormant host).
read -r -d '' PRUNER_BODY <<PRUNER || true
#!/usr/bin/env bash
# Managed by scripts/deployment/install-prune-cron.sh. Edits overwritten
# on next install. Opt out by deleting this file.
set -euo pipefail
BACKUP_DIR="${BACKUP_DIR}"
RETAIN_DAYS=${RETAIN_DAYS}
KEEP_MIN=${KEEP_MIN}
[[ -d "\$BACKUP_DIR" ]] || exit 0
cd "\$BACKUP_DIR"
mapfile -t all < <(find . -mindepth 1 -maxdepth 1 -type d -printf '%T@ %p\n' 2>/dev/null | sort -rn | awk '{print \$2}')
count=\${#all[@]}
if (( count <= KEEP_MIN )); then
logger -t currencicombo-prune "count=\$count <= KEEP_MIN=\$KEEP_MIN; nothing to prune"
exit 0
fi
cutoff=\$(date -d "\$RETAIN_DAYS days ago" +%s)
deleted=0
kept=0
for i in "\${!all[@]}"; do
p="\${all[\$i]}"
if (( i < KEEP_MIN )); then
kept=\$((kept + 1))
continue
fi
mtime=\$(stat -c %Y "\$p" 2>/dev/null || echo 0)
if (( mtime < cutoff )); then
rm -rf -- "\$p"
deleted=\$((deleted + 1))
else
kept=\$((kept + 1))
fi
done
logger -t currencicombo-prune "deleted=\$deleted kept=\$kept total_before=\$count"
PRUNER
if [[ "${DRY_RUN}" -eq 1 ]]; then
log "[dry-run] would write ${CRON_FILE} (0755) with pruner targeting ${BACKUP_DIR}, retain ${RETAIN_DAYS}d, keep-min ${KEEP_MIN}"
echo "---"
echo "${PRUNER_BODY}"
echo "---"
exit 0
fi
printf '%s\n' "${PRUNER_BODY}" > "${CRON_FILE}"
chmod 0755 "${CRON_FILE}"
chown root:root "${CRON_FILE}"
log "installed ${CRON_FILE} (backups older than ${RETAIN_DAYS}d, keep-min ${KEEP_MIN}, target ${BACKUP_DIR})"
log "runs daily via /etc/cron.daily/. Opt out: sudo rm ${CRON_FILE}"
log "logs to syslog (tag currencicombo-prune); journalctl -t currencicombo-prune"