geocrop-platform./apps/nextgen/scripts/backup/install-backup-cron.sh

104 lines
3.6 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# install-backup-cron.sh
# -----------------------
# One-shot installer for the Africa Alert SQLite backup cron job.
#
# Idempotent: re-running is a no-op if the cron entry is already present
# (detected by `crontab -l | grep -q africa-alert`).
#
# Default schedule: every 12 hours (00:00 and 12:00 UTC).
# Override with CRON_SCHEDULE env var, e.g.
# CRON_SCHEDULE="0 */6 * * *" sudo ./install-backup-cron.sh
#
# This script is meant to be run on the production Ubuntu 22.04 host.
# It is NOT a Windows script. On a Windows dev box, only
# `bash -n install-backup-cron.sh` (syntax check) is meaningful.
set -eu
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
BACKUP_SCRIPT="${SCRIPT_DIR}/africa-alert-backup.sh"
CRON_SCHEDULE="${CRON_SCHEDULE:-0 */12 * * *}" # every 12h, on the hour
LOG_DIR="${LOG_DIR:-${PROJECT_ROOT}/logs}"
INSTALL_LOG="${LOG_DIR}/backup-install.log"
# Marker used by both the grep-based idempotency check and as a comment
# inside the crontab so an operator reading `crontab -l` knows what the
# line does. Keep the marker stable — other tooling relies on it.
CRON_MARKER="africa-alert-backup"
mkdir -p "${LOG_DIR}"
touch "${INSTALL_LOG}"
log() {
local msg="[$(date -u +%Y-%m-%dT%H:%M:%SZ)] [install-cron] $*"
echo "${msg}" | tee -a "${INSTALL_LOG}" >&2
}
if [ ! -x "${BACKUP_SCRIPT}" ]; then
log "ERROR: backup script not found or not executable: ${BACKUP_SCRIPT}"
log "Hint: chmod +x ${BACKUP_SCRIPT}"
exit 1
fi
# Idempotency check: does the current crontab already contain our marker?
if command -v crontab >/dev/null 2>&1; then
EXISTING="$(crontab -l 2>/dev/null || true)"
if echo "${EXISTING}" | grep -q "${CRON_MARKER}"; then
log "cron entry already installed; nothing to do."
log "current crontab:"
echo "${EXISTING}" | grep "${CRON_MARKER}" | sed 's/^/ /' | tee -a "${INSTALL_LOG}" >&2
log "to reinstall, first run: crontab -l | grep -v '${CRON_MARKER}' | crontab -"
exit 0
fi
else
log "WARN: crontab command not found; this is not a Linux host. Aborting."
exit 1
fi
# Build the cron line. The marker is a leading comment so it's greppable.
CRON_LINE="${CRON_SCHEDULE} /bin/bash ${BACKUP_SCRIPT} >> ${LOG_DIR}/backup.log 2>&1 # ${CRON_MARKER}"
# Install: append the new line to whatever crontab exists, or create one
# if none. `crontab -` reads from stdin.
{
echo "${EXISTING:-}"
echo "${CRON_LINE}"
} | crontab -
# Compute the next-run time. We use a small GNU-date trick: if now is
# earlier than the next scheduled firing, that's the next run; otherwise
# advance by 12h. This is a best-effort estimate — cron itself is the
# source of truth. Format: YYYY-MM-DD HH:MM:SS UTC.
compute_next_run() {
local now_epoch
now_epoch="$(date -u +%s)"
# Step forward in 12h blocks until we land in the future.
local candidate="${now_epoch}"
while [ "${candidate}" -le "${now_epoch}" ]; do
candidate=$((candidate + 12 * 3600))
done
# Snap to the next "round" 12h boundary (00:00 or 12:00 UTC) by
# subtracting (epoch mod 12h). This matches CRON_SCHEDULE default.
local bucket=$((candidate % (12 * 3600)))
candidate=$((candidate - bucket))
# If snapping pushed us into the past, add another 12h.
if [ "${candidate}" -le "${now_epoch}" ]; then
candidate=$((candidate + 12 * 3600))
fi
date -u -d "@${candidate}" +"%Y-%m-%d %H:%M:%S UTC"
}
NEXT_RUN="$(compute_next_run)"
log "installed cron entry:"
log " ${CRON_LINE}"
log "next scheduled run (estimate): ${NEXT_RUN}"
log "verify with: crontab -l | grep ${CRON_MARKER}"
log "uninstall with: crontab -l | grep -v '${CRON_MARKER}' | crontab -"
exit 0