#!/bin/bash # Cross-host migrate inherits the source's CFG__* values via the restored # config file. Most of them (DB passwords, API keys, user preferences) are # data and must survive the move. A small set are host-bound — they describe # where the app lives — and would 404 or break TLS if we kept them pointing # at the source. This module identifies and rewrites those. # # Host-bound fields are detected by suffix (URL, HOST, DOMAIN, DOMAIN_PREFIX), # and the rewrite source-of-truth is the destination's install-template # config (containers//.config under the install tree) — that's what # a fresh install on this box would produce. # # Per-app opt-out: set CFG__MIGRATE_URL_REWRITE="false" in the app's # install-template config to skip the rewrite (e.g. for apps with hardcoded # URLs that mustn't change). # Field-name suffixes treated as host-bound. Compared after stripping the # CFG__ prefix. _MIGRATE_HOST_BOUND_SUFFIXES=(URL HOST DOMAIN DOMAIN_PREFIX HOSTNAME PUBLIC_URL) # Echo "true" or "false" — should we rewrite host-bound URLs for this app? # Defaults true unless the app explicitly opts out. migrateUrlRewriteEnabled() { local app="$1" local template_config="$install_containers_dir$app/$app.config" [[ ! -f "$template_config" ]] && { echo "true"; return; } local opt_key="CFG_${app^^}_MIGRATE_URL_REWRITE" local val val=$(grep -E "^${opt_key}=" "$template_config" 2>/dev/null \ | head -1 | cut -d'=' -f2- | tr -d '"' | tr -d "'") if [[ "$val" == "false" || "$val" == "no" || "$val" == "0" ]]; then echo "false" else echo "true" fi } # Read the destination's install template, find host-bound CFG__* keys, # and overwrite the same keys in the deployed (just-restored) config with the # template's values. Anything not in the host-bound list is left alone — the # source's data/preferences survive. # # Args: # Returns: count of fields rewritten (emitted as `migrate.url_rewrite.fields`). migrateApplyUrlRewrite() { local app="$1" [[ -z "$app" ]] && { isError "migrateApplyUrlRewrite: app required"; return 1; } if [[ "$(migrateUrlRewriteEnabled "$app")" != "true" ]]; then isNotice "URL rewrite disabled by app config — keeping source URLs for $app" migrateEmit phase=url-rewrite status=skipped reason=app-opt-out app="$app" return 0 fi local template="$install_containers_dir$app/$app.config" local deployed="$containers_dir$app/$app.config" if [[ ! -f "$template" || ! -f "$deployed" ]]; then isNotice "URL rewrite: missing template or deployed config for $app — skipping" migrateEmit phase=url-rewrite status=skipped reason=missing-config app="$app" return 0 fi local rewritten=0 local key value bare_suffix while IFS='=' read -r key value; do [[ -z "$key" ]] && continue [[ "$key" =~ ^# ]] && continue [[ ! "$key" =~ ^CFG_ ]] && continue bare_suffix="${key##*_}" # Also catch the two-word _DOMAIN_PREFIX / _PUBLIC_URL cases. local two_word="${key%_*}" two_word="${two_word##*_}_${bare_suffix}" local is_host_bound=0 local suffix for suffix in "${_MIGRATE_HOST_BOUND_SUFFIXES[@]}"; do if [[ "$bare_suffix" == "$suffix" || "$two_word" == "$suffix" ]]; then is_host_bound=1 break fi done (( is_host_bound )) || continue # Strip surrounding quotes; keep whatever the template specifies, even # if empty (a deliberately-blank URL is a valid state). value="${value%\"}"; value="${value#\"}" value="${value%\'}"; value="${value#\'}" updateConfigOption "$key" "$value" "$deployed" >/dev/null 2>&1 ((rewritten++)) migrateEmit phase=url-rewrite status=field app="$app" key="$key" new_value="$value" done < <(grep -E '^CFG_' "$template" 2>/dev/null) isSuccessful "URL rewrite: $rewritten host-bound field(s) repointed to this host for $app" migrateEmit phase=url-rewrite status=complete app="$app" fields="$rewritten" }