deploy: ai-app in Rollout-Skripte 131 #448
No files matched your search
@@ -20,6 +20,7 @@ REPO_DIR="${NEXARCH_ROLLOUT_REPO_DIR:-/root/nexarch-code}"
|
||||
ENV_DIR=/etc/nexarch
|
||||
DMS_INSTALL_DIR="${NEXARCH_DMS_INSTALL_DIR:-/opt/nexarch-dms}"
|
||||
CONNECT_INSTALL_DIR="${NEXARCH_CONNECT_INSTALL_DIR:-/opt/nexarch-connect}"
|
||||
AI_INSTALL_DIR="${NEXARCH_AI_INSTALL_DIR:-/opt/nexarch-ai}"
|
||||
DMS_STORAGE_DIR="${NEXARCH_DMS_STORAGE_DIR:-/var/lib/nexarch-dms/storage}"
|
||||
DMS_STAGING_DIR="${NEXARCH_DMS_STAGING_DIR:-/var/lib/nexarch-dms/staging}"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
@@ -50,10 +51,18 @@ require_set() {
|
||||
return 0
|
||||
}
|
||||
|
||||
echo "== 1. Pruefe die 5 echten TODO-Werte =="
|
||||
echo "== 1. Pruefe die echten TODO-Werte =="
|
||||
missing=0
|
||||
require_set "$ENV_DIR/connect-app.env" NEXARCH_CONNECT_APP_LISTEN_ADDR || missing=1
|
||||
require_set "$ENV_DIR/connect-app.env" NEXARCH_CONNECT_APP_TENANT_DSN || missing=1
|
||||
require_set "$ENV_DIR/ai-app.env" NEXARCH_AI_APP_LISTEN_ADDR || missing=1
|
||||
require_set "$ENV_DIR/ai-app.env" NEXARCH_AI_APP_TENANT_DSN || missing=1
|
||||
require_set "$ENV_DIR/ai-app.env" NEXARCH_AI_APP_SERVICE_TOKEN || missing=1
|
||||
if ! require_set "$ENV_DIR/ai-app.env" NEXARCH_AI_APP_POLICY_URL 2>/dev/null \
|
||||
&& ! grep -q '^NEXARCH_AI_APP_POLICY_DISABLED=1' "$ENV_DIR/ai-app.env" 2>/dev/null; then
|
||||
echo "OFFEN: NEXARCH_AI_APP_POLICY_URL (mit _POLICY_SERVICE_TOKEN) oder NEXARCH_AI_APP_POLICY_DISABLED=1 in $ENV_DIR/ai-app.env" >&2
|
||||
missing=1
|
||||
fi
|
||||
require_set "$ENV_DIR/dms-app.env" NEXARCH_DMS_APP_CORE_SERVICE_TOKEN || missing=1
|
||||
require_set "$ENV_DIR/dms-app.env" NEXARCH_DMS_APP_KEK_CLIENT_ID || missing=1
|
||||
require_set "$ENV_DIR/dms-app.env" NEXARCH_DMS_APP_KEK_CLIENT_SECRET || missing=1
|
||||
@@ -63,10 +72,10 @@ if [ "$missing" -eq 1 ]; then
|
||||
echo "Trage die fehlenden Werte von Hand in die genannten Dateien ein und starte das Skript erneut." >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Alle 5 TODO-Werte sind gesetzt."
|
||||
echo "Alle TODO-Werte sind gesetzt."
|
||||
|
||||
echo "== 2. Build (falls rollout-131-sync.sh das noch nicht getan hat) =="
|
||||
for mod in dms connect; do
|
||||
for mod in dms connect ai; do
|
||||
if [ -f "$REPO_DIR/$mod/go.mod" ]; then
|
||||
( cd "$REPO_DIR/$mod" && go build ./... && go vet ./... )
|
||||
echo "gebaut/verifiziert: $mod"
|
||||
@@ -77,14 +86,16 @@ for mod in dms connect; do
|
||||
done
|
||||
|
||||
echo "== 3. Binaries kopieren =="
|
||||
mkdir -p "$DMS_INSTALL_DIR/bin" "$CONNECT_INSTALL_DIR/bin"
|
||||
mkdir -p "$DMS_INSTALL_DIR/bin" "$CONNECT_INSTALL_DIR/bin" "$AI_INSTALL_DIR/bin"
|
||||
( cd "$REPO_DIR/dms" && go build -o "$DMS_INSTALL_DIR/bin/dms-app" ./cmd/app )
|
||||
( cd "$REPO_DIR/dms" && go build -o "$DMS_INSTALL_DIR/bin/dms-worker" ./cmd/worker )
|
||||
( cd "$REPO_DIR/connect" && go build -o "$CONNECT_INSTALL_DIR/bin/connect-app" ./cmd/connect-app )
|
||||
echo "Binaries liegen unter ${DMS_INSTALL_DIR}/bin und ${CONNECT_INSTALL_DIR}/bin."
|
||||
( cd "$REPO_DIR/ai" && go build -o "$AI_INSTALL_DIR/bin/ai-app" ./cmd/ai-app )
|
||||
( cd "$REPO_DIR/ai" && go build -o "$AI_INSTALL_DIR/bin/ai-migrate" ./cmd/migrate )
|
||||
echo "Binaries liegen unter ${DMS_INSTALL_DIR}/bin, ${CONNECT_INSTALL_DIR}/bin und ${AI_INSTALL_DIR}/bin."
|
||||
|
||||
if id nexarch >/dev/null 2>&1; then
|
||||
chown -R nexarch:nexarch "$DMS_INSTALL_DIR" "$CONNECT_INSTALL_DIR"
|
||||
chown -R nexarch:nexarch "$DMS_INSTALL_DIR" "$CONNECT_INSTALL_DIR" "$AI_INSTALL_DIR"
|
||||
else
|
||||
echo "WARNUNG: Systembenutzer 'nexarch' existiert nicht -- Units werden trotzdem als User=nexarch geschrieben (wie bei Core/Archive ueblich), legen den Benutzer aber nicht an. Falls er fehlt, vor dem Start anlegen: useradd --system --no-create-home --shell /usr/sbin/nologin nexarch" >&2
|
||||
fi
|
||||
@@ -129,7 +140,15 @@ else
|
||||
echo "${ENV_DIR}/dms-worker.env existiert bereits -- wird nicht ueberschrieben."
|
||||
fi
|
||||
|
||||
echo "== 5b. AI-Migrationen anwenden =="
|
||||
AI_DSN="$(grep '^NEXARCH_AI_APP_TENANT_DSN=' "$ENV_DIR/ai-app.env" | head -n1 | cut -d= -f2-)"
|
||||
NEXARCH_AI_APP_TENANT_DSN="$AI_DSN" "$AI_INSTALL_DIR/bin/ai-migrate" "$REPO_DIR/ai/migrations"
|
||||
unset AI_DSN
|
||||
|
||||
echo "== 6. systemd-Units installieren =="
|
||||
sed -e "s#__INSTALL_DIR__#${AI_INSTALL_DIR}#g" \
|
||||
"$SCRIPT_DIR/systemd/nexarch-ai-app.service.tmpl" > /etc/systemd/system/nexarch-ai-app.service
|
||||
|
||||
sed -e "s#__INSTALL_DIR__#${CONNECT_INSTALL_DIR}#g" \
|
||||
"$SCRIPT_DIR/systemd/nexarch-connect-app.service.tmpl" > /etc/systemd/system/nexarch-connect-app.service
|
||||
|
||||
@@ -142,7 +161,7 @@ sed -e "s#__INSTALL_DIR__#${DMS_INSTALL_DIR}#g" \
|
||||
-e "s#__STORAGE_DIR__#${DMS_STORAGE_DIR}#g" \
|
||||
"$SCRIPT_DIR/systemd/nexarch-dms-worker.service.tmpl" > /etc/systemd/system/nexarch-dms-worker.service
|
||||
|
||||
echo "Units geschrieben: nexarch-connect-app, nexarch-dms-app, nexarch-dms-worker"
|
||||
echo "Units geschrieben: nexarch-ai-app, nexarch-connect-app, nexarch-dms-app, nexarch-dms-worker"
|
||||
|
||||
echo "== 7. daemon-reload =="
|
||||
systemctl daemon-reload
|
||||
@@ -167,7 +186,8 @@ if [ "$ok" -ne 1 ]; then
|
||||
fi
|
||||
echo "account-api liefert /auth/module-jwks."
|
||||
|
||||
echo "== 9. connect-app, dms-app, dms-worker aktivieren und starten =="
|
||||
echo "== 9. ai-app, connect-app, dms-app, dms-worker aktivieren und starten =="
|
||||
systemctl enable --now nexarch-ai-app.service
|
||||
systemctl enable --now nexarch-connect-app.service
|
||||
systemctl enable --now nexarch-dms-app.service
|
||||
systemctl enable --now nexarch-dms-worker.service
|
||||
|
||||
@@ -37,6 +37,7 @@ DMS_APP_ADDR=$(listen_addr "$ENV_DIR/dms-app.env" NEXARCH_DMS_APP_LISTEN_ADDR "1
|
||||
DMS_WORKER_METRICS_ADDR=$(listen_addr "$ENV_DIR/dms-worker.env" NEXARCH_DMS_WORKER_METRICS_ADDR "127.0.0.1:8601")
|
||||
DMS_KOSIT_ADDR=$(listen_addr "$ENV_DIR/dms-worker.env" NEXARCH_DMS_WORKER_KOSIT_ADDR "127.0.0.1:8610")
|
||||
CONNECT_APP_ADDR=$(listen_addr "$ENV_DIR/connect-app.env" NEXARCH_CONNECT_APP_LISTEN_ADDR "127.0.0.1:9500")
|
||||
AI_APP_ADDR=$(listen_addr "$ENV_DIR/ai-app.env" NEXARCH_AI_APP_LISTEN_ADDR "127.0.0.1:8900")
|
||||
|
||||
echo "== Core (bereits laufend erwartet) =="
|
||||
check "nexarch-core" "http://127.0.0.1:8080/healthz"
|
||||
@@ -53,6 +54,9 @@ check "dms-kosit-sidecar" "http://${DMS_KOSIT_ADDR}/healthz"
|
||||
echo "== Connect (Erstinstallation durch diesen Rollout) =="
|
||||
check "connect-app" "http://${CONNECT_APP_ADDR}/healthz"
|
||||
|
||||
echo "== AI =="
|
||||
check "ai-app" "http://${AI_APP_ADDR}/healthz"
|
||||
|
||||
echo
|
||||
echo "Hinweis: Adressen werden aus den echten Env-Dateien gelesen"
|
||||
echo "(NEXARCH_*_LISTEN_ADDR); ohne gesetzten Wert greift der Platzhalter aus"
|
||||
|
||||
@@ -13,6 +13,7 @@ set -euo pipefail
|
||||
CONNECT_ENV=/etc/nexarch/connect-app.env
|
||||
DMS_ENV=/etc/nexarch/dms-app.env
|
||||
CORE_ENV=/etc/nexarch/core.env
|
||||
AI_ENV=/etc/nexarch/ai-app.env
|
||||
|
||||
if [ ! -f "$CONNECT_ENV" ] || [ ! -f "$DMS_ENV" ] || [ ! -f "$CORE_ENV" ]; then
|
||||
echo "Abbruch: eine der Env-Dateien fehlt ($CONNECT_ENV, $DMS_ENV, $CORE_ENV)." >&2
|
||||
@@ -50,6 +51,42 @@ else
|
||||
echo "Uebersprungen: NEXARCH_CONNECT_APP_LISTEN_ADDR ist schon gesetzt."
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "== 1b. AI-DB (Rolle + Datenbank) =="
|
||||
if [ ! -f "$AI_ENV" ]; then
|
||||
echo "Uebersprungen: $AI_ENV fehlt (rollout-131-sync.sh zuerst ausfuehren)."
|
||||
else
|
||||
if grep -q '^NEXARCH_AI_APP_TENANT_DSN=.*TODO' "$AI_ENV" 2>/dev/null || ! grep -q '^NEXARCH_AI_APP_TENANT_DSN=' "$AI_ENV"; then
|
||||
PW=$(openssl rand -hex 20)
|
||||
sudo -u postgres psql -v ON_ERROR_STOP=1 <<SQL
|
||||
DO \$\$
|
||||
BEGIN
|
||||
IF EXISTS (SELECT FROM pg_roles WHERE rolname = 'ai_app') THEN
|
||||
ALTER ROLE ai_app WITH PASSWORD '${PW}';
|
||||
ELSE
|
||||
CREATE ROLE ai_app LOGIN PASSWORD '${PW}';
|
||||
END IF;
|
||||
END
|
||||
\$\$;
|
||||
SELECT 'CREATE DATABASE ai_app_tenant OWNER ai_app'
|
||||
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'ai_app_tenant')\gexec
|
||||
SQL
|
||||
sed -i '/^NEXARCH_AI_APP_TENANT_DSN=/d' "$AI_ENV"
|
||||
echo "NEXARCH_AI_APP_TENANT_DSN=postgresql://ai_app:${PW}@localhost:5432/ai_app_tenant?sslmode=disable" >> "$AI_ENV"
|
||||
echo "OK: NEXARCH_AI_APP_TENANT_DSN gesetzt."
|
||||
else
|
||||
echo "Uebersprungen: NEXARCH_AI_APP_TENANT_DSN ist schon gesetzt."
|
||||
fi
|
||||
if grep -q '^NEXARCH_AI_APP_LISTEN_ADDR=.*TODO' "$AI_ENV" 2>/dev/null || ! grep -q '^NEXARCH_AI_APP_LISTEN_ADDR=' "$AI_ENV"; then
|
||||
sed -i '/^NEXARCH_AI_APP_LISTEN_ADDR=/d' "$AI_ENV"
|
||||
echo "NEXARCH_AI_APP_LISTEN_ADDR=127.0.0.1:8900" >> "$AI_ENV"
|
||||
echo "OK: NEXARCH_AI_APP_LISTEN_ADDR gesetzt (127.0.0.1:8900)."
|
||||
else
|
||||
echo "Uebersprungen: NEXARCH_AI_APP_LISTEN_ADDR ist schon gesetzt."
|
||||
fi
|
||||
echo "OFFEN: NEXARCH_AI_APP_SERVICE_TOKEN und Policy-Anbindung (POLICY_URL/_POLICY_SERVICE_TOKEN oder POLICY_DISABLED=1) setzt der Betreiber von Hand."
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "== 2. KEK-Client fuer DMS registrieren =="
|
||||
if grep -q '^NEXARCH_DMS_APP_KEK_CLIENT_ID=.*TODO' "$DMS_ENV" 2>/dev/null; then
|
||||
@@ -135,3 +172,4 @@ echo
|
||||
echo "== Zusammenfassung =="
|
||||
grep -c TODO "$CONNECT_ENV" | xargs -I{} echo "connect-app.env: {} offene TODOs"
|
||||
grep -c TODO "$DMS_ENV" | xargs -I{} echo "dms-app.env: {} offene TODOs"
|
||||
[ -f "$AI_ENV" ] && { grep -c TODO "$AI_ENV" | xargs -I{} echo "ai-app.env: {} offene TODOs" || true; }
|
||||
@@ -17,10 +17,12 @@ REPO_DIR="${NEXARCH_ROLLOUT_REPO_DIR:-/root/nexarch-code}"
|
||||
ENV_DIR=/etc/nexarch
|
||||
DMS_INSTALL_DIR="${NEXARCH_DMS_INSTALL_DIR:-/opt/nexarch-dms}"
|
||||
CONNECT_INSTALL_DIR="${NEXARCH_CONNECT_INSTALL_DIR:-/opt/nexarch-connect}"
|
||||
AI_INSTALL_DIR="${NEXARCH_AI_INSTALL_DIR:-/opt/nexarch-ai}"
|
||||
DMS_STORAGE_DIR="${NEXARCH_DMS_STORAGE_DIR:-/var/lib/nexarch-dms/storage}"
|
||||
DMS_STAGING_DIR="${NEXARCH_DMS_STAGING_DIR:-/var/lib/nexarch-dms/staging}"
|
||||
CONNECT_ENV="$ENV_DIR/connect-app.env"
|
||||
DMS_ENV="$ENV_DIR/dms-app.env"
|
||||
AI_ENV="$ENV_DIR/ai-app.env"
|
||||
CORE_ENV="$ENV_DIR/core.env"
|
||||
MAX_ATTEMPTS=10
|
||||
|
||||
@@ -93,7 +95,7 @@ while [ "$attempt" -lt "$MAX_ATTEMPTS" ]; do
|
||||
fi
|
||||
|
||||
for pair in "$CONNECT_ENV:NEXARCH_CONNECT_APP_TENANT_DSN" "$CONNECT_ENV:NEXARCH_CONNECT_APP_LISTEN_ADDR" \
|
||||
"$DMS_ENV:NEXARCH_DMS_APP_CORE_SERVICE_TOKEN" "$DMS_ENV:NEXARCH_DMS_APP_KEK_CLIENT_ID" "$DMS_ENV:NEXARCH_DMS_APP_KEK_CLIENT_SECRET"; do
|
||||
"$AI_ENV:NEXARCH_AI_APP_TENANT_DSN" "$AI_ENV:NEXARCH_AI_APP_LISTEN_ADDR" "$AI_ENV:NEXARCH_AI_APP_SERVICE_TOKEN" "$DMS_ENV:NEXARCH_DMS_APP_CORE_SERVICE_TOKEN" "$DMS_ENV:NEXARCH_DMS_APP_KEK_CLIENT_ID" "$DMS_ENV:NEXARCH_DMS_APP_KEK_CLIENT_SECRET"; do
|
||||
f="${pair%%:*}"; n="${pair#*:}"
|
||||
if is_open "$f" "$n"; then
|
||||
blockers+=("${n} in ${f} ist weiterhin offen -- braucht einen externen Wert, den nur der Nutzer kennt (kein Konfigurationsfehler, den dieses Skript loesen darf).")
|
||||
@@ -125,7 +127,7 @@ while [ "$attempt" -lt "$MAX_ATTEMPTS" ]; do
|
||||
done
|
||||
|
||||
log "== Zielverzeichnisse pruefen =="
|
||||
for d in "$DMS_INSTALL_DIR/bin" "$CONNECT_INSTALL_DIR/bin" "$DMS_STORAGE_DIR" "$DMS_STAGING_DIR"; do
|
||||
for d in "$DMS_INSTALL_DIR/bin" "$CONNECT_INSTALL_DIR/bin" "$AI_INSTALL_DIR/bin" "$DMS_STORAGE_DIR" "$DMS_STAGING_DIR"; do
|
||||
if [ ! -d "$d" ]; then
|
||||
mkdir -p "$d"
|
||||
log "repariert: Verzeichnis $d angelegt."
|
||||
@@ -133,13 +135,15 @@ while [ "$attempt" -lt "$MAX_ATTEMPTS" ]; do
|
||||
fi
|
||||
done
|
||||
if id nexarch >/dev/null 2>&1; then
|
||||
chown -R nexarch:nexarch "$DMS_INSTALL_DIR" "$CONNECT_INSTALL_DIR" "$DMS_STORAGE_DIR" "$DMS_STAGING_DIR" 2>/dev/null || true
|
||||
chown -R nexarch:nexarch "$DMS_INSTALL_DIR" "$CONNECT_INSTALL_DIR" "$AI_INSTALL_DIR" "$DMS_STORAGE_DIR" "$DMS_STAGING_DIR" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
log "== Binaries pruefen (nachbauen falls sie fehlen) =="
|
||||
for triple in "$DMS_INSTALL_DIR/bin/dms-app:$REPO_DIR/dms:./cmd/app" \
|
||||
"$DMS_INSTALL_DIR/bin/dms-worker:$REPO_DIR/dms:./cmd/worker" \
|
||||
"$CONNECT_INSTALL_DIR/bin/connect-app:$REPO_DIR/connect:./cmd/connect-app"; do
|
||||
"$CONNECT_INSTALL_DIR/bin/connect-app:$REPO_DIR/connect:./cmd/connect-app" \
|
||||
"$AI_INSTALL_DIR/bin/ai-app:$REPO_DIR/ai:./cmd/ai-app" \
|
||||
"$AI_INSTALL_DIR/bin/ai-migrate:$REPO_DIR/ai:./cmd/migrate"; do
|
||||
bin="${triple%%:*}"; rest="${triple#*:}"; moddir="${rest%%:*}"; pkg="${rest#*:}"
|
||||
if [ ! -x "$bin" ]; then
|
||||
if [ -f "$moddir/go.mod" ]; then
|
||||
@@ -190,7 +194,7 @@ while [ "$attempt" -lt "$MAX_ATTEMPTS" ]; do
|
||||
fi
|
||||
|
||||
log "== systemd-Unit-Dateien pruefen (nur Datei-Kopie, kein systemctl) =="
|
||||
for unit in nexarch-connect-app nexarch-dms-app nexarch-dms-worker; do
|
||||
for unit in nexarch-ai-app nexarch-connect-app nexarch-dms-app nexarch-dms-worker; do
|
||||
tmpl="$SCRIPT_DIR/systemd/${unit}.service.tmpl"
|
||||
dest="/etc/systemd/system/${unit}.service"
|
||||
if [ ! -f "$tmpl" ]; then
|
||||
@@ -199,6 +203,9 @@ while [ "$attempt" -lt "$MAX_ATTEMPTS" ]; do
|
||||
fi
|
||||
if [ ! -f "$dest" ] || grep -q '__INSTALL_DIR__\|__STORAGE_DIR__\|__STAGING_DIR__' "$dest" 2>/dev/null; then
|
||||
case "$unit" in
|
||||
nexarch-ai-app)
|
||||
sed -e "s#__INSTALL_DIR__#${AI_INSTALL_DIR}#g" "$tmpl" > "$dest"
|
||||
;;
|
||||
nexarch-connect-app)
|
||||
sed -e "s#__INSTALL_DIR__#${CONNECT_INSTALL_DIR}#g" "$tmpl" > "$dest"
|
||||
;;
|
||||
@@ -234,7 +241,7 @@ if [ "$ready" -eq 1 ]; then
|
||||
echo " systemctl daemon-reload"
|
||||
echo " systemctl restart nexarch-account-api"
|
||||
echo " sleep 3 && curl -sf http://127.0.0.1:8099/auth/module-jwks && echo OK"
|
||||
echo " systemctl enable --now nexarch-connect-app nexarch-dms-app nexarch-dms-worker"
|
||||
echo " systemctl enable --now nexarch-ai-app nexarch-connect-app nexarch-dms-app nexarch-dms-worker"
|
||||
echo " $SCRIPT_DIR/rollout-131-healthcheck.sh"
|
||||
echo
|
||||
echo "(Alternativ deckt deploy/rollout-131-apply.sh genau diese Schritte in einem Lauf ab.)"
|
||||
|
||||
@@ -67,6 +67,12 @@ echo "-- connect-app.env (neu, Connect API-02) --"
|
||||
ensure_var "$ENV_DIR/connect-app.env" NEXARCH_CONNECT_APP_LISTEN_ADDR "z.B. 127.0.0.1:9500"
|
||||
ensure_var "$ENV_DIR/connect-app.env" NEXARCH_CONNECT_APP_TENANT_DSN "Postgres-DSN fuer den Connect-Mandanten"
|
||||
|
||||
echo "-- ai-app.env (neu, ENG-10) --"
|
||||
ensure_var "$ENV_DIR/ai-app.env" NEXARCH_AI_APP_LISTEN_ADDR "z.B. 127.0.0.1:8900"
|
||||
ensure_var "$ENV_DIR/ai-app.env" NEXARCH_AI_APP_TENANT_DSN "Postgres-DSN fuer die AI-Datenbank"
|
||||
ensure_var "$ENV_DIR/ai-app.env" NEXARCH_AI_APP_SERVICE_TOKEN "Token, das alle Aufrufer im Header X-Service-Token senden -- muss zu den Aufrufern passen"
|
||||
ensure_var "$ENV_DIR/ai-app.env" NEXARCH_AI_APP_POLICY_URL "policy-api-Adresse fuer die Rechtepruefung der Suche (alternativ NEXARCH_AI_APP_POLICY_DISABLED=1 als Uebergang)"
|
||||
|
||||
echo "-- dms-app.env (Ergaenzungen aus dieser Session gehaerteter Konfiguration) --"
|
||||
# Pflicht zum Start ueberhaupt (TENANT_DSN/TENANT_SLUG waren auf 131 bei der
|
||||
# Bestandsaufnahme bereits gesetzt, hier nur zur Vollstaendigkeit abgesichert):
|
||||
|
||||
Reference in new issue
Block a user