Panel: dashboard de CloudWatch, varias cuentas y avisos de cuota¶
Tres extras opcionales del panel de gestión (ADR-026,
fase 3). Ninguno se activa solo y ninguno necesita un servidor de Rayito: lo
que crean es tuyo y se borra con rayito stack destroy.
Los pasos de cada extra van en su sección. Sólo la vista multicuenta lleva captura: el dashboard de CloudWatch y los avisos de SNS se ven en la consola de AWS, que muestra datos de tu cuenta, así que aquí van como texto y salida de ejemplo. La guía con capturas del panel cubre el resto, y la entrada Ayuda del panel la resume.
| Extra | Qué es | Dónde corre |
|---|---|---|
| Dashboard de CloudWatch | El JSON de un dashboard con logs de los sandboxes, métricas OTLP y uso de cuota | Se imprime (sin AWS) o se despliega la pila dashboard-cloudwatch |
| Varias cuentas | rayito dashboard --account ve otras cuentas con un rol de sólo lectura |
Tu portátil; la pila dashboard-read-role va en cada cuenta destino |
| Avisos de cuota | Una Lambda programada publica en SNS al cruzar un umbral de la cuota | La pila quota-alerts, en tu cuenta |
Dashboard de CloudWatch¶
Coste y activación
- Por defecto: apagado.
rayito dashboard cloudwatchsólo imprime texto: no necesita credenciales ni hace ninguna llamada a AWS. La piladashboard-cloudwatchno se crea hasta que la despliegas. - Activa:
rayito stack deploy dashboard-cloudwatch, oaws cloudwatch put-dashboardcon el JSON que imprime la CLI.IncludeOtlp=trueyIncludeQuota=trueañaden las gráficas opcionales. - Recursos y llamadas AWS: un único
AWS::CloudWatch::Dashboard; ni función, ni rol, ni datos. - Coste aproximado: generar el JSON es gratis (
rayito dashboard cloudwatchno llama a AWS); desplegarlo cuesta. $0 mientras tengas menos de 4 dashboards (los 3 primeros, de hasta 50 métricas, son gratuitos); por encima de esos 3, $3 al mes por dashboard. Cada widget de Logs Insights ejecuta su consulta cada vez que abres o refrescas el dashboard y CloudWatch factura los datos escaneados ($0,005 por GB): acota el intervalo de tiempo.--quota(oIncludeQuota=true) grafica la métrica de la pilaquota-alerts, que cuesta ~$0,30 al mes aparte; las consultas PromQL de--otlpdesde la consola no se facturan (precios de CloudWatch, consultados el 2026-10-13, us-east-1). - IAM: quien despliega, lo de Pilas opcionales
más
cloudwatch:PutDashboard,GetDashboardyDeleteDashboards(CloudFormation actúa con sus permisos); quien lo mira,logs:StartQueryylogs:GetQueryResultssobre los grupos. - Cómo apagarla:
rayito stack destroy dashboard-cloudwatch, oaws cloudwatch delete-dashboards. - Ejemplo: el de la sección siguiente.
El dashboard lleva cinco widgets de Logs Insights (más un encabezado) sobre los grupos /rayito/*
(el que usa el SDK con logging="cloudwatch"): líneas por intervalo, errores
por intervalo, líneas por grupo, streams más ruidosos y errores recientes. Con
--otlp añade CPU, memoria y disco de las
métricas OTLP de rayd; con --quota, la gráfica del
uso de la cuota de memoria con los umbrales de aviso y crítico como líneas.
# Sólo imprime: ninguna llamada a AWS, ni siquiera credenciales
rayito --region us-east-1 dashboard cloudwatch > rayito-board.json
rayito dashboard cloudwatch --otlp --quota --output rayito-board.json
# Otros grupos de logs, o un prefijo propio
rayito dashboard cloudwatch --log-group /rayito/base --log-group /rayito/agent
rayito dashboard cloudwatch --log-group-prefix /rayito/team-a/
# Crearlo es cosa tuya:
aws cloudwatch put-dashboard --dashboard-name "$NOMBRE_DEL_DASHBOARD" \
--dashboard-body file://rayito-board.json
El nombre del dashboard. La pila no fija un nombre: con el parámetro
DashboardName vacío (el valor por defecto) el dashboard se llama como la pila
(rayito-dashboard-cloudwatch salvo que uses --stack-name), que ya es único
en la región, así que desplegar no choca con un dashboard tuyo llamado
rayito. Para elegir otro, pásalo como parámetro (--param
DashboardName=<nombre>). Una pila desplegada antes de este cambio conserva el
nombre que ya tenía: redesplegar no la renombra.
El JSON que imprime la CLI y el que despliega la pila salen del mismo
generador, así que no pueden divergir (un test lo comprueba). El nombre de
grupo y el prefijo se validan antes de construir ninguna consulta: sólo letras,
números y _ . # - /.
Probar las gráficas OTLP¶
Las gráficas de --otlp (o IncludeOtlp=true) sólo tienen datos si algún
sandbox exporta sus métricas OTLP, y esa exportación
está apagada por defecto. Para ver las gráficas con datos:
- Despliega la política de exportación una vez en la cuenta:
rayito stack deploy otlp-export. No cuesta nada en reposo. - Crea un sandbox con
telemetry=TelemetryExport(...)(TypeScript:telemetry: new TelemetryExport({...})) sobre la imagenrayito-base-capscon tu rol de ejecución, tal como muestra el ejemplo de la exportación OTLP. Cada lote cuesta unos $0,00002 por sandbox-hora ainterval_s=60. - Espera al menos dos intervalos (
interval_s, 60 s por defecto) y comprueba en el propio sandbox que el envío funciona:sbx.get_telemetry_status()debe darexportedmayor que cero ylast_error_classvacío. - Despliega o actualiza el dashboard con
IncludeOtlp=truey ábrelo en la consola de CloudWatch. Las tres gráficas (CPU, memoria y disco) usan consultas PromQL con el nombre de la métrica entre comillas, por los puntos:avg({"rayito.sandbox.cpu.used_pct"}). Si exportas connames="e2b", las métricas se llamane2b.sandbox.*y estas gráficas quedan vacías. - Para apagarlo, termina el sandbox (
sbx.kill()) y, si ya nadie lo usa,rayito stack destroy otlp-export. Si adjuntaste la políticaRayitoOtlpExporta un rol, suéltala antes: CloudFormation no borra una política que sigue adjunta (DELETE_FAILED).
Las métricas OTLP no salen en ListMetrics, así que busca las series en
Metrics → Query de la consola con PromQL, no en el explorador clásico. Así
se ven las tres gráficas del dashboard con datos de ejemplo (en tu cuenta
dibujarán lo que exporten tus sandboxes):

Para comprobar los datos sin abrir la consola, CloudWatch ofrece una API HTTP
de PromQL (https://monitoring.<región>.amazonaws.com/api/v1/query y
query_range, firmada con SigV4 de servicio monitoring) que acepta la misma
consulta que el widget:
import json
import urllib.parse
import urllib.request
import boto3
from botocore.auth import SigV4Auth
from botocore.awsrequest import AWSRequest
session = boto3.Session(region_name="us-east-1")
query = urllib.parse.urlencode({"query": 'avg({"rayito.sandbox.cpu.used_pct"})'})
url = f"https://monitoring.us-east-1.amazonaws.com/api/v1/query?{query}"
request = AWSRequest(method="GET", url=url)
SigV4Auth(session.get_credentials().get_frozen_credentials(), "monitoring", "us-east-1").add_auth(request)
reply = urllib.request.urlopen(urllib.request.Request(url, headers=dict(request.headers)))
print(json.load(reply)["data"]["result"])
Medido en AWS real
Probado el 2026-10-14 en us-east-1 con sandboxes de Python y de TypeScript
(interval_s=15): el primer lote llega en segundos y las siete métricas
responden a la consulta con el nombre entre comillas; sin comillas, PromQL
da un error de sintaxis. Cada sandbox es una serie distinta
(@resource.sandbox_id). El SOURCE logGroups(namePrefix: [...]) de los
widgets de log se ejecuta en Logs Insights y devuelve resultados. Lo que no
se pudo comprobar por API es cómo dibuja la consola los widgets PromQL
(GetMetricWidgetImage no los admite). Detalle: AWS_API_NOTES.md §30,
Q167.
Varias cuentas¶
Coste y activación
- Por defecto: apagado.
rayito dashboardsin--accountve sólo la cuenta de tus credenciales, y no se llama a STS. - Activa:
rayito dashboard --account NOMBRE=ARN_DEL_ROL, repetible hasta 10 cuentas, después de desplegardashboard-read-roleen cada cuenta destino. - Recursos y llamadas AWS: en cada cuenta destino, un
AWS::IAM::Rolede sólo lectura. En el panel, unsts:AssumeRolepor cuenta (al pedir su vista por primera vez y al renovar cada hora) y las mismas lecturas que el panel de una cuenta:ListMicrovms,ListMicrovmImages,Get/ListMicrovmImageVersionyListServiceQuotas. - Coste aproximado: $0. IAM y STS no facturan; las lecturas no tienen precio (IAM, consultado el 2026-10-13).
- IAM: la identidad del panel necesita
sts:AssumeRolesobre esos roles; cada rol destino sólo permite las cinco lecturas anteriores. - Cómo apagarla: no pases
--account;rayito stack destroy dashboard-read-roleen cada cuenta destino borra el rol. - Ejemplo: el de esta sección.
La vista multicuenta es del panel local (rayito dashboard). Las cuentas
adicionales son siempre de sólo lectura: sin acciones, sin coste facturado,
sin logs y sin eventos. El selector de la página sólo muestra los nombres que
elegiste; el ARN del rol y el id de la cuenta no salen por la API.
1. En cada cuenta destino, despliega el rol de lectura. Confía en la
identidad que ejecuta el panel (nunca en la raíz de la cuenta) y, si quieres,
exige un ExternalId:
2. En la cuenta del panel, dale a tu identidad permiso para asumir esos roles y arranca el panel con ellos:
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::123456789012:role/rayito-dashboard-read-*"
}
rayito dashboard \
--account staging=arn:aws:iam::123456789012:role/rayito-dashboard-read-AbC123 \
--external-id un-valor-largo-y-aleatorio
# Panel de Rayito (us-east-1, sólo lectura, más 1 cuenta de sólo lectura). Ábrelo en tu navegador:
3. Cambia de cuenta. Con una o más cuentas adicionales, la esquina superior derecha muestra un selector con Esta cuenta y el nombre de cada una. Las adicionales son siempre de sólo lectura. La captura usa cuentas de ejemplo.

Sin escribir cuentas en la orden. Nada de esto exige ARNs en un fichero ni
en el historial del shell: la cuenta destino puede venir sólo de variables de
entorno y armarse al ejecutar. --account se lee también de
RAYITO_DASHBOARD_ACCOUNTS (entradas NOMBRE=ARN separadas por espacios) y el
ExternalId, de RAYITO_DASHBOARD_EXTERNAL_ID:
export TARGET_ACCOUNT_ID=<id-de-la-cuenta-destino> # lo pones tú, nunca en el repo
export TARGET_ROLE_NAME=<nombre-del-rol-de-lectura> # la salida RoleArn de la pila
export RAYITO_DASHBOARD_ACCOUNTS="staging=arn:aws:iam::${TARGET_ACCOUNT_ID}:role/${TARGET_ROLE_NAME}"
export RAYITO_DASHBOARD_EXTERNAL_ID=<el-mismo-valor-de-la-pila>
rayito dashboard
La plantilla, el panel y la política de la identidad son independientes de la
cuenta: sólo el ARN del rol cambia, y llega en tiempo de ejecución. Para
comprobar una cuenta destino de punta a punta: despliega dashboard-read-role
en ella (paso 1), exporta las variables, arranca rayito dashboard y elige la
cuenta en el selector; una cuenta que rechaza el rol aparece con el código
AccessDenied. Si lo que quieres es comprobar que el rol no puede actuar, no
lo pruebes con un id de MicroVM inventado: AWS responde ResourceNotFoundException
antes de autorizar. Usa el simulador de IAM (aws iam simulate-principal-policy
sobre el rol) o un MicroVM real.
Así se ve una cuenta cuyo rol rechaza el panel (por ejemplo, un ExternalId
que no coincide): la página muestra el código de AWS y nada más.

El ExternalId es el mismo para todas las cuentas. Si una cuenta rechaza el rol, la página lo dice con el
código de AWS (AccessDenied) y sin el mensaje, que nombraría rol y cuenta. La
sesión asumida dura 3600 s y se renueva sola.
La pila dashboard de tu cuenta no incluye vista multicuenta todavía: sólo
el panel local la tiene.
Avisos de cuota¶
Coste y activación
- Por defecto: apagado. Nada se crea hasta que ejecutas
rayito stack deploy quota-alerts. - Activa:
rayito stack deploy quota-alerts --artifact-bucket <bucket>.--param NotificationEmail=...suscribe un correo al tema;--param TopicArn=...usa un tema tuyo;WarningPercentyCriticalPercentcambian los umbrales yScheduleExpressionla frecuencia. - Recursos y llamadas AWS: una Lambda con su log group, una regla de
EventBridge, un tema SNS (salvo con
TopicArn) y su suscripción, una tabla DynamoDB bajo demanda con una fila y un rol de IAM. Cada ejecución lista los MicroVMs y las cuotas de la región y publica una métrica personalizada. - Coste aproximado: ~$0,30 al mes por la métrica personalizada
(
Rayito/Dashboard); Lambda (~720 ejecuciones al mes conrate(1 hour)), EventBridge, DynamoDB y SNS por correo caben en sus capas gratuitas (CloudWatch, Lambda, SNS; consultados el 2026-10-13, us-east-1). - IAM: quien despliega necesita
CAPABILITY_IAM. La función sólo lee MicroVMs y cuotas; escribe en SNS (sns:Publishsobre su tema), en su fila de DynamoDB y en su espacio de nombres de CloudWatch (cloudwatch:namespace). - Cómo apagarla:
rayito stack destroy quota-alerts. Borra todo, incluido el tema que creó (no el deTopicArn). - Ejemplo: el de esta sección.
La función mide la memoria asignada (RUNNING más suspendidos) contra la cuota
de la región, igual que la pestaña de cuotas del panel, y clasifica el uso con
los umbrales (0.8 y 0.95 de la cuota
por defecto, en porcentaje en la pila). Avisa una vez por cruce: cuando el
nivel sube (de normal a alto, de alto a crítico) y no en cada ejecución
mientras se mantiene. Recuerda el nivel más alto alcanzado hasta que el uso
vuelve a normal, así que un uso que oscila alrededor del umbral crítico avisa
una vez y no cada vez que lo cruza; al bajar a normal, el siguiente cruce vuelve
a avisar. Si SNS falla, la ejecución falla y el siguiente ciclo reintenta el aviso.
El mensaje lleva la región, la memoria asignada y la cuota, y cuántos sandboxes cuentan; nunca ids de sandbox, nombres de imagen ni de cuenta. Si no se pudo leer la memoria de algún sandbox, lo dice: el uso real puede ser mayor.
Cada pila vigila una región: despliega una por región. La métrica
Rayito/Dashboard/MemoryAllocatedFraction (dimensión Region) es la que
dibuja el dashboard de CloudWatch con --quota. El
tema SNS no se cifra: el mensaje no lleva datos sensibles.
IAM mínimo¶
| Quién | Qué permite | Dónde |
|---|---|---|
Rol de la función quota-alerts |
lambda:ListMicrovms, lambda:GetMicrovmImageVersion (imágenes de la cuenta), servicequotas:ListServiceQuotas, sns:Publish sobre su tema, dynamodb:GetItem/PutItem sobre su tabla, cloudwatch:PutMetricData sólo con cloudwatch:namespace igual a Rayito/Dashboard |
infra/quota-alerts.yaml |
Rol dashboard-read-role |
lambda:ListMicrovms, ListMicrovmImages, ListMicrovmImageVersions, GetMicrovmImageVersion, servicequotas:ListServiceQuotas; ninguna escritura |
infra/dashboard-read-role.yaml |
Identidad del panel local con --account |
sts:AssumeRole sobre esos roles |
tu política |
Ninguna de las tres pilas crea CloudFront ni buckets, y la de avisos funciona con las restricciones de una cuenta de pruebas (la Lambda la crea CloudFormation).