- phase1_gitea_unraid.sh: 9-step deploy (dirs, docker-compose, app.ini, container start, wait, admin user, API token, save to .env, create org). Every step has idempotency check — running twice changes nothing. - phase1_post_check.sh: 5 independent verification checks - phase1_teardown.sh: stop container + optionally remove data, with prompts Also adds inline comments to lib/common.sh and preflight.sh explaining WHY decisions were made (SSH flags, API tmpfile pattern, port checks, etc.) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
266 lines
10 KiB
Bash
Executable File
266 lines
10 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# =============================================================================
|
|
# preflight.sh — Validate everything before running migration phases
|
|
# Installs nothing. Exits 0 only if ALL checks pass.
|
|
# =============================================================================
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
source "${SCRIPT_DIR}/lib/common.sh"
|
|
|
|
log_info "=== Preflight Checks ==="
|
|
|
|
PASS_COUNT=0
|
|
FAIL_COUNT=0
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Check helper — runs a check function, tracks pass/fail count.
|
|
# Intentionally does NOT exit on failure — we want to run ALL 16 checks
|
|
# so the user sees every issue at once, not one at a time.
|
|
# ---------------------------------------------------------------------------
|
|
check() {
|
|
local num="$1" description="$2"
|
|
shift 2
|
|
|
|
if "$@" 2>/dev/null; then
|
|
log_success "[${num}] ${description}"
|
|
PASS_COUNT=$((PASS_COUNT + 1))
|
|
else
|
|
log_error "[${num}] FAIL: ${description}"
|
|
FAIL_COUNT=$((FAIL_COUNT + 1))
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Check 1: .env exists
|
|
# ---------------------------------------------------------------------------
|
|
check_env_exists() {
|
|
[[ -f "${SCRIPT_DIR}/.env" ]]
|
|
}
|
|
check 1 ".env file exists" check_env_exists
|
|
if [[ ! -f "${SCRIPT_DIR}/.env" ]]; then
|
|
log_error " → .env not found. Copy .env.example to .env and fill in values."
|
|
log_error " → Or run: setup/configure_env.sh"
|
|
# Can't continue without .env — run remaining checks but they'll mostly fail
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Check 2: runners.conf exists
|
|
# ---------------------------------------------------------------------------
|
|
check_runners_conf() {
|
|
[[ -f "${SCRIPT_DIR}/runners.conf" ]]
|
|
}
|
|
check 2 "runners.conf file exists" check_runners_conf
|
|
if [[ ! -f "${SCRIPT_DIR}/runners.conf" ]]; then
|
|
log_error " → runners.conf not found. Copy runners.conf.example to runners.conf."
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Load env for remaining checks (may fail if .env missing)
|
|
# ---------------------------------------------------------------------------
|
|
if [[ -f "${SCRIPT_DIR}/.env" ]]; then
|
|
load_env
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Check 3: Required .env vars
|
|
# ---------------------------------------------------------------------------
|
|
REQUIRED_VARS=(
|
|
UNRAID_IP UNRAID_SSH_USER UNRAID_GITEA_DATA_PATH
|
|
FEDORA_IP FEDORA_SSH_USER FEDORA_GITEA_DATA_PATH
|
|
GITEA_ADMIN_USER GITEA_ADMIN_PASSWORD GITEA_ADMIN_EMAIL
|
|
GITEA_ORG_NAME GITEA_INSTANCE_NAME
|
|
GITEA_DOMAIN GITEA_INTERNAL_URL
|
|
GITEA_BACKUP_INTERNAL_URL BACKUP_STORAGE_PATH
|
|
GITHUB_USERNAME GITHUB_TOKEN
|
|
REPO_1_NAME REPO_2_NAME REPO_3_NAME
|
|
GITHUB_MIRROR_TOKEN
|
|
NGINX_CONTAINER_NAME NGINX_CONF_PATH SSL_EMAIL
|
|
)
|
|
|
|
check_required_vars() {
|
|
local missing=0
|
|
for var in "${REQUIRED_VARS[@]}"; do
|
|
if [[ -z "${!var:-}" ]]; then
|
|
log_error " → Missing required var: $var"
|
|
missing=1
|
|
fi
|
|
done
|
|
return $missing
|
|
}
|
|
check 3 "All required .env vars are set" check_required_vars
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Check 4: SSH to Unraid
|
|
# ---------------------------------------------------------------------------
|
|
check_ssh_unraid() {
|
|
ssh_check UNRAID
|
|
}
|
|
check 4 "SSH to Unraid (${UNRAID_IP:-<not set>})" check_ssh_unraid
|
|
if [[ $FAIL_COUNT -gt 0 ]] && ! ssh_check UNRAID 2>/dev/null; then
|
|
log_error " → Cannot SSH to Unraid. Run setup/unraid.sh or check SSH config."
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Check 5: SSH to Fedora
|
|
# ---------------------------------------------------------------------------
|
|
check_ssh_fedora() {
|
|
ssh_check FEDORA
|
|
}
|
|
check 5 "SSH to Fedora (${FEDORA_IP:-<not set>})" check_ssh_fedora
|
|
if ! ssh_check FEDORA 2>/dev/null; then
|
|
log_error " → Cannot SSH to Fedora. Run setup/fedora.sh or check SSH config."
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Check 6: Docker on Unraid
|
|
# ---------------------------------------------------------------------------
|
|
check_docker_unraid() {
|
|
ssh_exec UNRAID "docker --version" &>/dev/null
|
|
}
|
|
check 6 "Docker available on Unraid" check_docker_unraid
|
|
if ! check_docker_unraid 2>/dev/null; then
|
|
log_error " → Docker not found on Unraid. Run setup/unraid.sh."
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Check 7: Docker on Fedora
|
|
# ---------------------------------------------------------------------------
|
|
check_docker_fedora() {
|
|
ssh_exec FEDORA "docker --version" &>/dev/null
|
|
}
|
|
check 7 "Docker available on Fedora" check_docker_fedora
|
|
if ! check_docker_fedora 2>/dev/null; then
|
|
log_error " → Docker not found on Fedora. Run setup/fedora.sh."
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Check 8: docker-compose on Unraid
|
|
# ---------------------------------------------------------------------------
|
|
check_compose_unraid() {
|
|
ssh_exec UNRAID "docker compose version" &>/dev/null || ssh_exec UNRAID "docker-compose --version" &>/dev/null
|
|
}
|
|
check 8 "docker-compose available on Unraid" check_compose_unraid
|
|
if ! check_compose_unraid 2>/dev/null; then
|
|
log_error " → docker-compose not found on Unraid. Run setup/unraid.sh."
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Check 9: docker-compose on Fedora
|
|
# ---------------------------------------------------------------------------
|
|
check_compose_fedora() {
|
|
ssh_exec FEDORA "docker compose version" &>/dev/null || ssh_exec FEDORA "docker-compose --version" &>/dev/null
|
|
}
|
|
check 9 "docker-compose available on Fedora" check_compose_fedora
|
|
if ! check_compose_fedora 2>/dev/null; then
|
|
log_error " → docker-compose not found on Fedora. Run setup/fedora.sh."
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Check 10: Port free on Unraid
|
|
# Uses ss (socket statistics) to check if any process is listening on the port.
|
|
# The ! negates the grep — we PASS if the port is NOT found in use.
|
|
# ---------------------------------------------------------------------------
|
|
check_port_unraid() {
|
|
local port="${UNRAID_GITEA_PORT:-3000}"
|
|
! ssh_exec UNRAID "ss -tlnp | grep -q ':${port} '" 2>/dev/null
|
|
}
|
|
check 10 "Port ${UNRAID_GITEA_PORT:-3000} free on Unraid" check_port_unraid
|
|
if ! check_port_unraid 2>/dev/null; then
|
|
log_error " → Port ${UNRAID_GITEA_PORT:-3000} already in use on Unraid."
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Check 11: Port free on Fedora
|
|
# ---------------------------------------------------------------------------
|
|
check_port_fedora() {
|
|
local port="${FEDORA_GITEA_PORT:-3000}"
|
|
! ssh_exec FEDORA "ss -tlnp | grep -q ':${port} '" 2>/dev/null
|
|
}
|
|
check 11 "Port ${FEDORA_GITEA_PORT:-3000} free on Fedora" check_port_fedora
|
|
if ! check_port_fedora 2>/dev/null; then
|
|
log_error " → Port ${FEDORA_GITEA_PORT:-3000} already in use on Fedora."
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Check 12: DNS resolves
|
|
# ---------------------------------------------------------------------------
|
|
check_dns() {
|
|
local resolved
|
|
resolved=$(dig +short "${GITEA_DOMAIN:-}" 2>/dev/null | head -1)
|
|
[[ "$resolved" == "${UNRAID_IP:-}" ]]
|
|
}
|
|
check 12 "DNS: ${GITEA_DOMAIN:-<not set>} resolves to ${UNRAID_IP:-<not set>}" check_dns
|
|
if ! check_dns 2>/dev/null; then
|
|
log_error " → ${GITEA_DOMAIN:-GITEA_DOMAIN} does not resolve to ${UNRAID_IP:-UNRAID_IP}."
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Check 13: GitHub token valid
|
|
# ---------------------------------------------------------------------------
|
|
check_github_token() {
|
|
[[ -n "${GITHUB_TOKEN:-}" ]] && curl -sf -H "Authorization: token ${GITHUB_TOKEN}" https://api.github.com/user -o /dev/null
|
|
}
|
|
check 13 "GitHub token valid" check_github_token
|
|
if ! check_github_token 2>/dev/null; then
|
|
log_error " → GitHub token invalid. Check GITHUB_TOKEN in .env."
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Check 14: GitHub repos exist
|
|
# ---------------------------------------------------------------------------
|
|
check_github_repos() {
|
|
local all_ok=0
|
|
for var in REPO_1_NAME REPO_2_NAME REPO_3_NAME; do
|
|
local repo="${!var:-}"
|
|
if [[ -z "$repo" ]]; then
|
|
continue
|
|
fi
|
|
if ! curl -sf -H "Authorization: token ${GITHUB_TOKEN:-}" "https://api.github.com/repos/${GITHUB_USERNAME:-}/${repo}" -o /dev/null 2>/dev/null; then
|
|
log_error " → GitHub repo ${repo} not found under ${GITHUB_USERNAME:-}"
|
|
all_ok=1
|
|
fi
|
|
done
|
|
return $all_ok
|
|
}
|
|
check 14 "All GitHub repos exist" check_github_repos
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Check 15: Nginx running on Unraid
|
|
# ---------------------------------------------------------------------------
|
|
check_nginx() {
|
|
local status
|
|
status=$(ssh_exec UNRAID "docker ps --filter name=${NGINX_CONTAINER_NAME:-nginx} --format '{{.Status}}'" 2>/dev/null)
|
|
[[ "$status" == *"Up"* ]]
|
|
}
|
|
check 15 "Nginx container '${NGINX_CONTAINER_NAME:-<not set>}' running on Unraid" check_nginx
|
|
if ! check_nginx 2>/dev/null; then
|
|
log_error " → Nginx container '${NGINX_CONTAINER_NAME:-}' not running on Unraid."
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Check 16: Nginx conf dir writable
|
|
# ---------------------------------------------------------------------------
|
|
check_nginx_conf() {
|
|
ssh_exec UNRAID "test -w '${NGINX_CONF_PATH:-/nonexistent}'" 2>/dev/null
|
|
}
|
|
check 16 "Nginx config path writable (${NGINX_CONF_PATH:-<not set>})" check_nginx_conf
|
|
if ! check_nginx_conf 2>/dev/null; then
|
|
log_error " → Nginx config path ${NGINX_CONF_PATH:-} not writable on Unraid."
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Summary
|
|
# ---------------------------------------------------------------------------
|
|
printf '\n'
|
|
log_info "Results: ${PASS_COUNT} passed, ${FAIL_COUNT} failed (out of 16 checks)"
|
|
|
|
if [[ $FAIL_COUNT -gt 0 ]]; then
|
|
log_error "Preflight FAILED — fix the issues above before proceeding."
|
|
exit 1
|
|
else
|
|
log_success "All preflight checks passed. Ready to run migration phases."
|
|
exit 0
|
|
fi
|