apiVersion: v1 data: backup.sh: "#!/bin/sh\nset -e\n\nBACKUP_DIR=\"/backups\"\nDATE=$(date +%Y-%m-%d_%H-%M-%S)\n\ RETENTION_DAYS=7\n\necho \"==========================================\"\necho\ \ \"Backup iniciado: $DATE\"\necho \"==========================================\"\ \n\nbackup_dir() {\n NAME=$1\n SRC=$2\n\n if [ ! -d \"$SRC\" ]; then\n echo\ \ \"[WARN] $NAME: directorio $SRC no encontrado, omitiendo.\"\n return\n fi\n\ \n DEST=\"$BACKUP_DIR/${NAME}_${DATE}.tar.gz\"\n echo \"[INFO] Comprimiendo\ \ $NAME ($SRC) \u2192 $DEST\"\n tar -czf \"$DEST\" -C \"$(dirname $SRC)\" \"\ $(basename $SRC)\"\n SIZE=$(du -sh \"$DEST\" | cut -f1)\n echo \"[OK] $NAME\ \ backup completado. Tamano: $SIZE\"\n}\n\nbackup_dir \"n8n\" \"/src/n8n\"\ \nbackup_dir \"openclaw\" \"/src/openclaw\"\nbackup_dir \"agent-ia\" \"\ /src/agent-ia\"\nbackup_dir \"agente-data\" \"/src/agente-data\"\nbackup_dir\ \ \"authentik-pg\" \"/src/authentik-pg\"\nbackup_dir \"homarr\" \"/src/homarr\"\ \nbackup_dir \"grafana\" \"/src/grafana\"\n\necho \"\"\necho \"--- Limpiando\ \ backups con mas de $RETENTION_DAYS dias ---\"\nfind \"$BACKUP_DIR\" -name \"\ *.tar.gz\" -mtime +${RETENTION_DAYS} -print -delete\necho \"\"\n\necho \"--- Backups\ \ actuales en $BACKUP_DIR ---\"\nls -lh \"$BACKUP_DIR\"/*.tar.gz 2>/dev/null ||\ \ echo \"(ninguno aun)\"\n\necho \"\"\necho \"Backup finalizado: $(date +%Y-%m-%d_%H-%M-%S)\"\ \n" kind: ConfigMap metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: "{\"apiVersion\":\"v1\",\"data\"\ :{\"backup.sh\":\"#!/bin/sh\\nset -e\\n\\nBACKUP_DIR=\\\"/backups\\\"\\nDATE=$(date\ \ +%Y-%m-%d_%H-%M-%S)\\nRETENTION_DAYS=7\\n\\necho \\\"==========================================\\\ \"\\necho \\\"Backup iniciado: $DATE\\\"\\necho \\\"==========================================\\\ \"\\n\\nbackup_dir() {\\n NAME=$1\\n SRC=$2\\n\\n if [ ! -d \\\"$SRC\\\"\ \ ]; then\\n echo \\\"[WARN] $NAME: directorio $SRC no encontrado, omitiendo.\\\ \"\\n return\\n fi\\n\\n DEST=\\\"$BACKUP_DIR/${NAME}_${DATE}.tar.gz\\\"\ \\n echo \\\"[INFO] Comprimiendo $NAME ($SRC) \u2192 $DEST\\\"\\n tar -czf\ \ \\\"$DEST\\\" -C \\\"$(dirname $SRC)\\\" \\\"$(basename $SRC)\\\"\\n SIZE=$(du\ \ -sh \\\"$DEST\\\" | cut -f1)\\n echo \\\"[OK] $NAME backup completado.\ \ Tama\xF1o: $SIZE\\\"\\n}\\n\\nbackup_dir \\\"n8n\\\" \\\"/src/n8n\\\ \"\\nbackup_dir \\\"openclaw\\\" \\\"/src/openclaw\\\"\\nbackup_dir \\\"\ agent-ia\\\" \\\"/src/agent-ia\\\"\\nbackup_dir \\\"agente-data\\\" \\\"\ /src/agente-data\\\"\\n\\necho \\\"\\\"\\necho \\\"--- Limpiando backups con\ \ m\xE1s de $RETENTION_DAYS d\xEDas ---\\\"\\nfind \\\"$BACKUP_DIR\\\" -name\ \ \\\"*.tar.gz\\\" -mtime +${RETENTION_DAYS} -print -delete\\necho \\\"\\\"\\\ n\\necho \\\"--- Backups actuales en $BACKUP_DIR ---\\\"\\nls -lh \\\"$BACKUP_DIR\\\ \"/*.tar.gz 2\\u003e/dev/null || echo \\\"(ninguno a\xFAn)\\\"\\n\\necho \\\"\ \\\"\\necho \\\"Backup finalizado: $(date +%Y-%m-%d_%H-%M-%S)\\\"\\n\"},\"kind\"\ :\"ConfigMap\",\"metadata\":{\"annotations\":{},\"name\":\"backup-scripts\"\ ,\"namespace\":\"backup-system\"}}\n" name: backup-scripts namespace: backup-system --- apiVersion: v1 data: verify.sh: "#!/bin/sh\nset -e\n\nBOT_TOKEN=\"8611913802:AAFlrFtc0vYISOliO_W8B4c-W1ue0hG9Fio\"\ \nCHAT_ID=\"5138407666\"\nBACKUP_DIR=\"/backups\"\nERRORS=\"\"\nREPORT=\"\"\n\n\ send_telegram() {\n MSG=\"$1\"\n wget -qO- \"https://api.telegram.org/bot${BOT_TOKEN}/sendMessage\"\ \ \\\n --post-data=\"chat_id=${CHAT_ID}&text=${MSG}&parse_mode=Markdown\" >\ \ /dev/null 2>&1 || true\n}\n\n# \u2500\u2500 1. Verificar backups locales \u2500\ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ \u2500\nREPORT=\"${REPORT}*Verificaci\xF3n Backups \u2014 $(date +%Y-%m-%d)*\\\ n\\n\"\nREPORT=\"${REPORT}\U0001F4C2 *Backups locales:*\\n\"\n\nfor SERVICE in\ \ n8n openclaw agent-ia agente-data authentik-pg homarr grafana; do\n LATEST=$(ls\ \ -t \"${BACKUP_DIR}/${SERVICE}_\"*.tar.gz 2>/dev/null | head -1)\n if [ -z \"\ $LATEST\" ]; then\n REPORT=\"${REPORT}\u274C ${SERVICE}: no encontrado\\n\"\ \n ERRORS=\"${ERRORS}${SERVICE}:missing \"\n continue\n fi\n AGE_DAYS=$((\ \ ( $(date +%s) - $(date -r \"$LATEST\" +%s) ) / 86400 ))\n if [ \"$AGE_DAYS\"\ \ -gt 2 ]; then\n REPORT=\"${REPORT}\u26A0\uFE0F ${SERVICE}: antiguo (${AGE_DAYS}d)\\\ n\"\n ERRORS=\"${ERRORS}${SERVICE}:old \"\n continue\n fi\n # Verificar\ \ integridad\n if tar -tzf \"$LATEST\" > /dev/null 2>&1; then\n SIZE=$(du\ \ -sh \"$LATEST\" | cut -f1)\n REPORT=\"${REPORT}\u2705 ${SERVICE}: OK (${SIZE},\ \ ${AGE_DAYS}d)\\n\"\n else\n REPORT=\"${REPORT}\u274C ${SERVICE}: CORRUPTO\\\ n\"\n ERRORS=\"${ERRORS}${SERVICE}:corrupt \"\n fi\ndone\n\n# \u2500\u2500\ \ 2. Verificar backup en Mega \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nREPORT=\"${REPORT}\\n\u2601\uFE0F\ \ *Backup Mega:*\\n\"\n\n# Configurar rclone con credenciales del secret (montadas\ \ como env)\nMEGA_PASS_OBF=$(rclone obscure \"$MEGA_PASSWORD\")\nmkdir -p /root/.config/rclone\n\ cat > /root/.config/rclone/rclone.conf << RCLEOF\n[mega]\ntype = mega\nuser =\ \ ${MEGA_USER}\npass = ${MEGA_PASS_OBF}\nRCLEOF\n\nMEGA_FILES=$(rclone lsf mega:k3s-backups/\ \ 2>/dev/null | grep \"backup-k3s-\" | sort | tail -3)\nif [ -z \"$MEGA_FILES\"\ \ ]; then\n REPORT=\"${REPORT}\u274C Sin backups en Mega\\n\"\n ERRORS=\"${ERRORS}mega:missing\ \ \"\nelse\n LATEST_MEGA=$(echo \"$MEGA_FILES\" | tail -1)\n MEGA_DATE=$(echo\ \ \"$LATEST_MEGA\" | grep -oE '[0-9]{4}-[0-9]{2}-[0-9]{2}' | head -1)\n REPORT=\"\ ${REPORT}\u2705 \xDAltimo: ${LATEST_MEGA}\\n\"\nfi\n\n# \u2500\u2500 3. Enviar\ \ resumen \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ \u2500\nif [ -n \"$ERRORS\" ]; then\n HEADER=\"\u274C *BACKUP ALERT \u2014 Problemas\ \ detectados*\\n\"\nelse\n HEADER=\"\u2705 *Backups OK*\\n\"\nfi\n\nFULL_MSG=\"\ ${HEADER}${REPORT}\"\nsend_telegram \"$FULL_MSG\"\n\necho \"Verificaci\xF3n completada.\ \ Errores: ${ERRORS:-ninguno}\"\n[ -z \"$ERRORS\" ] || exit 1\n" kind: ConfigMap metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: "{\"apiVersion\":\"v1\",\"data\"\ :{\"verify.sh\":\"#!/bin/sh\\nset -e\\n\\nBOT_TOKEN=\\\"8611913802:AAFlrFtc0vYISOliO_W8B4c-W1ue0hG9Fio\\\ \"\\nCHAT_ID=\\\"5138407666\\\"\\nBACKUP_DIR=\\\"/backups\\\"\\nERRORS=\\\"\\\ \"\\nREPORT=\\\"\\\"\\n\\nsend_telegram() {\\n MSG=\\\"$1\\\"\\n wget -qO-\ \ \\\"https://api.telegram.org/bot${BOT_TOKEN}/sendMessage\\\" \\\\\\n --post-data=\\\ \"chat_id=${CHAT_ID}\\u0026text=${MSG}\\u0026parse_mode=Markdown\\\" \\u003e\ \ /dev/null 2\\u003e\\u00261 || true\\n}\\n\\n# \u2500\u2500 1. Verificar backups\ \ locales \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ \u2500\u2500\u2500\u2500\\nREPORT=\\\"${REPORT}*Verificaci\xF3n Backups \u2014\ \ $(date +%Y-%m-%d)*\\\\n\\\\n\\\"\\nREPORT=\\\"${REPORT}\U0001F4C2 *Backups\ \ locales:*\\\\n\\\"\\n\\nfor SERVICE in n8n openclaw agent-ia agente-data authentik-pg\ \ homarr grafana; do\\n LATEST=$(ls -t \\\"${BACKUP_DIR}/${SERVICE}_\\\"*.tar.gz\ \ 2\\u003e/dev/null | head -1)\\n if [ -z \\\"$LATEST\\\" ]; then\\n REPORT=\\\ \"${REPORT}\u274C ${SERVICE}: no encontrado\\\\n\\\"\\n ERRORS=\\\"${ERRORS}${SERVICE}:missing\ \ \\\"\\n continue\\n fi\\n AGE_DAYS=$(( ( $(date +%s) - $(date -r \\\"\ $LATEST\\\" +%s) ) / 86400 ))\\n if [ \\\"$AGE_DAYS\\\" -gt 2 ]; then\\n \ \ REPORT=\\\"${REPORT}\u26A0\uFE0F ${SERVICE}: antiguo (${AGE_DAYS}d)\\\\n\\\ \"\\n ERRORS=\\\"${ERRORS}${SERVICE}:old \\\"\\n continue\\n fi\\n #\ \ Verificar integridad\\n if tar -tzf \\\"$LATEST\\\" \\u003e /dev/null 2\\\ u003e\\u00261; then\\n SIZE=$(du -sh \\\"$LATEST\\\" | cut -f1)\\n REPORT=\\\ \"${REPORT}\u2705 ${SERVICE}: OK (${SIZE}, ${AGE_DAYS}d)\\\\n\\\"\\n else\\\ n REPORT=\\\"${REPORT}\u274C ${SERVICE}: CORRUPTO\\\\n\\\"\\n ERRORS=\\\ \"${ERRORS}${SERVICE}:corrupt \\\"\\n fi\\ndone\\n\\n# \u2500\u2500 2. Verificar\ \ backup en Mega \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ \u2500\u2500\u2500\u2500\u2500\u2500\\nREPORT=\\\"${REPORT}\\\\n\u2601\uFE0F\ \ *Backup Mega:*\\\\n\\\"\\n\\n# Configurar rclone con credenciales del secret\ \ (montadas como env)\\nMEGA_PASS_OBF=$(rclone obscure \\\"$MEGA_PASSWORD\\\"\ )\\nmkdir -p /root/.config/rclone\\ncat \\u003e /root/.config/rclone/rclone.conf\ \ \\u003c\\u003c RCLEOF\\n[mega]\\ntype = mega\\nuser = ${MEGA_USER}\\npass\ \ = ${MEGA_PASS_OBF}\\nRCLEOF\\n\\nMEGA_FILES=$(rclone lsf mega:k3s-backups/\ \ 2\\u003e/dev/null | grep \\\"backup-k3s-\\\" | sort | tail -3)\\nif [ -z \\\ \"$MEGA_FILES\\\" ]; then\\n REPORT=\\\"${REPORT}\u274C Sin backups en Mega\\\ \\n\\\"\\n ERRORS=\\\"${ERRORS}mega:missing \\\"\\nelse\\n LATEST_MEGA=$(echo\ \ \\\"$MEGA_FILES\\\" | tail -1)\\n MEGA_DATE=$(echo \\\"$LATEST_MEGA\\\" |\ \ grep -oE '[0-9]{4}-[0-9]{2}-[0-9]{2}' | head -1)\\n REPORT=\\\"${REPORT}\u2705\ \ \xDAltimo: ${LATEST_MEGA}\\\\n\\\"\\nfi\\n\\n# \u2500\u2500 3. Enviar resumen\ \ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\ \\nif [ -n \\\"$ERRORS\\\" ]; then\\n HEADER=\\\"\u274C *BACKUP ALERT \u2014\ \ Problemas detectados*\\\\n\\\"\\nelse\\n HEADER=\\\"\u2705 *Backups OK*\\\ \\n\\\"\\nfi\\n\\nFULL_MSG=\\\"${HEADER}${REPORT}\\\"\\nsend_telegram \\\"$FULL_MSG\\\ \"\\n\\necho \\\"Verificaci\xF3n completada. Errores: ${ERRORS:-ninguno}\\\"\ \\n[ -z \\\"$ERRORS\\\" ] || exit 1\\n\"},\"kind\":\"ConfigMap\",\"metadata\"\ :{\"annotations\":{},\"name\":\"backup-verify-script\",\"namespace\":\"backup-system\"\ }}\n" name: backup-verify-script namespace: backup-system --- apiVersion: v1 data: backup-mega.sh: "#!/bin/sh\nset -e\n\nDATE=$(date +%Y-%m-%d)\nBACKUP_FILE=\"/tmp/backup-k3s-${DATE}.tar.gz\"\ \n\necho \"=== Rclone Mega Backup - ${DATE} ===\"\n\n# Generar rclone config con\ \ password ofuscado\nMEGA_PASS_OBF=$(rclone obscure \"$MEGA_PASSWORD\")\nmkdir\ \ -p /root/.config/rclone\ncat > /root/.config/rclone/rclone.conf << EOF\n[mega]\n\ type = mega\nuser = ${MEGA_USER}\npass = ${MEGA_PASS_OBF}\nEOF\n\n# Comprimir\ \ /data/backups\necho \"Comprimiendo /data/backups...\"\ntar -czf \"$BACKUP_FILE\"\ \ -C /data backups/\nSIZE=$(du -sh \"$BACKUP_FILE\" | cut -f1)\necho \"Archivo\ \ generado: $BACKUP_FILE ($SIZE)\"\n\n# Crear carpeta destino en Mega si no existe\n\ rclone mkdir mega:k3s-backups/ 2>/dev/null || true\n\n# Subir a Mega\necho \"\ Subiendo a Mega...\"\nrclone copy \"$BACKUP_FILE\" mega:k3s-backups/ --progress\n\ echo \"Upload completado.\"\n\n# Limpiar archivo temporal\nrm -f \"$BACKUP_FILE\"\ \n\n# Retenci\xF3n: mantener solo las \xFAltimas 4 semanas\necho \"Aplicando retenci\xF3\ n (m\xE1ximo 4 backups)...\"\nFILES=$(rclone lsf mega:k3s-backups/ | sort)\nCOUNT=$(echo\ \ \"$FILES\" | grep -c . || true)\necho \"Backups en Mega: $COUNT\"\n\nif [ \"\ $COUNT\" -gt 4 ]; then\n TO_DELETE=$((COUNT - 4))\n echo \"Eliminando $TO_DELETE\ \ backup(s) antiguo(s)...\"\n echo \"$FILES\" | head -n \"$TO_DELETE\" | while\ \ IFS= read -r f; do\n echo \" Borrando: $f\"\n rclone deletefile \"mega:k3s-backups/$f\"\ \n done\nfi\n\necho \"=== Backup a Mega finalizado - $(date) ===\"\n" kind: ConfigMap metadata: annotations: kubectl.kubernetes.io/last-applied-configuration: "{\"apiVersion\":\"v1\",\"data\"\ :{\"backup-mega.sh\":\"#!/bin/sh\\nset -e\\n\\nDATE=$(date +%Y-%m-%d)\\nBACKUP_FILE=\\\ \"/tmp/backup-k3s-${DATE}.tar.gz\\\"\\n\\necho \\\"=== Rclone Mega Backup -\ \ ${DATE} ===\\\"\\n\\n# Generar rclone config con password ofuscado\\nMEGA_PASS_OBF=$(rclone\ \ obscure \\\"$MEGA_PASSWORD\\\")\\nmkdir -p /root/.config/rclone\\ncat \\u003e\ \ /root/.config/rclone/rclone.conf \\u003c\\u003c EOF\\n[mega]\\ntype = mega\\\ nuser = ${MEGA_USER}\\npass = ${MEGA_PASS_OBF}\\nEOF\\n\\n# Comprimir /data/backups\\\ necho \\\"Comprimiendo /data/backups...\\\"\\ntar -czf \\\"$BACKUP_FILE\\\"\ \ -C /data backups/\\nSIZE=$(du -sh \\\"$BACKUP_FILE\\\" | cut -f1)\\necho \\\ \"Archivo generado: $BACKUP_FILE ($SIZE)\\\"\\n\\n# Crear carpeta destino en\ \ Mega si no existe\\nrclone mkdir mega:k3s-backups/ 2\\u003e/dev/null || true\\\ n\\n# Subir a Mega\\necho \\\"Subiendo a Mega...\\\"\\nrclone copy \\\"$BACKUP_FILE\\\ \" mega:k3s-backups/ --progress\\necho \\\"Upload completado.\\\"\\n\\n# Limpiar\ \ archivo temporal\\nrm -f \\\"$BACKUP_FILE\\\"\\n\\n# Retenci\xF3n: mantener\ \ solo las \xFAltimas 4 semanas\\necho \\\"Aplicando retenci\xF3n (m\xE1ximo\ \ 4 backups)...\\\"\\nFILES=$(rclone lsf mega:k3s-backups/ | sort)\\nCOUNT=$(echo\ \ \\\"$FILES\\\" | grep -c . || true)\\necho \\\"Backups en Mega: $COUNT\\\"\ \\n\\nif [ \\\"$COUNT\\\" -gt 4 ]; then\\n TO_DELETE=$((COUNT - 4))\\n echo\ \ \\\"Eliminando $TO_DELETE backup(s) antiguo(s)...\\\"\\n echo \\\"$FILES\\\ \" | head -n \\\"$TO_DELETE\\\" | while IFS= read -r f; do\\n echo \\\" \ \ Borrando: $f\\\"\\n rclone deletefile \\\"mega:k3s-backups/$f\\\"\\n done\\\ nfi\\n\\necho \\\"=== Backup a Mega finalizado - $(date) ===\\\"\\n\"},\"kind\"\ :\"ConfigMap\",\"metadata\":{\"annotations\":{},\"name\":\"rclone-mega-script\"\ ,\"namespace\":\"backup-system\"}}\n" name: rclone-mega-script namespace: backup-system