initial COM2 system snapshot
This commit is contained in:
132
COM2_CANONICAL_WRITE_AND_UP.sh
Executable file
132
COM2_CANONICAL_WRITE_AND_UP.sh
Executable file
@@ -0,0 +1,132 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DIR="/opt/hx-ki/com2-stack"
|
||||||
|
F="$DIR/docker-compose.yml"
|
||||||
|
ENVF="$DIR/.env"
|
||||||
|
NET="hxki-internal"
|
||||||
|
|
||||||
|
mkdir -p "$DIR"
|
||||||
|
|
||||||
|
echo "=== COM2 · CANONICAL WRITE + UP ==="
|
||||||
|
|
||||||
|
# Netzwerk muss existieren (external)
|
||||||
|
docker network inspect "$NET" >/dev/null 2>&1 || docker network create "$NET" >/dev/null
|
||||||
|
|
||||||
|
# .env (Passwörter hier)
|
||||||
|
cat > "$ENVF" <<'ENV'
|
||||||
|
PG_USER=hxki
|
||||||
|
PG_PASSWORD=CHANGE_ME_STRONG
|
||||||
|
PG_DB=n8n
|
||||||
|
|
||||||
|
MAUTIC_DB_ROOT_PASSWORD=CHANGE_ME_STRONG
|
||||||
|
MAUTIC_DB_NAME=mautic
|
||||||
|
MAUTIC_DB_USER=mautic
|
||||||
|
MAUTIC_DB_PASSWORD=CHANGE_ME_STRONG
|
||||||
|
|
||||||
|
N8N_HOST=n8n.hx-ki.com
|
||||||
|
N8N_PROTOCOL=https
|
||||||
|
ENV
|
||||||
|
|
||||||
|
# Compose: autark, ohne Grafana
|
||||||
|
cat > "$F" <<'YML'
|
||||||
|
services:
|
||||||
|
hxki-postgres:
|
||||||
|
image: postgres:16
|
||||||
|
container_name: hxki-postgres
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: ${PG_USER}
|
||||||
|
POSTGRES_PASSWORD: ${PG_PASSWORD}
|
||||||
|
POSTGRES_DB: ${PG_DB}
|
||||||
|
volumes:
|
||||||
|
- /opt/hx-ki/postgres:/var/lib/postgresql/data
|
||||||
|
networks: [hxki-internal]
|
||||||
|
ports: ["5432:5432"]
|
||||||
|
|
||||||
|
hxki-mariadb:
|
||||||
|
image: mariadb:10.11
|
||||||
|
container_name: hxki-mariadb
|
||||||
|
restart: unless-stopped
|
||||||
|
command: ["--character-set-server=utf8mb4","--collation-server=utf8mb4_unicode_ci"]
|
||||||
|
environment:
|
||||||
|
MARIADB_ROOT_PASSWORD: ${MAUTIC_DB_ROOT_PASSWORD}
|
||||||
|
MARIADB_DATABASE: ${MAUTIC_DB_NAME}
|
||||||
|
MARIADB_USER: ${MAUTIC_DB_USER}
|
||||||
|
MARIADB_PASSWORD: ${MAUTIC_DB_PASSWORD}
|
||||||
|
volumes:
|
||||||
|
- /opt/hx-ki/mautic/db:/var/lib/mysql
|
||||||
|
networks: [hxki-internal]
|
||||||
|
ports: ["3306:3306"]
|
||||||
|
|
||||||
|
hxki-mautic:
|
||||||
|
image: mautic/mautic:5-apache
|
||||||
|
container_name: hxki-mautic
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on: [hxki-mariadb]
|
||||||
|
environment:
|
||||||
|
MAUTIC_DB_HOST: hxki-mariadb
|
||||||
|
MAUTIC_DB_USER: ${MAUTIC_DB_USER}
|
||||||
|
MAUTIC_DB_PASSWORD: ${MAUTIC_DB_PASSWORD}
|
||||||
|
MAUTIC_DB_NAME: ${MAUTIC_DB_NAME}
|
||||||
|
volumes:
|
||||||
|
- /opt/hx-ki/mautic/app:/var/www/html
|
||||||
|
networks: [hxki-internal]
|
||||||
|
ports: ["8080:80"]
|
||||||
|
|
||||||
|
hxki-n8n:
|
||||||
|
image: docker.n8n.io/n8nio/n8n:latest
|
||||||
|
container_name: hxki-n8n
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on: [hxki-postgres]
|
||||||
|
environment:
|
||||||
|
DB_TYPE: postgresdb
|
||||||
|
DB_POSTGRESDB_HOST: hxki-postgres
|
||||||
|
DB_POSTGRESDB_PORT: 5432
|
||||||
|
DB_POSTGRESDB_DATABASE: ${PG_DB}
|
||||||
|
DB_POSTGRESDB_USER: ${PG_USER}
|
||||||
|
DB_POSTGRESDB_PASSWORD: ${PG_PASSWORD}
|
||||||
|
N8N_HOST: ${N8N_HOST}
|
||||||
|
N8N_PROTOCOL: ${N8N_PROTOCOL}
|
||||||
|
N8N_PORT: 5678
|
||||||
|
N8N_EDITOR_BASE_URL: ${N8N_PROTOCOL}://${N8N_HOST}
|
||||||
|
WEBHOOK_URL: ${N8N_PROTOCOL}://${N8N_HOST}
|
||||||
|
volumes:
|
||||||
|
- /data/HXKI_WORKSPACE/router:/home/node/.n8n
|
||||||
|
- /data/HXKI_WORKSPACE:/data/HXKI_WORKSPACE
|
||||||
|
networks: [hxki-internal]
|
||||||
|
ports: ["5678:5678"]
|
||||||
|
|
||||||
|
# Caddy auf COM2 – Cluster-Client: Container bleibt drin.
|
||||||
|
# Cluster-spezifische Settings kommen über DEIN Caddy-Cluster-Mechanismus (Volumes/Env/Config),
|
||||||
|
# den wir nicht raten, sondern aus deinem vorhandenen COM2-Caddy Setup übernehmen.
|
||||||
|
hx-caddy:
|
||||||
|
image: caddy:2
|
||||||
|
container_name: hx-caddy
|
||||||
|
restart: unless-stopped
|
||||||
|
networks: [hxki-internal]
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
- "443:443/udp"
|
||||||
|
- "2019:2019"
|
||||||
|
volumes:
|
||||||
|
- /opt/hx-ki/caddy/Caddyfile:/etc/caddy/Caddyfile:ro
|
||||||
|
- /opt/hx-ki/caddy/data:/data
|
||||||
|
- /opt/hx-ki/caddy/config:/config
|
||||||
|
|
||||||
|
networks:
|
||||||
|
hxki-internal:
|
||||||
|
external: true
|
||||||
|
YML
|
||||||
|
|
||||||
|
echo "[1] Validate"
|
||||||
|
( cd "$DIR" && docker compose --env-file .env config >/dev/null )
|
||||||
|
echo "OK: compose valide."
|
||||||
|
|
||||||
|
echo "[2] Up"
|
||||||
|
( cd "$DIR" && docker compose --env-file .env up -d )
|
||||||
|
|
||||||
|
echo "[3] Status"
|
||||||
|
docker ps --format 'NAME={{.Names}} STATUS={{.Status}} PORTS={{.Ports}}' | egrep 'hxki-|hx-caddy' || true
|
||||||
|
echo "=== ENDE ==="
|
||||||
31
COM2_CAUSE_DOCTOR_ONE_SHOT.sh
Executable file
31
COM2_CAUSE_DOCTOR_ONE_SHOT.sh
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
cd /opt/hx-ki/com2-stack
|
||||||
|
|
||||||
|
echo "=== COM2 CAUSE DOCTOR (one-shot) ==="
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[1] Status"
|
||||||
|
docker ps --format 'NAME={{.Names}} STATUS={{.Status}} PORTS={{.Ports}}' | egrep 'hxki-|hx-caddy' || true
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[2] Logs (n8n/mautic/postgres/mariadb) letzte 80"
|
||||||
|
for c in hxki-n8n hxki-mautic hxki-postgres hxki-mariadb; do
|
||||||
|
echo; echo "--- $c ---"
|
||||||
|
docker logs --tail=80 "$c" 2>&1 || true
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[3] Listen-Check im Container (muss LISTEN zeigen)"
|
||||||
|
docker exec -it hxki-n8n sh -lc '(ss -lntp 2>/dev/null || true) | egrep "(:5678\\b|LISTEN)" || true'
|
||||||
|
docker exec -it hxki-postgres sh -lc '(ss -lntp 2>/dev/null || true) | egrep "(:5432\\b|LISTEN)" || true'
|
||||||
|
docker exec -it hxki-mariadb sh -lc '(ss -lntp 2>/dev/null || true) | egrep "(:3306\\b|LISTEN)" || true'
|
||||||
|
docker exec -it hxki-mautic sh -lc '(ss -lntp 2>/dev/null || true) | egrep "(:80\\b|LISTEN)" || true'
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[4] Caddy -> Upstreams (nur Test, kein Fix)"
|
||||||
|
docker exec -it hx-caddy sh -lc 'wget -qO- http://hxki-n8n:5678/ >/dev/null && echo OK_CADDY_TO_N8N || echo FAIL_CADDY_TO_N8N'
|
||||||
|
docker exec -it hx-caddy sh -lc 'wget -qO- http://hxki-mautic/ >/dev/null && echo OK_CADDY_TO_MAUTIC || echo FAIL_CADDY_TO_MAUTIC'
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "=== ENDE ==="
|
||||||
31
COM2_CLEAN_NAME_CONFLICTS_ONE_SHOT.sh
Executable file
31
COM2_CLEAN_NAME_CONFLICTS_ONE_SHOT.sh
Executable file
@@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DIR="/opt/hx-ki/com2-stack"
|
||||||
|
cd "$DIR"
|
||||||
|
|
||||||
|
echo "=== COM2 · CLEAN NAME CONFLICTS (container-only, no data loss) ==="
|
||||||
|
echo "[1] Zeige laufende hxki-Container (harte Fakten)"
|
||||||
|
docker ps --format 'NAME={{.Names}} STATUS={{.Status}}' | egrep '^(hxki-|hx-caddy)' || true
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "[2] Versuche COM2 sauber runterzufahren (falls Projekt schon existiert)"
|
||||||
|
docker compose down --remove-orphans || true
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "[3] Entferne nur Konflikt-Container (NUR Container, keine Volumes/Dirs)"
|
||||||
|
for n in hxki-mariadb hxki-postgres hxki-n8n hxki-mautic hxki-web hx-caddy hxki-grafana; do
|
||||||
|
if docker ps -a --format '{{.Names}}' | grep -qx "$n"; then
|
||||||
|
echo " - rm -f $n"
|
||||||
|
docker rm -f "$n" >/dev/null || true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "[4] COM2 hochfahren"
|
||||||
|
docker compose up -d --remove-orphans
|
||||||
|
echo
|
||||||
|
|
||||||
|
echo "[5] Status"
|
||||||
|
docker ps --format 'NAME={{.Names}} STATUS={{.Status}} PORTS={{.Ports}}' | egrep 'hxki-|hx-caddy' || true
|
||||||
|
echo "=== DONE ==="
|
||||||
218
COM2_DB_ALIGN_ONE_SHOT.sh
Executable file
218
COM2_DB_ALIGN_ONE_SHOT.sh
Executable file
@@ -0,0 +1,218 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DIR="/opt/hx-ki/com2-stack"
|
||||||
|
F="$DIR/docker-compose.yml"
|
||||||
|
ENVF="$DIR/.env"
|
||||||
|
NET="hxki-internal"
|
||||||
|
TS="$(date +%Y%m%d-%H%M%S)"
|
||||||
|
BKDIR="/opt/hx-ki/backups/com2-db-align-$TS"
|
||||||
|
mkdir -p "$BKDIR"
|
||||||
|
|
||||||
|
echo "=== COM2 DB ALIGN (one-shot) ==="
|
||||||
|
echo "Compose: $F"
|
||||||
|
echo "Env: $ENVF"
|
||||||
|
echo "Backup: $BKDIR"
|
||||||
|
|
||||||
|
[ -f "$F" ] || { echo "FEHLT: $F"; exit 1; }
|
||||||
|
[ -f "$ENVF" ] || { echo "FEHLT: $ENVF"; exit 1; }
|
||||||
|
|
||||||
|
cp -a "$F" "$BKDIR/docker-compose.yml"
|
||||||
|
cp -a "$ENVF" "$BKDIR/.env"
|
||||||
|
|
||||||
|
# Netzwerk muss existieren (external)
|
||||||
|
docker network inspect "$NET" >/dev/null 2>&1 || docker network create "$NET" >/dev/null
|
||||||
|
|
||||||
|
# --- .env laden (ohne zu crashen wenn Leerzeilen/Kommentare) ---
|
||||||
|
set -a
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
source <(grep -v '^\s*#' "$ENVF" | sed '/^\s*$/d')
|
||||||
|
set +a
|
||||||
|
|
||||||
|
need_real_pw() {
|
||||||
|
local k="$1"; local v="${!k:-}"
|
||||||
|
if [[ -z "$v" || "$v" =~ CHANGE_ME|CHANGEME|changeme ]]; then return 0; fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[0] Secrets prüfen (keine Platzhalter erlaubt)"
|
||||||
|
if need_real_pw PG_PASSWORD || need_real_pw MARIADB_ROOT_PASSWORD || need_real_pw MAUTIC_DB_PASSWORD; then
|
||||||
|
echo "WARN: In $ENVF sind Platzhalter/fehlende Werte."
|
||||||
|
echo " Ich frage jetzt EINMAL nach echten Passwörtern und schreibe sie nach $ENVF."
|
||||||
|
echo
|
||||||
|
|
||||||
|
if need_real_pw PG_PASSWORD; then
|
||||||
|
read -r -s -p "PG_PASSWORD (für Postgres User hxki): " PG_PASSWORD; echo
|
||||||
|
fi
|
||||||
|
if need_real_pw MARIADB_ROOT_PASSWORD; then
|
||||||
|
read -r -s -p "MARIADB_ROOT_PASSWORD (neues Root-PW für MariaDB): " MARIADB_ROOT_PASSWORD; echo
|
||||||
|
fi
|
||||||
|
if need_real_pw MAUTIC_DB_PASSWORD; then
|
||||||
|
read -r -s -p "MAUTIC_DB_PASSWORD (für MariaDB User mautic): " MAUTIC_DB_PASSWORD; echo
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Minimaler .env Patch (nur Keys, die wir brauchen)
|
||||||
|
# Backup ist schon in BKDIR.
|
||||||
|
awk -v pg="$PG_PASSWORD" -v mr="$MARIADB_ROOT_PASSWORD" -v mp="$MAUTIC_DB_PASSWORD" '
|
||||||
|
BEGIN{done_pg=done_mr=done_mp=0}
|
||||||
|
/^PG_PASSWORD=/{print "PG_PASSWORD="pg; done_pg=1; next}
|
||||||
|
/^MARIADB_ROOT_PASSWORD=/{print "MARIADB_ROOT_PASSWORD="mr; done_mr=1; next}
|
||||||
|
/^MAUTIC_DB_PASSWORD=/{print "MAUTIC_DB_PASSWORD="mp; done_mp=1; next}
|
||||||
|
{print}
|
||||||
|
END{
|
||||||
|
if(!done_pg) print "PG_PASSWORD="pg
|
||||||
|
if(!done_mr) print "MARIADB_ROOT_PASSWORD="mr
|
||||||
|
if(!done_mp) print "MAUTIC_DB_PASSWORD="mp
|
||||||
|
}
|
||||||
|
' "$ENVF" > "$ENVF.tmp" && mv "$ENVF.tmp" "$ENVF"
|
||||||
|
|
||||||
|
echo "OK: $ENVF aktualisiert (Backup: $BKDIR/.env)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Reload .env after potential patch
|
||||||
|
set -a
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
source <(grep -v '^\s*#' "$ENVF" | sed '/^\s*$/d')
|
||||||
|
set +a
|
||||||
|
|
||||||
|
: "${PG_USER:=hxki}"
|
||||||
|
: "${PG_DB:=n8n}"
|
||||||
|
: "${MAUTIC_DB_USER:=mautic}"
|
||||||
|
: "${MAUTIC_DB_NAME:=mautic}"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[1] Orchester: sicher hoch (damit DB-Container laufen)"
|
||||||
|
cd "$DIR"
|
||||||
|
docker compose up -d --remove-orphans
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[2] POSTGRES align (User+DB+PW) – Volume bleibt"
|
||||||
|
# Wir gehen als postgres-OS-User rein (nicht als DB-User), damit kein Passwort-Raten nötig ist.
|
||||||
|
docker exec -u postgres -i hxki-postgres psql -d postgres <<SQL
|
||||||
|
DO \$\$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = '${PG_USER}') THEN
|
||||||
|
CREATE ROLE ${PG_USER} LOGIN;
|
||||||
|
END IF;
|
||||||
|
ALTER ROLE ${PG_USER} WITH PASSWORD '${PG_PASSWORD}';
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM pg_database WHERE datname = '${PG_DB}') THEN
|
||||||
|
CREATE DATABASE ${PG_DB} OWNER ${PG_USER};
|
||||||
|
END IF;
|
||||||
|
END
|
||||||
|
\$\$;
|
||||||
|
SQL
|
||||||
|
echo "OK: Postgres User/DB/PW aligned: ${PG_USER}/${PG_DB}"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[3] MARIADB Root-Reset (Recovery-Container) + Mautic User/DB fix – Volume bleibt"
|
||||||
|
# Volume/Bind für /var/lib/mysql ermitteln
|
||||||
|
MOUNT_SRC="$(docker inspect hxki-mariadb --format '{{range .Mounts}}{{if eq .Destination "/var/lib/mysql"}}{{.Source}}{{end}}{{end}}')"
|
||||||
|
MOUNT_NAME="$(docker inspect hxki-mariadb --format '{{range .Mounts}}{{if eq .Destination "/var/lib/mysql"}}{{.Name}}{{end}}{{end}}')"
|
||||||
|
IMG="$(docker inspect hxki-mariadb --format '{{.Config.Image}}')"
|
||||||
|
|
||||||
|
if [[ -n "$MOUNT_NAME" ]]; then
|
||||||
|
VOLARG="-v ${MOUNT_NAME}:/var/lib/mysql"
|
||||||
|
elif [[ -n "$MOUNT_SRC" ]]; then
|
||||||
|
VOLARG="-v ${MOUNT_SRC}:/var/lib/mysql"
|
||||||
|
else
|
||||||
|
echo "FAIL: Konnte MariaDB /var/lib/mysql Mount nicht ermitteln."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Mautic stoppen damit es nicht dauernd hämmert
|
||||||
|
docker stop hxki-mautic >/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
# MariaDB stoppen (damit Volume frei ist)
|
||||||
|
docker stop hxki-mariadb >/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
# Recovery-Container starten (ohne Grants, ohne Network)
|
||||||
|
docker rm -f hxki-mariadb-recover >/dev/null 2>&1 || true
|
||||||
|
docker run -d --name hxki-mariadb-recover $VOLARG --entrypoint mysqld "$IMG" \
|
||||||
|
--skip-grant-tables --skip-networking --socket=/tmp/mysqld.sock >/dev/null
|
||||||
|
|
||||||
|
# Warten bis Socket da ist
|
||||||
|
for i in {1..40}; do
|
||||||
|
if docker exec hxki-mariadb-recover sh -lc 'test -S /tmp/mysqld.sock'; then break; fi
|
||||||
|
sleep 0.25
|
||||||
|
done
|
||||||
|
docker exec hxki-mariadb-recover sh -lc 'test -S /tmp/mysqld.sock' || { echo "FAIL: MariaDB recover socket nicht bereit"; docker logs --tail=80 hxki-mariadb-recover; exit 1; }
|
||||||
|
|
||||||
|
# Root-PW setzen + Mautic DB/User fixen
|
||||||
|
docker exec -i hxki-mariadb-recover sh -lc "mariadb --protocol=socket -uroot -S /tmp/mysqld.sock" <<SQL
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
ALTER USER IF EXISTS 'root'@'localhost' IDENTIFIED BY '${MARIADB_ROOT_PASSWORD}';
|
||||||
|
ALTER USER IF EXISTS 'root'@'%' IDENTIFIED BY '${MARIADB_ROOT_PASSWORD}';
|
||||||
|
|
||||||
|
CREATE DATABASE IF NOT EXISTS ${MAUTIC_DB_NAME};
|
||||||
|
CREATE USER IF NOT EXISTS '${MAUTIC_DB_USER}'@'%' IDENTIFIED BY '${MAUTIC_DB_PASSWORD}';
|
||||||
|
ALTER USER '${MAUTIC_DB_USER}'@'%' IDENTIFIED BY '${MAUTIC_DB_PASSWORD}';
|
||||||
|
GRANT ALL PRIVILEGES ON ${MAUTIC_DB_NAME}.* TO '${MAUTIC_DB_USER}'@'%';
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
SQL
|
||||||
|
|
||||||
|
# Recovery runter
|
||||||
|
docker rm -f hxki-mariadb-recover >/dev/null
|
||||||
|
|
||||||
|
# MariaDB wieder hoch über Compose (mit NEUEM Root-PW in .env)
|
||||||
|
cd "$DIR"
|
||||||
|
docker compose up -d --remove-orphans hxki-mariadb
|
||||||
|
|
||||||
|
# kurz warten
|
||||||
|
sleep 2
|
||||||
|
|
||||||
|
# Mautic wieder hoch
|
||||||
|
docker compose up -d --remove-orphans hxki-mautic
|
||||||
|
|
||||||
|
echo "OK: MariaDB Root-PW + Mautic DB/User aligned."
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[4] Services neu hoch (n8n/web/caddy) und harte Checks"
|
||||||
|
docker compose up -d --remove-orphans
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[A] Container Status"
|
||||||
|
docker ps --format 'NAME={{.Names}} STATUS={{.Status}} PORTS={{.Ports}}' | egrep 'hxki-|hx-caddy' || true
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[B] Netzwerk-Mitglieder ($NET)"
|
||||||
|
docker network inspect "$NET" --format '{{range $id,$c := .Containers}}{{println $c.Name}}{{end}}' | sort
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[C] Caddy -> Upstreams (intern, 10s Retry)"
|
||||||
|
check_up() {
|
||||||
|
local name="$1" url="$2"
|
||||||
|
for i in {1..20}; do
|
||||||
|
if docker exec hx-caddy sh -lc "wget -qO- '$url' >/dev/null 2>&1"; then
|
||||||
|
echo "OK_CADDY_TO_${name}"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
sleep 0.5
|
||||||
|
done
|
||||||
|
echo "FAIL_CADDY_TO_${name}"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
FAIL=0
|
||||||
|
check_up WEB "http://hxki-web:3000/" || FAIL=1
|
||||||
|
check_up N8N "http://hxki-n8n:5678/" || FAIL=1
|
||||||
|
check_up MAUTIC "http://hxki-mautic:80/" || FAIL=1
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[D] Logs (kurz)"
|
||||||
|
echo "--- n8n ---"
|
||||||
|
docker logs --tail=40 hxki-n8n || true
|
||||||
|
echo "--- mautic ---"
|
||||||
|
docker logs --tail=40 hxki-mautic || true
|
||||||
|
echo "--- web ---"
|
||||||
|
docker logs --tail=40 hxki-web || true
|
||||||
|
echo "--- caddy ---"
|
||||||
|
docker logs --tail=40 hx-caddy || true
|
||||||
|
|
||||||
|
echo
|
||||||
|
if [[ "$FAIL" -eq 0 ]]; then
|
||||||
|
echo "=== OK: COM2 ist wieder stabil (DBs aligned, Upstreams erreichbar) ==="
|
||||||
|
else
|
||||||
|
echo "=== WARN: DBs aligned, aber mind. ein Upstream ist noch nicht erreichbar (siehe FAIL_*) ==="
|
||||||
|
echo "Backup liegt hier: $BKDIR"
|
||||||
|
fi
|
||||||
152
COM2_DB_ALIGN_TO_ENV_ONE_SHOT.sh
Executable file
152
COM2_DB_ALIGN_TO_ENV_ONE_SHOT.sh
Executable file
@@ -0,0 +1,152 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DIR="/opt/hx-ki/com2-stack"
|
||||||
|
ENVF="$DIR/.env"
|
||||||
|
NET="hxki-internal"
|
||||||
|
BK="/opt/hx-ki/backups/com2-db-align-$(date +%Y%m%d-%H%M%S)"
|
||||||
|
mkdir -p "$BK"
|
||||||
|
|
||||||
|
echo "=== COM2 · DB ALIGN TO ENV (ONE-SHOT, NO DATA LOSS) ==="
|
||||||
|
echo "Env: $ENVF"
|
||||||
|
echo "Backup: $BK"
|
||||||
|
echo
|
||||||
|
|
||||||
|
[ -f "$ENVF" ] || { echo "FAIL: FEHLT $ENVF"; exit 1; }
|
||||||
|
if grep -qE 'CHANGE_ME|CHANGEME|changeme' "$ENVF"; then
|
||||||
|
echo "FAIL: In $ENVF sind noch Platzhalter (CHANGE_ME...)."; exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# .env laden (nur simple KEY=VALUE Zeilen)
|
||||||
|
set -a
|
||||||
|
. "$ENVF"
|
||||||
|
set +a
|
||||||
|
|
||||||
|
# Pflicht-Keys Postgres
|
||||||
|
: "${PG_USER:?fehlend in .env}"
|
||||||
|
: "${PG_PASSWORD:?fehlend in .env}"
|
||||||
|
: "${PG_DB:?fehlend in .env}"
|
||||||
|
|
||||||
|
# Pflicht-Keys MariaDB/Mautic (passen zu deinem Compose – ggf. in .env ergänzen)
|
||||||
|
: "${MYSQL_ROOT_PASSWORD:?fehlend in .env}"
|
||||||
|
: "${MAUTIC_DB_NAME:?fehlend in .env}"
|
||||||
|
: "${MAUTIC_DB_USER:?fehlend in .env}"
|
||||||
|
: "${MAUTIC_DB_PASSWORD:?fehlend in .env}"
|
||||||
|
|
||||||
|
docker network inspect "$NET" >/dev/null 2>&1 || docker network create "$NET" >/dev/null
|
||||||
|
|
||||||
|
cd "$DIR"
|
||||||
|
|
||||||
|
echo "[1] DB-Container sauber runter (nur DBs)"
|
||||||
|
docker compose rm -sf hxki-postgres hxki-mariadb >/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
echo "[2] Postgres hoch (nur DB)"
|
||||||
|
docker compose up -d hxki-postgres
|
||||||
|
|
||||||
|
echo "[3] Wait: Postgres ready (pg_isready)"
|
||||||
|
for i in $(seq 1 60); do
|
||||||
|
if docker exec -u postgres hxki-postgres pg_isready -q >/dev/null 2>&1; then
|
||||||
|
echo "OK: Postgres ready."
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
if [ "$i" = "60" ]; then
|
||||||
|
echo "FAIL: Postgres wird nicht ready."; exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "[4] Postgres: Role/DB auf .env angleichen (ohne pg_hba-Hacks)"
|
||||||
|
# WICHTIG: als OS-User 'postgres' im Container -> lokaler Socket -> kein Passwort nötig
|
||||||
|
docker exec -u postgres hxki-postgres psql -v ON_ERROR_STOP=1 -d postgres <<SQL
|
||||||
|
DO \$\$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = '${PG_USER}') THEN
|
||||||
|
CREATE ROLE "${PG_USER}" LOGIN;
|
||||||
|
END IF;
|
||||||
|
END \$\$;
|
||||||
|
|
||||||
|
ALTER ROLE "${PG_USER}" WITH PASSWORD '${PG_PASSWORD}';
|
||||||
|
|
||||||
|
DO \$\$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM pg_database WHERE datname = '${PG_DB}') THEN
|
||||||
|
CREATE DATABASE "${PG_DB}" OWNER "${PG_USER}";
|
||||||
|
END IF;
|
||||||
|
END \$\$;
|
||||||
|
|
||||||
|
ALTER DATABASE "${PG_DB}" OWNER TO "${PG_USER}";
|
||||||
|
SQL
|
||||||
|
echo "OK: Postgres aligned."
|
||||||
|
|
||||||
|
echo "[5] MariaDB: Reset-Container im 'skip-grant-tables' Modus (NO DATA LOSS)"
|
||||||
|
# Image von vorhandener Definition nehmen (falls schon bekannt), sonst mariadb:10.11
|
||||||
|
IMG="$(docker inspect hxki-mariadb --format '{{.Config.Image}}' 2>/dev/null || true)"
|
||||||
|
[ -n "$IMG" ] || IMG="mariadb:10.11"
|
||||||
|
|
||||||
|
# Sicherheit: falls noch ein Reset-Container existiert
|
||||||
|
docker rm -f hxki-mariadb-reset >/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
# Reset-Container starten (gleicher Bind-Mount wie dein echtes Setup!)
|
||||||
|
docker run -d --name hxki-mariadb-reset \
|
||||||
|
--network "$NET" \
|
||||||
|
-v /opt/hx-ki/mautic/db:/var/lib/mysql \
|
||||||
|
"$IMG" \
|
||||||
|
--skip-networking --skip-grant-tables >/dev/null
|
||||||
|
|
||||||
|
echo "[6] Wait: MariaDB Reset ready"
|
||||||
|
for i in $(seq 1 60); do
|
||||||
|
if docker exec hxki-mariadb-reset sh -lc "mariadb -uroot -e 'SELECT 1' >/dev/null 2>&1"; then
|
||||||
|
echo "OK: MariaDB reset ready."
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
if [ "$i" = "60" ]; then
|
||||||
|
echo "FAIL: MariaDB reset wird nicht ready."; docker logs --tail=80 hxki-mariadb-reset || true; exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "[7] MariaDB: root-PW setzen + Mautic DB/User sicherstellen"
|
||||||
|
docker exec hxki-mariadb-reset sh -lc "mariadb -uroot <<'SQL'
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
|
||||||
|
-- Root Passwort (für localhost und %)
|
||||||
|
ALTER USER 'root'@'localhost' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}';
|
||||||
|
CREATE USER IF NOT EXISTS 'root'@'%' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}';
|
||||||
|
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' WITH GRANT OPTION;
|
||||||
|
|
||||||
|
-- Mautic DB + User
|
||||||
|
CREATE DATABASE IF NOT EXISTS \`${MAUTIC_DB_NAME}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
|
CREATE USER IF NOT EXISTS '${MAUTIC_DB_USER}'@'%' IDENTIFIED BY '${MAUTIC_DB_PASSWORD}';
|
||||||
|
GRANT ALL PRIVILEGES ON \`${MAUTIC_DB_NAME}\`.* TO '${MAUTIC_DB_USER}'@'%';
|
||||||
|
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
SQL"
|
||||||
|
echo "OK: MariaDB aligned."
|
||||||
|
|
||||||
|
echo "[8] Reset-Container stoppen"
|
||||||
|
docker rm -f hxki-mariadb-reset >/dev/null
|
||||||
|
|
||||||
|
echo "[9] Echtes Orchester hoch (DBs + Apps)"
|
||||||
|
docker compose up -d --remove-orphans
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[A] Quick checks"
|
||||||
|
echo "- Postgres Auth (mit .env User/PW):"
|
||||||
|
docker exec -e PGPASSWORD="${PG_PASSWORD}" hxki-postgres sh -lc "psql -U '${PG_USER}' -d '${PG_DB}' -c 'select 1' >/dev/null" \
|
||||||
|
&& echo "OK_PG_AUTH" || echo "FAIL_PG_AUTH"
|
||||||
|
|
||||||
|
echo "- MariaDB Auth (Mautic User):"
|
||||||
|
docker exec hxki-mariadb sh -lc "mariadb -u'${MAUTIC_DB_USER}' -p'${MAUTIC_DB_PASSWORD}' -e 'SELECT 1' '${MAUTIC_DB_NAME}' >/dev/null" \
|
||||||
|
&& echo "OK_MY_AUTH" || echo "FAIL_MY_AUTH"
|
||||||
|
|
||||||
|
echo "- n8n -> localhost:5678 im Container:"
|
||||||
|
docker exec hxki-n8n sh -lc "wget -qO- http://127.0.0.1:5678/ >/dev/null && echo OK_N8N_LISTEN || echo FAIL_N8N_LISTEN" || true
|
||||||
|
|
||||||
|
echo "- Caddy -> n8n/mautic/web intern:"
|
||||||
|
docker exec hx-caddy sh -lc "wget -qO- http://hxki-n8n:5678/ >/dev/null && echo OK_CADDY_TO_N8N || echo FAIL_CADDY_TO_N8N" || true
|
||||||
|
docker exec hx-caddy sh -lc "wget -qO- http://hxki-mautic/ >/dev/null && echo OK_CADDY_TO_MAUTIC || echo FAIL_CADDY_TO_MAUTIC" || true
|
||||||
|
docker exec hx-caddy sh -lc "wget -qO- http://hxki-web/ >/dev/null && echo OK_CADDY_TO_WEB || echo FAIL_CADDY_TO_WEB" || true
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "=== DONE ==="
|
||||||
|
echo "Backup dir: $BK"
|
||||||
232
COM2_DB_BINDMOUNT_RECOVER_AND_FIX_ONE_SHOT.sh
Executable file
232
COM2_DB_BINDMOUNT_RECOVER_AND_FIX_ONE_SHOT.sh
Executable file
@@ -0,0 +1,232 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# === Autorität ===
|
||||||
|
COMPOSE_DIR="/opt/hx-ki/com2-stack"
|
||||||
|
COMPOSE_FILE="${COMPOSE_DIR}/docker-compose.yml"
|
||||||
|
ENV_FILE="${COMPOSE_DIR}/.env"
|
||||||
|
|
||||||
|
# Bind-Mount Pfade (IST-Zustand, von dir geliefert)
|
||||||
|
PG_BIND="/opt/hx-ki/postgres"
|
||||||
|
MY_BIND="/opt/hx-ki/mautic/db"
|
||||||
|
|
||||||
|
# Container-Namen (IST)
|
||||||
|
PG_C="hxki-postgres"
|
||||||
|
MY_C="hxki-mariadb"
|
||||||
|
|
||||||
|
TS="$(date +%Y%m%d-%H%M%S)"
|
||||||
|
BK_DIR="/opt/hx-ki/backups/com2-one-shot-${TS}"
|
||||||
|
mkdir -p "$BK_DIR"
|
||||||
|
|
||||||
|
echo "=== COM2 ONE-SHOT · RECOVER + FIX (no guessing) ==="
|
||||||
|
echo "Compose: $COMPOSE_FILE"
|
||||||
|
echo "Env: $ENV_FILE"
|
||||||
|
echo "Backup: $BK_DIR"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# --- Preconditions ---
|
||||||
|
[ -f "$COMPOSE_FILE" ] || { echo "FAIL: FEHLT $COMPOSE_FILE"; exit 1; }
|
||||||
|
[ -d "$PG_BIND" ] || { echo "FAIL: FEHLT Postgres Bind $PG_BIND"; exit 1; }
|
||||||
|
[ -d "$MY_BIND" ] || { echo "FAIL: FEHLT MariaDB Bind $MY_BIND"; exit 1; }
|
||||||
|
|
||||||
|
cp -a "$COMPOSE_FILE" "$BK_DIR/docker-compose.yml.bak"
|
||||||
|
[ -f "$ENV_FILE" ] && cp -a "$ENV_FILE" "$BK_DIR/.env.bak" || true
|
||||||
|
|
||||||
|
# --- Helper: finde letzte echte Secrets (ohne CHANGE_ME) ---
|
||||||
|
find_last_secret() {
|
||||||
|
local key="$1"
|
||||||
|
local base="/opt/hx-ki"
|
||||||
|
# Suche in .env / compose / backups
|
||||||
|
# Priorität: neueste Datei gewinnt
|
||||||
|
local hit
|
||||||
|
hit="$(find "$base" -maxdepth 6 -type f \
|
||||||
|
\( -iname ".env" -o -iname "*.env" -o -iname "docker-compose*.yml" -o -iname "*.bak*" -o -iname "*.yml" \) \
|
||||||
|
-printf '%T@ %p\n' 2>/dev/null \
|
||||||
|
| sort -nr \
|
||||||
|
| awk '{print $2}' \
|
||||||
|
| while read -r f; do
|
||||||
|
# KEY=VALUE Zeile
|
||||||
|
if grep -qE "^${key}=" "$f" 2>/dev/null; then
|
||||||
|
v="$(grep -E "^${key}=" "$f" | tail -n 1 | cut -d= -f2- | tr -d '\r')"
|
||||||
|
# skip empty / placeholder
|
||||||
|
if [ -n "$v" ] && ! echo "$v" | grep -qiE 'CHANGE_ME|CHANGEME|changeme|__REPLACE__'; then
|
||||||
|
echo "$v"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done)" || true
|
||||||
|
echo "$hit"
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- 1) ENV befüllen aus altem Zustand (nur wenn gefunden) ---
|
||||||
|
echo "[1] Recover Secrets aus /opt/hx-ki (no guessing)"
|
||||||
|
PG_PASSWORD="$(find_last_secret "PG_PASSWORD")"
|
||||||
|
MARIADB_ROOT_PASSWORD="$(find_last_secret "MARIADB_ROOT_PASSWORD")"
|
||||||
|
MAUTIC_DB_PASSWORD="$(find_last_secret "MAUTIC_DB_PASSWORD")"
|
||||||
|
|
||||||
|
# Optional Defaults (nur wenn vorhanden)
|
||||||
|
PG_USER="$(find_last_secret "PG_USER")"; PG_USER="${PG_USER:-hxki}"
|
||||||
|
PG_DB="$(find_last_secret "PG_DB")"; PG_DB="${PG_DB:-n8n}"
|
||||||
|
|
||||||
|
MAUTIC_DB_USER="$(find_last_secret "MAUTIC_DB_USER")"; MAUTIC_DB_USER="${MAUTIC_DB_USER:-mautic}"
|
||||||
|
MAUTIC_DB_NAME="$(find_last_secret "MAUTIC_DB_NAME")"; MAUTIC_DB_NAME="${MAUTIC_DB_NAME:-mautic}"
|
||||||
|
|
||||||
|
# N8N Host/Proto (optional)
|
||||||
|
N8N_HOST="$(find_last_secret "N8N_HOST")"; N8N_HOST="${N8N_HOST:-n8n.hx-ki.com}"
|
||||||
|
N8N_PROTOCOL="$(find_last_secret "N8N_PROTOCOL")"; N8N_PROTOCOL="${N8N_PROTOCOL:-https}"
|
||||||
|
|
||||||
|
missing=0
|
||||||
|
[ -n "$PG_PASSWORD" ] || { echo "FAIL: PG_PASSWORD nicht gefunden (alter Zustand fehlt)"; missing=1; }
|
||||||
|
[ -n "$MARIADB_ROOT_PASSWORD" ] || { echo "FAIL: MARIADB_ROOT_PASSWORD nicht gefunden (alter Zustand fehlt)"; missing=1; }
|
||||||
|
[ -n "$MAUTIC_DB_PASSWORD" ] || { echo "FAIL: MAUTIC_DB_PASSWORD nicht gefunden (alter Zustand fehlt)"; missing=1; }
|
||||||
|
|
||||||
|
if [ "$missing" -ne 0 ]; then
|
||||||
|
echo
|
||||||
|
echo "STOP: Ich rate keine Passwörter."
|
||||||
|
echo "Gib mir die alten Values oder lege die alte .env Datei in /opt/hx-ki/ ab."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat > "$ENV_FILE" <<ENV
|
||||||
|
PG_USER=${PG_USER}
|
||||||
|
PG_PASSWORD=${PG_PASSWORD}
|
||||||
|
PG_DB=${PG_DB}
|
||||||
|
|
||||||
|
MARIADB_ROOT_PASSWORD=${MARIADB_ROOT_PASSWORD}
|
||||||
|
MAUTIC_DB_USER=${MAUTIC_DB_USER}
|
||||||
|
MAUTIC_DB_PASSWORD=${MAUTIC_DB_PASSWORD}
|
||||||
|
MAUTIC_DB_NAME=${MAUTIC_DB_NAME}
|
||||||
|
|
||||||
|
N8N_HOST=${N8N_HOST}
|
||||||
|
N8N_PROTOCOL=${N8N_PROTOCOL}
|
||||||
|
ENV
|
||||||
|
|
||||||
|
echo "OK: .env konsistent aus altem Zustand gesetzt."
|
||||||
|
echo
|
||||||
|
|
||||||
|
# --- 2) Stack runter (sauber) ---
|
||||||
|
echo "[2] Orchester down"
|
||||||
|
cd "$COMPOSE_DIR"
|
||||||
|
docker compose down --remove-orphans || true
|
||||||
|
|
||||||
|
# --- 3) Postgres: PW + DB fix via temporär trust (bind-mount pg_hba.conf) ---
|
||||||
|
echo "[3] Postgres Repair (bind-mount, deterministisch)"
|
||||||
|
|
||||||
|
PG_HBA="${PG_BIND}/pg_hba.conf"
|
||||||
|
[ -f "$PG_HBA" ] || { echo "FAIL: FEHLT $PG_HBA"; exit 1; }
|
||||||
|
|
||||||
|
cp -a "$PG_HBA" "$BK_DIR/pg_hba.conf.bak"
|
||||||
|
|
||||||
|
# Setze ALLE host/local auf trust (temporär), damit wir ohne Passwort reinkommen
|
||||||
|
# Danach setzen wir wieder auf scram-sha-256 zurück.
|
||||||
|
python3 - <<'PY'
|
||||||
|
from pathlib import Path
|
||||||
|
p = Path("/opt/hx-ki/postgres/pg_hba.conf")
|
||||||
|
s = p.read_text()
|
||||||
|
out=[]
|
||||||
|
for line in s.splitlines():
|
||||||
|
if line.strip().startswith("#") or line.strip()=="":
|
||||||
|
out.append(line); continue
|
||||||
|
parts=line.split()
|
||||||
|
if len(parts)>=5 and parts[0] in ("local","host","hostssl","hostnossl"):
|
||||||
|
# method ist letztes token
|
||||||
|
parts[-1]="trust"
|
||||||
|
out.append(" ".join(parts))
|
||||||
|
else:
|
||||||
|
out.append(line)
|
||||||
|
p.write_text("\n".join(out)+ "\n")
|
||||||
|
PY
|
||||||
|
|
||||||
|
# Starte nur Postgres
|
||||||
|
docker compose up -d "$PG_C"
|
||||||
|
|
||||||
|
# Warten bis Postgres bereit
|
||||||
|
for i in $(seq 1 60); do
|
||||||
|
if docker exec -i "$PG_C" sh -lc "pg_isready -U '$PG_USER' -d postgres >/dev/null 2>&1"; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
# Setze Passwort + DB erstellen (wenn fehlt)
|
||||||
|
docker exec -i "$PG_C" sh -lc "
|
||||||
|
psql -U '$PG_USER' -d postgres -v ON_ERROR_STOP=1 <<SQL
|
||||||
|
DO \$\$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM pg_database WHERE datname='${PG_DB}') THEN
|
||||||
|
CREATE DATABASE \"${PG_DB}\";
|
||||||
|
END IF;
|
||||||
|
END
|
||||||
|
\$\$;
|
||||||
|
ALTER ROLE \"${PG_USER}\" WITH PASSWORD '${PG_PASSWORD}';
|
||||||
|
SQL
|
||||||
|
"
|
||||||
|
|
||||||
|
# Restore pg_hba.conf (Original wiederherstellen)
|
||||||
|
cp -a "$BK_DIR/pg_hba.conf.bak" "$PG_HBA"
|
||||||
|
|
||||||
|
# Restart Postgres (scram wieder aktiv)
|
||||||
|
docker compose restart "$PG_C"
|
||||||
|
echo "OK: Postgres repaired (PW + DB) und auth wieder wie vorher."
|
||||||
|
echo
|
||||||
|
|
||||||
|
# --- 4) MariaDB: root + mautic-user fix via temporary skip-grant-tables ---
|
||||||
|
echo "[4] MariaDB Repair (bind-mount, deterministisch)"
|
||||||
|
|
||||||
|
# Stop mariadb, starte temporär mit skip-grant-tables (nur lokal im container)
|
||||||
|
docker compose stop "$MY_C" || true
|
||||||
|
|
||||||
|
TMP_C="hxki-mariadb-repair-${TS}"
|
||||||
|
# gleicher bind mount, aber ohne Auth
|
||||||
|
docker run -d --rm \
|
||||||
|
--name "$TMP_C" \
|
||||||
|
-v "${MY_BIND}:/var/lib/mysql" \
|
||||||
|
--network none \
|
||||||
|
mariadb:latest \
|
||||||
|
--skip-grant-tables --skip-networking
|
||||||
|
|
||||||
|
# warten bis mysqld da ist
|
||||||
|
for i in $(seq 1 60); do
|
||||||
|
if docker exec -i "$TMP_C" sh -lc "mysqladmin ping --silent >/dev/null 2>&1"; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
# Set root pw + mautic user + db
|
||||||
|
docker exec -i "$TMP_C" sh -lc "
|
||||||
|
mysql -uroot <<SQL
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
ALTER USER 'root'@'localhost' IDENTIFIED BY '${MARIADB_ROOT_PASSWORD}';
|
||||||
|
CREATE DATABASE IF NOT EXISTS \`${MAUTIC_DB_NAME}\`;
|
||||||
|
CREATE USER IF NOT EXISTS '${MAUTIC_DB_USER}'@'%' IDENTIFIED BY '${MAUTIC_DB_PASSWORD}';
|
||||||
|
GRANT ALL PRIVILEGES ON \`${MAUTIC_DB_NAME}\`.* TO '${MAUTIC_DB_USER}'@'%';
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
SQL
|
||||||
|
"
|
||||||
|
|
||||||
|
docker stop "$TMP_C" >/dev/null
|
||||||
|
|
||||||
|
# normal wieder hoch
|
||||||
|
docker compose up -d "$MY_C"
|
||||||
|
echo "OK: MariaDB repaired (root + mautic user/db)."
|
||||||
|
echo
|
||||||
|
|
||||||
|
# --- 5) Full stack up + checks ---
|
||||||
|
echo "[5] Orchester up"
|
||||||
|
docker compose up -d --remove-orphans
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "=== STATUS ==="
|
||||||
|
docker ps --format 'NAME={{.Names}} STATUS={{.Status}} PORTS={{.Ports}}' | egrep 'hxki-|hx-caddy' || true
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "=== CHECKS (DB auth) ==="
|
||||||
|
echo "[A] n8n logs (tail 20)"
|
||||||
|
docker logs --tail=20 hxki-n8n || true
|
||||||
|
echo
|
||||||
|
echo "[B] mautic logs (tail 20)"
|
||||||
|
docker logs --tail=20 hxki-mautic || true
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "=== ENDE · ONE-SHOT ==="
|
||||||
91
COM2_DB_CAUSE_FIX_ONE_SHOT.sh
Executable file
91
COM2_DB_CAUSE_FIX_ONE_SHOT.sh
Executable file
@@ -0,0 +1,91 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DIR="/opt/hx-ki/com2-stack"
|
||||||
|
ENVF="$DIR/.env"
|
||||||
|
NET="hxki-internal"
|
||||||
|
BKDIR="/opt/hx-ki/backups/com2-db-$(date +%Y%m%d-%H%M%S)"
|
||||||
|
|
||||||
|
cd "$DIR"
|
||||||
|
mkdir -p "$BKDIR"
|
||||||
|
|
||||||
|
echo "=== COM2 DB CAUSE FIX (one-shot, deterministisch) ==="
|
||||||
|
echo "Compose: $DIR/docker-compose.yml"
|
||||||
|
echo "ENV: $ENVF"
|
||||||
|
echo "Backup: $BKDIR"
|
||||||
|
|
||||||
|
[ -f "$DIR/docker-compose.yml" ] || { echo "FEHLT: $DIR/docker-compose.yml"; exit 1; }
|
||||||
|
[ -f "$ENVF" ] || { echo "FEHLT: $ENVF"; exit 1; }
|
||||||
|
|
||||||
|
# Kein Placeholders
|
||||||
|
if grep -qE 'CHANGE_ME|CHANGEME|changeme' "$ENVF"; then
|
||||||
|
echo "FAIL: In $ENVF sind noch Platzhalter (CHANGE_ME...). Erst echte Passwörter setzen."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Netzwerk external muss existieren (keine YAML-Frickelei, nur Host-Fakt)
|
||||||
|
docker network inspect "$NET" >/dev/null 2>&1 || docker network create "$NET" >/dev/null
|
||||||
|
|
||||||
|
echo "[1] Orchester runter"
|
||||||
|
docker compose down --remove-orphans || true
|
||||||
|
|
||||||
|
# Helper: Named Volume ermitteln (Destination muss Standard sein)
|
||||||
|
get_named_volume_for_dest() {
|
||||||
|
local c="$1" dest="$2"
|
||||||
|
docker inspect "$c" --format '{{range .Mounts}}{{if and (eq .Type "volume") (eq .Destination "'"$dest"'")}}{{println .Name}}{{end}}{{end}}'
|
||||||
|
}
|
||||||
|
|
||||||
|
backup_volume() {
|
||||||
|
local vol="$1" name="$2"
|
||||||
|
echo " -> Backup volume $vol -> $BKDIR/${name}.tar.gz"
|
||||||
|
docker run --rm -v "${vol}:/v:ro" -v "${BKDIR}:/b" alpine \
|
||||||
|
sh -lc "cd /v && tar -czf /b/${name}.tar.gz ."
|
||||||
|
}
|
||||||
|
|
||||||
|
PGC="hxki-postgres"
|
||||||
|
MDBC="hxki-mariadb"
|
||||||
|
|
||||||
|
echo "[2] Container check"
|
||||||
|
docker inspect "$PGC" >/dev/null 2>&1 || { echo "FAIL: Container fehlt: $PGC"; exit 1; }
|
||||||
|
docker inspect "$MDBC" >/dev/null 2>&1 || { echo "FAIL: Container fehlt: $MDBC"; exit 1; }
|
||||||
|
|
||||||
|
echo "[3] Volumes ermitteln"
|
||||||
|
PGVOL="$(get_named_volume_for_dest "$PGC" "/var/lib/postgresql/data" || true)"
|
||||||
|
MDBVOL="$(get_named_volume_for_dest "$MDBC" "/var/lib/mysql" || true)"
|
||||||
|
|
||||||
|
echo " Postgres volume: ${PGVOL:-<NONE>}"
|
||||||
|
echo " MariaDB volume: ${MDBVOL:-<NONE>}"
|
||||||
|
|
||||||
|
[ -n "${PGVOL:-}" ] || { echo "FAIL: Postgres nutzt kein Named Volume auf /var/lib/postgresql/data"; exit 1; }
|
||||||
|
[ -n "${MDBVOL:-}" ] || { echo "FAIL: MariaDB nutzt kein Named Volume auf /var/lib/mysql"; exit 1; }
|
||||||
|
|
||||||
|
echo "[4] Backup DB-Volumes (Beweis/Absicherung)"
|
||||||
|
backup_volume "$PGVOL" "postgres_${PGVOL}"
|
||||||
|
backup_volume "$MDBVOL" "mariadb_${MDBVOL}"
|
||||||
|
|
||||||
|
echo "[5] Volume-Reset (Ursache fixen: Secrets-Drift eliminieren)"
|
||||||
|
docker volume rm "$PGVOL" "$MDBVOL"
|
||||||
|
|
||||||
|
echo "[6] Orchester hoch (DBs initialisieren NEU aus .env)"
|
||||||
|
docker compose up -d --remove-orphans
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[7] Hard checks (nur Fakten)"
|
||||||
|
docker ps --format 'NAME={{.Names}} STATUS={{.Status}} PORTS={{.Ports}}' | egrep 'hxki-postgres|hxki-mariadb|hxki-n8n|hxki-mautic|hxki-web|hx-caddy' || true
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[8] DB Init-Fakten (Logs kurz)"
|
||||||
|
echo "--- postgres ---"
|
||||||
|
docker logs --tail=40 hxki-postgres || true
|
||||||
|
echo "--- mariadb ---"
|
||||||
|
docker logs --tail=40 hxki-mariadb || true
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[9] App-Fakten (Logs kurz)"
|
||||||
|
echo "--- n8n ---"
|
||||||
|
docker logs --tail=60 hxki-n8n || true
|
||||||
|
echo "--- mautic ---"
|
||||||
|
docker logs --tail=60 hxki-mautic || true
|
||||||
|
|
||||||
|
echo "=== ENDE ==="
|
||||||
|
echo "Backups: $BKDIR"
|
||||||
104
COM2_DB_VOLUME_REPAIR_ONE_SHOT.sh
Executable file
104
COM2_DB_VOLUME_REPAIR_ONE_SHOT.sh
Executable file
@@ -0,0 +1,104 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DIR="/opt/hx-ki/com2-stack"
|
||||||
|
ENVF="$DIR/.env"
|
||||||
|
|
||||||
|
echo "=== COM2 · DB VOLUME REPAIR (one-shot, deterministisch) ==="
|
||||||
|
[ -f "$ENVF" ] || { echo "FEHLT: $ENVF"; exit 1; }
|
||||||
|
|
||||||
|
# .env laden
|
||||||
|
set -a
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
source "$ENVF"
|
||||||
|
set +a
|
||||||
|
|
||||||
|
# Hard stop bei Platzhaltern
|
||||||
|
if grep -qE 'CHANGE_ME|CHANGEME|changeme' "$ENVF"; then
|
||||||
|
echo "FAIL: In $ENVF sind noch Platzhalter (CHANGE_ME...). Erst echte Passwörter setzen."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Erwartete Variablen (min.)
|
||||||
|
: "${PG_USER:?PG_USER fehlt}"
|
||||||
|
: "${PG_PASSWORD:?PG_PASSWORD fehlt}"
|
||||||
|
: "${PG_DB:?PG_DB fehlt}"
|
||||||
|
: "${MAUTIC_DB:?MAUTIC_DB fehlt}"
|
||||||
|
: "${MAUTIC_DB_USER:?MAUTIC_DB_USER fehlt}"
|
||||||
|
: "${MAUTIC_DB_PASSWORD:?MAUTIC_DB_PASSWORD fehlt}"
|
||||||
|
: "${MARIADB_ROOT_PASSWORD:?MARIADB_ROOT_PASSWORD fehlt}"
|
||||||
|
|
||||||
|
echo "[1] POSTGRES fix im bestehenden Volume (User/Pass/DB)"
|
||||||
|
# In der offiziellen postgres-image ist "local" i.d.R. trust -> psql ohne Passwort im Container möglich.
|
||||||
|
# Wir connecten als der initiale Admin-User (POSTGRES_USER im Container), der bei dir "hxki" ist.
|
||||||
|
if ! docker exec -i hxki-postgres sh -lc "psql -U '${PG_USER}' -d postgres -tAc \"SELECT 1\" >/dev/null" 2>/dev/null; then
|
||||||
|
echo "FAIL: Kann Postgres im Container nicht per local-socket als ${PG_USER} erreichen."
|
||||||
|
echo " Ursache: entweder Container nicht running oder local auth ist nicht trust."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Passwort angleichen + DB sicherstellen
|
||||||
|
docker exec -i hxki-postgres sh -lc "
|
||||||
|
psql -U '${PG_USER}' -d postgres -v ON_ERROR_STOP=1 <<SQL
|
||||||
|
DO \$\$
|
||||||
|
BEGIN
|
||||||
|
-- User sicherstellen
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname='${PG_USER}') THEN
|
||||||
|
CREATE ROLE ${PG_USER} LOGIN;
|
||||||
|
END IF;
|
||||||
|
END
|
||||||
|
\$\$;
|
||||||
|
|
||||||
|
ALTER ROLE ${PG_USER} WITH PASSWORD '${PG_PASSWORD}';
|
||||||
|
|
||||||
|
DO \$\$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM pg_database WHERE datname='${PG_DB}') THEN
|
||||||
|
CREATE DATABASE ${PG_DB} OWNER ${PG_USER};
|
||||||
|
END IF;
|
||||||
|
END
|
||||||
|
\$\$;
|
||||||
|
SQL
|
||||||
|
" >/dev/null
|
||||||
|
echo "OK: Postgres User/Pass/DB synchronisiert (Volume bleibt intakt)"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[2] MARIADB fix im bestehenden Volume (root erreichbar? user/db/grants)"
|
||||||
|
# Versuch 1: root via unix_socket (ohne Passwort) – klappt bei manchen Setups
|
||||||
|
if docker exec -i hxki-mariadb sh -lc "mysql -uroot -e 'SELECT 1' >/dev/null" 2>/dev/null; then
|
||||||
|
MYSQL_AUTH="mysql -uroot"
|
||||||
|
else
|
||||||
|
# Versuch 2: root mit Passwort aus .env
|
||||||
|
MYSQL_AUTH="mysql -uroot -p'${MARIADB_ROOT_PASSWORD}'"
|
||||||
|
if ! docker exec -i hxki-mariadb sh -lc "${MYSQL_AUTH} -e 'SELECT 1' >/dev/null" 2>/dev/null; then
|
||||||
|
echo "FAIL: MariaDB root login schlägt fehl (weder socket noch Passwort)."
|
||||||
|
echo " Das heißt: Volume hat ein anderes root-PW als in .env."
|
||||||
|
echo " Ferrari-like Optionen: (A) altes root-PW wiederfinden ODER (B) Volume kontrolliert neu initialisieren."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# DB + User + Grants für Mautic
|
||||||
|
docker exec -i hxki-mariadb sh -lc "
|
||||||
|
${MYSQL_AUTH} <<SQL
|
||||||
|
CREATE DATABASE IF NOT EXISTS \`${MAUTIC_DB}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
|
CREATE USER IF NOT EXISTS '${MAUTIC_DB_USER}'@'%' IDENTIFIED BY '${MAUTIC_DB_PASSWORD}';
|
||||||
|
GRANT ALL PRIVILEGES ON \`${MAUTIC_DB}\`.* TO '${MAUTIC_DB_USER}'@'%';
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
SQL
|
||||||
|
" >/dev/null
|
||||||
|
echo "OK: MariaDB mautic DB/User/Grants synchronisiert (Volume bleibt intakt)"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[3] Services neu starten (damit sie die jetzt korrekten Credentials nutzen)"
|
||||||
|
cd "$DIR"
|
||||||
|
docker compose restart hxki-postgres hxki-mariadb hxki-n8n hxki-mautic >/dev/null || true
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[4] Hard Checks (nur Fakten)"
|
||||||
|
echo "--- n8n should stop DB-auth loop ---"
|
||||||
|
docker logs --tail=25 hxki-n8n || true
|
||||||
|
echo "--- mautic should stop DB-auth loop ---"
|
||||||
|
docker logs --tail=25 hxki-mautic || true
|
||||||
|
|
||||||
|
echo "=== ENDE ==="
|
||||||
92
COM2_DISCOVER_AND_VERIFY_DB_CREDS_ONE_SHOT.sh
Executable file
92
COM2_DISCOVER_AND_VERIFY_DB_CREDS_ONE_SHOT.sh
Executable file
@@ -0,0 +1,92 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="/opt/hx-ki"
|
||||||
|
COMPOSE="/opt/hx-ki/com2-stack/docker-compose.yml"
|
||||||
|
PG_C="hxki-postgres"
|
||||||
|
MY_C="hxki-mariadb"
|
||||||
|
|
||||||
|
echo "=== COM2 · DISCOVER + VERIFY DB CREDS (one-shot, no guessing) ==="
|
||||||
|
|
||||||
|
[ -f "$COMPOSE" ] || { echo "FAIL: missing $COMPOSE"; exit 1; }
|
||||||
|
|
||||||
|
echo "[0] Start only DB containers (for verification tests)"
|
||||||
|
docker compose -f "$COMPOSE" up -d "$PG_C" "$MY_C" >/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
echo "[1] Read current container ENV (ground truth candidates)"
|
||||||
|
PG_USER="$(docker inspect "$PG_C" --format '{{range .Config.Env}}{{println .}}{{end}}' | awk -F= '/^POSTGRES_USER=/{print $2}' | tail -n1 || true)"
|
||||||
|
PG_DB="$(docker inspect "$PG_C" --format '{{range .Config.Env}}{{println .}}{{end}}' | awk -F= '/^POSTGRES_DB=/{print $2}' | tail -n1 || true)"
|
||||||
|
MY_ROOT_PW_ENV="$(docker inspect "$MY_C" --format '{{range .Config.Env}}{{println .}}{{end}}' | awk -F= '/^(MARIADB_ROOT_PASSWORD|MYSQL_ROOT_PASSWORD)=/{print $2}' | tail -n1 || true)"
|
||||||
|
|
||||||
|
echo " PG_USER=${PG_USER:-<unknown>} PG_DB=${PG_DB:-<unknown>}"
|
||||||
|
echo " MY_ROOT_PW_ENV=${MY_ROOT_PW_ENV:+<set>} ${MY_ROOT_PW_ENV:+"(not shown)"}"
|
||||||
|
|
||||||
|
echo "[2] Collect password candidates from existing files (no guessing)"
|
||||||
|
# We only scan /opt/hx-ki for known keys; no invention.
|
||||||
|
mapfile -t CANDIDATES < <(
|
||||||
|
grep -RInh --binary-files=without-match -E \
|
||||||
|
'(^|[[:space:]])(POSTGRES_PASSWORD|PG_PASSWORD|DB_POSTGRESDB_PASSWORD|MARIADB_ROOT_PASSWORD|MYSQL_ROOT_PASSWORD|MAUTIC_DB_PASSWORD|MAUTIC_DB_ROOT_PASSWORD)[[:space:]]*[:=][[:space:]]*[^[:space:]]+' \
|
||||||
|
"$ROOT" 2>/dev/null \
|
||||||
|
| sed -E 's/.*[:=][[:space:]]*//' \
|
||||||
|
| sed -E "s/^['\"]//; s/['\"]$//" \
|
||||||
|
| awk 'NF' \
|
||||||
|
| sort -u
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add current env passwords as candidates (if set)
|
||||||
|
if [ -n "${MY_ROOT_PW_ENV:-}" ]; then
|
||||||
|
CANDIDATES+=("$MY_ROOT_PW_ENV")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# De-dup again
|
||||||
|
mapfile -t CANDIDATES < <(printf "%s\n" "${CANDIDATES[@]}" | awk 'NF' | sort -u)
|
||||||
|
|
||||||
|
echo " Found candidates: ${#CANDIDATES[@]}"
|
||||||
|
|
||||||
|
mask() { local s="$1"; local n="${#s}"; if [ "$n" -le 4 ]; then echo "****"; else echo "****${s: -4}"; fi; }
|
||||||
|
|
||||||
|
echo "[3] Verify Postgres password by REAL login test (no assumptions)"
|
||||||
|
PG_OK=""
|
||||||
|
if [ -z "${PG_USER:-}" ]; then
|
||||||
|
echo " FAIL: PG_USER not detectable from container env"
|
||||||
|
else
|
||||||
|
for pw in "${CANDIDATES[@]}"; do
|
||||||
|
# Try connecting to default DBs first; existence of PG_DB may vary.
|
||||||
|
if docker exec -e PGPASSWORD="$pw" "$PG_C" sh -lc \
|
||||||
|
"psql -U '$PG_USER' -d postgres -tAc 'SELECT 1' >/dev/null 2>&1 || psql -U '$PG_USER' -d template1 -tAc 'SELECT 1' >/dev/null 2>&1"; then
|
||||||
|
PG_OK="$pw"
|
||||||
|
echo " OK: Postgres login works with password $(mask "$pw")"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
[ -n "$PG_OK" ] || echo " FAIL: No candidate password could log in to Postgres as user '$PG_USER'"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[4] Verify MariaDB root password by REAL login test (no assumptions)"
|
||||||
|
MY_OK=""
|
||||||
|
for pw in "${CANDIDATES[@]}"; do
|
||||||
|
if docker exec "$MY_C" sh -lc "mysql -uroot -p'$pw' -e 'SELECT 1' >/dev/null 2>&1"; then
|
||||||
|
MY_OK="$pw"
|
||||||
|
echo " OK: MariaDB root login works with password $(mask "$pw")"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
[ -n "$MY_OK" ] || echo " FAIL: No candidate password could log in to MariaDB as root"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "=== RESULT (verifiziert oder nicht auffindbar) ==="
|
||||||
|
if [ -n "$PG_OK" ]; then
|
||||||
|
echo "POSTGRES_USER=$PG_USER"
|
||||||
|
echo "POSTGRES_PASSWORD=<VERIFIED $(mask "$PG_OK")>"
|
||||||
|
else
|
||||||
|
echo "POSTGRES: VERIFIED PASSWORD NOT FOUND IN /opt/hx-ki SOURCES"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$MY_OK" ]; then
|
||||||
|
echo "MYSQL_ROOT_PASSWORD=<VERIFIED $(mask "$MY_OK")>"
|
||||||
|
else
|
||||||
|
echo "MARIADB: VERIFIED ROOT PASSWORD NOT FOUND IN /opt/hx-ki SOURCES"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "If one of them is NOT found: the only deterministic path is a controlled password reset (auth bypass), because plaintext cannot be recovered from the data directories."
|
||||||
137
COM2_DOCTOR_ONE_SHOT.sh
Executable file
137
COM2_DOCTOR_ONE_SHOT.sh
Executable file
@@ -0,0 +1,137 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DIR="/opt/hx-ki/com2-stack"
|
||||||
|
F="$DIR/docker-compose.yml"
|
||||||
|
NET="hxki-internal"
|
||||||
|
TS="$(date +%Y%m%d-%H%M%S)"
|
||||||
|
BK="$DIR/backup-$TS"
|
||||||
|
|
||||||
|
echo "=== COM2 DOCTOR (one-shot, deterministisch) ==="
|
||||||
|
echo "Autorität: $F"
|
||||||
|
echo "Backup: $BK"
|
||||||
|
mkdir -p "$BK"
|
||||||
|
|
||||||
|
# 0) Preconditions
|
||||||
|
[ -f "$F" ] || { echo "FEHLT: $F"; exit 1; }
|
||||||
|
cp -a "$F" "$BK/docker-compose.yml.orig"
|
||||||
|
|
||||||
|
# 1) Host-Caddy darf NICHT Port 80/443 blocken, wenn Docker-Caddy laufen soll
|
||||||
|
if systemctl is-active --quiet caddy 2>/dev/null; then
|
||||||
|
echo "[1] Stoppe host-caddy (systemd), damit Docker-Caddy 80/443 bekommt"
|
||||||
|
systemctl stop caddy
|
||||||
|
else
|
||||||
|
echo "[1] OK: host-caddy ist nicht aktiv"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 2) Docker Netzwerk sicherstellen (external)
|
||||||
|
docker network inspect "$NET" >/dev/null 2>&1 || { echo "[2] Erzeuge Docker-Netzwerk: $NET"; docker network create "$NET" >/dev/null; }
|
||||||
|
echo "[2] OK: Netzwerk existiert: $NET"
|
||||||
|
|
||||||
|
# 3) Compose YAML MUSS valide sein – sonst: Restore und STOP mit Zeilenanzeige
|
||||||
|
echo "[3] Validate Compose YAML"
|
||||||
|
if ! docker compose -f "$F" config >/dev/null 2>&1; then
|
||||||
|
echo "FAIL: Compose ist NICHT valide."
|
||||||
|
echo "---- Parser-Fehler ----"
|
||||||
|
docker compose -f "$F" config 2>&1 | tail -n 30 || true
|
||||||
|
echo "---- Zeilen um die vermutete Fehlerstelle (45-80) ----"
|
||||||
|
nl -ba "$F" | sed -n '45,80p' || true
|
||||||
|
echo
|
||||||
|
echo "Auto-Restore auf Backup und STOP."
|
||||||
|
cp -a "$BK/docker-compose.yml.orig" "$F"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "[3] OK: Compose ist valide"
|
||||||
|
|
||||||
|
# 4) Pflicht-Services auf COM2 (laut deiner Vorgabe: autark)
|
||||||
|
echo "[4] Prüfe Pflicht-Services im Compose (ohne Umbau)"
|
||||||
|
python3 - <<'PY'
|
||||||
|
import re, pathlib, sys
|
||||||
|
p = pathlib.Path("/opt/hx-ki/com2-stack/docker-compose.yml")
|
||||||
|
s = p.read_text()
|
||||||
|
m = re.search(r'(?ms)^services:\s*\n(.*?)(?=^\S|\Z)', s)
|
||||||
|
if not m:
|
||||||
|
print("FAIL: Kein Top-Level 'services:' Block.")
|
||||||
|
sys.exit(1)
|
||||||
|
block = m.group(1)
|
||||||
|
names = re.findall(r'(?m)^\s{2}([A-Za-z0-9_.-]+):\s*$', block)
|
||||||
|
need = ["hx-caddy","hxki-n8n","hxki-postgres","hxki-mariadb","hxki-mautic"]
|
||||||
|
missing = [x for x in need if x not in names]
|
||||||
|
print("Services gefunden:", ", ".join(names))
|
||||||
|
if missing:
|
||||||
|
print("FAIL: Pflicht-Services fehlen:", ", ".join(missing))
|
||||||
|
sys.exit(2)
|
||||||
|
print("OK: Pflicht-Services vorhanden.")
|
||||||
|
PY
|
||||||
|
|
||||||
|
# 5) hxki-internal als external:true MUSS im Compose vorhanden sein (sonst knallt network-ref)
|
||||||
|
echo "[5] Prüfe: networks/hxki-internal external:true"
|
||||||
|
python3 - <<'PY'
|
||||||
|
from pathlib import Path
|
||||||
|
import re, sys
|
||||||
|
p = Path("/opt/hx-ki/com2-stack/docker-compose.yml")
|
||||||
|
s = p.read_text()
|
||||||
|
# sehr konservativ: nur prüfen, nicht "raten"
|
||||||
|
if not re.search(r'(?ms)^networks:\s*\n(?:.*\n)*?\s{2}hxki-internal:\s*\n(?:.*\n)*?\s{4}external:\s*true\s*$', s):
|
||||||
|
print("FAIL: networks: hxki-internal: external:true fehlt oder ist anders.")
|
||||||
|
print("Zeilen-Hinweis:")
|
||||||
|
import subprocess, shlex
|
||||||
|
subprocess.run(["bash","-lc",f"nl -ba {p} | grep -nE '^(\\s*networks:|\\s{{2}}hxki-internal:|\\s{{4}}external:)' -n || true"])
|
||||||
|
sys.exit(3)
|
||||||
|
print("OK: networks/hxki-internal external:true gefunden.")
|
||||||
|
PY
|
||||||
|
|
||||||
|
# 6) n8n config MUSS gültiges JSON sein (dein log beweist, dass es kaputt war)
|
||||||
|
# Wir reparieren NUR das deterministisch: config als JSON resetten, ohne Workflows/DB anzufassen.
|
||||||
|
echo "[6] Fix: n8n config JSON (nur wenn kaputt)"
|
||||||
|
MOUNT_SRC="/data/HXKI_WORKSPACE/router"
|
||||||
|
CFG="$MOUNT_SRC/config"
|
||||||
|
if [ -d "$MOUNT_SRC" ]; then
|
||||||
|
docker stop hxki-n8n >/dev/null 2>&1 || true
|
||||||
|
|
||||||
|
if [ -f "$CFG" ]; then
|
||||||
|
if python3 - <<PY >/dev/null 2>&1
|
||||||
|
import json
|
||||||
|
json.load(open("$CFG","r"))
|
||||||
|
PY
|
||||||
|
then
|
||||||
|
echo "OK: $CFG ist gültiges JSON (nichts zu tun)"
|
||||||
|
else
|
||||||
|
echo "WARN: $CFG ist KEIN gültiges JSON -> schreibe minimal gültig + Backup"
|
||||||
|
cp -a "$CFG" "$CFG.bak.$TS"
|
||||||
|
cat > "$CFG" <<JSON
|
||||||
|
{"encryptionKey":"","instanceId":""}
|
||||||
|
JSON
|
||||||
|
chown 1000:1000 "$CFG" || true
|
||||||
|
chmod 600 "$CFG" || true
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "INFO: $CFG existiert nicht -> wird von n8n beim Start erzeugt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Rechte auf Mount (konservativ)
|
||||||
|
chown -R 1000:1000 "$MOUNT_SRC" || true
|
||||||
|
chmod -R u+rwX "$MOUNT_SRC" || true
|
||||||
|
chmod -R g+rwX "$MOUNT_SRC" || true
|
||||||
|
|
||||||
|
docker start hxki-n8n >/dev/null 2>&1 || true
|
||||||
|
else
|
||||||
|
echo "WARN: $MOUNT_SRC fehlt -> n8n Mount passt nicht (keine Reparatur)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 7) Orchester hoch (alles oder nichts)
|
||||||
|
echo "[7] Orchester UP (alles zusammen)"
|
||||||
|
cd "$DIR"
|
||||||
|
docker compose up -d --remove-orphans
|
||||||
|
|
||||||
|
echo "[8] Status (Container)"
|
||||||
|
docker ps --format 'NAME={{.Names}} STATUS={{.Status}} PORTS={{.Ports}}' | egrep 'hxki-|hx-' || true
|
||||||
|
|
||||||
|
echo "[9] Netzwerk-Mitglieder: $NET"
|
||||||
|
docker network inspect "$NET" --format '{{range $id,$c := .Containers}}{{println $c.Name}}{{end}}' | sort || true
|
||||||
|
|
||||||
|
# 10) Caddy -> n8n intern test (nur intern, ohne "lokal 127.0.0.1")
|
||||||
|
echo "[10] Caddy->n8n Service-Test (intern)"
|
||||||
|
docker exec -it hx-caddy sh -lc 'wget -qO- http://hxki-n8n:5678/ >/dev/null && echo OK_CADDY_TO_N8N || echo FAIL_CADDY_TO_N8N' || true
|
||||||
|
|
||||||
|
echo "=== ENDE ==="
|
||||||
59
COM2_DOCTOR_PORTS_ONE_SHOT.sh
Executable file
59
COM2_DOCTOR_PORTS_ONE_SHOT.sh
Executable file
@@ -0,0 +1,59 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
NET="hxki-internal"
|
||||||
|
SVC_LIST=("hxki-web:80" "hxki-n8n:5678" "hxki-mautic:80")
|
||||||
|
|
||||||
|
echo "=== COM2 DOCTOR · PORTS / LISTEN / LOGS ==="
|
||||||
|
|
||||||
|
echo "[0] Netzwerk"
|
||||||
|
docker network inspect "$NET" >/dev/null 2>&1 && echo "OK: $NET existiert" || { echo "FAIL: $NET fehlt"; exit 1; }
|
||||||
|
docker network inspect "$NET" --format '{{range $id,$c := .Containers}}{{println $c.Name}}{{end}}' | sort
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[1] Container-Status"
|
||||||
|
docker ps --format 'NAME={{.Names}} STATUS={{.Status}} PORTS={{.Ports}}' | egrep 'hxki-|hx-caddy' || true
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[2] Listen-Checks IN jedem Service-Container (ss/netstat)"
|
||||||
|
for entry in "${SVC_LIST[@]}"; do
|
||||||
|
c="${entry%%:*}"
|
||||||
|
p="${entry##*:}"
|
||||||
|
echo
|
||||||
|
echo "--- $c (soll lauschen auf :$p) ---"
|
||||||
|
docker exec -it "$c" sh -lc "
|
||||||
|
echo 'id:'; id || true
|
||||||
|
echo 'ps:'; ps aux | head -n 20 || true
|
||||||
|
echo 'ss:'; (ss -lntp 2>/dev/null || netstat -lntp 2>/dev/null || true) | egrep '(:$p\\b|LISTEN)' || true
|
||||||
|
echo 'localhost test:'; (wget -qO- http://127.0.0.1:$p/ >/dev/null && echo OK_LOCALHOST || echo FAIL_LOCALHOST) || true
|
||||||
|
" || echo "WARN: docker exec in $c fehlgeschlagen"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[3] Caddy -> Upstreams (mit Retry 30s)"
|
||||||
|
for entry in "${SVC_LIST[@]}"; do
|
||||||
|
host="${entry%%:*}"
|
||||||
|
port="${entry##*:}"
|
||||||
|
echo
|
||||||
|
echo "--- hx-caddy -> $host:$port ---"
|
||||||
|
docker exec -it hx-caddy sh -lc "
|
||||||
|
i=0
|
||||||
|
while [ \$i -lt 30 ]; do
|
||||||
|
wget -qO- http://$host:$port/ >/dev/null 2>&1 && { echo OK; exit 0; }
|
||||||
|
i=\$((i+1)); sleep 1
|
||||||
|
done
|
||||||
|
echo FAIL
|
||||||
|
exit 0
|
||||||
|
" || true
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[4] Logs (letzte 120 Zeilen)"
|
||||||
|
for c in hxki-web hxki-n8n hxki-mautic hx-caddy; do
|
||||||
|
echo
|
||||||
|
echo "--- logs: $c ---"
|
||||||
|
docker logs --tail=120 "$c" 2>&1 || true
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "=== ENDE ==="
|
||||||
258
COM2_FERRARI_REPAIR_ONE_SHOT.sh
Executable file
258
COM2_FERRARI_REPAIR_ONE_SHOT.sh
Executable file
@@ -0,0 +1,258 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DIR="/opt/hx-ki/com2-stack"
|
||||||
|
F="$DIR/docker-compose.yml"
|
||||||
|
ENVF="$DIR/.env"
|
||||||
|
NET="hxki-internal"
|
||||||
|
TS="$(date +%Y%m%d-%H%M%S)"
|
||||||
|
BK="/opt/hx-ki/backups/com2-ferrari-$TS"
|
||||||
|
|
||||||
|
mkdir -p "$BK"
|
||||||
|
echo "=== COM2 · FERRARI REPAIR ONE-SHOT (no guessing) ==="
|
||||||
|
echo "Compose: $F"
|
||||||
|
echo "Env: $ENVF"
|
||||||
|
echo "Backup: $BK"
|
||||||
|
echo
|
||||||
|
|
||||||
|
[ -f "$F" ] || { echo "FAIL: FEHLT $F"; exit 1; }
|
||||||
|
cp -a "$F" "$BK/docker-compose.yml.pre" || true
|
||||||
|
[ -f "$ENVF" ] && cp -a "$ENVF" "$BK/.env.pre" || true
|
||||||
|
|
||||||
|
# --- helpers ---------------------------------------------------------------
|
||||||
|
die(){ echo "FAIL: $*" ; exit 1; }
|
||||||
|
|
||||||
|
# find candidates from many places, newest first
|
||||||
|
collect_kv_candidates() {
|
||||||
|
local key="$1"
|
||||||
|
# search in .env files + compose backups + docker-compose.yml* (only small grep)
|
||||||
|
find /opt/hx-ki -maxdepth 6 -type f \
|
||||||
|
\( -iname ".env" -o -iname "*.env" -o -iname "docker-compose*.yml" -o -iname "docker-compose*.yml.*" -o -iname "*.yml.bak*" \) \
|
||||||
|
-printf "%T@ %p\n" 2>/dev/null | sort -nr | awk '{ $1=""; sub(/^ /,""); print }' |
|
||||||
|
while read -r p; do
|
||||||
|
[ -f "$p" ] || continue
|
||||||
|
# exact KEY=VALUE lines only
|
||||||
|
awk -v k="$key" -F= '
|
||||||
|
$1==k {
|
||||||
|
v=$0; sub(/^[^=]+= /,"",v); sub(/^[^=]+=/,"",v);
|
||||||
|
gsub(/\r/,"",v);
|
||||||
|
if (v!="" && v !~ /CHANGE_ME|CHANGEME|changeme/) { print v }
|
||||||
|
}' "$p" 2>/dev/null | head -n 5
|
||||||
|
done | awk 'NF' | awk '!seen[$0]++' | head -n 30
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_net() {
|
||||||
|
docker network inspect "$NET" >/dev/null 2>&1 || docker network create "$NET" >/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_host_caddy() {
|
||||||
|
if systemctl is-active --quiet caddy 2>/dev/null; then
|
||||||
|
echo "[0] Stoppe host-caddy (systemd) – Ports 80/443 frei"
|
||||||
|
systemctl stop caddy
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
compose_down() {
|
||||||
|
cd "$DIR"
|
||||||
|
docker compose down --remove-orphans || true
|
||||||
|
}
|
||||||
|
|
||||||
|
compose_up() {
|
||||||
|
cd "$DIR"
|
||||||
|
docker compose up -d --remove-orphans
|
||||||
|
}
|
||||||
|
|
||||||
|
# Test Postgres password by real connection
|
||||||
|
pg_try_pw() {
|
||||||
|
local user="$1" pw="$2"
|
||||||
|
docker exec -e PGPASSWORD="$pw" hxki-postgres sh -lc "psql -U '$user' -d postgres -tAc 'select 1' >/dev/null 2>&1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ensure DB exists (create if missing) using admin user
|
||||||
|
pg_ensure_db() {
|
||||||
|
local admin_user="$1" admin_pw="$2" db="$3"
|
||||||
|
docker exec -e PGPASSWORD="$admin_pw" hxki-postgres sh -lc \
|
||||||
|
"psql -U '$admin_user' -d postgres -tAc \"select 1 from pg_database where datname='${db}'\" | grep -q 1 || psql -U '$admin_user' -d postgres -c \"create database \\\"${db}\\\"\" >/dev/null"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ensure role exists + password (only if missing)
|
||||||
|
pg_ensure_role() {
|
||||||
|
local admin_user="$1" admin_pw="$2" role="$3" role_pw="$4"
|
||||||
|
docker exec -e PGPASSWORD="$admin_pw" hxki-postgres sh -lc \
|
||||||
|
"psql -U '$admin_user' -d postgres -tAc \"select 1 from pg_roles where rolname='${role}'\" | grep -q 1 || psql -U '$admin_user' -d postgres -c \"create role \\\"${role}\\\" login password '${role_pw}'\" >/dev/null"
|
||||||
|
}
|
||||||
|
|
||||||
|
# grant owner if needed
|
||||||
|
pg_set_owner() {
|
||||||
|
local admin_user="$1" admin_pw="$2" db="$3" owner="$4"
|
||||||
|
docker exec -e PGPASSWORD="$admin_pw" hxki-postgres sh -lc \
|
||||||
|
"psql -U '$admin_user' -d postgres -c \"alter database \\\"${db}\\\" owner to \\\"${owner}\\\"\" >/dev/null 2>&1 || true"
|
||||||
|
}
|
||||||
|
|
||||||
|
# MariaDB root auth test (real)
|
||||||
|
my_root_try_pw() {
|
||||||
|
local pw="$1"
|
||||||
|
docker exec hxki-mariadb sh -lc "mysqladmin ping -uroot -p'$pw' --silent >/dev/null 2>&1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# MariaDB user auth test
|
||||||
|
my_user_try_pw() {
|
||||||
|
local user="$1" pw="$2" db="$3"
|
||||||
|
docker exec hxki-mariadb sh -lc "mysql -u'$user' -p'$pw' -D'$db' -e 'select 1' >/dev/null 2>&1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ensure mautic db/user exists (create only if missing; uses root)
|
||||||
|
my_ensure_mautic() {
|
||||||
|
local rootpw="$1" db="$2" user="$3" userpw="$4"
|
||||||
|
docker exec hxki-mariadb sh -lc "
|
||||||
|
mysql -uroot -p'$rootpw' -e \"CREATE DATABASE IF NOT EXISTS \\\`$db\\\`;\" >/dev/null &&
|
||||||
|
mysql -uroot -p'$rootpw' -e \"CREATE USER IF NOT EXISTS '$user'@'%' IDENTIFIED BY '$userpw';\" >/dev/null &&
|
||||||
|
mysql -uroot -p'$rootpw' -e \"GRANT ALL PRIVILEGES ON \\\`$db\\\`.* TO '$user'@'%'; FLUSH PRIVILEGES;\" >/dev/null
|
||||||
|
"
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- start ---------------------------------------------------------------
|
||||||
|
[ -d "$DIR" ] || die "FEHLT: $DIR"
|
||||||
|
stop_host_caddy
|
||||||
|
ensure_net
|
||||||
|
|
||||||
|
echo "[1] Orchester runter (sauber)"
|
||||||
|
compose_down
|
||||||
|
|
||||||
|
echo "[2] Starte NUR DBs (damit wir Credentials echt testen können)"
|
||||||
|
cd "$DIR"
|
||||||
|
docker compose up -d hxki-postgres hxki-mariadb || die "DB-Start fehlgeschlagen"
|
||||||
|
|
||||||
|
# --- discover postgres admin user (from container env) ----------------------
|
||||||
|
PG_ADMIN_USER="$(docker inspect hxki-postgres --format '{{range .Config.Env}}{{println .}}{{end}}' | awk -F= '$1=="POSTGRES_USER"{print $2}' | tail -n 1)"
|
||||||
|
[ -n "$PG_ADMIN_USER" ] || die "POSTGRES_USER nicht gefunden in hxki-postgres Env"
|
||||||
|
|
||||||
|
# Candidate passwords from old state
|
||||||
|
echo "[3] Suche Postgres-Passwort (no guessing: scan + real login test)"
|
||||||
|
mapfile -t PG_PWS < <(collect_kv_candidates "POSTGRES_PASSWORD")
|
||||||
|
# also accept PG_PASSWORD style keys
|
||||||
|
mapfile -t PG_PWS2 < <(collect_kv_candidates "PG_PASSWORD")
|
||||||
|
PG_PWS+=( "${PG_PWS2[@]}" )
|
||||||
|
# de-dupe
|
||||||
|
PG_PWS=( $(printf "%s\n" "${PG_PWS[@]}" | awk 'NF' | awk '!seen[$0]++') )
|
||||||
|
|
||||||
|
PG_ADMIN_PW=""
|
||||||
|
for pw in "${PG_PWS[@]}"; do
|
||||||
|
if pg_try_pw "$PG_ADMIN_USER" "$pw"; then
|
||||||
|
PG_ADMIN_PW="$pw"; break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
[ -n "$PG_ADMIN_PW" ] || die "Kein funktionierendes Postgres-Passwort gefunden (scan+test)."
|
||||||
|
|
||||||
|
echo " OK: Postgres auth funktioniert für user=$PG_ADMIN_USER"
|
||||||
|
|
||||||
|
# --- discover mariadb root pw ---------------------------------------------
|
||||||
|
echo "[4] Suche MariaDB root Passwort (scan + real ping test)"
|
||||||
|
mapfile -t MYROOT_PWS < <(collect_kv_candidates "MARIADB_ROOT_PASSWORD")
|
||||||
|
mapfile -t MYROOT_PWS2 < <(collect_kv_candidates "MYSQL_ROOT_PASSWORD")
|
||||||
|
MYROOT_PWS+=( "${MYROOT_PWS2[@]}" )
|
||||||
|
MYROOT_PWS=( $(printf "%s\n" "${MYROOT_PWS[@]}" | awk 'NF' | awk '!seen[$0]++') )
|
||||||
|
|
||||||
|
MY_ROOT_PW=""
|
||||||
|
for pw in "${MYROOT_PWS[@]}"; do
|
||||||
|
if my_root_try_pw "$pw"; then
|
||||||
|
MY_ROOT_PW="$pw"; break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
[ -n "$MY_ROOT_PW" ] || die "Kein funktionierendes MariaDB root Passwort gefunden (scan+test)."
|
||||||
|
|
||||||
|
echo " OK: MariaDB root auth funktioniert"
|
||||||
|
|
||||||
|
# --- read target vars from compose/env (but align with OLD secrets) ---------
|
||||||
|
# Extract current target DB names from compose env placeholders (.env)
|
||||||
|
# If not present, fall back to container env default
|
||||||
|
PG_DB="${PG_DB:-}"
|
||||||
|
PG_USER="${PG_USER:-}"
|
||||||
|
if [ -f "$ENVF" ]; then
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
set -a; source "$ENVF" 2>/dev/null || true; set +a
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Ensure defaults if env missing
|
||||||
|
: "${PG_USER:=$PG_ADMIN_USER}"
|
||||||
|
: "${PG_DB:=n8n}"
|
||||||
|
|
||||||
|
# Mautic target vars
|
||||||
|
: "${MAUTIC_DB_NAME:=mautic}"
|
||||||
|
: "${MAUTIC_DB_USER:=mautic}"
|
||||||
|
# try recover MAUTIC_DB_PASSWORD from old state too
|
||||||
|
mapfile -t MAUTIC_PWS < <(collect_kv_candidates "MAUTIC_DB_PASSWORD")
|
||||||
|
MAUTIC_DB_PASSWORD="${MAUTIC_DB_PASSWORD:-${MAUTIC_PWS[0]:-}}"
|
||||||
|
|
||||||
|
# If not found, we do NOT invent: we only proceed if we can validate, else stop.
|
||||||
|
if [ -z "${MAUTIC_DB_PASSWORD:-}" ]; then
|
||||||
|
die "MAUTIC_DB_PASSWORD nicht gefunden im alten Zustand. (Bitte in alten .env/Backups vorhanden machen.)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[5] Schreibe kanonische .env (nur funktionierende Secrets, kein CHANGE_ME)"
|
||||||
|
cp -a "$ENVF" "$BK/.env.prewrite" 2>/dev/null || true
|
||||||
|
|
||||||
|
cat > "$ENVF" <<ENV
|
||||||
|
# === CANONICAL (recovered + validated) ===
|
||||||
|
# Postgres (n8n)
|
||||||
|
PG_USER=${PG_USER}
|
||||||
|
PG_PASSWORD=${PG_ADMIN_PW}
|
||||||
|
PG_DB=${PG_DB}
|
||||||
|
|
||||||
|
# Mautic (MariaDB)
|
||||||
|
MAUTIC_DB_NAME=${MAUTIC_DB_NAME}
|
||||||
|
MAUTIC_DB_USER=${MAUTIC_DB_USER}
|
||||||
|
MAUTIC_DB_PASSWORD=${MAUTIC_DB_PASSWORD}
|
||||||
|
MAUTIC_DB_ROOT_PASSWORD=${MY_ROOT_PW}
|
||||||
|
|
||||||
|
# n8n public vars (leave if you already had them in compose via defaults)
|
||||||
|
N8N_HOST=${N8N_HOST:-localhost}
|
||||||
|
N8N_PROTOCOL=${N8N_PROTOCOL:-http}
|
||||||
|
ENV
|
||||||
|
|
||||||
|
echo "[6] Postgres: stelle sicher, dass DB für n8n existiert (create only if missing)"
|
||||||
|
pg_ensure_db "$PG_ADMIN_USER" "$PG_ADMIN_PW" "$PG_DB"
|
||||||
|
pg_ensure_role "$PG_ADMIN_USER" "$PG_ADMIN_PW" "$PG_USER" "$PG_ADMIN_PW" || true
|
||||||
|
pg_set_owner "$PG_ADMIN_USER" "$PG_ADMIN_PW" "$PG_DB" "$PG_USER" || true
|
||||||
|
echo " OK: Postgres DB/Role geprüft"
|
||||||
|
|
||||||
|
echo "[7] MariaDB: stelle sicher, dass mautic DB/User passt (create/grant only if needed)"
|
||||||
|
# if mautic user auth already works, we don't touch grants
|
||||||
|
if my_user_try_pw "$MAUTIC_DB_USER" "$MAUTIC_DB_PASSWORD" "$MAUTIC_DB_NAME"; then
|
||||||
|
echo " OK: mautic user auth OK – keine Änderungen an MariaDB nötig"
|
||||||
|
else
|
||||||
|
echo " INFO: mautic user auth FAIL – setze DB/User/Grants deterministisch via root"
|
||||||
|
my_ensure_mautic "$MY_ROOT_PW" "$MAUTIC_DB_NAME" "$MAUTIC_DB_USER" "$MAUTIC_DB_PASSWORD" || die "MariaDB repair failed"
|
||||||
|
echo " OK: MariaDB DB/User/Grants gesetzt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[8] Validate Compose"
|
||||||
|
cd "$DIR"
|
||||||
|
docker compose config >/dev/null || die "Compose ist nicht valide."
|
||||||
|
|
||||||
|
echo "[9] Orchester hoch"
|
||||||
|
docker compose up -d --remove-orphans
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "=== HARD CHECKS (facts) ==="
|
||||||
|
echo "[A] Container Status"
|
||||||
|
docker ps --format 'NAME={{.Names}} STATUS={{.Status}} PORTS={{.Ports}}' | egrep 'hxki-|hx-' || true
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[B] Logs (tail 30)"
|
||||||
|
echo "--- hxki-n8n ---"
|
||||||
|
docker logs --tail=30 hxki-n8n || true
|
||||||
|
echo "--- hxki-mautic ---"
|
||||||
|
docker logs --tail=30 hxki-mautic || true
|
||||||
|
echo "--- hxki-web ---"
|
||||||
|
docker logs --tail=30 hxki-web || true
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[C] Caddy -> Upstreams (internal reachability)"
|
||||||
|
docker exec -it hx-caddy sh -lc 'wget -qO- http://hxki-n8n:5678/ >/dev/null && echo OK_CADDY_TO_N8N || echo FAIL_CADDY_TO_N8N' || true
|
||||||
|
docker exec -it hx-caddy sh -lc 'wget -qO- http://hxki-mautic/ >/dev/null && echo OK_CADDY_TO_MAUTIC || echo FAIL_CADDY_TO_MAUTIC' || true
|
||||||
|
docker exec -it hx-caddy sh -lc 'wget -qO- http://hxki-web/ >/dev/null && echo OK_CADDY_TO_WEB || echo FAIL_CADDY_TO_WEB' || true
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "=== DONE ==="
|
||||||
|
echo "Backup: $BK"
|
||||||
38
COM2_FIX_MAUTIC_ONLY_ONE_SHOT.sh
Executable file
38
COM2_FIX_MAUTIC_ONLY_ONE_SHOT.sh
Executable file
@@ -0,0 +1,38 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
MA="hxki-mautic"
|
||||||
|
CA="hx-caddy"
|
||||||
|
|
||||||
|
echo "=== COM2 · FIX MAUTIC ONLY (no rebuild, no guessing) ==="
|
||||||
|
|
||||||
|
echo "[1] Stoppe NUR Mautic"
|
||||||
|
docker stop "$MA" >/dev/null || true
|
||||||
|
|
||||||
|
echo "[2] Starte NUR Mautic neu"
|
||||||
|
docker start "$MA" >/dev/null
|
||||||
|
|
||||||
|
echo "[3] Warte bis Mautic auf :80 lauscht (max 60s)"
|
||||||
|
for i in {1..60}; do
|
||||||
|
if docker exec "$MA" sh -lc "ss -lnt | grep -q ':80 '"; then
|
||||||
|
echo "OK: Mautic lauscht auf Port 80"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
if [ "$i" -eq 60 ]; then
|
||||||
|
echo "FAIL: Mautic lauscht NICHT auf Port 80"
|
||||||
|
docker logs --tail=120 "$MA"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "[4] Test: Caddy -> Mautic"
|
||||||
|
if docker exec "$CA" sh -lc "wget -qO- http://hxki-mautic/ >/dev/null"; then
|
||||||
|
echo "OK_CADDY_TO_MAUTIC"
|
||||||
|
else
|
||||||
|
echo "FAIL_CADDY_TO_MAUTIC"
|
||||||
|
docker logs --tail=120 "$MA"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "=== DONE: COM2 IST SAUBER ==="
|
||||||
199
COM2_FIX_ONE_SHOT.sh
Executable file
199
COM2_FIX_ONE_SHOT.sh
Executable file
@@ -0,0 +1,199 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DIR="/opt/hx-ki/com2-stack"
|
||||||
|
F="$DIR/docker-compose.yml"
|
||||||
|
ENVF="$DIR/.env"
|
||||||
|
NET="hxki-internal"
|
||||||
|
TS="$(date +%Y%m%d-%H%M%S)"
|
||||||
|
BK="$DIR/backup-fix-$TS"
|
||||||
|
mkdir -p "$BK"
|
||||||
|
|
||||||
|
echo "=== COM2 FIX ONE-SHOT ==="
|
||||||
|
echo "Autorität: $F"
|
||||||
|
[ -f "$F" ] || { echo "FEHLT: $F"; exit 1; }
|
||||||
|
|
||||||
|
cp -a "$F" "$BK/docker-compose.yml.pre"
|
||||||
|
|
||||||
|
# Netzwerk muss als external existieren (Host)
|
||||||
|
docker network inspect "$NET" >/dev/null 2>&1 || docker network create "$NET" >/dev/null
|
||||||
|
|
||||||
|
# .env laden (falls vorhanden)
|
||||||
|
if [ -f "$ENVF" ]; then
|
||||||
|
set -a
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
. "$ENVF"
|
||||||
|
set +a
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Helper: ENV aus Container ziehen
|
||||||
|
get_env_from_container() {
|
||||||
|
local c="$1" key="$2"
|
||||||
|
docker inspect "$c" --format '{{range .Config.Env}}{{println .}}{{end}}' \
|
||||||
|
| awk -F= -v k="$key" '$1==k{print substr($0, index($0,"=")+1)}' \
|
||||||
|
| head -n1
|
||||||
|
}
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[1] Container vorhanden?"
|
||||||
|
for c in hxki-postgres hxki-mariadb hxki-n8n hxki-mautic; do
|
||||||
|
docker inspect "$c" >/dev/null 2>&1 || { echo "FEHLT Container: $c"; exit 1; }
|
||||||
|
done
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[2] Postgres: setze/angleiche User/DB/PW (damit n8n startet)"
|
||||||
|
|
||||||
|
# Werte entweder aus .env oder aus n8n-Container ENV
|
||||||
|
PG_USER="${PG_USER:-$(get_env_from_container hxki-n8n DB_POSTGRESDB_USER)}"
|
||||||
|
PG_PASSWORD="${PG_PASSWORD:-$(get_env_from_container hxki-n8n DB_POSTGRESDB_PASSWORD)}"
|
||||||
|
PG_DB="${PG_DB:-$(get_env_from_container hxki-n8n DB_POSTGRESDB_DATABASE)}"
|
||||||
|
|
||||||
|
[ -n "${PG_USER:-}" ] || { echo "FEHLT: PG_USER (in $ENVF oder n8n ENV)"; exit 1; }
|
||||||
|
[ -n "${PG_PASSWORD:-}" ] || { echo "FEHLT: PG_PASSWORD (in $ENVF oder n8n ENV)"; exit 1; }
|
||||||
|
[ -n "${PG_DB:-}" ] || { echo "FEHLT: PG_DB (in $ENVF oder n8n ENV)"; exit 1; }
|
||||||
|
|
||||||
|
docker exec -u postgres -i hxki-postgres psql -v ON_ERROR_STOP=1 -d postgres <<SQL
|
||||||
|
DO \$\$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname='${PG_USER}') THEN
|
||||||
|
CREATE ROLE ${PG_USER} LOGIN PASSWORD '${PG_PASSWORD}';
|
||||||
|
ELSE
|
||||||
|
ALTER ROLE ${PG_USER} WITH LOGIN PASSWORD '${PG_PASSWORD}';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM pg_database WHERE datname='${PG_DB}') THEN
|
||||||
|
CREATE DATABASE ${PG_DB} OWNER ${PG_USER};
|
||||||
|
END IF;
|
||||||
|
END
|
||||||
|
\$\$;
|
||||||
|
GRANT ALL PRIVILEGES ON DATABASE ${PG_DB} TO ${PG_USER};
|
||||||
|
SQL
|
||||||
|
|
||||||
|
echo "OK: Postgres User/DB/PW angeglichen."
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[3] MariaDB: setze/angleiche Mautic DB/User/PW (damit mautic startet)"
|
||||||
|
|
||||||
|
# Root-PW aus MariaDB Container ENV
|
||||||
|
MDB_ROOT_PW="$(get_env_from_container hxki-mariadb MYSQL_ROOT_PASSWORD || true)"
|
||||||
|
[ -n "${MDB_ROOT_PW:-}" ] || MDB_ROOT_PW="$(get_env_from_container hxki-mariadb MARIADB_ROOT_PASSWORD || true)"
|
||||||
|
[ -n "${MDB_ROOT_PW:-}" ] || { echo "FEHLT: MariaDB Root-Passwort (MYSQL_ROOT_PASSWORD/MARIADB_ROOT_PASSWORD im Container)"; exit 1; }
|
||||||
|
|
||||||
|
# Mautic Zielwerte: aus Mautic Container ENV (Quelle der Wahrheit)
|
||||||
|
MAUTIC_DB_HOST="$(get_env_from_container hxki-mautic MAUTIC_DB_HOST || true)"
|
||||||
|
MAUTIC_DB_USER="$(get_env_from_container hxki-mautic MAUTIC_DB_USER || true)"
|
||||||
|
MAUTIC_DB_PASSWORD="$(get_env_from_container hxki-mautic MAUTIC_DB_PASSWORD || true)"
|
||||||
|
MAUTIC_DB_NAME="$(get_env_from_container hxki-mautic MAUTIC_DB_NAME || true)"
|
||||||
|
|
||||||
|
# Fallbacks (falls Image andere Keys nutzt)
|
||||||
|
[ -n "${MAUTIC_DB_USER:-}" ] || MAUTIC_DB_USER="$(get_env_from_container hxki-mautic MYSQL_USER || true)"
|
||||||
|
[ -n "${MAUTIC_DB_PASSWORD:-}" ] || MAUTIC_DB_PASSWORD="$(get_env_from_container hxki-mautic MYSQL_PASSWORD || true)"
|
||||||
|
[ -n "${MAUTIC_DB_NAME:-}" ] || MAUTIC_DB_NAME="$(get_env_from_container hxki-mautic MYSQL_DATABASE || true)"
|
||||||
|
|
||||||
|
[ -n "${MAUTIC_DB_USER:-}" ] || { echo "FEHLT: MAUTIC_DB_USER (im hxki-mautic ENV)"; exit 1; }
|
||||||
|
[ -n "${MAUTIC_DB_PASSWORD:-}" ] || { echo "FEHLT: MAUTIC_DB_PASSWORD (im hxki-mautic ENV)"; exit 1; }
|
||||||
|
[ -n "${MAUTIC_DB_NAME:-}" ] || { echo "FEHLT: MAUTIC_DB_NAME (im hxki-mautic ENV)"; exit 1; }
|
||||||
|
|
||||||
|
docker exec -i hxki-mariadb mysql -uroot -p"${MDB_ROOT_PW}" <<SQL
|
||||||
|
CREATE DATABASE IF NOT EXISTS \`${MAUTIC_DB_NAME}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
|
CREATE USER IF NOT EXISTS '${MAUTIC_DB_USER}'@'%' IDENTIFIED BY '${MAUTIC_DB_PASSWORD}';
|
||||||
|
ALTER USER '${MAUTIC_DB_USER}'@'%' IDENTIFIED BY '${MAUTIC_DB_PASSWORD}';
|
||||||
|
GRANT ALL PRIVILEGES ON \`${MAUTIC_DB_NAME}\`.* TO '${MAUTIC_DB_USER}'@'%';
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
SQL
|
||||||
|
|
||||||
|
echo "OK: MariaDB User/DB/PW angeglichen."
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[4] hxki-web: repariere Service-Definition aus vorhandenem Backup (damit /app/package.json wieder stimmt)"
|
||||||
|
|
||||||
|
# Quelle suchen (du hast welche gefunden)
|
||||||
|
SRC=""
|
||||||
|
for cand in \
|
||||||
|
/opt/hx-ki/com-stack/docker-compose.yml \
|
||||||
|
/opt/hx-ki/com-stack/docker-compose.yml.bak.* \
|
||||||
|
/opt/hx-ki/docker/docker-compose.yml.bak_* \
|
||||||
|
/opt/hx-ki/com2-stack/docker-compose.yml.bak.* ; do
|
||||||
|
for f in $cand; do
|
||||||
|
[ -f "$f" ] || continue
|
||||||
|
if grep -qE '^[[:space:]]{2}hxki-web:[[:space:]]*$' "$f"; then
|
||||||
|
SRC="$f"
|
||||||
|
break 2
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ -z "$SRC" ]; then
|
||||||
|
echo "WARN: Keine Quelle mit hxki-web gefunden -> überspringe web-restore."
|
||||||
|
else
|
||||||
|
echo "SRC(web)=$SRC"
|
||||||
|
cp -a "$SRC" "$BK/docker-compose.yml.web-src"
|
||||||
|
python3 - <<PY
|
||||||
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
dst = Path("$F")
|
||||||
|
src = Path("$SRC")
|
||||||
|
|
||||||
|
d = dst.read_text()
|
||||||
|
s = src.read_text()
|
||||||
|
|
||||||
|
def extract_block(text, name):
|
||||||
|
# block: " name:" bis zum nächsten " <service>:"
|
||||||
|
m = re.search(rf'(?ms)^\\s{{2}}{re.escape(name)}:\\s*\\n.*?(?=^\\s{{2}}[A-Za-z0-9_.-]+:\\s*$|\\Z)', text)
|
||||||
|
return m.group(0) if m else None
|
||||||
|
|
||||||
|
web = extract_block(s, "hxki-web")
|
||||||
|
if not web:
|
||||||
|
raise SystemExit("SRC hat keinen hxki-web Block obwohl grep ihn fand (unerwartet).")
|
||||||
|
|
||||||
|
# dst services-block finden
|
||||||
|
ms = re.search(r'(?ms)^services:\\s*\\n', d)
|
||||||
|
if not ms:
|
||||||
|
raise SystemExit("DST hat keinen top-level services:-Block.")
|
||||||
|
|
||||||
|
# wenn dst schon hxki-web hat -> ersetzen, sonst einfügen
|
||||||
|
if re.search(r'(?m)^\\s{2}hxki-web:\\s*$', d):
|
||||||
|
d2 = re.sub(r'(?ms)^\\s{2}hxki-web:\\s*\\n.*?(?=^\\s{2}[A-Za-z0-9_.-]+:\\s*$|\\Z)', web, d)
|
||||||
|
else:
|
||||||
|
# nach services: direkt einfügen (oben)
|
||||||
|
d2 = re.sub(r'(?ms)^(services:\\s*\\n)', r'\\1' + web + "\\n", d, count=1)
|
||||||
|
|
||||||
|
# sicherstellen, dass hxki-web im hxki-internal hängt (wenn nicht, adden)
|
||||||
|
if "hxki-web:" in d2 and "networks: [hxki-internal]" not in web and "networks:" not in web:
|
||||||
|
# falls web-block gar keine networks hat: am Ende des blocks ergänzen
|
||||||
|
d2 = re.sub(r'(?ms)(^\\s{2}hxki-web:\\s*\\n.*?)(?=^\\s{2}[A-Za-z0-9_.-]+:\\s*$|\\Z)',
|
||||||
|
lambda m: m.group(1).rstrip()+"\\n networks: [hxki-internal]\\n",
|
||||||
|
d2, count=1)
|
||||||
|
|
||||||
|
dst.write_text(d2)
|
||||||
|
PY
|
||||||
|
echo "OK: hxki-web Block restored/patched."
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[5] Validate + Restart Orchester"
|
||||||
|
cd "$DIR"
|
||||||
|
docker compose -f "$F" config >/dev/null
|
||||||
|
docker compose down --remove-orphans
|
||||||
|
docker compose up -d --remove-orphans
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[6] Hard Checks"
|
||||||
|
docker ps --format 'NAME={{.Names}} STATUS={{.Status}} PORTS={{.Ports}}' | egrep 'hxki-|hx-caddy' || true
|
||||||
|
docker network inspect "$NET" --format '{{range $id,$c := .Containers}}{{println $c.Name}}{{end}}' | sort
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[7] Caddy -> Upstreams"
|
||||||
|
docker exec -it hx-caddy sh -lc 'wget -qO- http://hxki-n8n:5678/ >/dev/null && echo OK_CADDY_TO_N8N || echo FAIL_CADDY_TO_N8N' || true
|
||||||
|
docker exec -it hx-caddy sh -lc 'wget -qO- http://hxki-mautic/ >/dev/null && echo OK_CADDY_TO_MAUTIC || echo FAIL_CADDY_TO_MAUTIC' || true
|
||||||
|
# web: probiere 80 und 3000
|
||||||
|
docker exec -it hx-caddy sh -lc '(wget -qO- http://hxki-web/ >/dev/null && echo OK_CADDY_TO_WEB_80) || (wget -qO- http://hxki-web:3000/ >/dev/null && echo OK_CADDY_TO_WEB_3000) || echo FAIL_CADDY_TO_WEB' || true
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[8] Logs kurz"
|
||||||
|
docker logs --tail=30 hxki-n8n 2>&1 || true
|
||||||
|
docker logs --tail=30 hxki-mautic 2>&1 || true
|
||||||
|
docker logs --tail=30 hxki-web 2>&1 || true
|
||||||
|
|
||||||
|
echo "=== ENDE ==="
|
||||||
76
COM2_FIX_POSTGRES_ADMIN_ONE_SHOT.sh
Executable file
76
COM2_FIX_POSTGRES_ADMIN_ONE_SHOT.sh
Executable file
@@ -0,0 +1,76 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
C="hxki-postgres"
|
||||||
|
|
||||||
|
echo "=== FIX POSTGRES ADMIN (one-shot) ==="
|
||||||
|
docker inspect "$C" >/dev/null 2>&1 || { echo "FEHLT: $C"; exit 1; }
|
||||||
|
|
||||||
|
IMG="$(docker inspect "$C" --format '{{.Config.Image}}')"
|
||||||
|
echo "[0] Image: $IMG"
|
||||||
|
|
||||||
|
# Admin-User/PW/DB aus ENV lesen (Autorität: Container selbst)
|
||||||
|
get_env() {
|
||||||
|
local key="$1"
|
||||||
|
docker inspect "$C" --format '{{range .Config.Env}}{{println .}}{{end}}' \
|
||||||
|
| awk -F= -v k="$key" '$1==k{print substr($0, index($0,"=")+1)}' | head -n1
|
||||||
|
}
|
||||||
|
|
||||||
|
ADMIN_USER="$(get_env POSTGRES_USER || true)"
|
||||||
|
ADMIN_PW="$(get_env POSTGRES_PASSWORD || true)"
|
||||||
|
ADMIN_DB="$(get_env POSTGRES_DB || true)"
|
||||||
|
|
||||||
|
# Bitnami-Fallbacks
|
||||||
|
[ -n "${ADMIN_USER:-}" ] || ADMIN_USER="$(get_env POSTGRESQL_USERNAME || true)"
|
||||||
|
[ -n "${ADMIN_PW:-}" ] || ADMIN_PW="$(get_env POSTGRESQL_PASSWORD || true)"
|
||||||
|
[ -n "${ADMIN_DB:-}" ] || ADMIN_DB="$(get_env POSTGRESQL_DATABASE || true)"
|
||||||
|
|
||||||
|
# Default-DB-Fallback
|
||||||
|
[ -n "${ADMIN_DB:-}" ] || ADMIN_DB="postgres"
|
||||||
|
|
||||||
|
echo "[1] Detected ADMIN_USER=${ADMIN_USER:-<leer>} ADMIN_DB=${ADMIN_DB:-<leer>}"
|
||||||
|
[ -n "${ADMIN_USER:-}" ] || { echo "FAIL: Konnte ADMIN_USER nicht aus Container ENV lesen."; exit 1; }
|
||||||
|
[ -n "${ADMIN_PW:-}" ] || { echo "FAIL: Konnte ADMIN_PW nicht aus Container ENV lesen."; exit 1; }
|
||||||
|
|
||||||
|
# Zielwerte für n8n (aus n8n-Container-ENV – Autorität!)
|
||||||
|
N8N="hxki-n8n"
|
||||||
|
docker inspect "$N8N" >/dev/null 2>&1 || { echo "FEHLT: $N8N"; exit 1; }
|
||||||
|
|
||||||
|
get_env_n8n() {
|
||||||
|
local key="$1"
|
||||||
|
docker inspect "$N8N" --format '{{range .Config.Env}}{{println .}}{{end}}' \
|
||||||
|
| awk -F= -v k="$key" '$1==k{print substr($0, index($0,"=")+1)}' | head -n1
|
||||||
|
}
|
||||||
|
|
||||||
|
PG_USER="$(get_env_n8n DB_POSTGRESDB_USER || true)"
|
||||||
|
PG_PW="$(get_env_n8n DB_POSTGRESDB_PASSWORD || true)"
|
||||||
|
PG_DB="$(get_env_n8n DB_POSTGRESDB_DATABASE || true)"
|
||||||
|
|
||||||
|
[ -n "${PG_USER:-}" ] || { echo "FAIL: n8n ENV fehlt DB_POSTGRESDB_USER"; exit 1; }
|
||||||
|
[ -n "${PG_PW:-}" ] || { echo "FAIL: n8n ENV fehlt DB_POSTGRESDB_PASSWORD"; exit 1; }
|
||||||
|
[ -n "${PG_DB:-}" ] || { echo "FAIL: n8n ENV fehlt DB_POSTGRESDB_DATABASE"; exit 1; }
|
||||||
|
|
||||||
|
echo "[2] Target (für n8n): user=$PG_USER db=$PG_DB"
|
||||||
|
|
||||||
|
echo "[3] Apply in Postgres (create/alter role + create db)"
|
||||||
|
docker exec -i "$C" sh -lc "export PGPASSWORD='${ADMIN_PW}'; psql -v ON_ERROR_STOP=1 -U '${ADMIN_USER}' -d '${ADMIN_DB}'" <<SQL
|
||||||
|
DO \$\$
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname='${PG_USER}') THEN
|
||||||
|
CREATE ROLE ${PG_USER} LOGIN PASSWORD '${PG_PW}';
|
||||||
|
ELSE
|
||||||
|
ALTER ROLE ${PG_USER} WITH LOGIN PASSWORD '${PG_PW}';
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM pg_database WHERE datname='${PG_DB}') THEN
|
||||||
|
CREATE DATABASE ${PG_DB} OWNER ${PG_USER};
|
||||||
|
END IF;
|
||||||
|
END
|
||||||
|
\$\$;
|
||||||
|
GRANT ALL PRIVILEGES ON DATABASE ${PG_DB} TO ${PG_USER};
|
||||||
|
SQL
|
||||||
|
|
||||||
|
echo "[4] Quick check: kann sich n8n-user anmelden?"
|
||||||
|
docker exec -i "$C" sh -lc "export PGPASSWORD='${PG_PW}'; psql -v ON_ERROR_STOP=1 -U '${PG_USER}' -d '${PG_DB}' -c 'select 1;' >/dev/null"
|
||||||
|
echo "OK: Postgres Credentials passen jetzt für n8n."
|
||||||
|
echo "=== ENDE ==="
|
||||||
85
COM2_FIX_POSTGRES_SEMICOLON_AND_VERIFY_ONE_SHOT.sh
Executable file
85
COM2_FIX_POSTGRES_SEMICOLON_AND_VERIFY_ONE_SHOT.sh
Executable file
@@ -0,0 +1,85 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DIR="/opt/hx-ki/com2-stack"
|
||||||
|
F="$DIR/docker-compose.yml"
|
||||||
|
C="hxki-postgres"
|
||||||
|
TS="$(date +%Y%m%d-%H%M%S)"
|
||||||
|
BK="/opt/hx-ki/backups/com2-pg-semicolon-$TS"
|
||||||
|
mkdir -p "$BK"
|
||||||
|
|
||||||
|
echo "=== COM2 · FIX POSTGRES ; + VERIFY (one-shot) ==="
|
||||||
|
echo "Compose: $F"
|
||||||
|
echo "Backup: $BK"
|
||||||
|
echo
|
||||||
|
|
||||||
|
[ -f "$F" ] || { echo "FAIL: missing $F"; exit 1; }
|
||||||
|
|
||||||
|
cp -a "$F" "$BK/docker-compose.yml.pre"
|
||||||
|
|
||||||
|
echo "[1] Show offending lines (with trailing ';')"
|
||||||
|
grep -nE 'POSTGRES_(USER|PASSWORD|DB)=.*;$' "$F" || echo "OK: no trailing ';' in compose"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[2] Patch ONLY trailing ';' for POSTGRES_USER/POSTGRES_PASSWORD/POSTGRES_DB (compose is authority)"
|
||||||
|
# supports both list-form " - POSTGRES_USER=..." and mapping-form "POSTGRES_USER: ..."
|
||||||
|
sed -i -E \
|
||||||
|
-e 's/^(\s*-\s*POSTGRES_USER=[^;]*);$/\1/' \
|
||||||
|
-e 's/^(\s*-\s*POSTGRES_PASSWORD=[^;]*);$/\1/' \
|
||||||
|
-e 's/^(\s*-\s*POSTGRES_DB=[^;]*);$/\1/' \
|
||||||
|
-e 's/^(\s*POSTGRES_USER:\s*[^;]*);$/\1/' \
|
||||||
|
-e 's/^(\s*POSTGRES_PASSWORD:\s*[^;]*);$/\1/' \
|
||||||
|
-e 's/^(\s*POSTGRES_DB:\s*[^;]*);$/\1/' \
|
||||||
|
"$F"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[3] Validate compose"
|
||||||
|
docker compose -f "$F" config >/dev/null
|
||||||
|
echo "OK: compose valid"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[4] Recreate postgres container to re-inject ENV"
|
||||||
|
cd "$DIR"
|
||||||
|
docker compose up -d --force-recreate --no-deps "$C" >/dev/null
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[5] Read ENV actually inside container (ground truth)"
|
||||||
|
docker inspect "$C" --format '{{range .Config.Env}}{{println .}}{{end}}' | egrep '^POSTGRES_(USER|PASSWORD|DB)=' || true
|
||||||
|
|
||||||
|
PG_USER="$(docker inspect "$C" --format '{{range .Config.Env}}{{println .}}{{end}}' | awk -F= '/^POSTGRES_USER=/{print $2}' | tail -n1)"
|
||||||
|
PG_DB="$(docker inspect "$C" --format '{{range .Config.Env}}{{println .}}{{end}}' | awk -F= '/^POSTGRES_DB=/{print $2}' | tail -n1)"
|
||||||
|
PG_PW="$(docker inspect "$C" --format '{{range .Config.Env}}{{println .}}{{end}}' | awk -F= '/^POSTGRES_PASSWORD=/{print $2}' | tail -n1)"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[6] Wait until Postgres accepts connections (max 30s)"
|
||||||
|
for i in $(seq 1 30); do
|
||||||
|
if docker exec -e PGPASSWORD="$PG_PW" "$C" psql -U "$PG_USER" -d "$PG_DB" -c "SELECT 1;" >/dev/null 2>&1; then
|
||||||
|
echo "OK: login works with CURRENT ENV"
|
||||||
|
OK_MODE="CURRENT_ENV"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "${OK_MODE:-}" != "CURRENT_ENV" ]; then
|
||||||
|
echo "WARN: login failed with CURRENT ENV. Testing legacy ';' variants deterministically."
|
||||||
|
|
||||||
|
# Variant B: user+db with ';' and password with ';'
|
||||||
|
if docker exec -e PGPASSWORD="${PG_PW};" "$C" psql -U "${PG_USER};" -d "${PG_DB};" -c "SELECT 1;" >/dev/null 2>&1; then
|
||||||
|
echo "OK: legacy semicolon credentials work (user/db/pw had ';' at init time)"
|
||||||
|
OK_MODE="LEGACY_SEMICOLON"
|
||||||
|
else
|
||||||
|
echo "FAIL: Neither CURRENT_ENV nor LEGACY_SEMICOLON credentials can authenticate."
|
||||||
|
echo "=> Then the only deterministic path is an auth-reset inside the data dir (no guessing), because plaintext can't be recovered."
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "=== RESULT ==="
|
||||||
|
echo "MODE=$OK_MODE"
|
||||||
|
echo "POSTGRES_USER=$PG_USER"
|
||||||
|
echo "POSTGRES_DB=$PG_DB"
|
||||||
|
echo "POSTGRES_PASSWORD=$PG_PW"
|
||||||
|
echo "Backup: $BK"
|
||||||
|
echo "=== DONE ==="
|
||||||
77
COM2_MAUTIC_FIX_RUN_ON_SERVER_ONE_SHOT.sh
Executable file
77
COM2_MAUTIC_FIX_RUN_ON_SERVER_ONE_SHOT.sh
Executable file
@@ -0,0 +1,77 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
COMPOSE="/opt/hx-ki/com2-stack/docker-compose.yml"
|
||||||
|
ENVF="/opt/hx-ki/com2-stack/.env"
|
||||||
|
|
||||||
|
MY="hxki-mariadb"
|
||||||
|
MA="hxki-mautic"
|
||||||
|
CA="hx-caddy"
|
||||||
|
|
||||||
|
echo "=== COM2 · MAUTIC FIX (run on server only) ==="
|
||||||
|
[ -f "$COMPOSE" ] || { echo "FAIL: missing $COMPOSE"; exit 1; }
|
||||||
|
[ -f "$ENVF" ] || { echo "FAIL: missing $ENVF"; exit 1; }
|
||||||
|
|
||||||
|
# load .env (simple KEY=VALUE)
|
||||||
|
set -a
|
||||||
|
. "$ENVF"
|
||||||
|
set +a
|
||||||
|
|
||||||
|
# bring up mariadb first
|
||||||
|
docker compose -f "$COMPOSE" up -d "$MY"
|
||||||
|
|
||||||
|
# root pw from .env or container env
|
||||||
|
ROOTPW="${MARIADB_ROOT_PASSWORD-${MYSQL_ROOT_PASSWORD-}}"
|
||||||
|
if [ -z "${ROOTPW:-}" ]; then
|
||||||
|
ROOTPW="$(docker inspect "$MY" --format '{{range .Config.Env}}{{println .}}{{end}}' \
|
||||||
|
| awk -F= '/^(MARIADB_ROOT_PASSWORD|MYSQL_ROOT_PASSWORD)=/{print $2}' | tail -n1 || true)"
|
||||||
|
fi
|
||||||
|
[ -n "${ROOTPW:-}" ] || { echo "FAIL: cannot determine MariaDB root password"; exit 1; }
|
||||||
|
|
||||||
|
# mautic creds STRICTLY from .env (must exist)
|
||||||
|
DB_NAME="${MAUTIC_DB_NAME-${MYSQL_DATABASE-mautic}}"
|
||||||
|
DB_USER="${MAUTIC_DB_USER-${MYSQL_USER-mautic}}"
|
||||||
|
DB_PASS="${MAUTIC_DB_PASSWORD-${MYSQL_PASSWORD-}}"
|
||||||
|
[ -n "${DB_USER:-}" ] || { echo "FAIL: MAUTIC_DB_USER or MYSQL_USER missing in .env"; exit 1; }
|
||||||
|
[ -n "${DB_PASS:-}" ] || { echo "FAIL: MAUTIC_DB_PASSWORD or MYSQL_PASSWORD missing in .env"; exit 1; }
|
||||||
|
|
||||||
|
echo "DB_NAME=$DB_NAME"
|
||||||
|
echo "DB_USER=$DB_USER"
|
||||||
|
echo "DB_PASS=***"
|
||||||
|
|
||||||
|
# wait mariadb ready
|
||||||
|
for i in {1..40}; do
|
||||||
|
if docker exec -i "$MY" sh -lc "mariadb -uroot -p\"$ROOTPW\" -e 'SELECT 1' >/dev/null 2>&1"; then
|
||||||
|
echo "OK: MariaDB ready"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
[ "$i" -eq 40 ] && { echo "FAIL: MariaDB not ready"; exit 1; }
|
||||||
|
done
|
||||||
|
|
||||||
|
# align user/db/grants (no data loss)
|
||||||
|
docker exec -i "$MY" sh -lc "mariadb -uroot -p\"$ROOTPW\" <<SQL
|
||||||
|
CREATE DATABASE IF NOT EXISTS \\\`$DB_NAME\\\`;
|
||||||
|
CREATE USER IF NOT EXISTS '$DB_USER'@'%' IDENTIFIED BY '$DB_PASS';
|
||||||
|
ALTER USER '$DB_USER'@'%' IDENTIFIED BY '$DB_PASS';
|
||||||
|
GRANT ALL PRIVILEGES ON \\\`$DB_NAME\\\`.* TO '$DB_USER'@'%';
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
SQL"
|
||||||
|
|
||||||
|
echo "OK: grants aligned"
|
||||||
|
|
||||||
|
# restart mautic and caddy (if present in compose)
|
||||||
|
docker compose -f "$COMPOSE" up -d --force-recreate "$MA" "$CA" || true
|
||||||
|
|
||||||
|
echo "=== STATUS ==="
|
||||||
|
docker ps --format 'NAME={{.Names}} STATUS={{.Status}} PORTS={{.Ports}}' | egrep 'hxki-|hx-caddy' || true
|
||||||
|
|
||||||
|
echo "=== CADDY -> MAUTIC CHECK ==="
|
||||||
|
if docker exec -i "$CA" sh -lc "wget -qO- http://$MA/ >/dev/null"; then
|
||||||
|
echo "OK_CADDY_TO_MAUTIC"
|
||||||
|
else
|
||||||
|
echo "FAIL_CADDY_TO_MAUTIC"
|
||||||
|
echo "--- mautic logs (tail 120) ---"
|
||||||
|
docker logs --tail=120 "$MA" || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
159
COM2_MAUTIC_INSTALL_FERRARI_ONE_SHOT.sh
Executable file
159
COM2_MAUTIC_INSTALL_FERRARI_ONE_SHOT.sh
Executable file
@@ -0,0 +1,159 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DIR="/opt/hx-ki/com2-stack"
|
||||||
|
COMPOSE="$DIR/docker-compose.yml"
|
||||||
|
ENVF="$DIR/.env"
|
||||||
|
|
||||||
|
[ -f "$COMPOSE" ] || { echo "FAIL: missing $COMPOSE"; exit 1; }
|
||||||
|
[ -f "$ENVF" ] || { echo "FAIL: missing $ENVF"; exit 1; }
|
||||||
|
|
||||||
|
cd "$DIR"
|
||||||
|
|
||||||
|
echo "=== COM2 · MAUTIC INSTALL (ONE-SHOT, NO REBUILD, NO GUESSING) ==="
|
||||||
|
|
||||||
|
# Load .env as authority (only simple KEY=VALUE lines)
|
||||||
|
set -a
|
||||||
|
. "$ENVF"
|
||||||
|
set +a
|
||||||
|
|
||||||
|
# Resolve service names from compose (authority: compose)
|
||||||
|
MAUTIC_SVC="$(python3 - <<'PY'
|
||||||
|
import re, pathlib
|
||||||
|
p=pathlib.Path("/opt/hx-ki/com2-stack/docker-compose.yml")
|
||||||
|
s=p.read_text()
|
||||||
|
m=re.search(r'(?ms)^services:\s*\n(.*?)(?=^\S|\Z)', s)
|
||||||
|
if not m: raise SystemExit("FAIL: no services: block")
|
||||||
|
blk=m.group(1)
|
||||||
|
# find service with container_name: hxki-mautic
|
||||||
|
cur=None
|
||||||
|
for line in blk.splitlines():
|
||||||
|
mm=re.match(r'^\s{2}([A-Za-z0-9_.-]+):\s*$', line)
|
||||||
|
if mm: cur=mm.group(1); continue
|
||||||
|
if cur and re.match(r'^\s{4}container_name:\s*hxki-mautic\s*$', line):
|
||||||
|
print(cur); raise SystemExit(0)
|
||||||
|
raise SystemExit("FAIL: could not find service for container_name: hxki-mautic")
|
||||||
|
PY
|
||||||
|
)"
|
||||||
|
DB_SVC="$(python3 - <<'PY'
|
||||||
|
import re, pathlib
|
||||||
|
p=pathlib.Path("/opt/hx-ki/com2-stack/docker-compose.yml")
|
||||||
|
s=p.read_text()
|
||||||
|
m=re.search(r'(?ms)^services:\s*\n(.*?)(?=^\S|\Z)', s)
|
||||||
|
if not m: raise SystemExit("FAIL: no services: block")
|
||||||
|
blk=m.group(1)
|
||||||
|
# find service with container_name: hxki-mariadb
|
||||||
|
cur=None
|
||||||
|
for line in blk.splitlines():
|
||||||
|
mm=re.match(r'^\s{2}([A-Za-z0-9_.-]+):\s*$', line)
|
||||||
|
if mm: cur=mm.group(1); continue
|
||||||
|
if cur and re.match(r'^\s{4}container_name:\s*hxki-mariadb\s*$', line):
|
||||||
|
print(cur); raise SystemExit(0)
|
||||||
|
raise SystemExit("FAIL: could not find service for container_name: hxki-mariadb")
|
||||||
|
PY
|
||||||
|
)"
|
||||||
|
|
||||||
|
MA="hxki-mautic"
|
||||||
|
MY="hxki-mariadb"
|
||||||
|
CA="hx-caddy"
|
||||||
|
|
||||||
|
echo "[1] Bring up DB + Mautic (no orphans change)"
|
||||||
|
docker compose up -d "$DB_SVC" "$MAUTIC_SVC" >/dev/null
|
||||||
|
|
||||||
|
echo "[2] Hard requirements from .env (NO guessing)"
|
||||||
|
req() { local k="$1"; [ -n "${!k:-}" ] || { echo "FAIL: missing $k in $ENVF"; exit 1; }; }
|
||||||
|
|
||||||
|
req MAUTIC_DB_HOST
|
||||||
|
req MAUTIC_DB_NAME
|
||||||
|
req MAUTIC_DB_USER
|
||||||
|
req MAUTIC_DB_PASSWORD
|
||||||
|
req MAUTIC_ADMIN_USERNAME
|
||||||
|
req MAUTIC_ADMIN_PASSWORD
|
||||||
|
req MAUTIC_ADMIN_EMAIL
|
||||||
|
|
||||||
|
echo " DB_HOST=$MAUTIC_DB_HOST DB_NAME=$MAUTIC_DB_NAME DB_USER=$MAUTIC_DB_USER DB_PASS=***"
|
||||||
|
echo " ADMIN_USER=$MAUTIC_ADMIN_USERNAME ADMIN_EMAIL=$MAUTIC_ADMIN_EMAIL ADMIN_PASS=***"
|
||||||
|
|
||||||
|
echo "[3] Read MariaDB root password (NO guessing: container env)"
|
||||||
|
ROOTPW="$(docker inspect "$MY" --format '{{range .Config.Env}}{{println .}}{{end}}' \
|
||||||
|
| awk -F= '/^(MARIADB_ROOT_PASSWORD|MYSQL_ROOT_PASSWORD)=/{print $2}' | tail -n1 || true)"
|
||||||
|
[ -n "${ROOTPW:-}" ] || { echo "FAIL: MariaDB root password not found in container env"; exit 1; }
|
||||||
|
|
||||||
|
echo "[4] Wait MariaDB ready (max 60s) + ensure DB exists (no data loss)"
|
||||||
|
for i in {1..60}; do
|
||||||
|
if docker exec -i "$MY" sh -lc "mariadb -uroot -p\"$ROOTPW\" -e 'SELECT 1' >/dev/null 2>&1"; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
[ "$i" -eq 60 ] && { echo "FAIL: MariaDB not ready"; docker logs --tail=120 "$MY" || true; exit 1; }
|
||||||
|
done
|
||||||
|
|
||||||
|
docker exec -i "$MY" sh -lc "mariadb -uroot -p\"$ROOTPW\" <<SQL
|
||||||
|
CREATE DATABASE IF NOT EXISTS \\\`$MAUTIC_DB_NAME\\\`;
|
||||||
|
SQL" >/dev/null
|
||||||
|
|
||||||
|
# If Mautic uses non-root user, ensure it can log in + has grants (still no data loss)
|
||||||
|
if [ "$MAUTIC_DB_USER" != "root" ]; then
|
||||||
|
docker exec -i "$MY" sh -lc "mariadb -uroot -p\"$ROOTPW\" <<SQL
|
||||||
|
CREATE USER IF NOT EXISTS '$MAUTIC_DB_USER'@'%' IDENTIFIED BY '$MAUTIC_DB_PASSWORD';
|
||||||
|
ALTER USER '$MAUTIC_DB_USER'@'%' IDENTIFIED BY '$MAUTIC_DB_PASSWORD';
|
||||||
|
GRANT ALL PRIVILEGES ON \\\`$MAUTIC_DB_NAME\\\`.* TO '$MAUTIC_DB_USER'@'%';
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
SQL" >/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[5] If already installed -> stop here (local.php present)"
|
||||||
|
if docker exec -i "$MA" sh -lc "test -f app/config/local.php"; then
|
||||||
|
echo "OK: already installed (app/config/local.php exists)"
|
||||||
|
else
|
||||||
|
echo "[6] Run Mautic installer inside container (deterministic CLI)"
|
||||||
|
# detect console path
|
||||||
|
CONSOLE=""
|
||||||
|
if docker exec -i "$MA" sh -lc "test -x bin/console"; then
|
||||||
|
CONSOLE="bin/console"
|
||||||
|
elif docker exec -i "$MA" sh -lc "test -x app/console"; then
|
||||||
|
CONSOLE="app/console"
|
||||||
|
else
|
||||||
|
echo "FAIL: cannot find bin/console or app/console inside $MA"
|
||||||
|
docker exec -i "$MA" sh -lc "ls -la" || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run installer (no interaction)
|
||||||
|
docker exec -i "$MA" sh -lc "
|
||||||
|
php $CONSOLE mautic:install \
|
||||||
|
--db_driver=pdo_mysql \
|
||||||
|
--db_host=\"$MAUTIC_DB_HOST\" \
|
||||||
|
--db_port=3306 \
|
||||||
|
--db_name=\"$MAUTIC_DB_NAME\" \
|
||||||
|
--db_user=\"$MAUTIC_DB_USER\" \
|
||||||
|
--db_password=\"$MAUTIC_DB_PASSWORD\" \
|
||||||
|
--admin_firstname=HXKI \
|
||||||
|
--admin_lastname=Admin \
|
||||||
|
--admin_username=\"$MAUTIC_ADMIN_USERNAME\" \
|
||||||
|
--admin_password=\"$MAUTIC_ADMIN_PASSWORD\" \
|
||||||
|
--admin_email=\"$MAUTIC_ADMIN_EMAIL\" \
|
||||||
|
--no-interaction
|
||||||
|
" || { echo "FAIL: mautic:install failed"; docker logs --tail=200 "$MA" || true; exit 1; }
|
||||||
|
|
||||||
|
echo "[7] Verify local.php created"
|
||||||
|
docker exec -i "$MA" sh -lc "test -f app/config/local.php" || { echo "FAIL: install did not create app/config/local.php"; exit 1; }
|
||||||
|
echo "OK: installed (local.php present)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[8] Restart Mautic (clean) and verify Caddy can reach it"
|
||||||
|
docker compose up -d --force-recreate "$MAUTIC_SVC" >/dev/null
|
||||||
|
|
||||||
|
# wait for http from caddy
|
||||||
|
for i in {1..60}; do
|
||||||
|
if docker exec -i "$CA" sh -lc "wget -qO- http://$MA/ >/dev/null"; then
|
||||||
|
echo "OK_CADDY_TO_MAUTIC"
|
||||||
|
echo "=== DONE ==="
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "FAIL: Caddy still cannot reach Mautic after install"
|
||||||
|
docker logs --tail=200 "$MA" || true
|
||||||
|
exit 1
|
||||||
131
COM2_MAUTIC_INSTALL_ONE_SHOT.sh
Executable file
131
COM2_MAUTIC_INSTALL_ONE_SHOT.sh
Executable file
@@ -0,0 +1,131 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DIR="/opt/hx-ki/com2-stack"
|
||||||
|
ENVF="$DIR/.env"
|
||||||
|
COMPOSE="$DIR/docker-compose.yml"
|
||||||
|
|
||||||
|
MA="hxki-mautic"
|
||||||
|
MY="hxki-mariadb"
|
||||||
|
|
||||||
|
echo "=== COM2 · MAUTIC INSTALL ONE-SHOT (no guessing) ==="
|
||||||
|
echo "Compose: $COMPOSE"
|
||||||
|
echo "Env: $ENVF"
|
||||||
|
echo
|
||||||
|
|
||||||
|
[ -f "$COMPOSE" ] || { echo "FAIL: missing $COMPOSE"; exit 1; }
|
||||||
|
[ -f "$ENVF" ] || { echo "FAIL: missing $ENVF"; exit 1; }
|
||||||
|
|
||||||
|
docker inspect "$MA" >/dev/null 2>&1 || { echo "FAIL: missing container $MA"; exit 1; }
|
||||||
|
docker inspect "$MY" >/dev/null 2>&1 || { echo "FAIL: missing container $MY"; exit 1; }
|
||||||
|
|
||||||
|
# --- [1] Ground truth DB params from mautic container env -------------------
|
||||||
|
DB_HOST="$(docker inspect "$MA" --format '{{range .Config.Env}}{{println .}}{{end}}' | awk -F= '/^MAUTIC_DB_HOST=/{print $2}' | tail -n1)"
|
||||||
|
DB_USER="$(docker inspect "$MA" --format '{{range .Config.Env}}{{println .}}{{end}}' | awk -F= '/^MAUTIC_DB_USER=/{print $2}' | tail -n1)"
|
||||||
|
DB_PASS="$(docker inspect "$MA" --format '{{range .Config.Env}}{{println .}}{{end}}' | awk -F= '/^MAUTIC_DB_PASSWORD=/{print $2}' | tail -n1)"
|
||||||
|
DB_NAME="$(docker inspect "$MA" --format '{{range .Config.Env}}{{println .}}{{end}}' | awk -F= '/^MAUTIC_DB_NAME=/{print $2}' | tail -n1)"
|
||||||
|
|
||||||
|
[ -n "${DB_HOST:-}" ] || { echo "FAIL: MAUTIC_DB_HOST missing in container env"; exit 1; }
|
||||||
|
[ -n "${DB_USER:-}" ] || { echo "FAIL: MAUTIC_DB_USER missing in container env"; exit 1; }
|
||||||
|
[ -n "${DB_PASS:-}" ] || { echo "FAIL: MAUTIC_DB_PASSWORD missing in container env"; exit 1; }
|
||||||
|
[ -n "${DB_NAME:-}" ] || { echo "FAIL: MAUTIC_DB_NAME missing in container env"; exit 1; }
|
||||||
|
|
||||||
|
echo "[1] DB (ground truth): host=$DB_HOST db=$DB_NAME user=$DB_USER pass=***"
|
||||||
|
|
||||||
|
# --- [2] MariaDB root password from MariaDB container env (no guessing) -----
|
||||||
|
ROOTPW="$(docker inspect "$MY" --format '{{range .Config.Env}}{{println .}}{{end}}' \
|
||||||
|
| awk -F= '/^(MARIADB_ROOT_PASSWORD|MYSQL_ROOT_PASSWORD)=/{print $2}' | tail -n1 || true)"
|
||||||
|
|
||||||
|
[ -n "${ROOTPW:-}" ] || { echo "FAIL: MariaDB root PW not found in container env"; exit 1; }
|
||||||
|
echo "[2] MariaDB root PW present (not shown)"
|
||||||
|
|
||||||
|
# Wait until MariaDB accepts root connections
|
||||||
|
echo "[2a] Wait MariaDB ready (max 60s)"
|
||||||
|
for i in {1..60}; do
|
||||||
|
if docker exec -i "$MY" sh -lc "mariadb -uroot -p\"$ROOTPW\" -e 'SELECT 1' >/dev/null 2>&1"; then
|
||||||
|
echo " OK: MariaDB ready"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
[ "$i" -eq 60 ] && { echo "FAIL: MariaDB not ready"; docker logs --tail=120 "$MY" || true; exit 1; }
|
||||||
|
done
|
||||||
|
|
||||||
|
# Ensure DB + user + grants match the *existing* state (no data loss)
|
||||||
|
echo "[2b] Align DB user/grants to existing DB (no data loss)"
|
||||||
|
docker exec -i "$MY" sh -lc "mariadb -uroot -p\"$ROOTPW\" <<SQL
|
||||||
|
CREATE DATABASE IF NOT EXISTS \\\`$DB_NAME\\\`;
|
||||||
|
CREATE USER IF NOT EXISTS '$DB_USER'@'%' IDENTIFIED BY '$DB_PASS';
|
||||||
|
ALTER USER '$DB_USER'@'%' IDENTIFIED BY '$DB_PASS';
|
||||||
|
GRANT ALL PRIVILEGES ON \\\`$DB_NAME\\\`.* TO '$DB_USER'@'%';
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
SQL"
|
||||||
|
echo " OK: grants aligned"
|
||||||
|
|
||||||
|
# --- [3] Ensure MAUTIC_ADMIN_* exists in .env (generate once, then persist) ---
|
||||||
|
echo "[3] Ensure MAUTIC_ADMIN_* in $ENVF (no guessing: generate+persist if missing)"
|
||||||
|
|
||||||
|
# Load env
|
||||||
|
set -a
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
. "$ENVF" || true
|
||||||
|
set +a
|
||||||
|
|
||||||
|
gen_pw() { tr -dc 'A-Za-z0-9!@#%^_-.' </dev/urandom | head -c 24; echo; }
|
||||||
|
|
||||||
|
if [ -z "${MAUTIC_ADMIN_USERNAME:-}" ]; then
|
||||||
|
MAUTIC_ADMIN_USERNAME="admin"
|
||||||
|
fi
|
||||||
|
if [ -z "${MAUTIC_ADMIN_PASSWORD:-}" ]; then
|
||||||
|
MAUTIC_ADMIN_PASSWORD="$(gen_pw)"
|
||||||
|
fi
|
||||||
|
if [ -z "${MAUTIC_ADMIN_EMAIL:-}" ]; then
|
||||||
|
MAUTIC_ADMIN_EMAIL="admin@hxki.local"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Persist into .env (idempotent)
|
||||||
|
grep -q '^MAUTIC_ADMIN_USERNAME=' "$ENVF" && sed -i "s/^MAUTIC_ADMIN_USERNAME=.*/MAUTIC_ADMIN_USERNAME=$MAUTIC_ADMIN_USERNAME/" "$ENVF" || echo "MAUTIC_ADMIN_USERNAME=$MAUTIC_ADMIN_USERNAME" >> "$ENVF"
|
||||||
|
grep -q '^MAUTIC_ADMIN_PASSWORD=' "$ENVF" && sed -i "s/^MAUTIC_ADMIN_PASSWORD=.*/MAUTIC_ADMIN_PASSWORD=$MAUTIC_ADMIN_PASSWORD/" "$ENVF" || echo "MAUTIC_ADMIN_PASSWORD=$MAUTIC_ADMIN_PASSWORD" >> "$ENVF"
|
||||||
|
grep -q '^MAUTIC_ADMIN_EMAIL=' "$ENVF" && sed -i "s/^MAUTIC_ADMIN_EMAIL=.*/MAUTIC_ADMIN_EMAIL=$MAUTIC_ADMIN_EMAIL/" "$ENVF" || echo "MAUTIC_ADMIN_EMAIL=$MAUTIC_ADMIN_EMAIL" >> "$ENVF"
|
||||||
|
|
||||||
|
echo " OK: MAUTIC_ADMIN_USERNAME=$MAUTIC_ADMIN_USERNAME"
|
||||||
|
echo " OK: MAUTIC_ADMIN_EMAIL=$MAUTIC_ADMIN_EMAIL"
|
||||||
|
echo " OK: MAUTIC_ADMIN_PASSWORD=*** (written to .env)"
|
||||||
|
|
||||||
|
# --- [4] Recreate mautic so it receives new env ----------------------------
|
||||||
|
echo "[4] Recreate $MA to inject admin env"
|
||||||
|
cd "$DIR"
|
||||||
|
docker compose up -d --force-recreate "$MA" >/dev/null
|
||||||
|
|
||||||
|
# --- [5] Install if not installed -----------------------------------------
|
||||||
|
echo "[5] Install check"
|
||||||
|
if docker exec "$MA" test -f app/config/local.php; then
|
||||||
|
echo "OK: already installed (local.php exists)"
|
||||||
|
else
|
||||||
|
echo "Not installed yet -> trying CLI install (only if available)"
|
||||||
|
|
||||||
|
# Find console path
|
||||||
|
CONSOLE=""
|
||||||
|
if docker exec "$MA" test -x /var/www/html/bin/console; then CONSOLE="/var/www/html/bin/console"; fi
|
||||||
|
if [ -z "$CONSOLE" ] && docker exec "$MA" test -x /var/www/html/app/console; then CONSOLE="/var/www/html/app/console"; fi
|
||||||
|
|
||||||
|
[ -n "$CONSOLE" ] || { echo "FAIL: cannot find Mautic console (bin/console or app/console)"; exit 1; }
|
||||||
|
|
||||||
|
# Verify command exists
|
||||||
|
if ! docker exec "$MA" sh -lc "php $CONSOLE list 2>/dev/null | grep -q 'mautic:install'"; then
|
||||||
|
echo "FAIL: mautic:install command not available in this image -> cannot do scripted install without guessing image internals."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Run install with explicit params (no guessing)
|
||||||
|
docker exec "$MA" sh -lc "php $CONSOLE mautic:install --force \
|
||||||
|
--db_host='$DB_HOST' --db_name='$DB_NAME' --db_user='$DB_USER' --db_password='$DB_PASS' \
|
||||||
|
--admin_username='$MAUTIC_ADMIN_USERNAME' --admin_password='$MAUTIC_ADMIN_PASSWORD' --admin_email='$MAUTIC_ADMIN_EMAIL'"
|
||||||
|
|
||||||
|
echo "OK: install command executed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "=== DONE ==="
|
||||||
|
echo "Admin user: $MAUTIC_ADMIN_USERNAME"
|
||||||
|
echo "Admin email: $MAUTIC_ADMIN_EMAIL"
|
||||||
|
echo "Admin pass: (steht in $ENVF)"
|
||||||
89
COM2_MAUTIC_RECREATE_BY_SERVICE_ONE_SHOT.sh
Executable file
89
COM2_MAUTIC_RECREATE_BY_SERVICE_ONE_SHOT.sh
Executable file
@@ -0,0 +1,89 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DIR="/opt/hx-ki/com2-stack"
|
||||||
|
COMPOSE="$DIR/docker-compose.yml"
|
||||||
|
ENVF="$DIR/.env"
|
||||||
|
MA_CONTAINER="hxki-mautic"
|
||||||
|
|
||||||
|
echo "=== COM2 · MAUTIC RECREATE (service-resolve, no guessing) ==="
|
||||||
|
[ -f "$COMPOSE" ] || { echo "FAIL: missing $COMPOSE"; exit 1; }
|
||||||
|
[ -f "$ENVF" ] || { echo "FAIL: missing $ENVF"; exit 1; }
|
||||||
|
|
||||||
|
# 1) Find service name that owns container_name: hxki-mautic (authority: compose)
|
||||||
|
SVC="$(
|
||||||
|
python3 - <<'PY'
|
||||||
|
import re, pathlib
|
||||||
|
p = pathlib.Path("/opt/hx-ki/com2-stack/docker-compose.yml")
|
||||||
|
s = p.read_text()
|
||||||
|
|
||||||
|
m = re.search(r'(?ms)^services:\s*\n(.*?)(?=^\S|\Z)', s)
|
||||||
|
if not m:
|
||||||
|
print("")
|
||||||
|
raise SystemExit(0)
|
||||||
|
blk = m.group(1)
|
||||||
|
|
||||||
|
# parse services by 2-space indentation
|
||||||
|
services = []
|
||||||
|
cur = None
|
||||||
|
cur_lines = []
|
||||||
|
for line in blk.splitlines(True):
|
||||||
|
m2 = re.match(r'^ ([A-Za-z0-9_.-]+):\s*$', line)
|
||||||
|
if m2:
|
||||||
|
if cur:
|
||||||
|
services.append((cur, "".join(cur_lines)))
|
||||||
|
cur = m2.group(1)
|
||||||
|
cur_lines = []
|
||||||
|
else:
|
||||||
|
if cur is not None:
|
||||||
|
cur_lines.append(line)
|
||||||
|
if cur:
|
||||||
|
services.append((cur, "".join(cur_lines)))
|
||||||
|
|
||||||
|
# priority 1: container_name match
|
||||||
|
for name, body in services:
|
||||||
|
if re.search(r'(?m)^\s{4}container_name:\s*hxki-mautic\s*$', body):
|
||||||
|
print(name); raise SystemExit(0)
|
||||||
|
|
||||||
|
# priority 2: image contains mautic
|
||||||
|
for name, body in services:
|
||||||
|
if re.search(r'(?m)^\s{4}image:\s*.*mautic.*$', body, re.I):
|
||||||
|
print(name); raise SystemExit(0)
|
||||||
|
|
||||||
|
print("")
|
||||||
|
PY
|
||||||
|
)"
|
||||||
|
|
||||||
|
if [ -z "$SVC" ]; then
|
||||||
|
echo "FAIL: Konnte Mautic-Service-Namen in $COMPOSE nicht finden."
|
||||||
|
echo "Check: grep -n 'container_name: hxki-mautic' $COMPOSE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "OK: Mautic service name in compose = $SVC"
|
||||||
|
|
||||||
|
# 2) Ensure admin vars exist in .env (no guessing; generate if missing) - safe charset (no tr range bug)
|
||||||
|
set -a
|
||||||
|
# shellcheck disable=SC1090
|
||||||
|
. "$ENVF" || true
|
||||||
|
set +a
|
||||||
|
|
||||||
|
gen_pw() { tr -dc 'A-Za-z0-9@#%+=:,.!' </dev/urandom | head -c 24; echo; }
|
||||||
|
|
||||||
|
: "${MAUTIC_ADMIN_USERNAME:=admin}"
|
||||||
|
: "${MAUTIC_ADMIN_PASSWORD:=$(gen_pw)}"
|
||||||
|
: "${MAUTIC_ADMIN_EMAIL:=admin@hxki.local}"
|
||||||
|
|
||||||
|
grep -q '^MAUTIC_ADMIN_USERNAME=' "$ENVF" && sed -i "s/^MAUTIC_ADMIN_USERNAME=.*/MAUTIC_ADMIN_USERNAME=$MAUTIC_ADMIN_USERNAME/" "$ENVF" || echo "MAUTIC_ADMIN_USERNAME=$MAUTIC_ADMIN_USERNAME" >> "$ENVF"
|
||||||
|
grep -q '^MAUTIC_ADMIN_PASSWORD=' "$ENVF" && sed -i "s/^MAUTIC_ADMIN_PASSWORD=.*/MAUTIC_ADMIN_PASSWORD=$MAUTIC_ADMIN_PASSWORD/" "$ENVF" || echo "MAUTIC_ADMIN_PASSWORD=$MAUTIC_ADMIN_PASSWORD" >> "$ENVF"
|
||||||
|
grep -q '^MAUTIC_ADMIN_EMAIL=' "$ENVF" && sed -i "s/^MAUTIC_ADMIN_EMAIL=.*/MAUTIC_ADMIN_EMAIL=$MAUTIC_ADMIN_EMAIL/" "$ENVF" || echo "MAUTIC_ADMIN_EMAIL=$MAUTIC_ADMIN_EMAIL" >> "$ENVF"
|
||||||
|
|
||||||
|
echo "OK: Admin ENV ensured in .env (password stored in file)"
|
||||||
|
|
||||||
|
# 3) Recreate using SERVICE name (not container name)
|
||||||
|
cd "$DIR"
|
||||||
|
docker compose up -d --force-recreate "$SVC"
|
||||||
|
|
||||||
|
echo "=== DONE ==="
|
||||||
|
echo "If Mautic still not ready, run:"
|
||||||
|
echo " docker logs --tail=200 $MA_CONTAINER"
|
||||||
98
COM2_REBUILD_FROM_EXISTING.sh
Executable file
98
COM2_REBUILD_FROM_EXISTING.sh
Executable file
@@ -0,0 +1,98 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
BASE="/opt/hx-ki/com-stack/docker-compose.yml"
|
||||||
|
OUTDIR="/opt/hx-ki/com2-stack"
|
||||||
|
OUT="$OUTDIR/docker-compose.yml"
|
||||||
|
TS="$(date +%Y%m%d-%H%M%S)"
|
||||||
|
|
||||||
|
echo "=== COM2 REBUILD (Autorität wird: $OUT) ==="
|
||||||
|
|
||||||
|
# 0) Basis muss existieren (dein aktueller „Wahrheits-Compose“)
|
||||||
|
[ -f "$BASE" ] || { echo "FEHLT: $BASE"; exit 1; }
|
||||||
|
|
||||||
|
mkdir -p "$OUTDIR"
|
||||||
|
|
||||||
|
echo "[1] Backup vom aktuellen com-stack Compose"
|
||||||
|
cp -a "$BASE" "${BASE}.bak.${TS}"
|
||||||
|
|
||||||
|
echo "[2] Erzeuge kanonische YAML aus Basis-Compose"
|
||||||
|
TMP_CANON="/tmp/com2.base.${TS}.yml"
|
||||||
|
docker compose -f "$BASE" config > "$TMP_CANON"
|
||||||
|
|
||||||
|
echo "[3] Entferne Service: grafana (falls vorhanden)"
|
||||||
|
TMP_NOGRAF="/tmp/com2.nograf.${TS}.yml"
|
||||||
|
awk '
|
||||||
|
BEGIN{skip=0}
|
||||||
|
/^ grafana:$/ {skip=1; next}
|
||||||
|
skip==1 && /^ [A-Za-z0-9_.-]+:$/ {skip=0}
|
||||||
|
skip==0 {print}
|
||||||
|
' "$TMP_CANON" > "$TMP_NOGRAF"
|
||||||
|
|
||||||
|
echo "[4] Suche vorhandene Mautic-Compose-Datei auf dem Server"
|
||||||
|
MAUTIC_FILE="$(grep -RIl --exclude-dir='.git' --include='*.yml' --include='*.yaml' -E '^[[:space:]]*mautic:' /opt/hx-ki 2>/dev/null | head -n1 || true)"
|
||||||
|
|
||||||
|
if [ -z "${MAUTIC_FILE:-}" ]; then
|
||||||
|
echo "WARN: Keine vorhandene 'mautic:' Definition unter /opt/hx-ki gefunden."
|
||||||
|
echo " -> COM2-Compose wird OHNE Mautic geschrieben (weil du 0% Vermutung willst)."
|
||||||
|
cp -a "$TMP_NOGRAF" "$OUT"
|
||||||
|
else
|
||||||
|
echo "OK: Mautic-Definition gefunden in: $MAUTIC_FILE"
|
||||||
|
TMP_MAUTIC_CANON="/tmp/com2.mautic.${TS}.yml"
|
||||||
|
docker compose -f "$MAUTIC_FILE" config > "$TMP_MAUTIC_CANON"
|
||||||
|
|
||||||
|
echo "[5] Extrahiere nur den Mautic-Service-Block (deterministisch)"
|
||||||
|
TMP_MAUTIC_BLOCK="/tmp/com2.mautic.block.${TS}.yml"
|
||||||
|
awk '
|
||||||
|
BEGIN{inservices=0; grab=0}
|
||||||
|
/^services:$/ {inservices=1; next}
|
||||||
|
inservices==1 && /^ mautic:$/ {grab=1; print " mautic:"; next}
|
||||||
|
grab==1 && /^ [A-Za-z0-9_.-]+:$/ {grab=0}
|
||||||
|
grab==1 {print}
|
||||||
|
' "$TMP_MAUTIC_CANON" > "$TMP_MAUTIC_BLOCK"
|
||||||
|
|
||||||
|
if ! grep -q '^ mautic:$' "$TMP_MAUTIC_BLOCK"; then
|
||||||
|
echo "WARN: Konnte mautic-Block nicht extrahieren -> schreibe ohne Mautic (0% Vermutung)."
|
||||||
|
cp -a "$TMP_NOGRAF" "$OUT"
|
||||||
|
else
|
||||||
|
echo "[6] Füge Mautic in COM2-Compose ein (unter services:)"
|
||||||
|
# Insert mautic block right after 'services:' line
|
||||||
|
awk -v block="$TMP_MAUTIC_BLOCK" '
|
||||||
|
BEGIN{inserted=0}
|
||||||
|
/^services:$/ {
|
||||||
|
print
|
||||||
|
if (inserted==0) {
|
||||||
|
while ((getline line < block) > 0) print line
|
||||||
|
close(block)
|
||||||
|
inserted=1
|
||||||
|
}
|
||||||
|
next
|
||||||
|
}
|
||||||
|
{print}
|
||||||
|
' "$TMP_NOGRAF" > "$OUT"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[7] Host-Caddy stoppen (damit Docker-Caddy Port 80/443 bekommt), falls aktiv"
|
||||||
|
if systemctl is-active --quiet caddy 2>/dev/null; then
|
||||||
|
systemctl stop caddy
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[8] hxki-internal sicherstellen"
|
||||||
|
if ! docker network ls --format '{{.Name}}' | grep -q '^hxki-internal$'; then
|
||||||
|
docker network create hxki-internal >/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[9] COM2 Orchester starten NUR aus $OUT"
|
||||||
|
cd "$OUTDIR"
|
||||||
|
docker compose down --remove-orphans || true
|
||||||
|
docker compose up -d --remove-orphans
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "=== COM2 STATUS (nur Fakten) ==="
|
||||||
|
docker ps --format 'NAME={{.Names}} STATUS={{.Status}} PORTS={{.Ports}}'
|
||||||
|
echo
|
||||||
|
echo "hxki-internal Mitglieder:"
|
||||||
|
docker network inspect hxki-internal --format '{{range $id,$c := .Containers}}{{println $c.Name}}{{end}}' | sort
|
||||||
|
|
||||||
|
echo "=== ENDE ==="
|
||||||
145
COM2_REPAIR_CANONICAL_ONE_SHOT.sh
Executable file
145
COM2_REPAIR_CANONICAL_ONE_SHOT.sh
Executable file
@@ -0,0 +1,145 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DIR="/opt/hx-ki/com2-stack"
|
||||||
|
F="$DIR/docker-compose.yml"
|
||||||
|
ENVF="$DIR/.env"
|
||||||
|
NET="hxki-internal"
|
||||||
|
TS="$(date +%Y%m%d-%H%M%S)"
|
||||||
|
BK="/opt/hx-ki/backups/com2-repair-$TS"
|
||||||
|
|
||||||
|
mkdir -p "$BK"
|
||||||
|
echo "=== COM2 REPAIR · CANONICAL ONE-SHOT (no guessing) ==="
|
||||||
|
echo "Compose: $F"
|
||||||
|
echo "Env: $ENVF"
|
||||||
|
echo "Backup: $BK"
|
||||||
|
echo
|
||||||
|
|
||||||
|
[ -f "$F" ] || { echo "FAIL: FEHLT $F"; exit 1; }
|
||||||
|
|
||||||
|
cp -a "$F" "$BK/docker-compose.yml.pre"
|
||||||
|
|
||||||
|
# 0) Netzwerk sicherstellen (external)
|
||||||
|
docker network inspect "$NET" >/dev/null 2>&1 || docker network create "$NET" >/dev/null
|
||||||
|
|
||||||
|
# 1) Alte Secrets/DB-Namen aus vorhandenen Dateien RECOVERn (keine Fantasie)
|
||||||
|
# Priorität: Inventory/Backups -> dann bestehende .env
|
||||||
|
echo "[1] Recover old state (secrets/dbnames) from /opt/hx-ki …"
|
||||||
|
|
||||||
|
# helper: first match from file list
|
||||||
|
first_match() { local re="$1"; shift; for f in "$@"; do [ -f "$f" ] || continue; local v; v="$(grep -Eo "$re" "$f" | head -n1 || true)"; [ -n "$v" ] && { echo "$v"; return 0; }; done; return 1; }
|
||||||
|
|
||||||
|
# Kandidatenquellen (du hast sie bereits im System)
|
||||||
|
SRC_FILES=(
|
||||||
|
"/opt/hx-ki/inventory/"*.txt
|
||||||
|
"/opt/hx-ki/com2-stack/"*.bak.*
|
||||||
|
"/opt/hx-ki/com-stack/docker-compose.yml"
|
||||||
|
"/opt/hx-ki/com-stack/"*.bak.*
|
||||||
|
"/opt/hx-ki/docker/"docker-compose.yml*
|
||||||
|
"$ENVF"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Postgres: Passwort + DB
|
||||||
|
PG_PASS_LINE="$(first_match 'POSTGRES_PASSWORD=[^[:space:]]+' "${SRC_FILES[@]}" || true)"
|
||||||
|
PG_DB_LINE="$(first_match 'POSTGRES_DB=[^[:space:]]+' "${SRC_FILES[@]}" || true)"
|
||||||
|
PG_USER_LINE="$(first_match 'POSTGRES_USER=[^[:space:]]+' "${SRC_FILES[@]}" || true)"
|
||||||
|
|
||||||
|
# Mautic/MariaDB: root oder mautic creds
|
||||||
|
MY_ROOT_LINE="$(first_match '(MARIADB_ROOT_PASSWORD|MYSQL_ROOT_PASSWORD)=[^[:space:]]+' "${SRC_FILES[@]}" || true)"
|
||||||
|
MAUTIC_USER_LINE="$(first_match 'MAUTIC_DB_USER=[^[:space:]]+' "${SRC_FILES[@]}" || true)"
|
||||||
|
MAUTIC_PASS_LINE="$(first_match 'MAUTIC_DB_PASSWORD=[^[:space:]]+' "${SRC_FILES[@]}" || true)"
|
||||||
|
MAUTIC_NAME_LINE="$(first_match 'MAUTIC_DB_NAME=[^[:space:]]+' "${SRC_FILES[@]}" || true)"
|
||||||
|
MAUTIC_ROOT_LINE="$(first_match 'MAUTIC_DB_ROOT_PASSWORD=[^[:space:]]+' "${SRC_FILES[@]}" || true)"
|
||||||
|
|
||||||
|
# Minimalanforderungen
|
||||||
|
if [ -z "${PG_PASS_LINE:-}" ] || [ -z "${PG_DB_LINE:-}" ] || [ -z "${PG_USER_LINE:-}" ]; then
|
||||||
|
echo "FAIL: Postgres Altzustand nicht eindeutig (POSTGRES_USER/PASSWORD/DB)."
|
||||||
|
echo " Liefere eine Quelle mit diesen Keys (inventory txt oder altes .env)."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# MariaDB/Mautic: entweder ROOT oder MAUTIC_* muss vorhanden sein
|
||||||
|
if [ -z "${MY_ROOT_LINE:-}" ] && [ -z "${MAUTIC_ROOT_LINE:-}" ] && ( [ -z "${MAUTIC_USER_LINE:-}" ] || [ -z "${MAUTIC_PASS_LINE:-}" ] ); then
|
||||||
|
echo "FAIL: MariaDB/Mautic Altzustand nicht eindeutig (root oder mautic creds fehlen)."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo " OK Postgres: $PG_USER_LINE $PG_DB_LINE (PW recovered)"
|
||||||
|
echo " OK MariaDB: $( [ -n "${MY_ROOT_LINE:-}" ] && echo "$MY_ROOT_LINE" || echo "$MAUTIC_ROOT_LINE" ) (root PW recovered)"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# 2) Schreibe .env KANONISCH (nur Werte, die wir wirklich kennen)
|
||||||
|
echo "[2] Write canonical .env (aligned to old DB state)"
|
||||||
|
cp -a "${ENVF:-/dev/null}" "$BK/.env.pre" 2>/dev/null || true
|
||||||
|
|
||||||
|
PG_USER="${PG_USER_LINE#POSTGRES_USER=}"
|
||||||
|
PG_PASSWORD="${PG_PASS_LINE#POSTGRES_PASSWORD=}"
|
||||||
|
PG_DB="${PG_DB_LINE#POSTGRES_DB=}"
|
||||||
|
|
||||||
|
# Mautic Defaults (wenn nicht vorhanden, bleiben leer -> Compose muss dann nicht drauf referenzieren)
|
||||||
|
MAUTIC_DB_USER="${MAUTIC_USER_LINE#MAUTIC_DB_USER=}"
|
||||||
|
MAUTIC_DB_PASSWORD="${MAUTIC_PASS_LINE#MAUTIC_DB_PASSWORD=}"
|
||||||
|
MAUTIC_DB_NAME="${MAUTIC_NAME_LINE#MAUTIC_DB_NAME=}"
|
||||||
|
MAUTIC_DB_ROOT_PASSWORD="${MAUTIC_ROOT_LINE#MAUTIC_DB_ROOT_PASSWORD=}"
|
||||||
|
|
||||||
|
# root pw aus MARIADB_ROOT_PASSWORD falls vorhanden
|
||||||
|
if [ -n "${MY_ROOT_LINE:-}" ]; then
|
||||||
|
ROOTPW="${MY_ROOT_LINE#*=}"
|
||||||
|
else
|
||||||
|
ROOTPW="${MAUTIC_DB_ROOT_PASSWORD:-}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat > "$ENVF" <<ENV
|
||||||
|
# === CANONICAL COM2 ENV (recovered from old state) ===
|
||||||
|
PG_USER=$PG_USER
|
||||||
|
PG_PASSWORD=$PG_PASSWORD
|
||||||
|
PG_DB=$PG_DB
|
||||||
|
|
||||||
|
# MariaDB/Mautic
|
||||||
|
MARIADB_ROOT_PASSWORD=$ROOTPW
|
||||||
|
MAUTIC_DB_ROOT_PASSWORD=$ROOTPW
|
||||||
|
MAUTIC_DB_USER=${MAUTIC_DB_USER:-root}
|
||||||
|
MAUTIC_DB_PASSWORD=${MAUTIC_DB_PASSWORD:-$ROOTPW}
|
||||||
|
MAUTIC_DB_NAME=${MAUTIC_DB_NAME:-mautic}
|
||||||
|
|
||||||
|
# n8n public host/proto (falls du es nutzt; ansonsten bleibt's neutral)
|
||||||
|
N8N_HOST=${N8N_HOST:-localhost}
|
||||||
|
N8N_PROTOCOL=${N8N_PROTOCOL:-http}
|
||||||
|
ENV
|
||||||
|
|
||||||
|
echo " OK: .env written"
|
||||||
|
|
||||||
|
# 3) Validate Compose
|
||||||
|
echo "[3] Validate compose"
|
||||||
|
docker compose -f "$F" --env-file "$ENVF" config >/dev/null
|
||||||
|
echo " OK: compose valid"
|
||||||
|
|
||||||
|
# 4) Orchester hoch
|
||||||
|
echo "[4] Up"
|
||||||
|
cd "$DIR"
|
||||||
|
docker compose --env-file "$ENVF" down --remove-orphans || true
|
||||||
|
docker compose --env-file "$ENVF" up -d --remove-orphans
|
||||||
|
|
||||||
|
# 5) Hard checks: DB login, then services listen, then caddy->upstreams
|
||||||
|
echo
|
||||||
|
echo "[5] HARD CHECKS"
|
||||||
|
|
||||||
|
echo "--- Postgres auth check (inside container) ---"
|
||||||
|
docker exec -e PGPASSWORD="$PG_PASSWORD" -it hxki-postgres psql -U "$PG_USER" -d "$PG_DB" -c "SELECT 1;" >/dev/null && echo "OK_PG_AUTH" || echo "FAIL_PG_AUTH"
|
||||||
|
|
||||||
|
echo "--- MariaDB auth check (inside container) ---"
|
||||||
|
docker exec -it hxki-mariadb sh -lc "mysql -uroot -p'$ROOTPW' -e 'SELECT 1;' >/dev/null 2>&1 && echo OK_MY_AUTH || echo FAIL_MY_AUTH"
|
||||||
|
|
||||||
|
echo "--- n8n logs (tail) ---"
|
||||||
|
docker logs --tail=20 hxki-n8n || true
|
||||||
|
|
||||||
|
echo "--- mautic logs (tail) ---"
|
||||||
|
docker logs --tail=40 hxki-mautic || true
|
||||||
|
|
||||||
|
echo "--- caddy -> upstreams ---"
|
||||||
|
docker exec -it hx-caddy sh -lc "wget -qO- http://hxki-n8n:5678/ >/dev/null && echo OK_CADDY_TO_N8N || echo FAIL_CADDY_TO_N8N" || true
|
||||||
|
docker exec -it hx-caddy sh -lc "wget -qO- http://hxki-mautic/ >/dev/null && echo OK_CADDY_TO_MAUTIC || echo FAIL_CADDY_TO_MAUTIC" || true
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "=== DONE ==="
|
||||||
|
echo "Backup: $BK"
|
||||||
168
COM2_REPAIR_ONE_SHOT.sh
Executable file
168
COM2_REPAIR_ONE_SHOT.sh
Executable file
@@ -0,0 +1,168 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DIR="/opt/hx-ki/com2-stack"
|
||||||
|
F="$DIR/docker-compose.yml"
|
||||||
|
NET="hxki-internal"
|
||||||
|
TS="$(date +%Y%m%d-%H%M%S)"
|
||||||
|
BK="$DIR/backup-$TS"
|
||||||
|
mkdir -p "$BK"
|
||||||
|
|
||||||
|
echo "=== COM2 REPAIR ONE-SHOT ==="
|
||||||
|
echo "Autorität: $F"
|
||||||
|
[ -f "$F" ] || { echo "FEHLT: $F"; exit 1; }
|
||||||
|
|
||||||
|
cp -a "$F" "$BK/docker-compose.yml.pre"
|
||||||
|
|
||||||
|
# 0) hxki-internal muss als external existieren
|
||||||
|
docker network inspect "$NET" >/dev/null 2>&1 || docker network create "$NET" >/dev/null
|
||||||
|
|
||||||
|
# 1) Service hxki-web wiederherstellen aus letztem Backup das hxki-web enthält
|
||||||
|
LATEST_WEB_SRC="$(ls -1t "$DIR"/backup-*/docker-compose.yml.orig 2>/dev/null | head -n1 || true)"
|
||||||
|
if ! grep -qE '^\s{2}hxki-web:\s*$' "$F"; then
|
||||||
|
echo "[1] hxki-web fehlt -> versuche Restore aus Backup"
|
||||||
|
if [ -z "${LATEST_WEB_SRC:-}" ] || ! grep -qE '^\s{2}hxki-web:\s*$' "$LATEST_WEB_SRC"; then
|
||||||
|
echo "FAIL: Kein Backup mit hxki-web gefunden. Lege eine Quelle bereit (z.B. altes Compose)."
|
||||||
|
echo " Erwartet: $DIR/backup-*/docker-compose.yml.orig mit ' hxki-web:' drin."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
python3 - <<PY
|
||||||
|
import re, pathlib
|
||||||
|
dst = pathlib.Path("$F").read_text()
|
||||||
|
src = pathlib.Path("$LATEST_WEB_SRC").read_text()
|
||||||
|
|
||||||
|
def extract_service(text, name):
|
||||||
|
m = re.search(r'(?ms)^services:\s*\n(.*?)(?=^\S|\Z)', text)
|
||||||
|
if not m: raise SystemExit("FEHLT services: im Source")
|
||||||
|
block = m.group(1)
|
||||||
|
pat = rf'(?ms)^\s{{2}}{re.escape(name)}:\s*\n(?:^\s{{4}}.*\n|^\s{{6}}.*\n|^\s{{8}}.*\n|^\s*\n)*?(?=^\s{{2}}[A-Za-z0-9_.-]+:\s*$|\Z)'
|
||||||
|
mm = re.search(pat, block)
|
||||||
|
if not mm: raise SystemExit(f"Service {name} nicht im Source gefunden")
|
||||||
|
return mm.group(0)
|
||||||
|
|
||||||
|
web = extract_service(src, "hxki-web")
|
||||||
|
|
||||||
|
m = re.search(r'(?ms)^services:\s*\n', dst)
|
||||||
|
if not m: raise SystemExit("FEHLT services: im Ziel")
|
||||||
|
# direkt nach "services:\n" einfügen
|
||||||
|
dst2 = re.sub(r'(?ms)^(services:\s*\n)', r'\1' + web + "\n", dst, count=1)
|
||||||
|
pathlib.Path("$F").write_text(dst2)
|
||||||
|
print("OK: hxki-web aus Backup wieder eingefügt.")
|
||||||
|
PY
|
||||||
|
else
|
||||||
|
echo "[1] OK: hxki-web ist vorhanden"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 2) Caddy Ports nach außen sicherstellen (damit es "reagiert")
|
||||||
|
python3 - <<PY
|
||||||
|
import re, pathlib
|
||||||
|
p = pathlib.Path("$F")
|
||||||
|
s = p.read_text()
|
||||||
|
|
||||||
|
def ensure_ports_for(service, ports_lines):
|
||||||
|
# finde service block
|
||||||
|
m = re.search(r'(?ms)^services:\s*\n(.*?)(?=^\S|\Z)', s)
|
||||||
|
if not m: raise SystemExit("FEHLT services:")
|
||||||
|
block = m.group(1)
|
||||||
|
|
||||||
|
pat = rf'(?ms)^\s{{2}}{re.escape(service)}:\s*\n(?:^\s{{4}}.*\n|^\s{{6}}.*\n|^\s{{8}}.*\n|^\s*\n)*?(?=^\s{{2}}[A-Za-z0-9_.-]+:\s*$|\Z)'
|
||||||
|
mm = re.search(pat, block)
|
||||||
|
if not mm: raise SystemExit(f"FEHLT Service {service}")
|
||||||
|
sb = mm.group(0)
|
||||||
|
|
||||||
|
if re.search(r'(?m)^\s{4}ports:\s*$', sb):
|
||||||
|
# ports block vorhanden -> ergänze fehlende mappings
|
||||||
|
def has(line): return re.search(r'(?m)^\s{6}-\s*' + re.escape(line) + r'\s*$', sb)
|
||||||
|
add = [l for l in ports_lines if not has(l)]
|
||||||
|
if add:
|
||||||
|
sb2 = re.sub(r'(?m)^(\s{4}ports:\s*\n)', r'\1' + ''.join([f' - "{l}"\n' for l in add]), sb, count=1)
|
||||||
|
else:
|
||||||
|
sb2 = sb
|
||||||
|
else:
|
||||||
|
# kein ports block -> vor networks oder am ende einfügen
|
||||||
|
ins = " ports:\n" + ''.join([f' - "{l}"\n' for l in ports_lines])
|
||||||
|
if re.search(r'(?m)^\s{4}networks:\s*', sb):
|
||||||
|
sb2 = re.sub(r'(?m)^(\s{4}networks:\s*)', ins + r'\1', sb, count=1)
|
||||||
|
else:
|
||||||
|
sb2 = sb.rstrip() + "\n" + ins
|
||||||
|
return pat, sb, sb2
|
||||||
|
|
||||||
|
ports = ["80:80","443:443","443:443/udp","2019:2019"]
|
||||||
|
pat, old, new = ensure_ports_for("hx-caddy", ports)
|
||||||
|
if old != new:
|
||||||
|
s2 = re.sub(pat, new, s, count=1)
|
||||||
|
p.write_text(s2)
|
||||||
|
print("OK: hx-caddy ports nach außen gesetzt/ergänzt.")
|
||||||
|
else:
|
||||||
|
print("OK: hx-caddy ports waren schon da.")
|
||||||
|
PY
|
||||||
|
|
||||||
|
# 3) n8n muss im Container auf 0.0.0.0 lauschen (damit Caddy reinkommt)
|
||||||
|
python3 - <<PY
|
||||||
|
import re, pathlib
|
||||||
|
p = pathlib.Path("$F")
|
||||||
|
s = p.read_text()
|
||||||
|
|
||||||
|
def patch_env(service, key, val):
|
||||||
|
m = re.search(r'(?ms)^services:\s*\n(.*?)(?=^\S|\Z)', s)
|
||||||
|
if not m: raise SystemExit("FEHLT services:")
|
||||||
|
block = m.group(1)
|
||||||
|
pat = rf'(?ms)^\s{{2}}{re.escape(service)}:\s*\n(?:^\s{{4}}.*\n|^\s{{6}}.*\n|^\s{{8}}.*\n|^\s*\n)*?(?=^\s{{2}}[A-Za-z0-9_.-]+:\s*$|\Z)'
|
||||||
|
mm = re.search(pat, block)
|
||||||
|
if not mm: raise SystemExit(f"FEHLT Service {service}")
|
||||||
|
sb = mm.group(0)
|
||||||
|
|
||||||
|
if re.search(r'(?m)^\s{6}'+re.escape(key)+r':', sb):
|
||||||
|
sb2 = re.sub(r'(?m)^(\s{6}'+re.escape(key)+r':\s*).*$' , r'\1'+val, sb)
|
||||||
|
else:
|
||||||
|
if re.search(r'(?m)^\s{4}environment:\s*$', sb):
|
||||||
|
sb2 = re.sub(r'(?m)^(\s{4}environment:\s*\n)', r'\1' + f' {key}: {val}\n', sb, count=1)
|
||||||
|
else:
|
||||||
|
# env block vor volumes/networks einfügen
|
||||||
|
env = " environment:\n" + f" {key}: {val}\n"
|
||||||
|
if re.search(r'(?m)^\s{4}volumes:\s*', sb):
|
||||||
|
sb2 = re.sub(r'(?m)^(\s{4}volumes:\s*)', env + r'\1', sb, count=1)
|
||||||
|
elif re.search(r'(?m)^\s{4}networks:\s*', sb):
|
||||||
|
sb2 = re.sub(r'(?m)^(\s{4}networks:\s*)', env + r'\1', sb, count=1)
|
||||||
|
else:
|
||||||
|
sb2 = sb.rstrip() + "\n" + env
|
||||||
|
return pat, sb, sb2
|
||||||
|
|
||||||
|
pat, old, new = patch_env("hxki-n8n", "N8N_LISTEN_ADDRESS", "0.0.0.0")
|
||||||
|
if old != new:
|
||||||
|
s2 = re.sub(pat, new, s, count=1)
|
||||||
|
p.write_text(s2)
|
||||||
|
print("OK: hxki-n8n N8N_LISTEN_ADDRESS=0.0.0.0 gesetzt.")
|
||||||
|
else:
|
||||||
|
print("OK: hxki-n8n N8N_LISTEN_ADDRESS war schon ok.")
|
||||||
|
PY
|
||||||
|
|
||||||
|
# 4) Validate (harte Wahrheit)
|
||||||
|
echo "[V] Validate: docker compose config"
|
||||||
|
docker compose -f "$F" config >/dev/null
|
||||||
|
echo "OK: Compose valide."
|
||||||
|
|
||||||
|
# 5) Orchester neu starten
|
||||||
|
cd "$DIR"
|
||||||
|
docker compose down --remove-orphans || true
|
||||||
|
docker compose up -d --remove-orphans
|
||||||
|
|
||||||
|
# 6) n8n Listen-Check im Container
|
||||||
|
echo "[T] n8n lauscht?"
|
||||||
|
for i in {1..60}; do
|
||||||
|
if docker exec hxki-n8n sh -lc "ss -lnt | grep -q ':5678'"; then
|
||||||
|
echo "OK: n8n lauscht auf 5678."
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
# 7) Caddy -> n8n intern
|
||||||
|
echo "[T] Caddy -> n8n?"
|
||||||
|
docker exec -it hx-caddy sh -lc 'wget -qO- http://hxki-n8n:5678/ >/dev/null && echo OK_CADDY_TO_N8N || echo FAIL_CADDY_TO_N8N'
|
||||||
|
|
||||||
|
# 8) Status
|
||||||
|
docker ps --format 'NAME={{.Names}} STATUS={{.Status}} PORTS={{.Ports}}'
|
||||||
|
|
||||||
|
echo "=== ENDE COM2 REPAIR ONE-SHOT ==="
|
||||||
68
COM2_RESTORE_ORIGINAL_STATE_ONE_SHOT.sh
Executable file
68
COM2_RESTORE_ORIGINAL_STATE_ONE_SHOT.sh
Executable file
@@ -0,0 +1,68 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
ROOT="/opt/hx-ki"
|
||||||
|
DIR="$ROOT/com2-stack"
|
||||||
|
COMPOSE_DST="$DIR/docker-compose.yml"
|
||||||
|
NET="hxki-internal"
|
||||||
|
TS="$(date +%Y%m%d-%H%M%S)"
|
||||||
|
BK="$ROOT/backups/com2-original-restore-$TS"
|
||||||
|
|
||||||
|
mkdir -p "$BK"
|
||||||
|
echo "=== COM2 · RESTORE ORIGINAL STATE (one-shot, no guessing) ==="
|
||||||
|
echo "DST compose: $COMPOSE_DST"
|
||||||
|
echo "Backup: $BK"
|
||||||
|
echo
|
||||||
|
|
||||||
|
[ -f "$COMPOSE_DST" ] || { echo "FAIL: missing $COMPOSE_DST"; exit 1; }
|
||||||
|
cp -a "$COMPOSE_DST" "$BK/docker-compose.yml.pre" || true
|
||||||
|
|
||||||
|
echo "[1] Suche Compose-Quelle mit hxki-web (ohne Raten)…"
|
||||||
|
pick_src() {
|
||||||
|
# COM2 Backups (neueste zuerst)
|
||||||
|
for f in $(ls -1t /opt/hx-ki/com2-stack/docker-compose.yml.bak.* 2>/dev/null); do
|
||||||
|
grep -qE '^[[:space:]]{2}hxki-web:[[:space:]]*$' "$f" && { echo "$f"; return 0; }
|
||||||
|
done
|
||||||
|
# COM1 compose + backups
|
||||||
|
for f in /opt/hx-ki/com-stack/docker-compose.yml /opt/hx-ki/com-stack/docker-compose.yml.bak.*; do
|
||||||
|
[ -f "$f" ] || continue
|
||||||
|
grep -qE '^[[:space:]]{2}hxki-web:[[:space:]]*$' "$f" && { echo "$f"; return 0; }
|
||||||
|
done
|
||||||
|
# docker Backups
|
||||||
|
for f in /opt/hx-ki/docker/docker-compose.yml*; do
|
||||||
|
[ -f "$f" ] || continue
|
||||||
|
grep -qE '^[[:space:]]{2}hxki-web:[[:space:]]*$' "$f" && { echo "$f"; return 0; }
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
SRC="$(pick_src || true)"
|
||||||
|
[ -n "${SRC:-}" ] || { echo "FAIL: keine Compose-Quelle mit hxki-web gefunden"; exit 1; }
|
||||||
|
|
||||||
|
echo "OK: SRC=$SRC"
|
||||||
|
cp -a "$SRC" "$BK/docker-compose.source.used"
|
||||||
|
cp -a "$SRC" "$COMPOSE_DST"
|
||||||
|
|
||||||
|
echo "[2] hxki-internal als external sicherstellen (nur ergänzen, nichts raten)"
|
||||||
|
docker network inspect "$NET" >/dev/null 2>&1 || docker network create "$NET" >/dev/null
|
||||||
|
|
||||||
|
# Falls am Ende kein networks:-Block existiert: minimal anhängen
|
||||||
|
if ! grep -qE '^networks:' "$COMPOSE_DST"; then
|
||||||
|
cat >> "$COMPOSE_DST" <<NETS
|
||||||
|
|
||||||
|
networks:
|
||||||
|
hxki-internal:
|
||||||
|
external: true
|
||||||
|
NETS
|
||||||
|
else
|
||||||
|
# Wenn networks existiert, aber hxki-internal nicht: minimal ergänzen
|
||||||
|
if ! grep -qE '^[[:space:]]{2}hxki-internal:' "$COMPOSE_DST"; then
|
||||||
|
echo "WARN: networks: existiert, aber hxki-internal fehlt -> bitte manuell prüfen (ich ändere hier nicht kreativ)."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "[3] Validate compose"
|
||||||
|
docker compose -f "$COMPOSE_DST" config >/dev/null
|
||||||
|
echo "OK: compose valid"
|
||||||
|
|
||||||
|
echo "DONE. Backup: $BK"
|
||||||
68
COM2_RESTORE_WEB_ONE_SHOT.sh
Executable file
68
COM2_RESTORE_WEB_ONE_SHOT.sh
Executable file
@@ -0,0 +1,68 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DST="/opt/hx-ki/com2-stack/docker-compose.yml"
|
||||||
|
[ -f "$DST" ] || { echo "FEHLT: $DST"; exit 1; }
|
||||||
|
|
||||||
|
pick_src() {
|
||||||
|
# 1) COM2 Backups (neueste zuerst)
|
||||||
|
for f in $(ls -1t /opt/hx-ki/com2-stack/docker-compose.yml.bak.* 2>/dev/null); do
|
||||||
|
grep -qE '^[[:space:]]{2}hxki-web:[[:space:]]*$' "$f" && { echo "$f"; return 0; }
|
||||||
|
done
|
||||||
|
|
||||||
|
# 2) COM-Stack
|
||||||
|
for f in /opt/hx-ki/com-stack/docker-compose.yml /opt/hx-ki/com-stack/docker-compose.yml.bak.*; do
|
||||||
|
[ -f "$f" ] || continue
|
||||||
|
grep -qE '^[[:space:]]{2}hxki-web:[[:space:]]*$' "$f" && { echo "$f"; return 0; }
|
||||||
|
done
|
||||||
|
|
||||||
|
# 3) docker Backups
|
||||||
|
for f in /opt/hx-ki/docker/docker-compose.yml*; do
|
||||||
|
[ -f "$f" ] || continue
|
||||||
|
grep -qE '^[[:space:]]{2}hxki-web:[[:space:]]*$' "$f" && { echo "$f"; return 0; }
|
||||||
|
done
|
||||||
|
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
SRC="$(pick_src)"
|
||||||
|
[ -n "$SRC" ] || { echo "FAIL: Keine Quelle mit hxki-web gefunden"; exit 1; }
|
||||||
|
|
||||||
|
export SRC DST
|
||||||
|
|
||||||
|
echo "=== COM2 RESTORE hxki-web ==="
|
||||||
|
echo "SRC=$SRC"
|
||||||
|
echo "DST=$DST"
|
||||||
|
|
||||||
|
python3 <<'PY'
|
||||||
|
import re, pathlib, os
|
||||||
|
|
||||||
|
src = pathlib.Path(os.environ["SRC"]).read_text()
|
||||||
|
dstp = pathlib.Path(os.environ["DST"])
|
||||||
|
dst = dstp.read_text()
|
||||||
|
|
||||||
|
m = re.search(r'(?ms)^services:\s*\n(.*?)(?=^\S|\Z)', src)
|
||||||
|
if not m:
|
||||||
|
raise SystemExit("FEHLT: services: im Source")
|
||||||
|
|
||||||
|
block = m.group(1)
|
||||||
|
|
||||||
|
pat = r'(?ms)^\s{2}hxki-web:\s*\n(?:^\s{4}.*\n|^\s{6}.*\n|^\s{8}.*\n|^\s*\n)*?(?=^\s{2}[A-Za-z0-9_.-]+:\s*$|\Z)'
|
||||||
|
mm = re.search(pat, block)
|
||||||
|
if not mm:
|
||||||
|
raise SystemExit("FEHLT: hxki-web Block")
|
||||||
|
|
||||||
|
web = mm.group(0)
|
||||||
|
|
||||||
|
if 'hxki-web:' in dst:
|
||||||
|
print("OK: hxki-web bereits vorhanden")
|
||||||
|
raise SystemExit(0)
|
||||||
|
|
||||||
|
dst = re.sub(r'(?m)^(services:\s*\n)', r'\1' + web + '\n', dst, count=1)
|
||||||
|
dstp.write_text(dst)
|
||||||
|
|
||||||
|
print("OK: hxki-web eingefügt")
|
||||||
|
PY
|
||||||
|
|
||||||
|
docker compose -f "$DST" config >/dev/null
|
||||||
|
echo "OK: Compose valide."
|
||||||
84
COM2_STRIP_PG_SEMICOLONS_AND_REVERIFY_ONE_SHOT.sh
Executable file
84
COM2_STRIP_PG_SEMICOLONS_AND_REVERIFY_ONE_SHOT.sh
Executable file
@@ -0,0 +1,84 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DIR="/opt/hx-ki/com2-stack"
|
||||||
|
F="$DIR/docker-compose.yml"
|
||||||
|
C="hxki-postgres"
|
||||||
|
TS="$(date +%Y%m%d-%H%M%S)"
|
||||||
|
BK="/opt/hx-ki/backups/com2-strip-pg-$TS"
|
||||||
|
mkdir -p "$BK"
|
||||||
|
|
||||||
|
echo "=== COM2 · STRIP PG ';' + REVERIFY (one-shot) ==="
|
||||||
|
echo "Compose: $F"
|
||||||
|
echo "Backup: $BK"
|
||||||
|
echo
|
||||||
|
|
||||||
|
[ -f "$F" ] || { echo "FAIL: missing $F"; exit 1; }
|
||||||
|
cp -a "$F" "$BK/docker-compose.yml.pre"
|
||||||
|
|
||||||
|
echo "[1] Strip trailing ';' from POSTGRES_USER/DB/PASSWORD values (list + mapping, quoted/unquoted)"
|
||||||
|
python3 - <<'PY'
|
||||||
|
from pathlib import Path
|
||||||
|
import re
|
||||||
|
|
||||||
|
p = Path("/opt/hx-ki/com2-stack/docker-compose.yml")
|
||||||
|
s = p.read_text()
|
||||||
|
|
||||||
|
keys = ["POSTGRES_USER", "POSTGRES_PASSWORD", "POSTGRES_DB"]
|
||||||
|
|
||||||
|
# list-form: - KEY=value;
|
||||||
|
for k in keys:
|
||||||
|
s = re.sub(rf'^(\s*-\s*{k}=)(.*?);(\s*)$', r'\1\2\3', s, flags=re.M)
|
||||||
|
|
||||||
|
# mapping-form: KEY: value;
|
||||||
|
for k in keys:
|
||||||
|
s = re.sub(rf'^(\s*{k}:\s*)(.*?);(\s*)$', r'\1\2\3', s, flags=re.M)
|
||||||
|
|
||||||
|
# also handle quoted values: KEY: "value;";
|
||||||
|
for k in keys:
|
||||||
|
s = re.sub(rf'^(\s*{k}:\s*")(.*?);("(\s*)$)', r'\1\2\3', s, flags=re.M)
|
||||||
|
|
||||||
|
p.write_text(s)
|
||||||
|
PY
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[2] Validate compose"
|
||||||
|
docker compose -f "$F" config >/dev/null
|
||||||
|
echo "OK: compose valid"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[3] Recreate postgres to re-inject sanitized ENV"
|
||||||
|
cd "$DIR"
|
||||||
|
docker compose up -d --force-recreate --no-deps "$C" >/dev/null
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[4] Ground truth ENV inside container (must NOT end with ';')"
|
||||||
|
docker inspect "$C" --format '{{range .Config.Env}}{{println .}}{{end}}' | egrep '^POSTGRES_(USER|PASSWORD|DB)='
|
||||||
|
|
||||||
|
PG_USER="$(docker inspect "$C" --format '{{range .Config.Env}}{{println .}}{{end}}' | awk -F= '/^POSTGRES_USER=/{print $2}' | tail -n1)"
|
||||||
|
PG_DB="$(docker inspect "$C" --format '{{range .Config.Env}}{{println .}}{{end}}' | awk -F= '/^POSTGRES_DB=/{print $2}' | tail -n1)"
|
||||||
|
PG_PW="$(docker inspect "$C" --format '{{range .Config.Env}}{{println .}}{{end}}' | awk -F= '/^POSTGRES_PASSWORD=/{print $2}' | tail -n1)"
|
||||||
|
|
||||||
|
for x in "$PG_USER" "$PG_DB" "$PG_PW"; do
|
||||||
|
if [[ "$x" == *";"* ]]; then
|
||||||
|
echo "FAIL: still contains ';' in ENV -> $x"
|
||||||
|
exit 3
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "OK: no semicolons in ENV"
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[5] Verify REAL login (max 30s)"
|
||||||
|
for i in $(seq 1 30); do
|
||||||
|
if docker exec -e PGPASSWORD="$PG_PW" "$C" psql -U "$PG_USER" -d "$PG_DB" -c "SELECT 1;" >/dev/null 2>&1; then
|
||||||
|
echo "OK: Postgres auth works with CURRENT ENV"
|
||||||
|
echo "=== DONE ==="
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "FAIL: Postgres still rejects CURRENT ENV."
|
||||||
|
echo "=> That means the DATA DIR was initialized with different credentials."
|
||||||
|
echo "=> Next deterministic step is a controlled auth-reset (one-time), or you provide the real old password."
|
||||||
|
exit 2
|
||||||
38
COM2_UP_AND_HARD_CHECKS.sh
Executable file
38
COM2_UP_AND_HARD_CHECKS.sh
Executable file
@@ -0,0 +1,38 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
DIR="/opt/hx-ki/com2-stack"
|
||||||
|
F="$DIR/docker-compose.yml"
|
||||||
|
NET="hxki-internal"
|
||||||
|
|
||||||
|
echo "=== COM2 UP + HARD CHECKS ==="
|
||||||
|
[ -f "$F" ] || { echo "FEHLT: $F"; exit 1; }
|
||||||
|
|
||||||
|
# 0) Netzwerk muss external existieren
|
||||||
|
docker network inspect "$NET" >/dev/null 2>&1 || docker network create "$NET" >/dev/null
|
||||||
|
|
||||||
|
# 1) Orchester neu hoch
|
||||||
|
cd "$DIR"
|
||||||
|
docker compose down --remove-orphans
|
||||||
|
docker compose up -d --remove-orphans
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[A] Container Status"
|
||||||
|
docker ps --format 'NAME={{.Names}} STATUS={{.Status}} PORTS={{.Ports}}' | egrep 'hxki-|hx-caddy' || true
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[B] Netzwerk-Mitglieder ($NET)"
|
||||||
|
docker network inspect "$NET" --format '{{range $id,$c := .Containers}}{{println $c.Name}}{{end}}' | sort
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[C] Caddy -> Service Reachability (intern)"
|
||||||
|
docker exec -it hx-caddy sh -lc 'wget -qO- http://hxki-web/ >/dev/null && echo OK_CADDY_TO_WEB || echo FAIL_CADDY_TO_WEB'
|
||||||
|
docker exec -it hx-caddy sh -lc 'wget -qO- http://hxki-n8n:5678/ >/dev/null && echo OK_CADDY_TO_N8N || echo FAIL_CADDY_TO_N8N'
|
||||||
|
docker exec -it hx-caddy sh -lc 'wget -qO- http://hxki-mautic/ >/dev/null && echo OK_CADDY_TO_MAUTIC || echo FAIL_CADDY_TO_MAUTIC'
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "[D] n8n Logs (letzte 40)"
|
||||||
|
docker logs --tail=40 hxki-n8n || true
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "=== ENDE ==="
|
||||||
131
agent/hxki_agent.py
Executable file
131
agent/hxki_agent.py
Executable file
@@ -0,0 +1,131 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
from datetime import datetime
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
TS = datetime.utcnow().strftime("%Y%m%d-%H%M%S")
|
||||||
|
|
||||||
|
BASE_DIR = Path("/opt/hx-ki")
|
||||||
|
INVENTORY_DIR = BASE_DIR / "inventory"
|
||||||
|
INVENTORY_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# .env laden (HXKI_NODE_NAME etc.)
|
||||||
|
ENV_FILE = BASE_DIR / "env" / ".env"
|
||||||
|
if ENV_FILE.exists():
|
||||||
|
for line in ENV_FILE.read_text().splitlines():
|
||||||
|
line = line.strip()
|
||||||
|
if not line or line.startswith("#") or "=" not in line:
|
||||||
|
continue
|
||||||
|
k, v = line.split("=", 1)
|
||||||
|
os.environ.setdefault(k.strip(), v.strip())
|
||||||
|
|
||||||
|
HOST = subprocess.getoutput("hostname")
|
||||||
|
NODE = os.environ.get("HXKI_NODE_NAME", "")
|
||||||
|
|
||||||
|
def run(cmd: str) -> str:
|
||||||
|
try:
|
||||||
|
out = subprocess.check_output(
|
||||||
|
cmd, shell=True, stderr=subprocess.DEVNULL, text=True
|
||||||
|
)
|
||||||
|
return out.strip()
|
||||||
|
except Exception:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def bytes_to_mb(b: int) -> float:
|
||||||
|
return round(b / 1024 / 1024, 2)
|
||||||
|
|
||||||
|
def workspace_info():
|
||||||
|
ws_path = Path(os.environ.get("HXKI_WORKSPACE", "/data/HXKI_WORKSPACE"))
|
||||||
|
info = {"path": str(ws_path), "exists": ws_path.exists()}
|
||||||
|
if ws_path.exists():
|
||||||
|
total_size = 0
|
||||||
|
count = 0
|
||||||
|
for root, dirs, files in os.walk(ws_path):
|
||||||
|
for name in files:
|
||||||
|
try:
|
||||||
|
p = Path(root) / name
|
||||||
|
total_size += p.stat().st_size
|
||||||
|
count += 1
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
info["file_count"] = count
|
||||||
|
info["total_bytes"] = total_size
|
||||||
|
info["total_mb"] = bytes_to_mb(total_size)
|
||||||
|
return info
|
||||||
|
|
||||||
|
def telemetry_info():
|
||||||
|
tel_path = Path(os.environ.get("HXKI_TELEMETRY_LOG", "/opt/hx-ki/logs/autoindexer_events.log"))
|
||||||
|
info = {"path": str(tel_path), "exists": tel_path.exists()}
|
||||||
|
if tel_path.exists():
|
||||||
|
try:
|
||||||
|
sz = tel_path.stat().st_size
|
||||||
|
info["size_bytes"] = sz
|
||||||
|
info["size_mb"] = bytes_to_mb(sz)
|
||||||
|
info["tail_10"] = run(f"tail -n 10 {tel_path}")
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return info
|
||||||
|
|
||||||
|
summary = {
|
||||||
|
"timestamp_utc": TS,
|
||||||
|
"host": HOST,
|
||||||
|
"node_name": NODE,
|
||||||
|
"sections": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
summary["sections"]["system"] = {
|
||||||
|
"hostnamectl": run("hostnamectl || echo ''"),
|
||||||
|
"cpu": run("lscpu || echo ''"),
|
||||||
|
"memory": run("free -h || echo ''"),
|
||||||
|
"disk_root": run("df -h / || echo ''"),
|
||||||
|
}
|
||||||
|
|
||||||
|
summary["sections"]["workspace"] = workspace_info()
|
||||||
|
summary["sections"]["telemetry"] = telemetry_info()
|
||||||
|
summary["sections"]["docker"] = {
|
||||||
|
"ps": run("docker ps || echo ''"),
|
||||||
|
"images": run("docker images || echo ''"),
|
||||||
|
}
|
||||||
|
|
||||||
|
hx_vars = {}
|
||||||
|
for k, v in os.environ.items():
|
||||||
|
if k.startswith("HXKI_") or k in ("CHROMA_HOST", "CHROMA_PORT", "POSTGRES_HOST", "POSTGRES_DB"):
|
||||||
|
hx_vars[k] = v
|
||||||
|
|
||||||
|
summary["sections"]["env"] = {
|
||||||
|
"env_file": str(ENV_FILE),
|
||||||
|
"present": ENV_FILE.exists(),
|
||||||
|
"hx_vars": hx_vars,
|
||||||
|
}
|
||||||
|
|
||||||
|
summary["sections"]["load"] = {"uptime": run("uptime || echo ''")}
|
||||||
|
summary["sections"]["disk_detail"] = {"df_all": run("df -h || echo ''")}
|
||||||
|
|
||||||
|
log_path = INVENTORY_DIR / f"hxki_agent_{TS}.log"
|
||||||
|
json_path = INVENTORY_DIR / f"hxki_agent_{TS}.json"
|
||||||
|
|
||||||
|
with log_path.open("w", encoding="utf-8") as f:
|
||||||
|
f.write("==== HX-KI AGENT INVENTAR ====\n")
|
||||||
|
f.write(f"Zeit (UTC): {TS}\n")
|
||||||
|
f.write(f"Host: {HOST}\n")
|
||||||
|
f.write(f"Node-Name: {NODE}\n")
|
||||||
|
f.write("====================================\n\n")
|
||||||
|
|
||||||
|
for section, data in summary["sections"].items():
|
||||||
|
f.write(f"---- {section.upper()} ----\n")
|
||||||
|
if isinstance(data, dict):
|
||||||
|
f.write(json.dumps(data, indent=2, ensure_ascii=False))
|
||||||
|
else:
|
||||||
|
f.write(str(data))
|
||||||
|
f.write("\n\n")
|
||||||
|
|
||||||
|
with json_path.open("w", encoding="utf-8") as jf:
|
||||||
|
json.dump(summary, jf, indent=2, ensure_ascii=False)
|
||||||
|
|
||||||
|
print("========================================================")
|
||||||
|
print("HX-KI AGENT – RUN COMPLETE")
|
||||||
|
print("Log: ", log_path)
|
||||||
|
print("JSON: ", json_path)
|
||||||
|
print("========================================================")
|
||||||
28
agents/json_homepage_agent.py
Executable file
28
agents/json_homepage_agent.py
Executable file
@@ -0,0 +1,28 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
WORKSPACE = "/opt/hx-ki/workspaces/homepage"
|
||||||
|
FILE = os.path.join(WORKSPACE, "homepage.json")
|
||||||
|
|
||||||
|
os.makedirs(WORKSPACE, exist_ok=True)
|
||||||
|
|
||||||
|
content = {
|
||||||
|
"hero_title": "HX-KI – Dynamischer JSON-Agent",
|
||||||
|
"hero_sub": "Content kommt aus dem Workspace auf Falkenstein – kein Zugriff auf Gehirn oder Motor.",
|
||||||
|
"sections": [
|
||||||
|
{
|
||||||
|
"title": "Agent-Status",
|
||||||
|
"text": "Dieser JSON-Agent kann von Events, Cron, KI oder Mautic getriggert werden."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Architektur-Sicherheit",
|
||||||
|
"text": "Falkenstein liest nur den Workspace. Nürnberg & Helsinki bleiben intern."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
with open(FILE, "w") as f:
|
||||||
|
json.dump(content, f, indent=2)
|
||||||
|
|
||||||
|
print(f"✔ homepage.json durch json_homepage_agent.py erzeugt/aktualisiert: {FILE}")
|
||||||
0
archive/git/.ssh/authorized_keys
Normal file
0
archive/git/.ssh/authorized_keys
Normal file
1
archive/git/.ssh/environment
Normal file
1
archive/git/.ssh/environment
Normal file
@@ -0,0 +1 @@
|
|||||||
|
GITEA_CUSTOM=/data/gitea
|
||||||
1
archive/git/repositories/harald/hx-ki.com.git/HEAD
Normal file
1
archive/git/repositories/harald/hx-ki.com.git/HEAD
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ref: refs/heads/main
|
||||||
4
archive/git/repositories/harald/hx-ki.com.git/config
Normal file
4
archive/git/repositories/harald/hx-ki.com.git/config
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[core]
|
||||||
|
repositoryformatversion = 0
|
||||||
|
filemode = true
|
||||||
|
bare = true
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Unnamed repository; edit this file 'description' to name the repository.
|
||||||
15
archive/git/repositories/harald/hx-ki.com.git/hooks/applypatch-msg.sample
Executable file
15
archive/git/repositories/harald/hx-ki.com.git/hooks/applypatch-msg.sample
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to check the commit log message taken by
|
||||||
|
# applypatch from an e-mail message.
|
||||||
|
#
|
||||||
|
# The hook should exit with non-zero status after issuing an
|
||||||
|
# appropriate message if it wants to stop the commit. The hook is
|
||||||
|
# allowed to edit the commit message file.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "applypatch-msg".
|
||||||
|
|
||||||
|
. git-sh-setup
|
||||||
|
commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
|
||||||
|
test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
|
||||||
|
:
|
||||||
24
archive/git/repositories/harald/hx-ki.com.git/hooks/commit-msg.sample
Executable file
24
archive/git/repositories/harald/hx-ki.com.git/hooks/commit-msg.sample
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to check the commit log message.
|
||||||
|
# Called by "git commit" with one argument, the name of the file
|
||||||
|
# that has the commit message. The hook should exit with non-zero
|
||||||
|
# status after issuing an appropriate message if it wants to stop the
|
||||||
|
# commit. The hook is allowed to edit the commit message file.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "commit-msg".
|
||||||
|
|
||||||
|
# Uncomment the below to add a Signed-off-by line to the message.
|
||||||
|
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
|
||||||
|
# hook is more suited to it.
|
||||||
|
#
|
||||||
|
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
||||||
|
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
|
||||||
|
|
||||||
|
# This example catches duplicate Signed-off-by lines.
|
||||||
|
|
||||||
|
test "" = "$(grep '^Signed-off-by: ' "$1" |
|
||||||
|
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
|
||||||
|
echo >&2 Duplicate Signed-off-by lines.
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
16
archive/git/repositories/harald/hx-ki.com.git/hooks/post-receive
Executable file
16
archive/git/repositories/harald/hx-ki.com.git/hooks/post-receive
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# AUTO GENERATED BY GITEA, DO NOT MODIFY
|
||||||
|
data=$(cat)
|
||||||
|
exitcodes=""
|
||||||
|
hookname=$(basename $0)
|
||||||
|
GIT_DIR=${GIT_DIR:-$(dirname $0)/..}
|
||||||
|
|
||||||
|
for hook in ${GIT_DIR}/hooks/${hookname}.d/*; do
|
||||||
|
test -x "${hook}" && test -f "${hook}" || continue
|
||||||
|
echo "${data}" | "${hook}"
|
||||||
|
exitcodes="${exitcodes} $?"
|
||||||
|
done
|
||||||
|
|
||||||
|
for i in ${exitcodes}; do
|
||||||
|
[ ${i} -eq 0 ] || exit ${i}
|
||||||
|
done
|
||||||
3
archive/git/repositories/harald/hx-ki.com.git/hooks/post-receive.d/gitea
Executable file
3
archive/git/repositories/harald/hx-ki.com.git/hooks/post-receive.d/gitea
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# AUTO GENERATED BY GITEA, DO NOT MODIFY
|
||||||
|
/usr/local/bin/gitea hook --config=/data/gitea/conf/app.ini post-receive
|
||||||
8
archive/git/repositories/harald/hx-ki.com.git/hooks/post-update.sample
Executable file
8
archive/git/repositories/harald/hx-ki.com.git/hooks/post-update.sample
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to prepare a packed repository for use over
|
||||||
|
# dumb transports.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "post-update".
|
||||||
|
|
||||||
|
exec git update-server-info
|
||||||
14
archive/git/repositories/harald/hx-ki.com.git/hooks/pre-applypatch.sample
Executable file
14
archive/git/repositories/harald/hx-ki.com.git/hooks/pre-applypatch.sample
Executable file
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to verify what is about to be committed
|
||||||
|
# by applypatch from an e-mail message.
|
||||||
|
#
|
||||||
|
# The hook should exit with non-zero status after issuing an
|
||||||
|
# appropriate message if it wants to stop the commit.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "pre-applypatch".
|
||||||
|
|
||||||
|
. git-sh-setup
|
||||||
|
precommit="$(git rev-parse --git-path hooks/pre-commit)"
|
||||||
|
test -x "$precommit" && exec "$precommit" ${1+"$@"}
|
||||||
|
:
|
||||||
49
archive/git/repositories/harald/hx-ki.com.git/hooks/pre-commit.sample
Executable file
49
archive/git/repositories/harald/hx-ki.com.git/hooks/pre-commit.sample
Executable file
@@ -0,0 +1,49 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to verify what is about to be committed.
|
||||||
|
# Called by "git commit" with no arguments. The hook should
|
||||||
|
# exit with non-zero status after issuing an appropriate message if
|
||||||
|
# it wants to stop the commit.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "pre-commit".
|
||||||
|
|
||||||
|
if git rev-parse --verify HEAD >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
against=HEAD
|
||||||
|
else
|
||||||
|
# Initial commit: diff against an empty tree object
|
||||||
|
against=$(git hash-object -t tree /dev/null)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If you want to allow non-ASCII filenames set this variable to true.
|
||||||
|
allownonascii=$(git config --type=bool hooks.allownonascii)
|
||||||
|
|
||||||
|
# Redirect output to stderr.
|
||||||
|
exec 1>&2
|
||||||
|
|
||||||
|
# Cross platform projects tend to avoid non-ASCII filenames; prevent
|
||||||
|
# them from being added to the repository. We exploit the fact that the
|
||||||
|
# printable range starts at the space character and ends with tilde.
|
||||||
|
if [ "$allownonascii" != "true" ] &&
|
||||||
|
# Note that the use of brackets around a tr range is ok here, (it's
|
||||||
|
# even required, for portability to Solaris 10's /usr/bin/tr), since
|
||||||
|
# the square bracket bytes happen to fall in the designated range.
|
||||||
|
test $(git diff-index --cached --name-only --diff-filter=A -z $against |
|
||||||
|
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
|
||||||
|
then
|
||||||
|
cat <<\EOF
|
||||||
|
Error: Attempt to add a non-ASCII file name.
|
||||||
|
|
||||||
|
This can cause problems if you want to work with people on other platforms.
|
||||||
|
|
||||||
|
To be portable it is advisable to rename the file.
|
||||||
|
|
||||||
|
If you know what you are doing you can disable this check using:
|
||||||
|
|
||||||
|
git config hooks.allownonascii true
|
||||||
|
EOF
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If there are whitespace errors, print the offending file names and fail.
|
||||||
|
exec git diff-index --check --cached $against --
|
||||||
13
archive/git/repositories/harald/hx-ki.com.git/hooks/pre-merge-commit.sample
Executable file
13
archive/git/repositories/harald/hx-ki.com.git/hooks/pre-merge-commit.sample
Executable file
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to verify what is about to be committed.
|
||||||
|
# Called by "git merge" with no arguments. The hook should
|
||||||
|
# exit with non-zero status after issuing an appropriate message to
|
||||||
|
# stderr if it wants to stop the merge commit.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "pre-merge-commit".
|
||||||
|
|
||||||
|
. git-sh-setup
|
||||||
|
test -x "$GIT_DIR/hooks/pre-commit" &&
|
||||||
|
exec "$GIT_DIR/hooks/pre-commit"
|
||||||
|
:
|
||||||
53
archive/git/repositories/harald/hx-ki.com.git/hooks/pre-push.sample
Executable file
53
archive/git/repositories/harald/hx-ki.com.git/hooks/pre-push.sample
Executable file
@@ -0,0 +1,53 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# An example hook script to verify what is about to be pushed. Called by "git
|
||||||
|
# push" after it has checked the remote status, but before anything has been
|
||||||
|
# pushed. If this script exits with a non-zero status nothing will be pushed.
|
||||||
|
#
|
||||||
|
# This hook is called with the following parameters:
|
||||||
|
#
|
||||||
|
# $1 -- Name of the remote to which the push is being done
|
||||||
|
# $2 -- URL to which the push is being done
|
||||||
|
#
|
||||||
|
# If pushing without using a named remote those arguments will be equal.
|
||||||
|
#
|
||||||
|
# Information about the commits which are being pushed is supplied as lines to
|
||||||
|
# the standard input in the form:
|
||||||
|
#
|
||||||
|
# <local ref> <local oid> <remote ref> <remote oid>
|
||||||
|
#
|
||||||
|
# This sample shows how to prevent push of commits where the log message starts
|
||||||
|
# with "WIP" (work in progress).
|
||||||
|
|
||||||
|
remote="$1"
|
||||||
|
url="$2"
|
||||||
|
|
||||||
|
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
|
||||||
|
|
||||||
|
while read local_ref local_oid remote_ref remote_oid
|
||||||
|
do
|
||||||
|
if test "$local_oid" = "$zero"
|
||||||
|
then
|
||||||
|
# Handle delete
|
||||||
|
:
|
||||||
|
else
|
||||||
|
if test "$remote_oid" = "$zero"
|
||||||
|
then
|
||||||
|
# New branch, examine all commits
|
||||||
|
range="$local_oid"
|
||||||
|
else
|
||||||
|
# Update to existing branch, examine new commits
|
||||||
|
range="$remote_oid..$local_oid"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for WIP commit
|
||||||
|
commit=$(git rev-list -n 1 --grep '^WIP' "$range")
|
||||||
|
if test -n "$commit"
|
||||||
|
then
|
||||||
|
echo >&2 "Found WIP commit in $local_ref, not pushing"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
exit 0
|
||||||
169
archive/git/repositories/harald/hx-ki.com.git/hooks/pre-rebase.sample
Executable file
169
archive/git/repositories/harald/hx-ki.com.git/hooks/pre-rebase.sample
Executable file
@@ -0,0 +1,169 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Copyright (c) 2006, 2008 Junio C Hamano
|
||||||
|
#
|
||||||
|
# The "pre-rebase" hook is run just before "git rebase" starts doing
|
||||||
|
# its job, and can prevent the command from running by exiting with
|
||||||
|
# non-zero status.
|
||||||
|
#
|
||||||
|
# The hook is called with the following parameters:
|
||||||
|
#
|
||||||
|
# $1 -- the upstream the series was forked from.
|
||||||
|
# $2 -- the branch being rebased (or empty when rebasing the current branch).
|
||||||
|
#
|
||||||
|
# This sample shows how to prevent topic branches that are already
|
||||||
|
# merged to 'next' branch from getting rebased, because allowing it
|
||||||
|
# would result in rebasing already published history.
|
||||||
|
|
||||||
|
publish=next
|
||||||
|
basebranch="$1"
|
||||||
|
if test "$#" = 2
|
||||||
|
then
|
||||||
|
topic="refs/heads/$2"
|
||||||
|
else
|
||||||
|
topic=`git symbolic-ref HEAD` ||
|
||||||
|
exit 0 ;# we do not interrupt rebasing detached HEAD
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$topic" in
|
||||||
|
refs/heads/??/*)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
exit 0 ;# we do not interrupt others.
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Now we are dealing with a topic branch being rebased
|
||||||
|
# on top of master. Is it OK to rebase it?
|
||||||
|
|
||||||
|
# Does the topic really exist?
|
||||||
|
git show-ref -q "$topic" || {
|
||||||
|
echo >&2 "No such branch $topic"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Is topic fully merged to master?
|
||||||
|
not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
|
||||||
|
if test -z "$not_in_master"
|
||||||
|
then
|
||||||
|
echo >&2 "$topic is fully merged to master; better remove it."
|
||||||
|
exit 1 ;# we could allow it, but there is no point.
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Is topic ever merged to next? If so you should not be rebasing it.
|
||||||
|
only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
|
||||||
|
only_next_2=`git rev-list ^master ${publish} | sort`
|
||||||
|
if test "$only_next_1" = "$only_next_2"
|
||||||
|
then
|
||||||
|
not_in_topic=`git rev-list "^$topic" master`
|
||||||
|
if test -z "$not_in_topic"
|
||||||
|
then
|
||||||
|
echo >&2 "$topic is already up to date with master"
|
||||||
|
exit 1 ;# we could allow it, but there is no point.
|
||||||
|
else
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
|
||||||
|
/usr/bin/perl -e '
|
||||||
|
my $topic = $ARGV[0];
|
||||||
|
my $msg = "* $topic has commits already merged to public branch:\n";
|
||||||
|
my (%not_in_next) = map {
|
||||||
|
/^([0-9a-f]+) /;
|
||||||
|
($1 => 1);
|
||||||
|
} split(/\n/, $ARGV[1]);
|
||||||
|
for my $elem (map {
|
||||||
|
/^([0-9a-f]+) (.*)$/;
|
||||||
|
[$1 => $2];
|
||||||
|
} split(/\n/, $ARGV[2])) {
|
||||||
|
if (!exists $not_in_next{$elem->[0]}) {
|
||||||
|
if ($msg) {
|
||||||
|
print STDERR $msg;
|
||||||
|
undef $msg;
|
||||||
|
}
|
||||||
|
print STDERR " $elem->[1]\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
' "$topic" "$not_in_next" "$not_in_master"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
<<\DOC_END
|
||||||
|
|
||||||
|
This sample hook safeguards topic branches that have been
|
||||||
|
published from being rewound.
|
||||||
|
|
||||||
|
The workflow assumed here is:
|
||||||
|
|
||||||
|
* Once a topic branch forks from "master", "master" is never
|
||||||
|
merged into it again (either directly or indirectly).
|
||||||
|
|
||||||
|
* Once a topic branch is fully cooked and merged into "master",
|
||||||
|
it is deleted. If you need to build on top of it to correct
|
||||||
|
earlier mistakes, a new topic branch is created by forking at
|
||||||
|
the tip of the "master". This is not strictly necessary, but
|
||||||
|
it makes it easier to keep your history simple.
|
||||||
|
|
||||||
|
* Whenever you need to test or publish your changes to topic
|
||||||
|
branches, merge them into "next" branch.
|
||||||
|
|
||||||
|
The script, being an example, hardcodes the publish branch name
|
||||||
|
to be "next", but it is trivial to make it configurable via
|
||||||
|
$GIT_DIR/config mechanism.
|
||||||
|
|
||||||
|
With this workflow, you would want to know:
|
||||||
|
|
||||||
|
(1) ... if a topic branch has ever been merged to "next". Young
|
||||||
|
topic branches can have stupid mistakes you would rather
|
||||||
|
clean up before publishing, and things that have not been
|
||||||
|
merged into other branches can be easily rebased without
|
||||||
|
affecting other people. But once it is published, you would
|
||||||
|
not want to rewind it.
|
||||||
|
|
||||||
|
(2) ... if a topic branch has been fully merged to "master".
|
||||||
|
Then you can delete it. More importantly, you should not
|
||||||
|
build on top of it -- other people may already want to
|
||||||
|
change things related to the topic as patches against your
|
||||||
|
"master", so if you need further changes, it is better to
|
||||||
|
fork the topic (perhaps with the same name) afresh from the
|
||||||
|
tip of "master".
|
||||||
|
|
||||||
|
Let's look at this example:
|
||||||
|
|
||||||
|
o---o---o---o---o---o---o---o---o---o "next"
|
||||||
|
/ / / /
|
||||||
|
/ a---a---b A / /
|
||||||
|
/ / / /
|
||||||
|
/ / c---c---c---c B /
|
||||||
|
/ / / \ /
|
||||||
|
/ / / b---b C \ /
|
||||||
|
/ / / / \ /
|
||||||
|
---o---o---o---o---o---o---o---o---o---o---o "master"
|
||||||
|
|
||||||
|
|
||||||
|
A, B and C are topic branches.
|
||||||
|
|
||||||
|
* A has one fix since it was merged up to "next".
|
||||||
|
|
||||||
|
* B has finished. It has been fully merged up to "master" and "next",
|
||||||
|
and is ready to be deleted.
|
||||||
|
|
||||||
|
* C has not merged to "next" at all.
|
||||||
|
|
||||||
|
We would want to allow C to be rebased, refuse A, and encourage
|
||||||
|
B to be deleted.
|
||||||
|
|
||||||
|
To compute (1):
|
||||||
|
|
||||||
|
git rev-list ^master ^topic next
|
||||||
|
git rev-list ^master next
|
||||||
|
|
||||||
|
if these match, topic has not merged in next at all.
|
||||||
|
|
||||||
|
To compute (2):
|
||||||
|
|
||||||
|
git rev-list master..topic
|
||||||
|
|
||||||
|
if this is empty, it is fully merged to "master".
|
||||||
|
|
||||||
|
DOC_END
|
||||||
16
archive/git/repositories/harald/hx-ki.com.git/hooks/pre-receive
Executable file
16
archive/git/repositories/harald/hx-ki.com.git/hooks/pre-receive
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# AUTO GENERATED BY GITEA, DO NOT MODIFY
|
||||||
|
data=$(cat)
|
||||||
|
exitcodes=""
|
||||||
|
hookname=$(basename $0)
|
||||||
|
GIT_DIR=${GIT_DIR:-$(dirname $0)/..}
|
||||||
|
|
||||||
|
for hook in ${GIT_DIR}/hooks/${hookname}.d/*; do
|
||||||
|
test -x "${hook}" && test -f "${hook}" || continue
|
||||||
|
echo "${data}" | "${hook}"
|
||||||
|
exitcodes="${exitcodes} $?"
|
||||||
|
done
|
||||||
|
|
||||||
|
for i in ${exitcodes}; do
|
||||||
|
[ ${i} -eq 0 ] || exit ${i}
|
||||||
|
done
|
||||||
3
archive/git/repositories/harald/hx-ki.com.git/hooks/pre-receive.d/gitea
Executable file
3
archive/git/repositories/harald/hx-ki.com.git/hooks/pre-receive.d/gitea
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# AUTO GENERATED BY GITEA, DO NOT MODIFY
|
||||||
|
/usr/local/bin/gitea hook --config=/data/gitea/conf/app.ini pre-receive
|
||||||
24
archive/git/repositories/harald/hx-ki.com.git/hooks/pre-receive.sample
Executable file
24
archive/git/repositories/harald/hx-ki.com.git/hooks/pre-receive.sample
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to make use of push options.
|
||||||
|
# The example simply echoes all push options that start with 'echoback='
|
||||||
|
# and rejects all pushes when the "reject" push option is used.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "pre-receive".
|
||||||
|
|
||||||
|
if test -n "$GIT_PUSH_OPTION_COUNT"
|
||||||
|
then
|
||||||
|
i=0
|
||||||
|
while test "$i" -lt "$GIT_PUSH_OPTION_COUNT"
|
||||||
|
do
|
||||||
|
eval "value=\$GIT_PUSH_OPTION_$i"
|
||||||
|
case "$value" in
|
||||||
|
echoback=*)
|
||||||
|
echo "echo from the pre-receive-hook: ${value#*=}" >&2
|
||||||
|
;;
|
||||||
|
reject)
|
||||||
|
exit 1
|
||||||
|
esac
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
fi
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to prepare the commit log message.
|
||||||
|
# Called by "git commit" with the name of the file that has the
|
||||||
|
# commit message, followed by the description of the commit
|
||||||
|
# message's source. The hook's purpose is to edit the commit
|
||||||
|
# message file. If the hook fails with a non-zero status,
|
||||||
|
# the commit is aborted.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "prepare-commit-msg".
|
||||||
|
|
||||||
|
# This hook includes three examples. The first one removes the
|
||||||
|
# "# Please enter the commit message..." help message.
|
||||||
|
#
|
||||||
|
# The second includes the output of "git diff --name-status -r"
|
||||||
|
# into the message, just before the "git status" output. It is
|
||||||
|
# commented because it doesn't cope with --amend or with squashed
|
||||||
|
# commits.
|
||||||
|
#
|
||||||
|
# The third example adds a Signed-off-by line to the message, that can
|
||||||
|
# still be edited. This is rarely a good idea.
|
||||||
|
|
||||||
|
COMMIT_MSG_FILE=$1
|
||||||
|
COMMIT_SOURCE=$2
|
||||||
|
SHA1=$3
|
||||||
|
|
||||||
|
/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE"
|
||||||
|
|
||||||
|
# case "$COMMIT_SOURCE,$SHA1" in
|
||||||
|
# ,|template,)
|
||||||
|
# /usr/bin/perl -i.bak -pe '
|
||||||
|
# print "\n" . `git diff --cached --name-status -r`
|
||||||
|
# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;;
|
||||||
|
# *) ;;
|
||||||
|
# esac
|
||||||
|
|
||||||
|
# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
||||||
|
# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE"
|
||||||
|
# if test -z "$COMMIT_SOURCE"
|
||||||
|
# then
|
||||||
|
# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE"
|
||||||
|
# fi
|
||||||
3
archive/git/repositories/harald/hx-ki.com.git/hooks/proc-receive
Executable file
3
archive/git/repositories/harald/hx-ki.com.git/hooks/proc-receive
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# AUTO GENERATED BY GITEA, DO NOT MODIFY
|
||||||
|
/usr/local/bin/gitea hook --config=/data/gitea/conf/app.ini proc-receive
|
||||||
0
archive/git/repositories/harald/hx-ki.com.git/hooks/proc-receive.d/gitea
Executable file
0
archive/git/repositories/harald/hx-ki.com.git/hooks/proc-receive.d/gitea
Executable file
78
archive/git/repositories/harald/hx-ki.com.git/hooks/push-to-checkout.sample
Executable file
78
archive/git/repositories/harald/hx-ki.com.git/hooks/push-to-checkout.sample
Executable file
@@ -0,0 +1,78 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# An example hook script to update a checked-out tree on a git push.
|
||||||
|
#
|
||||||
|
# This hook is invoked by git-receive-pack(1) when it reacts to git
|
||||||
|
# push and updates reference(s) in its repository, and when the push
|
||||||
|
# tries to update the branch that is currently checked out and the
|
||||||
|
# receive.denyCurrentBranch configuration variable is set to
|
||||||
|
# updateInstead.
|
||||||
|
#
|
||||||
|
# By default, such a push is refused if the working tree and the index
|
||||||
|
# of the remote repository has any difference from the currently
|
||||||
|
# checked out commit; when both the working tree and the index match
|
||||||
|
# the current commit, they are updated to match the newly pushed tip
|
||||||
|
# of the branch. This hook is to be used to override the default
|
||||||
|
# behaviour; however the code below reimplements the default behaviour
|
||||||
|
# as a starting point for convenient modification.
|
||||||
|
#
|
||||||
|
# The hook receives the commit with which the tip of the current
|
||||||
|
# branch is going to be updated:
|
||||||
|
commit=$1
|
||||||
|
|
||||||
|
# It can exit with a non-zero status to refuse the push (when it does
|
||||||
|
# so, it must not modify the index or the working tree).
|
||||||
|
die () {
|
||||||
|
echo >&2 "$*"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Or it can make any necessary changes to the working tree and to the
|
||||||
|
# index to bring them to the desired state when the tip of the current
|
||||||
|
# branch is updated to the new commit, and exit with a zero status.
|
||||||
|
#
|
||||||
|
# For example, the hook can simply run git read-tree -u -m HEAD "$1"
|
||||||
|
# in order to emulate git fetch that is run in the reverse direction
|
||||||
|
# with git push, as the two-tree form of git read-tree -u -m is
|
||||||
|
# essentially the same as git switch or git checkout that switches
|
||||||
|
# branches while keeping the local changes in the working tree that do
|
||||||
|
# not interfere with the difference between the branches.
|
||||||
|
|
||||||
|
# The below is a more-or-less exact translation to shell of the C code
|
||||||
|
# for the default behaviour for git's push-to-checkout hook defined in
|
||||||
|
# the push_to_deploy() function in builtin/receive-pack.c.
|
||||||
|
#
|
||||||
|
# Note that the hook will be executed from the repository directory,
|
||||||
|
# not from the working tree, so if you want to perform operations on
|
||||||
|
# the working tree, you will have to adapt your code accordingly, e.g.
|
||||||
|
# by adding "cd .." or using relative paths.
|
||||||
|
|
||||||
|
if ! git update-index -q --ignore-submodules --refresh
|
||||||
|
then
|
||||||
|
die "Up-to-date check failed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! git diff-files --quiet --ignore-submodules --
|
||||||
|
then
|
||||||
|
die "Working directory has unstaged changes"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# This is a rough translation of:
|
||||||
|
#
|
||||||
|
# head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX
|
||||||
|
if git cat-file -e HEAD 2>/dev/null
|
||||||
|
then
|
||||||
|
head=HEAD
|
||||||
|
else
|
||||||
|
head=$(git hash-object -t tree --stdin </dev/null)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! git diff-index --quiet --cached --ignore-submodules $head --
|
||||||
|
then
|
||||||
|
die "Working directory has staged changes"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! git read-tree -u -m "$commit"
|
||||||
|
then
|
||||||
|
die "Could not update working tree to new HEAD"
|
||||||
|
fi
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# An example hook script to validate a patch (and/or patch series) before
|
||||||
|
# sending it via email.
|
||||||
|
#
|
||||||
|
# The hook should exit with non-zero status after issuing an appropriate
|
||||||
|
# message if it wants to prevent the email(s) from being sent.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "sendemail-validate".
|
||||||
|
#
|
||||||
|
# By default, it will only check that the patch(es) can be applied on top of
|
||||||
|
# the default upstream branch without conflicts in a secondary worktree. After
|
||||||
|
# validation (successful or not) of the last patch of a series, the worktree
|
||||||
|
# will be deleted.
|
||||||
|
#
|
||||||
|
# The following config variables can be set to change the default remote and
|
||||||
|
# remote ref that are used to apply the patches against:
|
||||||
|
#
|
||||||
|
# sendemail.validateRemote (default: origin)
|
||||||
|
# sendemail.validateRemoteRef (default: HEAD)
|
||||||
|
#
|
||||||
|
# Replace the TODO placeholders with appropriate checks according to your
|
||||||
|
# needs.
|
||||||
|
|
||||||
|
validate_cover_letter () {
|
||||||
|
file="$1"
|
||||||
|
# TODO: Replace with appropriate checks (e.g. spell checking).
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_patch () {
|
||||||
|
file="$1"
|
||||||
|
# Ensure that the patch applies without conflicts.
|
||||||
|
git am -3 "$file" || return
|
||||||
|
# TODO: Replace with appropriate checks for this patch
|
||||||
|
# (e.g. checkpatch.pl).
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_series () {
|
||||||
|
# TODO: Replace with appropriate checks for the whole series
|
||||||
|
# (e.g. quick build, coding style checks, etc.).
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
# main -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
if test "$GIT_SENDEMAIL_FILE_COUNTER" = 1
|
||||||
|
then
|
||||||
|
remote=$(git config --default origin --get sendemail.validateRemote) &&
|
||||||
|
ref=$(git config --default HEAD --get sendemail.validateRemoteRef) &&
|
||||||
|
worktree=$(mktemp --tmpdir -d sendemail-validate.XXXXXXX) &&
|
||||||
|
git worktree add -fd --checkout "$worktree" "refs/remotes/$remote/$ref" &&
|
||||||
|
git config --replace-all sendemail.validateWorktree "$worktree"
|
||||||
|
else
|
||||||
|
worktree=$(git config --get sendemail.validateWorktree)
|
||||||
|
fi || {
|
||||||
|
echo "sendemail-validate: error: failed to prepare worktree" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
unset GIT_DIR GIT_WORK_TREE
|
||||||
|
cd "$worktree" &&
|
||||||
|
|
||||||
|
if grep -q "^diff --git " "$1"
|
||||||
|
then
|
||||||
|
validate_patch "$1"
|
||||||
|
else
|
||||||
|
validate_cover_letter "$1"
|
||||||
|
fi &&
|
||||||
|
|
||||||
|
if test "$GIT_SENDEMAIL_FILE_COUNTER" = "$GIT_SENDEMAIL_FILE_TOTAL"
|
||||||
|
then
|
||||||
|
git config --unset-all sendemail.validateWorktree &&
|
||||||
|
trap 'git worktree remove -ff "$worktree"' EXIT &&
|
||||||
|
validate_series
|
||||||
|
fi
|
||||||
15
archive/git/repositories/harald/hx-ki.com.git/hooks/update
Executable file
15
archive/git/repositories/harald/hx-ki.com.git/hooks/update
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# AUTO GENERATED BY GITEA, DO NOT MODIFY
|
||||||
|
exitcodes=""
|
||||||
|
hookname=$(basename $0)
|
||||||
|
GIT_DIR=${GIT_DIR:-$(dirname $0/..)}
|
||||||
|
|
||||||
|
for hook in ${GIT_DIR}/hooks/${hookname}.d/*; do
|
||||||
|
test -x "${hook}" && test -f "${hook}" || continue
|
||||||
|
"${hook}" $1 $2 $3
|
||||||
|
exitcodes="${exitcodes} $?"
|
||||||
|
done
|
||||||
|
|
||||||
|
for i in ${exitcodes}; do
|
||||||
|
[ ${i} -eq 0 ] || exit ${i}
|
||||||
|
done
|
||||||
3
archive/git/repositories/harald/hx-ki.com.git/hooks/update.d/gitea
Executable file
3
archive/git/repositories/harald/hx-ki.com.git/hooks/update.d/gitea
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# AUTO GENERATED BY GITEA, DO NOT MODIFY
|
||||||
|
/usr/local/bin/gitea hook --config=/data/gitea/conf/app.ini update $1 $2 $3
|
||||||
128
archive/git/repositories/harald/hx-ki.com.git/hooks/update.sample
Executable file
128
archive/git/repositories/harald/hx-ki.com.git/hooks/update.sample
Executable file
@@ -0,0 +1,128 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to block unannotated tags from entering.
|
||||||
|
# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "update".
|
||||||
|
#
|
||||||
|
# Config
|
||||||
|
# ------
|
||||||
|
# hooks.allowunannotated
|
||||||
|
# This boolean sets whether unannotated tags will be allowed into the
|
||||||
|
# repository. By default they won't be.
|
||||||
|
# hooks.allowdeletetag
|
||||||
|
# This boolean sets whether deleting tags will be allowed in the
|
||||||
|
# repository. By default they won't be.
|
||||||
|
# hooks.allowmodifytag
|
||||||
|
# This boolean sets whether a tag may be modified after creation. By default
|
||||||
|
# it won't be.
|
||||||
|
# hooks.allowdeletebranch
|
||||||
|
# This boolean sets whether deleting branches will be allowed in the
|
||||||
|
# repository. By default they won't be.
|
||||||
|
# hooks.denycreatebranch
|
||||||
|
# This boolean sets whether remotely creating branches will be denied
|
||||||
|
# in the repository. By default this is allowed.
|
||||||
|
#
|
||||||
|
|
||||||
|
# --- Command line
|
||||||
|
refname="$1"
|
||||||
|
oldrev="$2"
|
||||||
|
newrev="$3"
|
||||||
|
|
||||||
|
# --- Safety check
|
||||||
|
if [ -z "$GIT_DIR" ]; then
|
||||||
|
echo "Don't run this script from the command line." >&2
|
||||||
|
echo " (if you want, you could supply GIT_DIR then run" >&2
|
||||||
|
echo " $0 <ref> <oldrev> <newrev>)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
|
||||||
|
echo "usage: $0 <ref> <oldrev> <newrev>" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Config
|
||||||
|
allowunannotated=$(git config --type=bool hooks.allowunannotated)
|
||||||
|
allowdeletebranch=$(git config --type=bool hooks.allowdeletebranch)
|
||||||
|
denycreatebranch=$(git config --type=bool hooks.denycreatebranch)
|
||||||
|
allowdeletetag=$(git config --type=bool hooks.allowdeletetag)
|
||||||
|
allowmodifytag=$(git config --type=bool hooks.allowmodifytag)
|
||||||
|
|
||||||
|
# check for no description
|
||||||
|
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
|
||||||
|
case "$projectdesc" in
|
||||||
|
"Unnamed repository"* | "")
|
||||||
|
echo "*** Project description file hasn't been set" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# --- Check types
|
||||||
|
# if $newrev is 0000...0000, it's a commit to delete a ref.
|
||||||
|
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
|
||||||
|
if [ "$newrev" = "$zero" ]; then
|
||||||
|
newrev_type=delete
|
||||||
|
else
|
||||||
|
newrev_type=$(git cat-file -t $newrev)
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$refname","$newrev_type" in
|
||||||
|
refs/tags/*,commit)
|
||||||
|
# un-annotated tag
|
||||||
|
short_refname=${refname##refs/tags/}
|
||||||
|
if [ "$allowunannotated" != "true" ]; then
|
||||||
|
echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
|
||||||
|
echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
refs/tags/*,delete)
|
||||||
|
# delete tag
|
||||||
|
if [ "$allowdeletetag" != "true" ]; then
|
||||||
|
echo "*** Deleting a tag is not allowed in this repository" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
refs/tags/*,tag)
|
||||||
|
# annotated tag
|
||||||
|
if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
|
||||||
|
then
|
||||||
|
echo "*** Tag '$refname' already exists." >&2
|
||||||
|
echo "*** Modifying a tag is not allowed in this repository." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
refs/heads/*,commit)
|
||||||
|
# branch
|
||||||
|
if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
|
||||||
|
echo "*** Creating a branch is not allowed in this repository" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
refs/heads/*,delete)
|
||||||
|
# delete branch
|
||||||
|
if [ "$allowdeletebranch" != "true" ]; then
|
||||||
|
echo "*** Deleting a branch is not allowed in this repository" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
refs/remotes/*,commit)
|
||||||
|
# tracking branch
|
||||||
|
;;
|
||||||
|
refs/remotes/*,delete)
|
||||||
|
# delete tracking branch
|
||||||
|
if [ "$allowdeletebranch" != "true" ]; then
|
||||||
|
echo "*** Deleting a tracking branch is not allowed in this repository" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# Anything else (is there anything else?)
|
||||||
|
echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# --- Finished
|
||||||
|
exit 0
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# git ls-files --others --exclude-from=.git/info/exclude
|
||||||
|
# Lines that start with '#' are comments.
|
||||||
|
# For a project mostly in C, the following would be a good set of
|
||||||
|
# exclude patterns (uncomment them if you want to use them):
|
||||||
|
# *.[oa]
|
||||||
|
# *~
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
archive/git/repositories/harald/hxki-engine.git/HEAD
Normal file
1
archive/git/repositories/harald/hxki-engine.git/HEAD
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ref: refs/heads/main
|
||||||
4
archive/git/repositories/harald/hxki-engine.git/config
Normal file
4
archive/git/repositories/harald/hxki-engine.git/config
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[core]
|
||||||
|
repositoryformatversion = 0
|
||||||
|
filemode = true
|
||||||
|
bare = true
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Unnamed repository; edit this file 'description' to name the repository.
|
||||||
15
archive/git/repositories/harald/hxki-engine.git/hooks/applypatch-msg.sample
Executable file
15
archive/git/repositories/harald/hxki-engine.git/hooks/applypatch-msg.sample
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to check the commit log message taken by
|
||||||
|
# applypatch from an e-mail message.
|
||||||
|
#
|
||||||
|
# The hook should exit with non-zero status after issuing an
|
||||||
|
# appropriate message if it wants to stop the commit. The hook is
|
||||||
|
# allowed to edit the commit message file.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "applypatch-msg".
|
||||||
|
|
||||||
|
. git-sh-setup
|
||||||
|
commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
|
||||||
|
test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
|
||||||
|
:
|
||||||
24
archive/git/repositories/harald/hxki-engine.git/hooks/commit-msg.sample
Executable file
24
archive/git/repositories/harald/hxki-engine.git/hooks/commit-msg.sample
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to check the commit log message.
|
||||||
|
# Called by "git commit" with one argument, the name of the file
|
||||||
|
# that has the commit message. The hook should exit with non-zero
|
||||||
|
# status after issuing an appropriate message if it wants to stop the
|
||||||
|
# commit. The hook is allowed to edit the commit message file.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "commit-msg".
|
||||||
|
|
||||||
|
# Uncomment the below to add a Signed-off-by line to the message.
|
||||||
|
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
|
||||||
|
# hook is more suited to it.
|
||||||
|
#
|
||||||
|
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
||||||
|
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
|
||||||
|
|
||||||
|
# This example catches duplicate Signed-off-by lines.
|
||||||
|
|
||||||
|
test "" = "$(grep '^Signed-off-by: ' "$1" |
|
||||||
|
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
|
||||||
|
echo >&2 Duplicate Signed-off-by lines.
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
16
archive/git/repositories/harald/hxki-engine.git/hooks/post-receive
Executable file
16
archive/git/repositories/harald/hxki-engine.git/hooks/post-receive
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# AUTO GENERATED BY GITEA, DO NOT MODIFY
|
||||||
|
data=$(cat)
|
||||||
|
exitcodes=""
|
||||||
|
hookname=$(basename $0)
|
||||||
|
GIT_DIR=${GIT_DIR:-$(dirname $0)/..}
|
||||||
|
|
||||||
|
for hook in ${GIT_DIR}/hooks/${hookname}.d/*; do
|
||||||
|
test -x "${hook}" && test -f "${hook}" || continue
|
||||||
|
echo "${data}" | "${hook}"
|
||||||
|
exitcodes="${exitcodes} $?"
|
||||||
|
done
|
||||||
|
|
||||||
|
for i in ${exitcodes}; do
|
||||||
|
[ ${i} -eq 0 ] || exit ${i}
|
||||||
|
done
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# AUTO GENERATED BY GITEA, DO NOT MODIFY
|
||||||
|
/usr/local/bin/gitea hook --config=/data/gitea/conf/app.ini post-receive
|
||||||
8
archive/git/repositories/harald/hxki-engine.git/hooks/post-update.sample
Executable file
8
archive/git/repositories/harald/hxki-engine.git/hooks/post-update.sample
Executable file
@@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to prepare a packed repository for use over
|
||||||
|
# dumb transports.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "post-update".
|
||||||
|
|
||||||
|
exec git update-server-info
|
||||||
14
archive/git/repositories/harald/hxki-engine.git/hooks/pre-applypatch.sample
Executable file
14
archive/git/repositories/harald/hxki-engine.git/hooks/pre-applypatch.sample
Executable file
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to verify what is about to be committed
|
||||||
|
# by applypatch from an e-mail message.
|
||||||
|
#
|
||||||
|
# The hook should exit with non-zero status after issuing an
|
||||||
|
# appropriate message if it wants to stop the commit.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "pre-applypatch".
|
||||||
|
|
||||||
|
. git-sh-setup
|
||||||
|
precommit="$(git rev-parse --git-path hooks/pre-commit)"
|
||||||
|
test -x "$precommit" && exec "$precommit" ${1+"$@"}
|
||||||
|
:
|
||||||
49
archive/git/repositories/harald/hxki-engine.git/hooks/pre-commit.sample
Executable file
49
archive/git/repositories/harald/hxki-engine.git/hooks/pre-commit.sample
Executable file
@@ -0,0 +1,49 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to verify what is about to be committed.
|
||||||
|
# Called by "git commit" with no arguments. The hook should
|
||||||
|
# exit with non-zero status after issuing an appropriate message if
|
||||||
|
# it wants to stop the commit.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "pre-commit".
|
||||||
|
|
||||||
|
if git rev-parse --verify HEAD >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
against=HEAD
|
||||||
|
else
|
||||||
|
# Initial commit: diff against an empty tree object
|
||||||
|
against=$(git hash-object -t tree /dev/null)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If you want to allow non-ASCII filenames set this variable to true.
|
||||||
|
allownonascii=$(git config --type=bool hooks.allownonascii)
|
||||||
|
|
||||||
|
# Redirect output to stderr.
|
||||||
|
exec 1>&2
|
||||||
|
|
||||||
|
# Cross platform projects tend to avoid non-ASCII filenames; prevent
|
||||||
|
# them from being added to the repository. We exploit the fact that the
|
||||||
|
# printable range starts at the space character and ends with tilde.
|
||||||
|
if [ "$allownonascii" != "true" ] &&
|
||||||
|
# Note that the use of brackets around a tr range is ok here, (it's
|
||||||
|
# even required, for portability to Solaris 10's /usr/bin/tr), since
|
||||||
|
# the square bracket bytes happen to fall in the designated range.
|
||||||
|
test $(git diff-index --cached --name-only --diff-filter=A -z $against |
|
||||||
|
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
|
||||||
|
then
|
||||||
|
cat <<\EOF
|
||||||
|
Error: Attempt to add a non-ASCII file name.
|
||||||
|
|
||||||
|
This can cause problems if you want to work with people on other platforms.
|
||||||
|
|
||||||
|
To be portable it is advisable to rename the file.
|
||||||
|
|
||||||
|
If you know what you are doing you can disable this check using:
|
||||||
|
|
||||||
|
git config hooks.allownonascii true
|
||||||
|
EOF
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If there are whitespace errors, print the offending file names and fail.
|
||||||
|
exec git diff-index --check --cached $against --
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to verify what is about to be committed.
|
||||||
|
# Called by "git merge" with no arguments. The hook should
|
||||||
|
# exit with non-zero status after issuing an appropriate message to
|
||||||
|
# stderr if it wants to stop the merge commit.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "pre-merge-commit".
|
||||||
|
|
||||||
|
. git-sh-setup
|
||||||
|
test -x "$GIT_DIR/hooks/pre-commit" &&
|
||||||
|
exec "$GIT_DIR/hooks/pre-commit"
|
||||||
|
:
|
||||||
53
archive/git/repositories/harald/hxki-engine.git/hooks/pre-push.sample
Executable file
53
archive/git/repositories/harald/hxki-engine.git/hooks/pre-push.sample
Executable file
@@ -0,0 +1,53 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# An example hook script to verify what is about to be pushed. Called by "git
|
||||||
|
# push" after it has checked the remote status, but before anything has been
|
||||||
|
# pushed. If this script exits with a non-zero status nothing will be pushed.
|
||||||
|
#
|
||||||
|
# This hook is called with the following parameters:
|
||||||
|
#
|
||||||
|
# $1 -- Name of the remote to which the push is being done
|
||||||
|
# $2 -- URL to which the push is being done
|
||||||
|
#
|
||||||
|
# If pushing without using a named remote those arguments will be equal.
|
||||||
|
#
|
||||||
|
# Information about the commits which are being pushed is supplied as lines to
|
||||||
|
# the standard input in the form:
|
||||||
|
#
|
||||||
|
# <local ref> <local oid> <remote ref> <remote oid>
|
||||||
|
#
|
||||||
|
# This sample shows how to prevent push of commits where the log message starts
|
||||||
|
# with "WIP" (work in progress).
|
||||||
|
|
||||||
|
remote="$1"
|
||||||
|
url="$2"
|
||||||
|
|
||||||
|
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
|
||||||
|
|
||||||
|
while read local_ref local_oid remote_ref remote_oid
|
||||||
|
do
|
||||||
|
if test "$local_oid" = "$zero"
|
||||||
|
then
|
||||||
|
# Handle delete
|
||||||
|
:
|
||||||
|
else
|
||||||
|
if test "$remote_oid" = "$zero"
|
||||||
|
then
|
||||||
|
# New branch, examine all commits
|
||||||
|
range="$local_oid"
|
||||||
|
else
|
||||||
|
# Update to existing branch, examine new commits
|
||||||
|
range="$remote_oid..$local_oid"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for WIP commit
|
||||||
|
commit=$(git rev-list -n 1 --grep '^WIP' "$range")
|
||||||
|
if test -n "$commit"
|
||||||
|
then
|
||||||
|
echo >&2 "Found WIP commit in $local_ref, not pushing"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
exit 0
|
||||||
169
archive/git/repositories/harald/hxki-engine.git/hooks/pre-rebase.sample
Executable file
169
archive/git/repositories/harald/hxki-engine.git/hooks/pre-rebase.sample
Executable file
@@ -0,0 +1,169 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Copyright (c) 2006, 2008 Junio C Hamano
|
||||||
|
#
|
||||||
|
# The "pre-rebase" hook is run just before "git rebase" starts doing
|
||||||
|
# its job, and can prevent the command from running by exiting with
|
||||||
|
# non-zero status.
|
||||||
|
#
|
||||||
|
# The hook is called with the following parameters:
|
||||||
|
#
|
||||||
|
# $1 -- the upstream the series was forked from.
|
||||||
|
# $2 -- the branch being rebased (or empty when rebasing the current branch).
|
||||||
|
#
|
||||||
|
# This sample shows how to prevent topic branches that are already
|
||||||
|
# merged to 'next' branch from getting rebased, because allowing it
|
||||||
|
# would result in rebasing already published history.
|
||||||
|
|
||||||
|
publish=next
|
||||||
|
basebranch="$1"
|
||||||
|
if test "$#" = 2
|
||||||
|
then
|
||||||
|
topic="refs/heads/$2"
|
||||||
|
else
|
||||||
|
topic=`git symbolic-ref HEAD` ||
|
||||||
|
exit 0 ;# we do not interrupt rebasing detached HEAD
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$topic" in
|
||||||
|
refs/heads/??/*)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
exit 0 ;# we do not interrupt others.
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Now we are dealing with a topic branch being rebased
|
||||||
|
# on top of master. Is it OK to rebase it?
|
||||||
|
|
||||||
|
# Does the topic really exist?
|
||||||
|
git show-ref -q "$topic" || {
|
||||||
|
echo >&2 "No such branch $topic"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Is topic fully merged to master?
|
||||||
|
not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
|
||||||
|
if test -z "$not_in_master"
|
||||||
|
then
|
||||||
|
echo >&2 "$topic is fully merged to master; better remove it."
|
||||||
|
exit 1 ;# we could allow it, but there is no point.
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Is topic ever merged to next? If so you should not be rebasing it.
|
||||||
|
only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
|
||||||
|
only_next_2=`git rev-list ^master ${publish} | sort`
|
||||||
|
if test "$only_next_1" = "$only_next_2"
|
||||||
|
then
|
||||||
|
not_in_topic=`git rev-list "^$topic" master`
|
||||||
|
if test -z "$not_in_topic"
|
||||||
|
then
|
||||||
|
echo >&2 "$topic is already up to date with master"
|
||||||
|
exit 1 ;# we could allow it, but there is no point.
|
||||||
|
else
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
|
||||||
|
/usr/bin/perl -e '
|
||||||
|
my $topic = $ARGV[0];
|
||||||
|
my $msg = "* $topic has commits already merged to public branch:\n";
|
||||||
|
my (%not_in_next) = map {
|
||||||
|
/^([0-9a-f]+) /;
|
||||||
|
($1 => 1);
|
||||||
|
} split(/\n/, $ARGV[1]);
|
||||||
|
for my $elem (map {
|
||||||
|
/^([0-9a-f]+) (.*)$/;
|
||||||
|
[$1 => $2];
|
||||||
|
} split(/\n/, $ARGV[2])) {
|
||||||
|
if (!exists $not_in_next{$elem->[0]}) {
|
||||||
|
if ($msg) {
|
||||||
|
print STDERR $msg;
|
||||||
|
undef $msg;
|
||||||
|
}
|
||||||
|
print STDERR " $elem->[1]\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
' "$topic" "$not_in_next" "$not_in_master"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
<<\DOC_END
|
||||||
|
|
||||||
|
This sample hook safeguards topic branches that have been
|
||||||
|
published from being rewound.
|
||||||
|
|
||||||
|
The workflow assumed here is:
|
||||||
|
|
||||||
|
* Once a topic branch forks from "master", "master" is never
|
||||||
|
merged into it again (either directly or indirectly).
|
||||||
|
|
||||||
|
* Once a topic branch is fully cooked and merged into "master",
|
||||||
|
it is deleted. If you need to build on top of it to correct
|
||||||
|
earlier mistakes, a new topic branch is created by forking at
|
||||||
|
the tip of the "master". This is not strictly necessary, but
|
||||||
|
it makes it easier to keep your history simple.
|
||||||
|
|
||||||
|
* Whenever you need to test or publish your changes to topic
|
||||||
|
branches, merge them into "next" branch.
|
||||||
|
|
||||||
|
The script, being an example, hardcodes the publish branch name
|
||||||
|
to be "next", but it is trivial to make it configurable via
|
||||||
|
$GIT_DIR/config mechanism.
|
||||||
|
|
||||||
|
With this workflow, you would want to know:
|
||||||
|
|
||||||
|
(1) ... if a topic branch has ever been merged to "next". Young
|
||||||
|
topic branches can have stupid mistakes you would rather
|
||||||
|
clean up before publishing, and things that have not been
|
||||||
|
merged into other branches can be easily rebased without
|
||||||
|
affecting other people. But once it is published, you would
|
||||||
|
not want to rewind it.
|
||||||
|
|
||||||
|
(2) ... if a topic branch has been fully merged to "master".
|
||||||
|
Then you can delete it. More importantly, you should not
|
||||||
|
build on top of it -- other people may already want to
|
||||||
|
change things related to the topic as patches against your
|
||||||
|
"master", so if you need further changes, it is better to
|
||||||
|
fork the topic (perhaps with the same name) afresh from the
|
||||||
|
tip of "master".
|
||||||
|
|
||||||
|
Let's look at this example:
|
||||||
|
|
||||||
|
o---o---o---o---o---o---o---o---o---o "next"
|
||||||
|
/ / / /
|
||||||
|
/ a---a---b A / /
|
||||||
|
/ / / /
|
||||||
|
/ / c---c---c---c B /
|
||||||
|
/ / / \ /
|
||||||
|
/ / / b---b C \ /
|
||||||
|
/ / / / \ /
|
||||||
|
---o---o---o---o---o---o---o---o---o---o---o "master"
|
||||||
|
|
||||||
|
|
||||||
|
A, B and C are topic branches.
|
||||||
|
|
||||||
|
* A has one fix since it was merged up to "next".
|
||||||
|
|
||||||
|
* B has finished. It has been fully merged up to "master" and "next",
|
||||||
|
and is ready to be deleted.
|
||||||
|
|
||||||
|
* C has not merged to "next" at all.
|
||||||
|
|
||||||
|
We would want to allow C to be rebased, refuse A, and encourage
|
||||||
|
B to be deleted.
|
||||||
|
|
||||||
|
To compute (1):
|
||||||
|
|
||||||
|
git rev-list ^master ^topic next
|
||||||
|
git rev-list ^master next
|
||||||
|
|
||||||
|
if these match, topic has not merged in next at all.
|
||||||
|
|
||||||
|
To compute (2):
|
||||||
|
|
||||||
|
git rev-list master..topic
|
||||||
|
|
||||||
|
if this is empty, it is fully merged to "master".
|
||||||
|
|
||||||
|
DOC_END
|
||||||
16
archive/git/repositories/harald/hxki-engine.git/hooks/pre-receive
Executable file
16
archive/git/repositories/harald/hxki-engine.git/hooks/pre-receive
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# AUTO GENERATED BY GITEA, DO NOT MODIFY
|
||||||
|
data=$(cat)
|
||||||
|
exitcodes=""
|
||||||
|
hookname=$(basename $0)
|
||||||
|
GIT_DIR=${GIT_DIR:-$(dirname $0)/..}
|
||||||
|
|
||||||
|
for hook in ${GIT_DIR}/hooks/${hookname}.d/*; do
|
||||||
|
test -x "${hook}" && test -f "${hook}" || continue
|
||||||
|
echo "${data}" | "${hook}"
|
||||||
|
exitcodes="${exitcodes} $?"
|
||||||
|
done
|
||||||
|
|
||||||
|
for i in ${exitcodes}; do
|
||||||
|
[ ${i} -eq 0 ] || exit ${i}
|
||||||
|
done
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# AUTO GENERATED BY GITEA, DO NOT MODIFY
|
||||||
|
/usr/local/bin/gitea hook --config=/data/gitea/conf/app.ini pre-receive
|
||||||
24
archive/git/repositories/harald/hxki-engine.git/hooks/pre-receive.sample
Executable file
24
archive/git/repositories/harald/hxki-engine.git/hooks/pre-receive.sample
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to make use of push options.
|
||||||
|
# The example simply echoes all push options that start with 'echoback='
|
||||||
|
# and rejects all pushes when the "reject" push option is used.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "pre-receive".
|
||||||
|
|
||||||
|
if test -n "$GIT_PUSH_OPTION_COUNT"
|
||||||
|
then
|
||||||
|
i=0
|
||||||
|
while test "$i" -lt "$GIT_PUSH_OPTION_COUNT"
|
||||||
|
do
|
||||||
|
eval "value=\$GIT_PUSH_OPTION_$i"
|
||||||
|
case "$value" in
|
||||||
|
echoback=*)
|
||||||
|
echo "echo from the pre-receive-hook: ${value#*=}" >&2
|
||||||
|
;;
|
||||||
|
reject)
|
||||||
|
exit 1
|
||||||
|
esac
|
||||||
|
i=$((i + 1))
|
||||||
|
done
|
||||||
|
fi
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to prepare the commit log message.
|
||||||
|
# Called by "git commit" with the name of the file that has the
|
||||||
|
# commit message, followed by the description of the commit
|
||||||
|
# message's source. The hook's purpose is to edit the commit
|
||||||
|
# message file. If the hook fails with a non-zero status,
|
||||||
|
# the commit is aborted.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "prepare-commit-msg".
|
||||||
|
|
||||||
|
# This hook includes three examples. The first one removes the
|
||||||
|
# "# Please enter the commit message..." help message.
|
||||||
|
#
|
||||||
|
# The second includes the output of "git diff --name-status -r"
|
||||||
|
# into the message, just before the "git status" output. It is
|
||||||
|
# commented because it doesn't cope with --amend or with squashed
|
||||||
|
# commits.
|
||||||
|
#
|
||||||
|
# The third example adds a Signed-off-by line to the message, that can
|
||||||
|
# still be edited. This is rarely a good idea.
|
||||||
|
|
||||||
|
COMMIT_MSG_FILE=$1
|
||||||
|
COMMIT_SOURCE=$2
|
||||||
|
SHA1=$3
|
||||||
|
|
||||||
|
/usr/bin/perl -i.bak -ne 'print unless(m/^. Please enter the commit message/..m/^#$/)' "$COMMIT_MSG_FILE"
|
||||||
|
|
||||||
|
# case "$COMMIT_SOURCE,$SHA1" in
|
||||||
|
# ,|template,)
|
||||||
|
# /usr/bin/perl -i.bak -pe '
|
||||||
|
# print "\n" . `git diff --cached --name-status -r`
|
||||||
|
# if /^#/ && $first++ == 0' "$COMMIT_MSG_FILE" ;;
|
||||||
|
# *) ;;
|
||||||
|
# esac
|
||||||
|
|
||||||
|
# SOB=$(git var GIT_COMMITTER_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
||||||
|
# git interpret-trailers --in-place --trailer "$SOB" "$COMMIT_MSG_FILE"
|
||||||
|
# if test -z "$COMMIT_SOURCE"
|
||||||
|
# then
|
||||||
|
# /usr/bin/perl -i.bak -pe 'print "\n" if !$first_line++' "$COMMIT_MSG_FILE"
|
||||||
|
# fi
|
||||||
3
archive/git/repositories/harald/hxki-engine.git/hooks/proc-receive
Executable file
3
archive/git/repositories/harald/hxki-engine.git/hooks/proc-receive
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# AUTO GENERATED BY GITEA, DO NOT MODIFY
|
||||||
|
/usr/local/bin/gitea hook --config=/data/gitea/conf/app.ini proc-receive
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# An example hook script to update a checked-out tree on a git push.
|
||||||
|
#
|
||||||
|
# This hook is invoked by git-receive-pack(1) when it reacts to git
|
||||||
|
# push and updates reference(s) in its repository, and when the push
|
||||||
|
# tries to update the branch that is currently checked out and the
|
||||||
|
# receive.denyCurrentBranch configuration variable is set to
|
||||||
|
# updateInstead.
|
||||||
|
#
|
||||||
|
# By default, such a push is refused if the working tree and the index
|
||||||
|
# of the remote repository has any difference from the currently
|
||||||
|
# checked out commit; when both the working tree and the index match
|
||||||
|
# the current commit, they are updated to match the newly pushed tip
|
||||||
|
# of the branch. This hook is to be used to override the default
|
||||||
|
# behaviour; however the code below reimplements the default behaviour
|
||||||
|
# as a starting point for convenient modification.
|
||||||
|
#
|
||||||
|
# The hook receives the commit with which the tip of the current
|
||||||
|
# branch is going to be updated:
|
||||||
|
commit=$1
|
||||||
|
|
||||||
|
# It can exit with a non-zero status to refuse the push (when it does
|
||||||
|
# so, it must not modify the index or the working tree).
|
||||||
|
die () {
|
||||||
|
echo >&2 "$*"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Or it can make any necessary changes to the working tree and to the
|
||||||
|
# index to bring them to the desired state when the tip of the current
|
||||||
|
# branch is updated to the new commit, and exit with a zero status.
|
||||||
|
#
|
||||||
|
# For example, the hook can simply run git read-tree -u -m HEAD "$1"
|
||||||
|
# in order to emulate git fetch that is run in the reverse direction
|
||||||
|
# with git push, as the two-tree form of git read-tree -u -m is
|
||||||
|
# essentially the same as git switch or git checkout that switches
|
||||||
|
# branches while keeping the local changes in the working tree that do
|
||||||
|
# not interfere with the difference between the branches.
|
||||||
|
|
||||||
|
# The below is a more-or-less exact translation to shell of the C code
|
||||||
|
# for the default behaviour for git's push-to-checkout hook defined in
|
||||||
|
# the push_to_deploy() function in builtin/receive-pack.c.
|
||||||
|
#
|
||||||
|
# Note that the hook will be executed from the repository directory,
|
||||||
|
# not from the working tree, so if you want to perform operations on
|
||||||
|
# the working tree, you will have to adapt your code accordingly, e.g.
|
||||||
|
# by adding "cd .." or using relative paths.
|
||||||
|
|
||||||
|
if ! git update-index -q --ignore-submodules --refresh
|
||||||
|
then
|
||||||
|
die "Up-to-date check failed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! git diff-files --quiet --ignore-submodules --
|
||||||
|
then
|
||||||
|
die "Working directory has unstaged changes"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# This is a rough translation of:
|
||||||
|
#
|
||||||
|
# head_has_history() ? "HEAD" : EMPTY_TREE_SHA1_HEX
|
||||||
|
if git cat-file -e HEAD 2>/dev/null
|
||||||
|
then
|
||||||
|
head=HEAD
|
||||||
|
else
|
||||||
|
head=$(git hash-object -t tree --stdin </dev/null)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! git diff-index --quiet --cached --ignore-submodules $head --
|
||||||
|
then
|
||||||
|
die "Working directory has staged changes"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! git read-tree -u -m "$commit"
|
||||||
|
then
|
||||||
|
die "Could not update working tree to new HEAD"
|
||||||
|
fi
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# An example hook script to validate a patch (and/or patch series) before
|
||||||
|
# sending it via email.
|
||||||
|
#
|
||||||
|
# The hook should exit with non-zero status after issuing an appropriate
|
||||||
|
# message if it wants to prevent the email(s) from being sent.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "sendemail-validate".
|
||||||
|
#
|
||||||
|
# By default, it will only check that the patch(es) can be applied on top of
|
||||||
|
# the default upstream branch without conflicts in a secondary worktree. After
|
||||||
|
# validation (successful or not) of the last patch of a series, the worktree
|
||||||
|
# will be deleted.
|
||||||
|
#
|
||||||
|
# The following config variables can be set to change the default remote and
|
||||||
|
# remote ref that are used to apply the patches against:
|
||||||
|
#
|
||||||
|
# sendemail.validateRemote (default: origin)
|
||||||
|
# sendemail.validateRemoteRef (default: HEAD)
|
||||||
|
#
|
||||||
|
# Replace the TODO placeholders with appropriate checks according to your
|
||||||
|
# needs.
|
||||||
|
|
||||||
|
validate_cover_letter () {
|
||||||
|
file="$1"
|
||||||
|
# TODO: Replace with appropriate checks (e.g. spell checking).
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_patch () {
|
||||||
|
file="$1"
|
||||||
|
# Ensure that the patch applies without conflicts.
|
||||||
|
git am -3 "$file" || return
|
||||||
|
# TODO: Replace with appropriate checks for this patch
|
||||||
|
# (e.g. checkpatch.pl).
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_series () {
|
||||||
|
# TODO: Replace with appropriate checks for the whole series
|
||||||
|
# (e.g. quick build, coding style checks, etc.).
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
# main -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
if test "$GIT_SENDEMAIL_FILE_COUNTER" = 1
|
||||||
|
then
|
||||||
|
remote=$(git config --default origin --get sendemail.validateRemote) &&
|
||||||
|
ref=$(git config --default HEAD --get sendemail.validateRemoteRef) &&
|
||||||
|
worktree=$(mktemp --tmpdir -d sendemail-validate.XXXXXXX) &&
|
||||||
|
git worktree add -fd --checkout "$worktree" "refs/remotes/$remote/$ref" &&
|
||||||
|
git config --replace-all sendemail.validateWorktree "$worktree"
|
||||||
|
else
|
||||||
|
worktree=$(git config --get sendemail.validateWorktree)
|
||||||
|
fi || {
|
||||||
|
echo "sendemail-validate: error: failed to prepare worktree" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
unset GIT_DIR GIT_WORK_TREE
|
||||||
|
cd "$worktree" &&
|
||||||
|
|
||||||
|
if grep -q "^diff --git " "$1"
|
||||||
|
then
|
||||||
|
validate_patch "$1"
|
||||||
|
else
|
||||||
|
validate_cover_letter "$1"
|
||||||
|
fi &&
|
||||||
|
|
||||||
|
if test "$GIT_SENDEMAIL_FILE_COUNTER" = "$GIT_SENDEMAIL_FILE_TOTAL"
|
||||||
|
then
|
||||||
|
git config --unset-all sendemail.validateWorktree &&
|
||||||
|
trap 'git worktree remove -ff "$worktree"' EXIT &&
|
||||||
|
validate_series
|
||||||
|
fi
|
||||||
15
archive/git/repositories/harald/hxki-engine.git/hooks/update
Executable file
15
archive/git/repositories/harald/hxki-engine.git/hooks/update
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# AUTO GENERATED BY GITEA, DO NOT MODIFY
|
||||||
|
exitcodes=""
|
||||||
|
hookname=$(basename $0)
|
||||||
|
GIT_DIR=${GIT_DIR:-$(dirname $0/..)}
|
||||||
|
|
||||||
|
for hook in ${GIT_DIR}/hooks/${hookname}.d/*; do
|
||||||
|
test -x "${hook}" && test -f "${hook}" || continue
|
||||||
|
"${hook}" $1 $2 $3
|
||||||
|
exitcodes="${exitcodes} $?"
|
||||||
|
done
|
||||||
|
|
||||||
|
for i in ${exitcodes}; do
|
||||||
|
[ ${i} -eq 0 ] || exit ${i}
|
||||||
|
done
|
||||||
3
archive/git/repositories/harald/hxki-engine.git/hooks/update.d/gitea
Executable file
3
archive/git/repositories/harald/hxki-engine.git/hooks/update.d/gitea
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# AUTO GENERATED BY GITEA, DO NOT MODIFY
|
||||||
|
/usr/local/bin/gitea hook --config=/data/gitea/conf/app.ini update $1 $2 $3
|
||||||
128
archive/git/repositories/harald/hxki-engine.git/hooks/update.sample
Executable file
128
archive/git/repositories/harald/hxki-engine.git/hooks/update.sample
Executable file
@@ -0,0 +1,128 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to block unannotated tags from entering.
|
||||||
|
# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "update".
|
||||||
|
#
|
||||||
|
# Config
|
||||||
|
# ------
|
||||||
|
# hooks.allowunannotated
|
||||||
|
# This boolean sets whether unannotated tags will be allowed into the
|
||||||
|
# repository. By default they won't be.
|
||||||
|
# hooks.allowdeletetag
|
||||||
|
# This boolean sets whether deleting tags will be allowed in the
|
||||||
|
# repository. By default they won't be.
|
||||||
|
# hooks.allowmodifytag
|
||||||
|
# This boolean sets whether a tag may be modified after creation. By default
|
||||||
|
# it won't be.
|
||||||
|
# hooks.allowdeletebranch
|
||||||
|
# This boolean sets whether deleting branches will be allowed in the
|
||||||
|
# repository. By default they won't be.
|
||||||
|
# hooks.denycreatebranch
|
||||||
|
# This boolean sets whether remotely creating branches will be denied
|
||||||
|
# in the repository. By default this is allowed.
|
||||||
|
#
|
||||||
|
|
||||||
|
# --- Command line
|
||||||
|
refname="$1"
|
||||||
|
oldrev="$2"
|
||||||
|
newrev="$3"
|
||||||
|
|
||||||
|
# --- Safety check
|
||||||
|
if [ -z "$GIT_DIR" ]; then
|
||||||
|
echo "Don't run this script from the command line." >&2
|
||||||
|
echo " (if you want, you could supply GIT_DIR then run" >&2
|
||||||
|
echo " $0 <ref> <oldrev> <newrev>)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
|
||||||
|
echo "usage: $0 <ref> <oldrev> <newrev>" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# --- Config
|
||||||
|
allowunannotated=$(git config --type=bool hooks.allowunannotated)
|
||||||
|
allowdeletebranch=$(git config --type=bool hooks.allowdeletebranch)
|
||||||
|
denycreatebranch=$(git config --type=bool hooks.denycreatebranch)
|
||||||
|
allowdeletetag=$(git config --type=bool hooks.allowdeletetag)
|
||||||
|
allowmodifytag=$(git config --type=bool hooks.allowmodifytag)
|
||||||
|
|
||||||
|
# check for no description
|
||||||
|
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
|
||||||
|
case "$projectdesc" in
|
||||||
|
"Unnamed repository"* | "")
|
||||||
|
echo "*** Project description file hasn't been set" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# --- Check types
|
||||||
|
# if $newrev is 0000...0000, it's a commit to delete a ref.
|
||||||
|
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
|
||||||
|
if [ "$newrev" = "$zero" ]; then
|
||||||
|
newrev_type=delete
|
||||||
|
else
|
||||||
|
newrev_type=$(git cat-file -t $newrev)
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$refname","$newrev_type" in
|
||||||
|
refs/tags/*,commit)
|
||||||
|
# un-annotated tag
|
||||||
|
short_refname=${refname##refs/tags/}
|
||||||
|
if [ "$allowunannotated" != "true" ]; then
|
||||||
|
echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
|
||||||
|
echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
refs/tags/*,delete)
|
||||||
|
# delete tag
|
||||||
|
if [ "$allowdeletetag" != "true" ]; then
|
||||||
|
echo "*** Deleting a tag is not allowed in this repository" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
refs/tags/*,tag)
|
||||||
|
# annotated tag
|
||||||
|
if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
|
||||||
|
then
|
||||||
|
echo "*** Tag '$refname' already exists." >&2
|
||||||
|
echo "*** Modifying a tag is not allowed in this repository." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
refs/heads/*,commit)
|
||||||
|
# branch
|
||||||
|
if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
|
||||||
|
echo "*** Creating a branch is not allowed in this repository" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
refs/heads/*,delete)
|
||||||
|
# delete branch
|
||||||
|
if [ "$allowdeletebranch" != "true" ]; then
|
||||||
|
echo "*** Deleting a branch is not allowed in this repository" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
refs/remotes/*,commit)
|
||||||
|
# tracking branch
|
||||||
|
;;
|
||||||
|
refs/remotes/*,delete)
|
||||||
|
# delete tracking branch
|
||||||
|
if [ "$allowdeletebranch" != "true" ]; then
|
||||||
|
echo "*** Deleting a tracking branch is not allowed in this repository" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# Anything else (is there anything else?)
|
||||||
|
echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# --- Finished
|
||||||
|
exit 0
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
# git ls-files --others --exclude-from=.git/info/exclude
|
||||||
|
# Lines that start with '#' are comments.
|
||||||
|
# For a project mostly in C, the following would be a good set of
|
||||||
|
# exclude patterns (uncomment them if you want to use them):
|
||||||
|
# *.[oa]
|
||||||
|
# *~
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
ref: refs/heads/main
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[core]
|
||||||
|
repositoryformatversion = 0
|
||||||
|
filemode = true
|
||||||
|
bare = true
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Unnamed repository; edit this file 'description' to name the repository.
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to check the commit log message taken by
|
||||||
|
# applypatch from an e-mail message.
|
||||||
|
#
|
||||||
|
# The hook should exit with non-zero status after issuing an
|
||||||
|
# appropriate message if it wants to stop the commit. The hook is
|
||||||
|
# allowed to edit the commit message file.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "applypatch-msg".
|
||||||
|
|
||||||
|
. git-sh-setup
|
||||||
|
commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
|
||||||
|
test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
|
||||||
|
:
|
||||||
24
archive/git/repositories/hxki-engine/hxki-events.git/hooks/commit-msg.sample
Executable file
24
archive/git/repositories/hxki-engine/hxki-events.git/hooks/commit-msg.sample
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to check the commit log message.
|
||||||
|
# Called by "git commit" with one argument, the name of the file
|
||||||
|
# that has the commit message. The hook should exit with non-zero
|
||||||
|
# status after issuing an appropriate message if it wants to stop the
|
||||||
|
# commit. The hook is allowed to edit the commit message file.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "commit-msg".
|
||||||
|
|
||||||
|
# Uncomment the below to add a Signed-off-by line to the message.
|
||||||
|
# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
|
||||||
|
# hook is more suited to it.
|
||||||
|
#
|
||||||
|
# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
|
||||||
|
# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
|
||||||
|
|
||||||
|
# This example catches duplicate Signed-off-by lines.
|
||||||
|
|
||||||
|
test "" = "$(grep '^Signed-off-by: ' "$1" |
|
||||||
|
sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || {
|
||||||
|
echo >&2 Duplicate Signed-off-by lines.
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
16
archive/git/repositories/hxki-engine/hxki-events.git/hooks/post-receive
Executable file
16
archive/git/repositories/hxki-engine/hxki-events.git/hooks/post-receive
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# AUTO GENERATED BY GITEA, DO NOT MODIFY
|
||||||
|
data=$(cat)
|
||||||
|
exitcodes=""
|
||||||
|
hookname=$(basename $0)
|
||||||
|
GIT_DIR=${GIT_DIR:-$(dirname $0)/..}
|
||||||
|
|
||||||
|
for hook in ${GIT_DIR}/hooks/${hookname}.d/*; do
|
||||||
|
test -x "${hook}" && test -f "${hook}" || continue
|
||||||
|
echo "${data}" | "${hook}"
|
||||||
|
exitcodes="${exitcodes} $?"
|
||||||
|
done
|
||||||
|
|
||||||
|
for i in ${exitcodes}; do
|
||||||
|
[ ${i} -eq 0 ] || exit ${i}
|
||||||
|
done
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# AUTO GENERATED BY GITEA, DO NOT MODIFY
|
||||||
|
/usr/local/bin/gitea hook --config=/data/gitea/conf/app.ini post-receive
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to prepare a packed repository for use over
|
||||||
|
# dumb transports.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "post-update".
|
||||||
|
|
||||||
|
exec git update-server-info
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to verify what is about to be committed
|
||||||
|
# by applypatch from an e-mail message.
|
||||||
|
#
|
||||||
|
# The hook should exit with non-zero status after issuing an
|
||||||
|
# appropriate message if it wants to stop the commit.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "pre-applypatch".
|
||||||
|
|
||||||
|
. git-sh-setup
|
||||||
|
precommit="$(git rev-parse --git-path hooks/pre-commit)"
|
||||||
|
test -x "$precommit" && exec "$precommit" ${1+"$@"}
|
||||||
|
:
|
||||||
49
archive/git/repositories/hxki-engine/hxki-events.git/hooks/pre-commit.sample
Executable file
49
archive/git/repositories/hxki-engine/hxki-events.git/hooks/pre-commit.sample
Executable file
@@ -0,0 +1,49 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to verify what is about to be committed.
|
||||||
|
# Called by "git commit" with no arguments. The hook should
|
||||||
|
# exit with non-zero status after issuing an appropriate message if
|
||||||
|
# it wants to stop the commit.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "pre-commit".
|
||||||
|
|
||||||
|
if git rev-parse --verify HEAD >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
against=HEAD
|
||||||
|
else
|
||||||
|
# Initial commit: diff against an empty tree object
|
||||||
|
against=$(git hash-object -t tree /dev/null)
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If you want to allow non-ASCII filenames set this variable to true.
|
||||||
|
allownonascii=$(git config --type=bool hooks.allownonascii)
|
||||||
|
|
||||||
|
# Redirect output to stderr.
|
||||||
|
exec 1>&2
|
||||||
|
|
||||||
|
# Cross platform projects tend to avoid non-ASCII filenames; prevent
|
||||||
|
# them from being added to the repository. We exploit the fact that the
|
||||||
|
# printable range starts at the space character and ends with tilde.
|
||||||
|
if [ "$allownonascii" != "true" ] &&
|
||||||
|
# Note that the use of brackets around a tr range is ok here, (it's
|
||||||
|
# even required, for portability to Solaris 10's /usr/bin/tr), since
|
||||||
|
# the square bracket bytes happen to fall in the designated range.
|
||||||
|
test $(git diff-index --cached --name-only --diff-filter=A -z $against |
|
||||||
|
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
|
||||||
|
then
|
||||||
|
cat <<\EOF
|
||||||
|
Error: Attempt to add a non-ASCII file name.
|
||||||
|
|
||||||
|
This can cause problems if you want to work with people on other platforms.
|
||||||
|
|
||||||
|
To be portable it is advisable to rename the file.
|
||||||
|
|
||||||
|
If you know what you are doing you can disable this check using:
|
||||||
|
|
||||||
|
git config hooks.allownonascii true
|
||||||
|
EOF
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# If there are whitespace errors, print the offending file names and fail.
|
||||||
|
exec git diff-index --check --cached $against --
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# An example hook script to verify what is about to be committed.
|
||||||
|
# Called by "git merge" with no arguments. The hook should
|
||||||
|
# exit with non-zero status after issuing an appropriate message to
|
||||||
|
# stderr if it wants to stop the merge commit.
|
||||||
|
#
|
||||||
|
# To enable this hook, rename this file to "pre-merge-commit".
|
||||||
|
|
||||||
|
. git-sh-setup
|
||||||
|
test -x "$GIT_DIR/hooks/pre-commit" &&
|
||||||
|
exec "$GIT_DIR/hooks/pre-commit"
|
||||||
|
:
|
||||||
53
archive/git/repositories/hxki-engine/hxki-events.git/hooks/pre-push.sample
Executable file
53
archive/git/repositories/hxki-engine/hxki-events.git/hooks/pre-push.sample
Executable file
@@ -0,0 +1,53 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# An example hook script to verify what is about to be pushed. Called by "git
|
||||||
|
# push" after it has checked the remote status, but before anything has been
|
||||||
|
# pushed. If this script exits with a non-zero status nothing will be pushed.
|
||||||
|
#
|
||||||
|
# This hook is called with the following parameters:
|
||||||
|
#
|
||||||
|
# $1 -- Name of the remote to which the push is being done
|
||||||
|
# $2 -- URL to which the push is being done
|
||||||
|
#
|
||||||
|
# If pushing without using a named remote those arguments will be equal.
|
||||||
|
#
|
||||||
|
# Information about the commits which are being pushed is supplied as lines to
|
||||||
|
# the standard input in the form:
|
||||||
|
#
|
||||||
|
# <local ref> <local oid> <remote ref> <remote oid>
|
||||||
|
#
|
||||||
|
# This sample shows how to prevent push of commits where the log message starts
|
||||||
|
# with "WIP" (work in progress).
|
||||||
|
|
||||||
|
remote="$1"
|
||||||
|
url="$2"
|
||||||
|
|
||||||
|
zero=$(git hash-object --stdin </dev/null | tr '[0-9a-f]' '0')
|
||||||
|
|
||||||
|
while read local_ref local_oid remote_ref remote_oid
|
||||||
|
do
|
||||||
|
if test "$local_oid" = "$zero"
|
||||||
|
then
|
||||||
|
# Handle delete
|
||||||
|
:
|
||||||
|
else
|
||||||
|
if test "$remote_oid" = "$zero"
|
||||||
|
then
|
||||||
|
# New branch, examine all commits
|
||||||
|
range="$local_oid"
|
||||||
|
else
|
||||||
|
# Update to existing branch, examine new commits
|
||||||
|
range="$remote_oid..$local_oid"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for WIP commit
|
||||||
|
commit=$(git rev-list -n 1 --grep '^WIP' "$range")
|
||||||
|
if test -n "$commit"
|
||||||
|
then
|
||||||
|
echo >&2 "Found WIP commit in $local_ref, not pushing"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
exit 0
|
||||||
169
archive/git/repositories/hxki-engine/hxki-events.git/hooks/pre-rebase.sample
Executable file
169
archive/git/repositories/hxki-engine/hxki-events.git/hooks/pre-rebase.sample
Executable file
@@ -0,0 +1,169 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# Copyright (c) 2006, 2008 Junio C Hamano
|
||||||
|
#
|
||||||
|
# The "pre-rebase" hook is run just before "git rebase" starts doing
|
||||||
|
# its job, and can prevent the command from running by exiting with
|
||||||
|
# non-zero status.
|
||||||
|
#
|
||||||
|
# The hook is called with the following parameters:
|
||||||
|
#
|
||||||
|
# $1 -- the upstream the series was forked from.
|
||||||
|
# $2 -- the branch being rebased (or empty when rebasing the current branch).
|
||||||
|
#
|
||||||
|
# This sample shows how to prevent topic branches that are already
|
||||||
|
# merged to 'next' branch from getting rebased, because allowing it
|
||||||
|
# would result in rebasing already published history.
|
||||||
|
|
||||||
|
publish=next
|
||||||
|
basebranch="$1"
|
||||||
|
if test "$#" = 2
|
||||||
|
then
|
||||||
|
topic="refs/heads/$2"
|
||||||
|
else
|
||||||
|
topic=`git symbolic-ref HEAD` ||
|
||||||
|
exit 0 ;# we do not interrupt rebasing detached HEAD
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$topic" in
|
||||||
|
refs/heads/??/*)
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
exit 0 ;# we do not interrupt others.
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Now we are dealing with a topic branch being rebased
|
||||||
|
# on top of master. Is it OK to rebase it?
|
||||||
|
|
||||||
|
# Does the topic really exist?
|
||||||
|
git show-ref -q "$topic" || {
|
||||||
|
echo >&2 "No such branch $topic"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Is topic fully merged to master?
|
||||||
|
not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
|
||||||
|
if test -z "$not_in_master"
|
||||||
|
then
|
||||||
|
echo >&2 "$topic is fully merged to master; better remove it."
|
||||||
|
exit 1 ;# we could allow it, but there is no point.
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Is topic ever merged to next? If so you should not be rebasing it.
|
||||||
|
only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
|
||||||
|
only_next_2=`git rev-list ^master ${publish} | sort`
|
||||||
|
if test "$only_next_1" = "$only_next_2"
|
||||||
|
then
|
||||||
|
not_in_topic=`git rev-list "^$topic" master`
|
||||||
|
if test -z "$not_in_topic"
|
||||||
|
then
|
||||||
|
echo >&2 "$topic is already up to date with master"
|
||||||
|
exit 1 ;# we could allow it, but there is no point.
|
||||||
|
else
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
|
||||||
|
/usr/bin/perl -e '
|
||||||
|
my $topic = $ARGV[0];
|
||||||
|
my $msg = "* $topic has commits already merged to public branch:\n";
|
||||||
|
my (%not_in_next) = map {
|
||||||
|
/^([0-9a-f]+) /;
|
||||||
|
($1 => 1);
|
||||||
|
} split(/\n/, $ARGV[1]);
|
||||||
|
for my $elem (map {
|
||||||
|
/^([0-9a-f]+) (.*)$/;
|
||||||
|
[$1 => $2];
|
||||||
|
} split(/\n/, $ARGV[2])) {
|
||||||
|
if (!exists $not_in_next{$elem->[0]}) {
|
||||||
|
if ($msg) {
|
||||||
|
print STDERR $msg;
|
||||||
|
undef $msg;
|
||||||
|
}
|
||||||
|
print STDERR " $elem->[1]\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
' "$topic" "$not_in_next" "$not_in_master"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
<<\DOC_END
|
||||||
|
|
||||||
|
This sample hook safeguards topic branches that have been
|
||||||
|
published from being rewound.
|
||||||
|
|
||||||
|
The workflow assumed here is:
|
||||||
|
|
||||||
|
* Once a topic branch forks from "master", "master" is never
|
||||||
|
merged into it again (either directly or indirectly).
|
||||||
|
|
||||||
|
* Once a topic branch is fully cooked and merged into "master",
|
||||||
|
it is deleted. If you need to build on top of it to correct
|
||||||
|
earlier mistakes, a new topic branch is created by forking at
|
||||||
|
the tip of the "master". This is not strictly necessary, but
|
||||||
|
it makes it easier to keep your history simple.
|
||||||
|
|
||||||
|
* Whenever you need to test or publish your changes to topic
|
||||||
|
branches, merge them into "next" branch.
|
||||||
|
|
||||||
|
The script, being an example, hardcodes the publish branch name
|
||||||
|
to be "next", but it is trivial to make it configurable via
|
||||||
|
$GIT_DIR/config mechanism.
|
||||||
|
|
||||||
|
With this workflow, you would want to know:
|
||||||
|
|
||||||
|
(1) ... if a topic branch has ever been merged to "next". Young
|
||||||
|
topic branches can have stupid mistakes you would rather
|
||||||
|
clean up before publishing, and things that have not been
|
||||||
|
merged into other branches can be easily rebased without
|
||||||
|
affecting other people. But once it is published, you would
|
||||||
|
not want to rewind it.
|
||||||
|
|
||||||
|
(2) ... if a topic branch has been fully merged to "master".
|
||||||
|
Then you can delete it. More importantly, you should not
|
||||||
|
build on top of it -- other people may already want to
|
||||||
|
change things related to the topic as patches against your
|
||||||
|
"master", so if you need further changes, it is better to
|
||||||
|
fork the topic (perhaps with the same name) afresh from the
|
||||||
|
tip of "master".
|
||||||
|
|
||||||
|
Let's look at this example:
|
||||||
|
|
||||||
|
o---o---o---o---o---o---o---o---o---o "next"
|
||||||
|
/ / / /
|
||||||
|
/ a---a---b A / /
|
||||||
|
/ / / /
|
||||||
|
/ / c---c---c---c B /
|
||||||
|
/ / / \ /
|
||||||
|
/ / / b---b C \ /
|
||||||
|
/ / / / \ /
|
||||||
|
---o---o---o---o---o---o---o---o---o---o---o "master"
|
||||||
|
|
||||||
|
|
||||||
|
A, B and C are topic branches.
|
||||||
|
|
||||||
|
* A has one fix since it was merged up to "next".
|
||||||
|
|
||||||
|
* B has finished. It has been fully merged up to "master" and "next",
|
||||||
|
and is ready to be deleted.
|
||||||
|
|
||||||
|
* C has not merged to "next" at all.
|
||||||
|
|
||||||
|
We would want to allow C to be rebased, refuse A, and encourage
|
||||||
|
B to be deleted.
|
||||||
|
|
||||||
|
To compute (1):
|
||||||
|
|
||||||
|
git rev-list ^master ^topic next
|
||||||
|
git rev-list ^master next
|
||||||
|
|
||||||
|
if these match, topic has not merged in next at all.
|
||||||
|
|
||||||
|
To compute (2):
|
||||||
|
|
||||||
|
git rev-list master..topic
|
||||||
|
|
||||||
|
if this is empty, it is fully merged to "master".
|
||||||
|
|
||||||
|
DOC_END
|
||||||
16
archive/git/repositories/hxki-engine/hxki-events.git/hooks/pre-receive
Executable file
16
archive/git/repositories/hxki-engine/hxki-events.git/hooks/pre-receive
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# AUTO GENERATED BY GITEA, DO NOT MODIFY
|
||||||
|
data=$(cat)
|
||||||
|
exitcodes=""
|
||||||
|
hookname=$(basename $0)
|
||||||
|
GIT_DIR=${GIT_DIR:-$(dirname $0)/..}
|
||||||
|
|
||||||
|
for hook in ${GIT_DIR}/hooks/${hookname}.d/*; do
|
||||||
|
test -x "${hook}" && test -f "${hook}" || continue
|
||||||
|
echo "${data}" | "${hook}"
|
||||||
|
exitcodes="${exitcodes} $?"
|
||||||
|
done
|
||||||
|
|
||||||
|
for i in ${exitcodes}; do
|
||||||
|
[ ${i} -eq 0 ] || exit ${i}
|
||||||
|
done
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# AUTO GENERATED BY GITEA, DO NOT MODIFY
|
||||||
|
/usr/local/bin/gitea hook --config=/data/gitea/conf/app.ini pre-receive
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user