feat: add Phase 2 — Gitea on Fedora (backup instance)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
S
2026-02-26 15:16:32 -06:00
parent 63f708e556
commit eaffb97144
3 changed files with 290 additions and 0 deletions

154
phase2_gitea_fedora.sh Executable file
View File

@@ -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"

71
phase2_post_check.sh Executable file
View File

@@ -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

65
phase2_teardown.sh Executable file
View File

@@ -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"