Themabewertung:
  • 0 Bewertung(en) - 0 im Durchschnitt
  • 1
  • 2
  • 3
  • 4
  • 5
Sim Start | Stop script
#1
Fast drei Monate habe ich jetzt wieder Opensimulator und die Server am Wickel.
Heute möchte ich euch mein sim_start_stop.sh script – Projektstatus & Dokumentationsanker vorstellen.

Nach dem die neu aufgebauten Debian GNU/Linux 13 (trixie) und Ubuntu Ubuntu 22.04 (jammy) Server Laufen,
ist jetzt OpenSim 0.9.3 in Brid-Berlin am laufen.

Es hat mich einiges an zeit gekostet meine Alten scripte zu sortieren, aufzuräumen, auszumülllen, anzupassen und kann sie hier heute stabil euch zeigen.
Ach und was ganz WICHTIGES, das script nimt keine änderungen an eurern Opensim instalationen vor!!

Ziel des Projekts:
- Robustes, nachvollziehbares Start/Stop/Status-Script für OpenSim
- Fokus auf Stabilität, klare Prüfungen und saubere Fehlermeldungen

Getestete / Zielumgebung:
- Ubuntu (aktuelle LTS)
- Debian 13
- Bash-Scripting
- OpenSim mit Robust (local / remote / auto)

Bewusste Designentscheidungen:
- Keine Abhängigkeit von OpenSim-Konfigurationsstrings
- Keine Modifikation bestehender OpenSim-Konfigurationen
- Prüfungen erfolgen ausschließlich scriptseitig
- PID-Prüfungen nur als Rückverifizierung, niemals allein entscheidend
- Dienste müssen erreichbar sein, nicht nur „lokal laufen“

Robust-Prüfung:
- Modus: local / remote / auto
- Prüfung der tatsächlichen Erreichbarkeit (Ports)
- OpenSim-Instanzen starten nur, wenn ein passender Robust erreichbar ist
- Mehrere Robust-Instanzen (z. B. Grid, Assets, Login, Testgrid) sind berücksichtigt

MySQL-Prüfung:
- Analog zur Robust-Logik umgesetzt
- Local / remote / auto möglich
- Keine Abhängigkeit von EstateConnectionString
- Klare, explizite MySQL-Parameter im Script

Was ich mir von der Community wünsche:
- Feedback zu Designentscheidungen
- Erfahrungen aus anderen Systemumgebungen
- Hinweise auf reale Edge-Cases
- Sachliche Kritik, keine Grundsatzdebatten

Code:
#!/usr/bin/env bash
# ==========================================================
# sim_start_stop.sh
# ----------------------------------------------------------
# OpenSimulator Start | Stop | Status Script
#
# Version:        0.5.3
# OpenSim:        0.9.3
# Getestet unter: Ubuntu / Debian (mit MySQL)
#
# Lizenz: BSD (Open Source)
# Autor:  Gau Hax
# Mail:   gauhax@vamp-berlin.de
#
# Zweck:
#  - Starten, Stoppen und Statusabfrage einzelner
#    OpenSimulator-Instanzen in einem Multi-Screen-Setup
#
# Philosophie:
#  - Klar, robust, admin-tauglich
#  - Keine Magie, keine Endlosschleifen
#  - Fehler sichtbar machen, nicht verstecken
# ==========================================================
# -----------------------------
# Parameter ( Start )
# -----------------------------
AKTION="$1"
INSTANZ="$2"

if [[ ! "${AKTION}" =~ ^(start|stop|status)$ ]]; then
    echo "Nutzung: $0 start|stop|status <1-20>"
    exit 1
fi

if [[ ! "${INSTANZ}" =~ ^[0-9]+$ ]] || (( INSTANZ < 1 || INSTANZ > 20 )); then
    echo "Instanz muss eine Zahl von 1 bis 20 sein"
    exit 1
fi

INSTNUM="$(printf "%02d" "${INSTANZ}")"
INSTTAG="Inst_${INSTNUM}"

STATUS_MODUS=false
[[ "${AKTION}" == "status" ]] && STATUS_MODUS=true

abbruch_oder_status() {
    [[ "${STATUS_MODUS}" == false ]] && exit 1
}

# ----------------------------------------------------------
# Statische Konfiguration ( Robust / MySql / Verzeichnisse )
# ----------------------------------------------------------

# --- Robust Grid Service ---
ROBUST_MODE="auto"        # local | remote | auto
ROBUST_HOST="127.0.0.1"   # Host oder IP
ROBUST_PORT_1="8002"
ROBUST_PORT_2="8003"
ROBUST_TAG="Robust"       # -smtag=Robust z.b.

# --- MySQL ---
MYSQL_MODE="auto"         # local | remote | auto
MYSQL_HOST="127.0.0.1"      # Host oder IP
MYSQL_PORT="3306"
MYSQL_DB="opensim-datenbank"    # Anpassen DB

# --- Basis & Pfade ---
#
# Start Verzeichniss von OpenSimulator / Anpassen !
#
BASIS_VERZEICHNIS="/opt/opensim"
ARBEITS_VERZEICHNIS="${BASIS_VERZEICHNIS}/bin_${INSTNUM}"

# PID Verzeichniss = OpenSim.ini / Anpassen !
PID_DATEI="/opt/opensim/run/pid/${INSTTAG}.pid"

# Log Datein Verzeichniss
LOG_VERZEICHNIS="/opt/opensim/log"
LOG_DATEI="${LOG_VERZEICHNIS}/sim_start_stop${INSTNUM}.log"

SCREEN_HAUPT="HAUPSCREEN-NAME"  # z.b. Simss / Simss_01 !!
ERWARTETER_USER="OPENSIMUNSER"  # euer User vom System für Opensim!

mkdir -p "${LOG_VERZEICHNIS}"

# -----------------------------
# Pflichtdateien – Definition
# -----------------------------

# Dateien direkt im Arbeitsverzeichnis (bin_XX)
PFLICHT_DATEIEN_ROOT=(
    "OpenSim.ini"
    "OpenSimDefaults.ini"
)

# Dateien unter config-include/
# Sind hier als vorlage für ... !
PFLICHT_DATEIEN_CONFIG=(
    "GridCommon.ini"
    "FlotsamCache.ini"
)

# Regions-Datei (Sonderpfad)
# Ich gehe hier davon aus, das script, es es mindestens
# eine "Regions.ini" Datei für eine Inst hat
REGION_DATEI="${ARBEITS_VERZEICHNIS}/Regions/Regions.ini"

# -----------------------------
# Pflicht Datein Prüfung (erweiterung)
# ERWEITERUNG !!! in vorbereitung !
# -----------------------------
## PFLICHT_DATEIEN_CONFIG+=( "NeueDatei.ini" )

# -----------------------------
# Farben (Konsole)
# muss ja schön aussehen
# Danke an Manfred Aabye für die Inspiration
# -----------------------------
## C_RESET="\033[0m"
## C_INFO="\033[1;34m"
## C_WARN="\033[1;33m"
## C_ERR="\033[1;31m"
## C_OK="\033[1;32m"
C_RESET="\033[0m"
C_INFO="\033[1;33m"
C_WARN="\033[33;1m"
C_ERR="\033[31m"
C_OK="\033[32m"

# -----------------------------
# Logging
# Console mit Farbe, Datei mit Datum und Uhrzeit
# -----------------------------
log_console() {
    echo -e "$2[$1]${C_RESET} $3"
}

log_file() {
    echo "[ $(date '+%Y-%m-%d %H:%M:%S') ] [$1] $2" >> "${LOG_DATEI}"
}

log_info() { log_console INFO "${C_INFO}" "$1"; log_file INFO "$1"; }
log_warn() { log_console WARN "${C_WARN}" "$1"; log_file WARN "$1"; }
log_err()  { log_console FEHLER "${C_ERR}" "$1"; log_file FEHLER "$1"; }
log_ok()   { log_console OK "${C_OK}" "$1"; log_file OK "$1"; }

# -----------------------------
# Robust Prüfung
# -----------------------------

check_robust() {

    log_info "Robust-Prüfung gestartet (Modus: ${ROBUST_MODE})"

    # -------------------------
    # Port-Check Funktion
    # -------------------------
    check_ports() {
        local ok=true

        for port in "${ROBUST_PORT_1}" "${ROBUST_PORT_2}"; do
            if timeout 2 bash -c "</dev/tcp/${ROBUST_HOST}/${port}" 2>/dev/null; then
                log_ok "Robust-Port erreichbar: ${ROBUST_HOST}:${port}"
            else
                log_err "Robust-Port NICHT erreichbar: ${ROBUST_HOST}:${port}"
                ok=false
            fi
        done

        [[ "${ok}" == true ]]
    }

    # -------------------------
    # Prozess-Check Funktion
    # -------------------------
    check_process() {
        local found=false

        while read -r pid; do
            CMD="$(tr '\0' ' ' < /proc/${pid}/cmdline 2>/dev/null)"
            if echo "${CMD}" | grep -qi "Robust" && echo "${CMD}" | grep -q -- "-smtag=${ROBUST_TAG}"; then
                log_ok "Robust-Prozess gefunden (PID=${pid})"
                found=true
                break
            fi
        done < <(pgrep -f dotnet || true)

        [[ "${found}" == true ]]
    }

    # -------------------------
    # Modus-Auswertung
    # -------------------------
    case "${ROBUST_MODE}" in

        local)
            log_info "Robust LOCAL: Prozessprüfung"
            check_process || {
                log_err "Lokaler Robust läuft nicht"
                return 1
            }
            ;;

        remote)
            log_info "Robust REMOTE: Portprüfung"
            check_ports || {
                log_err "Remote Robust nicht erreichbar"
                return 1
            }
            ;;

        auto)
            log_info "Robust AUTO: Erkennung local / remote"

            if check_process; then
                log_ok "Robust lokal erkannt"
                return 0
            fi

            log_warn "Kein lokaler Robust – prüfe Remote"
            check_ports || {
                log_err "Robust weder lokal noch remote erreichbar"
                return 1
            }
            ;;

        *)
            log_err "Unbekannter ROBUST_MODE: ${ROBUST_MODE}"
            return 1
            ;;
    esac

    log_ok "Robust-Prüfung erfolgreich"
    return 0
}

# ----------------------------------------------------------
# MySQL-Prüfung (analog Robust)
# ----------------------------------------------------------
check_mysql() {

    log_info "MySQL-Prüfung gestartet (Modus: ${MYSQL_MODE})"

    # -------------------------
    # Port-Check Funktion
    # -------------------------
    check_port() {
        if timeout 2 bash -c "</dev/tcp/${MYSQL_HOST}/${MYSQL_PORT}" 2>/dev/null; then
            log_ok "MySQL-Port erreichbar: ${MYSQL_HOST}:${MYSQL_PORT}"
            return 0
        else
            log_err "MySQL-Port NICHT erreichbar: ${MYSQL_HOST}:${MYSQL_PORT}"
            return 1
        fi
    }

    # -------------------------
    # Lokaler Dienst-Check
    # -------------------------
    check_local_service() {
        if mysqladmin ping --silent >/dev/null 2>&1; then
            log_ok "Lokaler MySQL-Dienst erreichbar"
            return 0
        else
            log_err "Lokaler MySQL-Dienst nicht erreichbar"
            return 1
        fi
    }

    # -------------------------
    # Datenbank-Check
    # -------------------------
    check_database() {
        if mysql -e "USE ${MYSQL_DB};" >/dev/null 2>&1; then
            log_ok "MySQL-Datenbank '${MYSQL_DB}' erreichbar"
            return 0
        else
            log_err "MySQL-Datenbank '${MYSQL_DB}' nicht erreichbar"
            return 1
        fi
    }

    # -------------------------
    # Modus-Auswertung
    # -------------------------
    case "${MYSQL_MODE}" in

        local)
            log_info "MySQL LOCAL: Dienstprüfung"
            check_local_service || return 1
            ;;

        remote)
            log_info "MySQL REMOTE: Portprüfung"
            check_port || return 1
            ;;

        auto)
            log_info "MySQL AUTO: Erkennung local / remote"

            if check_local_service; then
                log_ok "MySQL lokal erkannt"
            else
                log_warn "Kein lokaler MySQL – prüfe Remote"
                check_port || {
                    log_err "MySQL weder lokal noch remote erreichbar"
                    return 1
                }
            fi
            ;;

        *)
            log_err "Unbekannter MYSQL_MODE: ${MYSQL_MODE}"
            return 1
            ;;
    esac

    # -------------------------
    # Datenbank immer prüfen
    # -------------------------
    check_database || return 1

    log_ok "MySQL-Datenbank-Prüfung erfolgreich"
    return 0
}

# -----------------------------
# Benutzerprüfung
# Läuft OpenSim unter dem richtigen SystemBenutzer
# -----------------------------
AKTUELLER_USER="$(whoami)"
if [[ "${AKTUELLER_USER}" != "${ERWARTETER_USER}" ]]; then
    log_warn "Script läuft als '${AKTUELLER_USER}', erwartet '${ERWARTETER_USER}'"
else
    log_ok "Script läuft unter korrektem Benutzer '${ERWARTETER_USER}'"
fi


# -----------------------------
# Host & IP
# Hier prüfen / ermitteln IP / Host
# -----------------------------
HOST="$(hostname)"
HOSTIP="$(
    ip route get 1.1.1.1 2>/dev/null \
    | awk '{for(i=1;i<=NF;i++) if ($i=="src") {print $(i+1); exit}}'
)"

[[ -n "${HOSTIP}" ]] \
    && log_ok "System: HOST=${HOST}, IP=${HOSTIP}" \
    || log_err "System-IP konnte nicht ermittelt werden"


# -----------------------------
# Arbeitsverzeichnis
# -----------------------------
if [[ ! -d "${ARBEITS_VERZEICHNIS}" ]]; then
    log_err "Arbeitsverzeichnis fehlt: ${ARBEITS_VERZEICHNIS}"
    abbruch_oder_status
else
    log_ok "Arbeitsverzeichnis vorhanden"
fi

# -----------------------------
# Pflichtdateien prüfen
# -----------------------------

# Root-Dateien
for datei in "${PFLICHT_DATEIEN_ROOT[@]}"; do
    pfad="${ARBEITS_VERZEICHNIS}/${datei}"

    if [[ ! -f "${pfad}" ]]; then
        log_err "Pflichtdatei fehlt: ${pfad}"
        abbruch_oder_status
    elif [[ ! -s "${pfad}" ]]; then
        log_err "Pflichtdatei ist leer: ${pfad}"
        abbruch_oder_status
    else
        log_ok "Pflichtdatei geprüft: ${datei}"
    fi
done

# config-include-Dateien
for datei in "${PFLICHT_DATEIEN_CONFIG[@]}"; do
    pfad="${ARBEITS_VERZEICHNIS}/config-include/${datei}"

    if [[ ! -f "${pfad}" ]]; then
        log_err "Pflichtdatei fehlt: ${pfad}"
        abbruch_oder_status
    elif [[ ! -s "${pfad}" ]]; then
        log_err "Pflichtdatei ist leer: ${pfad}"
        abbruch_oder_status
    else
        log_ok "Pflichtdatei geprüft: config-include/${datei}"
    fi
done

# Regions.ini
if [[ ! -f "${REGION_DATEI}" ]]; then
    log_err "Regions-Datei fehlt: ${REGION_DATEI}"
    abbruch_oder_status
elif [[ ! -s "${REGION_DATEI}" ]]; then
    log_err "Regions-Datei ist leer: ${REGION_DATEI}"
    abbruch_oder_status
else
    log_ok "Regions-Datei geprüft: Regions.ini"
fi

# -----------------------------
# Regions.ini auswerten
# -----------------------------
REGIONS_NAME="$(
    awk -F'[][]' '/^\[/{print $2; exit}' "${REGION_DATEI}" \
    | sed 's/^[[:space:]]*//; s/[[:space:]]*$//'
)"

REGIONS_UUID="$(
    grep -E '^RegionUUID[[:space:]]*=' "${REGION_DATEI}" \
    | awk -F '=' '{gsub(/[[:space:]]/, "", $2); print $2}' \
    | head -n1
)"

[[ -n "${REGIONS_NAME}" ]] \
    && log_ok "Regionsname: ${REGIONS_NAME}" \
    || log_warn "Kein Regionsname gefunden"

[[ -n "${REGIONS_UUID}" ]] \
    && log_ok "RegionUUID: ${REGIONS_UUID}" \
    || log_warn "Keine RegionUUID gefunden"


# -----------------------------
# Port-Prüfung
# -----------------------------
OS_PORT="$(
    grep -E '^[[:space:]]*http_listener_port[[:space:]]*=' \
    "${ARBEITS_VERZEICHNIS}/OpenSim.ini" \
    | awk -F '=' '{gsub(/[[:space:]]/, "", $2); print $2}' \
    | head -n1
)"

REGION_PORTS="$(
    grep -E '^[[:space:]]*InternalPort[[:space:]]*=' "${REGION_DATEI}" \
    | awk -F '=' '{gsub(/[[:space:]]/, "", $2); print $2}'
)"

[[ -n "${OS_PORT}" ]] \
    && log_ok "OpenSim Listener-Port: ${OS_PORT}" \
    || { log_err "Kein http_listener_port gefunden"; abbruch_oder_status; }

for rport in ${REGION_PORTS}; do
    [[ "${rport}" == "${OS_PORT}" ]] \
        && log_ok "Region-Port ${rport} passt" \
        || log_warn "Region-Port ${rport} weicht ab"
done


# ==========================================================
# PIDFile Prüfung (OpenSim.ini) – robust (mit/ohne Anführungszeichen)
#
# ==========================================================
PIDFILE_INI_RAW="$(
    grep -E '^[[:space:]]*PIDFile[[:space:]]*=' \
    "${ARBEITS_VERZEICHNIS}/OpenSim.ini" \
    | head -n1 \
    | awk -F '=' '{print $2}'
)"

PIDFILE_INI="$(
    echo "${PIDFILE_INI_RAW}" \
    | sed 's/^[[:space:]]*//; s/[[:space:]]*$//' \
    | sed 's/^"//; s/"$//'
)"

if [[ -z "${PIDFILE_INI}" ]]; then
    log_err "PIDFile ist nicht in OpenSim.ini gesetzt"
    abbruch_oder_status
elif [[ "${PIDFILE_INI}" != "${PID_DATEI}" ]]; then
    log_err "PIDFile stimmt nicht"
    log_err "Gefunden : ${PIDFILE_INI}"
    log_err "Erwartet: ${PID_DATEI}"
    abbruch_oder_status
else
    log_ok "PIDFile korrekt gesetzt (${PIDFILE_INI})"
fi


# ==========================================================
# AKTIONEN ( start | stop | status )
# ==========================================================
case "${AKTION}" in

# -----------------------------
# STATUS
# Läuft komplett durch, auch bei Fehlern !
# -----------------------------
status)
    if [[ -f "${PID_DATEI}" ]]; then
        PID="$(cat "${PID_DATEI}")"
        if [[ -n "${PID}" && -d "/proc/${PID}" ]]; then
            CMD="$(tr '\0' ' ' < /proc/${PID}/cmdline)"
            if echo "${CMD}" | grep -q -- "-smtag=${INSTTAG}"; then
                log_ok "Instanz läuft (PID=${PID})"
            else
                log_warn "PID aktiv, aber falscher Prozess"
            fi
        else
            log_warn "Verwaiste PID-Datei gefunden"
        fi
    else
        log_info "Instanz läuft nicht"
    fi
    if [[ "${AKTION}" == "status" ]]; then
        check_robust \
            && log_ok "Robust-Status: OK" \
            || log_warn "Robust-Status: NICHT erreichbar"
        check_mysql \
        && log_ok "MySQL-Status: OK" \
        || log_warn "MySQL-Status: FEHLER"
    fi
    ;;

# -----------------------------
# START
# Hier muss alles passen
# ansonsten abbruch
# -----------------------------
start)
    log_ok "Startbefehl gesendet - Anfang"
#    check_robust || { log_err "Start abgebrochen: Robust nicht verfügbar"; exit 1; }
    check_mysql  || { log_err "Start abgebrochen: MySQL nicht verfügbar"; exit 1; }
        if [[ "${AKTION}" == "start" ]]; then
            check_robust || {
                log_err "Start abgebrochen: Robust nicht verfügbar"
                exit 1
            }
        fi
    if [[ -f "${PID_DATEI}" ]]; then
        PID="$(cat "${PID_DATEI}")"
        if [[ -n "${PID}" && -d "/proc/${PID}" ]]; then
            log_warn "Instanz läuft bereits (PID=${PID})"
            exit 0
        else
            log_warn "Verwaiste PID-Datei entfernt"
            rm -f "${PID_DATEI}"
        fi
    fi

    if ! screen -list | grep -q "\.${SCREEN_HAUPT}"; then
        log_err "Hauptscreen '${SCREEN_HAUPT}' existiert nicht"
        exit 1
    fi

    log_info "Starte Instanz ${INSTTAG} (${REGIONS_NAME})"

    screen -S "${SCREEN_HAUPT}" -p 0 -X screen -t "${REGIONS_NAME}" "${INSTNUM}"
    sleep 0.5

    screen -S "${SCREEN_HAUPT}" -p "${INSTNUM}" -X stuff \
        "cd ${ARBEITS_VERZEICHNIS} && dotnet OpenSim.dll -smtag=${INSTTAG}^M"

    log_ok "Startbefehl gesendet - Ende"
    ;;

# -----------------------------
# STOP
# mit kontrolle auf sauberes ENDE
# -----------------------------
stop)
    if [[ ! -f "${PID_DATEI}" ]]; then
        log_warn "Keine PID-Datei – Instanz läuft nicht"
        exit 0
    fi

    PID="$(cat "${PID_DATEI}")"

    log_info "Stoppe Instanz ${INSTTAG} (${REGIONS_NAME})"

    screen -S "${SCREEN_HAUPT}" -p "${INSTNUM}" -X stuff \
        "alert Die Region ${REGIONS_NAME} wird in 2 Minuten gestoppt.^M"
    sleep 0.3
    screen -S "${SCREEN_HAUPT}" -p "${INSTNUM}" -X stuff "login disable^M"
    sleep 120

    screen -S "${SCREEN_HAUPT}" -p "${INSTNUM}" -X stuff \
        "alert Die Region ${REGIONS_NAME} wird in 1 Minute gestoppt.^M"
    sleep 45

    screen -S "${SCREEN_HAUPT}" -p "${INSTNUM}" -X stuff \
        "alert Die Region ${REGIONS_NAME} wird in 15 Sekunden gestoppt.^M"
    sleep 15

    screen -S "${SCREEN_HAUPT}" -p "${INSTNUM}" -X stuff "quit^M"
    sleep 5

    screen -S "${SCREEN_HAUPT}" -p "${INSTNUM}" -X stuff "exit^M"

    # -------------------------
    # Warte Zyklus auf sauber Stop
    # -------------------------
    for ((i=0;i<20;i++)); do
        sleep 15
        [[ ! -d "/proc/${PID}" ]] && break
    done

    if [[ -d "/proc/${PID}" ]]; then
        log_warn "Prozess hängt – hartes KILL"
        kill -9 "${PID}"
    fi

    rm -f "${PID_DATEI}"
    log_ok "Instanz sauber gestoppt"
    ;;
esac

exit 0

Kurze erklärung zu dem Script.
Eine genaue Erklärung, Anleitung unter Opensim Start Stop Script

Im Kopf sind alle wichtigen angaben zu machen für Robus und MySql den Verzeichnissen und SystemUser unter dem Opemsim Läuft.
Vorraussetzungen
- Laufender HAUPTSCREEN
" Ein HauptScreen wird bei mir mit dem System automatsch gestartet "
" Wer kein script für ein "Hauptscreen hat, kann sich gerne melden"
- Opensim muss auf dem System Lauffähig vorliegen
"keine nachinstalationen durch das script"
- Robust muss erreichbar sein local | remote | auto
- MySql ebenso local | remote | auto
- eine vorhandene ( .my.cnf ) im stamverzeichniss des Opensim Users
[client]
user=opensimuser
password=suppergeheim
muss identisch zu dem User sein der in Opensimulator ist, und zugriff auf die entsprechende Datenbank haben


Hier jetzt mal ein Beispiel zu der Gesamt Konfiguration

Stamm Verzeichniss /opt/opensim
Instanzen bin_01
bin_02 ... usw
eine Instanz wird immer von 1 -20 aufgerufen, daraus wird an nötigen stellen 1 = 01 / 2 = 02 ... usw ist für die bin_xx für den INSTTAG (Inst_01) und den screen (1, 2 ,3 ... ) verwendet

Instanzlogik:
- INSTNUM = zweistellig (01–20)
- INSTTAG = Inst_XX
- smtag = -smtag=INSTTAG (zwingend)
Opensim aufruf / start ( dotnet OpenSim.dll -smtag=Inst_XX ) xx ersetzt das script durch entsprechdende Nummer!
(diesen -smtag=Robust könnt ihr, solltet ihr auch machen)
Log Verzeichniss, ist das einziegstes was bei nicht vorhanden sein, im Arbeitsverzeichniss angelegt wird
/log
weiter muss
/run/pid
PID_DATEI="/opt/opensim/run/pid/${INSTTAG}.pid"
Dies muss in der " OpenSim.ini angegeben werden " /opt/opensim/run/pid/Inst_01.pid " 02/03 je nach bin_xx
vorhanden sein

Noch ein Wort zu der MySql und Robust prüfung. Bei " auto " wird geprüft ob unter der angegeben IP / HOST der Dienst verfügbar ist, in zweiter line, ob er local läuft.
Ein Abruch kommt, wenn
Dienst nicht erreichbar
Config falsch, leer oder nicht vorhanden, ebenso Arbeitsverzeichniss fehlt oder ports falsch sind !

Unter Ubuntu, kann das script eins zu eins in "Monit" eingebunden werden
(Debian ist da leider zickig Wink )
Beispiel:
Code:
# Monitor mono opensim Service for Instanze 01
check process SIMNAME (/ INST oder wie man möchte)
    with pidfile /opt/opensim/run/pid/Inst_01.pid
GROUP opensim
ONREBOOT NOSTART

    start program = "/home/OPENSIMUSER/.local/bin/sim_start_sop.sh start 1"
        as uid OPENSIMUSER and gid OPENSIMUSER

    stop program  = "/home/OPENSIMUSER/.local/bin/sim_start_stop.sh stop 1"
        as uid OPENSIMUSER and gid OPENSIMUSER

    if failed
        host 127.0.0.1
        port 9010
        protocol http
        request "/simstatus" within
        15 cycles then restart

    if memory usage > 768 MB then alert
    if memory usage > 972 MB then restart
    if cpu usage > 50% then alert
    if cpu usage > 75% for 3 cycles then restart

    if does not exist then restart
    if 3 restarts within 5 cycles then timeout

depends on mysqld , Robust


Ach ja, das script kann also wie im Beispiel oben
" sim_start_stop.sh start 1 "
" sim_start_stop.sh stop 1 "
" sim_start_stop.sh status 1 "
aufgefrufen werden ...

Als dann, ich hoffe, das ich alles Gut Klar beschrieben habe, und bin auf eure reaktionen gespannt.

Und zu guter letzt, möchte ich mich bei "Manfred Aabye" für die Inspiration für die Color ausgabe in der Console bedanken.
WinBlöd wird ja auch so viel verkauft, weil es hüpsch aussieht Wink
niemand ist eine Insel, und Selbsthilfe heißt nicht sich nur um sich zu kümmern. www.vamp-berlin.de www.grid-berlin.de
[-] The following 2 users say Thank You to Gau Hax for this post:
  • Dorena Verne, Pius Noel
Zitieren
#2
Hui, ganz schön aufwändig Gau, auf den ersten Blick etwas verwirrend für mich. Aber toll, wenn es läuft. :-)

Bei mir ist alles etwas einfacher gestalten:

Das screenscript für eine Instanz:
   

Hier alle mal untereinander:
   

Und hier als laufende Prozesse:
   

Überwachen tue ich das Ganze im Moment durchs tägliche hereinschauen und es läuft stabil. Aber ich werde es noch ergänzen, der Faulheit der manuellen Überwachung geschuldet.Wink
Zitieren
#3
Code Review: sim_start_stop.sh



Was sehr gut ist

Struktur & Philosophie – Die klare Trennung von Prüfung, Logging und Aktionen ist vorbildlich. Der Kommentar "Keine Magie, keine Endlosschleifen" wird auch eingehalten.

Logging – Die doppelte Ausgabe (Konsole mit Farbe, Datei mit Timestamp) ist sauber gelöst. Die Trennung in log_info/warn/err/ok macht den Output übersichtlich.

abbruch_oder_status – Eine elegante Lösung, damit status immer durchläuft, während start bei Fehlern abbricht.

Robust/MySQL-Modi – Das auto/local/remote-System ist flexibel und praxisnah.



Probleme & Verbesserungsvorschläge

1. Doppelter Robust-Aufruf im start-Block

Der auskommentierte check_robust-Aufruf und der if-Block darunter sind ein Überbleibsel – hier sollte aufgeräumt werden.

Code:
# check_robust wird zweimal definiert / aufgerufen:
check_mysql  || ...
    if [[ "${AKTION}" == "start" ]]; then   # ← Dieser Block ist überflüssig
        check_robust || ...
    fi
# Zeile davor ist auskommentiert, aber die Logik ist redundant



2. Stop-Timeout potenziell sehr lang

Nach dem quit wartet das Script im schlechtesten Fall 5 Minuten (20 × 15 Sekunden). Eine Statusausgabe in der Schleife wäre hilfreich:

Code:
for ((i=0;i<20;i++)); do
    sleep 15   # = bis zu 300 Sekunden (5 Minuten!)
    log_info "Warte auf Prozessende... (${i}/20)"   # ← ergänzen
    [[ ! -d "/proc/${PID}" ]] && break
done



3. screen -p "${INSTNUM}" – Fenster-Tab-Logik fragil

Beim Start wird ein neues Screen-Fenster mit -t "${REGIONS_NAME}" "${INSTNUM}" erstellt – die Fensternummer ist dabei die letzte Zahl, die screen vergeben würde, nicht zwingend INSTNUM. Beim Stop wird dann blind auf -p "${INSTNUM}" zugegriffen. Das kann ins Leere laufen, wenn Fenster zwischenzeitlich umbenannt oder geschlossen wurden.



4. Kein Schutz gegen Race Conditions beim Start

Zwischen der PID-Prüfung und dem tatsächlichen Start gibt es ein kleines Zeitfenster. Nicht kritisch, aber bei einem Script das regelmäßig automatisiert läuft (z.B. per systemd/cron) sollte man das im Hinterkopf behalten.



5. mysql-Befehl ohne Credentials

Code:
mysql -e "USE ${MYSQL_DB};" >/dev/null 2>&1

Das funktioniert nur wenn ~/.my.cnf korrekt konfiguriert ist oder der Unix-Socket-Auth greift. Ansonsten schlägt der Check stillschweigend fehl und die Fehlermeldung ist irreführend. Ein Kommentar dazu wäre nützlich.



6. Kleinigkeit: Pflicht-Konfigurationsvariablen ohne Validierung

Die Variablen SCREEN_HAUPT und ERWARTETER_USER haben Platzhalterwerte (HAUPSCREEN-NAME, OPENSIMUNSER). Das Script sollte beim Start prüfen ob diese noch auf dem Default stehen:

Code:
if [[ "${SCREEN_HAUPT}" == "HAUPSCREEN-NAME" ]]; then
    log_err "SCREEN_HAUPT ist nicht konfiguriert!"
    exit 1
fi



Fazit

Ein solides, gut lesbares Admin-Script. Die größten praktischen Stolpersteine sind der doppelte Robust-Aufruf und die Screen-Fenster-Nummerierung. Alles andere sind eher Verfeinerungen als echte Fehler.
[Bild: footert5jul.jpg]
Zitieren
#4
Wow … danke für das Lob – und vor allem danke für eure Reaktionen!

Ich habe mir alles noch mal in Ruhe angeschaut und das Script direkt an den zwei wichtigen Stellen nachgebessert. Danke auch für den Hinweis mit der Warteschleife – da kam bei mir im „Bauscript“ tatsächlich bei jedem Zyklus eine Ausgabe. Das habe ich jetzt sauber gelöst.
Man sieht jetzt klar, dass das Script noch arbeitet und nicht hängt.

Hier nur kurz zur Info die neue Warteschleife:

Code:
# ----------------------------
    # Warte Zyklus auf sauber Stop
    # ----------------------------
    log_info "Warte auf sauberen Shutdown (max. ${STOP_MAX_WAIT_SEC}s)"

    elapsed=0
    loops=$(( STOP_MAX_WAIT_SEC / STOP_CHECK_INTERVAL ))
    progress_counter=0

    for ((i=1; i<=loops; i++)); do
        sleep "${STOP_CHECK_INTERVAL}"
        elapsed=$(( elapsed + STOP_CHECK_INTERVAL ))
        progress_counter=$(( progress_counter + 1 ))

        # Prozess beendet?
        if [[ ! -d "/proc/${PID}" ]]; then
            log_ok "Prozess nach ${elapsed}s sauber beendet"
            break
        fi

        # Fortschrittsmeldung
        if (( progress_counter % STOP_PROGRESS_EVERY == 0 )); then
            remaining=$(( STOP_MAX_WAIT_SEC - elapsed ))
            log_info "Shutdown läuft … ${elapsed}s vergangen, ${remaining}s verbleiben"
        fi
    done

    if [[ -d "/proc/${PID}" ]]; then
        log_warn "Prozess reagiert nicht nach ${STOP_MAX_WAIT_SEC}s – hartes KILL"
        kill -9 "${PID}"
    else
        log_ok "Instanz sauber gestoppt"
    fi

    rm -f "${PID_DATEI}"

Wie man sieht, sind das jetzt alles Variablen, die oben im Kopf definiert werden:

# -----------------------------
# Stop-Wartezeiten
# nur hier die Wartezeiten
# einstellen / ändern
# -----------------------------
STOP_MAX_WAIT_SEC=300 # max. Wartezeit auf sauberen Stop (300 = 5 Minuten)
STOP_CHECK_INTERVAL=10 # Prüfintervall in Sekunden
STOP_PROGRESS_EVERY=2 # alle X Durchläufe Fortschritt in der Konsole anzeigen


So kann man die Zeiten zentral anpassen, ohne im Script suchen zu müssen.

Das mit dem doppelten „Robust“ – ja, unschön !!!
Ist ein Überbleibsel vom Umbau, habe ich aber direkt geradegezogen. War mehr optisch störend als funktional kritisch.

Zum Thema screen: Danke für den Hinweis, da gehe ich noch mal sauber ran. Bei mir ist an der Stelle seit Jahren nichts passiert, aber ihr habt recht – sicher ist sicher. Ich baue da noch eine zusätzliche Rückversicherung ein, damit wirklich das richtige Screen-Fenster getroffen wird.

Ganz wichtig noch zu meiner Philosophie:
Passwörter gehören nicht ins Script. Gerade bei MySQL ist es ja sauber lösbar über eine .my.cnf im Home-Verzeichnis des Benutzers – so wie ich es im Beispiel beschrieben habe. Das ist für mich der deutlich bessere Weg.

Unterm Strich ist es ein bewusst schlankes Script, das vor dem Start alle wichtigen Punkte prüft und dann den Simulator sauber startet.

Für die nächste Version werden Start und Stop als separate, gekapselte Funktionen umgesetzt. Mit eigener Rückversicherung, ob der Vorgang wirklich erfolgreich war – und natürlich weiterhin mit zentral definierten Zeit-Variablen im Kopfbereich.

Danke euch auf jeden Fall für das Feedback – und ich freue mich schon, euch die nächsten Verbesserungen zu zeigen ! Wink
niemand ist eine Insel, und Selbsthilfe heißt nicht sich nur um sich zu kümmern. www.vamp-berlin.de www.grid-berlin.de
[-] The following 2 users say Thank You to Gau Hax for this post:
  • Akira, Dorena Verne
Zitieren
#5
Gerne möchte ich euch zeigen, wie es dann, von zuhause aus, mit ssh aufgerufen werden kann, und aussehen kann.
Die Bilder jetzt, da habe ich die Anmerkungen von Akira schon umgesetzt.
... und die zwei "Variablen SCREEN_HAUPT und ERWARTETER_USER" sind im Kopf definiert.
Schaue bitte nochmal genau nach.

So, nun dann, hier jetzt mal der Start Aufruf, von mir zuhause, mit ssh ( setzt ssh per key vorraus, ohne passwort )

ssh -t -p PORT SUPERUSER@domain/ip "sudo -i -u OPENSIMUSER bash sim_start_stop stop 9"

sim start
[Bild: sim_start.jpg]

sim stop 1
[Bild: sim_stop1.jpg]

sim stop 2
[Bild: sim_stop2.jpg]

Bis hier hin Läuft alles problemlos per Remote Aufruf. Und die Konsolen ausgaben können klar zeigen ob es geklappt hat.
damit ich das script so Starten kann, liegt es bei mir im HOME verzeichniss meines Opensim Users unter
~/.local/bin/sim_start_stop

und ich der .profile eures Benutzers, sollte sicherlich der PATH schon angegeben sein.

Code:
# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/.local/bin" ] ; then
    PATH="$HOME/.local/bin:$PATH"
fi
in der art etwa

Ich muss dazusagen, nach der Anregung von Akira, habe ich schon etwas nachgearbeitet, was die ausgaben beim Start und Stop angehen. ebenso, der Umzug in separate Funktionen. Also wenn ich das Sauber habe, dann werde ich das gesamte script Komplett mit einer Anleitung Posten.

Ansonsten, möchte ich nochmal klar hervorheben, das StartStopScript nimmt keinerlei Veränderungen vor, es prüft nur die Gegebenheiten, und kann somit gefahrlos getestet werden, ohne das irgendwelche Änderung gemacht werden. weder am System, noch bei Opensimulator.

Für die Hübsche Anleitung, da muss ich noch ein paar Tage warten, bis ne gute Freundin wieder zu Besuch kommt, und mir den Test für alle Sauer schreibt Wink

P.S. Ihr könnt mich bitte auch auf Rechtschreibfehler, oder bessere Ausdrucksform im script hinweisen Smile

Bis dahin, viel Spass, Erfolg beim Ausprobieren.
niemand ist eine Insel, und Selbsthilfe heißt nicht sich nur um sich zu kümmern. www.vamp-berlin.de www.grid-berlin.de
Zitieren


Möglicherweise verwandte Themen…
Thema Verfasser Antworten Ansichten Letzter Beitrag
  Automatische Einstellung einer IP beim Start von OpenSim royalgrid 6 3.000 26.03.2024, 14:31
Letzter Beitrag: Manfred Aabye
  Database Cleanup Script [OpenSim 0.9.x] bimbam2103 29 33.639 15.05.2019, 10:54
Letzter Beitrag: Manfred Aabye
  start stop bash shell scripte Manfred Aabye 0 3.180 17.01.2019, 17:37
Letzter Beitrag: Manfred Aabye
  GitRepo OpenSim installieren per Script unter Debian Bogus Curry 0 4.991 11.12.2016, 23:19
Letzter Beitrag: Bogus Curry
  Start Region Rebecka Alder 3 7.936 02.04.2016, 15:11
Letzter Beitrag: Dorena Verne

Gehe zu:


Benutzer, die gerade dieses Thema anschauen: 1 Gast/Gäste