# Tema 3 · 8 · Visor web de DynamoDB con Streamlit Presentación del Tema 3: «Ejemplo aplicaciones uso DynamoDB – Ejercicio 2» (visor web de DynamoDB). Duración: 5 a 10 minutos (medido con la versión anterior: con la plantilla, 3-4 minutos hasta `CREATE_COMPLETE` y la app responde un minuto después de que arranque la instancia, unos 4 minutos desde que lanzas la plantilla; con el script, ~1 minuto hasta `running` y ~1 minuto más hasta que la app responde). Coste: una EC2 `t3.small` por hora encendida. Se apaga sola a las 4 horas (ver «Apagado automático»), pero bórrala en cuanto termines. **Sobre esta versión.** Antes había un script de Python (sin opción de borrado) y una plantilla de CloudFormation sueltos. Ahora hay **un solo fichero**, `gestionar-visor-dynamodb.sh`, que lleva dentro la plantilla y la aplicación, y sabe **crear**, **comprobar el estado** y **eliminar** (borrando todo a la fuerza). Si la presentación te indica ejecutar un script `.py` con `python3`, el comando equivalente ahora es `./gestionar-visor-dynamodb.sh crear`. Se ha probado con una simulación de la AWS CLI y se han validado la plantilla y las consultas con la AWS CLI real en modo lectura; lo que no se ha probado de extremo a extremo en una cuenta real está marcado con. > **¿Dudas con un script?** Todos los scripts de esta carpeta traen su propia ayuda: `./gestionar-visor-dynamodb.sh --ayuda` (también vale `--help` o `-h`) explica los pasos y las opciones. Este `README.md` es el paso a paso de la actividad: tenlo a mano y consúltalo antes de preguntar. > **Etiquetas de lo que creas.** `./gestionar-visor-dynamodb.sh crear` etiqueta la instancia, su disco, el Security Group, el rol, la política, el perfil de IAM y el stack con `curso` = `G214`, `universidad` = `CUNEF`, `actividad` = `03.08-dynamodbvisor` y `script` = `gestionar-visor-dynamodb.sh`. Las verás en la consola (pestaña *Tags* del recurso) y, si hiciera falta borrar a mano, se localizan con `aws resourcegroupstaggingapi get-resources --region eu-north-1 --tag-filters Key=actividad,Values=03.08-dynamodbvisor`. Más detalle (cómo etiquetar con la CLI, cómo buscar y qué hacer en una emergencia): [README principal](../../README.md), sección «Etiquetas». ## Qué vas a hacer Vas a desplegar una EC2 que publica una web (Streamlit, puerto 8501) con tus tablas de DynamoDB. Es un **visor**: lista las tablas de una región, te deja elegir una, buscar texto dentro y refrescar. No escribe. Para añadir datos usa `dynamodb-cli.py` ([03.07](../03.07-dynamodbcli/README.md)) o la consola, y en el visor pulsa **Refrescar datos**. Lee con un rol de IAM de solo lectura (`Scan` y `ListTables`), así que no necesitas darle credenciales. ``` CloudShell/consola ──(script o plantilla)──> EC2 + rol IAM de solo lectura ──Scan/ListTables──> tus tablas DynamoDB Tu navegador ──http://:8501──> Streamlit en la EC2 ``` El visor corre en **Amazon Linux 2023** con Python 3.11 (el script y la plantilla instalan `python3.11`, `streamlit`, `boto3` y `pandas` al arrancar la máquina). Hay dos formas de desplegarlo; elige UNA. Las dos hacen lo mismo y se borran igual de fácil (`eliminar`). | | Script `gestionar-visor-dynamodb.sh` (por defecto, `--modo cli`) | Plantilla de CloudFormation (`--modo cloudformation`, o desde la consola) | |---|---|---| | Cómo se despliega | `./gestionar-visor-dynamodb.sh crear` en CloudShell: comandos sueltos de la AWS CLI | `./gestionar-visor-dynamodb.sh crear --modo cloudformation`, o la consola de CloudFormation con la plantilla que escribe `extraer` | | Cómo se borra | `./gestionar-visor-dynamodb.sh eliminar` (forzado) | `./gestionar-visor-dynamodb.sh eliminar --modo cloudformation` (forzado) o **Delete stack** en la consola | | Región | Siempre `eu-north-1` (la app te deja consultar otra) | Siempre `eu-north-1` con el script; donde crees el stack, si lo haces por consola | **Qué se crea en AWS:** | Pieza | Qué crea en AWS | |---|---| | Script (modo `cli`) | La instancia `Streamlit-DynamoDB-Viewer`, el Security Group `streamlit-sg`, el rol `EC2-DynamoDB-Role`, el perfil `EC2-DynamoDB-Profile` y la política `DynamoDB-ReadOnly-Policy` | | Plantilla (modo `cloudformation`, stack `dynamodb-streamlit`) | 1 stack con una instancia EC2 `G214-DynamoDB-Streamlit-Viewer` (t3.small por defecto, Amazon Linux 2023), un rol de IAM de solo lectura (`Scan` y `ListTables`) con su perfil, y un Security Group (puertos 8501 y 22 abiertos a todo Internet) | En las dos: la instancia se apaga sola a las 4 h (apartado «Apagado automático»), pero mientras está encendida su Security Group abre los puertos 8501 y 22 a **todo Internet** (`0.0.0.0/0`); cualquiera que conozca la IP podría ver el contenido de tus tablas, así que no pongas datos que no quieras publicar. Si quieres cerrarlo, cambia el origen de la regla del 8501 a *My IP* en el Security Group. Streamlit está instalado como servicio, así que vuelve solo cuando arrancas la instancia parada (la IP pública cambia: mírala con `estado`). ## Qué contiene esta carpeta | Fichero | Para qué sirve | En qué paso se usa | |---|---|---| | `gestionar-visor-dynamodb.sh` | Un solo script autónomo: crea, comprueba y elimina el visor, con la plantilla de CloudFormation y la app Streamlit embebidas | Pasos 1A, 1B y 1C | | `README.md` | Esta guía | Siempre | La plantilla va dentro del script (entre las marcas `INICIO ARCHIVO EMBEBIDO` y `FIN ARCHIVO EMBEBIDO`). Si la necesitas como fichero (para subirla en la consola de CloudFormation), `./gestionar-visor-dynamodb.sh extraer` escribe `plantilla-visor-dynamodb.yaml` en la carpeta actual (o en la carpeta que indiques: `extraer mi-carpeta`). ### Comandos | Comando | Qué hace | |---|---| | `crear [--horas N] [--permanente]` | Despliega el visor; se apaga solo a las 4 h (`--horas` admite 1-24). Si ya existe, **no crea otro**: arranca la instancia si está parada y renueva el plazo | | `estado` | Muestra qué hay creado, su estado, la URL y la línea «Apagado automático» | | `extender [--horas N\|--permanente]` | Solo cambia el plazo de apagado automático (por defecto, otras 4 h desde ahora) | | `arrancar` | Igual que `crear` sobre lo ya existente: arranca la instancia parada y renueva el plazo | | `eliminar` | Borra **todo** lo creado, de forma forzada y repetible; pide confirmación (se omite con `--si`) | | `extraer [CARPETA]` | Escribe la plantilla de CloudFormation embebida | | `ayuda` | Muestra el uso | Opciones: `--si` (o `-y`, `--yes`) no pide confirmación; `--horas N` y `--permanente` fijan el plazo de apagado automático; `--modo cli|cloudformation` elige la forma de desplegar. **Sin comando y con terminal interactiva se abre un menú numerado**; sin terminal imprime el uso y termina sin quedarse esperando. Aliases `--create`, `--status`, `--delete` y `--help` también funcionan. Solo necesita bash y la AWS CLI (en CloudShell ya están); no necesita Python en tu máquina, `jq` ni `boto3`. ## Apagado automático - El visor se **apaga solo a las 4 horas** de crearlo (para que no quede encendido y facturando). Al vencer **se apaga, no se borra**: la instancia queda `stopped`; solo `eliminar` la borra. - **Ampliar**: vuelve a ejecutar `./gestionar-visor-dynamodb.sh crear` (arranca la instancia si estaba parada y concede otras 4 h; también vale `arrancar`) o `extender` (solo cambia el plazo). Con `--horas N` (1-24) eliges otro plazo. - **Permanente**: `./gestionar-visor-dynamodb.sh crear --permanente` (o `extender --permanente`). `estado` avisa con «PERMANENTE (¡ojo con el coste!)». - `estado` muestra siempre la línea «Apagado automático: se apagará a las HH:MM UTC (dentro de N min)», `PERMANENTE` o «ya se apagó: ejecuta `crear`». - Funciona con una etiqueta de la instancia (`g214-apagar-tras`) que un servicio interno lee cada 30 s. Si la arrancas a mano con el plazo vencido, tiene 60 min de gracia. ## Antes de empezar - [ ] Cuenta de AWS propia, región de la consola `eu-north-1` (elígela ANTES de abrir CloudShell). - [ ] La tabla `Usuarios` con clave `UserID` (String) creada ([03.07](../03.07-dynamodbcli/README.md), pasos 1 y 3; o la presentación) y, si quieres ver datos, con algún ítem. Si la tabla está vacía, el visor dirá `La tabla seleccionada está vacía.` - [ ] Permisos de IAM: el script crea una política, un rol y un perfil de IAM, un Security Group y una EC2, y los asocia (`iam:PassRole`). Con la cuenta de la asignatura (administrador) no hay problema; con una cuenta de permisos restringidos fallará con `AccessDenied` en el primer recurso que no pueda crear (el modo `cloudformation` necesita `CAPABILITY_IAM` por lo mismo; el script lo pone solo). - Esta actividad **no** necesita la RDS ni Adminer. ## Cómo llevar los ficheros a donde toque - **Plantilla por consola (1A):** en CloudShell ejecuta `./gestionar-visor-dynamodb.sh extraer`, descarga `plantilla-visor-dynamodb.yaml` (**Actions** > **Download file**) y súbelo en el asistente de CloudFormation. (Si prefieres hacerlo desde tu PC, `extraer` también funciona en Git Bash o WSL.) - **Script (1B/1C):** en CloudShell. Comprime **esta carpeta** (`03.08-dynamodbvisor`) en un zip, abre CloudShell en `eu-north-1`, **Actions** > **Upload file** y sube el zip. Después: ```bash unzip -o 03.08-dynamodbvisor.zip && cd 03.08-dynamodbvisor sed -i 's/\r$//' *.sh chmod -R u+rwX . && chmod +x *.sh ls ``` > Si ya subiste `g214-materiales.zip` (README principal), no necesitas este zip: entra con `cd ~/g214-materiales/tema3/03.08-dynamodbvisor` y, si algún fichero da `Permission denied`, ejecuta allí `chmod -R u+rwX . && chmod +x *.sh`. `sed` quita los finales de línea de Windows y `chmod +x` da permiso de ejecución (un zip creado en Windows no lo conserva; también puedes lanzarlo con `bash gestionar-visor-dynamodb.sh crear`). Qué verás: `ls` muestra `README.md` y `gestionar-visor-dynamodb.sh`. Ya no importa desde qué carpeta lances el script: lo que ha creado se averigua consultando AWS. ## Paso a paso **Paso 1A. Con la plantilla (consola).** 1. Consigue `plantilla-visor-dynamodb.yaml` (ver arriba, `extraer`). Consola de AWS (región `eu-north-1`) > **CloudFormation** > **Create stack** > **With new resources (standard)** > **Upload a template file** > `plantilla-visor-dynamodb.yaml` > **Next**. 2. Nombre del stack: `dynamodb-streamlit` (si usas otro, lanza luego `G214_STACK=tu-nombre ./gestionar-visor-dynamodb.sh eliminar --modo cloudformation`). Parámetros: `VpcId` (la VPC por defecto), `SubnetId` (una subred pública de esa VPC), `InstanceType` (`t3.small` por defecto; admite `t3.micro`) y `LatestAmiId` (déjalo como está). 3. **Next** > **Next**. En la última pantalla **marca la casilla** `I acknowledge that AWS CloudFormation might create IAM resources`: la plantilla crea un rol de IAM y sin esa casilla el envío se rechaza. **Submit**. 4. Espera a `CREATE_COMPLETE` y abre la pestaña **Outputs**: `PublicIP` y `AppURL` (`http://:8501`). **Paso 1B. Con la plantilla (desde el script, sin consola).** ```bash ./gestionar-visor-dynamodb.sh crear --modo cloudformation ``` Detecta tu VPC por defecto y una subred pública, crea el stack `dynamodb-streamlit` con `CAPABILITY_IAM`, espera a `CREATE_COMPLETE` (con progreso y un máximo de espera), te enseña la tabla de Outputs y la URL `http://:8501`. Si el stack existe pero quedó fallido (`ROLLBACK_COMPLETE`...), lo elimina antes de crear uno nuevo. **Paso 1C. Con el script.** ```bash ./gestionar-visor-dynamodb.sh crear ``` Si lo lanzas sin nada (`./gestionar-visor-dynamodb.sh`) se abre un menú numerado: elige `1) Crear`. No pide nada por teclado al crear. Va escribiendo lo que hace (secuencia de mensajes de esta versión): busca la VPC y una subred, resuelve la AMI más reciente de Amazon Linux 2023 (parámetro público de SSM, con plan B por nombre), crea la política `DynamoDB-ReadOnly-Policy`, el rol `EC2-DynamoDB-Role` y el perfil `EC2-DynamoDB-Profile`, espera a que el perfil se propague, crea el Security Group `streamlit-sg` (SSH y Streamlit abiertos a `0.0.0.0/0`), lanza la instancia (`t3.small`; `INSTANCE_TYPE=t3.micro ./gestionar-visor-dynamodb.sh crear` la cambia) y espera a que esté en `running` (~1 minuto, medido con la versión anterior). Al terminar imprime `Despliegue completado` y la URL `http://:8501`, y te pide darle 1-2 minutos. Si lo repites: **no crea otra instancia**. Escribe `Ya tienes una instancia de Visor DynamoDB creada: no creo otra.`, la arranca si estaba parada, renueva el plazo de apagado automático y te enseña su estado y su URL. (La versión anterior terminaba la instancia vieja y lanzaba una nueva; ahora, para empezar de cero, ejecuta primero `eliminar`.) Reutiliza la política, el rol, el perfil y el Security Group que ya existan (lo avisa con `ya existe`). Solo vale para la región `eu-north-1`. Los recursos que crea el script se encuentran por su nombre (`Streamlit-DynamoDB-Viewer`, `streamlit-sg`, `EC2-DynamoDB-Role`, `EC2-DynamoDB-Profile`, `DynamoDB-ReadOnly-Policy`), así que `estado` y `eliminar` los localizan solos. **Paso 2. Esperar a que termine de instalarse.** La app se instala dentro de la máquina después de crearla (instala Python 3.11, Streamlit, `boto3` y `pandas`). Tiempos medidos arriba (~1 minuto el script, ~4 minutos la plantilla). `./gestionar-visor-dynamodb.sh estado` te dice si la aplicación ya responde. Si la página no carga, mira «Errores frecuentes». **Paso 3. Usar el visor.** 1. Abre `http://:8501` (con `http`, puerto 8501). 2. Verás el título `Visor de Tablas de AWS DynamoDB`, en el lateral el campo de región (por defecto `eu-north-1`), un desplegable con tus tablas, el botón **Refrescar datos**, una caja `Buscar en la tabla` y la tabla de datos. 3. Elige `Usuarios`. Si la tabla está vacía verás `La tabla seleccionada está vacía.`; si el desplegable sale vacío, cambia la región por donde están tus tablas. 4. Añade un ítem con `dynamodb-cli.py` (en CloudShell, [03.07](../03.07-dynamodbcli/README.md), paso 6) y pulsa **Refrescar datos** para verlo. ## Errores frecuentes | Síntoma | Causa | Solución | |---|---|---| | CloudFormation rechaza el stack pidiendo capacidades de IAM | No marcaste la casilla de IAM (consola) | Marca `I acknowledge that AWS CloudFormation might create IAM resources`. Con `--modo cloudformation` el script ya lo hace | | `AccessDenied` / `Tu usuario de AWS no tiene permiso para esto` (cuenta con permisos restringidos) | El script crea política, rol, perfil, Security Group y EC2 | Usa una cuenta con permisos de administrador | | `No encuentro la AWS CLI` o `Las credenciales de AWS no funcionan: ...` | Estás fuera de CloudShell sin AWS CLI configurada, o la sesión ha caducado | Usa CloudShell (recarga la pestaña si caducó) o `aws configure` en tu PC | | La URL del visor no carga | Aún se instala (hasta ~4 minutos con la plantilla); usas `https://` o falta `:8501`; la instalación ha fallado; o la instancia se apagó sola (`estado` lo dice; ejecuta `crear`) y la IP es nueva | Espera unos minutos y abre `http://:8501` (`estado` te da la URL actual). Si pasados 15 minutos sigue igual, ejecuta `eliminar` y vuelve a `crear` | | La URL del visor muestra `Web Filter Violation` o `Access Blocked` (página de FortiGuard u otro filtro) | Es el filtro web de tu red, no AWS: bloquea direcciones IP sin categoría | Prueba con otra red (por ejemplo, los datos del móvil) | | El desplegable de tablas del visor está vacío | La región del campo lateral no es la de tus tablas | Escribe en él la región correcta | | `Permission denied` al lanzar `./gestionar-visor-dynamodb.sh` | Sin permiso de ejecución | `chmod +x gestionar-visor-dynamodb.sh` (o `bash gestionar-visor-dynamodb.sh crear`) | | `bad interpreter` o `$'\r': command not found` | Finales de línea de Windows | `sed -i 's/\r$//' *.sh` y repite | | `No hay terminal interactiva para confirmar` | Has lanzado `eliminar` sin teclado (desde otro script, por ejemplo) | Añade `--si` | | `Ha quedado algo sin borrar` al hacer `eliminar` | AWS tardó más de lo normal en liberar algún recurso | Espera un minuto y repite `eliminar`: es seguro repetirlo y continúa donde se quedó | | `AWS no responde bien (Throttling); reintento 1/5...` | AWS pide ir más despacio | No es un error: el script espera y reintenta solo | ## Limpieza Bórralo en cuanto termines el ejercicio (su puerto 8501 está abierto a Internet mientras está encendido). ```bash ./gestionar-visor-dynamodb.sh eliminar # el visor creado con el script (modo cli, por defecto) ./gestionar-visor-dynamodb.sh eliminar --modo cloudformation # el stack dynamodb-streamlit ``` Enseña lo que va a borrar y pide confirmación (`--si` la omite). Después, a la fuerza y en este orden: termina la instancia, borra el Security Group (reintentando mientras AWS lo libera), el perfil de instancia, el rol y la política de IAM (la política solo si ninguna otra entidad la usa) y los volúmenes sueltos; o, con el stack, lo borra y, si se atasca en `DELETE_FAILED`, lo fuerza. Al final hace una **comprobación** y escribe qué queda (`Instancias EC2: ninguna`, `Security Groups: ninguno`, `Rol EC2-DynamoDB-Role: no existe`...) y `Limpieza completa`. Es idempotente: se puede repetir, aunque hayas borrado algo a mano. Con un stack sano, el borrado limpio tardó ~1 minuto (medido con la versión anterior). Si lo creaste desde la consola con otro nombre de stack, usa `G214_STACK=tu-nombre ./gestionar-visor-dynamodb.sh eliminar --modo cloudformation`, o **Delete stack** en la consola. Verificación (todo en `eu-north-1`; el propio `eliminar` ya la hace al terminar, pero puedes repetirla a mano): ```bash aws ec2 describe-instances --region eu-north-1 \ --filters "Name=instance-state-name,Values=pending,running,stopping,stopped" \ --query "Reservations[].Instances[].[InstanceId,State.Name,Tags[?Key=='Name']|[0].Value]" --output table aws ec2 describe-security-groups --region eu-north-1 \ --filters "Name=group-name,Values=streamlit-sg" --query "SecurityGroups[].GroupName" aws cloudformation list-stacks --region eu-north-1 \ --stack-status-filter CREATE_COMPLETE UPDATE_COMPLETE ROLLBACK_COMPLETE DELETE_FAILED \ --query "StackSummaries[].StackName" ``` Qué debes ver: ninguna instancia `G214-DynamoDB-Streamlit-Viewer` ni `Streamlit-DynamoDB-Viewer` (si tienes instancias de otros laboratorios, saldrán aquí: son de otro tema), ningún Security Group `streamlit-sg` y ningún stack `dynamodb-streamlit`. La tabla `Usuarios` **no** se borra aquí: es de [03.07](../03.07-dynamodbcli/README.md) (su limpieza la borra, cuando termines también el ejercicio de S3). ## Cómo sabes que has terminado - [ ] El visor abre en `http://:8501`, muestra `Usuarios` y, tras añadir un ítem con `dynamodb-cli.py` y pulsar **Refrescar datos**, lo ves. - [ ] Has ejecutado `./gestionar-visor-dynamodb.sh eliminar` (o borrado el stack) y la verificación sale vacía. Anterior: [03.07 · DynamoDB con la CLI y Python](../03.07-dynamodbcli/README.md) · Siguiente: [03.09 · Ejercicios adicionales A y B (INE y aire)](../03.09-ineaire/README.md)