Files
awoooi/scripts/backup/gitea-bundle-sample-restore-dry-run.sh
Your Name 2f3db555e4
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 1m1s
CD Pipeline / build-and-deploy (push) Successful in 4m25s
AWOOOI Harbor 110 Local Repair / workflow-shape (push) Successful in 0s
AWOOOI Harbor 110 Local Repair / harbor-110-local-repair (push) Failing after 29s
CD Pipeline / post-deploy-checks (push) Successful in 1m45s
fix(gitea): expose bundle backup restore readback
2026-07-02 23:13:13 +08:00

150 lines
5.0 KiB
Bash
Executable File

#!/usr/bin/env bash
# Verify one Gitea bundle can be restored into a temporary mirror clone.
# This is a dry-run verifier only. It does not restore into production, mutate
# Gitea, read credentials, delete repositories, or change repo visibility.
set -euo pipefail
ROOT="${AIOPS_GITEA_BUNDLE_ROOT:-/home/ollama/backup/110/gitea/git-bundles/latest-private-complete}"
REPO="${AIOPS_GITEA_BUNDLE_SAMPLE_REPO:-wooo/awoooi}"
HOST_LABEL="${AIOPS_HOST_LABEL:-188}"
TEXTFILE_PATH="${AIOPS_GITEA_BUNDLE_RESTORE_TEXTFILE:-/home/ollama/node_exporter_textfiles/gitea_bundle_restore_dry_run.prom}"
WRITE_TEXTFILE=0
TIMEOUT_SECONDS="${TIMEOUT_SECONDS:-120}"
usage() {
cat <<'USAGE'
Usage: scripts/backup/gitea-bundle-sample-restore-dry-run.sh [options]
Options:
--root PATH Bundle root directory.
--repo OWNER/NAME Repository sample to verify. Default: wooo/awoooi.
--write-textfile Write node-exporter textfile metric after verification.
--textfile PATH Textfile metric path.
-h, --help Show this help.
This verifier clones the bundle into a temporary mirror and runs git fsck.
It never restores to production, never contacts Gitea, and never reads tokens.
USAGE
}
while [ "$#" -gt 0 ]; do
case "$1" in
--root)
shift
ROOT="${1:?--root requires PATH}"
;;
--repo)
shift
REPO="${1:?--repo requires OWNER/NAME}"
;;
--write-textfile)
WRITE_TEXTFILE=1
;;
--textfile)
shift
TEXTFILE_PATH="${1:?--textfile requires PATH}"
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown argument: $1" >&2
usage >&2
exit 64
;;
esac
shift
done
slug="${REPO//\//__}"
repo_name="${REPO##*/}"
bundle_path=""
checksum_path=""
if [ -f "${ROOT}/${slug}.bundle" ]; then
bundle_path="${ROOT}/${slug}.bundle"
elif [ -f "${ROOT}/manifest.remote.tsv" ] || [ -f "${ROOT}/manifest.tsv" ]; then
manifest="${ROOT}/manifest.remote.tsv"
[ -f "$manifest" ] || manifest="${ROOT}/manifest.tsv"
bundle_path="$(awk -F '\t' -v repo="$REPO" 'NR > 1 && $1 == repo {print $4; exit}' "$manifest")"
if [ -n "$bundle_path" ] && [ ! -f "$bundle_path" ] && [ -f "${ROOT}/$(basename "$bundle_path")" ]; then
bundle_path="${ROOT}/$(basename "$bundle_path")"
fi
fi
if [ -z "$bundle_path" ] || [ ! -f "$bundle_path" ]; then
first_match="$(find "$ROOT" -maxdepth 1 -type f -name "${repo_name}-local-*.bundle" | sort | tail -n 1)"
bundle_path="$first_match"
fi
ok=0
ref_count=0
error_reason=""
tmp_root=""
if [ -z "$bundle_path" ] || [ ! -f "$bundle_path" ]; then
error_reason="bundle_not_found"
else
checksum_path="${bundle_path}.sha256"
if [ -f "$checksum_path" ]; then
expected="$(awk 'NR == 1 {print $1}' "$checksum_path")"
if command -v sha256sum >/dev/null 2>&1; then
actual="$(sha256sum "$bundle_path" | awk '{print $1}')"
else
actual="$(shasum -a 256 "$bundle_path" | awk '{print $1}')"
fi
if [ "$expected" != "$actual" ]; then
error_reason="checksum_mismatch"
fi
fi
fi
if [ -z "$error_reason" ]; then
tmp_root="$(mktemp -d "${TMPDIR:-/tmp}/gitea-bundle-restore.XXXXXX")"
trap 'rm -rf "$tmp_root"' EXIT
if ! timeout "$TIMEOUT_SECONDS" git clone --mirror --quiet "$bundle_path" "${tmp_root}/restore.git"; then
error_reason="clone_failed"
elif ! timeout "$TIMEOUT_SECONDS" git -C "${tmp_root}/restore.git" fsck --connectivity-only >/dev/null; then
error_reason="fsck_failed"
else
ref_count="$(git -C "${tmp_root}/restore.git" for-each-ref --format='%(refname)' | wc -l | tr -d ' ')"
ok=1
fi
fi
timestamp="$(date +%s)"
bundle_name="$(basename "${bundle_path:-missing}")"
root_label="${ROOT//\\/\\\\}"
root_label="${root_label//\"/\\\"}"
repo_label="${REPO//\\/\\\\}"
repo_label="${repo_label//\"/\\\"}"
bundle_label="${bundle_name//\\/\\\\}"
bundle_label="${bundle_label//\"/\\\"}"
error_label="${error_reason//\\/\\\\}"
error_label="${error_label//\"/\\\"}"
if [ "$WRITE_TEXTFILE" -eq 1 ]; then
mkdir -p "$(dirname "$TEXTFILE_PATH")"
tmp_textfile="${TEXTFILE_PATH}.$$"
{
echo '# HELP awoooi_gitea_bundle_sample_restore_dry_run_ok Whether sample Gitea bundle restore dry-run succeeded.'
echo '# TYPE awoooi_gitea_bundle_sample_restore_dry_run_ok gauge'
printf 'awoooi_gitea_bundle_sample_restore_dry_run_ok{host="%s",repo="%s",root="%s",bundle="%s",error="%s"} %s\n' "$HOST_LABEL" "$repo_label" "$root_label" "$bundle_label" "$error_label" "$ok"
printf 'awoooi_gitea_bundle_sample_restore_dry_run_timestamp{host="%s",repo="%s"} %s\n' "$HOST_LABEL" "$repo_label" "$timestamp"
printf 'awoooi_gitea_bundle_sample_restore_dry_run_ref_count{host="%s",repo="%s"} %s\n' "$HOST_LABEL" "$repo_label" "$ref_count"
} > "$tmp_textfile"
mv "$tmp_textfile" "$TEXTFILE_PATH"
fi
printf 'GITEA_BUNDLE_SAMPLE_RESTORE_DRY_RUN_OK=%s\n' "$ok"
printf 'REPO=%s\n' "$REPO"
printf 'BUNDLE=%s\n' "${bundle_path:-missing}"
printf 'REF_COUNT=%s\n' "$ref_count"
printf 'TEXTFILE_WRITTEN=%s\n' "$WRITE_TEXTFILE"
if [ -n "$error_reason" ]; then
printf 'ERROR=%s\n' "$error_reason"
exit 1
fi