Distinguir "no se reinicio" de "no pude comprobarlo"
El GET de comprobacion no miraba su propio codigo HTTP. Un 403 devuelve un
objeto Status, que parsea como JSON perfectamente y luego revienta en
dep.spec.replicas ("Cannot read properties of undefined (reading 'replicas')").
El aviso resultante decia "reinicio fallido, intervencion manual necesaria"
cuando el reinicio habia ido BIEN y lo unico roto era la verificacion.
Falso negativo, mucho menos grave que el falso positivo de ayer -- pero te
levanta de la cama para nada, y estando Jose fuera eso importa.
Ahora el nodo marca verificable:false cuando no ha podido comprobar (HTTP no
2xx, cuerpo ilegible o error de red) y el aviso lo dice con esas palabras,
con el codigo de la comprobacion aparte del codigo del PATCH.
Reproducido en produccion: POST legitimo a las 08:43:22 (PATCH ok, restartedAt
cambia), permiso retirado a los 15 s, GET a los 60 s con 403. Ejecucion de
60,394 s, o sea el camino completo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -80,7 +80,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"jsCode": "const https = require('https');\nconst fs = require('fs');\n\nconst token = fs.readFileSync('/var/run/secrets/kubernetes.io/serviceaccount/token', 'utf8').trim();\nconst ca = fs.readFileSync('/var/run/secrets/kubernetes.io/serviceaccount/ca.crt');\n\nconst deployment = $input.first().json.deployment;\nconst namespace = $input.first().json.namespace;\nconst serviceName = $input.first().json.serviceName;\n// Sin kind, deployments: asi un workflow viejo en vuelo no se rompe.\nconst kind = $input.first().json.kind || 'deployments';\nconst generation = $input.first().json.generation;\n\nreturn new Promise((resolve) => {\n const req = https.request({\n hostname: 'kubernetes.default.svc',\n port: 443,\n path: `/apis/apps/v1/namespaces/${namespace}/${kind}/${deployment}`,\n method: 'GET',\n headers: { 'Authorization': `Bearer ${token}` },\n ca\n }, (res) => {\n let data = '';\n res.on('data', c => data += c);\n res.on('end', () => {\n try {\n const dep = JSON.parse(data);\n const desired = dep.spec.replicas || 1;\n const ready = dep.status.readyReplicas || 0;\n const updated = dep.status.updatedReplicas || 0;\n // Que este sano no prueba que se haya reiniciado: si el PATCH no\n // hubiera surtido efecto, un servicio que ya estaba bien daria\n // 'exito' igual. observedGeneration >= la generation que devolvio\n // el PATCH significa que el controlador ya proceso ESE cambio.\n // Se compara con >= y no con == a proposito: ArgoCD (selfHeal)\n // revierte la anotacion restartedAt poco despues, lo que sube la\n // generation otra vez. Con == eso daria un fallo falso.\n const observed = dep.status.observedGeneration || 0;\n const rolloutOk = generation == null ? true : observed >= generation;\n const statusOk = ready >= desired && updated >= desired && rolloutOk;\n resolve([{ json: { serviceName, deployment, kind, namespace, statusOk,\n ready, desired, generation, observed, rolloutOk } }]);\n } catch (e) {\n resolve([{ json: { serviceName, deployment, kind, namespace, statusOk: false, error: e.message } }]);\n }\n });\n });\n req.on('error', (e) => resolve([{ json: { serviceName, deployment, kind, namespace, statusOk: false, error: e.message } }]));\n req.end();\n});"
|
"jsCode": "const https = require('https');\nconst fs = require('fs');\n\nconst token = fs.readFileSync('/var/run/secrets/kubernetes.io/serviceaccount/token', 'utf8').trim();\nconst ca = fs.readFileSync('/var/run/secrets/kubernetes.io/serviceaccount/ca.crt');\n\nconst deployment = $input.first().json.deployment;\nconst namespace = $input.first().json.namespace;\nconst serviceName = $input.first().json.serviceName;\n// Sin kind, deployments: asi un workflow viejo en vuelo no se rompe.\nconst kind = $input.first().json.kind || 'deployments';\nconst generation = $input.first().json.generation;\n\nreturn new Promise((resolve) => {\n const req = https.request({\n hostname: 'kubernetes.default.svc',\n port: 443,\n path: `/apis/apps/v1/namespaces/${namespace}/${kind}/${deployment}`,\n method: 'GET',\n headers: { 'Authorization': `Bearer ${token}` },\n ca\n }, (res) => {\n let data = '';\n res.on('data', c => data += c);\n res.on('end', () => {\n // 'verificable: false' = no se pudo COMPROBAR, que no es lo mismo que\n // 'no se reinicio'. El PATCH ya habia dicho que si.\n if (res.statusCode < 200 || res.statusCode >= 300) {\n return resolve([{ json: { serviceName, deployment, kind, namespace,\n statusOk: false, verificable: false, checkCode: res.statusCode,\n error: String(data || '').slice(0, 200) } }]);\n }\n try {\n const dep = JSON.parse(data);\n const desired = dep.spec.replicas || 1;\n const ready = dep.status.readyReplicas || 0;\n const updated = dep.status.updatedReplicas || 0;\n // Que este sano no prueba que se haya reiniciado: si el PATCH no\n // hubiera surtido efecto, un servicio que ya estaba bien daria\n // 'exito' igual. observedGeneration >= la generation que devolvio\n // el PATCH significa que el controlador ya proceso ESE cambio.\n // Se compara con >= y no con == a proposito: ArgoCD (selfHeal)\n // revierte la anotacion restartedAt poco despues, lo que sube la\n // generation otra vez. Con == eso daria un fallo falso.\n const observed = dep.status.observedGeneration || 0;\n const rolloutOk = generation == null ? true : observed >= generation;\n const statusOk = ready >= desired && updated >= desired && rolloutOk;\n resolve([{ json: { serviceName, deployment, kind, namespace, statusOk,\n verificable: true, ready, desired, generation, observed, rolloutOk } }]);\n } catch (e) {\n resolve([{ json: { serviceName, deployment, kind, namespace,\n statusOk: false, verificable: false, checkCode: res.statusCode,\n error: e.message } }]);\n }\n });\n });\n req.on('error', (e) => resolve([{ json: { serviceName, deployment, kind, namespace,\n statusOk: false, verificable: false, checkCode: null, error: e.message } }]));\n req.end();\n});"
|
||||||
},
|
},
|
||||||
"id": "d1a2b3c4-6666-6666-6666-000000000006",
|
"id": "d1a2b3c4-6666-6666-6666-000000000006",
|
||||||
"name": "K8s API Check Status",
|
"name": "K8s API Check Status",
|
||||||
@@ -156,7 +156,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "text",
|
"name": "text",
|
||||||
"value": "={{ '❌ Servicio *' + $json.serviceName + '* caído — reinicio fallido, intervención manual necesaria' + ($json.statusCode ? ' (HTTP ' + $json.statusCode + ')' : '') + ($json.error ? ': ' + String($json.error).replace(/[*_`\\[\\]]/g, '').slice(0, 200) : '') + ($json.rolloutOk === false ? ' — el PATCH pasó pero el rollout no llegó a completarse' : '') }}"
|
"value": "={{ ($json.verificable === false ? '⚠️ Servicio *' + $json.serviceName + '* caído — el reinicio se lanzó BIEN, pero no he podido comprobar cómo quedó' : '❌ Servicio *' + $json.serviceName + '* caído — reinicio fallido, intervención manual necesaria') + ($json.statusCode ? ' (HTTP ' + $json.statusCode + ')' : '') + ($json.checkCode ? ' (comprobación: HTTP ' + $json.checkCode + ')' : '') + ($json.error ? ': ' + String($json.error).replace(/[*_`\\[\\]]/g, '').slice(0, 200) : '') + ($json.rolloutOk === false ? ' — el PATCH pasó pero el rollout no llegó a completarse' : '') }}"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "parse_mode",
|
"name": "parse_mode",
|
||||||
|
|||||||
Reference in New Issue
Block a user