diff --git a/phase2_gitea_fedora.sh b/phase2_gitea_fedora.sh new file mode 100755 index 0000000..fc877dd --- /dev/null +++ b/phase2_gitea_fedora.sh @@ -0,0 +1,154 @@ +#!/usr/bin/env bash +set -euo pipefail + +# ============================================================================= +# phase2_gitea_fedora.sh — Deploy Gitea on Fedora (backup instance) +# Identical to Phase 1 except: targets Fedora, uses BACKUP vars, NO org created. +# Produces: Running Gitea on Fedora, admin user, backup API token in .env +# ============================================================================= + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +source "${SCRIPT_DIR}/lib/common.sh" + +load_env +require_vars FEDORA_IP FEDORA_SSH_USER FEDORA_SSH_PORT \ + FEDORA_GITEA_PORT FEDORA_GITEA_SSH_PORT FEDORA_GITEA_DATA_PATH \ + GITEA_ADMIN_USER GITEA_ADMIN_PASSWORD GITEA_ADMIN_EMAIL \ + GITEA_INSTANCE_NAME GITEA_DB_TYPE GITEA_VERSION \ + GITEA_BACKUP_INTERNAL_URL + +phase_header 2 "Gitea on Fedora (Backup)" + +# Alias for template rendering — same template as Phase 1, different values +DATA_PATH="$FEDORA_GITEA_DATA_PATH" + +# --------------------------------------------------------------------------- +# Step 1: Create data directories on Fedora +# --------------------------------------------------------------------------- +log_step 1 "Creating data directories on Fedora..." +if ssh_exec FEDORA "test -d '${DATA_PATH}/data'"; then + log_info "Data directory already exists — skipping" +else + ssh_exec FEDORA "mkdir -p '${DATA_PATH}/data' '${DATA_PATH}/config'" + log_success "Data directories created" +fi + +# --------------------------------------------------------------------------- +# Step 2: Render + SCP docker-compose file +# Uses the same template as Phase 1 but with Fedora-specific port/path vars. +# --------------------------------------------------------------------------- +log_step 2 "Deploying docker-compose.yml..." +if ssh_exec FEDORA "test -f '${DATA_PATH}/docker-compose.yml'"; then + log_info "docker-compose.yml already exists — skipping" +else + TMPFILE=$(mktemp) + export DATA_PATH GITEA_PORT="${FEDORA_GITEA_PORT}" GITEA_SSH_PORT="${FEDORA_GITEA_SSH_PORT}" + render_template "${SCRIPT_DIR}/templates/docker-compose-gitea.yml.tpl" "$TMPFILE" + scp_to FEDORA "$TMPFILE" "${DATA_PATH}/docker-compose.yml" + rm -f "$TMPFILE" + log_success "docker-compose.yml deployed" +fi + +# --------------------------------------------------------------------------- +# Step 3: Render + SCP app.ini +# Uses GITEA_BACKUP_INTERNAL_URL as the ROOT_URL for the Fedora instance. +# The domain is derived from the backup URL since Fedora doesn't need a +# public-facing domain — it's accessed internally for mirrors. +# --------------------------------------------------------------------------- +log_step 3 "Deploying app.ini..." +if ssh_exec FEDORA "test -f '${DATA_PATH}/config/app.ini'"; then + log_info "app.ini already exists — skipping" +else + TMPFILE=$(mktemp) + # Generate a unique secret key for the Fedora instance (different from Unraid) + GITEA_SECRET_KEY=$(openssl rand -hex 32) + export GITEA_SECRET_KEY + # Override GITEA_DOMAIN for the backup instance — use the IP:port since + # the Fedora instance doesn't have a public domain + GITEA_DOMAIN="${FEDORA_IP}:${FEDORA_GITEA_PORT}" + export GITEA_DOMAIN + render_template "${SCRIPT_DIR}/templates/app.ini.tpl" "$TMPFILE" + scp_to FEDORA "$TMPFILE" "${DATA_PATH}/config/app.ini" + rm -f "$TMPFILE" + log_success "app.ini deployed" +fi + +# --------------------------------------------------------------------------- +# Step 4: Start Gitea container +# --------------------------------------------------------------------------- +log_step 4 "Starting Gitea container..." +CONTAINER_STATUS=$(ssh_exec FEDORA "docker ps --filter name=gitea --format '{{.Status}}'" 2>/dev/null || true) +if [[ "$CONTAINER_STATUS" == *"Up"* ]]; then + log_info "Gitea container already running — skipping" +else + # Try "docker compose" plugin first, fall back to standalone + ssh_exec FEDORA "cd '${DATA_PATH}' && docker compose up -d 2>/dev/null || docker-compose up -d" + log_success "Gitea container started" +fi + +# --------------------------------------------------------------------------- +# Step 5: Wait for Gitea to be ready +# --------------------------------------------------------------------------- +log_step 5 "Waiting for Gitea to be ready..." +wait_for_http "${GITEA_BACKUP_INTERNAL_URL}/api/v1/version" 120 + +# --------------------------------------------------------------------------- +# Step 6: Create admin user (same creds as primary — shared credentials) +# --------------------------------------------------------------------------- +log_step 6 "Creating admin user..." +if curl -sf -u "${GITEA_ADMIN_USER}:${GITEA_ADMIN_PASSWORD}" "${GITEA_BACKUP_INTERNAL_URL}/api/v1/user" -o /dev/null 2>/dev/null; then + log_info "Admin user already exists — skipping" +else + # Create via CLI inside container, same pattern as Phase 1 + ssh_exec FEDORA "docker exec gitea gitea admin user create \ + --username '${GITEA_ADMIN_USER}' \ + --password '${GITEA_ADMIN_PASSWORD}' \ + --email '${GITEA_ADMIN_EMAIL}' \ + --admin \ + --must-change-password=false" || true + + if curl -sf -u "${GITEA_ADMIN_USER}:${GITEA_ADMIN_PASSWORD}" "${GITEA_BACKUP_INTERNAL_URL}/api/v1/user" -o /dev/null 2>/dev/null; then + log_success "Admin user created" + else + log_error "Failed to create admin user on Fedora" + exit 1 + fi +fi + +# --------------------------------------------------------------------------- +# Step 7: Generate API token and save to .env as GITEA_BACKUP_ADMIN_TOKEN +# --------------------------------------------------------------------------- +log_step 7 "Generating backup API token..." +if [[ -n "${GITEA_BACKUP_ADMIN_TOKEN:-}" ]]; then + # Verify existing token works + if curl -sf -H "Authorization: token ${GITEA_BACKUP_ADMIN_TOKEN}" "${GITEA_BACKUP_INTERNAL_URL}/api/v1/user" -o /dev/null 2>/dev/null; then + log_info "Backup API token already exists and is valid — skipping" + else + log_warn "Existing backup token is invalid — generating new one" + GITEA_BACKUP_ADMIN_TOKEN="" + fi +fi + +if [[ -z "${GITEA_BACKUP_ADMIN_TOKEN:-}" ]]; then + # Generate via basic auth — token is only returned once in the .sha1 field + TOKEN_RESPONSE=$(curl -sf -u "${GITEA_ADMIN_USER}:${GITEA_ADMIN_PASSWORD}" \ + -X POST \ + -H "Content-Type: application/json" \ + -d '{"name":"migration-token","scopes":["all"]}' \ + "${GITEA_BACKUP_INTERNAL_URL}/api/v1/users/${GITEA_ADMIN_USER}/tokens") + + GITEA_BACKUP_ADMIN_TOKEN=$(printf '%s' "$TOKEN_RESPONSE" | jq -r '.sha1') + + if [[ -z "$GITEA_BACKUP_ADMIN_TOKEN" ]] || [[ "$GITEA_BACKUP_ADMIN_TOKEN" == "null" ]]; then + log_error "Failed to generate backup API token" + exit 1 + fi + + save_env_var "GITEA_BACKUP_ADMIN_TOKEN" "$GITEA_BACKUP_ADMIN_TOKEN" + log_success "Backup API token generated and saved to .env" +fi + +# NOTE: No organization is created on the Fedora instance. +# Mirror repos will be stored under the admin user's namespace. + +log_success "Phase 2 complete — Gitea backup instance is running on Fedora" diff --git a/phase2_post_check.sh b/phase2_post_check.sh new file mode 100755 index 0000000..981992f --- /dev/null +++ b/phase2_post_check.sh @@ -0,0 +1,71 @@ +#!/usr/bin/env bash +set -euo pipefail + +# ============================================================================= +# phase2_post_check.sh — Verify Phase 2 (Gitea on Fedora) succeeded +# Independent verification — can be run separately from phase2_gitea_fedora.sh +# Same checks as Phase 1 post-check MINUS the org check (Fedora has no org). +# Exits 0 only if ALL checks pass. +# ============================================================================= + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +source "${SCRIPT_DIR}/lib/common.sh" + +load_env +require_vars GITEA_BACKUP_INTERNAL_URL GITEA_ADMIN_USER GITEA_ADMIN_PASSWORD \ + GITEA_BACKUP_ADMIN_TOKEN + +log_info "=== Phase 2 Post-Check ===" + +PASS=0 +FAIL=0 + +# Helper: run a check, track results — same pattern as phase1_post_check.sh +run_check() { + local description="$1"; shift + if "$@" 2>/dev/null; then + log_success "$description" + PASS=$((PASS + 1)) + else + log_error "FAIL: $description" + FAIL=$((FAIL + 1)) + fi +} + +# Check 1: Gitea responds with HTTP 200 +run_check "Gitea HTTP 200 at ${GITEA_BACKUP_INTERNAL_URL}" \ + curl -sf -o /dev/null "${GITEA_BACKUP_INTERNAL_URL}/api/v1/version" + +# Check 2: Admin user authenticates with basic auth +run_check "Admin user authenticates (basic auth)" \ + curl -sf -o /dev/null -u "${GITEA_ADMIN_USER}:${GITEA_ADMIN_PASSWORD}" "${GITEA_BACKUP_INTERNAL_URL}/api/v1/user" + +# Check 3: API token works and returns correct username +check_token() { + local response + response=$(curl -sf -H "Authorization: token ${GITEA_BACKUP_ADMIN_TOKEN}" "${GITEA_BACKUP_INTERNAL_URL}/api/v1/user") + local login + login=$(printf '%s' "$response" | jq -r '.login') + [[ "$login" == "${GITEA_ADMIN_USER}" ]] +} +run_check "Backup API token valid (returns correct username)" check_token + +# Check 4: Gitea Actions enabled (verify via settings API) +# No org check here — the Fedora instance doesn't create an org. +# Mirror repos are stored under the admin user's namespace. +check_actions() { + curl -sf -H "Authorization: token ${GITEA_BACKUP_ADMIN_TOKEN}" "${GITEA_BACKUP_INTERNAL_URL}/api/v1/settings/api" -o /dev/null +} +run_check "Gitea API settings accessible (Actions check)" check_actions + +# Summary +printf '\n' +log_info "Results: ${PASS} passed, ${FAIL} failed" + +if [[ $FAIL -gt 0 ]]; then + log_error "Phase 2 post-check FAILED" + exit 1 +else + log_success "Phase 2 post-check PASSED — Gitea backup on Fedora is fully operational" + exit 0 +fi diff --git a/phase2_teardown.sh b/phase2_teardown.sh new file mode 100755 index 0000000..7633369 --- /dev/null +++ b/phase2_teardown.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +set -euo pipefail + +# ============================================================================= +# phase2_teardown.sh — Tear down Gitea on Fedora +# Destructive: stops container, optionally removes all data. +# Prompts for confirmation before each destructive action. +# Safe to run against an already-torn-down instance (no errors). +# ============================================================================= + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +source "${SCRIPT_DIR}/lib/common.sh" + +load_env +require_vars FEDORA_IP FEDORA_SSH_USER FEDORA_GITEA_DATA_PATH + +DATA_PATH="$FEDORA_GITEA_DATA_PATH" + +log_warn "=== Phase 2 Teardown: Gitea on Fedora ===" + +# --------------------------------------------------------------------------- +# Step 1: Stop and remove the Gitea container +# --------------------------------------------------------------------------- +# Check if docker-compose file exists (skip if already torn down) +if ssh_exec FEDORA "test -f '${DATA_PATH}/docker-compose.yml'" 2>/dev/null; then + printf 'This will stop Gitea on Fedora. Continue? [y/N] ' + read -r confirm + if [[ "$confirm" =~ ^[Yy]$ ]]; then + # Try modern "docker compose" first, fall back to standalone + ssh_exec FEDORA "cd '${DATA_PATH}' && docker compose down 2>/dev/null || docker-compose down" || true + log_success "Gitea container stopped and removed" + else + log_info "Skipped container shutdown" + fi +else + log_info "No docker-compose.yml found — container already removed" +fi + +# --------------------------------------------------------------------------- +# Step 2: Optionally remove all Gitea data +# This is irreversible — removes repos, database, config, everything. +# --------------------------------------------------------------------------- +if ssh_exec FEDORA "test -d '${DATA_PATH}'" 2>/dev/null; then + printf 'Remove ALL Gitea data at %s on Fedora? This is IRREVERSIBLE. [y/N] ' "$DATA_PATH" + read -r confirm + if [[ "$confirm" =~ ^[Yy]$ ]]; then + ssh_exec FEDORA "rm -rf '${DATA_PATH}'" + log_success "All Gitea data removed from Fedora" + else + log_info "Data preserved at ${DATA_PATH}" + fi +else + log_info "Data directory already removed" +fi + +# --------------------------------------------------------------------------- +# Step 3: Clear the auto-populated backup API token from .env +# The token is useless after teardown — clear it so phase2 generates a new one. +# --------------------------------------------------------------------------- +if [[ -n "${GITEA_BACKUP_ADMIN_TOKEN:-}" ]]; then + save_env_var "GITEA_BACKUP_ADMIN_TOKEN" "" + log_success "GITEA_BACKUP_ADMIN_TOKEN cleared from .env" +fi + +log_success "Phase 2 teardown complete"