backup-system: --b2-hard-delete + exporter de uso real de B2

B2 tiene el mismo fallo que la papelera de MEGA con otro nombre: al
borrar/espejar no elimina, oculta la version vieja y la sigue facturando.
Las versiones ocultas llegaron al ~88% del tramo gratis de 10GB el
2026-07-25 (8.78 GiB facturados vs 1.75 GiB visibles).

- --b2-hard-delete en el sync de crown-jewels y en el delete de reddit-intel
- mega-quota-exporter ahora tambien exporta b2_visible/billed/hidden_bytes

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-25 15:17:14 +00:00
co-authored by Claude Opus 4.8
parent c33913e481
commit dab1a72e1c
2 changed files with 65 additions and 11 deletions
+6 -1
View File
@@ -267,7 +267,11 @@ data:
N=$(ls -1 "$KEEP" | wc -l) N=$(ls -1 "$KEEP" | wc -l)
log "Sync de $N artefactos crown-jewels a B2..." log "Sync de $N artefactos crown-jewels a B2..."
# -L: resuelve los symlinks; sync = espejo → la retención remota (2/servicio) es automática # -L: resuelve los symlinks; sync = espejo → la retención remota (2/servicio) es automática
# --b2-hard-delete: sin esto B2 no borra al espejar, OCULTA la versión vieja y
# la sigue facturando (mismo patrón que la papelera de MEGA). Sin el flag las
# versiones ocultas llegaron al ~88% del tramo gratis de 10GB el 2026-07-25.
rclone sync "$KEEP" b2:chemavx-k3s-backups/crown-jewels/ -L \ rclone sync "$KEEP" b2:chemavx-k3s-backups/crown-jewels/ -L \
--b2-hard-delete \
--config /rclone/rclone.conf --log-level INFO --stats 60s --config /rclone/rclone.conf --log-level INFO --stats 60s
rm -rf "$KEEP" rm -rf "$KEEP"
log "B2 crown-jewels completado ($N artefactos)." log "B2 crown-jewels completado ($N artefactos)."
@@ -292,7 +296,8 @@ data:
rclone delete mega:k3s-backups/reddit-intel/ --min-age 8d --mega-hard-delete --config /rclone/rclone.conf rclone delete mega:k3s-backups/reddit-intel/ --min-age 8d --mega-hard-delete --config /rclone/rclone.conf
log "Subiendo a B2 (crown jewels, retención 3 días)..." log "Subiendo a B2 (crown jewels, retención 3 días)..."
rclone copy "$F" b2:chemavx-k3s-backups/reddit-intel/ --config /rclone/rclone.conf --log-level INFO rclone copy "$F" b2:chemavx-k3s-backups/reddit-intel/ --config /rclone/rclone.conf --log-level INFO
rclone delete b2:chemavx-k3s-backups/reddit-intel/ --min-age 3d --config /rclone/rclone.conf # --b2-hard-delete: ver nota en b2-crown-jewels.sh (B2 oculta y factura, no borra).
rclone delete b2:chemavx-k3s-backups/reddit-intel/ --min-age 3d --b2-hard-delete --config /rclone/rclone.conf
rm -f "$F" rm -f "$F"
log "reddit-intel OK" log "reddit-intel OK"
verify.sh: | verify.sh: |
+59 -10
View File
@@ -1,4 +1,4 @@
# Exporter de la cuota de MEGA. # Exporter de la cuota de los dos offsites: MEGA y B2.
# #
# Contexto: el 2026-07-25 la papelera de MEGA (que cuenta cuota) llenó los 20GB # Contexto: el 2026-07-25 la papelera de MEGA (que cuenta cuota) llenó los 20GB
# de la cuenta y tumbó rclone-mega-backup y reddit-intel-backup con "Request # de la cuenta y tumbó rclone-mega-backup y reddit-intel-backup con "Request
@@ -9,6 +9,11 @@
# mega_trash_bytes = usado - visible: es la métrica que habría cazado aquello. # mega_trash_bytes = usado - visible: es la métrica que habría cazado aquello.
# Con --mega-hard-delete en las rotaciones debería quedarse cerca de 0; si # Con --mega-hard-delete en las rotaciones debería quedarse cerca de 0; si
# vuelve a crecer, es que algún borrado se está yendo a la papelera otra vez. # vuelve a crecer, es que algún borrado se está yendo a la papelera otra vez.
#
# B2 tiene el MISMO fallo con otro nombre: al borrar/espejar no elimina, OCULTA
# la versión vieja y la sigue facturando. El mismo día las versiones ocultas de
# B2 estaban al ~88% del tramo gratis de 10GB. b2_hidden_bytes = todas las
# versiones - visible: con --b2-hard-delete en los scripts debería quedar en ~0.
--- ---
apiVersion: v1 apiVersion: v1
kind: ConfigMap kind: ConfigMap
@@ -19,25 +24,29 @@ data:
export.sh: | export.sh: |
#!/bin/sh #!/bin/sh
# Imagen BusyBox (rclone) — sin GNU-ismos. # Imagen BusyBox (rclone) — sin GNU-ismos.
# Exporta la cuota de MEGA (papelera) y el uso REAL de B2 (versiones ocultas).
set -u set -u
CONF=/rclone/rclone.conf CONF=/rclone/rclone.conf
OUT=/metrics/metrics OUT=/metrics/metrics
INTERVAL="${INTERVAL:-900}" INTERVAL="${INTERVAL:-900}"
B2_REMOTE="b2:chemavx-k3s-backups/"
# Extrae el entero que sigue a "clave". Hay que anclar en la clave y no # Extrae el entero que sigue a "clave". Hay que anclar en la clave y no
# limpiar la línea entera: `rclone size --json` saca {"count":N,"bytes":M} # limpiar la línea entera: `rclone size --json` saca {"count":N,"bytes":M}
# en una sola línea y un sed global concatenaría los dos números. # en una sola línea y un sed global concatenaría los dos números.
num() { sed -n 's/.*"'"$1"'"[^0-9]*\([0-9][0-9]*\).*/\1/p' "$2" 2>/dev/null | head -1; } num() { sed -n 's/.*"'"$1"'"[^0-9]*\([0-9][0-9]*\).*/\1/p' "$2" 2>/dev/null | head -1; }
# Últimos valores buenos: si un scrape falla preferimos republicarlos con # Últimos valores buenos por proveedor: si un scrape falla preferimos
# success=0 antes que dejar la serie en NoData y disparar un falso positivo. # republicarlos con success=0 antes que dejar la serie en NoData (falso positivo).
L_TOTAL=""; L_USED=""; L_FREE=""; L_VB=""; L_VC="" L_TOTAL=""; L_USED=""; L_FREE=""; L_VB=""; L_VC=""
LB_VIS=""; LB_ALL=""; LB_OBJ=""
while true; do while true; do
OK=1 # --- MEGA (about da la cuota; la papelera = usado - visible) ---
rclone about mega: --json --config "$CONF" > /tmp/about.json 2>/tmp/about.err || OK=0 MOK=1
rclone size mega: --json --config "$CONF" > /tmp/size.json 2>/tmp/size.err || OK=0 rclone about mega: --json --config "$CONF" > /tmp/about.json 2>/tmp/about.err || MOK=0
rclone size mega: --json --config "$CONF" > /tmp/size.json 2>/tmp/size.err || MOK=0
TOTAL=$(num total /tmp/about.json) TOTAL=$(num total /tmp/about.json)
USED=$(num used /tmp/about.json) USED=$(num used /tmp/about.json)
@@ -46,19 +55,42 @@ data:
VC=$(num count /tmp/size.json) VC=$(num count /tmp/size.json)
for v in "$TOTAL" "$USED" "$FREE" "$VB" "$VC"; do for v in "$TOTAL" "$USED" "$FREE" "$VB" "$VC"; do
[ -n "$v" ] || OK=0 [ -n "$v" ] || MOK=0
done done
if [ "$OK" = "1" ]; then if [ "$MOK" = "1" ]; then
L_TOTAL="$TOTAL"; L_USED="$USED"; L_FREE="$FREE"; L_VB="$VB"; L_VC="$VC" L_TOTAL="$TOTAL"; L_USED="$USED"; L_FREE="$FREE"; L_VB="$VB"; L_VC="$VC"
else else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] scrape fallido: $(cat /tmp/about.err /tmp/size.err 2>/dev/null | tr '\n' ' ')" echo "[$(date '+%Y-%m-%d %H:%M:%S')] MEGA scrape fallido: $(cat /tmp/about.err /tmp/size.err 2>/dev/null | tr '\n' ' ')"
fi
# --- B2 (sin about: el tramo gratis no lo reporta. Medimos visible vs
# TODAS las versiones, que es lo que B2 factura de verdad) ---
BOK=1
rclone size "$B2_REMOTE" --json --config "$CONF" > /tmp/b2vis.json 2>/tmp/b2vis.err || BOK=0
rclone size "$B2_REMOTE" --b2-versions --json --config "$CONF" > /tmp/b2all.json 2>/tmp/b2all.err || BOK=0
BVIS=$(num bytes /tmp/b2vis.json)
BALL=$(num bytes /tmp/b2all.json)
BOBJ=$(num count /tmp/b2vis.json)
for v in "$BVIS" "$BALL" "$BOBJ"; do
[ -n "$v" ] || BOK=0
done
if [ "$BOK" = "1" ]; then
LB_VIS="$BVIS"; LB_ALL="$BALL"; LB_OBJ="$BOBJ"
else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] B2 scrape fallido: $(cat /tmp/b2vis.err /tmp/b2all.err 2>/dev/null | tr '\n' ' ')"
fi fi
{ {
echo "# HELP mega_quota_scrape_success 1 si el ultimo sondeo a MEGA funciono." echo "# HELP mega_quota_scrape_success 1 si el ultimo sondeo a MEGA funciono."
echo "# TYPE mega_quota_scrape_success gauge" echo "# TYPE mega_quota_scrape_success gauge"
echo "mega_quota_scrape_success $OK" echo "mega_quota_scrape_success $MOK"
echo "# HELP b2_scrape_success 1 si el ultimo sondeo a B2 funciono."
echo "# TYPE b2_scrape_success gauge"
echo "b2_scrape_success $BOK"
echo "# HELP mega_quota_last_scrape_timestamp_seconds Momento del ultimo sondeo." echo "# HELP mega_quota_last_scrape_timestamp_seconds Momento del ultimo sondeo."
echo "# TYPE mega_quota_last_scrape_timestamp_seconds gauge" echo "# TYPE mega_quota_last_scrape_timestamp_seconds gauge"
echo "mega_quota_last_scrape_timestamp_seconds $(date +%s)" echo "mega_quota_last_scrape_timestamp_seconds $(date +%s)"
@@ -85,6 +117,23 @@ data:
echo "# TYPE mega_trash_bytes gauge" echo "# TYPE mega_trash_bytes gauge"
echo "mega_trash_bytes $TRASH" echo "mega_trash_bytes $TRASH"
fi fi
if [ -n "$LB_ALL" ]; then
BHID=$((LB_ALL - LB_VIS))
[ "$BHID" -lt 0 ] && BHID=0
echo "# HELP b2_visible_bytes Tamano de los ficheros visibles en B2."
echo "# TYPE b2_visible_bytes gauge"
echo "b2_visible_bytes $LB_VIS"
echo "# HELP b2_billed_bytes Tamano real facturado por B2 (todas las versiones)."
echo "# TYPE b2_billed_bytes gauge"
echo "b2_billed_bytes $LB_ALL"
echo "# HELP b2_hidden_bytes Versiones ocultas/antiguas (facturado - visible)."
echo "# TYPE b2_hidden_bytes gauge"
echo "b2_hidden_bytes $BHID"
echo "# HELP b2_visible_objects Numero de ficheros visibles en B2."
echo "# TYPE b2_visible_objects gauge"
echo "b2_visible_objects $LB_OBJ"
fi
} > "${OUT}.tmp" && mv "${OUT}.tmp" "$OUT" } > "${OUT}.tmp" && mv "${OUT}.tmp" "$OUT"
sleep "$INTERVAL" sleep "$INTERVAL"