Release v1.0.0
This commit is contained in:
76
scripts/scheduled-maintenance.sh
Executable file
76
scripts/scheduled-maintenance.sh
Executable file
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
usage() {
|
||||
cat >&2 <<'EOF'
|
||||
Usage: scheduled-maintenance.sh <backup|restore-latest>
|
||||
|
||||
Requires FRAMEFLOW_BACKUP_MOUNTPOINT and FRAMEFLOW_BACKUP_DESTINATION.
|
||||
The destination must be a writable directory inside the active mount point.
|
||||
EOF
|
||||
exit "${1:-2}"
|
||||
}
|
||||
|
||||
fail() {
|
||||
echo "Scheduled maintenance failed: $1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
[[ $# -eq 1 ]] || usage
|
||||
case "$1" in
|
||||
backup|restore-latest) mode="$1" ;;
|
||||
--help|-h) usage 0 ;;
|
||||
*) usage ;;
|
||||
esac
|
||||
|
||||
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
mount_point="${FRAMEFLOW_BACKUP_MOUNTPOINT:-}"
|
||||
backup_destination="${FRAMEFLOW_BACKUP_DESTINATION:-}"
|
||||
|
||||
[[ -n "${mount_point}" ]] || fail "FRAMEFLOW_BACKUP_MOUNTPOINT is required"
|
||||
[[ -n "${backup_destination}" ]] || fail "FRAMEFLOW_BACKUP_DESTINATION is required"
|
||||
|
||||
for path in "${mount_point}" "${backup_destination}"; do
|
||||
[[ "${path}" == /* ]] || fail "backup paths must be absolute: ${path}"
|
||||
[[ "${path}" != "/" ]] || fail "the filesystem root cannot be used for backups"
|
||||
[[ ! "${path}" =~ [[:space:]] ]] || fail "backup paths must not contain whitespace: ${path}"
|
||||
[[ -d "${path}" ]] || fail "backup directory does not exist: ${path}"
|
||||
[[ ! -L "${path}" ]] || fail "backup paths must not be symbolic links: ${path}"
|
||||
done
|
||||
|
||||
mount_point="$(cd "${mount_point}" && pwd -P)"
|
||||
backup_destination="$(cd "${backup_destination}" && pwd -P)"
|
||||
if [[ "${backup_destination}" != "${mount_point}" && "${backup_destination}" != "${mount_point}/"* ]]; then
|
||||
fail "backup destination must be inside FRAMEFLOW_BACKUP_MOUNTPOINT"
|
||||
fi
|
||||
[[ -w "${backup_destination}" ]] || fail "backup destination is not writable: ${backup_destination}"
|
||||
|
||||
command -v findmnt >/dev/null 2>&1 || fail "findmnt is required to verify the backup mount"
|
||||
mounted_target="$(findmnt -rn -M "${mount_point}" -o TARGET 2>/dev/null)" \
|
||||
|| fail "backup mount is not active: ${mount_point}"
|
||||
[[ "${mounted_target}" == "${mount_point}" ]] \
|
||||
|| fail "backup mount resolved to an unexpected target: ${mounted_target}"
|
||||
|
||||
case "${mode}" in
|
||||
backup)
|
||||
exec "${script_dir}/backup.sh" "${backup_destination}"
|
||||
;;
|
||||
restore-latest)
|
||||
latest_name=""
|
||||
latest_path=""
|
||||
while IFS= read -r -d '' candidate; do
|
||||
[[ ! -L "${candidate}" ]] || continue
|
||||
candidate_name="${candidate##*/}"
|
||||
[[ "${candidate_name}" =~ ^frameflow-[0-9]{8}T[0-9]{6}Z$ ]] || continue
|
||||
if [[ -z "${latest_name}" || "${candidate_name}" > "${latest_name}" ]]; then
|
||||
latest_name="${candidate_name}"
|
||||
latest_path="${candidate}"
|
||||
fi
|
||||
done < <(find "${backup_destination}" -mindepth 1 -maxdepth 1 -type d -name 'frameflow-*' -print0)
|
||||
|
||||
[[ -n "${latest_path}" ]] || fail "no timestamped FrameFlow backup was found"
|
||||
echo "Selected latest backup for restore rehearsal: ${latest_path}"
|
||||
"${script_dir}/verify-backup.sh" "${latest_path}"
|
||||
exec "${script_dir}/rehearse-restore.sh" "${latest_path}"
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user