servidor: el aviso periódico de novedades del repo, que sólo grita cuando cambia
Corre `takana outdated --json` contra el índice firmado y deja el resultado en un fichero de estado. No actualiza nada: instalar es reproducir y verificar, y eso no se cuelga de un cron — el aviso dice qué comando correr. Tres cosas deliberadas: · Sólo grita cuando la LISTA de novedades difiere de la del ciclo anterior. Un guardián que repite lo mismo cada 30 min se deja de leer, y entonces no avisa de nada. · La huella es nombre+versión publicada, no el JSON entero: éste trae contadores que se mueven solos y harían «cambiar» un estado idéntico. · Un repo caído NO se resume en «al día»: lo dice, sale ≠ 0 y conserva el último estado bueno. Probado en los tres caminos contra un repo servido por HTTP en la caja.
This commit is contained in:
Executable
+84
@@ -0,0 +1,84 @@
|
||||
#!/bin/sh
|
||||
# avisar-actualizaciones.sh — pregunta al repo si hay novedades para lo que esta máquina tiene
|
||||
# instalado, y AVISA sólo cuando la respuesta cambia.
|
||||
#
|
||||
# ── QUÉ HACE Y QUÉ NO ───────────────────────────────────────────────────────────────────────────
|
||||
# Corre `takana outdated --json` (que no construye, no baja `.swm` y no escribe nada: lee el índice
|
||||
# firmado y la DB de instalados) y deja el resultado en un fichero de estado. **No actualiza nada**:
|
||||
# instalar es reproducir y verificar, y eso no se cuelga de un cron. El aviso dice qué correr.
|
||||
#
|
||||
# ── POR QUÉ SÓLO AVISA CUANDO CAMBIA ────────────────────────────────────────────────────────────
|
||||
# Un guardián que grita lo mismo cada 30 minutos se deja de leer, y entonces no avisa de nada — es
|
||||
# la lección que ya está escrita en `vigia-subcomandos.py` ([[guardianes-el-ruido-los-mata]]).
|
||||
# Así que el ciclo normal es una línea sola («al día», o «3 novedades, las mismas de antes») y el
|
||||
# grito sale cuando la LISTA de novedades difiere de la del ciclo anterior.
|
||||
#
|
||||
# ── LA FIRMA NO ES OPCIONAL ACÁ ─────────────────────────────────────────────────────────────────
|
||||
# Se pasa `--trust`: decidir «hay que actualizar» a partir de un catálogo que nadie firmó es la
|
||||
# forma exacta de que te instalen lo que quieran. `outdated` aborta si el índice está manipulado
|
||||
# (BAD-SIG) e informa si está sin firmar o firmado por una clave desconocida — ese informe sale en
|
||||
# el log y en el estado, no se traga.
|
||||
#
|
||||
# Uso: scripts/servidor/avisar-actualizaciones.sh
|
||||
# */30 * * * * cd /work/sergio/takana && scripts/servidor/avisar-actualizaciones.sh \
|
||||
# >>work/avisar-actualizaciones.log 2>&1
|
||||
#
|
||||
# Env: REPO origen(es) del catálogo — dir local o lista HTTP(S) separada por comas
|
||||
# DB DB de instalados (def /var/lib/hammer/installed.json)
|
||||
# TRUST directorio de claves de confianza (def ./trust)
|
||||
# STATE fichero de estado (def work/actualizaciones.json)
|
||||
# TAKANA binario (def ./target/release/takana)
|
||||
set -eu
|
||||
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"; cd "$ROOT"
|
||||
|
||||
REPO="${REPO:-https://repo.gioser.net}"
|
||||
DB="${DB:-/var/lib/hammer/installed.json}"
|
||||
TRUST="${TRUST:-$ROOT/trust}"
|
||||
STATE="${STATE:-$ROOT/work/actualizaciones.json}"
|
||||
TAKANA="${TAKANA:-$ROOT/target/release/takana}"
|
||||
|
||||
[ -x "$TAKANA" ] || { echo "!! falta $TAKANA (cargo build --release)" >&2; exit 2; }
|
||||
mkdir -p "$(dirname "$STATE")"
|
||||
|
||||
NUEVO="$STATE.nuevo"
|
||||
if ! "$TAKANA" outdated --repo "$REPO" --db "$DB" --trust "$TRUST" --json >"$NUEVO" 2>"$NUEVO.err"; then
|
||||
# Un repo caído o un índice manipulado NO se resume en «al día»: se dice, y se deja el estado
|
||||
# anterior intacto para no borrar la última respuesta buena.
|
||||
echo "$(date -u +%FT%TZ) ✗ no pude preguntarle al repo $REPO:"
|
||||
sed 's/^/ /' "$NUEVO.err"
|
||||
rm -f "$NUEVO" "$NUEVO.err"
|
||||
exit 1
|
||||
fi
|
||||
rm -f "$NUEVO.err"
|
||||
|
||||
# La huella es la LISTA de novedades (nombre+versión publicada), no el JSON entero: el JSON trae
|
||||
# contadores que se mueven solos (p.ej. `no_instalados`) y harían «cambiar» un estado idéntico.
|
||||
huella() { [ -f "$1" ] || { echo ""; return; }; python3 - "$1" <<'PY'
|
||||
import json, sys
|
||||
try:
|
||||
d = json.load(open(sys.argv[1]))
|
||||
except Exception:
|
||||
print(""); raise SystemExit
|
||||
print(",".join(sorted(f"{n['name']}={n['publicada']}" for n in d.get("novedades", []))))
|
||||
PY
|
||||
}
|
||||
|
||||
ANTES="$(huella "$STATE")"
|
||||
AHORA="$(huella "$NUEVO")"
|
||||
mv "$NUEVO" "$STATE"
|
||||
|
||||
N=$(python3 -c 'import json,sys; print(len(json.load(open(sys.argv[1])).get("novedades",[])))' "$STATE")
|
||||
SELLO="$(date -u +%FT%TZ)"
|
||||
|
||||
if [ "$N" = "0" ]; then
|
||||
echo "$SELLO · al día contra $REPO"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ "$AHORA" = "$ANTES" ]; then
|
||||
echo "$SELLO · $N novedad(es), las mismas del ciclo anterior (estado en $STATE)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "$SELLO ⚠ HAY $N NOVEDAD(ES) en $REPO:"
|
||||
"$TAKANA" outdated --repo "$REPO" --db "$DB" --trust "$TRUST" | sed 's/^/ /'
|
||||
Reference in New Issue
Block a user