#!/usr/bin/env bash
# Stellt die Replikation her bzw. zeigt die Lage des Redis-Verbunds.
#
#   redis-zugang.sh <replik-ip> <master-ip>     # Replik an den Master haengen
#   redis-zugang.sh --lage <ip> [<ip> ...]      # Rolle und Verbindung zeigen
#
# Das Passwort kommt aus der REDIS_URL eines Frontends und wird ausschliesslich
# ueber die Standardeingabe weitergereicht - nie als Argument, sonst stuende es
# in der Prozessliste jeder Maschine, die gerade jemand anschaut.
#
# Angemeldet wird als ACL-Benutzer "default". Der Benutzer "shopware", mit dem
# der Shop arbeitet, hat "resetchannels" und darf damit kein Pub/Sub - fuer
# Replikation und Sentinel ist das aber Voraussetzung. Beide Benutzer haben
# denselben Passwort-Hash, das Passwort aus der REDIS_URL passt also.
set -uo pipefail

cd "$(dirname "$0")"
source ./lib-knoten.sh

QUELLE=10.0.1.1   # irgendein Frontend; dort steht die REDIS_URL

pw_holen() {
    rz_ssh "$QUELLE" "cd /var/www/riccardo && python3 -c \"
import re
from urllib.parse import urlparse, unquote
m = re.search(r'^REDIS_URL=(.+)\\\$', open('.env.local').read(), re.M)
print(unquote(urlparse(m.group(1).strip()).password or ''))
\""
}

if [ "${1:-}" = "--lage" ]; then
    shift
    PW=$(pw_holen)
    [ -n "$PW" ] || { echo "Kein Redis-Passwort gefunden."; exit 1; }
    for ip in "$@"; do
        printf '  %-10s ' "$ip"
        printf '%s\n' "$PW" | rz_ssh_stdin "$ip" '
            read -r pw || true   # ohne Zeilenumbruch liefert read 1, obwohl es gelesen hat
            export REDISCLI_AUTH="$pw"
            redis-cli --user default --no-auth-warning -h '"$ip"' info replication 2>/dev/null \
              | tr -d "\r" \
              | awk -F: "
                  /^role:/            { rolle=\$2 }
                  /^connected_slaves/ { repliken=\$2 }
                  /^master_link_status/ { verbindung=\$2 }
                  /^master_host/      { wessen=\$2 }
                  /^master_last_io_seconds_ago/ { still=\$2 }
                  END {
                    if (rolle == \"master\") printf \"Master, %s Replik(en)\n\", repliken
                    else printf \"Replik von %s, Verbindung %s, letzter Kontakt vor %ss\n\", wessen, verbindung, still
                  }"
        ' || echo "nicht erreichbar"
    done
    exit 0
fi

REPLIK="${1:?Replik-IP fehlt}"
MASTER="${2:?Master-IP fehlt}"
PW=$(pw_holen)
[ -n "$PW" ] || { echo "Kein Redis-Passwort gefunden."; exit 1; }

printf '%s\n' "$PW" | rz_ssh_stdin "$REPLIK" '
    set -e
    read -r pw || true   # ohne Zeilenumbruch liefert read 1, obwohl es gelesen hat
    # In die Konfiguration schreiben, damit die Replikation auch einen
    # Neustart uebersteht. Vorhandene Zeilen erst raus, sonst sammeln sie
    # sich bei jedem Lauf.
    sed -i "/^masteruser /d; /^masterauth /d; /^replicaof /d; /^slaveof /d" /etc/redis/redis.conf
    {
        echo ""
        echo "# Replikation - gesetzt von dev/deploy/redis-zugang.sh"
        echo "masteruser default"
        echo "masterauth $pw"
        echo "replicaof '"$MASTER"' 6379"
    } >> /etc/redis/redis.conf
    chown redis:redis /etc/redis/redis.conf; chmod 640 /etc/redis/redis.conf

    # Und sofort wirksam machen, ohne Neustart.
    export REDISCLI_AUTH="$pw"
    redis-cli --user default --no-auth-warning config set masteruser default > /dev/null
    redis-cli --user default --no-auth-warning config set masterauth "$pw" > /dev/null
    redis-cli --user default --no-auth-warning replicaof '"$MASTER"' 6379 > /dev/null
    echo "   Replikation gesetzt"
' || { echo "   Replikation fehlgeschlagen"; exit 1; }

echo "   Warten auf den ersten Abgleich"
for i in $(seq 1 30); do
    STAND=$(printf '%s\n' "$PW" | rz_ssh_stdin "$REPLIK" '
        read -r pw; export REDISCLI_AUTH="$pw"
        redis-cli --user default --no-auth-warning info replication 2>/dev/null | tr -d "\r" | grep -oP "master_link_status:\K.*"')
    [ "$STAND" = up ] && { echo "   abgeglichen nach ${i}s"; exit 0; }
    sleep 1
done
echo "   Der Abgleich ist nach 30 s noch nicht fertig - bitte nachsehen."
exit 1
