155 lines
4.6 KiB
Bash
Executable File
155 lines
4.6 KiB
Bash
Executable File
#!/bin/bash
|
|
# =============================================================================
|
|
# WOOO AIOps - Configure host-local Backblaze B2 credentials for offsite backup
|
|
# 2026-05-06 ogt + Codex: 提供不進 repo 的 offsite.env 設定 helper。
|
|
#
|
|
# Secrets policy:
|
|
# - Writes only to /backup/scripts/offsite.env by default.
|
|
# - File mode is 0600.
|
|
# - Never prints credential values.
|
|
# - Prefer interactive prompt on 110; --write-from-env is for controlled ops.
|
|
# =============================================================================
|
|
|
|
set -euo pipefail
|
|
|
|
BACKUP_BASE="${BACKUP_BASE:-/backup}"
|
|
OFFSITE_ENV_FILE="${BACKUP_OFFSITE_ENV_FILE:-${BACKUP_BASE}/scripts/offsite.env}"
|
|
MODE="status"
|
|
|
|
usage() {
|
|
cat <<'USAGE'
|
|
Usage:
|
|
configure-offsite-b2.sh --status
|
|
configure-offsite-b2.sh --interactive
|
|
B2_ACCOUNT_ID=... B2_APPLICATION_KEY=... B2_BUCKET=... configure-offsite-b2.sh --write-from-env
|
|
|
|
This writes /backup/scripts/offsite.env with mode 0600.
|
|
Do not paste secrets into chat, repo files, LOGBOOK, Telegram, or Prometheus labels.
|
|
USAGE
|
|
}
|
|
|
|
while [ "$#" -gt 0 ]; do
|
|
case "$1" in
|
|
--status)
|
|
MODE="status"
|
|
shift
|
|
;;
|
|
--interactive)
|
|
MODE="interactive"
|
|
shift
|
|
;;
|
|
--write-from-env)
|
|
MODE="write-from-env"
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown argument: $1" >&2
|
|
usage >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
done
|
|
|
|
configured() {
|
|
local value="$1"
|
|
[ -n "${value}" ] && [ "${value}" != "CHANGE_ME" ] && [ "${value}" != "REDACTED" ]
|
|
}
|
|
|
|
quote_shell() {
|
|
printf "%q" "$1"
|
|
}
|
|
|
|
load_existing() {
|
|
if [ -f "${OFFSITE_ENV_FILE}" ]; then
|
|
# shellcheck disable=SC1090
|
|
source "${OFFSITE_ENV_FILE}"
|
|
fi
|
|
}
|
|
|
|
show_status() {
|
|
load_existing
|
|
echo "OFFSITE_ENV_FILE=${OFFSITE_ENV_FILE}"
|
|
if [ -f "${OFFSITE_ENV_FILE}" ]; then
|
|
mode="$(stat -c '%a' "${OFFSITE_ENV_FILE}" 2>/dev/null || stat -f '%Lp' "${OFFSITE_ENV_FILE}" 2>/dev/null || echo unknown)"
|
|
echo "OFFSITE_ENV_PRESENT=1"
|
|
echo "OFFSITE_ENV_MODE=${mode}"
|
|
else
|
|
echo "OFFSITE_ENV_PRESENT=0"
|
|
fi
|
|
configured "${B2_ACCOUNT_ID:-}" && echo "B2_ACCOUNT_ID_CONFIGURED=1" || echo "B2_ACCOUNT_ID_CONFIGURED=0"
|
|
configured "${B2_APPLICATION_KEY:-}" && echo "B2_APPLICATION_KEY_CONFIGURED=1" || echo "B2_APPLICATION_KEY_CONFIGURED=0"
|
|
configured "${B2_BUCKET:-}" && echo "B2_BUCKET_CONFIGURED=1" || echo "B2_BUCKET_CONFIGURED=0"
|
|
command -v rclone >/dev/null 2>&1 && echo "RCLONE_PRESENT=1" || echo "RCLONE_PRESENT=0"
|
|
}
|
|
|
|
validate_inputs() {
|
|
if ! configured "${B2_ACCOUNT_ID:-}"; then
|
|
echo "B2_ACCOUNT_ID is required" >&2
|
|
return 1
|
|
fi
|
|
if ! configured "${B2_APPLICATION_KEY:-}"; then
|
|
echo "B2_APPLICATION_KEY is required" >&2
|
|
return 1
|
|
fi
|
|
if ! configured "${B2_BUCKET:-}"; then
|
|
echo "B2_BUCKET is required" >&2
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
write_env() {
|
|
validate_inputs
|
|
parent_dir="$(dirname "${OFFSITE_ENV_FILE}")"
|
|
if [ ! -d "${parent_dir}" ]; then
|
|
install -d -m 0750 "${parent_dir}"
|
|
fi
|
|
tmp="$(mktemp "${OFFSITE_ENV_FILE}.tmp.XXXXXX")"
|
|
chmod 0600 "${tmp}"
|
|
cat > "${tmp}" <<EOF
|
|
# AWOOOI host-local offsite backup credentials.
|
|
# Created by configure-offsite-b2.sh.
|
|
# Do not commit this file or paste its contents into chat/logs.
|
|
export B2_ACCOUNT_ID=$(quote_shell "${B2_ACCOUNT_ID}")
|
|
export B2_APPLICATION_KEY=$(quote_shell "${B2_APPLICATION_KEY}")
|
|
export B2_BUCKET=$(quote_shell "${B2_BUCKET}")
|
|
export RCLONE_BWLIMIT=$(quote_shell "${RCLONE_BWLIMIT:-8M}")
|
|
export RCLONE_TRANSFERS=$(quote_shell "${RCLONE_TRANSFERS:-2}")
|
|
export RCLONE_CHECKERS=$(quote_shell "${RCLONE_CHECKERS:-4}")
|
|
EOF
|
|
mv "${tmp}" "${OFFSITE_ENV_FILE}"
|
|
chmod 0600 "${OFFSITE_ENV_FILE}"
|
|
echo "OFFSITE_ENV_WRITTEN=${OFFSITE_ENV_FILE}"
|
|
}
|
|
|
|
interactive_write() {
|
|
if [ ! -t 0 ]; then
|
|
echo "--interactive requires a TTY" >&2
|
|
exit 2
|
|
fi
|
|
load_existing
|
|
read -r -p "B2_ACCOUNT_ID: " B2_ACCOUNT_ID
|
|
read -r -s -p "B2_APPLICATION_KEY: " B2_APPLICATION_KEY
|
|
printf '\n'
|
|
read -r -p "B2_BUCKET [${B2_BUCKET:-wooo-aiops-backup}]: " bucket_input
|
|
B2_BUCKET="${bucket_input:-${B2_BUCKET:-wooo-aiops-backup}}"
|
|
read -r -p "RCLONE_BWLIMIT [${RCLONE_BWLIMIT:-8M}]: " bwlimit_input
|
|
RCLONE_BWLIMIT="${bwlimit_input:-${RCLONE_BWLIMIT:-8M}}"
|
|
write_env
|
|
}
|
|
|
|
case "${MODE}" in
|
|
status)
|
|
show_status
|
|
;;
|
|
interactive)
|
|
interactive_write
|
|
;;
|
|
write-from-env)
|
|
write_env
|
|
;;
|
|
esac
|