diff --git a/scripts/restore-appfactory.sh b/scripts/restore-appfactory.sh index 073a262..f3932fb 100755 --- a/scripts/restore-appfactory.sh +++ b/scripts/restore-appfactory.sh @@ -14,6 +14,14 @@ usage() { cat </dev/null || true) +} + +restore_preserved_app_envs() { + local preserved_dir="$1" + local target_apps_dir="$2" + + [ -d "$preserved_dir" ] || return 0 + + while IFS= read -r preserved_env; do + [ -f "$preserved_env" ] || continue + + app_id="$(basename "$(dirname "$preserved_env")")" + target_env="$target_apps_dir/$app_id/.env" + + mkdir -p "$(dirname "$target_env")" + + if [ -f "$target_env" ]; then + backup_env_copy="$(mktemp)" + cp "$target_env" "$backup_env_copy" + + cp "$preserved_env" "$target_env" + merge_env_missing_keys "$backup_env_copy" "$target_env" + + rm -f "$backup_env_copy" + ok "Restored and merged app runtime env: $app_id" + else + cp "$preserved_env" "$target_env" + ok "Restored app runtime env: $app_id" + fi + done < <(find "$preserved_dir" -mindepth 2 -maxdepth 2 -type f -name ".env" 2>/dev/null || true) +} + [ -n "$BACKUP_FILE_INPUT" ] || { usage; fail "Backup file argument is required"; } [ "$(id -u)" -eq 0 ] || fail "Run as root via sudo" [ -f "$BACKUP_FILE_INPUT" ] || fail "Backup file not found: $BACKUP_FILE_INPUT" @@ -147,15 +216,38 @@ log "Calculated runtime APPFACTORY_UID=$APPFACTORY_UID" log "Calculated runtime APPFACTORY_GID=$APPFACTORY_GID" log "Calculated runtime APPFACTORY_DOCKER_GID=$APPFACTORY_DOCKER_GID" +PRESERVE_ROOT="$(mktemp -d)" PRESERVED_ENV="" +PRESERVED_CADDY="$PRESERVE_ROOT/caddy" +PRESERVED_CADDY_CONFIG="$PRESERVE_ROOT/caddy-config" +PRESERVED_SECRETS="$PRESERVE_ROOT/secrets" +PRESERVED_APP_ENVS="$PRESERVE_ROOT/app-envs" + EXISTING_ENV="$APPFACTORY_ROOT/config/appfactory.env" if [ -f "$EXISTING_ENV" ]; then - PRESERVED_ENV="$(mktemp)" + PRESERVED_ENV="$PRESERVE_ROOT/appfactory.env" cp "$EXISTING_ENV" "$PRESERVED_ENV" ok "Preserved existing env before restore: $EXISTING_ENV" fi +copy_dir_if_exists "$APPFACTORY_ROOT/data/caddy" "$PRESERVED_CADDY" +copy_dir_if_exists "$APPFACTORY_ROOT/data/caddy-config" "$PRESERVED_CADDY_CONFIG" +copy_dir_if_exists "$APPFACTORY_ROOT/data/secrets" "$PRESERVED_SECRETS" +preserve_app_envs "$APPFACTORY_ROOT/data/apps" "$PRESERVED_APP_ENVS" + +if [ -d "$PRESERVED_CADDY" ]; then + ok "Preserved Caddy TLS state: $APPFACTORY_ROOT/data/caddy" +fi + +if [ -d "$PRESERVED_CADDY_CONFIG" ]; then + ok "Preserved Caddy config state: $APPFACTORY_ROOT/data/caddy-config" +fi + +if [ -d "$PRESERVED_SECRETS" ]; then + ok "Preserved secrets directory: $APPFACTORY_ROOT/data/secrets" +fi + log "Removing existing AppFactory containers if present" mapfile -t APPFACTORY_CONTAINERS < <( docker ps -a --format '{{.Names}}' \ @@ -221,6 +313,29 @@ else set_env_value "$ENV_FILE" "APPFACTORY_DOCKER_GID" "$APPFACTORY_DOCKER_GID" fi +if [ -d "$PRESERVED_CADDY" ]; then + log "Restoring preserved Caddy TLS state" + rm -rf "$APPFACTORY_ROOT/data/caddy" + cp -a "$PRESERVED_CADDY" "$APPFACTORY_ROOT/data/caddy" + ok "Restored Caddy TLS state" +fi + +if [ -d "$PRESERVED_CADDY_CONFIG" ]; then + log "Restoring preserved Caddy config state" + rm -rf "$APPFACTORY_ROOT/data/caddy-config" + cp -a "$PRESERVED_CADDY_CONFIG" "$APPFACTORY_ROOT/data/caddy-config" + ok "Restored Caddy config state" +fi + +if [ -d "$PRESERVED_SECRETS" ]; then + log "Restoring preserved secrets directory" + rm -rf "$APPFACTORY_ROOT/data/secrets" + cp -a "$PRESERVED_SECRETS" "$APPFACTORY_ROOT/data/secrets" + ok "Restored secrets directory" +fi + +restore_preserved_app_envs "$PRESERVED_APP_ENVS" "$APPFACTORY_ROOT/data/apps" + log "Ensuring mandatory env keys without overwriting existing non-empty values" set_env_if_missing_or_empty "$ENV_FILE" "APPFACTORY_DIR" "$APPFACTORY_ROOT" set_env_if_missing_or_empty "$ENV_FILE" "WORKSPACE_DIR" "$APPFACTORY_ROOT/workspace" @@ -244,14 +359,20 @@ set_env_if_missing_or_empty "$ENV_FILE" "WEBHOOK_URL" "" set_env_if_missing_or_empty "$ENV_FILE" "GITEA_OAUTH_REDIRECT_URI" "" set_env_if_missing_or_empty "$ENV_FILE" "GITEA_SSH_PORT" "2222" +set_env_if_missing_or_empty "$ENV_FILE" "GITEA_ADMIN_TOKEN" "" +set_env_if_missing_or_empty "$ENV_FILE" "GITEA_API_TOKEN" "" +set_env_if_missing_or_empty "$ENV_FILE" "GITEA_TOKEN" "" + set_env_if_missing_or_empty "$ENV_FILE" "GOOGLE_OAUTH_ENABLED" "false" set_env_if_missing_or_empty "$ENV_FILE" "GOOGLE_CLIENT_ID" "" set_env_if_missing_or_empty "$ENV_FILE" "GOOGLE_CLIENT_SECRET" "" set_env_if_missing_or_empty "$ENV_FILE" "GOOGLE_REDIRECT_URI" "" set_env_if_missing_or_empty "$ENV_FILE" "GOOGLE_ALLOWED_DOMAIN" "" +set_env_if_missing_or_empty "$ENV_FILE" "AUTH_MODE" "google" + log "Effective runtime env:" -grep -E '^(APPFACTORY_UID|APPFACTORY_GID|APPFACTORY_DOCKER_GID|APPFACTORY_ENABLE_HTTPS|APPFACTORY_DOMAIN|APPFACTORY_PORTAL_DOMAIN|APPFACTORY_GITEA_DOMAIN|APPFACTORY_REGISTRY_DOMAIN|APPFACTORY_PORTAL_PUBLIC_URL|GITEA_DOMAIN|GITEA_ROOT_URL|GITEA_URL|WEBHOOK_URL|GITEA_OAUTH_REDIRECT_URI)=' "$ENV_FILE" || true +grep -E '^(APPFACTORY_UID|APPFACTORY_GID|APPFACTORY_DOCKER_GID|APPFACTORY_ENABLE_HTTPS|APPFACTORY_DOMAIN|APPFACTORY_PORTAL_DOMAIN|APPFACTORY_GITEA_DOMAIN|APPFACTORY_REGISTRY_DOMAIN|APPFACTORY_PORTAL_PUBLIC_URL|GITEA_DOMAIN|GITEA_ROOT_URL|GITEA_URL|WEBHOOK_URL|GITEA_OAUTH_REDIRECT_URI|AUTH_MODE)=' "$ENV_FILE" || true DB_FILE="$APPFACTORY_ROOT/data/appfactory/appfactory.db" [ -f "$DB_FILE" ] || fail "Missing AppFactory DB after restore: $DB_FILE" @@ -352,6 +473,15 @@ if [ -f "$GENERATE_CADDY" ]; then "$GENERATE_CADDY" fi +REDEPLOY_APPS="$APPFACTORY_ROOT/workspace/appfactory-tools/scripts/redeploy-enabled-apps.sh" +if [ -f "$REDEPLOY_APPS" ]; then + chmod +x "$REDEPLOY_APPS" + log "Redeploying enabled user applications" + "$REDEPLOY_APPS" || warn "redeploy-enabled-apps.sh failed; check app logs" +else + warn "redeploy-enabled-apps.sh not found, skipping user app redeploy" +fi + PREFLIGHT="$APPFACTORY_ROOT/workspace/appfactory-tools/maintenance/preflight-check.sh" [ -f "$PREFLIGHT" ] || fail "Missing preflight script: $PREFLIGHT" chmod +x "$PREFLIGHT" @@ -359,5 +489,8 @@ chmod +x "$PREFLIGHT" log "Running final preflight" "$PREFLIGHT" +rm -rf "$PRESERVE_ROOT" + echo echo "APPFACTORY RESTORE: READY" +EOF