diff --git a/webapps_migration/migrate_superx.conf.sam b/webapps_migration/migrate_superx.conf.sam new file mode 100644 index 0000000..6c37ac1 --- /dev/null +++ b/webapps_migration/migrate_superx.conf.sam @@ -0,0 +1,89 @@ +# migrate_superx.conf +# Konfiguration fuer die Migration einer bestehenden SuperX-Installation +# in eine Tomcat-Webapp-Struktur. +# +# Beide Dateien muessen im selben Verzeichnis liegen: +# migrate_superx.conf +# migrate_superx_webapp.sh +# +# Aufruf: +# ./migrate_superx_webapp.sh +# +# Produktiv mit Rechte-/Owner-Anpassung meist: +# sudo ./migrate_superx_webapp.sh +# +# Testlauf: +# DRY_RUN="true" + +# Bestehende SQL_ENV der alten Installation. +SQL_ENV="/home/superx/db/bin/SQL_ENV" + +# Migrationsmodus: +# full: +# - kopiert die bestehende Webapp nach TARGET_WEBAPP +# - kopiert oder verschiebt db nach TARGET_WEBAPP/WEB-INF/conf/edustore/db +# db_only: +# - kopiert keine Webapp +# - verwendet die bestehende WEBAPP aus der SQL_ENV als Ziel, wenn TARGET_WEBAPP="auto" +# - kopiert oder verschiebt nur db nach WEBAPP/WEB-INF/conf/edustore/db +MIGRATION_MODE="full" + +# Uebertragung des DB-Verzeichnisses: +# copy: db wird per rsync kopiert, Quelle bleibt erhalten. +# move: db wird per mv verschoben, Quelle ist danach nicht mehr am alten Ort. +# Bei move darf TARGET_DB noch nicht existieren. +DB_TRANSFER_MODE="copy" + +# Ziel-Webapp-Verzeichnis. +# Bei MIGRATION_MODE=full muss hier ein konkreter Pfad stehen. +# Bei MIGRATION_MODE=db_only kann TARGET_WEBAPP="auto" gesetzt werden. +TARGET_WEBAPP="/var/lib/tomcat/webapps/superx" + +# Benutzer/Gruppe fuer die Zielstruktur. +TOMCAT_USER="tomcat" +SUPERX_GROUP="superx" + +# Optionaler Tomcat-Service. +TOMCAT_SERVICE="tomcat10" +STOP_TOMCAT="false" +START_TOMCAT="false" + +# rsync-Verhalten fuer Webapp-Kopie und DB-Kopie. +DELETE_TARGET="false" + +# Wenn Ziel-Webapp bereits existiert, trotzdem weitermachen? +ALLOW_EXISTING_TARGET="true" + +# Wenn Ziel-DB bereits existiert: +# Bei DB_TRANSFER_MODE=copy erlaubt true das Ergaenzen/Ueberschreiben per rsync. +# Bei DB_TRANSFER_MODE=move darf Ziel-DB nie existieren. +ALLOW_EXISTING_TARGET_DB="true" + +# Testlauf ohne Aenderungen. +DRY_RUN="false" + +# Gruppen-/User-Verwaltung. +ADD_TOMCAT_TO_GROUP="true" +CREATE_GROUP_IF_MISSING="false" + +# SQL_ENV im Ziel anpassen. +UPDATE_SQL_ENV="true" + +# Rechte nach dem Kopieren/Verschieben setzen. +SET_RIGHTS="true" + +# Owner/Gruppe setzen. +# auto: root setzt chown; gleicher User mit passender Gruppe ueberspringt chown; sonst Abbruch. +# true: chown immer versuchen. +# false: chown nie ausfuehren. +SET_OWNER="auto" + +# chmod setzen. +SET_CHMOD="true" + +# Sicherheitspruefung fuer bereits migrierte Struktur. +# Nur im Notfall auf true setzen. +FORCE_ALREADY_MIGRATED="false" + +# Optional: zusaetzliche Ausgabe. +VERBOSE="true" diff --git a/webapps_migration/migrate_superx_webapp.sh b/webapps_migration/migrate_superx_webapp.sh new file mode 100644 index 0000000..41a3af1 --- /dev/null +++ b/webapps_migration/migrate_superx_webapp.sh @@ -0,0 +1,640 @@ +#!/usr/bin/env bash +# migrate_superx_webapp.sh +# +# Migriert eine bestehende SuperX-Installation in eine neue Tomcat-Webapp-Struktur. +# +# Erwartete Dateien im selben Verzeichnis: +# migrate_superx.conf +# migrate_superx_webapp.sh +# +# Modi: +# MIGRATION_MODE=full +# Webapp wird nach TARGET_WEBAPP kopiert. +# db wird nach TARGET_WEBAPP/WEB-INF/conf/edustore/db kopiert oder verschoben. +# +# MIGRATION_MODE=db_only +# Webapp wird nicht kopiert. +# db wird in die bestehende oder angegebene Webapp unter WEB-INF/conf/edustore/db kopiert oder verschoben. +# +# DB_TRANSFER_MODE: +# copy: db wird per rsync kopiert. +# move: db wird per mv verschoben. Ziel-db darf dabei noch nicht existieren. + +set -euo pipefail + +SCRIPT_NAME="$(basename "$0")" +SCRIPT_VERSION="1.4" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +CONFIG_FILE="$SCRIPT_DIR/migrate_superx.conf" + +log() { echo "[$SCRIPT_NAME] $*"; } +warn() { echo "[$SCRIPT_NAME] WARNUNG: $*" >&2; } +fail() { echo "[$SCRIPT_NAME] FEHLER: $*" >&2; exit 1; } + +is_true() { + case "${1:-false}" in true|TRUE|yes|YES|ja|JA|1) return 0 ;; *) return 1 ;; esac +} + +is_false() { + case "${1:-false}" in false|FALSE|no|NO|nein|NEIN|0|"") return 0 ;; *) return 1 ;; esac +} + +is_auto() { + case "${1:-}" in auto|AUTO|Auto) return 0 ;; *) return 1 ;; esac +} + +is_root() { [ "$(id -u)" -eq 0 ]; } +current_user() { id -un; } +user_exists() { id "$1" >/dev/null 2>&1; } +group_exists() { getent group "$1" >/dev/null 2>&1; } + +user_in_group() { + local user="$1" + local group="$2" + id -nG "$user" 2>/dev/null | tr ' ' '\n' | grep -qx "$group" +} + +current_user_matches_target() { + [ "$(current_user)" = "$TOMCAT_USER" ] && user_in_group "$(current_user)" "$SUPERX_GROUP" +} + +canon_path() { + if command -v realpath >/dev/null 2>&1; then + realpath -m "$1" + else + printf '%s\n' "$1" + fi +} + +run() { + if is_true "${DRY_RUN:-false}"; then + echo "[DRY-RUN] $*" + else + if is_true "${VERBOSE:-false}"; then + echo "+ $*" + fi + eval "$@" + fi +} + +usage() { + cat <&2 </dev/null 2>&1 || fail "systemctl nicht gefunden, kann Tomcat nicht stoppen." + run "systemctl stop '$TOMCAT_SERVICE'" + fi +} + +start_tomcat_if_requested() { + if is_true "$START_TOMCAT"; then + command -v systemctl >/dev/null 2>&1 || fail "systemctl nicht gefunden, kann Tomcat nicht starten." + run "systemctl start '$TOMCAT_SERVICE'" + fi +} + +copy_webapp_if_requested() { + if [ "$MIGRATION_MODE" != "full" ]; then + log "MIGRATION_MODE=db_only: Webapp wird nicht kopiert." + return 0 + fi + + command -v rsync >/dev/null 2>&1 || fail "rsync ist nicht installiert oder nicht im PATH." + run "mkdir -p '$TARGET_WEBAPP'" + + RSYNC_DELETE="" + if is_true "$DELETE_TARGET"; then RSYNC_DELETE="--delete"; fi + + log "Kopiere Webapp..." + run "rsync -a $RSYNC_DELETE '$SOURCE_WEBAPP/' '$TARGET_WEBAPP/'" +} + +transfer_db() { + run "mkdir -p '$TARGET_SUPERX_DIR'" + + if [ "$DB_TRANSFER_MODE" = "copy" ]; then + command -v rsync >/dev/null 2>&1 || fail "rsync ist nicht installiert oder nicht im PATH." + + RSYNC_DELETE="" + if is_true "$DELETE_TARGET"; then RSYNC_DELETE="--delete"; fi + + log "Kopiere DB-Verzeichnis nach WEB-INF/conf/edustore/db..." + run "mkdir -p '$TARGET_DB'" + run "rsync -a $RSYNC_DELETE '$SOURCE_DB/' '$TARGET_DB/'" + return 0 + fi + + if [ "$DB_TRANSFER_MODE" = "move" ]; then + log "Verschiebe DB-Verzeichnis nach WEB-INF/conf/edustore/db..." + run "mkdir -p '$(dirname "$TARGET_DB")'" + run "mv '$SOURCE_DB' '$TARGET_DB'" + return 0 + fi + + fail "Unbekannter DB_TRANSFER_MODE: $DB_TRANSFER_MODE" +} + +backup_target_sql_env() { + if [ -f "$TARGET_SQL_ENV" ]; then + TS="$(date +%Y%m%d_%H%M%S)" + run "cp -p '$TARGET_SQL_ENV' '$TARGET_SQL_ENV.bak.$TS'" + else + warn "Ziel-SQL_ENV existiert noch nicht: $TARGET_SQL_ENV" + fi +} + +update_target_sql_env() { + if ! is_true "$UPDATE_SQL_ENV"; then return 0; fi + [ -f "$TARGET_SQL_ENV" ] || fail "Ziel-SQL_ENV nicht gefunden: $TARGET_SQL_ENV" + + backup_target_sql_env + + if is_true "$DRY_RUN"; then + echo "[DRY-RUN] passe SQL_ENV an: $TARGET_SQL_ENV" + return 0 + fi + + python3 - "$TARGET_SQL_ENV" "$TARGET_SUPERX_DIR" "$TARGET_WEBAPP" <<'PY' +from pathlib import Path +import re +import sys + +path = Path(sys.argv[1]) +new_superx_dir = sys.argv[2] +new_webapp = sys.argv[3] + +text = path.read_text(encoding="utf-8", errors="surrogateescape").splitlines() + +out = [] +seen_umask = False +seen_superx = False +seen_webapp = False +seen_export_superx = False +seen_export_webapp = False + +for line in text: + stripped = line.strip() + + if re.match(r"^umask\s+", stripped): + if not seen_umask: + out.append("umask 002") + seen_umask = True + else: + out.append("# " + line) + continue + + if re.match(r"^SUPERX_DIR\s*=", stripped): + if not seen_superx: + out.append(f'SUPERX_DIR="{new_superx_dir}"') + seen_superx = True + else: + out.append("# " + line) + continue + + if re.match(r"^WEBAPP\s*=", stripped): + if not seen_webapp: + out.append(f'WEBAPP="{new_webapp}"') + seen_webapp = True + else: + out.append("# " + line) + continue + + if re.match(r"^export\s+SUPERX_DIR\b", stripped): + seen_export_superx = True + out.append(line) + continue + + if re.match(r"^export\s+WEBAPP\b", stripped): + seen_export_webapp = True + out.append(line) + continue + + out.append(line) + +insert = [] +if not seen_umask: + insert.append("umask 002") +if not seen_superx: + insert.append(f'SUPERX_DIR="{new_superx_dir}"') +if not seen_export_superx: + insert.append("export SUPERX_DIR") +if not seen_webapp: + insert.append(f'WEBAPP="{new_webapp}"') +if not seen_export_webapp: + insert.append("export WEBAPP") + +if insert: + out = insert + [""] + out + +path.write_text("\n".join(out) + "\n", encoding="utf-8", errors="surrogateescape") +PY +} + +set_rights() { + if ! is_true "$SET_RIGHTS"; then + log "Rechte setzen ist deaktiviert." + return 0 + fi + + [ -d "$TARGET_WEBAPP" ] || fail "TARGET_WEBAPP fehlt: $TARGET_WEBAPP" + + if is_true "$EFFECTIVE_SET_OWNER"; then + log "Setze Owner/Gruppe..." + run "chown -R '$TOMCAT_USER:$SUPERX_GROUP' '$TARGET_WEBAPP'" + else + log "Owner/Gruppe werden nicht gesetzt." + fi + + if is_true "$SET_CHMOD"; then + log "Setze Verzeichnisrechte mit setgid-Bit..." + run "find '$TARGET_WEBAPP' -type d -exec chmod 2775 {} +" + + log "Setze Standard-Dateirechte..." + run "find '$TARGET_WEBAPP' -type f -exec chmod 664 {} +" + + log "Setze ausfuehrbare Rechte fuer db/bin..." + if [ -d "$TARGET_DB/bin" ]; then + run "find '$TARGET_DB/bin' -type f -exec chmod 775 {} +" + else + warn "db/bin im Ziel nicht gefunden: $TARGET_DB/bin" + fi + + log "Setze ausfuehrbare Rechte fuer *.x und *.sh..." + run "find '$TARGET_WEBAPP' -type f \\( -name '*.x' -o -name '*.sh' \\) -exec chmod 775 {} +" + else + log "chmod ist deaktiviert." + fi +} + +final_notes() { + cat <