200420261134

This commit is contained in:
Manfred Aabye
2026-04-20 11:35:05 +02:00
committed by GitHub
parent 8569bc71b5
commit 88452a0bff
19 changed files with 12630 additions and 12630 deletions
+21 -21
View File
@@ -1,21 +1,21 @@
MIT License
Copyright (c) 2025 ManfredAabye
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
MIT License
Copyright (c) 2025 ManfredAabye
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+201 -201
View File
@@ -1,201 +1,201 @@
# opensimMULTITOOL II V26.4.230.588
Diese README ist fuer Einsteiger geschrieben.
Wenn du noch nie mit OpenSim oder Bash gearbeitet hast, starte mit den Schritten in diesem Dokument von oben nach unten.
## 1. Was ist dieses Projekt?
opensimMULTITOOLS-II hilft dir, einen OpenSim-Server zu:
- installieren
- starten und stoppen
- neu starten
- sichern (Backups)
- warten und pruefen
Das Projekt besteht aus zwei Hauptteilen:
- CLI-Skripte (Konsole): fuer Administration per Terminal
- Web-Oberflaeche unter webphp/: fuer Bedienung im Browser
Voraussetzungen
- Linux Server
## 2. Wichtige Sicherheitshinweise
- Vor groesseren Aktionen immer Backup machen.
- Erst in einer Testumgebung pruefen, dann auf Produktivsystem nutzen.
- Die Web-Oberflaeche nur mit HTTPS und moeglichst mit IP-Einschraenkung betreiben.
- Standard-Passwoerter sofort aendern.
## 3. Projektstruktur (kurz erklaert)
- osmtool_main.sh: Hauptstarter fuer Module und Aktionen
- modular/: einzelne Fachmodule (install, startstop, backup, restore, ...)
- webphp/: Web-Oberflaeche (PHP)
- osmtool.sh: klassisches Hauptskript mit vielen Direktfunktionen
## 4. Schnellstart fuer Einsteiger (CLI)
Voraussetzung: Du arbeitest auf Linux und hast Zugriff auf das Projektverzeichnis.
### Schritt 1: In das Projektverzeichnis wechseln
```bash
cd /opt/opensimMULTITOOLS-II
```
### Schritt 2: Ubuntu vorbereiten
```bash
bash osmtool_main.sh install-grid-sim
```
Hinweis: `install-grid-sim` fuehrt die komplette Installationskette fuer `grid-sim` aus.
### Schritt 3: OpenSim-Abhaengigkeiten installieren
```bash
bash osmtool_main.sh install-grid-sim
```
### Schritt 4: Server-Check ausfuehren
```bash
bash osmtool_main.sh healthcheck
```
### Schritt 5: OpenSim installieren und konfigurieren
```bash
bash osmtool_main.sh install-grid-sim
```
### Schritt 6: Datenbank einrichten
```bash
export OSM_DB_PASS='DEIN_PASSWORT'
bash osmtool_main.sh dbsetup
```
### Schritt 7: Grid starten
```bash
bash osmtool_main.sh opensimrestart
```
## 5. Alltagsbefehle (die wichtigsten)
```bash
# Grid neu starten
bash osmtool_main.sh opensimrestart
# Robust-Datenbank sichern
export OSM_DB_PASS='DEIN_PASSWORT'
bash osmtool_main.sh dbbackup
# Cronjobs installieren (automatische Backups/Checks)
bash osmtool_main.sh croninstall
```
Unterstuetzte Kurzbefehle (Ein-Wort-Aufruf):
- install-grid-sim
- opensimstart
- opensimstop
- opensimrestart
- healthcheck
- smoketest
- dailyreport
- croninstall
- cronlist
- janusinstall
- janusrestart
- dbsetup
- dbbackup
## 6. Web-Oberflaeche (webphp)
Die Web-Oberflaeche ist in webphp/ enthalten und zeigt unter anderem:
- Modulaktionen
- Kommando-Vorschau
- Ausgabe der Befehle
- Live-Status (Screens, Ports, Artefakte)
Detaillierte Web-Anleitung: webphp/README.md
### Wichtige Konfigurationsregel
Fuer die aktive Web-Konfiguration gilt:
- webphp/src/config.php = wird wirklich benutzt
- webphp/src/config.sample.php = nur Vorlage
Wenn du Ports oder Screens fuer den Live-Status aendern willst, musst du in config.php anpassen.
## 7. Login-Sicherheit der Web-Oberflaeche
Die Web-Oberflaeche hat einen Schutz gegen Brute-Force-Logins:
- Nach mehreren falschen Passwortversuchen wird die IP temporaer gesperrt.
- Sperrzeit und Schwelle sind konfigurierbar.
- Login-Ereignisse koennen in einer Audit-Logdatei gespeichert werden.
Wichtige Einstellungen in webphp/src/config.php:
- auth_lockout_max_attempts
- auth_lockout_seconds
- optional: auth_store_path
- optional: auth_audit_log_path
## 8. check_screens einfach erklaert
Die Funktion check_screens in osmtool.sh:
- prueft, ob wichtige Screen-Sessions laufen
- schreibt Ergebnisse in ProblemRestarts.log
- meldet auch, wenn ein Dienst laeuft
- startet ausgefallene Dienste neu (kritische Dienste mit Komplett-Neustart)
## 9. Typische Fehler und schnelle Loesungen
### Problem: Im Live-Status werden alte oder falsche Ports angezeigt
Loesung:
1. Ports in webphp/src/config.php aendern (nicht nur in config.sample.php).
2. Browser mit Hard-Reload neu laden (z. B. Ctrl+Shift+R).
3. Sicherstellen, dass du die richtige Instanz/den richtigen Server aufrufst.
### Problem: Login gesperrt nach Fehlversuchen
Loesung:
- Sperrzeit in auth_lockout_seconds abwarten
- oder Sperrdaten in der konfigurierten Lockout-Datei pruefen
## 10. Nuetzliche Dateien
- osmtool_main.sh
- osmtool.sh
- modular/osmtool_startstop.sh
- modular/osmtool_install.sh
- webphp/public/index.php
- webphp/src/config.php
- webphp/src/runner.php
- webphp/src/web_init.php
## 11. Hilfe
- Wiki: [opensimMULTITOOLS-II Wiki](https://github.com/ManfredAabye/opensimMULTITOOLS-II/wiki)
- Web-Dokumentation: webphp/README.md
## 12. Lizenz
- Skriptname: osmtool.sh
- Version: V26.4.230.588
- Autor: Manfred Aabye
- Lizenz: MIT
# opensimMULTITOOL II V26.4.230.588
Diese README ist fuer Einsteiger geschrieben.
Wenn du noch nie mit OpenSim oder Bash gearbeitet hast, starte mit den Schritten in diesem Dokument von oben nach unten.
## 1. Was ist dieses Projekt?
opensimMULTITOOLS-II hilft dir, einen OpenSim-Server zu:
- installieren
- starten und stoppen
- neu starten
- sichern (Backups)
- warten und pruefen
Das Projekt besteht aus zwei Hauptteilen:
- CLI-Skripte (Konsole): fuer Administration per Terminal
- Web-Oberflaeche unter webphp/: fuer Bedienung im Browser
Voraussetzungen
- Linux Server
## 2. Wichtige Sicherheitshinweise
- Vor groesseren Aktionen immer Backup machen.
- Erst in einer Testumgebung pruefen, dann auf Produktivsystem nutzen.
- Die Web-Oberflaeche nur mit HTTPS und moeglichst mit IP-Einschraenkung betreiben.
- Standard-Passwoerter sofort aendern.
## 3. Projektstruktur (kurz erklaert)
- osmtool_main.sh: Hauptstarter fuer Module und Aktionen
- modular/: einzelne Fachmodule (install, startstop, backup, restore, ...)
- webphp/: Web-Oberflaeche (PHP)
- osmtool.sh: klassisches Hauptskript mit vielen Direktfunktionen
## 4. Schnellstart fuer Einsteiger (CLI)
Voraussetzung: Du arbeitest auf Linux und hast Zugriff auf das Projektverzeichnis.
### Schritt 1: In das Projektverzeichnis wechseln
```bash
cd /opt/opensimMULTITOOLS-II
```
### Schritt 2: Ubuntu vorbereiten
```bash
bash osmtool_main.sh install-grid-sim
```
Hinweis: `install-grid-sim` fuehrt die komplette Installationskette fuer `grid-sim` aus.
### Schritt 3: OpenSim-Abhaengigkeiten installieren
```bash
bash osmtool_main.sh install-grid-sim
```
### Schritt 4: Server-Check ausfuehren
```bash
bash osmtool_main.sh healthcheck
```
### Schritt 5: OpenSim installieren und konfigurieren
```bash
bash osmtool_main.sh install-grid-sim
```
### Schritt 6: Datenbank einrichten
```bash
export OSM_DB_PASS='DEIN_PASSWORT'
bash osmtool_main.sh dbsetup
```
### Schritt 7: Grid starten
```bash
bash osmtool_main.sh opensimrestart
```
## 5. Alltagsbefehle (die wichtigsten)
```bash
# Grid neu starten
bash osmtool_main.sh opensimrestart
# Robust-Datenbank sichern
export OSM_DB_PASS='DEIN_PASSWORT'
bash osmtool_main.sh dbbackup
# Cronjobs installieren (automatische Backups/Checks)
bash osmtool_main.sh croninstall
```
Unterstuetzte Kurzbefehle (Ein-Wort-Aufruf):
- install-grid-sim
- opensimstart
- opensimstop
- opensimrestart
- healthcheck
- smoketest
- dailyreport
- croninstall
- cronlist
- janusinstall
- janusrestart
- dbsetup
- dbbackup
## 6. Web-Oberflaeche (webphp)
Die Web-Oberflaeche ist in webphp/ enthalten und zeigt unter anderem:
- Modulaktionen
- Kommando-Vorschau
- Ausgabe der Befehle
- Live-Status (Screens, Ports, Artefakte)
Detaillierte Web-Anleitung: webphp/README.md
### Wichtige Konfigurationsregel
Fuer die aktive Web-Konfiguration gilt:
- webphp/src/config.php = wird wirklich benutzt
- webphp/src/config.sample.php = nur Vorlage
Wenn du Ports oder Screens fuer den Live-Status aendern willst, musst du in config.php anpassen.
## 7. Login-Sicherheit der Web-Oberflaeche
Die Web-Oberflaeche hat einen Schutz gegen Brute-Force-Logins:
- Nach mehreren falschen Passwortversuchen wird die IP temporaer gesperrt.
- Sperrzeit und Schwelle sind konfigurierbar.
- Login-Ereignisse koennen in einer Audit-Logdatei gespeichert werden.
Wichtige Einstellungen in webphp/src/config.php:
- auth_lockout_max_attempts
- auth_lockout_seconds
- optional: auth_store_path
- optional: auth_audit_log_path
## 8. check_screens einfach erklaert
Die Funktion check_screens in osmtool.sh:
- prueft, ob wichtige Screen-Sessions laufen
- schreibt Ergebnisse in ProblemRestarts.log
- meldet auch, wenn ein Dienst laeuft
- startet ausgefallene Dienste neu (kritische Dienste mit Komplett-Neustart)
## 9. Typische Fehler und schnelle Loesungen
### Problem: Im Live-Status werden alte oder falsche Ports angezeigt
Loesung:
1. Ports in webphp/src/config.php aendern (nicht nur in config.sample.php).
2. Browser mit Hard-Reload neu laden (z. B. Ctrl+Shift+R).
3. Sicherstellen, dass du die richtige Instanz/den richtigen Server aufrufst.
### Problem: Login gesperrt nach Fehlversuchen
Loesung:
- Sperrzeit in auth_lockout_seconds abwarten
- oder Sperrdaten in der konfigurierten Lockout-Datei pruefen
## 10. Nuetzliche Dateien
- osmtool_main.sh
- osmtool.sh
- modular/osmtool_startstop.sh
- modular/osmtool_install.sh
- webphp/public/index.php
- webphp/src/config.php
- webphp/src/runner.php
- webphp/src/web_init.php
## 11. Hilfe
- Wiki: [opensimMULTITOOLS-II Wiki](https://github.com/ManfredAabye/opensimMULTITOOLS-II/wiki)
- Web-Dokumentation: webphp/README.md
## 12. Lizenz
- Skriptname: osmtool.sh
- Version: V26.4.230.588
- Autor: Manfred Aabye
- Lizenz: MIT
+125 -125
View File
@@ -1,125 +1,125 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=/dev/null
source "$SCRIPT_DIR/osmtool_core.sh"
usage() {
cat <<'EOF'
Usage:
osmtool_cleanup.sh [--workdir <path>] --action <cache-clean|log-clean|tmp-clean|reboot> [--dry-run <true|false>]
Examples:
osmtool_cleanup.sh --action log-clean --workdir /opt --dry-run true
osmtool_cleanup.sh --action cache-clean --workdir /opt/opensim
EOF
print_usage_common
}
realpath_safe() {
local p="$1"
python3 -c 'import os,sys; print(os.path.realpath(sys.argv[1]))' "$p" 2>/dev/null || echo "$p"
}
assert_safe_workdir() {
local rp
rp="$(realpath_safe "$WORKDIR")"
[[ -n "$rp" ]] || die "Invalid workdir"
[[ "$rp" != "/" ]] || die "Refusing cleanup on root directory"
[[ "$rp" != "/opt" ]] || die "Refusing cleanup on /opt root; choose a dedicated OpenSim workdir"
[[ -d "$rp" ]] || die "Workdir not found: $rp"
WORKDIR="$rp"
}
run_delete() {
local path="$1"
if [[ "$DRY_RUN" == "true" ]]; then
log INFO "[DRY-RUN] Would remove: $path"
else
rm -rf "$path"
log INFO "Removed: $path"
fi
}
run_delete_file() {
local path="$1"
if [[ "$DRY_RUN" == "true" ]]; then
log INFO "[DRY-RUN] Would delete file: $path"
else
rm -f "$path"
log INFO "Deleted file: $path"
fi
}
cache_clean() {
log INFO "Cleaning map tiles and cache under $WORKDIR"
local d
while IFS= read -r d; do
[[ -n "$d" ]] || continue
run_delete "$d"
done < <(find "$WORKDIR" -mindepth 2 -type d \( -name "assetcache" -o -name "MapTiles" -o -name "cache" \))
}
log_clean() {
log INFO "Cleaning log files under $WORKDIR"
local f
while IFS= read -r f; do
[[ -n "$f" ]] || continue
run_delete_file "$f"
done < <(find "$WORKDIR" -type f \( -name "*.log" -o -name "OpenSim.log" -o -name "ProblemRestarts.log" \))
}
tmp_clean() {
log INFO "Cleaning temporary files under $WORKDIR"
local f
while IFS= read -r f; do
[[ -n "$f" ]] || continue
run_delete_file "$f"
done < <(find "$WORKDIR" -type f \( -name "*.tmp" -o -name "*.temp" \))
}
safe_reboot() {
if confirm "Reboot" "Reboot server now?"; then
log INFO "Reboot requested"
sudo reboot
else
log INFO "Reboot canceled"
fi
}
WORKDIR="$DEFAULT_WORKDIR"
ACTION=""
PROFILE="grid-sim"
DRY_RUN="false"
while [[ $# -gt 0 ]]; do
case "$1" in
--workdir) WORKDIR="$2"; shift 2 ;;
--profile) PROFILE="$2"; shift 2 ;;
--action) ACTION="$2"; shift 2 ;;
--dry-run) DRY_RUN="$2"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) die "Unknown option: $1" ;;
esac
done
[[ -n "$ACTION" ]] || die "Missing --action"
validate_profile "$PROFILE"
ensure_profile_action_allowed cleanup "$PROFILE" "$ACTION"
case "$DRY_RUN" in true|false) ;; *) die "--dry-run must be true or false" ;; esac
assert_safe_workdir
log INFO "Using profile: $PROFILE"
log INFO "Dry-run mode: $DRY_RUN"
case "$ACTION" in
cache-clean) cache_clean ;;
log-clean) log_clean ;;
tmp-clean) tmp_clean ;;
reboot) safe_reboot ;;
*) die "Unsupported action: $ACTION" ;;
esac
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=/dev/null
source "$SCRIPT_DIR/osmtool_core.sh"
usage() {
cat <<'EOF'
Usage:
osmtool_cleanup.sh [--workdir <path>] --action <cache-clean|log-clean|tmp-clean|reboot> [--dry-run <true|false>]
Examples:
osmtool_cleanup.sh --action log-clean --workdir /opt --dry-run true
osmtool_cleanup.sh --action cache-clean --workdir /opt/opensim
EOF
print_usage_common
}
realpath_safe() {
local p="$1"
python3 -c 'import os,sys; print(os.path.realpath(sys.argv[1]))' "$p" 2>/dev/null || echo "$p"
}
assert_safe_workdir() {
local rp
rp="$(realpath_safe "$WORKDIR")"
[[ -n "$rp" ]] || die "Invalid workdir"
[[ "$rp" != "/" ]] || die "Refusing cleanup on root directory"
[[ "$rp" != "/opt" ]] || die "Refusing cleanup on /opt root; choose a dedicated OpenSim workdir"
[[ -d "$rp" ]] || die "Workdir not found: $rp"
WORKDIR="$rp"
}
run_delete() {
local path="$1"
if [[ "$DRY_RUN" == "true" ]]; then
log INFO "[DRY-RUN] Would remove: $path"
else
rm -rf "$path"
log INFO "Removed: $path"
fi
}
run_delete_file() {
local path="$1"
if [[ "$DRY_RUN" == "true" ]]; then
log INFO "[DRY-RUN] Would delete file: $path"
else
rm -f "$path"
log INFO "Deleted file: $path"
fi
}
cache_clean() {
log INFO "Cleaning map tiles and cache under $WORKDIR"
local d
while IFS= read -r d; do
[[ -n "$d" ]] || continue
run_delete "$d"
done < <(find "$WORKDIR" -mindepth 2 -type d \( -name "assetcache" -o -name "MapTiles" -o -name "cache" \))
}
log_clean() {
log INFO "Cleaning log files under $WORKDIR"
local f
while IFS= read -r f; do
[[ -n "$f" ]] || continue
run_delete_file "$f"
done < <(find "$WORKDIR" -type f \( -name "*.log" -o -name "OpenSim.log" -o -name "ProblemRestarts.log" \))
}
tmp_clean() {
log INFO "Cleaning temporary files under $WORKDIR"
local f
while IFS= read -r f; do
[[ -n "$f" ]] || continue
run_delete_file "$f"
done < <(find "$WORKDIR" -type f \( -name "*.tmp" -o -name "*.temp" \))
}
safe_reboot() {
if confirm "Reboot" "Reboot server now?"; then
log INFO "Reboot requested"
sudo reboot
else
log INFO "Reboot canceled"
fi
}
WORKDIR="$DEFAULT_WORKDIR"
ACTION=""
PROFILE="grid-sim"
DRY_RUN="false"
while [[ $# -gt 0 ]]; do
case "$1" in
--workdir) WORKDIR="$2"; shift 2 ;;
--profile) PROFILE="$2"; shift 2 ;;
--action) ACTION="$2"; shift 2 ;;
--dry-run) DRY_RUN="$2"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) die "Unknown option: $1" ;;
esac
done
[[ -n "$ACTION" ]] || die "Missing --action"
validate_profile "$PROFILE"
ensure_profile_action_allowed cleanup "$PROFILE" "$ACTION"
case "$DRY_RUN" in true|false) ;; *) die "--dry-run must be true or false" ;; esac
assert_safe_workdir
log INFO "Using profile: $PROFILE"
log INFO "Dry-run mode: $DRY_RUN"
case "$ACTION" in
cache-clean) cache_clean ;;
log-clean) log_clean ;;
tmp-clean) tmp_clean ;;
reboot) safe_reboot ;;
*) die "Unsupported action: $ACTION" ;;
esac
+219 -219
View File
@@ -1,220 +1,220 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=/dev/null
source "$SCRIPT_DIR/osmtool_core.sh"
usage() {
cat <<'EOF'
Usage:
osmtool_config.sh [--workdir <path>] --action <init-config|validate-file|validate-runtime>
[--file <path>] [--strict <true|false>]
Examples:
osmtool_config.sh --action init-config
osmtool_config.sh --action validate-file --file /opt/sim1/bin/OpenSim.ini
osmtool_config.sh --action validate-runtime --profile grid-sim --workdir /opt
EOF
print_usage_common
}
trim() {
local value="$1"
value="${value#"${value%%[![:space:]]*}"}"
value="${value%"${value##*[![:space:]]}"}"
printf '%s' "$value"
}
check_runtime_file() {
local file="$1"
local errors_before="$VALIDATION_ERRORS"
if [[ ! -f "$file" ]]; then
log ERROR "Missing config file: $file"
VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
return 1
fi
validate_file "$file"
if [[ "$VALIDATION_ERRORS" -gt "$errors_before" ]]; then
return 1
fi
return 0
}
validate_ini_file() {
local file="$1"
local line_number=0
local line trimmed seen_section=false
while IFS= read -r line || [[ -n "$line" ]]; do
line_number=$((line_number + 1))
trimmed="$(trim "$line")"
[[ -z "$trimmed" ]] && continue
case "$trimmed" in
';'*|'#'*) continue ;;
'['*']')
seen_section=true
continue
;;
*=*)
continue
;;
.include*)
continue
;;
*)
log ERROR "Invalid INI syntax in $file:$line_number -> $line"
VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
;;
esac
done < "$file"
if [[ "$STRICT" == "true" && "$seen_section" == "false" ]]; then
log ERROR "INI file has no section headers: $file"
VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
fi
}
validate_json_file() {
local file="$1"
if command -v jq >/dev/null 2>&1; then
if ! jq empty "$file" >/dev/null 2>&1; then
log ERROR "Invalid JSON syntax: $file"
VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
fi
return 0
fi
if command -v python3 >/dev/null 2>&1; then
if ! python3 -m json.tool "$file" >/dev/null 2>&1; then
log ERROR "Invalid JSON syntax: $file"
VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
fi
return 0
fi
die "validate-json requires jq or python3"
}
validate_file() {
local file="$1"
[[ -f "$file" ]] || die "Config file not found: $file"
case "$file" in
*.ini|*.INI)
log INFO "Validating INI file: $file"
validate_ini_file "$file"
;;
*.json|*.JSON)
log INFO "Validating JSON file: $file"
validate_json_file "$file"
;;
*)
die "Unsupported config file type: $file"
;;
esac
}
validate_grid_runtime() {
local sim_ini
local sim_count=0
check_runtime_file "$WORKDIR/robust/bin/Robust.ini"
shopt -s nullglob
for sim_ini in "$WORKDIR"/sim*/bin/OpenSim.ini; do
sim_count=$((sim_count + 1))
check_runtime_file "$sim_ini"
done
shopt -u nullglob
if [[ "$sim_count" -eq 0 ]]; then
log ERROR "No region runtime configs found under $WORKDIR/sim*/bin/OpenSim.ini"
VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
fi
}
validate_robust_runtime() {
check_runtime_file "$WORKDIR/robust/bin/Robust.ini"
}
validate_standalone_runtime() {
check_runtime_file "$WORKDIR/standalone/bin/OpenSim.ini"
}
validate_runtime() {
case "$PROFILE" in
grid-sim) validate_grid_runtime ;;
robust) validate_robust_runtime ;;
standalone) validate_standalone_runtime ;;
esac
if [[ "$VALIDATION_ERRORS" -gt 0 ]]; then
die "Configuration validation failed with $VALIDATION_ERRORS issue(s)"
fi
log INFO "Configuration validation passed"
}
WORKDIR="$DEFAULT_WORKDIR"
ACTION=""
PROFILE="grid-sim"
FILE=""
STRICT="false"
VALIDATION_ERRORS=0
while [[ $# -gt 0 ]]; do
case "$1" in
--workdir) WORKDIR="$2"; shift 2 ;;
--profile) PROFILE="$2"; shift 2 ;;
--action) ACTION="$2"; shift 2 ;;
--file) FILE="$2"; shift 2 ;;
--strict) STRICT="$2"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) die "Unknown option: $1" ;;
esac
done
[[ -n "$ACTION" ]] || die "Missing --action"
validate_profile "$PROFILE"
ensure_profile_action_allowed config "$PROFILE" "$ACTION"
if [[ "$ACTION" != "init-config" && ! -f "$OSMTOOL_CONFIG_FILE" ]]; then
if [[ -t 0 ]]; then
log INFO "Shared configuration not found. Starting interactive setup."
init_shared_config_interactive
else
log INFO "Shared configuration not found at $OSMTOOL_CONFIG_FILE (non-interactive mode)"
fi
fi
case "$STRICT" in
true|false) ;;
*) die "--strict must be true or false" ;;
esac
log INFO "Using profile: $PROFILE"
case "$ACTION" in
init-config)
init_shared_config_interactive
;;
validate-file)
[[ -n "$FILE" ]] || die "validate-file requires --file"
validate_file "$FILE"
if [[ "$VALIDATION_ERRORS" -gt 0 ]]; then
die "Configuration validation failed with $VALIDATION_ERRORS issue(s)"
fi
log INFO "Configuration validation passed"
;;
validate-runtime)
validate_runtime
;;
*) die "Unsupported action: $ACTION" ;;
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=/dev/null
source "$SCRIPT_DIR/osmtool_core.sh"
usage() {
cat <<'EOF'
Usage:
osmtool_config.sh [--workdir <path>] --action <init-config|validate-file|validate-runtime>
[--file <path>] [--strict <true|false>]
Examples:
osmtool_config.sh --action init-config
osmtool_config.sh --action validate-file --file /opt/sim1/bin/OpenSim.ini
osmtool_config.sh --action validate-runtime --profile grid-sim --workdir /opt
EOF
print_usage_common
}
trim() {
local value="$1"
value="${value#"${value%%[![:space:]]*}"}"
value="${value%"${value##*[![:space:]]}"}"
printf '%s' "$value"
}
check_runtime_file() {
local file="$1"
local errors_before="$VALIDATION_ERRORS"
if [[ ! -f "$file" ]]; then
log ERROR "Missing config file: $file"
VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
return 1
fi
validate_file "$file"
if [[ "$VALIDATION_ERRORS" -gt "$errors_before" ]]; then
return 1
fi
return 0
}
validate_ini_file() {
local file="$1"
local line_number=0
local line trimmed seen_section=false
while IFS= read -r line || [[ -n "$line" ]]; do
line_number=$((line_number + 1))
trimmed="$(trim "$line")"
[[ -z "$trimmed" ]] && continue
case "$trimmed" in
';'*|'#'*) continue ;;
'['*']')
seen_section=true
continue
;;
*=*)
continue
;;
.include*)
continue
;;
*)
log ERROR "Invalid INI syntax in $file:$line_number -> $line"
VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
;;
esac
done < "$file"
if [[ "$STRICT" == "true" && "$seen_section" == "false" ]]; then
log ERROR "INI file has no section headers: $file"
VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
fi
}
validate_json_file() {
local file="$1"
if command -v jq >/dev/null 2>&1; then
if ! jq empty "$file" >/dev/null 2>&1; then
log ERROR "Invalid JSON syntax: $file"
VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
fi
return 0
fi
if command -v python3 >/dev/null 2>&1; then
if ! python3 -m json.tool "$file" >/dev/null 2>&1; then
log ERROR "Invalid JSON syntax: $file"
VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
fi
return 0
fi
die "validate-json requires jq or python3"
}
validate_file() {
local file="$1"
[[ -f "$file" ]] || die "Config file not found: $file"
case "$file" in
*.ini|*.INI)
log INFO "Validating INI file: $file"
validate_ini_file "$file"
;;
*.json|*.JSON)
log INFO "Validating JSON file: $file"
validate_json_file "$file"
;;
*)
die "Unsupported config file type: $file"
;;
esac
}
validate_grid_runtime() {
local sim_ini
local sim_count=0
check_runtime_file "$WORKDIR/robust/bin/Robust.ini"
shopt -s nullglob
for sim_ini in "$WORKDIR"/sim*/bin/OpenSim.ini; do
sim_count=$((sim_count + 1))
check_runtime_file "$sim_ini"
done
shopt -u nullglob
if [[ "$sim_count" -eq 0 ]]; then
log ERROR "No region runtime configs found under $WORKDIR/sim*/bin/OpenSim.ini"
VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1))
fi
}
validate_robust_runtime() {
check_runtime_file "$WORKDIR/robust/bin/Robust.ini"
}
validate_standalone_runtime() {
check_runtime_file "$WORKDIR/standalone/bin/OpenSim.ini"
}
validate_runtime() {
case "$PROFILE" in
grid-sim) validate_grid_runtime ;;
robust) validate_robust_runtime ;;
standalone) validate_standalone_runtime ;;
esac
if [[ "$VALIDATION_ERRORS" -gt 0 ]]; then
die "Configuration validation failed with $VALIDATION_ERRORS issue(s)"
fi
log INFO "Configuration validation passed"
}
WORKDIR="$DEFAULT_WORKDIR"
ACTION=""
PROFILE="grid-sim"
FILE=""
STRICT="false"
VALIDATION_ERRORS=0
while [[ $# -gt 0 ]]; do
case "$1" in
--workdir) WORKDIR="$2"; shift 2 ;;
--profile) PROFILE="$2"; shift 2 ;;
--action) ACTION="$2"; shift 2 ;;
--file) FILE="$2"; shift 2 ;;
--strict) STRICT="$2"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) die "Unknown option: $1" ;;
esac
done
[[ -n "$ACTION" ]] || die "Missing --action"
validate_profile "$PROFILE"
ensure_profile_action_allowed config "$PROFILE" "$ACTION"
if [[ "$ACTION" != "init-config" && ! -f "$OSMTOOL_CONFIG_FILE" ]]; then
if [[ -t 0 ]]; then
log INFO "Shared configuration not found. Starting interactive setup."
init_shared_config_interactive
else
log INFO "Shared configuration not found at $OSMTOOL_CONFIG_FILE (non-interactive mode)"
fi
fi
case "$STRICT" in
true|false) ;;
*) die "--strict must be true or false" ;;
esac
log INFO "Using profile: $PROFILE"
case "$ACTION" in
init-config)
init_shared_config_interactive
;;
validate-file)
[[ -n "$FILE" ]] || die "validate-file requires --file"
validate_file "$FILE"
if [[ "$VALIDATION_ERRORS" -gt 0 ]]; then
die "Configuration validation failed with $VALIDATION_ERRORS issue(s)"
fi
log INFO "Configuration validation passed"
;;
validate-runtime)
validate_runtime
;;
*) die "Unsupported action: $ACTION" ;;
esac
+456 -456
View File
@@ -1,456 +1,456 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
export DEFAULT_WORKDIR="/opt"
export OSMTOOL_CONFIG_FILE="${OSMTOOL_CONFIG_FILE:-$ROOT_DIR/osmtool_config.json}"
LANG_DIR="$ROOT_DIR/lang"
APP_LANG="${OSM_LANG:-de}"
LOG_FILE="${LOG_FILE:-$ROOT_DIR/osmtool_backup.log}"
declare -A I18N_CURRENT=()
declare -A I18N_EN=()
log() {
local level="$1"
shift
printf '[%s] [%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$level" "$*" | tee -a "$LOG_FILE"
}
die() {
log ERROR "$*"
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || die "Missing required command: $1"
}
normalize_lang() {
case "$1" in
de|en|fr|es) echo "$1" ;;
*) echo "de" ;;
esac
}
config_get_string() {
local key="$1"
local default_value="$2"
local value=""
[[ -f "$OSMTOOL_CONFIG_FILE" ]] || {
printf '%s' "$default_value"
return
}
if command -v jq >/dev/null 2>&1; then
value="$(jq -r --arg k "$key" '.[$k] // empty' "$OSMTOOL_CONFIG_FILE" 2>/dev/null || true)"
else
value="$(sed -n -E "s/^[[:space:]]*\"${key}\"[[:space:]]*:[[:space:]]*\"([^\"]*)\"[[:space:]]*,?[[:space:]]*$/\1/p" "$OSMTOOL_CONFIG_FILE" | head -n1)"
fi
if [[ -n "$value" ]]; then
printf '%s' "$value"
else
printf '%s' "$default_value"
fi
}
config_get_bool() {
local key="$1"
local default_value="$2"
local value=""
[[ -f "$OSMTOOL_CONFIG_FILE" ]] || {
printf '%s' "$default_value"
return
}
if command -v jq >/dev/null 2>&1; then
value="$(jq -r --arg k "$key" '.[$k] // empty' "$OSMTOOL_CONFIG_FILE" 2>/dev/null || true)"
else
value="$(sed -n -E "s/^[[:space:]]*\"${key}\"[[:space:]]*:[[:space:]]*(true|false)[[:space:]]*,?[[:space:]]*$/\1/p" "$OSMTOOL_CONFIG_FILE" | head -n1)"
fi
case "$value" in
true|false) printf '%s' "$value" ;;
*) printf '%s' "$default_value" ;;
esac
}
config_get_int() {
local key="$1"
local default_value="$2"
local value=""
[[ -f "$OSMTOOL_CONFIG_FILE" ]] || {
printf '%s' "$default_value"
return
}
if command -v jq >/dev/null 2>&1; then
value="$(jq -r --arg k "$key" '.[$k] // empty' "$OSMTOOL_CONFIG_FILE" 2>/dev/null || true)"
else
value="$(sed -n -E "s/^[[:space:]]*\"${key}\"[[:space:]]*:[[:space:]]*([0-9]+)[[:space:]]*,?[[:space:]]*$/\1/p" "$OSMTOOL_CONFIG_FILE" | head -n1)"
fi
if [[ "$value" =~ ^[0-9]+$ ]]; then
printf '%s' "$value"
else
printf '%s' "$default_value"
fi
}
config_path_value() {
local value="$1"
if [[ "$value" = /* ]]; then
printf '%s' "$value"
else
printf '%s' "$ROOT_DIR/$value"
fi
}
load_shared_config() {
local cfg_lang cfg_workdir
cfg_lang="$(normalize_lang "$(config_get_string "language" "de")")"
cfg_workdir="$(config_get_string "path_workdir" "$DEFAULT_WORKDIR")"
DEFAULT_WORKDIR="$cfg_workdir"
export DEFAULT_WORKDIR
if [[ -z "${OSM_LANG:-}" ]]; then
APP_LANG="$cfg_lang"
fi
CONFIG_DB_ROOT_USER="$(config_get_string "db_root_user" "root")"
CONFIG_DB_ROOT_PASS="$(config_get_string "db_root_pass" "")"
CONFIG_DB_USER="$(config_get_string "db_user" "opensimuser")"
CONFIG_DB_PASS="$(config_get_string "db_pass" "")"
CONFIG_PUBLIC_HOST="$(config_get_string "public_host" "127.0.0.1")"
CONFIG_GRIDNAME="$(config_get_string "gridname" "")"
CONFIG_JANUS_PREFIX="$(config_get_string "janus_prefix" "/opt/janus")"
CONFIG_OPENSIM_DIR="$(config_get_string "opensim_dir" "")"
export CONFIG_DB_ROOT_USER CONFIG_DB_ROOT_PASS CONFIG_DB_USER CONFIG_DB_PASS
export CONFIG_PUBLIC_HOST CONFIG_GRIDNAME CONFIG_JANUS_PREFIX CONFIG_OPENSIM_DIR
}
config_prompt_with_default() {
local prompt="$1"
local default_value="$2"
local answer=""
read -r -p "$prompt [$default_value]: " answer
if [[ -z "$answer" ]]; then
printf '%s' "$default_value"
else
printf '%s' "$answer"
fi
}
write_shared_config_file() {
local language="$1"
local workdir="$2"
local db_root_user="$3"
local db_root_pass="$4"
local db_user="$5"
local db_pass="$6"
local public_host="$7"
local gridname="$8"
local janus_prefix="$9"
local opensim_dir="${10}"
cat > "$OSMTOOL_CONFIG_FILE" <<EOF
{
"language": "${language}",
"path_workdir": "${workdir}",
"path_lang_dir": "lang",
"path_robust_bin": "robust/bin",
"path_opensim_bin": "opensim/bin",
"db_root_user": "${db_root_user}",
"db_root_pass": "${db_root_pass}",
"db_user": "${db_user}",
"db_pass": "${db_pass}",
"public_host": "${public_host}",
"gridname": "${gridname}",
"janus_prefix": "${janus_prefix}",
"opensim_dir": "${opensim_dir}",
"log_enabled": true,
"old_log_del": true,
"debug_log": "osmtool_debug.log",
"max_log_size_mb": 10,
"simulator_start_wait": 15,
"moneyserver_start_wait": 30,
"robustserver_start_wait": 30,
"simulator_stop_wait": 15,
"moneyserver_stop_wait": 30,
"robustserver_stop_wait": 30
}
EOF
}
init_shared_config_interactive() {
local cur_lang cur_workdir cur_db_root_user cur_db_root_pass cur_db_user cur_db_pass
local cur_public_host cur_gridname cur_janus_prefix cur_opensim_dir
local language workdir db_root_user db_root_pass db_user db_pass public_host gridname janus_prefix opensim_dir
if [[ ! -t 0 ]]; then
die "Interactive config initialization requires a TTY"
fi
cur_lang="$(normalize_lang "${OSM_LANG:-$(config_get_string "language" "de")}")"
cur_workdir="$(config_get_string "path_workdir" "$DEFAULT_WORKDIR")"
cur_db_root_user="$(config_get_string "db_root_user" "root")"
cur_db_root_pass="$(config_get_string "db_root_pass" "")"
cur_db_user="$(config_get_string "db_user" "opensimuser")"
cur_db_pass="$(config_get_string "db_pass" "")"
cur_public_host="$(config_get_string "public_host" "127.0.0.1")"
cur_gridname="$(config_get_string "gridname" "")"
cur_janus_prefix="$(config_get_string "janus_prefix" "/opt/janus")"
cur_opensim_dir="$(config_get_string "opensim_dir" "$cur_workdir/opensim")"
echo "Shared configuration file: $OSMTOOL_CONFIG_FILE"
language="$(normalize_lang "$(config_prompt_with_default "Language (de|en|fr|es)" "$cur_lang")")"
workdir="$(config_prompt_with_default "Workdir" "$cur_workdir")"
db_root_user="$(config_prompt_with_default "DB root user" "$cur_db_root_user")"
db_root_pass="$(config_prompt_with_default "DB root password" "$cur_db_root_pass")"
db_user="$(config_prompt_with_default "DB app user" "$cur_db_user")"
db_pass="$(config_prompt_with_default "DB app password" "$cur_db_pass")"
public_host="$(config_prompt_with_default "Public host/IP" "$cur_public_host")"
gridname="$(config_prompt_with_default "Grid name" "$cur_gridname")"
janus_prefix="$(config_prompt_with_default "Janus prefix" "$cur_janus_prefix")"
opensim_dir="$(config_prompt_with_default "OpenSim source dir" "$cur_opensim_dir")"
mkdir -p "$(dirname "$OSMTOOL_CONFIG_FILE")"
write_shared_config_file "$language" "$workdir" "$db_root_user" "$db_root_pass" "$db_user" "$db_pass" "$public_host" "$gridname" "$janus_prefix" "$opensim_dir"
load_shared_config
set_language "$language"
log INFO "Shared configuration written: $OSMTOOL_CONFIG_FILE"
}
validate_profile() {
case "$1" in
grid-sim|robust|standalone) return 0 ;;
*) die "$(msg ERR_INVALID_PROFILE): $1" ;;
esac
}
profile_action_allowed() {
local module="$1"
local profile="$2"
local action="$3"
case "$module:$profile" in
install:grid-sim|install:robust|install:standalone)
case "$action" in init-config|server-check|prepare-ubuntu|install-opensim-deps|install-dotnet8|install-opensim|configure-opensim|configure-database|compile-janus|configure-janus|install-janus) return 0 ;; esac
;;
startstop:grid-sim|startstop:robust|startstop:standalone)
case "$action" in start|stop|restart) return 0 ;; esac
;;
cleanup:grid-sim|cleanup:robust|cleanup:standalone)
case "$action" in cache-clean|log-clean|tmp-clean|reboot) return 0 ;; esac
;;
health:grid-sim|health:robust|health:standalone)
case "$action" in run) return 0 ;; esac
;;
backup:grid-sim)
case "$action" in db-backup|oar-backup|full-backup) return 0 ;; esac
;;
backup:robust)
case "$action" in db-backup|full-backup) return 0 ;; esac
;;
backup:standalone)
case "$action" in oar-backup|full-backup) return 0 ;; esac
;;
cron:grid-sim|cron:robust|cron:standalone)
case "$action" in install|list|remove) return 0 ;; esac
;;
restore:grid-sim)
case "$action" in db-restore|oar-restore|full-restore|list-backups) return 0 ;; esac
;;
restore:robust)
case "$action" in db-restore|full-restore|list-backups) return 0 ;; esac
;;
restore:standalone)
case "$action" in oar-restore|full-restore|list-backups) return 0 ;; esac
;;
update:grid-sim|update:robust|update:standalone)
case "$action" in create-rollback|list-rollbacks|update-opensim|update-janus|full-update) return 0 ;; esac
;;
config:grid-sim|config:robust|config:standalone)
case "$action" in init-config|validate-file|validate-runtime) return 0 ;; esac
;;
report:grid-sim|report:robust|report:standalone)
case "$action" in generate) return 0 ;; esac
;;
smoke:grid-sim|smoke:robust|smoke:standalone)
case "$action" in run) return 0 ;; esac
;;
esac
return 1
}
ensure_profile_action_allowed() {
local module="$1"
local profile="$2"
local action="$3"
if ! profile_action_allowed "$module" "$profile" "$action"; then
die "$(msg ERR_ACTION_NOT_ALLOWED): module=$module profile=$profile action=$action"
fi
}
profile_target_allowed() {
local profile="$1"
local target="$2"
case "$profile" in
grid-sim)
case "$target" in grid|robust|sim1|region|janus) return 0 ;; esac
;;
robust)
case "$target" in robust|janus) return 0 ;; esac
;;
standalone)
case "$target" in standalone|janus) return 0 ;; esac
;;
esac
return 1
}
ensure_profile_target_allowed() {
local profile="$1"
local target="$2"
if ! profile_target_allowed "$profile" "$target"; then
die "$(msg ERR_TARGET_NOT_ALLOWED): profile=$profile target=$target"
fi
}
load_lang_file() {
local lang_file="$1"
local target_array_name="$2"
local line key value
[[ -f "$lang_file" ]] || return 1
while IFS= read -r line || [[ -n "$line" ]]; do
[[ -z "$line" || "${line:0:1}" == "#" ]] && continue
[[ "$line" == *=* ]] || continue
key="${line%%=*}"
value="${line#*=}"
if [[ "$target_array_name" == "I18N_EN" ]]; then
I18N_EN["$key"]="$value"
else
I18N_CURRENT["$key"]="$value"
fi
done < "$lang_file"
return 0
}
init_i18n() {
APP_LANG="$(normalize_lang "$APP_LANG")"
I18N_CURRENT=()
I18N_EN=()
load_lang_file "$LANG_DIR/en.lang" I18N_EN || true
load_lang_file "$LANG_DIR/${APP_LANG}.lang" I18N_CURRENT || true
}
set_language() {
APP_LANG="$(normalize_lang "$1")"
export OSM_LANG="$APP_LANG"
init_i18n
}
msg() {
local key="$1"
if [[ -n "${I18N_CURRENT[$key]:-}" ]]; then
printf '%s' "${I18N_CURRENT[$key]}"
return
fi
if [[ -n "${I18N_EN[$key]:-}" ]]; then
printf '%s' "${I18N_EN[$key]}"
return
fi
printf '%s' "$key"
}
ui_backend() {
if command -v whiptail >/dev/null 2>&1; then
echo "whiptail"
return
fi
if command -v dialog >/dev/null 2>&1; then
echo "dialog"
return
fi
echo "none"
}
show_menu() {
local title="$1"
local text="$2"
shift 2
local backend
backend="$(ui_backend)"
case "$backend" in
whiptail)
whiptail --title "$title" --menu "$text" 20 80 12 "$@" 3>&1 1>&2 2>&3
;;
dialog)
dialog --clear --stdout --title "$title" --menu "$text" 20 80 12 "$@"
;;
none)
die "$(msg ERR_NO_UI_BACKEND)"
;;
esac
}
confirm() {
local title="$1"
local text="$2"
local backend
backend="$(ui_backend)"
case "$backend" in
whiptail)
whiptail --title "$title" --yesno "$text" 10 70
;;
dialog)
dialog --clear --title "$title" --yesno "$text" 10 70
;;
none)
return 1
;;
esac
}
print_usage_common() {
cat <<'EOF'
Global options:
--workdir <path> Base path (default: /opt)
--mode <cli|ui> Run in CLI mode (default) or menu mode
--lang <de|en|fr|es> Language selection
--profile <name> Runtime profile (grid-sim|robust|standalone)
--help Show help
EOF
}
# Load shared settings before translations and module defaults are resolved.
load_shared_config
# Ensure translations are available in every script that sources this core.
init_i18n
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
export DEFAULT_WORKDIR="/opt"
export OSMTOOL_CONFIG_FILE="${OSMTOOL_CONFIG_FILE:-$ROOT_DIR/osmtool_config.json}"
LANG_DIR="$ROOT_DIR/lang"
APP_LANG="${OSM_LANG:-de}"
LOG_FILE="${LOG_FILE:-$ROOT_DIR/osmtool_backup.log}"
declare -A I18N_CURRENT=()
declare -A I18N_EN=()
log() {
local level="$1"
shift
printf '[%s] [%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$level" "$*" | tee -a "$LOG_FILE"
}
die() {
log ERROR "$*"
exit 1
}
need_cmd() {
command -v "$1" >/dev/null 2>&1 || die "Missing required command: $1"
}
normalize_lang() {
case "$1" in
de|en|fr|es) echo "$1" ;;
*) echo "de" ;;
esac
}
config_get_string() {
local key="$1"
local default_value="$2"
local value=""
[[ -f "$OSMTOOL_CONFIG_FILE" ]] || {
printf '%s' "$default_value"
return
}
if command -v jq >/dev/null 2>&1; then
value="$(jq -r --arg k "$key" '.[$k] // empty' "$OSMTOOL_CONFIG_FILE" 2>/dev/null || true)"
else
value="$(sed -n -E "s/^[[:space:]]*\"${key}\"[[:space:]]*:[[:space:]]*\"([^\"]*)\"[[:space:]]*,?[[:space:]]*$/\1/p" "$OSMTOOL_CONFIG_FILE" | head -n1)"
fi
if [[ -n "$value" ]]; then
printf '%s' "$value"
else
printf '%s' "$default_value"
fi
}
config_get_bool() {
local key="$1"
local default_value="$2"
local value=""
[[ -f "$OSMTOOL_CONFIG_FILE" ]] || {
printf '%s' "$default_value"
return
}
if command -v jq >/dev/null 2>&1; then
value="$(jq -r --arg k "$key" '.[$k] // empty' "$OSMTOOL_CONFIG_FILE" 2>/dev/null || true)"
else
value="$(sed -n -E "s/^[[:space:]]*\"${key}\"[[:space:]]*:[[:space:]]*(true|false)[[:space:]]*,?[[:space:]]*$/\1/p" "$OSMTOOL_CONFIG_FILE" | head -n1)"
fi
case "$value" in
true|false) printf '%s' "$value" ;;
*) printf '%s' "$default_value" ;;
esac
}
config_get_int() {
local key="$1"
local default_value="$2"
local value=""
[[ -f "$OSMTOOL_CONFIG_FILE" ]] || {
printf '%s' "$default_value"
return
}
if command -v jq >/dev/null 2>&1; then
value="$(jq -r --arg k "$key" '.[$k] // empty' "$OSMTOOL_CONFIG_FILE" 2>/dev/null || true)"
else
value="$(sed -n -E "s/^[[:space:]]*\"${key}\"[[:space:]]*:[[:space:]]*([0-9]+)[[:space:]]*,?[[:space:]]*$/\1/p" "$OSMTOOL_CONFIG_FILE" | head -n1)"
fi
if [[ "$value" =~ ^[0-9]+$ ]]; then
printf '%s' "$value"
else
printf '%s' "$default_value"
fi
}
config_path_value() {
local value="$1"
if [[ "$value" = /* ]]; then
printf '%s' "$value"
else
printf '%s' "$ROOT_DIR/$value"
fi
}
load_shared_config() {
local cfg_lang cfg_workdir
cfg_lang="$(normalize_lang "$(config_get_string "language" "de")")"
cfg_workdir="$(config_get_string "path_workdir" "$DEFAULT_WORKDIR")"
DEFAULT_WORKDIR="$cfg_workdir"
export DEFAULT_WORKDIR
if [[ -z "${OSM_LANG:-}" ]]; then
APP_LANG="$cfg_lang"
fi
CONFIG_DB_ROOT_USER="$(config_get_string "db_root_user" "root")"
CONFIG_DB_ROOT_PASS="$(config_get_string "db_root_pass" "")"
CONFIG_DB_USER="$(config_get_string "db_user" "opensimuser")"
CONFIG_DB_PASS="$(config_get_string "db_pass" "")"
CONFIG_PUBLIC_HOST="$(config_get_string "public_host" "127.0.0.1")"
CONFIG_GRIDNAME="$(config_get_string "gridname" "")"
CONFIG_JANUS_PREFIX="$(config_get_string "janus_prefix" "/opt/janus")"
CONFIG_OPENSIM_DIR="$(config_get_string "opensim_dir" "")"
export CONFIG_DB_ROOT_USER CONFIG_DB_ROOT_PASS CONFIG_DB_USER CONFIG_DB_PASS
export CONFIG_PUBLIC_HOST CONFIG_GRIDNAME CONFIG_JANUS_PREFIX CONFIG_OPENSIM_DIR
}
config_prompt_with_default() {
local prompt="$1"
local default_value="$2"
local answer=""
read -r -p "$prompt [$default_value]: " answer
if [[ -z "$answer" ]]; then
printf '%s' "$default_value"
else
printf '%s' "$answer"
fi
}
write_shared_config_file() {
local language="$1"
local workdir="$2"
local db_root_user="$3"
local db_root_pass="$4"
local db_user="$5"
local db_pass="$6"
local public_host="$7"
local gridname="$8"
local janus_prefix="$9"
local opensim_dir="${10}"
cat > "$OSMTOOL_CONFIG_FILE" <<EOF
{
"language": "${language}",
"path_workdir": "${workdir}",
"path_lang_dir": "lang",
"path_robust_bin": "robust/bin",
"path_opensim_bin": "opensim/bin",
"db_root_user": "${db_root_user}",
"db_root_pass": "${db_root_pass}",
"db_user": "${db_user}",
"db_pass": "${db_pass}",
"public_host": "${public_host}",
"gridname": "${gridname}",
"janus_prefix": "${janus_prefix}",
"opensim_dir": "${opensim_dir}",
"log_enabled": true,
"old_log_del": true,
"debug_log": "osmtool_debug.log",
"max_log_size_mb": 10,
"simulator_start_wait": 15,
"moneyserver_start_wait": 30,
"robustserver_start_wait": 30,
"simulator_stop_wait": 15,
"moneyserver_stop_wait": 30,
"robustserver_stop_wait": 30
}
EOF
}
init_shared_config_interactive() {
local cur_lang cur_workdir cur_db_root_user cur_db_root_pass cur_db_user cur_db_pass
local cur_public_host cur_gridname cur_janus_prefix cur_opensim_dir
local language workdir db_root_user db_root_pass db_user db_pass public_host gridname janus_prefix opensim_dir
if [[ ! -t 0 ]]; then
die "Interactive config initialization requires a TTY"
fi
cur_lang="$(normalize_lang "${OSM_LANG:-$(config_get_string "language" "de")}")"
cur_workdir="$(config_get_string "path_workdir" "$DEFAULT_WORKDIR")"
cur_db_root_user="$(config_get_string "db_root_user" "root")"
cur_db_root_pass="$(config_get_string "db_root_pass" "")"
cur_db_user="$(config_get_string "db_user" "opensimuser")"
cur_db_pass="$(config_get_string "db_pass" "")"
cur_public_host="$(config_get_string "public_host" "127.0.0.1")"
cur_gridname="$(config_get_string "gridname" "")"
cur_janus_prefix="$(config_get_string "janus_prefix" "/opt/janus")"
cur_opensim_dir="$(config_get_string "opensim_dir" "$cur_workdir/opensim")"
echo "Shared configuration file: $OSMTOOL_CONFIG_FILE"
language="$(normalize_lang "$(config_prompt_with_default "Language (de|en|fr|es)" "$cur_lang")")"
workdir="$(config_prompt_with_default "Workdir" "$cur_workdir")"
db_root_user="$(config_prompt_with_default "DB root user" "$cur_db_root_user")"
db_root_pass="$(config_prompt_with_default "DB root password" "$cur_db_root_pass")"
db_user="$(config_prompt_with_default "DB app user" "$cur_db_user")"
db_pass="$(config_prompt_with_default "DB app password" "$cur_db_pass")"
public_host="$(config_prompt_with_default "Public host/IP" "$cur_public_host")"
gridname="$(config_prompt_with_default "Grid name" "$cur_gridname")"
janus_prefix="$(config_prompt_with_default "Janus prefix" "$cur_janus_prefix")"
opensim_dir="$(config_prompt_with_default "OpenSim source dir" "$cur_opensim_dir")"
mkdir -p "$(dirname "$OSMTOOL_CONFIG_FILE")"
write_shared_config_file "$language" "$workdir" "$db_root_user" "$db_root_pass" "$db_user" "$db_pass" "$public_host" "$gridname" "$janus_prefix" "$opensim_dir"
load_shared_config
set_language "$language"
log INFO "Shared configuration written: $OSMTOOL_CONFIG_FILE"
}
validate_profile() {
case "$1" in
grid-sim|robust|standalone) return 0 ;;
*) die "$(msg ERR_INVALID_PROFILE): $1" ;;
esac
}
profile_action_allowed() {
local module="$1"
local profile="$2"
local action="$3"
case "$module:$profile" in
install:grid-sim|install:robust|install:standalone)
case "$action" in init-config|server-check|prepare-ubuntu|install-opensim-deps|install-dotnet8|install-opensim|configure-opensim|configure-database|compile-janus|configure-janus|install-janus) return 0 ;; esac
;;
startstop:grid-sim|startstop:robust|startstop:standalone)
case "$action" in start|stop|restart) return 0 ;; esac
;;
cleanup:grid-sim|cleanup:robust|cleanup:standalone)
case "$action" in cache-clean|log-clean|tmp-clean|reboot) return 0 ;; esac
;;
health:grid-sim|health:robust|health:standalone)
case "$action" in run) return 0 ;; esac
;;
backup:grid-sim)
case "$action" in db-backup|oar-backup|full-backup) return 0 ;; esac
;;
backup:robust)
case "$action" in db-backup|full-backup) return 0 ;; esac
;;
backup:standalone)
case "$action" in oar-backup|full-backup) return 0 ;; esac
;;
cron:grid-sim|cron:robust|cron:standalone)
case "$action" in install|list|remove) return 0 ;; esac
;;
restore:grid-sim)
case "$action" in db-restore|oar-restore|full-restore|list-backups) return 0 ;; esac
;;
restore:robust)
case "$action" in db-restore|full-restore|list-backups) return 0 ;; esac
;;
restore:standalone)
case "$action" in oar-restore|full-restore|list-backups) return 0 ;; esac
;;
update:grid-sim|update:robust|update:standalone)
case "$action" in create-rollback|list-rollbacks|update-opensim|update-janus|full-update) return 0 ;; esac
;;
config:grid-sim|config:robust|config:standalone)
case "$action" in init-config|validate-file|validate-runtime) return 0 ;; esac
;;
report:grid-sim|report:robust|report:standalone)
case "$action" in generate) return 0 ;; esac
;;
smoke:grid-sim|smoke:robust|smoke:standalone)
case "$action" in run) return 0 ;; esac
;;
esac
return 1
}
ensure_profile_action_allowed() {
local module="$1"
local profile="$2"
local action="$3"
if ! profile_action_allowed "$module" "$profile" "$action"; then
die "$(msg ERR_ACTION_NOT_ALLOWED): module=$module profile=$profile action=$action"
fi
}
profile_target_allowed() {
local profile="$1"
local target="$2"
case "$profile" in
grid-sim)
case "$target" in grid|robust|sim1|region|janus) return 0 ;; esac
;;
robust)
case "$target" in robust|janus) return 0 ;; esac
;;
standalone)
case "$target" in standalone|janus) return 0 ;; esac
;;
esac
return 1
}
ensure_profile_target_allowed() {
local profile="$1"
local target="$2"
if ! profile_target_allowed "$profile" "$target"; then
die "$(msg ERR_TARGET_NOT_ALLOWED): profile=$profile target=$target"
fi
}
load_lang_file() {
local lang_file="$1"
local target_array_name="$2"
local line key value
[[ -f "$lang_file" ]] || return 1
while IFS= read -r line || [[ -n "$line" ]]; do
[[ -z "$line" || "${line:0:1}" == "#" ]] && continue
[[ "$line" == *=* ]] || continue
key="${line%%=*}"
value="${line#*=}"
if [[ "$target_array_name" == "I18N_EN" ]]; then
I18N_EN["$key"]="$value"
else
I18N_CURRENT["$key"]="$value"
fi
done < "$lang_file"
return 0
}
init_i18n() {
APP_LANG="$(normalize_lang "$APP_LANG")"
I18N_CURRENT=()
I18N_EN=()
load_lang_file "$LANG_DIR/en.lang" I18N_EN || true
load_lang_file "$LANG_DIR/${APP_LANG}.lang" I18N_CURRENT || true
}
set_language() {
APP_LANG="$(normalize_lang "$1")"
export OSM_LANG="$APP_LANG"
init_i18n
}
msg() {
local key="$1"
if [[ -n "${I18N_CURRENT[$key]:-}" ]]; then
printf '%s' "${I18N_CURRENT[$key]}"
return
fi
if [[ -n "${I18N_EN[$key]:-}" ]]; then
printf '%s' "${I18N_EN[$key]}"
return
fi
printf '%s' "$key"
}
ui_backend() {
if command -v whiptail >/dev/null 2>&1; then
echo "whiptail"
return
fi
if command -v dialog >/dev/null 2>&1; then
echo "dialog"
return
fi
echo "none"
}
show_menu() {
local title="$1"
local text="$2"
shift 2
local backend
backend="$(ui_backend)"
case "$backend" in
whiptail)
whiptail --title "$title" --menu "$text" 20 80 12 "$@" 3>&1 1>&2 2>&3
;;
dialog)
dialog --clear --stdout --title "$title" --menu "$text" 20 80 12 "$@"
;;
none)
die "$(msg ERR_NO_UI_BACKEND)"
;;
esac
}
confirm() {
local title="$1"
local text="$2"
local backend
backend="$(ui_backend)"
case "$backend" in
whiptail)
whiptail --title "$title" --yesno "$text" 10 70
;;
dialog)
dialog --clear --title "$title" --yesno "$text" 10 70
;;
none)
return 1
;;
esac
}
print_usage_common() {
cat <<'EOF'
Global options:
--workdir <path> Base path (default: /opt)
--mode <cli|ui> Run in CLI mode (default) or menu mode
--lang <de|en|fr|es> Language selection
--profile <name> Runtime profile (grid-sim|robust|standalone)
--help Show help
EOF
}
# Load shared settings before translations and module defaults are resolved.
load_shared_config
# Ensure translations are available in every script that sources this core.
init_i18n
+203 -203
View File
@@ -1,203 +1,203 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
# shellcheck source=/dev/null
source "$SCRIPT_DIR/osmtool_core.sh"
usage() {
cat <<'EOF'
Usage:
osmtool_cron.sh [--workdir <path>] --action <install|list|remove>
[--backup-schedule "<cron>"] [--restart-schedule "<cron>"] [--check-schedule "<cron>"] [--report-schedule "<cron>"] [--smoke-schedule "<cron>"]
[--db-user <user>] [--db-pass <pass>] [--db-name <name>]
[--region <name>] [--session <screen-name>] [--compress <true|false>]
Examples:
osmtool_cron.sh --action list
osmtool_cron.sh --action install --backup-schedule "0 3 * * *" --db-user root --db-pass secret --db-name opensim --region sim1
osmtool_cron.sh --action remove
EOF
print_usage_common
}
need_crontab() {
need_cmd crontab
}
quote_sq() {
local s="$1"
s="${s//\'/\'\"\'\"\'}"
printf "'%s'" "$s"
}
build_backup_cmd() {
local cmd
cmd="bash $ROOT_DIR/osmtool_main.sh --module backup --profile $PROFILE --workdir $WORKDIR --action full-backup --db-user $DB_USER --db-name $DB_NAME --region $REGION --session $SESSION_NAME --compress $COMPRESS"
if [[ -n "$DB_PASS" ]]; then
cmd+=" --db-pass $DB_PASS"
fi
printf '%s' "$cmd"
}
build_restart_cmd() {
printf '%s' "bash $ROOT_DIR/osmtool_main.sh --module startstop --profile $PROFILE --workdir $WORKDIR --target grid --action restart"
}
build_check_cmd() {
printf '%s' "bash $ROOT_DIR/osmtool_main.sh --module install --profile $PROFILE --workdir $WORKDIR --action server-check"
}
build_report_cmd() {
local cmd
cmd="bash $ROOT_DIR/osmtool_main.sh --module report --profile $PROFILE --workdir $WORKDIR --action generate --db-user $DB_USER --db-name $DB_NAME"
if [[ -n "$DB_PASS" ]]; then
cmd+=" --db-pass $DB_PASS"
fi
printf '%s' "$cmd"
}
build_smoke_cmd() {
printf '%s' "bash $ROOT_DIR/osmtool_main.sh --module smoke --profile $PROFILE --workdir $WORKDIR --action run"
}
cron_block_start="# OSMTOOL_CRON_BEGIN"
cron_block_end="# OSMTOOL_CRON_END"
emit_cron_block() {
local backup_cmd restart_cmd check_cmd report_cmd smoke_cmd
backup_cmd="$(build_backup_cmd)"
restart_cmd="$(build_restart_cmd)"
check_cmd="$(build_check_cmd)"
report_cmd="$(build_report_cmd)"
smoke_cmd="$(build_smoke_cmd)"
echo "$cron_block_start"
echo "SHELL=/bin/bash"
echo "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
echo "$BACKUP_SCHEDULE $backup_cmd >> $ROOT_DIR/osmtool_backup.log 2>&1"
echo "$RESTART_SCHEDULE $restart_cmd >> $ROOT_DIR/osmtool_backup.log 2>&1"
echo "$CHECK_SCHEDULE $check_cmd >> $ROOT_DIR/osmtool_backup.log 2>&1"
echo "$REPORT_SCHEDULE $report_cmd >> $ROOT_DIR/osmtool_backup.log 2>&1"
echo "$SMOKE_SCHEDULE $smoke_cmd >> $ROOT_DIR/osmtool_backup.log 2>&1"
echo "$cron_block_end"
}
existing_crontab() {
crontab -l 2>/dev/null || true
}
strip_osmtool_block() {
awk -v start="$cron_block_start" -v end="$cron_block_end" '
$0 == start {inblock=1; next}
$0 == end {inblock=0; next}
!inblock {print}
'
}
install_cron() {
local current tmp
[[ -n "$DB_USER" && -n "$DB_NAME" ]] || die "install cron requires --db-user and --db-name"
current="$(existing_crontab)"
tmp="$(mktemp)"
printf '%s\n' "$current" | strip_osmtool_block > "$tmp"
if [[ -s "$tmp" ]]; then
echo >> "$tmp"
fi
emit_cron_block >> "$tmp"
crontab "$tmp"
rm -f "$tmp"
log INFO "OSMTool cron jobs installed/updated"
}
list_cron() {
local current
current="$(existing_crontab)"
if printf '%s\n' "$current" | grep -q "^$cron_block_start$"; then
printf '%s\n' "$current" | awk -v start="$cron_block_start" -v end="$cron_block_end" '
$0 == start {inblock=1; print; next}
$0 == end {print; inblock=0; next}
inblock {print}
'
else
log INFO "No OSMTool cron block configured"
fi
}
remove_cron() {
local current tmp
current="$(existing_crontab)"
tmp="$(mktemp)"
printf '%s\n' "$current" | strip_osmtool_block > "$tmp"
crontab "$tmp"
rm -f "$tmp"
log INFO "OSMTool cron block removed"
}
WORKDIR="$DEFAULT_WORKDIR"
ACTION=""
PROFILE="grid-sim"
BACKUP_SCHEDULE="0 3 * * *"
RESTART_SCHEDULE="0 5 * * 1"
CHECK_SCHEDULE="*/15 * * * *"
REPORT_SCHEDULE="30 6 * * *"
SMOKE_SCHEDULE="45 6 * * *"
DB_USER="root"
DB_PASS=""
DB_NAME="opensim"
REGION="sim1"
SESSION_NAME="sim1"
COMPRESS="true"
while [[ $# -gt 0 ]]; do
case "$1" in
--workdir) WORKDIR="$2"; shift 2 ;;
--profile) PROFILE="$2"; shift 2 ;;
--action) ACTION="$2"; shift 2 ;;
--backup-schedule) BACKUP_SCHEDULE="$2"; shift 2 ;;
--restart-schedule) RESTART_SCHEDULE="$2"; shift 2 ;;
--check-schedule) CHECK_SCHEDULE="$2"; shift 2 ;;
--report-schedule) REPORT_SCHEDULE="$2"; shift 2 ;;
--smoke-schedule) SMOKE_SCHEDULE="$2"; shift 2 ;;
--db-user) DB_USER="$2"; shift 2 ;;
--db-pass) DB_PASS="$2"; shift 2 ;;
--db-name) DB_NAME="$2"; shift 2 ;;
--region) REGION="$2"; shift 2 ;;
--session) SESSION_NAME="$2"; shift 2 ;;
--compress) COMPRESS="$2"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) die "Unknown option: $1" ;;
esac
done
[[ -n "$ACTION" ]] || die "Missing --action"
validate_profile "$PROFILE"
need_crontab
case "$ACTION" in
install|list|remove) ;;
*) die "Unsupported action: $ACTION" ;;
esac
case "$COMPRESS" in
true|false) ;;
*) die "--compress must be true or false" ;;
esac
case "$ACTION" in
install) install_cron ;;
list) list_cron ;;
remove) remove_cron ;;
esac
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
# shellcheck source=/dev/null
source "$SCRIPT_DIR/osmtool_core.sh"
usage() {
cat <<'EOF'
Usage:
osmtool_cron.sh [--workdir <path>] --action <install|list|remove>
[--backup-schedule "<cron>"] [--restart-schedule "<cron>"] [--check-schedule "<cron>"] [--report-schedule "<cron>"] [--smoke-schedule "<cron>"]
[--db-user <user>] [--db-pass <pass>] [--db-name <name>]
[--region <name>] [--session <screen-name>] [--compress <true|false>]
Examples:
osmtool_cron.sh --action list
osmtool_cron.sh --action install --backup-schedule "0 3 * * *" --db-user root --db-pass secret --db-name opensim --region sim1
osmtool_cron.sh --action remove
EOF
print_usage_common
}
need_crontab() {
need_cmd crontab
}
quote_sq() {
local s="$1"
s="${s//\'/\'\"\'\"\'}"
printf "'%s'" "$s"
}
build_backup_cmd() {
local cmd
cmd="bash $ROOT_DIR/osmtool_main.sh --module backup --profile $PROFILE --workdir $WORKDIR --action full-backup --db-user $DB_USER --db-name $DB_NAME --region $REGION --session $SESSION_NAME --compress $COMPRESS"
if [[ -n "$DB_PASS" ]]; then
cmd+=" --db-pass $DB_PASS"
fi
printf '%s' "$cmd"
}
build_restart_cmd() {
printf '%s' "bash $ROOT_DIR/osmtool_main.sh --module startstop --profile $PROFILE --workdir $WORKDIR --target grid --action restart"
}
build_check_cmd() {
printf '%s' "bash $ROOT_DIR/osmtool_main.sh --module install --profile $PROFILE --workdir $WORKDIR --action server-check"
}
build_report_cmd() {
local cmd
cmd="bash $ROOT_DIR/osmtool_main.sh --module report --profile $PROFILE --workdir $WORKDIR --action generate --db-user $DB_USER --db-name $DB_NAME"
if [[ -n "$DB_PASS" ]]; then
cmd+=" --db-pass $DB_PASS"
fi
printf '%s' "$cmd"
}
build_smoke_cmd() {
printf '%s' "bash $ROOT_DIR/osmtool_main.sh --module smoke --profile $PROFILE --workdir $WORKDIR --action run"
}
cron_block_start="# OSMTOOL_CRON_BEGIN"
cron_block_end="# OSMTOOL_CRON_END"
emit_cron_block() {
local backup_cmd restart_cmd check_cmd report_cmd smoke_cmd
backup_cmd="$(build_backup_cmd)"
restart_cmd="$(build_restart_cmd)"
check_cmd="$(build_check_cmd)"
report_cmd="$(build_report_cmd)"
smoke_cmd="$(build_smoke_cmd)"
echo "$cron_block_start"
echo "SHELL=/bin/bash"
echo "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
echo "$BACKUP_SCHEDULE $backup_cmd >> $ROOT_DIR/osmtool_backup.log 2>&1"
echo "$RESTART_SCHEDULE $restart_cmd >> $ROOT_DIR/osmtool_backup.log 2>&1"
echo "$CHECK_SCHEDULE $check_cmd >> $ROOT_DIR/osmtool_backup.log 2>&1"
echo "$REPORT_SCHEDULE $report_cmd >> $ROOT_DIR/osmtool_backup.log 2>&1"
echo "$SMOKE_SCHEDULE $smoke_cmd >> $ROOT_DIR/osmtool_backup.log 2>&1"
echo "$cron_block_end"
}
existing_crontab() {
crontab -l 2>/dev/null || true
}
strip_osmtool_block() {
awk -v start="$cron_block_start" -v end="$cron_block_end" '
$0 == start {inblock=1; next}
$0 == end {inblock=0; next}
!inblock {print}
'
}
install_cron() {
local current tmp
[[ -n "$DB_USER" && -n "$DB_NAME" ]] || die "install cron requires --db-user and --db-name"
current="$(existing_crontab)"
tmp="$(mktemp)"
printf '%s\n' "$current" | strip_osmtool_block > "$tmp"
if [[ -s "$tmp" ]]; then
echo >> "$tmp"
fi
emit_cron_block >> "$tmp"
crontab "$tmp"
rm -f "$tmp"
log INFO "OSMTool cron jobs installed/updated"
}
list_cron() {
local current
current="$(existing_crontab)"
if printf '%s\n' "$current" | grep -q "^$cron_block_start$"; then
printf '%s\n' "$current" | awk -v start="$cron_block_start" -v end="$cron_block_end" '
$0 == start {inblock=1; print; next}
$0 == end {print; inblock=0; next}
inblock {print}
'
else
log INFO "No OSMTool cron block configured"
fi
}
remove_cron() {
local current tmp
current="$(existing_crontab)"
tmp="$(mktemp)"
printf '%s\n' "$current" | strip_osmtool_block > "$tmp"
crontab "$tmp"
rm -f "$tmp"
log INFO "OSMTool cron block removed"
}
WORKDIR="$DEFAULT_WORKDIR"
ACTION=""
PROFILE="grid-sim"
BACKUP_SCHEDULE="0 3 * * *"
RESTART_SCHEDULE="0 5 * * 1"
CHECK_SCHEDULE="*/15 * * * *"
REPORT_SCHEDULE="30 6 * * *"
SMOKE_SCHEDULE="45 6 * * *"
DB_USER="root"
DB_PASS=""
DB_NAME="opensim"
REGION="sim1"
SESSION_NAME="sim1"
COMPRESS="true"
while [[ $# -gt 0 ]]; do
case "$1" in
--workdir) WORKDIR="$2"; shift 2 ;;
--profile) PROFILE="$2"; shift 2 ;;
--action) ACTION="$2"; shift 2 ;;
--backup-schedule) BACKUP_SCHEDULE="$2"; shift 2 ;;
--restart-schedule) RESTART_SCHEDULE="$2"; shift 2 ;;
--check-schedule) CHECK_SCHEDULE="$2"; shift 2 ;;
--report-schedule) REPORT_SCHEDULE="$2"; shift 2 ;;
--smoke-schedule) SMOKE_SCHEDULE="$2"; shift 2 ;;
--db-user) DB_USER="$2"; shift 2 ;;
--db-pass) DB_PASS="$2"; shift 2 ;;
--db-name) DB_NAME="$2"; shift 2 ;;
--region) REGION="$2"; shift 2 ;;
--session) SESSION_NAME="$2"; shift 2 ;;
--compress) COMPRESS="$2"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) die "Unknown option: $1" ;;
esac
done
[[ -n "$ACTION" ]] || die "Missing --action"
validate_profile "$PROFILE"
need_crontab
case "$ACTION" in
install|list|remove) ;;
*) die "Unsupported action: $ACTION" ;;
esac
case "$COMPRESS" in
true|false) ;;
*) die "--compress must be true or false" ;;
esac
case "$ACTION" in
install) install_cron ;;
list) list_cron ;;
remove) remove_cron ;;
esac
+170 -170
View File
@@ -1,170 +1,170 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=/dev/null
source "$SCRIPT_DIR/osmtool_core.sh"
usage() {
cat <<'EOF'
Usage:
osmtool_data.sh [--workdir <path>] --action <db-backup|oar-backup|full-backup>
[--db-user <user>] [--db-pass <pass>] [--db-name <name>]
[--region <name>] [--session <screen-name>] [--compress <true|false>]
Examples:
osmtool_data.sh --action db-backup --db-user opensim --db-pass secret --db-name robust
osmtool_data.sh --action oar-backup --region sim1 --session sim1 --workdir /opt
EOF
print_usage_common
}
timestamp() {
date '+%Y%m%d_%H%M%S'
}
backup_dir() {
printf '%s' "$WORKDIR/backup"
}
ensure_backup_dir() {
local dir
dir="$(backup_dir)"
if mkdir -p "$dir" 2>/dev/null; then
return 0
fi
sudo mkdir -p "$dir"
sudo chown "$(id -u):$(id -g)" "$dir"
}
compress_if_enabled() {
local file_path="$1"
if [[ "$COMPRESS" != "true" ]]; then
printf '%s' "$file_path"
return 0
fi
need_cmd gzip
gzip -f "$file_path"
printf '%s.gz' "$file_path"
}
resolve_default_session() {
if [[ -n "$SESSION_NAME" ]]; then
printf '%s' "$SESSION_NAME"
return 0
fi
if [[ -n "$REGION" ]]; then
printf '%s' "$REGION"
return 0
fi
printf 'sim1'
}
screen_session_exists() {
local name="$1"
screen -list 2>/dev/null | grep -qE "\\.${name}[[:space:]]"
}
send_to_screen() {
local session_name="$1"
local command_text="$2"
screen -S "$session_name" -p 0 -X stuff "${command_text}^M"
}
db_backup_mysql() {
local out
need_cmd mysqldump
[[ -n "$DB_USER" && -n "$DB_PASS" && -n "$DB_NAME" ]] || die "db-backup(mysql) requires --db-user --db-pass --db-name"
ensure_backup_dir
out="$(backup_dir)/robust_${DB_NAME}_$(timestamp).sql"
log INFO "Creating MySQL backup: $out"
mysqldump -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" > "$out"
out="$(compress_if_enabled "$out")"
log INFO "DB backup created: $out"
}
db_backup() {
db_backup_mysql
}
oar_backup() {
local session_name out command_text
[[ -n "$REGION" ]] || die "oar-backup requires --region"
session_name="$(resolve_default_session)"
ensure_backup_dir
out="$(backup_dir)/${REGION}_$(timestamp).oar"
if ! screen_session_exists "$session_name"; then
die "Screen session not running: $session_name"
fi
# OpenSim console command to export current region as OAR.
command_text="save oar $out"
log INFO "Sending OAR export command to screen session '$session_name': $command_text"
send_to_screen "$session_name" "$command_text"
log INFO "OAR export command sent. Validate completion in the session log/output."
}
full_backup() {
db_backup
if [[ -n "$REGION" ]]; then
oar_backup
else
log INFO "No --region provided. DB backup only in full-backup mode."
fi
}
WORKDIR="$DEFAULT_WORKDIR"
ACTION=""
DB_USER=""
DB_PASS=""
DB_NAME=""
REGION=""
SESSION_NAME=""
COMPRESS="false"
PROFILE="grid-sim"
while [[ $# -gt 0 ]]; do
case "$1" in
--workdir) WORKDIR="$2"; shift 2 ;;
--profile) PROFILE="$2"; shift 2 ;;
--action) ACTION="$2"; shift 2 ;;
--db-user) DB_USER="$2"; shift 2 ;;
--db-pass) DB_PASS="$2"; shift 2 ;;
--db-name) DB_NAME="$2"; shift 2 ;;
--region) REGION="$2"; shift 2 ;;
--session) SESSION_NAME="$2"; shift 2 ;;
--compress) COMPRESS="$2"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) die "Unknown option: $1" ;;
esac
done
[[ -n "$ACTION" ]] || die "Missing --action"
validate_profile "$PROFILE"
ensure_profile_action_allowed backup "$PROFILE" "$ACTION"
case "$COMPRESS" in
true|false) ;;
*) die "--compress must be true or false" ;;
esac
log INFO "Using profile: $PROFILE"
case "$ACTION" in
db-backup) db_backup ;;
oar-backup) oar_backup ;;
full-backup) full_backup ;;
*) die "Unsupported action: $ACTION" ;;
esac
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=/dev/null
source "$SCRIPT_DIR/osmtool_core.sh"
usage() {
cat <<'EOF'
Usage:
osmtool_data.sh [--workdir <path>] --action <db-backup|oar-backup|full-backup>
[--db-user <user>] [--db-pass <pass>] [--db-name <name>]
[--region <name>] [--session <screen-name>] [--compress <true|false>]
Examples:
osmtool_data.sh --action db-backup --db-user opensim --db-pass secret --db-name robust
osmtool_data.sh --action oar-backup --region sim1 --session sim1 --workdir /opt
EOF
print_usage_common
}
timestamp() {
date '+%Y%m%d_%H%M%S'
}
backup_dir() {
printf '%s' "$WORKDIR/backup"
}
ensure_backup_dir() {
local dir
dir="$(backup_dir)"
if mkdir -p "$dir" 2>/dev/null; then
return 0
fi
sudo mkdir -p "$dir"
sudo chown "$(id -u):$(id -g)" "$dir"
}
compress_if_enabled() {
local file_path="$1"
if [[ "$COMPRESS" != "true" ]]; then
printf '%s' "$file_path"
return 0
fi
need_cmd gzip
gzip -f "$file_path"
printf '%s.gz' "$file_path"
}
resolve_default_session() {
if [[ -n "$SESSION_NAME" ]]; then
printf '%s' "$SESSION_NAME"
return 0
fi
if [[ -n "$REGION" ]]; then
printf '%s' "$REGION"
return 0
fi
printf 'sim1'
}
screen_session_exists() {
local name="$1"
screen -list 2>/dev/null | grep -qE "\\.${name}[[:space:]]"
}
send_to_screen() {
local session_name="$1"
local command_text="$2"
screen -S "$session_name" -p 0 -X stuff "${command_text}^M"
}
db_backup_mysql() {
local out
need_cmd mysqldump
[[ -n "$DB_USER" && -n "$DB_PASS" && -n "$DB_NAME" ]] || die "db-backup(mysql) requires --db-user --db-pass --db-name"
ensure_backup_dir
out="$(backup_dir)/robust_${DB_NAME}_$(timestamp).sql"
log INFO "Creating MySQL backup: $out"
mysqldump -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" > "$out"
out="$(compress_if_enabled "$out")"
log INFO "DB backup created: $out"
}
db_backup() {
db_backup_mysql
}
oar_backup() {
local session_name out command_text
[[ -n "$REGION" ]] || die "oar-backup requires --region"
session_name="$(resolve_default_session)"
ensure_backup_dir
out="$(backup_dir)/${REGION}_$(timestamp).oar"
if ! screen_session_exists "$session_name"; then
die "Screen session not running: $session_name"
fi
# OpenSim console command to export current region as OAR.
command_text="save oar $out"
log INFO "Sending OAR export command to screen session '$session_name': $command_text"
send_to_screen "$session_name" "$command_text"
log INFO "OAR export command sent. Validate completion in the session log/output."
}
full_backup() {
db_backup
if [[ -n "$REGION" ]]; then
oar_backup
else
log INFO "No --region provided. DB backup only in full-backup mode."
fi
}
WORKDIR="$DEFAULT_WORKDIR"
ACTION=""
DB_USER=""
DB_PASS=""
DB_NAME=""
REGION=""
SESSION_NAME=""
COMPRESS="false"
PROFILE="grid-sim"
while [[ $# -gt 0 ]]; do
case "$1" in
--workdir) WORKDIR="$2"; shift 2 ;;
--profile) PROFILE="$2"; shift 2 ;;
--action) ACTION="$2"; shift 2 ;;
--db-user) DB_USER="$2"; shift 2 ;;
--db-pass) DB_PASS="$2"; shift 2 ;;
--db-name) DB_NAME="$2"; shift 2 ;;
--region) REGION="$2"; shift 2 ;;
--session) SESSION_NAME="$2"; shift 2 ;;
--compress) COMPRESS="$2"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) die "Unknown option: $1" ;;
esac
done
[[ -n "$ACTION" ]] || die "Missing --action"
validate_profile "$PROFILE"
ensure_profile_action_allowed backup "$PROFILE" "$ACTION"
case "$COMPRESS" in
true|false) ;;
*) die "--compress must be true or false" ;;
esac
log INFO "Using profile: $PROFILE"
case "$ACTION" in
db-backup) db_backup ;;
oar-backup) oar_backup ;;
full-backup) full_backup ;;
*) die "Unsupported action: $ACTION" ;;
esac
+268 -268
View File
@@ -1,268 +1,268 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
# shellcheck source=/dev/null
source "$SCRIPT_DIR/osmtool_core.sh"
usage() {
cat <<'EOF'
Usage:
osmtool_health.sh [--workdir <path>] --action <run>
[--expected-screens <csv|none>] [--ports <csv|none>] [--db-user <user>] [--db-pass <pass>] [--db-name <name>]
[--log-file <path>] [--warning-threshold <n>]
Examples:
osmtool_health.sh --action run --workdir /opt
osmtool_health.sh --action run --workdir /opt --expected-screens robustserver,sim1 --ports 9000,8002,8088
EOF
print_usage_common
}
split_csv() {
local csv="$1"
local token
local IFS=','
read -r -a _TOKENS <<< "$csv"
for token in "${_TOKENS[@]}"; do
token="${token## }"
token="${token%% }"
[[ -n "$token" ]] && printf '%s\n' "$token"
done
}
report_ok() {
log INFO "[OK] $1"
}
report_warn() {
log INFO "[WARN] $1"
}
report_err() {
log ERROR "[FAIL] $1"
}
check_screens() {
local fail_count=0
local screen_name
if [[ -z "$EXPECTED_SCREENS" ]]; then
report_warn "Screen check skipped (no expected screens configured)"
return 0
fi
while IFS= read -r screen_name; do
[[ -n "$screen_name" ]] || continue
if screen -list 2>/dev/null | grep -qE "\\.${screen_name}[[:space:]]"; then
report_ok "Screen session running: $screen_name"
else
report_err "Screen session missing: $screen_name"
fail_count=$((fail_count + 1))
fi
done < <(split_csv "$EXPECTED_SCREENS")
return "$fail_count"
}
check_ports() {
local fail_count=0
local port
local cmd_ss=0
if [[ -z "$PORTS" ]]; then
report_warn "Port check skipped (no ports configured)"
return 0
fi
if command -v ss >/dev/null 2>&1; then
cmd_ss=1
elif ! command -v netstat >/dev/null 2>&1; then
report_warn "Port check skipped (neither ss nor netstat available)"
return 0
fi
while IFS= read -r port; do
[[ -n "$port" ]] || continue
if [[ "$cmd_ss" -eq 1 ]]; then
if ss -ltnH | awk '{print $4}' | grep -qE "[:.]${port}$"; then
report_ok "Port listening: $port"
else
report_err "Port not listening: $port"
fail_count=$((fail_count + 1))
fi
else
if netstat -ltn 2>/dev/null | awk '{print $4}' | grep -qE "[:.]${port}$"; then
report_ok "Port listening: $port"
else
report_err "Port not listening: $port"
fail_count=$((fail_count + 1))
fi
fi
done < <(split_csv "$PORTS")
return "$fail_count"
}
check_database() {
local fail_count=0
if [[ -z "$DB_USER" || -z "$DB_NAME" ]]; then
report_warn "Database check skipped (missing --db-user/--db-name)"
return 0
fi
if ! command -v mariadb >/dev/null 2>&1; then
report_err "Database check failed: mariadb client missing"
return 1
fi
if [[ -n "$DB_PASS" ]]; then
if mariadb -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "SELECT 1" >/dev/null 2>&1; then
report_ok "Database reachable: $DB_NAME"
else
report_err "Database not reachable: $DB_NAME"
fail_count=$((fail_count + 1))
fi
else
if mariadb -u"$DB_USER" "$DB_NAME" -e "SELECT 1" >/dev/null 2>&1; then
report_ok "Database reachable: $DB_NAME"
else
report_err "Database not reachable: $DB_NAME"
fail_count=$((fail_count + 1))
fi
fi
return "$fail_count"
}
count_log_warnings() {
local file="$1"
grep -Eic 'error|warn|exception|fatal' "$file" 2>/dev/null || true
}
check_logs() {
local warn_count total=0
local default_logs=()
if [[ -n "$LOG_FILE_PATH" ]]; then
default_logs+=("$LOG_FILE_PATH")
else
default_logs+=("$ROOT_DIR/osmtool_backup.log")
default_logs+=("$WORKDIR/robust/bin/OpenSim.log")
fi
for logf in "${default_logs[@]}"; do
if [[ -f "$logf" ]]; then
warn_count="$(count_log_warnings "$logf")"
report_ok "Log scan: $logf -> $warn_count matches"
total=$((total + warn_count))
else
report_warn "Log file not found, skipped: $logf"
fi
done
if [[ "$total" -gt "$WARNING_THRESHOLD" ]]; then
report_err "Log warning threshold exceeded: $total > $WARNING_THRESHOLD"
return 1
fi
report_ok "Log warning threshold OK: $total <= $WARNING_THRESHOLD"
return 0
}
default_screens_for_profile() {
case "$1" in
grid-sim) echo "robustserver,sim1" ;;
robust) echo "robustserver" ;;
standalone) echo "standalone" ;;
esac
}
default_ports_for_profile() {
case "$1" in
grid-sim) echo "8002,9000,9001,8088" ;;
robust) echo "8002,9000,9001" ;;
standalone) echo "9000" ;;
esac
}
run_health() {
local fails=0
log INFO "Running health checks for profile: $PROFILE"
log INFO "Using workdir: $WORKDIR"
if ! check_screens; then
fails=$((fails + 1))
fi
if ! check_ports; then
fails=$((fails + 1))
fi
if ! check_database; then
fails=$((fails + 1))
fi
if ! check_logs; then
fails=$((fails + 1))
fi
if [[ "$fails" -eq 0 ]]; then
report_ok "Healthcheck PASSED"
return 0
fi
report_err "Healthcheck FAILED with $fails failing check group(s)"
return 1
}
WORKDIR="$DEFAULT_WORKDIR"
ACTION=""
PROFILE="grid-sim"
EXPECTED_SCREENS=""
PORTS=""
DB_USER=""
DB_PASS=""
DB_NAME=""
LOG_FILE_PATH=""
WARNING_THRESHOLD=50
while [[ $# -gt 0 ]]; do
case "$1" in
--workdir) WORKDIR="$2"; shift 2 ;;
--profile) PROFILE="$2"; shift 2 ;;
--action) ACTION="$2"; shift 2 ;;
--expected-screens) EXPECTED_SCREENS="$2"; shift 2 ;;
--ports) PORTS="$2"; shift 2 ;;
--db-user) DB_USER="$2"; shift 2 ;;
--db-pass) DB_PASS="$2"; shift 2 ;;
--db-name) DB_NAME="$2"; shift 2 ;;
--log-file) LOG_FILE_PATH="$2"; shift 2 ;;
--warning-threshold) WARNING_THRESHOLD="$2"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) die "Unknown option: $1" ;;
esac
done
[[ -n "$ACTION" ]] || die "Missing --action"
validate_profile "$PROFILE"
ensure_profile_action_allowed health "$PROFILE" "$ACTION"
if [[ -z "$EXPECTED_SCREENS" ]]; then
EXPECTED_SCREENS="$(default_screens_for_profile "$PROFILE")"
elif [[ "$EXPECTED_SCREENS" == "none" ]]; then
EXPECTED_SCREENS=""
fi
if [[ -z "$PORTS" ]]; then
PORTS="$(default_ports_for_profile "$PROFILE")"
elif [[ "$PORTS" == "none" ]]; then
PORTS=""
fi
case "$ACTION" in
run) run_health ;;
*) die "Unsupported action: $ACTION" ;;
esac
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
# shellcheck source=/dev/null
source "$SCRIPT_DIR/osmtool_core.sh"
usage() {
cat <<'EOF'
Usage:
osmtool_health.sh [--workdir <path>] --action <run>
[--expected-screens <csv|none>] [--ports <csv|none>] [--db-user <user>] [--db-pass <pass>] [--db-name <name>]
[--log-file <path>] [--warning-threshold <n>]
Examples:
osmtool_health.sh --action run --workdir /opt
osmtool_health.sh --action run --workdir /opt --expected-screens robustserver,sim1 --ports 9000,8002,8088
EOF
print_usage_common
}
split_csv() {
local csv="$1"
local token
local IFS=','
read -r -a _TOKENS <<< "$csv"
for token in "${_TOKENS[@]}"; do
token="${token## }"
token="${token%% }"
[[ -n "$token" ]] && printf '%s\n' "$token"
done
}
report_ok() {
log INFO "[OK] $1"
}
report_warn() {
log INFO "[WARN] $1"
}
report_err() {
log ERROR "[FAIL] $1"
}
check_screens() {
local fail_count=0
local screen_name
if [[ -z "$EXPECTED_SCREENS" ]]; then
report_warn "Screen check skipped (no expected screens configured)"
return 0
fi
while IFS= read -r screen_name; do
[[ -n "$screen_name" ]] || continue
if screen -list 2>/dev/null | grep -qE "\\.${screen_name}[[:space:]]"; then
report_ok "Screen session running: $screen_name"
else
report_err "Screen session missing: $screen_name"
fail_count=$((fail_count + 1))
fi
done < <(split_csv "$EXPECTED_SCREENS")
return "$fail_count"
}
check_ports() {
local fail_count=0
local port
local cmd_ss=0
if [[ -z "$PORTS" ]]; then
report_warn "Port check skipped (no ports configured)"
return 0
fi
if command -v ss >/dev/null 2>&1; then
cmd_ss=1
elif ! command -v netstat >/dev/null 2>&1; then
report_warn "Port check skipped (neither ss nor netstat available)"
return 0
fi
while IFS= read -r port; do
[[ -n "$port" ]] || continue
if [[ "$cmd_ss" -eq 1 ]]; then
if ss -ltnH | awk '{print $4}' | grep -qE "[:.]${port}$"; then
report_ok "Port listening: $port"
else
report_err "Port not listening: $port"
fail_count=$((fail_count + 1))
fi
else
if netstat -ltn 2>/dev/null | awk '{print $4}' | grep -qE "[:.]${port}$"; then
report_ok "Port listening: $port"
else
report_err "Port not listening: $port"
fail_count=$((fail_count + 1))
fi
fi
done < <(split_csv "$PORTS")
return "$fail_count"
}
check_database() {
local fail_count=0
if [[ -z "$DB_USER" || -z "$DB_NAME" ]]; then
report_warn "Database check skipped (missing --db-user/--db-name)"
return 0
fi
if ! command -v mariadb >/dev/null 2>&1; then
report_err "Database check failed: mariadb client missing"
return 1
fi
if [[ -n "$DB_PASS" ]]; then
if mariadb -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "SELECT 1" >/dev/null 2>&1; then
report_ok "Database reachable: $DB_NAME"
else
report_err "Database not reachable: $DB_NAME"
fail_count=$((fail_count + 1))
fi
else
if mariadb -u"$DB_USER" "$DB_NAME" -e "SELECT 1" >/dev/null 2>&1; then
report_ok "Database reachable: $DB_NAME"
else
report_err "Database not reachable: $DB_NAME"
fail_count=$((fail_count + 1))
fi
fi
return "$fail_count"
}
count_log_warnings() {
local file="$1"
grep -Eic 'error|warn|exception|fatal' "$file" 2>/dev/null || true
}
check_logs() {
local warn_count total=0
local default_logs=()
if [[ -n "$LOG_FILE_PATH" ]]; then
default_logs+=("$LOG_FILE_PATH")
else
default_logs+=("$ROOT_DIR/osmtool_backup.log")
default_logs+=("$WORKDIR/robust/bin/OpenSim.log")
fi
for logf in "${default_logs[@]}"; do
if [[ -f "$logf" ]]; then
warn_count="$(count_log_warnings "$logf")"
report_ok "Log scan: $logf -> $warn_count matches"
total=$((total + warn_count))
else
report_warn "Log file not found, skipped: $logf"
fi
done
if [[ "$total" -gt "$WARNING_THRESHOLD" ]]; then
report_err "Log warning threshold exceeded: $total > $WARNING_THRESHOLD"
return 1
fi
report_ok "Log warning threshold OK: $total <= $WARNING_THRESHOLD"
return 0
}
default_screens_for_profile() {
case "$1" in
grid-sim) echo "robustserver,sim1" ;;
robust) echo "robustserver" ;;
standalone) echo "standalone" ;;
esac
}
default_ports_for_profile() {
case "$1" in
grid-sim) echo "8002,9000,9001,8088" ;;
robust) echo "8002,9000,9001" ;;
standalone) echo "9000" ;;
esac
}
run_health() {
local fails=0
log INFO "Running health checks for profile: $PROFILE"
log INFO "Using workdir: $WORKDIR"
if ! check_screens; then
fails=$((fails + 1))
fi
if ! check_ports; then
fails=$((fails + 1))
fi
if ! check_database; then
fails=$((fails + 1))
fi
if ! check_logs; then
fails=$((fails + 1))
fi
if [[ "$fails" -eq 0 ]]; then
report_ok "Healthcheck PASSED"
return 0
fi
report_err "Healthcheck FAILED with $fails failing check group(s)"
return 1
}
WORKDIR="$DEFAULT_WORKDIR"
ACTION=""
PROFILE="grid-sim"
EXPECTED_SCREENS=""
PORTS=""
DB_USER=""
DB_PASS=""
DB_NAME=""
LOG_FILE_PATH=""
WARNING_THRESHOLD=50
while [[ $# -gt 0 ]]; do
case "$1" in
--workdir) WORKDIR="$2"; shift 2 ;;
--profile) PROFILE="$2"; shift 2 ;;
--action) ACTION="$2"; shift 2 ;;
--expected-screens) EXPECTED_SCREENS="$2"; shift 2 ;;
--ports) PORTS="$2"; shift 2 ;;
--db-user) DB_USER="$2"; shift 2 ;;
--db-pass) DB_PASS="$2"; shift 2 ;;
--db-name) DB_NAME="$2"; shift 2 ;;
--log-file) LOG_FILE_PATH="$2"; shift 2 ;;
--warning-threshold) WARNING_THRESHOLD="$2"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) die "Unknown option: $1" ;;
esac
done
[[ -n "$ACTION" ]] || die "Missing --action"
validate_profile "$PROFILE"
ensure_profile_action_allowed health "$PROFILE" "$ACTION"
if [[ -z "$EXPECTED_SCREENS" ]]; then
EXPECTED_SCREENS="$(default_screens_for_profile "$PROFILE")"
elif [[ "$EXPECTED_SCREENS" == "none" ]]; then
EXPECTED_SCREENS=""
fi
if [[ -z "$PORTS" ]]; then
PORTS="$(default_ports_for_profile "$PROFILE")"
elif [[ "$PORTS" == "none" ]]; then
PORTS=""
fi
case "$ACTION" in
run) run_health ;;
*) die "Unsupported action: $ACTION" ;;
esac
+1191 -1191
View File
File diff suppressed because it is too large Load Diff
+292 -292
View File
@@ -1,293 +1,293 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
# shellcheck source=/dev/null
source "$SCRIPT_DIR/osmtool_core.sh"
usage() {
cat <<'EOF'
Usage:
osmtool_report.sh [--workdir <path>] --action <generate>
[--output <file>] [--expected-screens <csv|none>] [--ports <csv|none>]
[--db-user <user>] [--db-pass <pass>] [--db-name <name>] [--log-file <path>]
Examples:
osmtool_report.sh --action generate --workdir /opt --db-user opensim --db-pass secret --db-name robust
osmtool_report.sh --action generate --workdir /opt --output /opt/reports/manual_report.txt
EOF
print_usage_common
}
timestamp_compact() {
date '+%Y%m%d_%H%M%S'
}
timestamp_iso() {
date '+%Y-%m-%d %H:%M:%S'
}
split_csv() {
local csv="$1"
local token
local IFS=','
read -r -a _TOKENS <<< "$csv"
for token in "${_TOKENS[@]}"; do
token="${token## }"
token="${token%% }"
[[ -n "$token" ]] && printf '%s\n' "$token"
done
}
reports_dir() {
printf '%s' "$WORKDIR/reports"
}
ensure_reports_dir() {
local dir
dir="$(reports_dir)"
if mkdir -p "$dir" 2>/dev/null; then
return 0
fi
sudo mkdir -p "$dir"
sudo chown "$(id -u):$(id -g)" "$dir"
}
latest_file() {
local dir="$1"
local pattern="$2"
[[ -d "$dir" ]] || return 0
find "$dir" -maxdepth 1 -type f -name "$pattern" -printf '%T@ %p\n' 2>/dev/null | \
sort -rn | head -1 | cut -d' ' -f2-
}
format_file_age_hours() {
local path="$1"
local now ts age
[[ -f "$path" ]] || {
printf 'n/a'
return 0
}
now="$(date +%s)"
ts="$(stat -c %Y "$path" 2>/dev/null || echo 0)"
if [[ "$ts" -le 0 ]]; then
printf 'n/a'
return 0
fi
age=$(( (now - ts) / 3600 ))
printf '%sh' "$age"
}
screen_status_lines() {
local screen_name
if [[ -z "$EXPECTED_SCREENS" ]]; then
printf 'screen: skipped\n'
return 0
fi
while IFS= read -r screen_name; do
[[ -n "$screen_name" ]] || continue
if screen -list 2>/dev/null | grep -qE "\\.${screen_name}[[:space:]]"; then
printf 'screen:%s=up\n' "$screen_name"
else
printf 'screen:%s=down\n' "$screen_name"
fi
done < <(split_csv "$EXPECTED_SCREENS")
}
port_status_lines() {
local port
local use_ss=0
if [[ -z "$PORTS" ]]; then
printf 'port: skipped\n'
return 0
fi
if command -v ss >/dev/null 2>&1; then
use_ss=1
elif ! command -v netstat >/dev/null 2>&1; then
printf 'port: unavailable (no ss/netstat)\n'
return 0
fi
while IFS= read -r port; do
[[ -n "$port" ]] || continue
if [[ "$use_ss" -eq 1 ]]; then
if ss -ltnH | awk '{print $4}' | grep -qE "[:.]${port}$"; then
printf 'port:%s=listen\n' "$port"
else
printf 'port:%s=closed\n' "$port"
fi
else
if netstat -ltn 2>/dev/null | awk '{print $4}' | grep -qE "[:.]${port}$"; then
printf 'port:%s=listen\n' "$port"
else
printf 'port:%s=closed\n' "$port"
fi
fi
done < <(split_csv "$PORTS")
}
database_status() {
if [[ -z "$DB_USER" || -z "$DB_NAME" ]]; then
printf 'db: skipped\n'
return 0
fi
if ! command -v mariadb >/dev/null 2>&1; then
printf 'db:%s=client-missing\n' "$DB_NAME"
return 0
fi
if [[ -n "$DB_PASS" ]]; then
if mariadb -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "SELECT 1" >/dev/null 2>&1; then
printf 'db:%s=ok\n' "$DB_NAME"
else
printf 'db:%s=fail\n' "$DB_NAME"
fi
else
if mariadb -u"$DB_USER" "$DB_NAME" -e "SELECT 1" >/dev/null 2>&1; then
printf 'db:%s=ok\n' "$DB_NAME"
else
printf 'db:%s=fail\n' "$DB_NAME"
fi
fi
}
log_warning_count() {
local file="$1"
[[ -f "$file" ]] || {
printf 'n/a'
return 0
}
grep -Eic 'error|warn|exception|fatal' "$file" 2>/dev/null || printf '0'
}
default_screens_for_profile() {
case "$1" in
grid-sim) echo "robustserver,sim1" ;;
robust) echo "robustserver" ;;
standalone) echo "standalone" ;;
esac
}
default_ports_for_profile() {
case "$1" in
grid-sim) echo "8002,9000,9001,8088" ;;
robust) echo "8002,9000,9001" ;;
standalone) echo "9000" ;;
esac
}
generate_report() {
local out report_title log_target
local newest_sql newest_oar newest_rollback
ensure_reports_dir
if [[ -n "$OUTPUT_FILE" ]]; then
out="$OUTPUT_FILE"
else
out="$(reports_dir)/osm_report_$(timestamp_compact).txt"
fi
newest_sql="$(latest_file "$WORKDIR/backup" 'robust_*.sql*')"
newest_oar="$(latest_file "$WORKDIR/backup" '*.oar')"
newest_rollback="$(latest_file "$WORKDIR/rollback" '*.manifest')"
log_target="$LOG_FILE_PATH"
if [[ -z "$log_target" ]]; then
log_target="$ROOT_DIR/osmtool_backup.log"
fi
report_title="OSMTool Daily Status Report"
{
printf '%s\n' "$report_title"
printf 'generated_at: %s\n' "$(timestamp_iso)"
printf 'profile: %s\n' "$PROFILE"
printf 'workdir: %s\n' "$WORKDIR"
printf '\n'
printf '[runtime]\n'
screen_status_lines
port_status_lines
database_status
printf '\n'
printf '[backup]\n'
printf 'sql_latest: %s\n' "${newest_sql:-none}"
printf 'sql_age: %s\n' "$(format_file_age_hours "${newest_sql:-}")"
printf 'oar_latest: %s\n' "${newest_oar:-none}"
printf 'oar_age: %s\n' "$(format_file_age_hours "${newest_oar:-}")"
printf '\n'
printf '[rollback]\n'
printf 'latest_manifest: %s\n' "${newest_rollback:-none}"
printf 'manifest_age: %s\n' "$(format_file_age_hours "${newest_rollback:-}")"
printf '\n'
printf '[logs]\n'
printf 'file: %s\n' "$log_target"
printf 'warning_matches: %s\n' "$(log_warning_count "$log_target")"
} > "$out"
log INFO "Report generated: $out"
cat "$out"
}
WORKDIR="$DEFAULT_WORKDIR"
ACTION=""
PROFILE="grid-sim"
OUTPUT_FILE=""
EXPECTED_SCREENS=""
PORTS=""
DB_USER=""
DB_PASS=""
DB_NAME=""
LOG_FILE_PATH=""
while [[ $# -gt 0 ]]; do
case "$1" in
--workdir) WORKDIR="$2"; shift 2 ;;
--profile) PROFILE="$2"; shift 2 ;;
--action) ACTION="$2"; shift 2 ;;
--output) OUTPUT_FILE="$2"; shift 2 ;;
--expected-screens) EXPECTED_SCREENS="$2"; shift 2 ;;
--ports) PORTS="$2"; shift 2 ;;
--db-user) DB_USER="$2"; shift 2 ;;
--db-pass) DB_PASS="$2"; shift 2 ;;
--db-name) DB_NAME="$2"; shift 2 ;;
--log-file) LOG_FILE_PATH="$2"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) die "Unknown option: $1" ;;
esac
done
[[ -n "$ACTION" ]] || die "Missing --action"
validate_profile "$PROFILE"
ensure_profile_action_allowed report "$PROFILE" "$ACTION"
if [[ -z "$EXPECTED_SCREENS" ]]; then
EXPECTED_SCREENS="$(default_screens_for_profile "$PROFILE")"
elif [[ "$EXPECTED_SCREENS" == "none" ]]; then
EXPECTED_SCREENS=""
fi
if [[ -z "$PORTS" ]]; then
PORTS="$(default_ports_for_profile "$PROFILE")"
elif [[ "$PORTS" == "none" ]]; then
PORTS=""
fi
log INFO "Using profile: $PROFILE"
case "$ACTION" in
generate) generate_report ;;
*) die "Unsupported action: $ACTION" ;;
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
# shellcheck source=/dev/null
source "$SCRIPT_DIR/osmtool_core.sh"
usage() {
cat <<'EOF'
Usage:
osmtool_report.sh [--workdir <path>] --action <generate>
[--output <file>] [--expected-screens <csv|none>] [--ports <csv|none>]
[--db-user <user>] [--db-pass <pass>] [--db-name <name>] [--log-file <path>]
Examples:
osmtool_report.sh --action generate --workdir /opt --db-user opensim --db-pass secret --db-name robust
osmtool_report.sh --action generate --workdir /opt --output /opt/reports/manual_report.txt
EOF
print_usage_common
}
timestamp_compact() {
date '+%Y%m%d_%H%M%S'
}
timestamp_iso() {
date '+%Y-%m-%d %H:%M:%S'
}
split_csv() {
local csv="$1"
local token
local IFS=','
read -r -a _TOKENS <<< "$csv"
for token in "${_TOKENS[@]}"; do
token="${token## }"
token="${token%% }"
[[ -n "$token" ]] && printf '%s\n' "$token"
done
}
reports_dir() {
printf '%s' "$WORKDIR/reports"
}
ensure_reports_dir() {
local dir
dir="$(reports_dir)"
if mkdir -p "$dir" 2>/dev/null; then
return 0
fi
sudo mkdir -p "$dir"
sudo chown "$(id -u):$(id -g)" "$dir"
}
latest_file() {
local dir="$1"
local pattern="$2"
[[ -d "$dir" ]] || return 0
find "$dir" -maxdepth 1 -type f -name "$pattern" -printf '%T@ %p\n' 2>/dev/null | \
sort -rn | head -1 | cut -d' ' -f2-
}
format_file_age_hours() {
local path="$1"
local now ts age
[[ -f "$path" ]] || {
printf 'n/a'
return 0
}
now="$(date +%s)"
ts="$(stat -c %Y "$path" 2>/dev/null || echo 0)"
if [[ "$ts" -le 0 ]]; then
printf 'n/a'
return 0
fi
age=$(( (now - ts) / 3600 ))
printf '%sh' "$age"
}
screen_status_lines() {
local screen_name
if [[ -z "$EXPECTED_SCREENS" ]]; then
printf 'screen: skipped\n'
return 0
fi
while IFS= read -r screen_name; do
[[ -n "$screen_name" ]] || continue
if screen -list 2>/dev/null | grep -qE "\\.${screen_name}[[:space:]]"; then
printf 'screen:%s=up\n' "$screen_name"
else
printf 'screen:%s=down\n' "$screen_name"
fi
done < <(split_csv "$EXPECTED_SCREENS")
}
port_status_lines() {
local port
local use_ss=0
if [[ -z "$PORTS" ]]; then
printf 'port: skipped\n'
return 0
fi
if command -v ss >/dev/null 2>&1; then
use_ss=1
elif ! command -v netstat >/dev/null 2>&1; then
printf 'port: unavailable (no ss/netstat)\n'
return 0
fi
while IFS= read -r port; do
[[ -n "$port" ]] || continue
if [[ "$use_ss" -eq 1 ]]; then
if ss -ltnH | awk '{print $4}' | grep -qE "[:.]${port}$"; then
printf 'port:%s=listen\n' "$port"
else
printf 'port:%s=closed\n' "$port"
fi
else
if netstat -ltn 2>/dev/null | awk '{print $4}' | grep -qE "[:.]${port}$"; then
printf 'port:%s=listen\n' "$port"
else
printf 'port:%s=closed\n' "$port"
fi
fi
done < <(split_csv "$PORTS")
}
database_status() {
if [[ -z "$DB_USER" || -z "$DB_NAME" ]]; then
printf 'db: skipped\n'
return 0
fi
if ! command -v mariadb >/dev/null 2>&1; then
printf 'db:%s=client-missing\n' "$DB_NAME"
return 0
fi
if [[ -n "$DB_PASS" ]]; then
if mariadb -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "SELECT 1" >/dev/null 2>&1; then
printf 'db:%s=ok\n' "$DB_NAME"
else
printf 'db:%s=fail\n' "$DB_NAME"
fi
else
if mariadb -u"$DB_USER" "$DB_NAME" -e "SELECT 1" >/dev/null 2>&1; then
printf 'db:%s=ok\n' "$DB_NAME"
else
printf 'db:%s=fail\n' "$DB_NAME"
fi
fi
}
log_warning_count() {
local file="$1"
[[ -f "$file" ]] || {
printf 'n/a'
return 0
}
grep -Eic 'error|warn|exception|fatal' "$file" 2>/dev/null || printf '0'
}
default_screens_for_profile() {
case "$1" in
grid-sim) echo "robustserver,sim1" ;;
robust) echo "robustserver" ;;
standalone) echo "standalone" ;;
esac
}
default_ports_for_profile() {
case "$1" in
grid-sim) echo "8002,9000,9001,8088" ;;
robust) echo "8002,9000,9001" ;;
standalone) echo "9000" ;;
esac
}
generate_report() {
local out report_title log_target
local newest_sql newest_oar newest_rollback
ensure_reports_dir
if [[ -n "$OUTPUT_FILE" ]]; then
out="$OUTPUT_FILE"
else
out="$(reports_dir)/osm_report_$(timestamp_compact).txt"
fi
newest_sql="$(latest_file "$WORKDIR/backup" 'robust_*.sql*')"
newest_oar="$(latest_file "$WORKDIR/backup" '*.oar')"
newest_rollback="$(latest_file "$WORKDIR/rollback" '*.manifest')"
log_target="$LOG_FILE_PATH"
if [[ -z "$log_target" ]]; then
log_target="$ROOT_DIR/osmtool_backup.log"
fi
report_title="OSMTool Daily Status Report"
{
printf '%s\n' "$report_title"
printf 'generated_at: %s\n' "$(timestamp_iso)"
printf 'profile: %s\n' "$PROFILE"
printf 'workdir: %s\n' "$WORKDIR"
printf '\n'
printf '[runtime]\n'
screen_status_lines
port_status_lines
database_status
printf '\n'
printf '[backup]\n'
printf 'sql_latest: %s\n' "${newest_sql:-none}"
printf 'sql_age: %s\n' "$(format_file_age_hours "${newest_sql:-}")"
printf 'oar_latest: %s\n' "${newest_oar:-none}"
printf 'oar_age: %s\n' "$(format_file_age_hours "${newest_oar:-}")"
printf '\n'
printf '[rollback]\n'
printf 'latest_manifest: %s\n' "${newest_rollback:-none}"
printf 'manifest_age: %s\n' "$(format_file_age_hours "${newest_rollback:-}")"
printf '\n'
printf '[logs]\n'
printf 'file: %s\n' "$log_target"
printf 'warning_matches: %s\n' "$(log_warning_count "$log_target")"
} > "$out"
log INFO "Report generated: $out"
cat "$out"
}
WORKDIR="$DEFAULT_WORKDIR"
ACTION=""
PROFILE="grid-sim"
OUTPUT_FILE=""
EXPECTED_SCREENS=""
PORTS=""
DB_USER=""
DB_PASS=""
DB_NAME=""
LOG_FILE_PATH=""
while [[ $# -gt 0 ]]; do
case "$1" in
--workdir) WORKDIR="$2"; shift 2 ;;
--profile) PROFILE="$2"; shift 2 ;;
--action) ACTION="$2"; shift 2 ;;
--output) OUTPUT_FILE="$2"; shift 2 ;;
--expected-screens) EXPECTED_SCREENS="$2"; shift 2 ;;
--ports) PORTS="$2"; shift 2 ;;
--db-user) DB_USER="$2"; shift 2 ;;
--db-pass) DB_PASS="$2"; shift 2 ;;
--db-name) DB_NAME="$2"; shift 2 ;;
--log-file) LOG_FILE_PATH="$2"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) die "Unknown option: $1" ;;
esac
done
[[ -n "$ACTION" ]] || die "Missing --action"
validate_profile "$PROFILE"
ensure_profile_action_allowed report "$PROFILE" "$ACTION"
if [[ -z "$EXPECTED_SCREENS" ]]; then
EXPECTED_SCREENS="$(default_screens_for_profile "$PROFILE")"
elif [[ "$EXPECTED_SCREENS" == "none" ]]; then
EXPECTED_SCREENS=""
fi
if [[ -z "$PORTS" ]]; then
PORTS="$(default_ports_for_profile "$PROFILE")"
elif [[ "$PORTS" == "none" ]]; then
PORTS=""
fi
log INFO "Using profile: $PROFILE"
case "$ACTION" in
generate) generate_report ;;
*) die "Unsupported action: $ACTION" ;;
esac
+260 -260
View File
@@ -1,260 +1,260 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=/dev/null
source "$SCRIPT_DIR/osmtool_core.sh"
usage() {
cat <<'EOF'
Usage:
osmtool_restore.sh [--workdir <path>] --action <db-restore|oar-restore|full-restore|list-backups>
[--db-user <user>] [--db-pass <pass>] [--db-name <name>]
[--region <name>] [--session <screen-name>] [--file <backup-file>]
[--dry-run <true|false>]
Examples:
osmtool_restore.sh --action list-backups --workdir /opt
osmtool_restore.sh --action db-restore --db-user opensim --db-pass secret --db-name robust --file /opt/backup/robust_robust_20260401_120000.sql
EOF
print_usage_common
}
backup_dir() {
printf '%s' "$WORKDIR/backup"
}
ensure_backup_dir() {
local dir
dir="$(backup_dir)"
if [[ ! -d "$dir" ]]; then
die "Backup directory does not exist: $dir"
fi
return 0
}
list_backups() {
local dir
dir="$(backup_dir)"
if [[ ! -d "$dir" ]]; then
log INFO "No backup directory found: $dir"
return 0
fi
log INFO "SQL Backups:"
find "$dir" -maxdepth 1 -name "robust_*.sql*" -type f -printf '%T@ %p\n' 2>/dev/null | \
sort -rn | cut -d' ' -f2- | head -5 || true
log INFO "OAR Backups:"
find "$dir" -maxdepth 1 -name "*.oar" -type f -printf '%T@ %p\n' 2>/dev/null | \
sort -rn | cut -d' ' -f2- | head -5 || true
}
resolve_default_session() {
if [[ -n "$SESSION_NAME" ]]; then
printf '%s' "$SESSION_NAME"
return 0
fi
if [[ -n "$REGION" ]]; then
printf '%s' "$REGION"
return 0
fi
printf 'sim1'
}
screen_session_exists() {
local name="$1"
screen -list 2>/dev/null | grep -qE "\\.${name}[[:space:]]"
}
send_to_screen() {
local session_name="$1"
local command_text="$2"
screen -S "$session_name" -p 0 -X stuff "${command_text}^M"
}
validate_sql_file() {
local file="$1"
if [[ ! -f "$file" ]]; then
die "SQL backup file not found: $file"
fi
# Check for gzip compression
if [[ "$file" =~ \.gz$ ]]; then
need_cmd zcat
return 0
fi
return 0
}
validate_oar_file() {
local file="$1"
if [[ ! -f "$file" ]]; then
die "OAR backup file not found: $file"
fi
if [[ ! "$file" =~ \.oar$ ]]; then
die "File does not appear to be an OAR backup: $file"
fi
return 0
}
db_restore_mysql() {
local file sql_cmd
[[ -n "$DB_USER" && -n "$DB_PASS" && -n "$DB_NAME" ]] || die "db-restore requires --db-user --db-pass --db-name"
[[ -n "$FILE" ]] || die "db-restore requires --file"
file="$FILE"
validate_sql_file "$file"
need_cmd mysql
if [[ "$file" =~ \.gz$ ]]; then
sql_cmd="zcat '$file' | mysql -u'$DB_USER' -p'$DB_PASS' '$DB_NAME'"
else
sql_cmd="mysql -u'$DB_USER' -p'$DB_PASS' '$DB_NAME' < '$file'"
fi
log INFO "Database restore command:"
log INFO "$sql_cmd"
if [[ "$DRY_RUN" == "true" ]]; then
log INFO "[DRY-RUN] Not executing database restore"
return 0
fi
log INFO "Restoring database from: $file"
if [[ "$file" =~ \.gz$ ]]; then
zcat "$file" | mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" || die "Database restore failed"
else
mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" < "$file" || die "Database restore failed"
fi
log INFO "Database restore completed successfully from: $file"
}
db_restore() {
db_restore_mysql
}
oar_restore() {
local session_name file cmd
[[ -n "$REGION" ]] || die "oar-restore requires --region"
[[ -n "$FILE" ]] || die "oar-restore requires --file"
file="$FILE"
validate_oar_file "$file"
session_name="$(resolve_default_session)"
if ! screen_session_exists "$session_name"; then
die "Screen session not running: $session_name"
fi
cmd="load oar $file"
log INFO "OAR restore command:"
log INFO "$cmd"
if [[ "$DRY_RUN" == "true" ]]; then
log INFO "[DRY-RUN] Not executing OAR restore"
log INFO "To complete restore, region '$session_name' must be running and responsive"
return 0
fi
log INFO "Sending OAR restore command to screen session '$session_name'"
send_to_screen "$session_name" "$cmd"
log INFO "OAR restore command sent. Region import may take some time. Check session output for completion."
}
full_restore() {
local has_sql has_oar
has_sql=false
has_oar=false
# Try to detect which restores to perform based on parameters
if [[ -n "$FILE" ]] && [[ "$FILE" =~ \.(sql|gz)$ ]]; then
has_sql=true
fi
if [[ -n "$FILE" ]] && [[ "$FILE" =~ \.oar$ ]]; then
has_oar=true
fi
if [[ "$has_sql" == "true" ]]; then
log INFO "Detected SQL backup file, proceeding with database restore..."
db_restore
fi
if [[ "$has_oar" == "true" ]]; then
log INFO "Detected OAR backup file, proceeding with OAR restore..."
if [[ -n "$REGION" ]]; then
oar_restore
else
log WARN "OAR file provided but no --region specified. Skipping OAR restore."
fi
fi
if [[ "$has_sql" == "false" && "$has_oar" == "false" ]]; then
die "full-restore requires --file with .sql/.sql.gz or .oar extension"
fi
}
WORKDIR="$DEFAULT_WORKDIR"
ACTION=""
DB_USER=""
DB_PASS=""
DB_NAME=""
REGION=""
SESSION_NAME=""
FILE=""
DRY_RUN="false"
PROFILE="grid-sim"
while [[ $# -gt 0 ]]; do
case "$1" in
--workdir) WORKDIR="$2"; shift 2 ;;
--profile) PROFILE="$2"; shift 2 ;;
--action) ACTION="$2"; shift 2 ;;
--db-user) DB_USER="$2"; shift 2 ;;
--db-pass) DB_PASS="$2"; shift 2 ;;
--db-name) DB_NAME="$2"; shift 2 ;;
--region) REGION="$2"; shift 2 ;;
--session) SESSION_NAME="$2"; shift 2 ;;
--file) FILE="$2"; shift 2 ;;
--dry-run) DRY_RUN="$2"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) die "Unknown option: $1" ;;
esac
done
[[ -n "$ACTION" ]] || die "Missing --action"
validate_profile "$PROFILE"
ensure_profile_action_allowed restore "$PROFILE" "$ACTION"
case "$DRY_RUN" in
true|false) ;;
*) die "--dry-run must be true or false" ;;
esac
log INFO "Using profile: $PROFILE"
case "$ACTION" in
db-restore) db_restore ;;
oar-restore) oar_restore ;;
full-restore) full_restore ;;
list-backups) ensure_backup_dir; list_backups ;;
*) die "Unsupported action: $ACTION" ;;
esac
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=/dev/null
source "$SCRIPT_DIR/osmtool_core.sh"
usage() {
cat <<'EOF'
Usage:
osmtool_restore.sh [--workdir <path>] --action <db-restore|oar-restore|full-restore|list-backups>
[--db-user <user>] [--db-pass <pass>] [--db-name <name>]
[--region <name>] [--session <screen-name>] [--file <backup-file>]
[--dry-run <true|false>]
Examples:
osmtool_restore.sh --action list-backups --workdir /opt
osmtool_restore.sh --action db-restore --db-user opensim --db-pass secret --db-name robust --file /opt/backup/robust_robust_20260401_120000.sql
EOF
print_usage_common
}
backup_dir() {
printf '%s' "$WORKDIR/backup"
}
ensure_backup_dir() {
local dir
dir="$(backup_dir)"
if [[ ! -d "$dir" ]]; then
die "Backup directory does not exist: $dir"
fi
return 0
}
list_backups() {
local dir
dir="$(backup_dir)"
if [[ ! -d "$dir" ]]; then
log INFO "No backup directory found: $dir"
return 0
fi
log INFO "SQL Backups:"
find "$dir" -maxdepth 1 -name "robust_*.sql*" -type f -printf '%T@ %p\n' 2>/dev/null | \
sort -rn | cut -d' ' -f2- | head -5 || true
log INFO "OAR Backups:"
find "$dir" -maxdepth 1 -name "*.oar" -type f -printf '%T@ %p\n' 2>/dev/null | \
sort -rn | cut -d' ' -f2- | head -5 || true
}
resolve_default_session() {
if [[ -n "$SESSION_NAME" ]]; then
printf '%s' "$SESSION_NAME"
return 0
fi
if [[ -n "$REGION" ]]; then
printf '%s' "$REGION"
return 0
fi
printf 'sim1'
}
screen_session_exists() {
local name="$1"
screen -list 2>/dev/null | grep -qE "\\.${name}[[:space:]]"
}
send_to_screen() {
local session_name="$1"
local command_text="$2"
screen -S "$session_name" -p 0 -X stuff "${command_text}^M"
}
validate_sql_file() {
local file="$1"
if [[ ! -f "$file" ]]; then
die "SQL backup file not found: $file"
fi
# Check for gzip compression
if [[ "$file" =~ \.gz$ ]]; then
need_cmd zcat
return 0
fi
return 0
}
validate_oar_file() {
local file="$1"
if [[ ! -f "$file" ]]; then
die "OAR backup file not found: $file"
fi
if [[ ! "$file" =~ \.oar$ ]]; then
die "File does not appear to be an OAR backup: $file"
fi
return 0
}
db_restore_mysql() {
local file sql_cmd
[[ -n "$DB_USER" && -n "$DB_PASS" && -n "$DB_NAME" ]] || die "db-restore requires --db-user --db-pass --db-name"
[[ -n "$FILE" ]] || die "db-restore requires --file"
file="$FILE"
validate_sql_file "$file"
need_cmd mysql
if [[ "$file" =~ \.gz$ ]]; then
sql_cmd="zcat '$file' | mysql -u'$DB_USER' -p'$DB_PASS' '$DB_NAME'"
else
sql_cmd="mysql -u'$DB_USER' -p'$DB_PASS' '$DB_NAME' < '$file'"
fi
log INFO "Database restore command:"
log INFO "$sql_cmd"
if [[ "$DRY_RUN" == "true" ]]; then
log INFO "[DRY-RUN] Not executing database restore"
return 0
fi
log INFO "Restoring database from: $file"
if [[ "$file" =~ \.gz$ ]]; then
zcat "$file" | mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" || die "Database restore failed"
else
mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" < "$file" || die "Database restore failed"
fi
log INFO "Database restore completed successfully from: $file"
}
db_restore() {
db_restore_mysql
}
oar_restore() {
local session_name file cmd
[[ -n "$REGION" ]] || die "oar-restore requires --region"
[[ -n "$FILE" ]] || die "oar-restore requires --file"
file="$FILE"
validate_oar_file "$file"
session_name="$(resolve_default_session)"
if ! screen_session_exists "$session_name"; then
die "Screen session not running: $session_name"
fi
cmd="load oar $file"
log INFO "OAR restore command:"
log INFO "$cmd"
if [[ "$DRY_RUN" == "true" ]]; then
log INFO "[DRY-RUN] Not executing OAR restore"
log INFO "To complete restore, region '$session_name' must be running and responsive"
return 0
fi
log INFO "Sending OAR restore command to screen session '$session_name'"
send_to_screen "$session_name" "$cmd"
log INFO "OAR restore command sent. Region import may take some time. Check session output for completion."
}
full_restore() {
local has_sql has_oar
has_sql=false
has_oar=false
# Try to detect which restores to perform based on parameters
if [[ -n "$FILE" ]] && [[ "$FILE" =~ \.(sql|gz)$ ]]; then
has_sql=true
fi
if [[ -n "$FILE" ]] && [[ "$FILE" =~ \.oar$ ]]; then
has_oar=true
fi
if [[ "$has_sql" == "true" ]]; then
log INFO "Detected SQL backup file, proceeding with database restore..."
db_restore
fi
if [[ "$has_oar" == "true" ]]; then
log INFO "Detected OAR backup file, proceeding with OAR restore..."
if [[ -n "$REGION" ]]; then
oar_restore
else
log WARN "OAR file provided but no --region specified. Skipping OAR restore."
fi
fi
if [[ "$has_sql" == "false" && "$has_oar" == "false" ]]; then
die "full-restore requires --file with .sql/.sql.gz or .oar extension"
fi
}
WORKDIR="$DEFAULT_WORKDIR"
ACTION=""
DB_USER=""
DB_PASS=""
DB_NAME=""
REGION=""
SESSION_NAME=""
FILE=""
DRY_RUN="false"
PROFILE="grid-sim"
while [[ $# -gt 0 ]]; do
case "$1" in
--workdir) WORKDIR="$2"; shift 2 ;;
--profile) PROFILE="$2"; shift 2 ;;
--action) ACTION="$2"; shift 2 ;;
--db-user) DB_USER="$2"; shift 2 ;;
--db-pass) DB_PASS="$2"; shift 2 ;;
--db-name) DB_NAME="$2"; shift 2 ;;
--region) REGION="$2"; shift 2 ;;
--session) SESSION_NAME="$2"; shift 2 ;;
--file) FILE="$2"; shift 2 ;;
--dry-run) DRY_RUN="$2"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) die "Unknown option: $1" ;;
esac
done
[[ -n "$ACTION" ]] || die "Missing --action"
validate_profile "$PROFILE"
ensure_profile_action_allowed restore "$PROFILE" "$ACTION"
case "$DRY_RUN" in
true|false) ;;
*) die "--dry-run must be true or false" ;;
esac
log INFO "Using profile: $PROFILE"
case "$ACTION" in
db-restore) db_restore ;;
oar-restore) oar_restore ;;
full-restore) full_restore ;;
list-backups) ensure_backup_dir; list_backups ;;
*) die "Unsupported action: $ACTION" ;;
esac
+190 -190
View File
@@ -1,191 +1,191 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
# shellcheck source=/dev/null
source "$SCRIPT_DIR/osmtool_core.sh"
usage() {
cat <<'EOF'
Usage:
osmtool_smoke.sh [--workdir <path>] --action <run>
[--target <grid|robust|sim1|standalone|janus|region>] [--name <region-screen-name>]
[--expected-screens <csv>] [--wait-after-start <sec>] [--wait-after-stop <sec>]
[--janus-prefix <path>]
Examples:
osmtool_smoke.sh --action run --profile grid-sim --workdir /opt
osmtool_smoke.sh --action run --profile robust --workdir /opt --expected-screens robustserver
EOF
print_usage_common
}
split_csv() {
local csv="$1"
local token
local IFS=','
read -r -a _TOKENS <<< "$csv"
for token in "${_TOKENS[@]}"; do
token="${token## }"
token="${token%% }"
[[ -n "$token" ]] && printf '%s\n' "$token"
done
}
default_target_for_profile() {
case "$1" in
grid-sim) echo "grid" ;;
robust) echo "robust" ;;
standalone) echo "standalone" ;;
esac
}
default_expected_screens_for_target() {
case "$1" in
grid) echo "robustserver,sim1" ;;
robust) echo "robustserver" ;;
sim1) echo "sim1" ;;
standalone) echo "standalone" ;;
janus) echo "janus_gateway" ;;
region) [[ -n "$NAME" ]] && echo "$NAME" || echo "" ;;
*) echo "" ;;
esac
}
screen_session_exists() {
local name="$1"
screen -list 2>/dev/null | grep -qE "\\.${name}[[:space:]]"
}
verify_screens_up() {
local name failed=0
[[ -n "$EXPECTED_SCREENS" ]] || {
log INFO "No expected screens configured; skipping UP verification"
return 0
}
while IFS= read -r name; do
[[ -n "$name" ]] || continue
if screen_session_exists "$name"; then
log INFO "[SMOKE][OK] screen up: $name"
else
log ERROR "[SMOKE][FAIL] screen not running: $name"
failed=$((failed + 1))
fi
done < <(split_csv "$EXPECTED_SCREENS")
return "$failed"
}
verify_screens_down() {
local name failed=0
[[ -n "$EXPECTED_SCREENS" ]] || {
log INFO "No expected screens configured; skipping DOWN verification"
return 0
}
while IFS= read -r name; do
[[ -n "$name" ]] || continue
if screen_session_exists "$name"; then
log ERROR "[SMOKE][FAIL] screen still running: $name"
failed=$((failed + 1))
else
log INFO "[SMOKE][OK] screen down: $name"
fi
done < <(split_csv "$EXPECTED_SCREENS")
return "$failed"
}
run_startstop() {
local action="$1"
local -a cmd
cmd=(bash "$ROOT_DIR/osmtool_main.sh" --module startstop --profile "$PROFILE" --workdir "$WORKDIR" --target "$TARGET" --action "$action")
if [[ "$TARGET" == "region" && -n "$NAME" ]]; then
cmd+=(--name "$NAME")
fi
if [[ -n "$JANUS_PREFIX" ]]; then
cmd+=(--janus-prefix "$JANUS_PREFIX")
fi
"${cmd[@]}"
}
run_smoke() {
local failures=0
log INFO "[SMOKE] profile=$PROFILE target=$TARGET workdir=$WORKDIR"
log INFO "[SMOKE] expected_screens=$EXPECTED_SCREENS"
run_startstop start || failures=$((failures + 1))
sleep "$WAIT_AFTER_START"
verify_screens_up || failures=$((failures + 1))
run_startstop restart || failures=$((failures + 1))
sleep "$WAIT_AFTER_START"
verify_screens_up || failures=$((failures + 1))
run_startstop stop || failures=$((failures + 1))
sleep "$WAIT_AFTER_STOP"
verify_screens_down || failures=$((failures + 1))
if [[ "$failures" -eq 0 ]]; then
log INFO "[SMOKE][PASS] Start/Restart/Stop smoke test successful"
return 0
fi
log ERROR "[SMOKE][FAIL] Smoke test failed with $failures issue group(s)"
return 1
}
WORKDIR="$DEFAULT_WORKDIR"
ACTION=""
PROFILE="grid-sim"
TARGET=""
NAME=""
EXPECTED_SCREENS=""
WAIT_AFTER_START="3"
WAIT_AFTER_STOP="8"
JANUS_PREFIX="${JANUS_PREFIX:-/opt/janus}"
while [[ $# -gt 0 ]]; do
case "$1" in
--workdir) WORKDIR="$2"; shift 2 ;;
--profile) PROFILE="$2"; shift 2 ;;
--action) ACTION="$2"; shift 2 ;;
--target) TARGET="$2"; shift 2 ;;
--name) NAME="$2"; shift 2 ;;
--expected-screens) EXPECTED_SCREENS="$2"; shift 2 ;;
--wait-after-start) WAIT_AFTER_START="$2"; shift 2 ;;
--wait-after-stop) WAIT_AFTER_STOP="$2"; shift 2 ;;
--janus-prefix) JANUS_PREFIX="$2"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) die "Unknown option: $1" ;;
esac
done
[[ -n "$ACTION" ]] || die "Missing --action"
validate_profile "$PROFILE"
ensure_profile_action_allowed smoke "$PROFILE" "$ACTION"
if [[ -z "$TARGET" ]]; then
TARGET="$(default_target_for_profile "$PROFILE")"
fi
ensure_profile_target_allowed "$PROFILE" "$TARGET"
if [[ "$TARGET" == "region" && -z "$NAME" ]]; then
die "--name is required for --target region"
fi
if [[ -z "$EXPECTED_SCREENS" ]]; then
EXPECTED_SCREENS="$(default_expected_screens_for_target "$TARGET")"
fi
case "$ACTION" in
run) run_smoke ;;
*) die "Unsupported action: $ACTION" ;;
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
# shellcheck source=/dev/null
source "$SCRIPT_DIR/osmtool_core.sh"
usage() {
cat <<'EOF'
Usage:
osmtool_smoke.sh [--workdir <path>] --action <run>
[--target <grid|robust|sim1|standalone|janus|region>] [--name <region-screen-name>]
[--expected-screens <csv>] [--wait-after-start <sec>] [--wait-after-stop <sec>]
[--janus-prefix <path>]
Examples:
osmtool_smoke.sh --action run --profile grid-sim --workdir /opt
osmtool_smoke.sh --action run --profile robust --workdir /opt --expected-screens robustserver
EOF
print_usage_common
}
split_csv() {
local csv="$1"
local token
local IFS=','
read -r -a _TOKENS <<< "$csv"
for token in "${_TOKENS[@]}"; do
token="${token## }"
token="${token%% }"
[[ -n "$token" ]] && printf '%s\n' "$token"
done
}
default_target_for_profile() {
case "$1" in
grid-sim) echo "grid" ;;
robust) echo "robust" ;;
standalone) echo "standalone" ;;
esac
}
default_expected_screens_for_target() {
case "$1" in
grid) echo "robustserver,sim1" ;;
robust) echo "robustserver" ;;
sim1) echo "sim1" ;;
standalone) echo "standalone" ;;
janus) echo "janus_gateway" ;;
region) [[ -n "$NAME" ]] && echo "$NAME" || echo "" ;;
*) echo "" ;;
esac
}
screen_session_exists() {
local name="$1"
screen -list 2>/dev/null | grep -qE "\\.${name}[[:space:]]"
}
verify_screens_up() {
local name failed=0
[[ -n "$EXPECTED_SCREENS" ]] || {
log INFO "No expected screens configured; skipping UP verification"
return 0
}
while IFS= read -r name; do
[[ -n "$name" ]] || continue
if screen_session_exists "$name"; then
log INFO "[SMOKE][OK] screen up: $name"
else
log ERROR "[SMOKE][FAIL] screen not running: $name"
failed=$((failed + 1))
fi
done < <(split_csv "$EXPECTED_SCREENS")
return "$failed"
}
verify_screens_down() {
local name failed=0
[[ -n "$EXPECTED_SCREENS" ]] || {
log INFO "No expected screens configured; skipping DOWN verification"
return 0
}
while IFS= read -r name; do
[[ -n "$name" ]] || continue
if screen_session_exists "$name"; then
log ERROR "[SMOKE][FAIL] screen still running: $name"
failed=$((failed + 1))
else
log INFO "[SMOKE][OK] screen down: $name"
fi
done < <(split_csv "$EXPECTED_SCREENS")
return "$failed"
}
run_startstop() {
local action="$1"
local -a cmd
cmd=(bash "$ROOT_DIR/osmtool_main.sh" --module startstop --profile "$PROFILE" --workdir "$WORKDIR" --target "$TARGET" --action "$action")
if [[ "$TARGET" == "region" && -n "$NAME" ]]; then
cmd+=(--name "$NAME")
fi
if [[ -n "$JANUS_PREFIX" ]]; then
cmd+=(--janus-prefix "$JANUS_PREFIX")
fi
"${cmd[@]}"
}
run_smoke() {
local failures=0
log INFO "[SMOKE] profile=$PROFILE target=$TARGET workdir=$WORKDIR"
log INFO "[SMOKE] expected_screens=$EXPECTED_SCREENS"
run_startstop start || failures=$((failures + 1))
sleep "$WAIT_AFTER_START"
verify_screens_up || failures=$((failures + 1))
run_startstop restart || failures=$((failures + 1))
sleep "$WAIT_AFTER_START"
verify_screens_up || failures=$((failures + 1))
run_startstop stop || failures=$((failures + 1))
sleep "$WAIT_AFTER_STOP"
verify_screens_down || failures=$((failures + 1))
if [[ "$failures" -eq 0 ]]; then
log INFO "[SMOKE][PASS] Start/Restart/Stop smoke test successful"
return 0
fi
log ERROR "[SMOKE][FAIL] Smoke test failed with $failures issue group(s)"
return 1
}
WORKDIR="$DEFAULT_WORKDIR"
ACTION=""
PROFILE="grid-sim"
TARGET=""
NAME=""
EXPECTED_SCREENS=""
WAIT_AFTER_START="3"
WAIT_AFTER_STOP="8"
JANUS_PREFIX="${JANUS_PREFIX:-/opt/janus}"
while [[ $# -gt 0 ]]; do
case "$1" in
--workdir) WORKDIR="$2"; shift 2 ;;
--profile) PROFILE="$2"; shift 2 ;;
--action) ACTION="$2"; shift 2 ;;
--target) TARGET="$2"; shift 2 ;;
--name) NAME="$2"; shift 2 ;;
--expected-screens) EXPECTED_SCREENS="$2"; shift 2 ;;
--wait-after-start) WAIT_AFTER_START="$2"; shift 2 ;;
--wait-after-stop) WAIT_AFTER_STOP="$2"; shift 2 ;;
--janus-prefix) JANUS_PREFIX="$2"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) die "Unknown option: $1" ;;
esac
done
[[ -n "$ACTION" ]] || die "Missing --action"
validate_profile "$PROFILE"
ensure_profile_action_allowed smoke "$PROFILE" "$ACTION"
if [[ -z "$TARGET" ]]; then
TARGET="$(default_target_for_profile "$PROFILE")"
fi
ensure_profile_target_allowed "$PROFILE" "$TARGET"
if [[ "$TARGET" == "region" && -z "$NAME" ]]; then
die "--name is required for --target region"
fi
if [[ -z "$EXPECTED_SCREENS" ]]; then
EXPECTED_SCREENS="$(default_expected_screens_for_target "$TARGET")"
fi
case "$ACTION" in
run) run_smoke ;;
*) die "Unsupported action: $ACTION" ;;
esac
+395 -395
View File
@@ -1,395 +1,395 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=/dev/null
source "$SCRIPT_DIR/osmtool_core.sh"
msgf() {
local key="$1"
shift
# shellcheck disable=SC2059
printf "$(msg "$key")" "$@"
}
usage() {
cat <<'EOF'
Usage:
osmtool_startstop.sh [--workdir <path>] [--profile <grid-sim|robust|standalone>] --target <grid|robust|sim1|standalone|janus|region> --action <start|stop|restart> [--name <region-screen-name>]
[--janus-prefix <path>]
Examples:
osmtool_startstop.sh --profile grid-sim --target grid --action start --workdir /opt
osmtool_startstop.sh --profile robust --target robust --action restart --workdir /opt
EOF
print_usage_common
}
run_screen_cmd() {
local screen_name="$1"
local command_text="$2"
screen -S "$screen_name" -p 0 -X stuff "${command_text}^M"
}
screen_session_exists() {
local screen_name="$1"
screen -list 2>/dev/null | grep -qE "\\.${screen_name}[[:space:]]"
}
stop_screen_session() {
local screen_name="$1"
local grace_seconds="${2:-$SIMULATOR_STOP_WAIT}"
if ! screen_session_exists "$screen_name"; then
log INFO "$(msgf STARTSTOP_NOT_RUNNING "$screen_name")"
return 0
fi
run_screen_cmd "$screen_name" "shutdown"
log INFO "$(msgf STARTSTOP_SENT_SHUTDOWN "$screen_name")"
sleep "$grace_seconds"
if screen_session_exists "$screen_name"; then
log INFO "$(msgf STARTSTOP_FORCE_QUIT "$screen_name")"
screen -S "$screen_name" -X quit || true
sleep 1
fi
if screen_session_exists "$screen_name"; then
log ERROR "$(msgf STARTSTOP_STOP_FAILED "$screen_name")"
return 1
fi
log INFO "$(msgf STARTSTOP_STOPPED "$screen_name")"
return 0
}
ensure_janus_ready() {
local marker="$JANUS_PREFIX/.osmtool_janus_ready"
local core_cfg="$JANUS_PREFIX/etc/janus/janus.jcfg"
local core_cfg_legacy="$JANUS_PREFIX/etc/janus/janus.cfg"
local http_cfg="$JANUS_PREFIX/etc/janus/janus.transport.http.jcfg"
local http_cfg_legacy="$JANUS_PREFIX/etc/janus/janus.transport.http.cfg"
[[ -f "$JANUS_PREFIX/bin/janus" ]] || die "$(msgf STARTSTOP_JANUS_BIN_MISSING "$JANUS_PREFIX/bin/janus")"
if [[ ! -f "$core_cfg" && ! -f "$core_cfg_legacy" ]]; then
die "$(msgf STARTSTOP_JANUS_CORE_CFG_MISSING "$JANUS_PREFIX/etc/janus")"
fi
if [[ ! -f "$http_cfg" && ! -f "$http_cfg_legacy" ]]; then
die "$(msgf STARTSTOP_JANUS_HTTP_CFG_MISSING "$JANUS_PREFIX/etc/janus")"
fi
[[ -f "$marker" ]] || log INFO "$(msgf STARTSTOP_JANUS_MARKER_MISSING "$marker")"
}
janus_service_action() {
local action="$1"
local janus_bin janus_cfg
janus_bin="$JANUS_PREFIX/bin/janus"
janus_cfg="$JANUS_PREFIX/etc/janus/janus.jcfg"
[[ -f "$janus_cfg" ]] || janus_cfg="$JANUS_PREFIX/etc/janus/janus.cfg"
if command -v systemctl >/dev/null 2>&1; then
if systemctl list-unit-files 2>/dev/null | grep -q '^janus\.service'; then
sudo systemctl "$action" janus
return 0
fi
fi
if command -v service >/dev/null 2>&1; then
if service --status-all 2>/dev/null | grep -q janus; then
sudo service janus "$action"
return 0
fi
fi
if [[ -x "$WORKDIR/janus.sh" ]]; then
"$WORKDIR/janus.sh" "${action}_janus" || "$WORKDIR/janus.sh" "$action"
return 0
fi
if [[ -x "$WORKDIR/janus/janus.sh" ]]; then
"$WORKDIR/janus/janus.sh" "${action}_janus" || "$WORKDIR/janus/janus.sh" "$action"
return 0
fi
# Fallback: control Janus directly from installed binary.
if [[ -x "$janus_bin" ]]; then
case "$action" in
start)
if pgrep -f "$janus_bin" >/dev/null 2>&1; then
log INFO "$(msg STARTSTOP_JANUS_ALREADY_RUNNING)"
return 0
fi
if command -v screen >/dev/null 2>&1; then
screen -fa -S janus_gateway -d -U -m "$janus_bin" -C "$janus_cfg"
else
nohup "$janus_bin" -C "$janus_cfg" >/tmp/janus.log 2>&1 &
fi
return 0
;;
stop)
pkill -f "$janus_bin" >/dev/null 2>&1 || true
if command -v screen >/dev/null 2>&1; then
if screen -list | grep -q "janus_gateway"; then
screen -S janus_gateway -X quit || true
fi
fi
return 0
;;
restart)
pkill -f "$janus_bin" >/dev/null 2>&1 || true
sleep 1
if command -v screen >/dev/null 2>&1; then
screen -fa -S janus_gateway -d -U -m "$janus_bin" -C "$janus_cfg"
else
nohup "$janus_bin" -C "$janus_cfg" >/tmp/janus.log 2>&1 &
fi
return 0
;;
esac
fi
die "$(msg STARTSTOP_JANUS_CONTROL_NOT_CONFIGURED)"
}
require_ini() {
local bin_dir="$1"
local ini_file="$2"
local label="$3"
if [[ ! -f "$bin_dir/$ini_file" ]]; then
die "$(msgf STARTSTOP_REQUIRED_INI_MISSING "$label" "$bin_dir/$ini_file")"
fi
}
screen_start() {
local screen_name="$1"
local bin_dir="$2"
local dll="$3"
local pat="\\.${screen_name}[[:space:]]"
if screen -list 2>/dev/null | grep -qE "$pat"; then
log INFO "$(msgf STARTSTOP_ALREADY_RUNNING "$screen_name")"
return 0
fi
log INFO "$(msgf STARTSTOP_STARTING_FROM "$screen_name" "$bin_dir")"
(cd "$bin_dir" && screen -fa -S "$screen_name" -d -U -m dotnet "$dll")
sleep 0.5
if screen -list 2>/dev/null | grep -qE "$pat"; then
log INFO "$(msgf STARTSTOP_STARTED_OK "$screen_name")"
return 0
else
log ERROR "$(msgf STARTSTOP_START_FAILED "$screen_name")"
return 1
fi
}
list_sim_names_asc() {
local sim_dir sim_name
local sim_names=()
shopt -s nullglob
for sim_dir in "$WORKDIR"/sim[0-9]*; do
[[ -d "$sim_dir/bin" ]] || continue
sim_name="$(basename "$sim_dir")"
[[ "$sim_name" =~ ^sim[0-9]+$ ]] || continue
sim_names+=("$sim_name")
done
shopt -u nullglob
if [[ ${#sim_names[@]} -eq 0 ]]; then
return 0
fi
printf '%s\n' "${sim_names[@]}" | sort -V
}
start_grid() {
local sim_name
local sim_count=0
log INFO "$(msgf STARTSTOP_GRID_STARTING "$WORKDIR")"
[[ -d "$WORKDIR/robust/bin" ]] || die "$(msgf STARTSTOP_ROBUST_DIR_MISSING "$WORKDIR/robust/bin")"
require_ini "$WORKDIR/robust/bin" "Robust.ini" "RobustServer"
screen_start "robustserver" "$WORKDIR/robust/bin" "Robust.dll" || die "$(msg STARTSTOP_ROBUST_START_FAILED)"
sleep "$ROBUSTSERVER_START_WAIT"
[[ -f "$WORKDIR/robust/bin/MoneyServer.dll" ]] || die "$(msgf STARTSTOP_MONEY_DLL_MISSING "$WORKDIR/robust/bin/MoneyServer.dll")"
[[ -f "$WORKDIR/robust/bin/MoneyServer.ini" ]] || die "$(msgf STARTSTOP_MONEY_INI_MISSING "$WORKDIR/robust/bin/MoneyServer.ini")"
screen_start "moneyserver" "$WORKDIR/robust/bin" "MoneyServer.dll" || die "$(msg STARTSTOP_MONEY_START_FAILED)"
sleep "$MONEYSERVER_START_WAIT"
while IFS= read -r sim_name; do
[[ -n "$sim_name" ]] || continue
require_ini "$WORKDIR/$sim_name/bin" "OpenSim.ini" "$sim_name"
screen_start "$sim_name" "$WORKDIR/$sim_name/bin" "OpenSim.dll" || die "$(msgf STARTSTOP_SIM_START_FAILED "$sim_name")"
sleep "$SIMULATOR_START_WAIT"
((sim_count+=1))
done < <(list_sim_names_asc)
[[ "$sim_count" -gt 0 ]] || die "$(msgf STARTSTOP_NO_SIM_FOUND "$WORKDIR")"
}
stop_grid() {
local sim_names=()
local idx
log INFO "$(msg STARTSTOP_GRID_STOPPING)"
mapfile -t sim_names < <(list_sim_names_asc)
for ((idx=${#sim_names[@]}-1; idx>=0; idx--)); do
stop_screen_session "${sim_names[$idx]}" "$SIMULATOR_STOP_WAIT" || true
done
stop_screen_session "moneyserver" "$MONEYSERVER_STOP_WAIT" || true
stop_screen_session "robustserver" "$ROBUSTSERVER_STOP_WAIT" || true
}
logclean_grid() {
log INFO "$(msg STARTSTOP_LOGCLEAN_BEGIN)"
if [[ -d "$WORKDIR/robust/bin" ]]; then
rm -f "$WORKDIR/robust/bin/"*.log
log INFO "$(msgf STARTSTOP_LOGS_DELETED "$WORKDIR/robust/bin")"
fi
local sim_dir sim_name
shopt -s nullglob
for sim_dir in "$WORKDIR"/sim[0-9]*/bin; do
sim_name="$(basename "$(dirname "$sim_dir")")"
[[ "$sim_name" =~ ^sim[0-9]+$ ]] || continue
rm -f "$sim_dir/"*.log
log INFO "$(msgf STARTSTOP_LOGS_DELETED "$sim_dir")"
done
shopt -u nullglob
log INFO "$(msg STARTSTOP_LOGCLEAN_DONE)"
}
restart_grid() {
stop_grid
sleep "$SIMULATOR_STOP_WAIT"
logclean_grid
sleep "$SIMULATOR_START_WAIT"
start_grid
log INFO "$(msg STARTSTOP_ACTIVE_SESSIONS)"
screen -ls 2>/dev/null || log INFO "$(msg STARTSTOP_NO_SESSIONS)"
}
start_single() {
local target="$1"
case "$target" in
robust)
require_ini "$WORKDIR/robust/bin" "Robust.ini" "RobustServer"
screen_start "robustserver" "$WORKDIR/robust/bin" "Robust.dll"
;;
sim1)
require_ini "$WORKDIR/sim1/bin" "OpenSim.ini" "sim1"
screen_start "sim1" "$WORKDIR/sim1/bin" "OpenSim.dll"
;;
standalone)
require_ini "$WORKDIR/standalone/bin" "OpenSim.ini" "standalone"
screen_start "standalone" "$WORKDIR/standalone/bin" "OpenSim.dll"
;;
janus)
ensure_janus_ready
janus_service_action start
;;
region)
[[ -n "$NAME" ]] || die "$(msg STARTSTOP_NAME_REQUIRED)"
require_ini "$WORKDIR/${NAME}/bin" "OpenSim.ini" "$NAME"
screen_start "$NAME" "$WORKDIR/${NAME}/bin" "OpenSim.dll"
;;
*)
die "$(msgf STARTSTOP_UNSUPPORTED_START_TARGET "$target")"
;;
esac
}
stop_single() {
local target="$1"
case "$target" in
robust)
stop_screen_session "robustserver"
;;
sim1)
stop_screen_session "sim1"
;;
standalone)
stop_screen_session "standalone"
;;
janus) janus_service_action stop ;;
region)
[[ -n "$NAME" ]] || die "$(msg STARTSTOP_NAME_REQUIRED)"
stop_screen_session "$NAME"
;;
*) die "$(msgf STARTSTOP_UNSUPPORTED_STOP_TARGET "$target")" ;;
esac
}
WORKDIR="$DEFAULT_WORKDIR"
TARGET=""
ACTION=""
NAME=""
PROFILE="grid-sim"
JANUS_PREFIX="${JANUS_PREFIX:-/opt/janus}"
# Wartezeiten (Sekunden) entsprechen den bewährten Werten aus osmtool.sh
SIMULATOR_STOP_WAIT="${SIMULATOR_STOP_WAIT:-15}"
MONEYSERVER_STOP_WAIT="${MONEYSERVER_STOP_WAIT:-30}"
ROBUSTSERVER_STOP_WAIT="${ROBUSTSERVER_STOP_WAIT:-30}"
SIMULATOR_START_WAIT="${SIMULATOR_START_WAIT:-15}"
MONEYSERVER_START_WAIT="${MONEYSERVER_START_WAIT:-30}"
ROBUSTSERVER_START_WAIT="${ROBUSTSERVER_START_WAIT:-30}"
while [[ $# -gt 0 ]]; do
case "$1" in
--workdir) WORKDIR="$2"; shift 2 ;;
--profile) PROFILE="$2"; shift 2 ;;
--janus-prefix) JANUS_PREFIX="$2"; shift 2 ;;
--target) TARGET="$2"; shift 2 ;;
--action) ACTION="$2"; shift 2 ;;
--name) NAME="$2"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) die "$(msgf ERR_UNKNOWN_OPTION "$1")" ;;
esac
done
[[ -n "$TARGET" ]] || die "$(msg ERR_MISSING_TARGET)"
[[ -n "$ACTION" ]] || die "$(msg ERR_MISSING_ACTION)"
validate_profile "$PROFILE"
ensure_profile_action_allowed startstop "$PROFILE" "$ACTION"
ensure_profile_target_allowed "$PROFILE" "$TARGET"
if [[ "$TARGET" == "janus" && "$ACTION" != "stop" ]]; then
ensure_janus_ready
fi
log INFO "$(msgf INFO_USING_PROFILE "$PROFILE")"
if [[ "$TARGET" == "grid" ]]; then
case "$ACTION" in
start) start_grid ;;
stop) stop_grid ;;
restart) restart_grid ;;
*) die "$(msgf ERR_UNSUPPORTED_GRID_ACTION "$ACTION")" ;;
esac
else
case "$ACTION" in
start) start_single "$TARGET" ;;
stop) stop_single "$TARGET" ;;
restart)
stop_single "$TARGET"
sleep 3
start_single "$TARGET"
;;
*) die "$(msgf ERR_UNSUPPORTED_ACTION "$ACTION")" ;;
esac
fi
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=/dev/null
source "$SCRIPT_DIR/osmtool_core.sh"
msgf() {
local key="$1"
shift
# shellcheck disable=SC2059
printf "$(msg "$key")" "$@"
}
usage() {
cat <<'EOF'
Usage:
osmtool_startstop.sh [--workdir <path>] [--profile <grid-sim|robust|standalone>] --target <grid|robust|sim1|standalone|janus|region> --action <start|stop|restart> [--name <region-screen-name>]
[--janus-prefix <path>]
Examples:
osmtool_startstop.sh --profile grid-sim --target grid --action start --workdir /opt
osmtool_startstop.sh --profile robust --target robust --action restart --workdir /opt
EOF
print_usage_common
}
run_screen_cmd() {
local screen_name="$1"
local command_text="$2"
screen -S "$screen_name" -p 0 -X stuff "${command_text}^M"
}
screen_session_exists() {
local screen_name="$1"
screen -list 2>/dev/null | grep -qE "\\.${screen_name}[[:space:]]"
}
stop_screen_session() {
local screen_name="$1"
local grace_seconds="${2:-$SIMULATOR_STOP_WAIT}"
if ! screen_session_exists "$screen_name"; then
log INFO "$(msgf STARTSTOP_NOT_RUNNING "$screen_name")"
return 0
fi
run_screen_cmd "$screen_name" "shutdown"
log INFO "$(msgf STARTSTOP_SENT_SHUTDOWN "$screen_name")"
sleep "$grace_seconds"
if screen_session_exists "$screen_name"; then
log INFO "$(msgf STARTSTOP_FORCE_QUIT "$screen_name")"
screen -S "$screen_name" -X quit || true
sleep 1
fi
if screen_session_exists "$screen_name"; then
log ERROR "$(msgf STARTSTOP_STOP_FAILED "$screen_name")"
return 1
fi
log INFO "$(msgf STARTSTOP_STOPPED "$screen_name")"
return 0
}
ensure_janus_ready() {
local marker="$JANUS_PREFIX/.osmtool_janus_ready"
local core_cfg="$JANUS_PREFIX/etc/janus/janus.jcfg"
local core_cfg_legacy="$JANUS_PREFIX/etc/janus/janus.cfg"
local http_cfg="$JANUS_PREFIX/etc/janus/janus.transport.http.jcfg"
local http_cfg_legacy="$JANUS_PREFIX/etc/janus/janus.transport.http.cfg"
[[ -f "$JANUS_PREFIX/bin/janus" ]] || die "$(msgf STARTSTOP_JANUS_BIN_MISSING "$JANUS_PREFIX/bin/janus")"
if [[ ! -f "$core_cfg" && ! -f "$core_cfg_legacy" ]]; then
die "$(msgf STARTSTOP_JANUS_CORE_CFG_MISSING "$JANUS_PREFIX/etc/janus")"
fi
if [[ ! -f "$http_cfg" && ! -f "$http_cfg_legacy" ]]; then
die "$(msgf STARTSTOP_JANUS_HTTP_CFG_MISSING "$JANUS_PREFIX/etc/janus")"
fi
[[ -f "$marker" ]] || log INFO "$(msgf STARTSTOP_JANUS_MARKER_MISSING "$marker")"
}
janus_service_action() {
local action="$1"
local janus_bin janus_cfg
janus_bin="$JANUS_PREFIX/bin/janus"
janus_cfg="$JANUS_PREFIX/etc/janus/janus.jcfg"
[[ -f "$janus_cfg" ]] || janus_cfg="$JANUS_PREFIX/etc/janus/janus.cfg"
if command -v systemctl >/dev/null 2>&1; then
if systemctl list-unit-files 2>/dev/null | grep -q '^janus\.service'; then
sudo systemctl "$action" janus
return 0
fi
fi
if command -v service >/dev/null 2>&1; then
if service --status-all 2>/dev/null | grep -q janus; then
sudo service janus "$action"
return 0
fi
fi
if [[ -x "$WORKDIR/janus.sh" ]]; then
"$WORKDIR/janus.sh" "${action}_janus" || "$WORKDIR/janus.sh" "$action"
return 0
fi
if [[ -x "$WORKDIR/janus/janus.sh" ]]; then
"$WORKDIR/janus/janus.sh" "${action}_janus" || "$WORKDIR/janus/janus.sh" "$action"
return 0
fi
# Fallback: control Janus directly from installed binary.
if [[ -x "$janus_bin" ]]; then
case "$action" in
start)
if pgrep -f "$janus_bin" >/dev/null 2>&1; then
log INFO "$(msg STARTSTOP_JANUS_ALREADY_RUNNING)"
return 0
fi
if command -v screen >/dev/null 2>&1; then
screen -fa -S janus_gateway -d -U -m "$janus_bin" -C "$janus_cfg"
else
nohup "$janus_bin" -C "$janus_cfg" >/tmp/janus.log 2>&1 &
fi
return 0
;;
stop)
pkill -f "$janus_bin" >/dev/null 2>&1 || true
if command -v screen >/dev/null 2>&1; then
if screen -list | grep -q "janus_gateway"; then
screen -S janus_gateway -X quit || true
fi
fi
return 0
;;
restart)
pkill -f "$janus_bin" >/dev/null 2>&1 || true
sleep 1
if command -v screen >/dev/null 2>&1; then
screen -fa -S janus_gateway -d -U -m "$janus_bin" -C "$janus_cfg"
else
nohup "$janus_bin" -C "$janus_cfg" >/tmp/janus.log 2>&1 &
fi
return 0
;;
esac
fi
die "$(msg STARTSTOP_JANUS_CONTROL_NOT_CONFIGURED)"
}
require_ini() {
local bin_dir="$1"
local ini_file="$2"
local label="$3"
if [[ ! -f "$bin_dir/$ini_file" ]]; then
die "$(msgf STARTSTOP_REQUIRED_INI_MISSING "$label" "$bin_dir/$ini_file")"
fi
}
screen_start() {
local screen_name="$1"
local bin_dir="$2"
local dll="$3"
local pat="\\.${screen_name}[[:space:]]"
if screen -list 2>/dev/null | grep -qE "$pat"; then
log INFO "$(msgf STARTSTOP_ALREADY_RUNNING "$screen_name")"
return 0
fi
log INFO "$(msgf STARTSTOP_STARTING_FROM "$screen_name" "$bin_dir")"
(cd "$bin_dir" && screen -fa -S "$screen_name" -d -U -m dotnet "$dll")
sleep 0.5
if screen -list 2>/dev/null | grep -qE "$pat"; then
log INFO "$(msgf STARTSTOP_STARTED_OK "$screen_name")"
return 0
else
log ERROR "$(msgf STARTSTOP_START_FAILED "$screen_name")"
return 1
fi
}
list_sim_names_asc() {
local sim_dir sim_name
local sim_names=()
shopt -s nullglob
for sim_dir in "$WORKDIR"/sim[0-9]*; do
[[ -d "$sim_dir/bin" ]] || continue
sim_name="$(basename "$sim_dir")"
[[ "$sim_name" =~ ^sim[0-9]+$ ]] || continue
sim_names+=("$sim_name")
done
shopt -u nullglob
if [[ ${#sim_names[@]} -eq 0 ]]; then
return 0
fi
printf '%s\n' "${sim_names[@]}" | sort -V
}
start_grid() {
local sim_name
local sim_count=0
log INFO "$(msgf STARTSTOP_GRID_STARTING "$WORKDIR")"
[[ -d "$WORKDIR/robust/bin" ]] || die "$(msgf STARTSTOP_ROBUST_DIR_MISSING "$WORKDIR/robust/bin")"
require_ini "$WORKDIR/robust/bin" "Robust.ini" "RobustServer"
screen_start "robustserver" "$WORKDIR/robust/bin" "Robust.dll" || die "$(msg STARTSTOP_ROBUST_START_FAILED)"
sleep "$ROBUSTSERVER_START_WAIT"
[[ -f "$WORKDIR/robust/bin/MoneyServer.dll" ]] || die "$(msgf STARTSTOP_MONEY_DLL_MISSING "$WORKDIR/robust/bin/MoneyServer.dll")"
[[ -f "$WORKDIR/robust/bin/MoneyServer.ini" ]] || die "$(msgf STARTSTOP_MONEY_INI_MISSING "$WORKDIR/robust/bin/MoneyServer.ini")"
screen_start "moneyserver" "$WORKDIR/robust/bin" "MoneyServer.dll" || die "$(msg STARTSTOP_MONEY_START_FAILED)"
sleep "$MONEYSERVER_START_WAIT"
while IFS= read -r sim_name; do
[[ -n "$sim_name" ]] || continue
require_ini "$WORKDIR/$sim_name/bin" "OpenSim.ini" "$sim_name"
screen_start "$sim_name" "$WORKDIR/$sim_name/bin" "OpenSim.dll" || die "$(msgf STARTSTOP_SIM_START_FAILED "$sim_name")"
sleep "$SIMULATOR_START_WAIT"
((sim_count+=1))
done < <(list_sim_names_asc)
[[ "$sim_count" -gt 0 ]] || die "$(msgf STARTSTOP_NO_SIM_FOUND "$WORKDIR")"
}
stop_grid() {
local sim_names=()
local idx
log INFO "$(msg STARTSTOP_GRID_STOPPING)"
mapfile -t sim_names < <(list_sim_names_asc)
for ((idx=${#sim_names[@]}-1; idx>=0; idx--)); do
stop_screen_session "${sim_names[$idx]}" "$SIMULATOR_STOP_WAIT" || true
done
stop_screen_session "moneyserver" "$MONEYSERVER_STOP_WAIT" || true
stop_screen_session "robustserver" "$ROBUSTSERVER_STOP_WAIT" || true
}
logclean_grid() {
log INFO "$(msg STARTSTOP_LOGCLEAN_BEGIN)"
if [[ -d "$WORKDIR/robust/bin" ]]; then
rm -f "$WORKDIR/robust/bin/"*.log
log INFO "$(msgf STARTSTOP_LOGS_DELETED "$WORKDIR/robust/bin")"
fi
local sim_dir sim_name
shopt -s nullglob
for sim_dir in "$WORKDIR"/sim[0-9]*/bin; do
sim_name="$(basename "$(dirname "$sim_dir")")"
[[ "$sim_name" =~ ^sim[0-9]+$ ]] || continue
rm -f "$sim_dir/"*.log
log INFO "$(msgf STARTSTOP_LOGS_DELETED "$sim_dir")"
done
shopt -u nullglob
log INFO "$(msg STARTSTOP_LOGCLEAN_DONE)"
}
restart_grid() {
stop_grid
sleep "$SIMULATOR_STOP_WAIT"
logclean_grid
sleep "$SIMULATOR_START_WAIT"
start_grid
log INFO "$(msg STARTSTOP_ACTIVE_SESSIONS)"
screen -ls 2>/dev/null || log INFO "$(msg STARTSTOP_NO_SESSIONS)"
}
start_single() {
local target="$1"
case "$target" in
robust)
require_ini "$WORKDIR/robust/bin" "Robust.ini" "RobustServer"
screen_start "robustserver" "$WORKDIR/robust/bin" "Robust.dll"
;;
sim1)
require_ini "$WORKDIR/sim1/bin" "OpenSim.ini" "sim1"
screen_start "sim1" "$WORKDIR/sim1/bin" "OpenSim.dll"
;;
standalone)
require_ini "$WORKDIR/standalone/bin" "OpenSim.ini" "standalone"
screen_start "standalone" "$WORKDIR/standalone/bin" "OpenSim.dll"
;;
janus)
ensure_janus_ready
janus_service_action start
;;
region)
[[ -n "$NAME" ]] || die "$(msg STARTSTOP_NAME_REQUIRED)"
require_ini "$WORKDIR/${NAME}/bin" "OpenSim.ini" "$NAME"
screen_start "$NAME" "$WORKDIR/${NAME}/bin" "OpenSim.dll"
;;
*)
die "$(msgf STARTSTOP_UNSUPPORTED_START_TARGET "$target")"
;;
esac
}
stop_single() {
local target="$1"
case "$target" in
robust)
stop_screen_session "robustserver"
;;
sim1)
stop_screen_session "sim1"
;;
standalone)
stop_screen_session "standalone"
;;
janus) janus_service_action stop ;;
region)
[[ -n "$NAME" ]] || die "$(msg STARTSTOP_NAME_REQUIRED)"
stop_screen_session "$NAME"
;;
*) die "$(msgf STARTSTOP_UNSUPPORTED_STOP_TARGET "$target")" ;;
esac
}
WORKDIR="$DEFAULT_WORKDIR"
TARGET=""
ACTION=""
NAME=""
PROFILE="grid-sim"
JANUS_PREFIX="${JANUS_PREFIX:-/opt/janus}"
# Wartezeiten (Sekunden) entsprechen den bewährten Werten aus osmtool.sh
SIMULATOR_STOP_WAIT="${SIMULATOR_STOP_WAIT:-15}"
MONEYSERVER_STOP_WAIT="${MONEYSERVER_STOP_WAIT:-30}"
ROBUSTSERVER_STOP_WAIT="${ROBUSTSERVER_STOP_WAIT:-30}"
SIMULATOR_START_WAIT="${SIMULATOR_START_WAIT:-15}"
MONEYSERVER_START_WAIT="${MONEYSERVER_START_WAIT:-30}"
ROBUSTSERVER_START_WAIT="${ROBUSTSERVER_START_WAIT:-30}"
while [[ $# -gt 0 ]]; do
case "$1" in
--workdir) WORKDIR="$2"; shift 2 ;;
--profile) PROFILE="$2"; shift 2 ;;
--janus-prefix) JANUS_PREFIX="$2"; shift 2 ;;
--target) TARGET="$2"; shift 2 ;;
--action) ACTION="$2"; shift 2 ;;
--name) NAME="$2"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) die "$(msgf ERR_UNKNOWN_OPTION "$1")" ;;
esac
done
[[ -n "$TARGET" ]] || die "$(msg ERR_MISSING_TARGET)"
[[ -n "$ACTION" ]] || die "$(msg ERR_MISSING_ACTION)"
validate_profile "$PROFILE"
ensure_profile_action_allowed startstop "$PROFILE" "$ACTION"
ensure_profile_target_allowed "$PROFILE" "$TARGET"
if [[ "$TARGET" == "janus" && "$ACTION" != "stop" ]]; then
ensure_janus_ready
fi
log INFO "$(msgf INFO_USING_PROFILE "$PROFILE")"
if [[ "$TARGET" == "grid" ]]; then
case "$ACTION" in
start) start_grid ;;
stop) stop_grid ;;
restart) restart_grid ;;
*) die "$(msgf ERR_UNSUPPORTED_GRID_ACTION "$ACTION")" ;;
esac
else
case "$ACTION" in
start) start_single "$TARGET" ;;
stop) stop_single "$TARGET" ;;
restart)
stop_single "$TARGET"
sleep 3
start_single "$TARGET"
;;
*) die "$(msgf ERR_UNSUPPORTED_ACTION "$ACTION")" ;;
esac
fi
+261 -261
View File
@@ -1,262 +1,262 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=/dev/null
source "$SCRIPT_DIR/osmtool_core.sh"
usage() {
cat <<'EOF'
Usage:
osmtool_update.sh [--workdir <path>] --action <create-rollback|list-rollbacks|update-opensim|update-janus|full-update>
[--opensim-dir <path>] [--opensim-repo <url>] [--opensim-branch <name>] [--repo-mode <update|fresh>]
[--tsassets-dir <path>] [--currency-dir <path>] [--data-backup-dir <path>]
[--deploy-binaries <true|false>] [--legacy-patch-dir <path>]
[--janus-prefix <path>] [--janus-src <path>] [--public-host <host>] [--http-port <port>]
[--admin-port <port>] [--rtp-range <from-to>] [--enable-admin <true|false>]
[--api-secret <value>] [--admin-secret <value>] [--label <name>] [--dry-run <true|false>]
Examples:
osmtool_update.sh --action create-rollback --workdir /opt --label pre_update
osmtool_update.sh --action update-opensim --workdir /opt --dry-run true
EOF
print_usage_common
}
timestamp() {
date '+%Y%m%d_%H%M%S'
}
rollback_dir() {
printf '%s' "$WORKDIR/rollback"
}
ensure_rollback_dir() {
local dir
dir="$(rollback_dir)"
if mkdir -p "$dir" 2>/dev/null; then
return 0
fi
sudo mkdir -p "$dir"
sudo chown "$(id -u):$(id -g)" "$dir"
}
path_relative_to_root() {
local path="$1"
printf '%s' "${path#/}"
}
append_snapshot_path() {
local path="$1"
[[ -e "$path" ]] || return 0
SNAPSHOT_PATHS+=("$(path_relative_to_root "$path")")
}
build_opensim_snapshot_paths() {
local sim_dir
SNAPSHOT_PATHS=()
append_snapshot_path "$OPENSIM_DIR"
append_snapshot_path "$WORKDIR/robust/bin"
append_snapshot_path "$WORKDIR/standalone/bin"
shopt -s nullglob
for sim_dir in "$WORKDIR"/sim*; do
append_snapshot_path "$sim_dir/bin"
done
shopt -u nullglob
}
build_janus_snapshot_paths() {
SNAPSHOT_PATHS=()
append_snapshot_path "$JANUS_PREFIX"
append_snapshot_path "$JANUS_SRC"
}
create_snapshot_archive() {
local scope="$1"
shift
local archive_name archive_path manifest_path
local -a paths=("$@")
ensure_rollback_dir
if [[ ${#paths[@]} -eq 0 ]]; then
log WARN "No existing paths found for rollback scope: $scope"
return 0
fi
archive_name="${scope}_$(timestamp)"
if [[ -n "$LABEL" ]]; then
archive_name="${archive_name}_${LABEL}"
fi
archive_path="$(rollback_dir)/${archive_name}.tar.gz"
manifest_path="$(rollback_dir)/${archive_name}.manifest"
log INFO "Creating rollback archive: $archive_path"
printf '%s\n' "${paths[@]}" > "$manifest_path"
if [[ "$DRY_RUN" == "true" ]]; then
log INFO "[DRY-RUN] Would archive paths listed in: $manifest_path"
return 0
fi
tar -czf "$archive_path" -C / "${paths[@]}"
log INFO "Rollback archive created: $archive_path"
log INFO "Rollback manifest created: $manifest_path"
}
run_install_action() {
local install_action="$1"
local -a cmd
cmd=("$SCRIPT_DIR/osmtool_install.sh" --profile "$PROFILE" --workdir "$WORKDIR" --action "$install_action")
[[ -n "$OPENSIM_DIR" ]] && cmd+=(--opensim-dir "$OPENSIM_DIR")
[[ -n "$OPENSIM_REPO" ]] && cmd+=(--opensim-repo "$OPENSIM_REPO")
[[ -n "$OPENSIM_BRANCH" ]] && cmd+=(--opensim-branch "$OPENSIM_BRANCH")
[[ -n "$REPO_MODE" ]] && cmd+=(--repo-mode "$REPO_MODE")
[[ -n "$TSASSETS_DIR" ]] && cmd+=(--tsassets-dir "$TSASSETS_DIR")
[[ -n "$CURRENCY_DIR" ]] && cmd+=(--currency-dir "$CURRENCY_DIR")
[[ -n "$DATA_BACKUP_DIR" ]] && cmd+=(--data-backup-dir "$DATA_BACKUP_DIR")
[[ -n "$DEPLOY_BINARIES" ]] && cmd+=(--deploy-binaries "$DEPLOY_BINARIES")
[[ -n "$LEGACY_PATCH_DIR" ]] && cmd+=(--legacy-patch-dir "$LEGACY_PATCH_DIR")
[[ -n "$JANUS_PREFIX" ]] && cmd+=(--janus-prefix "$JANUS_PREFIX")
[[ -n "$JANUS_SRC" ]] && cmd+=(--janus-src "$JANUS_SRC")
[[ -n "$PUBLIC_HOST" ]] && cmd+=(--public-host "$PUBLIC_HOST")
[[ -n "$HTTP_PORT" ]] && cmd+=(--http-port "$HTTP_PORT")
[[ -n "$ADMIN_PORT" ]] && cmd+=(--admin-port "$ADMIN_PORT")
[[ -n "$RTP_RANGE" ]] && cmd+=(--rtp-range "$RTP_RANGE")
[[ -n "$ENABLE_ADMIN" ]] && cmd+=(--enable-admin "$ENABLE_ADMIN")
[[ -n "$API_SECRET" ]] && cmd+=(--api-secret "$API_SECRET")
[[ -n "$ADMIN_SECRET" ]] && cmd+=(--admin-secret "$ADMIN_SECRET")
log INFO "Delegating update to install action: $install_action"
if [[ "$DRY_RUN" == "true" ]]; then
printf -v rendered '%q ' "${cmd[@]}"
log INFO "[DRY-RUN] $rendered"
return 0
fi
"${cmd[@]}"
}
create_rollback() {
build_opensim_snapshot_paths
create_snapshot_archive opensim "${SNAPSHOT_PATHS[@]}"
build_janus_snapshot_paths
create_snapshot_archive janus "${SNAPSHOT_PATHS[@]}"
}
list_rollbacks() {
local dir
dir="$(rollback_dir)"
if [[ ! -d "$dir" ]]; then
log INFO "No rollback directory found: $dir"
return 0
fi
find "$dir" -maxdepth 1 -type f \( -name '*.tar.gz' -o -name '*.manifest' \) -printf '%T@ %p\n' 2>/dev/null | \
sort -rn | cut -d' ' -f2-
}
update_opensim() {
build_opensim_snapshot_paths
create_snapshot_archive opensim "${SNAPSHOT_PATHS[@]}"
run_install_action install-opensim
}
update_janus() {
build_janus_snapshot_paths
create_snapshot_archive janus "${SNAPSHOT_PATHS[@]}"
run_install_action install-janus
}
full_update() {
update_opensim
update_janus
}
WORKDIR="$DEFAULT_WORKDIR"
ACTION=""
PROFILE="grid-sim"
OPENSIM_DIR=""
OPENSIM_REPO=""
OPENSIM_BRANCH=""
REPO_MODE="update"
TSASSETS_DIR=""
CURRENCY_DIR=""
DATA_BACKUP_DIR=""
DEPLOY_BINARIES="true"
LEGACY_PATCH_DIR=""
JANUS_PREFIX=""
JANUS_SRC=""
PUBLIC_HOST=""
HTTP_PORT=""
ADMIN_PORT=""
RTP_RANGE=""
ENABLE_ADMIN=""
API_SECRET=""
ADMIN_SECRET=""
LABEL=""
DRY_RUN="false"
SNAPSHOT_PATHS=()
while [[ $# -gt 0 ]]; do
case "$1" in
--workdir) WORKDIR="$2"; shift 2 ;;
--profile) PROFILE="$2"; shift 2 ;;
--action) ACTION="$2"; shift 2 ;;
--opensim-dir) OPENSIM_DIR="$2"; shift 2 ;;
--opensim-repo) OPENSIM_REPO="$2"; shift 2 ;;
--opensim-branch) OPENSIM_BRANCH="$2"; shift 2 ;;
--repo-mode) REPO_MODE="$2"; shift 2 ;;
--tsassets-dir) TSASSETS_DIR="$2"; shift 2 ;;
--currency-dir) CURRENCY_DIR="$2"; shift 2 ;;
--data-backup-dir) DATA_BACKUP_DIR="$2"; shift 2 ;;
--deploy-binaries) DEPLOY_BINARIES="$2"; shift 2 ;;
--legacy-patch-dir) LEGACY_PATCH_DIR="$2"; shift 2 ;;
--janus-prefix) JANUS_PREFIX="$2"; shift 2 ;;
--janus-src) JANUS_SRC="$2"; shift 2 ;;
--public-host) PUBLIC_HOST="$2"; shift 2 ;;
--http-port) HTTP_PORT="$2"; shift 2 ;;
--admin-port) ADMIN_PORT="$2"; shift 2 ;;
--rtp-range) RTP_RANGE="$2"; shift 2 ;;
--enable-admin) ENABLE_ADMIN="$2"; shift 2 ;;
--api-secret) API_SECRET="$2"; shift 2 ;;
--admin-secret) ADMIN_SECRET="$2"; shift 2 ;;
--label) LABEL="$2"; shift 2 ;;
--dry-run) DRY_RUN="$2"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) die "Unknown option: $1" ;;
esac
done
[[ -n "$ACTION" ]] || die "Missing --action"
validate_profile "$PROFILE"
ensure_profile_action_allowed update "$PROFILE" "$ACTION"
case "$DRY_RUN" in
true|false) ;;
*) die "--dry-run must be true or false" ;;
esac
OPENSIM_DIR="${OPENSIM_DIR:-$WORKDIR/opensim}"
JANUS_PREFIX="${JANUS_PREFIX:-/opt/janus}"
JANUS_SRC="${JANUS_SRC:-$WORKDIR/janus-gateway}"
log INFO "Using profile: $PROFILE"
case "$ACTION" in
create-rollback) create_rollback ;;
list-rollbacks) list_rollbacks ;;
update-opensim) update_opensim ;;
update-janus) update_janus ;;
full-update) full_update ;;
*) die "Unsupported action: $ACTION" ;;
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# shellcheck source=/dev/null
source "$SCRIPT_DIR/osmtool_core.sh"
usage() {
cat <<'EOF'
Usage:
osmtool_update.sh [--workdir <path>] --action <create-rollback|list-rollbacks|update-opensim|update-janus|full-update>
[--opensim-dir <path>] [--opensim-repo <url>] [--opensim-branch <name>] [--repo-mode <update|fresh>]
[--tsassets-dir <path>] [--currency-dir <path>] [--data-backup-dir <path>]
[--deploy-binaries <true|false>] [--legacy-patch-dir <path>]
[--janus-prefix <path>] [--janus-src <path>] [--public-host <host>] [--http-port <port>]
[--admin-port <port>] [--rtp-range <from-to>] [--enable-admin <true|false>]
[--api-secret <value>] [--admin-secret <value>] [--label <name>] [--dry-run <true|false>]
Examples:
osmtool_update.sh --action create-rollback --workdir /opt --label pre_update
osmtool_update.sh --action update-opensim --workdir /opt --dry-run true
EOF
print_usage_common
}
timestamp() {
date '+%Y%m%d_%H%M%S'
}
rollback_dir() {
printf '%s' "$WORKDIR/rollback"
}
ensure_rollback_dir() {
local dir
dir="$(rollback_dir)"
if mkdir -p "$dir" 2>/dev/null; then
return 0
fi
sudo mkdir -p "$dir"
sudo chown "$(id -u):$(id -g)" "$dir"
}
path_relative_to_root() {
local path="$1"
printf '%s' "${path#/}"
}
append_snapshot_path() {
local path="$1"
[[ -e "$path" ]] || return 0
SNAPSHOT_PATHS+=("$(path_relative_to_root "$path")")
}
build_opensim_snapshot_paths() {
local sim_dir
SNAPSHOT_PATHS=()
append_snapshot_path "$OPENSIM_DIR"
append_snapshot_path "$WORKDIR/robust/bin"
append_snapshot_path "$WORKDIR/standalone/bin"
shopt -s nullglob
for sim_dir in "$WORKDIR"/sim*; do
append_snapshot_path "$sim_dir/bin"
done
shopt -u nullglob
}
build_janus_snapshot_paths() {
SNAPSHOT_PATHS=()
append_snapshot_path "$JANUS_PREFIX"
append_snapshot_path "$JANUS_SRC"
}
create_snapshot_archive() {
local scope="$1"
shift
local archive_name archive_path manifest_path
local -a paths=("$@")
ensure_rollback_dir
if [[ ${#paths[@]} -eq 0 ]]; then
log WARN "No existing paths found for rollback scope: $scope"
return 0
fi
archive_name="${scope}_$(timestamp)"
if [[ -n "$LABEL" ]]; then
archive_name="${archive_name}_${LABEL}"
fi
archive_path="$(rollback_dir)/${archive_name}.tar.gz"
manifest_path="$(rollback_dir)/${archive_name}.manifest"
log INFO "Creating rollback archive: $archive_path"
printf '%s\n' "${paths[@]}" > "$manifest_path"
if [[ "$DRY_RUN" == "true" ]]; then
log INFO "[DRY-RUN] Would archive paths listed in: $manifest_path"
return 0
fi
tar -czf "$archive_path" -C / "${paths[@]}"
log INFO "Rollback archive created: $archive_path"
log INFO "Rollback manifest created: $manifest_path"
}
run_install_action() {
local install_action="$1"
local -a cmd
cmd=("$SCRIPT_DIR/osmtool_install.sh" --profile "$PROFILE" --workdir "$WORKDIR" --action "$install_action")
[[ -n "$OPENSIM_DIR" ]] && cmd+=(--opensim-dir "$OPENSIM_DIR")
[[ -n "$OPENSIM_REPO" ]] && cmd+=(--opensim-repo "$OPENSIM_REPO")
[[ -n "$OPENSIM_BRANCH" ]] && cmd+=(--opensim-branch "$OPENSIM_BRANCH")
[[ -n "$REPO_MODE" ]] && cmd+=(--repo-mode "$REPO_MODE")
[[ -n "$TSASSETS_DIR" ]] && cmd+=(--tsassets-dir "$TSASSETS_DIR")
[[ -n "$CURRENCY_DIR" ]] && cmd+=(--currency-dir "$CURRENCY_DIR")
[[ -n "$DATA_BACKUP_DIR" ]] && cmd+=(--data-backup-dir "$DATA_BACKUP_DIR")
[[ -n "$DEPLOY_BINARIES" ]] && cmd+=(--deploy-binaries "$DEPLOY_BINARIES")
[[ -n "$LEGACY_PATCH_DIR" ]] && cmd+=(--legacy-patch-dir "$LEGACY_PATCH_DIR")
[[ -n "$JANUS_PREFIX" ]] && cmd+=(--janus-prefix "$JANUS_PREFIX")
[[ -n "$JANUS_SRC" ]] && cmd+=(--janus-src "$JANUS_SRC")
[[ -n "$PUBLIC_HOST" ]] && cmd+=(--public-host "$PUBLIC_HOST")
[[ -n "$HTTP_PORT" ]] && cmd+=(--http-port "$HTTP_PORT")
[[ -n "$ADMIN_PORT" ]] && cmd+=(--admin-port "$ADMIN_PORT")
[[ -n "$RTP_RANGE" ]] && cmd+=(--rtp-range "$RTP_RANGE")
[[ -n "$ENABLE_ADMIN" ]] && cmd+=(--enable-admin "$ENABLE_ADMIN")
[[ -n "$API_SECRET" ]] && cmd+=(--api-secret "$API_SECRET")
[[ -n "$ADMIN_SECRET" ]] && cmd+=(--admin-secret "$ADMIN_SECRET")
log INFO "Delegating update to install action: $install_action"
if [[ "$DRY_RUN" == "true" ]]; then
printf -v rendered '%q ' "${cmd[@]}"
log INFO "[DRY-RUN] $rendered"
return 0
fi
"${cmd[@]}"
}
create_rollback() {
build_opensim_snapshot_paths
create_snapshot_archive opensim "${SNAPSHOT_PATHS[@]}"
build_janus_snapshot_paths
create_snapshot_archive janus "${SNAPSHOT_PATHS[@]}"
}
list_rollbacks() {
local dir
dir="$(rollback_dir)"
if [[ ! -d "$dir" ]]; then
log INFO "No rollback directory found: $dir"
return 0
fi
find "$dir" -maxdepth 1 -type f \( -name '*.tar.gz' -o -name '*.manifest' \) -printf '%T@ %p\n' 2>/dev/null | \
sort -rn | cut -d' ' -f2-
}
update_opensim() {
build_opensim_snapshot_paths
create_snapshot_archive opensim "${SNAPSHOT_PATHS[@]}"
run_install_action install-opensim
}
update_janus() {
build_janus_snapshot_paths
create_snapshot_archive janus "${SNAPSHOT_PATHS[@]}"
run_install_action install-janus
}
full_update() {
update_opensim
update_janus
}
WORKDIR="$DEFAULT_WORKDIR"
ACTION=""
PROFILE="grid-sim"
OPENSIM_DIR=""
OPENSIM_REPO=""
OPENSIM_BRANCH=""
REPO_MODE="update"
TSASSETS_DIR=""
CURRENCY_DIR=""
DATA_BACKUP_DIR=""
DEPLOY_BINARIES="true"
LEGACY_PATCH_DIR=""
JANUS_PREFIX=""
JANUS_SRC=""
PUBLIC_HOST=""
HTTP_PORT=""
ADMIN_PORT=""
RTP_RANGE=""
ENABLE_ADMIN=""
API_SECRET=""
ADMIN_SECRET=""
LABEL=""
DRY_RUN="false"
SNAPSHOT_PATHS=()
while [[ $# -gt 0 ]]; do
case "$1" in
--workdir) WORKDIR="$2"; shift 2 ;;
--profile) PROFILE="$2"; shift 2 ;;
--action) ACTION="$2"; shift 2 ;;
--opensim-dir) OPENSIM_DIR="$2"; shift 2 ;;
--opensim-repo) OPENSIM_REPO="$2"; shift 2 ;;
--opensim-branch) OPENSIM_BRANCH="$2"; shift 2 ;;
--repo-mode) REPO_MODE="$2"; shift 2 ;;
--tsassets-dir) TSASSETS_DIR="$2"; shift 2 ;;
--currency-dir) CURRENCY_DIR="$2"; shift 2 ;;
--data-backup-dir) DATA_BACKUP_DIR="$2"; shift 2 ;;
--deploy-binaries) DEPLOY_BINARIES="$2"; shift 2 ;;
--legacy-patch-dir) LEGACY_PATCH_DIR="$2"; shift 2 ;;
--janus-prefix) JANUS_PREFIX="$2"; shift 2 ;;
--janus-src) JANUS_SRC="$2"; shift 2 ;;
--public-host) PUBLIC_HOST="$2"; shift 2 ;;
--http-port) HTTP_PORT="$2"; shift 2 ;;
--admin-port) ADMIN_PORT="$2"; shift 2 ;;
--rtp-range) RTP_RANGE="$2"; shift 2 ;;
--enable-admin) ENABLE_ADMIN="$2"; shift 2 ;;
--api-secret) API_SECRET="$2"; shift 2 ;;
--admin-secret) ADMIN_SECRET="$2"; shift 2 ;;
--label) LABEL="$2"; shift 2 ;;
--dry-run) DRY_RUN="$2"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) die "Unknown option: $1" ;;
esac
done
[[ -n "$ACTION" ]] || die "Missing --action"
validate_profile "$PROFILE"
ensure_profile_action_allowed update "$PROFILE" "$ACTION"
case "$DRY_RUN" in
true|false) ;;
*) die "--dry-run must be true or false" ;;
esac
OPENSIM_DIR="${OPENSIM_DIR:-$WORKDIR/opensim}"
JANUS_PREFIX="${JANUS_PREFIX:-/opt/janus}"
JANUS_SRC="${JANUS_SRC:-$WORKDIR/janus-gateway}"
log INFO "Using profile: $PROFILE"
case "$ACTION" in
create-rollback) create_rollback ;;
list-rollbacks) list_rollbacks ;;
update-opensim) update_opensim ;;
update-janus) update_janus ;;
full-update) full_update ;;
*) die "Unsupported action: $ACTION" ;;
esac
+6919 -6919
View File
File diff suppressed because it is too large Load Diff
+718 -718
View File
File diff suppressed because it is too large Load Diff
+430 -430
View File
@@ -1,430 +1,430 @@
#!/usr/bin/env bash
set -euo pipefail
BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MOD_DIR="$BASE_DIR/modular"
# shellcheck source=/dev/null
source "$MOD_DIR/osmtool_core.sh"
init_i18n
usage() {
cat <<'EOF'
Usage:
osmtool_main.sh [--mode <cli|ui>] [--lang <de|en|fr|es>] [--profile <grid-sim|robust|standalone>] --module <install|startstop|cleanup|health|backup|restore|update|config|report|smoke|cron> [module-options]
osmtool_main.sh server_install
osmtool_main.sh <configinit|install-grid-sim|opensimstart|opensimstop|opensimrestart|healthcheck|smoketest|dailyreport|croninstall|cronlist|janusinstall|janusrestart|dbsetup|dbbackup>
Examples:
osmtool_main.sh install-grid-sim
osmtool_main.sh server_install
osmtool_main.sh opensimstart
osmtool_main.sh opensimrestart
osmtool_main.sh croninstall
osmtool_main.sh dbbackup
osmtool_main.sh --module install --action prepare-ubuntu
osmtool_main.sh --module startstop --target grid --action restart --workdir /opt
osmtool_main.sh --module cleanup --action log-clean --workdir /opt
osmtool_main.sh --module health --action run --workdir /opt
osmtool_main.sh --module backup --action db-backup --db-user root --db-pass secret --db-name opensim
osmtool_main.sh --module update --action create-rollback --workdir /opt
osmtool_main.sh --module config --action validate-runtime --workdir /opt
osmtool_main.sh --module report --action generate --workdir /opt
osmtool_main.sh --module smoke --action run --profile grid-sim --workdir /opt
osmtool_main.sh --module cron --action list
osmtool_main.sh --mode ui
EOF
print_usage_common
}
dispatch_module() {
local module="$1"
shift
case "$module" in
install)
bash "$MOD_DIR/osmtool_install.sh" --profile "$PROFILE" "$@"
;;
startstop)
bash "$MOD_DIR/osmtool_startstop.sh" --profile "$PROFILE" "$@"
;;
cleanup)
bash "$MOD_DIR/osmtool_cleanup.sh" --profile "$PROFILE" "$@"
;;
health)
bash "$MOD_DIR/osmtool_health.sh" --profile "$PROFILE" "$@"
;;
backup)
bash "$MOD_DIR/osmtool_data.sh" --profile "$PROFILE" "$@"
;;
update)
bash "$MOD_DIR/osmtool_update.sh" --profile "$PROFILE" "$@"
;;
config)
bash "$MOD_DIR/osmtool_config.sh" --profile "$PROFILE" "$@"
;;
report)
bash "$MOD_DIR/osmtool_report.sh" --profile "$PROFILE" "$@"
;;
smoke)
bash "$MOD_DIR/osmtool_smoke.sh" --profile "$PROFILE" "$@"
;;
cron)
bash "$MOD_DIR/osmtool_cron.sh" --profile "$PROFILE" "$@"
;;
restore)
bash "$MOD_DIR/osmtool_restore.sh" --profile "$PROFILE" "$@"
;;
*)
die "$(msg ERR_UNKNOWN_MODULE): $module"
;;
esac
}
default_target_for_profile() {
case "$1" in
grid-sim) echo "grid" ;;
robust) echo "robust" ;;
standalone) echo "standalone" ;;
esac
}
args_have_target() {
local prev=""
local token
for token in "$@"; do
if [[ "$prev" == "--target" ]]; then
return 0
fi
prev="$token"
done
return 1
}
ui_flow() {
local module action target
PROFILE="$(show_menu "$(msg APP_TITLE)" "$(msg MENU_CHOOSE_PROFILE)" \
"grid-sim" "$(msg PROFILE_GRID_SIM)" \
"robust" "$(msg PROFILE_ROBUST)" \
"standalone" "$(msg PROFILE_STANDALONE)")"
validate_profile "$PROFILE"
module="$(show_menu "$(msg APP_TITLE)" "$(msg MENU_CHOOSE_MODULE)" \
"install" "$(msg MENU_INSTALL)" \
"startstop" "$(msg MENU_STARTSTOP)" \
"cleanup" "$(msg MENU_CLEANUP)" \
"health" "$(msg MENU_HEALTH)" \
"backup" "$(msg MENU_BACKUP)" \
"restore" "$(msg MENU_RESTORE)" \
"update" "$(msg MENU_UPDATE)" \
"config" "$(msg MENU_CONFIG)" \
"report" "$(msg MENU_REPORT)" \
"smoke" "$(msg MENU_SMOKE)" \
"cron" "$(msg MENU_CRON)")"
case "$module" in
install)
action="$(show_menu "$(msg MENU_INSTALL)" "$(msg MENU_CHOOSE_ACTION)" \
"server-check" "server-check" \
"prepare-ubuntu" "prepare-ubuntu" \
"install-opensim-deps" "install-opensim-deps" \
"install-dotnet8" "install-dotnet8" \
"install-opensim" "install-opensim" \
"configure-opensim" "configure-opensim" \
"configure-database" "configure-database" \
"compile-janus" "compile-janus" \
"configure-janus" "configure-janus" \
"install-janus" "install-janus")"
dispatch_module install --action "$action"
;;
startstop)
if [[ "$PROFILE" == "grid-sim" ]]; then
target="$(show_menu "$(msg MENU_STARTSTOP)" "$(msg MENU_CHOOSE_TARGET)" \
"grid" "$(msg TARGET_GRID)" \
"robust" "$(msg TARGET_ROBUST)" \
"sim1" "$(msg TARGET_SIM1)" \
"janus" "$(msg TARGET_JANUS)")"
elif [[ "$PROFILE" == "robust" ]]; then
target="$(show_menu "$(msg MENU_STARTSTOP)" "$(msg MENU_CHOOSE_TARGET)" \
"robust" "$(msg TARGET_ROBUST)" \
"janus" "$(msg TARGET_JANUS)")"
else
target="$(show_menu "$(msg MENU_STARTSTOP)" "$(msg MENU_CHOOSE_TARGET)" \
"standalone" "$(msg TARGET_STANDALONE)" \
"janus" "$(msg TARGET_JANUS)")"
fi
action="$(show_menu "$(msg MENU_STARTSTOP)" "$(msg MENU_CHOOSE_ACTION)" \
"start" "$(msg ACTION_START)" \
"stop" "$(msg ACTION_STOP)" \
"restart" "$(msg ACTION_RESTART)")"
dispatch_module startstop --target "$target" --action "$action"
;;
cleanup)
action="$(show_menu "$(msg MENU_CLEANUP)" "$(msg MENU_CHOOSE_ACTION)" \
"cache-clean" "$(msg ACTION_CACHE_CLEAN)" \
"log-clean" "$(msg ACTION_LOG_CLEAN)" \
"tmp-clean" "$(msg ACTION_TMP_CLEAN)" \
"reboot" "$(msg ACTION_REBOOT)")"
dispatch_module cleanup --action "$action"
;;
health)
action="$(show_menu "$(msg MENU_HEALTH)" "$(msg MENU_CHOOSE_ACTION)" \
"run" "$(msg ACTION_HEALTH_RUN)")"
dispatch_module health --action "$action"
;;
backup)
action="$(show_menu "$(msg MENU_BACKUP)" "$(msg MENU_CHOOSE_ACTION)" \
"db-backup" "$(msg ACTION_DB_BACKUP)" \
"oar-backup" "$(msg ACTION_OAR_BACKUP)" \
"full-backup" "$(msg ACTION_FULL_BACKUP)")"
dispatch_module backup --action "$action"
;;
restore)
action="$(show_menu "$(msg MENU_RESTORE)" "$(msg MENU_CHOOSE_ACTION)" \
"list-backups" "$(msg ACTION_RESTORE_LIST)" \
"db-restore" "$(msg ACTION_RESTORE_DB)" \
"oar-restore" "$(msg ACTION_RESTORE_OAR)" \
"full-restore" "$(msg ACTION_RESTORE_FULL)")"
dispatch_module restore --action "$action"
;;
update)
action="$(show_menu "$(msg MENU_UPDATE)" "$(msg MENU_CHOOSE_ACTION)" \
"create-rollback" "$(msg ACTION_UPDATE_ROLLBACK)" \
"list-rollbacks" "$(msg ACTION_UPDATE_LIST)" \
"update-opensim" "$(msg ACTION_UPDATE_OPENSIM)" \
"update-janus" "$(msg ACTION_UPDATE_JANUS)" \
"full-update" "$(msg ACTION_UPDATE_FULL)")"
dispatch_module update --action "$action"
;;
config)
action="$(show_menu "$(msg MENU_CONFIG)" "$(msg MENU_CHOOSE_ACTION)" \
"validate-file" "$(msg ACTION_CONFIG_FILE)" \
"validate-runtime" "$(msg ACTION_CONFIG_RUNTIME)")"
dispatch_module config --action "$action"
;;
report)
action="$(show_menu "$(msg MENU_REPORT)" "$(msg MENU_CHOOSE_ACTION)" \
"generate" "$(msg ACTION_REPORT_GENERATE)")"
dispatch_module report --action "$action"
;;
smoke)
action="$(show_menu "$(msg MENU_SMOKE)" "$(msg MENU_CHOOSE_ACTION)" \
"run" "$(msg ACTION_SMOKE_RUN)")"
dispatch_module smoke --action "$action"
;;
cron)
action="$(show_menu "$(msg MENU_CRON)" "$(msg MENU_CHOOSE_ACTION)" \
"install" "$(msg ACTION_CRON_INSTALL)" \
"list" "$(msg ACTION_CRON_LIST)" \
"remove" "$(msg ACTION_CRON_REMOVE)")"
dispatch_module cron --action "$action"
;;
*)
die "$(msg ERR_UNKNOWN_UI_MODULE): $module"
;;
esac
}
MODE="cli"
MODULE=""
LANG_OVERRIDE="${OSM_LANG:-$APP_LANG}"
PROFILE="grid-sim"
if [[ $# -eq 0 ]]; then
MODE="ui"
ui_flow
exit 0
fi
if [[ "${1:-}" == "h" || "${1:-}" == "help" ]]; then
usage
exit 0
fi
if [[ "${1:-}" == "server_install" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
log INFO "Running server_install shortcut (prepare-ubuntu -> install-opensim-deps -> install-dotnet8 -> server-check -> install-opensim -> configure-opensim)"
dispatch_module install --action prepare-ubuntu --workdir "$DEFAULT_WORKDIR"
dispatch_module install --action install-opensim-deps --workdir "$DEFAULT_WORKDIR"
dispatch_module install --action install-dotnet8 --workdir "$DEFAULT_WORKDIR"
dispatch_module install --action server-check --workdir "$DEFAULT_WORKDIR"
dispatch_module install --action install-opensim --workdir "$DEFAULT_WORKDIR"
dispatch_module install --action configure-opensim --workdir "$DEFAULT_WORKDIR"
exit 0
fi
if [[ "${1:-}" == "configinit" ]]; then
set_language "$LANG_OVERRIDE"
dispatch_module config --action init-config --workdir "$DEFAULT_WORKDIR"
exit 0
fi
if [[ "${1:-}" == "install-grid-sim" ]]; then
PROFILE="grid-sim"
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
# Pflichtparameter: Datenbank-Credentials und Anzahl Simulatoren
_db_user="${OSM_DB_USER:-}"
_db_pass="${OSM_DB_PASS:-}"
_sim_count="${OSM_SIM_COUNT:-1}"
_hostname="${OSM_HOST:-}"
_gridname="${OSM_GRIDNAME:-}"
if [[ -z "$_db_user" || -z "$_db_pass" ]]; then
log ERROR "Datenbankzugangsdaten fehlen. Vor dem Aufruf setzen:"
log ERROR " export OSM_DB_USER=opensim"
log ERROR " export OSM_DB_PASS='MeinSicheresPasswort'"
log ERROR " export OSM_SIM_COUNT=3 # Anzahl sim-Instanzen"
log ERROR " export OSM_HOST=1.2.3.4 # Öffentliche IP oder Hostname"
log ERROR " export OSM_GRIDNAME='Mein Grid'"
exit 1
fi
log INFO "Starte install-grid-sim (prepare-ubuntu → deps → dotnet8 → server-check → install-opensim → configure-database → configure-opensim)"
dispatch_module install --action prepare-ubuntu --workdir "$DEFAULT_WORKDIR"
dispatch_module install --action install-opensim-deps --workdir "$DEFAULT_WORKDIR"
dispatch_module install --action install-dotnet8 --workdir "$DEFAULT_WORKDIR"
dispatch_module install --action server-check --workdir "$DEFAULT_WORKDIR"
dispatch_module install --action install-opensim --workdir "$DEFAULT_WORKDIR"
# Datenbanken vor configure-opensim anlegen (ConnectionStrings werden danach geschrieben)
dispatch_module install --action configure-database --workdir "$DEFAULT_WORKDIR" \
--db-user "$_db_user" --db-pass "$_db_pass" --sim-count "$_sim_count"
# Ini-Dateien mit Credentials, Hostname und Gridname befüllen
dispatch_module install --action configure-opensim --workdir "$DEFAULT_WORKDIR" \
--db-user "$_db_user" --db-pass "$_db_pass" \
${_hostname:+--public-host "$_hostname"} \
${_gridname:+--gridname "$_gridname"}
exit 0
fi
if [[ "${1:-}" == "opensimstart" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
dispatch_module startstop --target "$(default_target_for_profile "$PROFILE")" --action start --workdir "$DEFAULT_WORKDIR"
exit 0
fi
if [[ "${1:-}" == "opensimstop" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
dispatch_module startstop --target "$(default_target_for_profile "$PROFILE")" --action stop --workdir "$DEFAULT_WORKDIR"
exit 0
fi
if [[ "${1:-}" == "opensimrestart" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
dispatch_module startstop --target "$(default_target_for_profile "$PROFILE")" --action restart --workdir "$DEFAULT_WORKDIR"
exit 0
fi
if [[ "${1:-}" == "healthcheck" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
dispatch_module health --action run --workdir "$DEFAULT_WORKDIR"
exit 0
fi
if [[ "${1:-}" == "smoketest" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
dispatch_module smoke --action run --workdir "$DEFAULT_WORKDIR"
exit 0
fi
if [[ "${1:-}" == "dailyreport" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
dispatch_module report --action generate --workdir "$DEFAULT_WORKDIR"
exit 0
fi
if [[ "${1:-}" == "croninstall" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
dispatch_module cron --action install --workdir "$DEFAULT_WORKDIR"
exit 0
fi
if [[ "${1:-}" == "cronlist" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
dispatch_module cron --action list --workdir "$DEFAULT_WORKDIR"
exit 0
fi
if [[ "${1:-}" == "janusinstall" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
dispatch_module install --action install-janus --workdir "$DEFAULT_WORKDIR"
exit 0
fi
if [[ "${1:-}" == "janusrestart" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
dispatch_module startstop --target janus --action restart --workdir "$DEFAULT_WORKDIR"
exit 0
fi
if [[ "${1:-}" == "dbsetup" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
DB_USER_SHORT="${OSM_DB_USER:-opensim}"
DB_PASS_SHORT="${OSM_DB_PASS:-}"
DB_ROOT_USER_SHORT="${OSM_DB_ROOT_USER:-root}"
DB_ROOT_PASS_SHORT="${OSM_DB_ROOT_PASS:-}"
[[ -n "$DB_PASS_SHORT" ]] || die "dbsetup requires OSM_DB_PASS environment variable"
dispatch_module install --action configure-database --workdir "$DEFAULT_WORKDIR" --db-user "$DB_USER_SHORT" --db-pass "$DB_PASS_SHORT" --db-root-user "$DB_ROOT_USER_SHORT" --db-root-pass "$DB_ROOT_PASS_SHORT"
exit 0
fi
if [[ "${1:-}" == "dbbackup" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
DB_USER_SHORT="${OSM_DB_USER:-root}"
DB_PASS_SHORT="${OSM_DB_PASS:-}"
DB_NAME_SHORT="${OSM_DB_NAME:-opensim}"
[[ -n "$DB_PASS_SHORT" ]] || die "dbbackup requires OSM_DB_PASS environment variable"
dispatch_module backup --action db-backup --workdir "$DEFAULT_WORKDIR" --db-user "$DB_USER_SHORT" --db-pass "$DB_PASS_SHORT" --db-name "$DB_NAME_SHORT"
exit 0
fi
while [[ $# -gt 0 ]]; do
case "$1" in
--mode) MODE="$2"; shift 2 ;;
--lang) LANG_OVERRIDE="$2"; shift 2 ;;
--profile) PROFILE="$2"; shift 2 ;;
--module) MODULE="$2"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) break ;;
esac
done
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
if [[ "$MODE" == "ui" ]]; then
ui_flow
exit 0
fi
[[ -n "$MODULE" ]] || die "$(msg ERR_MISSING_MODULE)"
if [[ "$MODULE" == "startstop" ]] && ! args_have_target "$@"; then
dispatch_module "$MODULE" --target "$(default_target_for_profile "$PROFILE")" "$@"
else
dispatch_module "$MODULE" "$@"
fi
#!/usr/bin/env bash
set -euo pipefail
BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
MOD_DIR="$BASE_DIR/modular"
# shellcheck source=/dev/null
source "$MOD_DIR/osmtool_core.sh"
init_i18n
usage() {
cat <<'EOF'
Usage:
osmtool_main.sh [--mode <cli|ui>] [--lang <de|en|fr|es>] [--profile <grid-sim|robust|standalone>] --module <install|startstop|cleanup|health|backup|restore|update|config|report|smoke|cron> [module-options]
osmtool_main.sh server_install
osmtool_main.sh <configinit|install-grid-sim|opensimstart|opensimstop|opensimrestart|healthcheck|smoketest|dailyreport|croninstall|cronlist|janusinstall|janusrestart|dbsetup|dbbackup>
Examples:
osmtool_main.sh install-grid-sim
osmtool_main.sh server_install
osmtool_main.sh opensimstart
osmtool_main.sh opensimrestart
osmtool_main.sh croninstall
osmtool_main.sh dbbackup
osmtool_main.sh --module install --action prepare-ubuntu
osmtool_main.sh --module startstop --target grid --action restart --workdir /opt
osmtool_main.sh --module cleanup --action log-clean --workdir /opt
osmtool_main.sh --module health --action run --workdir /opt
osmtool_main.sh --module backup --action db-backup --db-user root --db-pass secret --db-name opensim
osmtool_main.sh --module update --action create-rollback --workdir /opt
osmtool_main.sh --module config --action validate-runtime --workdir /opt
osmtool_main.sh --module report --action generate --workdir /opt
osmtool_main.sh --module smoke --action run --profile grid-sim --workdir /opt
osmtool_main.sh --module cron --action list
osmtool_main.sh --mode ui
EOF
print_usage_common
}
dispatch_module() {
local module="$1"
shift
case "$module" in
install)
bash "$MOD_DIR/osmtool_install.sh" --profile "$PROFILE" "$@"
;;
startstop)
bash "$MOD_DIR/osmtool_startstop.sh" --profile "$PROFILE" "$@"
;;
cleanup)
bash "$MOD_DIR/osmtool_cleanup.sh" --profile "$PROFILE" "$@"
;;
health)
bash "$MOD_DIR/osmtool_health.sh" --profile "$PROFILE" "$@"
;;
backup)
bash "$MOD_DIR/osmtool_data.sh" --profile "$PROFILE" "$@"
;;
update)
bash "$MOD_DIR/osmtool_update.sh" --profile "$PROFILE" "$@"
;;
config)
bash "$MOD_DIR/osmtool_config.sh" --profile "$PROFILE" "$@"
;;
report)
bash "$MOD_DIR/osmtool_report.sh" --profile "$PROFILE" "$@"
;;
smoke)
bash "$MOD_DIR/osmtool_smoke.sh" --profile "$PROFILE" "$@"
;;
cron)
bash "$MOD_DIR/osmtool_cron.sh" --profile "$PROFILE" "$@"
;;
restore)
bash "$MOD_DIR/osmtool_restore.sh" --profile "$PROFILE" "$@"
;;
*)
die "$(msg ERR_UNKNOWN_MODULE): $module"
;;
esac
}
default_target_for_profile() {
case "$1" in
grid-sim) echo "grid" ;;
robust) echo "robust" ;;
standalone) echo "standalone" ;;
esac
}
args_have_target() {
local prev=""
local token
for token in "$@"; do
if [[ "$prev" == "--target" ]]; then
return 0
fi
prev="$token"
done
return 1
}
ui_flow() {
local module action target
PROFILE="$(show_menu "$(msg APP_TITLE)" "$(msg MENU_CHOOSE_PROFILE)" \
"grid-sim" "$(msg PROFILE_GRID_SIM)" \
"robust" "$(msg PROFILE_ROBUST)" \
"standalone" "$(msg PROFILE_STANDALONE)")"
validate_profile "$PROFILE"
module="$(show_menu "$(msg APP_TITLE)" "$(msg MENU_CHOOSE_MODULE)" \
"install" "$(msg MENU_INSTALL)" \
"startstop" "$(msg MENU_STARTSTOP)" \
"cleanup" "$(msg MENU_CLEANUP)" \
"health" "$(msg MENU_HEALTH)" \
"backup" "$(msg MENU_BACKUP)" \
"restore" "$(msg MENU_RESTORE)" \
"update" "$(msg MENU_UPDATE)" \
"config" "$(msg MENU_CONFIG)" \
"report" "$(msg MENU_REPORT)" \
"smoke" "$(msg MENU_SMOKE)" \
"cron" "$(msg MENU_CRON)")"
case "$module" in
install)
action="$(show_menu "$(msg MENU_INSTALL)" "$(msg MENU_CHOOSE_ACTION)" \
"server-check" "server-check" \
"prepare-ubuntu" "prepare-ubuntu" \
"install-opensim-deps" "install-opensim-deps" \
"install-dotnet8" "install-dotnet8" \
"install-opensim" "install-opensim" \
"configure-opensim" "configure-opensim" \
"configure-database" "configure-database" \
"compile-janus" "compile-janus" \
"configure-janus" "configure-janus" \
"install-janus" "install-janus")"
dispatch_module install --action "$action"
;;
startstop)
if [[ "$PROFILE" == "grid-sim" ]]; then
target="$(show_menu "$(msg MENU_STARTSTOP)" "$(msg MENU_CHOOSE_TARGET)" \
"grid" "$(msg TARGET_GRID)" \
"robust" "$(msg TARGET_ROBUST)" \
"sim1" "$(msg TARGET_SIM1)" \
"janus" "$(msg TARGET_JANUS)")"
elif [[ "$PROFILE" == "robust" ]]; then
target="$(show_menu "$(msg MENU_STARTSTOP)" "$(msg MENU_CHOOSE_TARGET)" \
"robust" "$(msg TARGET_ROBUST)" \
"janus" "$(msg TARGET_JANUS)")"
else
target="$(show_menu "$(msg MENU_STARTSTOP)" "$(msg MENU_CHOOSE_TARGET)" \
"standalone" "$(msg TARGET_STANDALONE)" \
"janus" "$(msg TARGET_JANUS)")"
fi
action="$(show_menu "$(msg MENU_STARTSTOP)" "$(msg MENU_CHOOSE_ACTION)" \
"start" "$(msg ACTION_START)" \
"stop" "$(msg ACTION_STOP)" \
"restart" "$(msg ACTION_RESTART)")"
dispatch_module startstop --target "$target" --action "$action"
;;
cleanup)
action="$(show_menu "$(msg MENU_CLEANUP)" "$(msg MENU_CHOOSE_ACTION)" \
"cache-clean" "$(msg ACTION_CACHE_CLEAN)" \
"log-clean" "$(msg ACTION_LOG_CLEAN)" \
"tmp-clean" "$(msg ACTION_TMP_CLEAN)" \
"reboot" "$(msg ACTION_REBOOT)")"
dispatch_module cleanup --action "$action"
;;
health)
action="$(show_menu "$(msg MENU_HEALTH)" "$(msg MENU_CHOOSE_ACTION)" \
"run" "$(msg ACTION_HEALTH_RUN)")"
dispatch_module health --action "$action"
;;
backup)
action="$(show_menu "$(msg MENU_BACKUP)" "$(msg MENU_CHOOSE_ACTION)" \
"db-backup" "$(msg ACTION_DB_BACKUP)" \
"oar-backup" "$(msg ACTION_OAR_BACKUP)" \
"full-backup" "$(msg ACTION_FULL_BACKUP)")"
dispatch_module backup --action "$action"
;;
restore)
action="$(show_menu "$(msg MENU_RESTORE)" "$(msg MENU_CHOOSE_ACTION)" \
"list-backups" "$(msg ACTION_RESTORE_LIST)" \
"db-restore" "$(msg ACTION_RESTORE_DB)" \
"oar-restore" "$(msg ACTION_RESTORE_OAR)" \
"full-restore" "$(msg ACTION_RESTORE_FULL)")"
dispatch_module restore --action "$action"
;;
update)
action="$(show_menu "$(msg MENU_UPDATE)" "$(msg MENU_CHOOSE_ACTION)" \
"create-rollback" "$(msg ACTION_UPDATE_ROLLBACK)" \
"list-rollbacks" "$(msg ACTION_UPDATE_LIST)" \
"update-opensim" "$(msg ACTION_UPDATE_OPENSIM)" \
"update-janus" "$(msg ACTION_UPDATE_JANUS)" \
"full-update" "$(msg ACTION_UPDATE_FULL)")"
dispatch_module update --action "$action"
;;
config)
action="$(show_menu "$(msg MENU_CONFIG)" "$(msg MENU_CHOOSE_ACTION)" \
"validate-file" "$(msg ACTION_CONFIG_FILE)" \
"validate-runtime" "$(msg ACTION_CONFIG_RUNTIME)")"
dispatch_module config --action "$action"
;;
report)
action="$(show_menu "$(msg MENU_REPORT)" "$(msg MENU_CHOOSE_ACTION)" \
"generate" "$(msg ACTION_REPORT_GENERATE)")"
dispatch_module report --action "$action"
;;
smoke)
action="$(show_menu "$(msg MENU_SMOKE)" "$(msg MENU_CHOOSE_ACTION)" \
"run" "$(msg ACTION_SMOKE_RUN)")"
dispatch_module smoke --action "$action"
;;
cron)
action="$(show_menu "$(msg MENU_CRON)" "$(msg MENU_CHOOSE_ACTION)" \
"install" "$(msg ACTION_CRON_INSTALL)" \
"list" "$(msg ACTION_CRON_LIST)" \
"remove" "$(msg ACTION_CRON_REMOVE)")"
dispatch_module cron --action "$action"
;;
*)
die "$(msg ERR_UNKNOWN_UI_MODULE): $module"
;;
esac
}
MODE="cli"
MODULE=""
LANG_OVERRIDE="${OSM_LANG:-$APP_LANG}"
PROFILE="grid-sim"
if [[ $# -eq 0 ]]; then
MODE="ui"
ui_flow
exit 0
fi
if [[ "${1:-}" == "h" || "${1:-}" == "help" ]]; then
usage
exit 0
fi
if [[ "${1:-}" == "server_install" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
log INFO "Running server_install shortcut (prepare-ubuntu -> install-opensim-deps -> install-dotnet8 -> server-check -> install-opensim -> configure-opensim)"
dispatch_module install --action prepare-ubuntu --workdir "$DEFAULT_WORKDIR"
dispatch_module install --action install-opensim-deps --workdir "$DEFAULT_WORKDIR"
dispatch_module install --action install-dotnet8 --workdir "$DEFAULT_WORKDIR"
dispatch_module install --action server-check --workdir "$DEFAULT_WORKDIR"
dispatch_module install --action install-opensim --workdir "$DEFAULT_WORKDIR"
dispatch_module install --action configure-opensim --workdir "$DEFAULT_WORKDIR"
exit 0
fi
if [[ "${1:-}" == "configinit" ]]; then
set_language "$LANG_OVERRIDE"
dispatch_module config --action init-config --workdir "$DEFAULT_WORKDIR"
exit 0
fi
if [[ "${1:-}" == "install-grid-sim" ]]; then
PROFILE="grid-sim"
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
# Pflichtparameter: Datenbank-Credentials und Anzahl Simulatoren
_db_user="${OSM_DB_USER:-}"
_db_pass="${OSM_DB_PASS:-}"
_sim_count="${OSM_SIM_COUNT:-1}"
_hostname="${OSM_HOST:-}"
_gridname="${OSM_GRIDNAME:-}"
if [[ -z "$_db_user" || -z "$_db_pass" ]]; then
log ERROR "Datenbankzugangsdaten fehlen. Vor dem Aufruf setzen:"
log ERROR " export OSM_DB_USER=opensim"
log ERROR " export OSM_DB_PASS='MeinSicheresPasswort'"
log ERROR " export OSM_SIM_COUNT=3 # Anzahl sim-Instanzen"
log ERROR " export OSM_HOST=1.2.3.4 # Öffentliche IP oder Hostname"
log ERROR " export OSM_GRIDNAME='Mein Grid'"
exit 1
fi
log INFO "Starte install-grid-sim (prepare-ubuntu → deps → dotnet8 → server-check → install-opensim → configure-database → configure-opensim)"
dispatch_module install --action prepare-ubuntu --workdir "$DEFAULT_WORKDIR"
dispatch_module install --action install-opensim-deps --workdir "$DEFAULT_WORKDIR"
dispatch_module install --action install-dotnet8 --workdir "$DEFAULT_WORKDIR"
dispatch_module install --action server-check --workdir "$DEFAULT_WORKDIR"
dispatch_module install --action install-opensim --workdir "$DEFAULT_WORKDIR"
# Datenbanken vor configure-opensim anlegen (ConnectionStrings werden danach geschrieben)
dispatch_module install --action configure-database --workdir "$DEFAULT_WORKDIR" \
--db-user "$_db_user" --db-pass "$_db_pass" --sim-count "$_sim_count"
# Ini-Dateien mit Credentials, Hostname und Gridname befüllen
dispatch_module install --action configure-opensim --workdir "$DEFAULT_WORKDIR" \
--db-user "$_db_user" --db-pass "$_db_pass" \
${_hostname:+--public-host "$_hostname"} \
${_gridname:+--gridname "$_gridname"}
exit 0
fi
if [[ "${1:-}" == "opensimstart" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
dispatch_module startstop --target "$(default_target_for_profile "$PROFILE")" --action start --workdir "$DEFAULT_WORKDIR"
exit 0
fi
if [[ "${1:-}" == "opensimstop" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
dispatch_module startstop --target "$(default_target_for_profile "$PROFILE")" --action stop --workdir "$DEFAULT_WORKDIR"
exit 0
fi
if [[ "${1:-}" == "opensimrestart" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
dispatch_module startstop --target "$(default_target_for_profile "$PROFILE")" --action restart --workdir "$DEFAULT_WORKDIR"
exit 0
fi
if [[ "${1:-}" == "healthcheck" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
dispatch_module health --action run --workdir "$DEFAULT_WORKDIR"
exit 0
fi
if [[ "${1:-}" == "smoketest" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
dispatch_module smoke --action run --workdir "$DEFAULT_WORKDIR"
exit 0
fi
if [[ "${1:-}" == "dailyreport" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
dispatch_module report --action generate --workdir "$DEFAULT_WORKDIR"
exit 0
fi
if [[ "${1:-}" == "croninstall" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
dispatch_module cron --action install --workdir "$DEFAULT_WORKDIR"
exit 0
fi
if [[ "${1:-}" == "cronlist" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
dispatch_module cron --action list --workdir "$DEFAULT_WORKDIR"
exit 0
fi
if [[ "${1:-}" == "janusinstall" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
dispatch_module install --action install-janus --workdir "$DEFAULT_WORKDIR"
exit 0
fi
if [[ "${1:-}" == "janusrestart" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
dispatch_module startstop --target janus --action restart --workdir "$DEFAULT_WORKDIR"
exit 0
fi
if [[ "${1:-}" == "dbsetup" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
DB_USER_SHORT="${OSM_DB_USER:-opensim}"
DB_PASS_SHORT="${OSM_DB_PASS:-}"
DB_ROOT_USER_SHORT="${OSM_DB_ROOT_USER:-root}"
DB_ROOT_PASS_SHORT="${OSM_DB_ROOT_PASS:-}"
[[ -n "$DB_PASS_SHORT" ]] || die "dbsetup requires OSM_DB_PASS environment variable"
dispatch_module install --action configure-database --workdir "$DEFAULT_WORKDIR" --db-user "$DB_USER_SHORT" --db-pass "$DB_PASS_SHORT" --db-root-user "$DB_ROOT_USER_SHORT" --db-root-pass "$DB_ROOT_PASS_SHORT"
exit 0
fi
if [[ "${1:-}" == "dbbackup" ]]; then
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
DB_USER_SHORT="${OSM_DB_USER:-root}"
DB_PASS_SHORT="${OSM_DB_PASS:-}"
DB_NAME_SHORT="${OSM_DB_NAME:-opensim}"
[[ -n "$DB_PASS_SHORT" ]] || die "dbbackup requires OSM_DB_PASS environment variable"
dispatch_module backup --action db-backup --workdir "$DEFAULT_WORKDIR" --db-user "$DB_USER_SHORT" --db-pass "$DB_PASS_SHORT" --db-name "$DB_NAME_SHORT"
exit 0
fi
while [[ $# -gt 0 ]]; do
case "$1" in
--mode) MODE="$2"; shift 2 ;;
--lang) LANG_OVERRIDE="$2"; shift 2 ;;
--profile) PROFILE="$2"; shift 2 ;;
--module) MODULE="$2"; shift 2 ;;
--help|-h) usage; exit 0 ;;
*) break ;;
esac
done
set_language "$LANG_OVERRIDE"
validate_profile "$PROFILE"
if [[ "$MODE" == "ui" ]]; then
ui_flow
exit 0
fi
[[ -n "$MODULE" ]] || die "$(msg ERR_MISSING_MODULE)"
if [[ "$MODULE" == "startstop" ]] && ! args_have_target "$@"; then
dispatch_module "$MODULE" --target "$(default_target_for_profile "$PROFILE")" "$@"
else
dispatch_module "$MODULE" "$@"
fi
+269 -269
View File
@@ -1,270 +1,270 @@
#!/bin/bash
#* WARTEZEITEN muessen leider sein damit der Server nicht überfordert wird.
Simulator_Start_wait=15 # Sekunden
MoneyServer_Start_wait=30 # Sekunden
RobustServer_Start_wait=30 # Sekunden
Simulator_Stop_wait=15 # Sekunden
MoneyServer_Stop_wait=30 # Sekunden
RobustServer_Stop_wait=30 # Sekunden
#?──────────────────────────────────────────────────────────────────────────────────────────
#* Start Stop Grid
#?──────────────────────────────────────────────────────────────────────────────────────────
function opensimstart() {
echo "${SYM_WAIT} ${COLOR_START}Starte das Grid!${COLOR_RESET}"
# 1. RobustServer (muss zuerst laufen)
if [[ -d "robust/bin" && -f "robust/bin/Robust.dll" ]]; then
echo "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}RobustServer ${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}robust/bin...${COLOR_RESET}"
(cd robust/bin && screen -fa -S robustserver -d -U -m dotnet Robust.dll)
sleep "$RobustServer_Start_wait"
else
echo "${SYM_BAD} ${COLOR_SERVER}RobustServer: ${COLOR_BAD}Robust.dll nicht gefunden.${COLOR_RESET} ${COLOR_START}Überspringe Start.${COLOR_RESET}"
fi
# 2. MoneyServer (optional)
if [[ -f "robust/bin/MoneyServer.dll" ]]; then
echo "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}MoneyServer${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}robust/bin...${COLOR_RESET}"
(cd robust/bin && screen -fa -S moneyserver -d -U -m dotnet MoneyServer.dll)
sleep "$MoneyServer_Start_wait"
fi
# 3. SIM1 ZUERST (sequentiell)
if [[ -d "sim1/bin" && -f "sim1/bin/OpenSim.dll" ]]; then
echo "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}sim1${COLOR_RESET} ${COLOR_START}(primäre Region)...${COLOR_RESET}"
(cd sim1/bin && screen -fa -S sim1 -d -U -m dotnet OpenSim.dll)
sleep "$Simulator_Start_wait"
else
echo "${SYM_BAD} ${COLOR_SERVER}sim1: ${COLOR_BAD}OpenSim.dll nicht gefunden.${COLOR_RESET}"
fi
# 4. SIM2-SIM99 PARALLEL
echo "${SYM_INFO} ${COLOR_START}Starte sekundäre Simulatoren parallel...${COLOR_RESET}"
# Maximal 10 parallele Jobs
MAX_JOBS=10
for ((i=2; i<=99; i++)); do
sim_dir="sim$i/bin"
if [[ -d "$sim_dir" && -f "$sim_dir/OpenSim.dll" ]]; then
# Warten falls zu viele Jobs laufen
while (( $(jobs -p | wc -l) >= MAX_JOBS )); do
sleep 1
done
echo "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}sim$i${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}$sim_dir...${COLOR_RESET}"
(cd "$sim_dir" && screen -fa -S "sim$i" -d -U -m dotnet OpenSim.dll) &
fi
done
wait # Warte auf alle Hintergrundjobs
echo "${SYM_OK} ${COLOR_START}Alle Simulatoren gestartet.${COLOR_RESET}"
echo .
}
function opensimstop() {
echo "${SYM_WAIT} ${COLOR_STOP}Stoppe das Grid!${COLOR_RESET}"
local MAX_PARALLEL=10 # Maximale parallele Stopp-Vorgänge
# 1. Paralleles Stoppen von sim999 bis sim2
echo "${SYM_INFO} ${COLOR_STOP}Stoppe sekundäre Simulatoren parallel...${COLOR_RESET}"
for ((i=999; i>=2; i--)); do
sim_name="sim$i"
# Warten falls zu viele parallele Jobs laufen
#while [ $(jobs -p | wc -l) -ge $MAX_PARALLEL ]; do
while [ "$(jobs -p | wc -l)" -ge $MAX_PARALLEL ]; do
sleep 0.5
done
if screen -list | grep -q "$sim_name"; then
echo "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}$sim_name${COLOR_RESET}"
(
screen -S "$sim_name" -p 0 -X stuff "shutdown^M"
sleep $Simulator_Stop_wait
) &
fi
done
wait # Warte auf alle parallelen Stopp-Vorgänge
# 2. Sim1 sequentiell stoppen
if screen -list | grep -q "sim1"; then
echo "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}sim1${COLOR_RESET} ${COLOR_STOP}(primäre Region)...${COLOR_RESET}"
screen -S "sim1" -p 0 -X stuff "shutdown^M"
sleep $Simulator_Stop_wait
fi
# 3. MoneyServer stoppen
if screen -list | grep -q "moneyserver"; then
echo "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}MoneyServer${COLOR_RESET} ${COLOR_STOP}...${COLOR_RESET}"
screen -S moneyserver -p 0 -X stuff "shutdown^M"
sleep $MoneyServer_Stop_wait
else
echo "${SYM_BAD} ${COLOR_SERVER}MoneyServer: ${COLOR_BAD}Läuft nicht.${COLOR_RESET}"
fi
# 4. RobustServer stoppen (zuletzt)
if screen -list | grep -q "robustserver"; then
echo "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}RobustServer${COLOR_RESET} ${COLOR_STOP}...${COLOR_RESET}"
screen -S robustserver -p 0 -X stuff "shutdown^M"
sleep $RobustServer_Stop_wait
else
echo "${SYM_BAD} ${COLOR_SERVER}RobustServer: ${COLOR_BAD}Läuft nicht.${COLOR_RESET}"
fi
echo "${SYM_OK} ${COLOR_STOP}Alle Dienste gestoppt.${COLOR_RESET}"
echo .
}
# check_screens ist eine Grid Funktion und funktioniert nicht im Standalone.
# bash osmtool_backup.sh check_screens
function check_screens() {
# echo "Überprüfung der laufenden OpenSim-Prozesse..."
restart_all=false
# Überprüfen, ob RobustServer läuft
if [[ -d "robust/bin" && -f "robust/bin/Robust.dll" ]]; then
screenRO=$(screen -ls | grep -w "robustserver")
if [[ -z "$screenRO" ]]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - RobustServer läuft nicht und muss neu gestartet werden." >> ProblemRestarts.log
restart_all=true
fi
fi
# Überprüfen, ob MoneyServer läuft
if [[ -d "robust/bin" && -f "robust/bin/MoneyServer.dll" ]];then
screenMoney=$(screen -ls | grep -w "moneyserver")
if [[ -z "$screenMoney" ]]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - MoneyServer läuft nicht und muss neu gestartet werden." >> ProblemRestarts.log
restart_all=true
fi
fi
# Überprüfen, ob sim1 läuft
if [[ -d "sim1/bin" && -f "sim1/bin/OpenSim.dll" ]]; then
screenSim1=$(screen -ls | grep -w "sim1")
if [[ -z "$screenSim1" ]]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - Sim1 läuft nicht und muss neu gestartet werden." >> ProblemRestarts.log
restart_all=true
fi
fi
# Falls eines der kritischen Systeme ausgefallen ist, alles neu starten
if [[ "$restart_all" == true ]]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - Kritische Prozesse sind ausgefallen! OpenSim wird komplett neu gestartet." >> ProblemRestarts.log
# opensimstart
opensimrestart
return 0
fi
# Überprüfen, ob andere Regionen (sim2 bis sim999) einzeln neu gestartet werden müssen
for ((i=2; i<=999; i++)); do
sim_dir="sim$i/bin"
if [[ -d "$sim_dir" && -f "$sim_dir/OpenSim.dll" ]]; then
screenSim=$(screen -ls | grep -w "sim$i")
if [[ -z "$screenSim" ]]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - Sim$i läuft nicht und wird einzeln neu gestartet." >> ProblemRestarts.log
cd "$sim_dir" || continue
screen -fa -S "sim$i" -d -U -m dotnet OpenSim.dll
cd - >/dev/null 2>&1 || continue
sleep $Simulator_Start_wait
fi
fi
done
echo .
}
# Neu Test
function check_screens_neu() {
echo "${SYM_WAIT} ${COLOR_START}Überprüfe laufende OpenSim-Prozesse...${COLOR_RESET}"
restart_all=false
log_file="ProblemRestarts.log"
timestamp="$(date '+%Y-%m-%d %H:%M:%S')"
# Funktion zum Screen-Check
function screen_running() {
screen -ls | grep -qw "$1"
}
# RobustServer prüfen
if [[ -d "robust/bin" && -f "robust/bin/Robust.dll" ]]; then
if ! screen_running "robustserver"; then
echo "$timestamp - RobustServer läuft nicht." >> "$log_file"
restart_all=true
fi
fi
# MoneyServer prüfen
if [[ -f "robust/bin/MoneyServer.dll" ]]; then
if ! screen_running "moneyserver"; then
echo "$timestamp - MoneyServer läuft nicht." >> "$log_file"
restart_all=true
fi
fi
# sim1 prüfen
if [[ -d "sim1/bin" && -f "sim1/bin/OpenSim.dll" ]]; then
if ! screen_running "sim1"; then
echo "$timestamp - sim1 läuft nicht." >> "$log_file"
restart_all=true
fi
fi
# Falls kritische Komponenten fehlen → kompletten Neustart
if [[ "$restart_all" == true ]]; then
echo "$timestamp - Kritische Komponenten fehlen. Starte das gesamte Grid neu." >> "$log_file"
opensimrestart
return 0
fi
# sim2 bis sim999 einzeln prüfen und ggf. neu starten
for ((i=2; i<=999; i++)); do
sim_dir="sim$i/bin"
if [[ -d "$sim_dir" && -f "$sim_dir/OpenSim.dll" ]]; then
if ! screen_running "sim$i"; then
echo "$timestamp - sim$i läuft nicht. Starte Region neu." >> "$log_file"
cd "$sim_dir" || continue
screen -fa -S "sim$i" -d -U -m dotnet OpenSim.dll
cd - >/dev/null 2>&1 || continue
sleep $Simulator_Start_wait
fi
fi
done
echo "${SYM_OK} ${COLOR_START}Überprüfung abgeschlossen.${COLOR_RESET}"
screen -ls || echo "Keine Screen-Sessions gefunden"
}
function opensimrestart() {
opensimstop
sleep $Simulator_Stop_wait # Wartezeit für Dienst-Stopp
opensimstart
screen -ls || echo "Keine Screen-Sessions gefunden"
}
KOMMANDO="$1"
case $KOMMANDO in
"start")
opensimstart
;;
"stop")
opensimstop
;;
"restart")
opensimrestart
;;
"check_screens")
check_screens_neu
;;
*)
opensimrestart
;;
esac
#!/bin/bash
#* WARTEZEITEN muessen leider sein damit der Server nicht überfordert wird.
Simulator_Start_wait=15 # Sekunden
MoneyServer_Start_wait=30 # Sekunden
RobustServer_Start_wait=30 # Sekunden
Simulator_Stop_wait=15 # Sekunden
MoneyServer_Stop_wait=30 # Sekunden
RobustServer_Stop_wait=30 # Sekunden
#?──────────────────────────────────────────────────────────────────────────────────────────
#* Start Stop Grid
#?──────────────────────────────────────────────────────────────────────────────────────────
function opensimstart() {
echo "${SYM_WAIT} ${COLOR_START}Starte das Grid!${COLOR_RESET}"
# 1. RobustServer (muss zuerst laufen)
if [[ -d "robust/bin" && -f "robust/bin/Robust.dll" ]]; then
echo "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}RobustServer ${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}robust/bin...${COLOR_RESET}"
(cd robust/bin && screen -fa -S robustserver -d -U -m dotnet Robust.dll)
sleep "$RobustServer_Start_wait"
else
echo "${SYM_BAD} ${COLOR_SERVER}RobustServer: ${COLOR_BAD}Robust.dll nicht gefunden.${COLOR_RESET} ${COLOR_START}Überspringe Start.${COLOR_RESET}"
fi
# 2. MoneyServer (optional)
if [[ -f "robust/bin/MoneyServer.dll" ]]; then
echo "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}MoneyServer${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}robust/bin...${COLOR_RESET}"
(cd robust/bin && screen -fa -S moneyserver -d -U -m dotnet MoneyServer.dll)
sleep "$MoneyServer_Start_wait"
fi
# 3. SIM1 ZUERST (sequentiell)
if [[ -d "sim1/bin" && -f "sim1/bin/OpenSim.dll" ]]; then
echo "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}sim1${COLOR_RESET} ${COLOR_START}(primäre Region)...${COLOR_RESET}"
(cd sim1/bin && screen -fa -S sim1 -d -U -m dotnet OpenSim.dll)
sleep "$Simulator_Start_wait"
else
echo "${SYM_BAD} ${COLOR_SERVER}sim1: ${COLOR_BAD}OpenSim.dll nicht gefunden.${COLOR_RESET}"
fi
# 4. SIM2-SIM99 PARALLEL
echo "${SYM_INFO} ${COLOR_START}Starte sekundäre Simulatoren parallel...${COLOR_RESET}"
# Maximal 10 parallele Jobs
MAX_JOBS=10
for ((i=2; i<=99; i++)); do
sim_dir="sim$i/bin"
if [[ -d "$sim_dir" && -f "$sim_dir/OpenSim.dll" ]]; then
# Warten falls zu viele Jobs laufen
while (( $(jobs -p | wc -l) >= MAX_JOBS )); do
sleep 1
done
echo "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}sim$i${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}$sim_dir...${COLOR_RESET}"
(cd "$sim_dir" && screen -fa -S "sim$i" -d -U -m dotnet OpenSim.dll) &
fi
done
wait # Warte auf alle Hintergrundjobs
echo "${SYM_OK} ${COLOR_START}Alle Simulatoren gestartet.${COLOR_RESET}"
echo .
}
function opensimstop() {
echo "${SYM_WAIT} ${COLOR_STOP}Stoppe das Grid!${COLOR_RESET}"
local MAX_PARALLEL=10 # Maximale parallele Stopp-Vorgänge
# 1. Paralleles Stoppen von sim999 bis sim2
echo "${SYM_INFO} ${COLOR_STOP}Stoppe sekundäre Simulatoren parallel...${COLOR_RESET}"
for ((i=999; i>=2; i--)); do
sim_name="sim$i"
# Warten falls zu viele parallele Jobs laufen
#while [ $(jobs -p | wc -l) -ge $MAX_PARALLEL ]; do
while [ "$(jobs -p | wc -l)" -ge $MAX_PARALLEL ]; do
sleep 0.5
done
if screen -list | grep -q "$sim_name"; then
echo "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}$sim_name${COLOR_RESET}"
(
screen -S "$sim_name" -p 0 -X stuff "shutdown^M"
sleep $Simulator_Stop_wait
) &
fi
done
wait # Warte auf alle parallelen Stopp-Vorgänge
# 2. Sim1 sequentiell stoppen
if screen -list | grep -q "sim1"; then
echo "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}sim1${COLOR_RESET} ${COLOR_STOP}(primäre Region)...${COLOR_RESET}"
screen -S "sim1" -p 0 -X stuff "shutdown^M"
sleep $Simulator_Stop_wait
fi
# 3. MoneyServer stoppen
if screen -list | grep -q "moneyserver"; then
echo "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}MoneyServer${COLOR_RESET} ${COLOR_STOP}...${COLOR_RESET}"
screen -S moneyserver -p 0 -X stuff "shutdown^M"
sleep $MoneyServer_Stop_wait
else
echo "${SYM_BAD} ${COLOR_SERVER}MoneyServer: ${COLOR_BAD}Läuft nicht.${COLOR_RESET}"
fi
# 4. RobustServer stoppen (zuletzt)
if screen -list | grep -q "robustserver"; then
echo "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}RobustServer${COLOR_RESET} ${COLOR_STOP}...${COLOR_RESET}"
screen -S robustserver -p 0 -X stuff "shutdown^M"
sleep $RobustServer_Stop_wait
else
echo "${SYM_BAD} ${COLOR_SERVER}RobustServer: ${COLOR_BAD}Läuft nicht.${COLOR_RESET}"
fi
echo "${SYM_OK} ${COLOR_STOP}Alle Dienste gestoppt.${COLOR_RESET}"
echo .
}
# check_screens ist eine Grid Funktion und funktioniert nicht im Standalone.
# bash osmtool_backup.sh check_screens
function check_screens() {
# echo "Überprüfung der laufenden OpenSim-Prozesse..."
restart_all=false
# Überprüfen, ob RobustServer läuft
if [[ -d "robust/bin" && -f "robust/bin/Robust.dll" ]]; then
screenRO=$(screen -ls | grep -w "robustserver")
if [[ -z "$screenRO" ]]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - RobustServer läuft nicht und muss neu gestartet werden." >> ProblemRestarts.log
restart_all=true
fi
fi
# Überprüfen, ob MoneyServer läuft
if [[ -d "robust/bin" && -f "robust/bin/MoneyServer.dll" ]];then
screenMoney=$(screen -ls | grep -w "moneyserver")
if [[ -z "$screenMoney" ]]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - MoneyServer läuft nicht und muss neu gestartet werden." >> ProblemRestarts.log
restart_all=true
fi
fi
# Überprüfen, ob sim1 läuft
if [[ -d "sim1/bin" && -f "sim1/bin/OpenSim.dll" ]]; then
screenSim1=$(screen -ls | grep -w "sim1")
if [[ -z "$screenSim1" ]]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - Sim1 läuft nicht und muss neu gestartet werden." >> ProblemRestarts.log
restart_all=true
fi
fi
# Falls eines der kritischen Systeme ausgefallen ist, alles neu starten
if [[ "$restart_all" == true ]]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - Kritische Prozesse sind ausgefallen! OpenSim wird komplett neu gestartet." >> ProblemRestarts.log
# opensimstart
opensimrestart
return 0
fi
# Überprüfen, ob andere Regionen (sim2 bis sim999) einzeln neu gestartet werden müssen
for ((i=2; i<=999; i++)); do
sim_dir="sim$i/bin"
if [[ -d "$sim_dir" && -f "$sim_dir/OpenSim.dll" ]]; then
screenSim=$(screen -ls | grep -w "sim$i")
if [[ -z "$screenSim" ]]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') - Sim$i läuft nicht und wird einzeln neu gestartet." >> ProblemRestarts.log
cd "$sim_dir" || continue
screen -fa -S "sim$i" -d -U -m dotnet OpenSim.dll
cd - >/dev/null 2>&1 || continue
sleep $Simulator_Start_wait
fi
fi
done
echo .
}
# Neu Test
function check_screens_neu() {
echo "${SYM_WAIT} ${COLOR_START}Überprüfe laufende OpenSim-Prozesse...${COLOR_RESET}"
restart_all=false
log_file="ProblemRestarts.log"
timestamp="$(date '+%Y-%m-%d %H:%M:%S')"
# Funktion zum Screen-Check
function screen_running() {
screen -ls | grep -qw "$1"
}
# RobustServer prüfen
if [[ -d "robust/bin" && -f "robust/bin/Robust.dll" ]]; then
if ! screen_running "robustserver"; then
echo "$timestamp - RobustServer läuft nicht." >> "$log_file"
restart_all=true
fi
fi
# MoneyServer prüfen
if [[ -f "robust/bin/MoneyServer.dll" ]]; then
if ! screen_running "moneyserver"; then
echo "$timestamp - MoneyServer läuft nicht." >> "$log_file"
restart_all=true
fi
fi
# sim1 prüfen
if [[ -d "sim1/bin" && -f "sim1/bin/OpenSim.dll" ]]; then
if ! screen_running "sim1"; then
echo "$timestamp - sim1 läuft nicht." >> "$log_file"
restart_all=true
fi
fi
# Falls kritische Komponenten fehlen → kompletten Neustart
if [[ "$restart_all" == true ]]; then
echo "$timestamp - Kritische Komponenten fehlen. Starte das gesamte Grid neu." >> "$log_file"
opensimrestart
return 0
fi
# sim2 bis sim999 einzeln prüfen und ggf. neu starten
for ((i=2; i<=999; i++)); do
sim_dir="sim$i/bin"
if [[ -d "$sim_dir" && -f "$sim_dir/OpenSim.dll" ]]; then
if ! screen_running "sim$i"; then
echo "$timestamp - sim$i läuft nicht. Starte Region neu." >> "$log_file"
cd "$sim_dir" || continue
screen -fa -S "sim$i" -d -U -m dotnet OpenSim.dll
cd - >/dev/null 2>&1 || continue
sleep $Simulator_Start_wait
fi
fi
done
echo "${SYM_OK} ${COLOR_START}Überprüfung abgeschlossen.${COLOR_RESET}"
screen -ls || echo "Keine Screen-Sessions gefunden"
}
function opensimrestart() {
opensimstop
sleep $Simulator_Stop_wait # Wartezeit für Dienst-Stopp
opensimstart
screen -ls || echo "Keine Screen-Sessions gefunden"
}
KOMMANDO="$1"
case $KOMMANDO in
"start")
opensimstart
;;
"stop")
opensimstop
;;
"restart")
opensimrestart
;;
"check_screens")
check_screens_neu
;;
*)
opensimrestart
;;
esac
# Ende des Skripts
+42 -42
View File
@@ -1,42 +1,42 @@
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
MAIN_SCRIPT="$PROJECT_ROOT/osmtool_main.sh"
if [[ ! -x "$MAIN_SCRIPT" ]]; then
echo "ERROR: osmtool_main.sh not executable: $MAIN_SCRIPT" >&2
exit 1
fi
MODULE="${1:-}"
ACTION="${2:-}"
PROFILE="${3:-grid-sim}"
LANG="${4:-de}"
WORKDIR="${5:-/opt}"
shift $(( $# >= 5 ? 5 : $# ))
EXTRA_ARGS=("$@")
case "$MODULE" in
install|startstop|cleanup|health|backup|restore|update|config|report|smoke|cron) ;;
*) echo "ERROR: unsupported module" >&2; exit 2 ;;
esac
case "$PROFILE" in
grid-sim|robust|standalone) ;;
*) echo "ERROR: invalid profile" >&2; exit 2 ;;
esac
case "$LANG" in
de|en|fr|es) ;;
*) echo "ERROR: invalid language" >&2; exit 2 ;;
esac
run_main() {
bash "$MAIN_SCRIPT" --mode cli --profile "$PROFILE" --lang "$LANG" --workdir "$WORKDIR" --module "$MODULE" --action "$ACTION" "${EXTRA_ARGS[@]}"
}
run_main
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
MAIN_SCRIPT="$PROJECT_ROOT/osmtool_main.sh"
if [[ ! -x "$MAIN_SCRIPT" ]]; then
echo "ERROR: osmtool_main.sh not executable: $MAIN_SCRIPT" >&2
exit 1
fi
MODULE="${1:-}"
ACTION="${2:-}"
PROFILE="${3:-grid-sim}"
LANG="${4:-de}"
WORKDIR="${5:-/opt}"
shift $(( $# >= 5 ? 5 : $# ))
EXTRA_ARGS=("$@")
case "$MODULE" in
install|startstop|cleanup|health|backup|restore|update|config|report|smoke|cron) ;;
*) echo "ERROR: unsupported module" >&2; exit 2 ;;
esac
case "$PROFILE" in
grid-sim|robust|standalone) ;;
*) echo "ERROR: invalid profile" >&2; exit 2 ;;
esac
case "$LANG" in
de|en|fr|es) ;;
*) echo "ERROR: invalid language" >&2; exit 2 ;;
esac
run_main() {
bash "$MAIN_SCRIPT" --mode cli --profile "$PROFILE" --lang "$LANG" --workdir "$WORKDIR" --module "$MODULE" --action "$ACTION" "${EXTRA_ARGS[@]}"
}
run_main