#!/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_DATA_PATH \ FEDORA_COMPOSE_DIR \ FEDORA_MACVLAN_PARENT FEDORA_MACVLAN_SUBNET FEDORA_MACVLAN_GATEWAY \ FEDORA_MACVLAN_IP_RANGE FEDORA_GITEA_IP \ GITEA_ADMIN_USER GITEA_ADMIN_PASSWORD GITEA_ADMIN_EMAIL \ GITEA_DB_TYPE GITEA_VERSION if [[ "${GITEA_DB_TYPE}" != "sqlite3" ]]; then require_vars GITEA_DB_PORT GITEA_DB_NAME GITEA_DB_USER GITEA_DB_PASSWD fi phase_header 2 "Gitea on Fedora (Backup)" # Alias for template rendering — same template as Phase 1, different values DATA_PATH="$FEDORA_GITEA_DATA_PATH" # Compose files live in a centralized project directory on each host. COMPOSE_DIR="${FEDORA_COMPOSE_DIR}/gitea" FEDORA_DOCKER_NETWORK_NAME="gitea_net" # DB helpers and strip_template_block are in lib/common.sh # --------------------------------------------------------------------------- # Step 1: Ensure data directories on Fedora # --------------------------------------------------------------------------- log_step 1 "Ensuring data directories on Fedora..." if [[ "${GITEA_DB_TYPE}" != "sqlite3" ]]; then ssh_exec FEDORA "mkdir -p '${DATA_PATH}/data' '${DATA_PATH}/config' '${DATA_PATH}/db'" else ssh_exec FEDORA "mkdir -p '${DATA_PATH}/data' '${DATA_PATH}/config'" fi log_success "Data directories ensured" # --------------------------------------------------------------------------- # Step 2: Create macvlan Docker network (idempotent) # --------------------------------------------------------------------------- log_step 2 "Creating macvlan Docker network on Fedora..." if ssh_exec FEDORA "docker network inspect '${FEDORA_DOCKER_NETWORK_NAME}'" &>/dev/null; then log_info "${FEDORA_DOCKER_NETWORK_NAME} network already exists — skipping" else ssh_exec FEDORA "docker network create \ --driver macvlan \ --subnet='${FEDORA_MACVLAN_SUBNET}' \ --gateway='${FEDORA_MACVLAN_GATEWAY}' \ --ip-range='${FEDORA_MACVLAN_IP_RANGE}' \ -o parent='${FEDORA_MACVLAN_PARENT}' \ '${FEDORA_DOCKER_NETWORK_NAME}'" log_success "macvlan network ${FEDORA_DOCKER_NETWORK_NAME} created" fi # --------------------------------------------------------------------------- # Step 3: Render + SCP docker-compose file # Uses the same template as Phase 1 but with Fedora-specific values. # --------------------------------------------------------------------------- log_step 3 "Deploying docker-compose.yml..." if ssh_exec FEDORA "test -f '${COMPOSE_DIR}/docker-compose.yml'"; then log_info "docker-compose.yml already exists — skipping" else ssh_exec FEDORA "mkdir -p '${COMPOSE_DIR}'" TMPFILE=$(mktemp) GITEA_CONTAINER_IP="${FEDORA_GITEA_IP}" GITEA_NETWORK_NAME="${FEDORA_DOCKER_NETWORK_NAME}" export DATA_PATH GITEA_CONTAINER_IP GITEA_NETWORK_NAME if [[ "$GITEA_DB_TYPE" == "sqlite3" ]]; then # No DB service needed — render template then strip DB + internal network blocks render_template "${SCRIPT_DIR}/templates/docker-compose-gitea.yml.tpl" "$TMPFILE" \ "\${GITEA_VERSION} \${DATA_PATH} \${GITEA_CONTAINER_IP} \${GITEA_NETWORK_NAME}" strip_template_block "$TMPFILE" "DB_SERVICE_START" "DB_SERVICE_END" strip_template_block "$TMPFILE" "DB_DEPENDS_START" "DB_DEPENDS_END" strip_template_block "$TMPFILE" "INTERNAL_NET_REF_START" "INTERNAL_NET_REF_END" strip_template_block "$TMPFILE" "INTERNAL_NET_DEF_START" "INTERNAL_NET_DEF_END" else # External DB — set DB-specific vars then render # DB container uses an internal bridge network (not exposed to LAN) set_db_vars render_template "${SCRIPT_DIR}/templates/docker-compose-gitea.yml.tpl" "$TMPFILE" \ "\${GITEA_VERSION} \${DATA_PATH} \${GITEA_CONTAINER_IP} \${GITEA_NETWORK_NAME} \${DB_DOCKER_IMAGE} \${DB_ENV_VARS} \${DB_DATA_DIR} \${DB_HEALTHCHECK}" fi scp_to FEDORA "$TMPFILE" "${COMPOSE_DIR}/docker-compose.yml" rm -f "$TMPFILE" log_success "docker-compose.yml deployed to ${COMPOSE_DIR}" fi # --------------------------------------------------------------------------- # Step 4: Render + SCP app.ini # Fedora is internal-only for pull mirrors, so ROOT_URL/DOMAIN use FEDORA_GITEA_IP. # API checks in this script use GITEA_BACKUP_INTERNAL_URL (derived in load_env()). # --------------------------------------------------------------------------- log_step 4 "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) GITEA_SECRET_KEY=$(openssl rand -hex 32) export GITEA_SECRET_KEY # Override GITEA_DOMAIN for the backup instance — use the container IP since # the Fedora instance doesn't have a public domain GITEA_DOMAIN="${FEDORA_GITEA_IP}" export GITEA_DOMAIN if [[ "$GITEA_DB_TYPE" == "sqlite3" ]]; then render_template "${SCRIPT_DIR}/templates/app.ini.tpl" "$TMPFILE" \ "\${GITEA_DOMAIN} \${GITEA_DB_TYPE} \${GITEA_SECRET_KEY}" strip_template_block "$TMPFILE" "EXTDB_BLOCK_START" "EXTDB_BLOCK_END" else render_template "${SCRIPT_DIR}/templates/app.ini.tpl" "$TMPFILE" \ "\${GITEA_DOMAIN} \${GITEA_DB_TYPE} \${GITEA_SECRET_KEY} \${GITEA_DB_PORT} \${GITEA_DB_NAME} \${GITEA_DB_USER} \${GITEA_DB_PASSWD}" strip_template_block "$TMPFILE" "SQLITE_BLOCK_START" "SQLITE_BLOCK_END" fi scp_to FEDORA "$TMPFILE" "${DATA_PATH}/config/app.ini" rm -f "$TMPFILE" log_success "app.ini deployed" fi # --------------------------------------------------------------------------- # Step 5: Start Gitea container # --------------------------------------------------------------------------- log_step 5 "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 '${COMPOSE_DIR}' && docker compose up -d 2>/dev/null || docker-compose up -d" log_success "Gitea container started" fi # --------------------------------------------------------------------------- # Step 6: Wait for Gitea to be ready # --------------------------------------------------------------------------- log_step 6 "Waiting for Gitea to be ready..." wait_for_http "${GITEA_BACKUP_INTERNAL_URL}/api/v1/version" 120 # --------------------------------------------------------------------------- # Step 7: Create admin user (same creds as primary — shared credentials) # --------------------------------------------------------------------------- log_step 7 "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 -u git 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 8: Generate API token and save to .env as GITEA_BACKUP_ADMIN_TOKEN # --------------------------------------------------------------------------- log_step 8 "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 # Delete any stale token with the same name (idempotent re-run safety). curl -sf -u "${GITEA_ADMIN_USER}:${GITEA_ADMIN_PASSWORD}" \ -X DELETE \ "${GITEA_BACKUP_INTERNAL_URL}/api/v1/users/${GITEA_ADMIN_USER}/tokens/migration-token" \ -o /dev/null 2>/dev/null || true # 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"