T4.2 Nextcloud migré (07c) + Collabora: --o:ssl.enable=false (TLS image par défaut)
This commit is contained in:
+128
@@ -0,0 +1,128 @@
|
||||
#!/usr/bin/env bash
|
||||
# 07d-migrate-photoprism.sh — T4.3 : PhotoPrism sur le G9, photos COPIÉES (décision #3).
|
||||
#
|
||||
# Vérité terrain mesurée 2026-10-11 : il n'y a **aucun conteneur ni image PhotoPrism sur .25**
|
||||
# (`docker ps -a` : rien, `docker images` : rien). PhotoPrism n'est donc pas « migré » :
|
||||
# il est **installé** sur le G9 à partir des photos du NAS (/volume1/photo = 530 Go,
|
||||
# 305 059 fichiers media, 2002→2026), avec un index neuf (décision #4 : indexation progressive).
|
||||
#
|
||||
# Transport : le sshd de DSM refuse rsync --server et scp (voir journal 2026-10-11) →
|
||||
# flux tar sur SSH, relayé par la machine de pilotage : .25 → pilot → .24.
|
||||
#
|
||||
# Intégrité : manifeste **métadonnées** (chemin + taille, LC_ALL=C) source vs G9, totaux
|
||||
# (nb fichiers, octets), plus échantillon sha256 de 200 fichiers.
|
||||
#
|
||||
# Usage : sur la machine de pilotage (détenant la clé), ./07d-migrate-photoprism.sh
|
||||
# Étape longue (530 Go). `SKIP_COPY=1` pour ne redéployer que la stack.
|
||||
# Rollback : `docker compose -f /data/docker/photoprism/docker-compose.yml down` +
|
||||
# `rm -rf /data/docker/photoprism` ; .25 intact (lecture seule sur /volume1/photo).
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
XP_USER="Master"; XP_HOST="192.168.1.25"; XP_PORT=222
|
||||
XP_PHOTO="/volume1/photo"
|
||||
G9_USER="folzo"; G9_HOST="192.168.1.24"
|
||||
KEY="${SSH_KEY:-$HOME/.ssh/id_ed25519_openfox11}"
|
||||
BRIQUE="photoprism"
|
||||
G9_DIR="/data/docker/$BRIQUE"
|
||||
KIT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
KIT_ON_G9="/home/folzo/g9-migration"
|
||||
JOURNAL="$KIT_DIR/journal.md"
|
||||
STAGE="${STAGE:-$HOME/migration-staging/$BRIQUE}"
|
||||
MIN_FREE_GB=600
|
||||
INDEX_TIMEOUT="${INDEX_TIMEOUT:-3600}"
|
||||
|
||||
SSH_XP="ssh -p $XP_PORT -i $KEY -o ControlMaster=auto -o ControlPath=/tmp/.g9-ctl-%r@%h:%p -o ControlPersist=600 $XP_USER@$XP_HOST"
|
||||
SSH_G9="ssh -i $KEY -o ControlMaster=auto -o ControlPath=/tmp/.g9-ctl-%r@%h:%p -o ControlPersist=600 $G9_USER@$G9_HOST"
|
||||
RSH_G9="ssh -i $KEY"
|
||||
|
||||
log() { echo -e "\n[photoprism] $*"; }
|
||||
journal() {
|
||||
printf '| %s | 4 | migrate:%s : %s | %s | %s | %s |\n' \
|
||||
"$(date '+%Y-%m-%d %H:%M')" "$BRIQUE" "$1" "$2" "$3" "$4" >> "$JOURNAL"
|
||||
}
|
||||
meta_manifest() { ( cd "$1" && find . -type f -printf '%p\t%s\n' 2>/dev/null | LC_ALL=C sort ); }
|
||||
|
||||
# ---------------------------------------------------------------- 0. préflight
|
||||
log "=== 0/5 PRÉFLIGHT ==="
|
||||
$SSH_XP "command -v tar >/dev/null && sudo tar --version >/dev/null" || { echo "ERREUR : SSH/tar .25"; exit 1; }
|
||||
$SSH_G9 "command -v docker >/dev/null && command -v rsync >/dev/null" || { echo "ERREUR : docker/rsync .24"; exit 1; }
|
||||
$SSH_XP "sudo test -d $XP_PHOTO" || { echo "ERREUR : $XP_PHOTO absent sur .25"; exit 1; }
|
||||
FREE_GB=$($SSH_G9 "df -BG --output=avail /data | tail -1 | tr -dc '0-9'")
|
||||
[[ "$FREE_GB" -ge "$MIN_FREE_GB" ]] || { echo "ERREUR : espace /data insuffisant (${FREE_GB} Go < ${MIN_FREE_GB} Go)"; exit 1; }
|
||||
log "espace /data = ${FREE_GB} Go"
|
||||
mkdir -p "$STAGE"
|
||||
|
||||
SRC_COUNT=$($SSH_XP "sudo find $XP_PHOTO -type f | wc -l")
|
||||
SRC_BYTES=$($SSH_XP "sudo find $XP_PHOTO -type f -printf '%s\n' | awk '{s+=\$1} END {print s}'")
|
||||
log "source .25 : $SRC_COUNT fichiers, $SRC_BYTES octets"
|
||||
|
||||
# ---------------------------------------------------------------- 1. backup G2
|
||||
log "=== 1/5 BACKUP restic (G2) ==="
|
||||
if $SSH_G9 "sudo restic snapshots 2>/dev/null | grep -q '$(date '+%Y-%m-%d')'"; then
|
||||
log " ⏭ snapshot du jour déjà présent — backup complet sauté (idempotence)"
|
||||
else
|
||||
$SSH_G9 "sudo /usr/local/bin/restic-daily.sh >/dev/null 2>&1; sudo restic snapshots 2>/dev/null | tail -2"
|
||||
journal "backup restic pré-migration" "Garde-fou G2 avant import PhotoPrism" "snapshot restic Freebox (log /var/log/restic-daily.log)" "restic forget <snapshot> && restic prune"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------- 2. copie des photos
|
||||
if [[ "${SKIP_COPY:-0}" != "1" ]]; then
|
||||
log "=== 2/5 COPIE $XP_PHOTO → $G9_DIR/originals (tar sur SSH, relais pilot) ==="
|
||||
$SSH_G9 "sudo mkdir -p $G9_DIR/originals $G9_DIR/storage $G9_DIR/import && sudo chown -R $G9_USER:$G9_USER $G9_DIR"
|
||||
# MariaDB = uid 999 : datadir à lui (sinon « Permission denied » sur db.opt).
|
||||
$SSH_G9 "sudo mkdir -p $G9_DIR/db && sudo chown -R 999:999 $G9_DIR/db && sudo chmod 750 $G9_DIR/db"
|
||||
t0=$(date +%s)
|
||||
# Progression : tar GNU du G9 émet un pointage sur stderr tous les 50 000 enregistrements
|
||||
# (stderr relayé par ssh) → la copie de 530 Go n'est pas silencieuse pendant des heures.
|
||||
if ! $SSH_XP "sudo tar cz -C '$XP_PHOTO' ." | $SSH_G9 "tar xz --checkpoint=50000 --checkpoint-action=echo='[copie] %n enregistrements' -C $G9_DIR/originals"; then
|
||||
echo "ERREUR : flux tar interrompu"; exit 1
|
||||
fi
|
||||
t=$(( $(date +%s) - t0 ))
|
||||
log " copie terminée en ${t} s"
|
||||
journal "copie photos .25 → G9" "530 Go, source en lecture seule (aucune écriture sur .25)" "tar/ssh relayé par le pilot, ${t} s ; $SRC_COUNT fichiers source" "rm -rf $G9_DIR/originals (source .25 intacte)"
|
||||
fi
|
||||
|
||||
# ---------------------------------------------------------------- 3. intégrité
|
||||
log "=== 3/5 INTÉGRITÉ (manifeste métadonnées + échantillon sha256) ==="
|
||||
$SSH_XP "sudo sh -c \"cd '$XP_PHOTO' && find . -type f -printf '%p\t%s\n' | LC_ALL=C sort\"" > "$STAGE/src.meta"
|
||||
$SSH_G9 "cd '$G9_DIR/originals' && find . -type f -printf '%p\t%s\n' | LC_ALL=C sort" > "$STAGE/g9.meta"
|
||||
DST_COUNT=$(wc -l < "$STAGE/g9.meta")
|
||||
DST_BYTES=$(awk -F'\t' '{s+=$2} END {print s}' "$STAGE/g9.meta")
|
||||
log " source=$SRC_COUNT fichiers / $SRC_BYTES o — G9=$DST_COUNT fichiers / $DST_BYTES o"
|
||||
[[ "$SRC_COUNT" == "$DST_COUNT" && "$SRC_BYTES" == "$DST_BYTES" ]] || { echo "ERREUR : compte/taille différents"; diff "$STAGE/src.meta" "$STAGE/g9.meta" | head -20; exit 1; }
|
||||
diff "$STAGE/src.meta" "$STAGE/g9.meta" > "$STAGE/meta.diff" || { log "❌ chemins/tailles différents :"; head -20 "$STAGE/meta.diff"; exit 1; }
|
||||
log " ✅ manifeste métadonnées identique ($DST_COUNT fichiers)"
|
||||
|
||||
SAMPLE=$(shuf -n 200 "$STAGE/g9.meta" | cut -f1)
|
||||
printf '%s\n' "$SAMPLE" > "$STAGE/sample.txt"
|
||||
n=$(wc -l < "$STAGE/sample.txt")
|
||||
SRC_SHA=$(printf '%s\n' "$SAMPLE" | $SSH_XP "sudo sh -c \"cd '$XP_PHOTO' && xargs -d '\n' sha256sum\"" | awk '{print $1}' | LC_ALL=C sort)
|
||||
DST_SHA=$(printf '%s\n' "$SAMPLE" | $SSH_G9 "cd '$G9_DIR/originals' && xargs -d '\n' sha256sum" | awk '{print $1}' | LC_ALL=C sort)
|
||||
if [[ "$SRC_SHA" == "$DST_SHA" ]]; then
|
||||
log " ✅ échantillon sha256 : $n/$n fichiers identiques"
|
||||
else
|
||||
log "❌ échantillon sha256 divergent"; diff <(echo "$SRC_SHA") <(echo "$DST_SHA") | head -10; exit 1
|
||||
fi
|
||||
journal "intégration PhotoPrism" "copie de 530 Go à vérifier avant indexation" "manifeste chemins+tailles identique ($DST_COUNT fichiers, $DST_BYTES o) + échantillon sha256 $n/$n" "re-copie ciblée via tar/ssh"
|
||||
|
||||
# ---------------------------------------------------------------- 4. stack + secrets
|
||||
log "=== 4/5 STACK + SECRETS ==="
|
||||
rsync -a --info=stats1 -e "$RSH_G9" --exclude "secrets" "$KIT_DIR/compose/$BRIQUE/" "$G9_USER@$G9_HOST:$KIT_ON_G9/compose/$BRIQUE/"
|
||||
rsync -a -e "$RSH_G9" "$KIT_DIR/scripts/03b-secrets.sh" "$G9_USER@$G9_HOST:$KIT_ON_G9/scripts/"
|
||||
$SSH_G9 "sudo bash $KIT_ON_G9/scripts/03b-secrets.sh >/dev/null"
|
||||
$SSH_G9 "sudo rsync -a $KIT_ON_G9/compose/$BRIQUE/ $G9_DIR/ && sudo chmod 755 $G9_DIR/secrets"
|
||||
$SSH_G9 "sudo chown -R 999:999 $G9_DIR/db && sudo chmod 750 $G9_DIR/db"
|
||||
# PhotoPrism n'accepte pas les *_FILE : env_file construit à partir des secrets (600, root, hors git).
|
||||
$SSH_G9 "sudo sh -c 'umask 077; { echo PHOTOPRISM_ADMIN_PASSWORD=\$(cat $G9_DIR/secrets/admin); echo PHOTOPRISM_DATABASE_PASSWORD=\$(cat $G9_DIR/secrets/dbpass); } > $G9_DIR/secrets/photoprism.env' && sudo chown root:root $G9_DIR/secrets/photoprism.env"
|
||||
$SSH_G9 "cd $G9_DIR && docker compose up -d && sleep 30 && docker compose ps --format '{{.Name}} {{.Status}}'"
|
||||
|
||||
# ---------------------------------------------------------------- 5. indexation + vérifs
|
||||
log "=== 5/5 INDEXATION (progressive, décision #4) + VÉRIFS ==="
|
||||
$SSH_G9 "curl -sf -o /dev/null -w 'photoprism HTTP %{http_code}\n' http://127.0.0.1:2342/api/v1/session/health"
|
||||
$SSH_G9 "cd $G9_DIR && timeout $INDEX_TIMEOUT docker compose exec -T photoprism photoprism index 2>&1 | tail -6 < /dev/null || true"
|
||||
$SSH_G9 "cd $G9_DIR && docker compose exec -T photoprism sh -c 'photoprism count 2>/dev/null | head -12' < /dev/null || true"
|
||||
journal "stack PhotoPrism déployée + indexation lancée" "T4.3 : stack saine, index progressif (photothèque 530 Go sur le G9)" "image épinglée 260919, MariaDB 10.11 (watchtower OFF), secrets via env_file 600, port 2342 LAN ; originals = copie locale" "docker compose down + rm -rf /data/docker/photoprism"
|
||||
|
||||
echo
|
||||
log "TERMINÉ. Prochaine étape : laisser monter l'index (cron/kommand), puis T4.5 (n8n)."
|
||||
Reference in New Issue
Block a user