spb/cluster-skill
Public
HTML 57.2%
Shell 19.1%
Python 11.2%
CSS 7.4%
JavaScript 5.1%
1#!/bin/bash2# cluster-gateway.sh — M3U96a comme porte d'entrée (staging) du cluster MacLustr.3#4# Principe : on pousse un projet UNE fois laptop -> M3U96a (~/cluster-projects/<nom>/),5# puis M3U96a le diffuse aux autres noeuds en parallele via le reseau local (Tailscale/LAN).6# Le meme chemin ~/cluster-projects/<nom>/ existe ainsi sur tous les noeuds cibles.7#8# Usage :9# cluster-gateway.sh stage <dir-local> [nom] # laptop -> M3U96a10# cluster-gateway.sh fanout <nom> [noeud ...] # M3U96a -> noeuds (defaut: tous sauf M3U96a & M2U64)11# cluster-gateway.sh push <dir-local> [nom] # stage + fanout (defaut)12# cluster-gateway.sh list # projets stages sur M3U96a13# cluster-gateway.sh where <nom> # sur quels noeuds le projet est present14# cluster-gateway.sh clean <nom> [--everywhere] # efface de M3U96a (et de tous les noeuds)15#16# Options : --include-m2u64 (fanout/push : inclure le noeud prod M2U64)17# Doc complete : ~/Desktop/cluster-skill/GATEWAY.md18set -euo pipefail1920GATEWAY="M3U96a"21DOMAIN="maclustr.io"22STAGE_DIR="cluster-projects"23LAN_PREFIX_RE='192\.168\.2\.' # sous-reseau LAN du cluster24ALL_NODES="M3U96b M2U64 M4M64a M4M64b M4BP48 M4BP36 M4M36 M2M32 M2M32b M2M32c m4mc M1M32 m4ma m4mb m2m16 M3BA24 M3BA16 m2m8a m2m8b"2526usage() { sed -n '2,18p' "$0" | sed 's/^# \{0,1\}//'; exit 1; }2728CMD="${1:-}"; shift || true2930INCLUDE_M2U64=031ARGS=()32for a in "$@"; do33 case "$a" in34 --include-m2u64) INCLUDE_M2U64=1 ;;35 *) ARGS+=("$a") ;;36 esac37done38set -- "${ARGS[@]:-}"3940default_targets() {41 local out=""42 for n in $ALL_NODES; do43 [ "$n" = "M2U64" ] && [ "$INCLUDE_M2U64" -eq 0 ] && continue44 out="$out $n"45 done46 echo "$out"47}4849do_stage() {50 local src="${1:?usage: stage <dir-local> [nom]}"51 src="${src%/}"52 [ -d "$src" ] || { echo "ERREUR: $src n'est pas un dossier" >&2; exit 2; }53 local name="${2:-$(basename "$src")}"54 echo ">> stage: $src -> $GATEWAY:~/$STAGE_DIR/$name/"55 rsync -az --delete --rsync-path="mkdir -p $STAGE_DIR && rsync" \56 "$src/" "$GATEWAY:$STAGE_DIR/$name/"57 echo "OK stage $name ($(du -sh "$src" | cut -f1))"58}5960do_fanout() {61 local name="${1:?usage: fanout <nom> [noeud ...]}"; shift || true62 local nodes="${*:-$(default_targets)}"63 # Le SSH inter-noeuds via Tailscale est filtre (ACL) : le fanout passe par le LAN64 # 192.168.2.x. Les IP LAN sont en DHCP -> on les resout en live depuis le laptop.65 echo ">> resolution des IP LAN des cibles ($(echo $nodes | wc -w | tr -d ' ') noeuds)..."66 local tmp; tmp=$(mktemp -d)67 local n68 for n in $nodes; do69 ( ip=$(ssh -n -o ConnectTimeout=8 "$n" \70 "ifconfig | awk '/inet $LAN_PREFIX_RE/{print \$2; exit}'" 2>/dev/null || true)71 echo "${ip:-NONE}" >"$tmp/$n" ) &72 done73 wait74 local pairs=""75 for n in $nodes; do pairs="$pairs $n=$(cat "$tmp/$n" 2>/dev/null || echo NONE)"; done76 rm -rf "$tmp"77 echo ">> fanout depuis $GATEWAY via LAN: $name ->$(echo "$pairs" | tr ' ' '\n' | grep -c '=' | xargs echo) noeuds"78 # shellcheck disable=SC208779 ssh -A "$GATEWAY" "NAME='$name' PAIRS='$pairs' bash -s" <<'REMOTE'80set -u81SRC="$HOME/cluster-projects/$NAME/"82[ -d "$SRC" ] || { echo "ERREUR: $SRC absent sur la passerelle — faire stage d abord" >&2; exit 2; }83TMP=$(mktemp -d)84for pair in $PAIRS; do85 n="${pair%%=*}"; ip="${pair##*=}"86 if [ "$ip" = "NONE" ]; then echo "FAIL (hors LAN cluster ou injoignable)" >"$TMP/$n"; continue; fi87 ( rsync -az --delete \88 -e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=8" \89 --rsync-path="mkdir -p cluster-projects && rsync" \90 "$SRC" "$ip:cluster-projects/$NAME/" \91 >/dev/null 2>"$TMP/$n.err" && echo "OK ($ip)" >"$TMP/$n" || echo "FAIL ($ip)" >"$TMP/$n" ) &92done93wait94FAILED=095for pair in $PAIRS; do96 n="${pair%%=*}"97 st=$(cat "$TMP/$n" 2>/dev/null || echo FAIL)98 printf " %-8s %s\n" "$n" "$st"99 case "$st" in FAIL*) FAILED=1; [ -f "$TMP/$n.err" ] && sed 's/^/ /' "$TMP/$n.err" | grep -v "known hosts" | head -2 ;; esac100done101rm -rf "$TMP"102exit $FAILED103REMOTE104 echo "OK fanout $name termine"105}106107do_list() {108 echo ">> projets stages sur $GATEWAY:~/$STAGE_DIR/"109 ssh "$GATEWAY" "du -sh $STAGE_DIR/*/ 2>/dev/null || echo ' (aucun projet stage)'"110}111112do_where() {113 local name="${1:?usage: where <nom>}"114 echo ">> presence de '$name' sur le cluster :"115 for n in $GATEWAY $ALL_NODES; do116 ( sz=$(ssh -o ConnectTimeout=6 "$n.$DOMAIN" "du -sh $STAGE_DIR/$name 2>/dev/null | cut -f1" 2>/dev/null)117 printf " %-8s %s\n" "$n" "${sz:-—}" ) &118 done119 wait120}121122do_clean() {123 local name="${1:?usage: clean <nom> [--everywhere]}"124 local everywhere=0125 [ "${2:-}" = "--everywhere" ] && everywhere=1126 if [ "$everywhere" -eq 1 ]; then127 echo ">> clean '$name' sur TOUS les noeuds"128 for n in $GATEWAY $ALL_NODES; do129 ( ssh -o ConnectTimeout=6 "$n.$DOMAIN" "rm -rf $STAGE_DIR/$name" 2>/dev/null \130 && printf " %-8s OK\n" "$n" || printf " %-8s (injoignable)\n" "$n" ) &131 done132 wait133 else134 echo ">> clean '$name' sur $GATEWAY uniquement"135 ssh "$GATEWAY" "rm -rf $STAGE_DIR/$name" && echo " $GATEWAY OK"136 fi137}138139case "$CMD" in140 stage) do_stage "$@" ;;141 fanout) do_fanout "$@" ;;142 push) do_stage "$1" "${2:-}"; do_fanout "${2:-$(basename "${1%/}")}" ;;143 list) do_list ;;144 where) do_where "$@" ;;145 clean) do_clean "$@" ;;146 *) usage ;;147esac148