updates-flow.sh
· 8.9 KiB · Bash
Brut
#!/usr/bin/env bash
# ═══════════════════════════════════════════════════════════════════════════
# updates-flow.sh — Demo del flujo de actualización de alloy
# Para el Episodio #834 — atareao con Linux
# ═══════════════════════════════════════════════════════════════════════════
# Muestra el flujo completo: check-all → digest compare → policy apply → SSE
# ═══════════════════════════════════════════════════════════════════════════
set -e
VERDE='\033[0;32m'
AMARILLO='\033[1;33m'
AZUL='\033[0;34m'
ROJO='\033[0;31m'
GRIS='\033[0;90m'
NC='\033[0m'
echo -e "${AZUL}╔══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${AZUL}║ 🔄 alloy — Flujo de actualización ║${NC}"
echo -e "${AZUL}║ Fase 1: Check (bloqueante, devuelve respuesta) ║${NC}"
echo -e "${AZUL}║ Fase 2: Policy apply (background, SSE progress) ║${NC}"
echo -e "${AZUL}╚══════════════════════════════════════════════════════════════╝${NC}"
echo ""
# ── Fase 1: Check ────────────────────────────────────────────────────────
echo -e "${VERDE}═══ Fase 1: Check All ═══${NC}"
echo ""
echo -e "${GRIS}El backend:${NC}"
echo " 1. Obtiene todos los contenedores (fetch_containers)"
echo " 2. Para cada contenedor (en paralelo, semáforo 4 conexiones):"
echo " a. Parsear referencia de imagen → (registry, repo, tag)"
echo " b. Solicitar token Bearer a auth.docker.io"
echo " c. Consultar manifest en registry-1.docker.io/v2/{repo}/manifests/{tag}"
echo " d. Extraer config.digest del manifest"
echo " e. Comparar short_digest(local) vs short_digest(remote)"
echo " 3. Persistir has_update en SQLite"
echo " 4. Construir lista de pendientes"
echo " 5. Lanzar apply_policies_background en tokio::spawn"
echo " 6. Devolver respuesta JSON con has_update flags"
echo ""
# ── Fase 2: Policy Apply ─────────────────────────────────────────────────
echo -e "${VERDE}═══ Fase 2: Policy Apply (background) ═══${NC}"
echo ""
echo -e "${GRIS}Para cada contenedor pendiente:${NC}"
echo ""
echo " ┌─ [PullRestart] ──────────────────────────────────────────────┐"
echo " │ 1. tag_backup_image() (si rollback_on_failure=true) │"
echo " │ 2. pull_image() → docker.create_image() │"
echo " │ 3. recreate_container() → stop + rename + create + start │"
echo " │ 4. verify_container_healthy() (si rollback) │"
echo " │ ├── OK → continue │"
echo " │ └── FAIL → rollback_container() (restaurar imagen) │"
echo " │ 5. cleanup_old_image() (si cleanup_old_image=true) │"
echo " └──────────────────────────────────────────────────────────────┘"
echo ""
echo " ┌─ [PullRestartStack] ─────────────────────────────────────────┐"
echo " │ 1. resolve_compose_file() → labels del contenedor │"
echo " │ 2. docker compose -f <file> pull │"
echo " │ 3. docker compose -f <file> up -d │"
echo " └──────────────────────────────────────────────────────────────┘"
echo ""
echo " ┌─ [Pull] ─────────────────────────────────────────────────────┐"
echo " │ 1. pull_image() → solo descargar, sin reiniciar │"
echo " └──────────────────────────────────────────────────────────────┘"
echo ""
# ── Políticas ────────────────────────────────────────────────────────────
echo -e "${VERDE}═══ Políticas de actualización ═══${NC}"
echo ""
printf " %-25s %s\n" "None" "No hacer nada"
printf " %-25s %s\n" "Pull" "Solo descargar imagen"
printf " %-25s %s\n" "PullRestart" "Descargar + reiniciar contenedor"
printf " %-25s %s\n" "PullRestartStack" "Descargar + recrear stack completo"
echo ""
# ── Resolución de políticas ──────────────────────────────────────────────
echo -e "${VERDE}═══ Resolución de políticas ═══${NC}"
echo ""
echo " 1. Se mira el label del contenedor (alloy_update_policy)"
echo " 2. Si no tiene label, se busca en update_policies (SQLite)"
echo " 3. Si no hay política específica, se usa la política global (settings)"
echo " 4. PullRestartStack resuelve el archivo compose desde los labels:"
echo " a. com.docker.compose.project → nombre del proyecto"
echo " b. com.docker.compose.config.files → ruta al compose file"
echo " c. com.docker.compose.working_dir → directorio del proyecto"
echo ""
# ── Rollback ─────────────────────────────────────────────────────────────
echo -e "${VERDE}═══ Rollback automático ═══${NC}"
echo ""
echo -e "${GRIS}Si rollback_on_failure=true y el contenedor no arranca:${NC}"
echo ""
echo " 1. tag_backup_image() → etiqueta la imagen actual como backup"
echo " 2. pull_image() → descarga la nueva imagen"
echo " 3. recreate_container() → crea contenedor con nueva imagen"
echo " 4. verify_container_healthy() → espera a que responda"
echo " ├── OK → todo bien, cleanup de imagen anterior"
echo " └── FAIL → rollback:"
echo " ├── remove contenedor nuevo"
echo " ├── restaurar nombre del backup"
echo " ├── restart contenedor con imagen anterior"
echo " └── notificar fallo"
echo ""
# ── SSE Progress ─────────────────────────────────────────────────────────
echo -e "${VERDE}═══ SSE Progress (tiempo real) ═══${NC}"
echo ""
echo -e "${GRIS}Eventos emitidos durante el proceso:${NC}"
echo ""
echo " event: update-progress"
echo " data: {\"container\":\"nginx\",\"status\":\"🔍 PullRestart\",\"done\":false}"
echo ""
echo " event: update-progress"
echo " data: {\"container\":\"nginx\",\"status\":\"📥 Pulling...\",\"done\":false}"
echo ""
echo " event: update-progress"
echo " data: {\"container\":\"nginx\",\"status\":\"✅ actualizado + reiniciado\",\"done\":true}"
echo ""
echo " event: notification"
echo " data: {\"container\":\"nginx\",\"status\":\"🔄 actualizado\",\"timestamp\":\"2026-08-29T12:00:00Z\"}"
echo ""
# ── Comandos curl ────────────────────────────────────────────────────────
echo -e "${VERDE}═══ Comandos para probar ═══${NC}"
echo ""
echo " # Check individual"
echo " curl -X POST http://localhost:3066/api/check-update/nginx \\"
echo " -H \"Cookie: session=TU_TOKEN\""
echo ""
echo " # Update individual"
echo " curl -X POST http://localhost:3066/api/update/nginx \\"
echo " -H \"Cookie: session=TU_TOKEN\""
echo ""
echo " # Check All (masivo)"
echo " curl -X POST http://localhost:3066/api/check-all \\"
echo " -H \"Cookie: session=TU_TOKEN\""
echo ""
echo " # SSE updates (tiempo real)"
echo " curl -N http://localhost:3066/api/updates \\"
echo " -H \"Cookie: session=TU_TOKEN\""
echo ""
echo " # Historial"
echo " curl http://localhost:3066/api/history \\"
echo " -H \"Cookie: session=TU_TOKEN\""
echo ""
| 1 | #!/usr/bin/env bash |
| 2 | # ═══════════════════════════════════════════════════════════════════════════ |
| 3 | # updates-flow.sh — Demo del flujo de actualización de alloy |
| 4 | # Para el Episodio #834 — atareao con Linux |
| 5 | # ═══════════════════════════════════════════════════════════════════════════ |
| 6 | # Muestra el flujo completo: check-all → digest compare → policy apply → SSE |
| 7 | # ═══════════════════════════════════════════════════════════════════════════ |
| 8 | |
| 9 | set -e |
| 10 | |
| 11 | VERDE='\033[0;32m' |
| 12 | AMARILLO='\033[1;33m' |
| 13 | AZUL='\033[0;34m' |
| 14 | ROJO='\033[0;31m' |
| 15 | GRIS='\033[0;90m' |
| 16 | NC='\033[0m' |
| 17 | |
| 18 | echo -e "${AZUL}╔══════════════════════════════════════════════════════════════╗${NC}" |
| 19 | echo -e "${AZUL}║ 🔄 alloy — Flujo de actualización ║${NC}" |
| 20 | echo -e "${AZUL}║ Fase 1: Check (bloqueante, devuelve respuesta) ║${NC}" |
| 21 | echo -e "${AZUL}║ Fase 2: Policy apply (background, SSE progress) ║${NC}" |
| 22 | echo -e "${AZUL}╚══════════════════════════════════════════════════════════════╝${NC}" |
| 23 | echo "" |
| 24 | |
| 25 | # ── Fase 1: Check ──────────────────────────────────────────────────────── |
| 26 | echo -e "${VERDE}═══ Fase 1: Check All ═══${NC}" |
| 27 | echo "" |
| 28 | echo -e "${GRIS}El backend:${NC}" |
| 29 | echo " 1. Obtiene todos los contenedores (fetch_containers)" |
| 30 | echo " 2. Para cada contenedor (en paralelo, semáforo 4 conexiones):" |
| 31 | echo " a. Parsear referencia de imagen → (registry, repo, tag)" |
| 32 | echo " b. Solicitar token Bearer a auth.docker.io" |
| 33 | echo " c. Consultar manifest en registry-1.docker.io/v2/{repo}/manifests/{tag}" |
| 34 | echo " d. Extraer config.digest del manifest" |
| 35 | echo " e. Comparar short_digest(local) vs short_digest(remote)" |
| 36 | echo " 3. Persistir has_update en SQLite" |
| 37 | echo " 4. Construir lista de pendientes" |
| 38 | echo " 5. Lanzar apply_policies_background en tokio::spawn" |
| 39 | echo " 6. Devolver respuesta JSON con has_update flags" |
| 40 | echo "" |
| 41 | |
| 42 | # ── Fase 2: Policy Apply ───────────────────────────────────────────────── |
| 43 | echo -e "${VERDE}═══ Fase 2: Policy Apply (background) ═══${NC}" |
| 44 | echo "" |
| 45 | echo -e "${GRIS}Para cada contenedor pendiente:${NC}" |
| 46 | echo "" |
| 47 | echo " ┌─ [PullRestart] ──────────────────────────────────────────────┐" |
| 48 | echo " │ 1. tag_backup_image() (si rollback_on_failure=true) │" |
| 49 | echo " │ 2. pull_image() → docker.create_image() │" |
| 50 | echo " │ 3. recreate_container() → stop + rename + create + start │" |
| 51 | echo " │ 4. verify_container_healthy() (si rollback) │" |
| 52 | echo " │ ├── OK → continue │" |
| 53 | echo " │ └── FAIL → rollback_container() (restaurar imagen) │" |
| 54 | echo " │ 5. cleanup_old_image() (si cleanup_old_image=true) │" |
| 55 | echo " └──────────────────────────────────────────────────────────────┘" |
| 56 | echo "" |
| 57 | echo " ┌─ [PullRestartStack] ─────────────────────────────────────────┐" |
| 58 | echo " │ 1. resolve_compose_file() → labels del contenedor │" |
| 59 | echo " │ 2. docker compose -f <file> pull │" |
| 60 | echo " │ 3. docker compose -f <file> up -d │" |
| 61 | echo " └──────────────────────────────────────────────────────────────┘" |
| 62 | echo "" |
| 63 | echo " ┌─ [Pull] ─────────────────────────────────────────────────────┐" |
| 64 | echo " │ 1. pull_image() → solo descargar, sin reiniciar │" |
| 65 | echo " └──────────────────────────────────────────────────────────────┘" |
| 66 | echo "" |
| 67 | |
| 68 | # ── Políticas ──────────────────────────────────────────────────────────── |
| 69 | echo -e "${VERDE}═══ Políticas de actualización ═══${NC}" |
| 70 | echo "" |
| 71 | printf " %-25s %s\n" "None" "No hacer nada" |
| 72 | printf " %-25s %s\n" "Pull" "Solo descargar imagen" |
| 73 | printf " %-25s %s\n" "PullRestart" "Descargar + reiniciar contenedor" |
| 74 | printf " %-25s %s\n" "PullRestartStack" "Descargar + recrear stack completo" |
| 75 | echo "" |
| 76 | |
| 77 | # ── Resolución de políticas ────────────────────────────────────────────── |
| 78 | echo -e "${VERDE}═══ Resolución de políticas ═══${NC}" |
| 79 | echo "" |
| 80 | echo " 1. Se mira el label del contenedor (alloy_update_policy)" |
| 81 | echo " 2. Si no tiene label, se busca en update_policies (SQLite)" |
| 82 | echo " 3. Si no hay política específica, se usa la política global (settings)" |
| 83 | echo " 4. PullRestartStack resuelve el archivo compose desde los labels:" |
| 84 | echo " a. com.docker.compose.project → nombre del proyecto" |
| 85 | echo " b. com.docker.compose.config.files → ruta al compose file" |
| 86 | echo " c. com.docker.compose.working_dir → directorio del proyecto" |
| 87 | echo "" |
| 88 | |
| 89 | # ── Rollback ───────────────────────────────────────────────────────────── |
| 90 | echo -e "${VERDE}═══ Rollback automático ═══${NC}" |
| 91 | echo "" |
| 92 | echo -e "${GRIS}Si rollback_on_failure=true y el contenedor no arranca:${NC}" |
| 93 | echo "" |
| 94 | echo " 1. tag_backup_image() → etiqueta la imagen actual como backup" |
| 95 | echo " 2. pull_image() → descarga la nueva imagen" |
| 96 | echo " 3. recreate_container() → crea contenedor con nueva imagen" |
| 97 | echo " 4. verify_container_healthy() → espera a que responda" |
| 98 | echo " ├── OK → todo bien, cleanup de imagen anterior" |
| 99 | echo " └── FAIL → rollback:" |
| 100 | echo " ├── remove contenedor nuevo" |
| 101 | echo " ├── restaurar nombre del backup" |
| 102 | echo " ├── restart contenedor con imagen anterior" |
| 103 | echo " └── notificar fallo" |
| 104 | echo "" |
| 105 | |
| 106 | # ── SSE Progress ───────────────────────────────────────────────────────── |
| 107 | echo -e "${VERDE}═══ SSE Progress (tiempo real) ═══${NC}" |
| 108 | echo "" |
| 109 | echo -e "${GRIS}Eventos emitidos durante el proceso:${NC}" |
| 110 | echo "" |
| 111 | echo " event: update-progress" |
| 112 | echo " data: {\"container\":\"nginx\",\"status\":\"🔍 PullRestart\",\"done\":false}" |
| 113 | echo "" |
| 114 | echo " event: update-progress" |
| 115 | echo " data: {\"container\":\"nginx\",\"status\":\"📥 Pulling...\",\"done\":false}" |
| 116 | echo "" |
| 117 | echo " event: update-progress" |
| 118 | echo " data: {\"container\":\"nginx\",\"status\":\"✅ actualizado + reiniciado\",\"done\":true}" |
| 119 | echo "" |
| 120 | echo " event: notification" |
| 121 | echo " data: {\"container\":\"nginx\",\"status\":\"🔄 actualizado\",\"timestamp\":\"2026-08-29T12:00:00Z\"}" |
| 122 | echo "" |
| 123 | |
| 124 | # ── Comandos curl ──────────────────────────────────────────────────────── |
| 125 | echo -e "${VERDE}═══ Comandos para probar ═══${NC}" |
| 126 | echo "" |
| 127 | echo " # Check individual" |
| 128 | echo " curl -X POST http://localhost:3066/api/check-update/nginx \\" |
| 129 | echo " -H \"Cookie: session=TU_TOKEN\"" |
| 130 | echo "" |
| 131 | echo " # Update individual" |
| 132 | echo " curl -X POST http://localhost:3066/api/update/nginx \\" |
| 133 | echo " -H \"Cookie: session=TU_TOKEN\"" |
| 134 | echo "" |
| 135 | echo " # Check All (masivo)" |
| 136 | echo " curl -X POST http://localhost:3066/api/check-all \\" |
| 137 | echo " -H \"Cookie: session=TU_TOKEN\"" |
| 138 | echo "" |
| 139 | echo " # SSE updates (tiempo real)" |
| 140 | echo " curl -N http://localhost:3066/api/updates \\" |
| 141 | echo " -H \"Cookie: session=TU_TOKEN\"" |
| 142 | echo "" |
| 143 | echo " # Historial" |
| 144 | echo " curl http://localhost:3066/api/history \\" |
| 145 | echo " -H \"Cookie: session=TU_TOKEN\"" |
| 146 | echo "" |