Servidor disponible solo los jueves de 10:30 a 12:30 y los viernes de 10:00 a 13:00 (hora de Madrid); fuera de ese horario está apagado. Fuera del horario, usa la documentación local del material que te descargaste (el README.md de cada carpeta).
G214 · CUNEF
Inicio / tema5 / 05.05-cryptoas3yrds

Tema 5 · 5 · Ejercicio 2, tipo 3: CoinGecko a S3 y RDS

Presentación del Tema 5: «Ejercicio 2: CoinGecko (Tipo 3)» (Power BI sobre la tabla) y «Ejercicio 2 · programar la ejecución con EventBridge». Duración: 25-30 min (sin contar Power BI ni EventBridge). Coste: prácticamente nulo en esta actividad; lo que cuesta es la infraestructura base de la carpeta 05.01 (RDS y EC2 por hora).

Solo haces UNA variante del Ejercicio 2. La carpeta 05.03 (S3), la 05.04 (DynamoDB) y esta (S3 + RDS) son las tres variantes. Haz la que te asigne tu docente. No hagas las tres.

¿Dudas con un script? Todos los scripts de esta carpeta traen su propia ayuda: ./gestionar-crypto-s3-rds.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-crypto-s3-rds.sh crear etiqueta el stack (Lambda, rol) y la regla de EventBridge con curso = G214, universidad = CUNEF, actividad = 05.05-cryptoas3yrds y script = gestionar-crypto-s3-rds.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=05.05-cryptoas3yrds. Más detalle (cómo etiquetar con la CLI, cómo buscar y qué hacer en una emergencia): README principal, sección «Etiquetas».

Qué vas a hacer

Vas a crear una función Lambda que pide a CoinGecko (API pública, sin clave) el precio en USD y EUR de cinco monedas (bitcoin, ethereum, cardano, solana, polkadot) con su capitalización, volumen y variación en 24 horas, guarda los datos originales en S3 y después inserta una fila por moneda y divisa en una tabla de la RDS MariaDB.

Qué se crea en AWS: el stack cunef-etl-crypto-rds (rol + función crypto-price-tracker-rds, 60 s, 256 MB). La primera ejecución crea en la RDS la base crypto y la tabla coins. Lo crea, lo comprueba y lo borra un único script: gestionar-crypto-s3-rds.sh.

Qué hace la función: guarda los datos originales en S3 (crypto/raw/history/crypto_prices_AAAAMMDD_HHMMSS.json y crypto/raw/crypto_prices_latest.json) e inserta en la RDS una fila por moneda y divisa (5 x 2 = 10 filas por ejecución) en la tabla crypto.coins, que crea si no existe. Las credenciales y el bucket los toma de variables de entorno que fija el script (S3_BUCKET, DB_HOST, DB_USER, DB_PASS, DB_NAME, DB_TABLE).

Importante: si falla la parte de RDS, la función no devuelve 500: devuelve statusCode 200 y dentro de body el campo rds con "success": false y el motivo en rds.message. Mira siempre rds.success.

Lo que debes saber antes de empezar (vale para las tres variantes)

  1. Un solo script hace todo. ./gestionar-crypto-s3-rds.sh crear detecta la RDS y el bucket del Paso 0, empaqueta el código con la librería pymysql, crea el stack de CloudFormation (con la plantilla que lleva dentro), sube el código de la función y, si quieres, la prueba. Ya no hay que crear el stack a mano. Es seguro repetirlo: si todo existe, solo actualiza el código; si quedó algo a medias de un intento anterior, lo repara.
  2. Menú o comandos. Sin argumentos y en una terminal, el script muestra un menú numérico. Con argumentos ejecuta directamente un comando: crear, estado, probar, logs, programar, extender, desprogramar, eliminar, extraer y ayuda (lista completa en Los comandos del script).
  3. El script pregunta ¿Deseas probar la función ahora? (s/n): al terminar crear. Escribe s y pulsa Intro. Con n solo despliega. Para no tener que contestar: crear --si (prueba) o crear --no (no prueba). Sin terminal interactiva nunca se queda esperando: no prueba.
  4. El script ya no crea un rol de IAM propio. La función usa el rol del stack. Si en una versión anterior se te creó un rol sobrante (LambdaCryptoTrackerRDSRole), eliminar lo borra.
  5. El script marca el resultado con el statusCode de la función. Tras la prueba verás ✓ Función ejecutada correctamente (statusCode 200) si fue bien, o ✗ La función devolvió statusCode 500 seguido del motivo (campo error) si falló por dentro. Con el CLI a mano ocurre lo contrario: "StatusCode": 200 solo dice que la llamada de invocación terminó, aunque dentro vaya statusCode 500. Comprueba siempre el dato en el destino.
  6. Cada ejecución añade datos nuevos (no se sobrescribe lo anterior), salvo crypto_prices_latest.json. Repetir la invocación es seguro, pero acumula ficheros y filas.
  7. Los "Comandos útiles" que imprime el script ya llevan --cli-binary-format raw-in-base64-out (AWS CLI v2).
  8. CoinGecko limita las peticiones y el límite es bajo. Tras unas 5 peticiones seguidas desde la misma IP responde error 429 (Status 429 o HTTP Error 429 en el campo error; en una prueba, 5 respuestas 200 y 7 con 429 en una ráfaga de 12). No encadenes el curl de comprobación, el script con s, el invoke a mano y la regla de cada minuto: deja 1-2 minutos entre pruebas. Si toda la clase sale por la misma IP, el 429 aparecerá antes. No es culpa de tu código: espera uno o dos minutos y vuelve a invocar. La función no reintenta sola.

Qué deberías ver tras la primera ejecución correcta: 2 ficheros JSON bajo crypto/raw/ y 10 filas en crypto.coins (5 monedas x 2 divisas); en cada ejecución siguiente, 2 ficheros nuevos y 10 filas más.

Qué contiene esta carpeta

Fichero Para qué sirve En qué paso se usa
gestionar-crypto-s3-rds.sh Todo el ejercicio en un solo archivo: detecta la RDS y el bucket del Paso 0, empaqueta el código con pymysql, crea el stack y sube el código, comprueba el estado, prueba la función, programa EventBridge y lo elimina todo (incluida la tabla de la RDS). Lleva dentro el código de la Lambda y la plantilla de CloudFormation. Pasos 3, 4, 5 y 7, y la Limpieza
README.md Este documento. Siempre

El código de la función y la plantilla viajan dentro del script. Para verlos o editarlos, extráelos a la carpeta actual:

./gestionar-crypto-s3-rds.sh extraer

Esto escribe lambda-crypto-s3-rds.py (el código de la función) y plantilla-crypto-s3-rds.yaml (la plantilla de CloudFormation). No son necesarios para desplegar. En este ejercicio no tienes que editar nada (el bucket llega a la función por variable de entorno), pero si editas el .py y ejecutas crear, el script despliega tu versión (también detecta un lambda_function.py en la carpeta, o el fichero que le indiques con --codigo mi-codigo.py; si no compila, no despliega nada y te lo dice). La plantilla extraída solo se usa con crear --plantilla plantilla-crypto-s3-rds.yaml. Si el fichero ya existe, extraer no lo sobrescribe (extraer --forzar lo hace y guarda una copia .bak).

Antes de empezar

Cómo llevar los ficheros a CloudShell

  1. En tu PC, comprime esta carpeta entera (05.05-cryptoas3yrds): clic derecho → Comprimir en archivo ZIP (Windows 11), Enviar a > Carpeta comprimida en zip (Windows 10) o Comprimir (Mac).
  2. En CloudShell (región eu-north-1): Actions → Upload file y elige 05.05-cryptoas3yrds.zip.
  3. Ejecuta:
cd ~
unzip -o 05.05-cryptoas3yrds.zip && cd 05.05-cryptoas3yrds
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/tema5/05.05-cryptoas3yrds y, si algún fichero da Permission denied, ejecuta allí chmod -R u+rwX . && chmod +x *.sh.

Qué verás: gestionar-crypto-s3-rds.sh y README.md. Ejecuta el script siempre dentro de esta carpeta. Las variables de shell se pierden al cerrar la pestaña.

Los comandos del script

./gestionar-crypto-s3-rds.sh COMANDO [opciones] (ayuda los lista; sin comando y con terminal, abre el menú).

Comando (alias) Qué hace
crear (desplegar, deploy) Detecta RDS y bucket, empaqueta pymysql, crea o actualiza el stack, sube el código y, si quieres, prueba la función. Repetible.
estado (status, verificar) Muestra qué existe (infraestructura base, stack, función y si tiene la RDS configurada, rol, datos en S3, reglas, logs), la última ejecución, las últimas líneas del log y qué hacer a continuación.
probar (test, invocar) Ejecuta la función una vez y comprueba statusCode, los ficheros en S3 y rds.success.
logs Últimas líneas de los logs (logs --seguir: en directo).
programar [N] (eventbridge) Ejecuta la función cada N minutos (por defecto 1) con EventBridge durante 4 h: después la regla se desactiva sola (ver Apagado automático). Si la regla ya existe, la reactiva y renueva el plazo. Ver 05.06.
extender (ampliar) Solo cambia el plazo del apagado automático (otras 4 h; --horas N o --permanente).
desprogramar (parar) Quita (borra) la programación.
eliminar (borrar, limpiar) Borra todo lo de este ejercicio (incluidos los datos de S3 y la tabla de la RDS) y comprueba al final qué queda. Pide confirmación (con --si o -y no).
extraer Escribe en la carpeta el .py y el .yaml embebidos para verlos o editarlos.

Opciones: --si/-y (responde sí: crear prueba la función, eliminar no pregunta), --no (crear no prueba; eliminar no borra), --codigo F.py, --plantilla F.yaml, --forzar (con extraer), --seguir (con logs), --cada "rate(1 hour)", --regla NOMBRE, --horas N (1-24) y --permanente (con programar y extender).

Paso a paso

0. Recupera las variables del Paso 0 (también si cerraste CloudShell):

OUT() { aws cloudformation describe-stacks --stack-name cunef-etl --region eu-north-1 \
  --query "Stacks[0].Outputs[?OutputKey=='$1'].OutputValue" --output text; }
BUCKET=$(OUT BucketName); RDS=$(OUT RDSEndpoint); FN=$(OUT LambdaName); ADMINER=$(OUT AdminerURL)
echo "Bucket : $BUCKET"; echo "RDS    : $RDS"; echo "Lambda : $FN"; echo "Adminer: $ADMINER"

Qué verás: cuatro líneas con valores (aquí necesitas BUCKET, y RDS y ADMINER para Adminer). Si salen vacías, el stack cunef-etl no existe: vuelve a la carpeta 05.01.

1. Comprueba que CoinGecko responde desde CloudShell:

curl -s -o /dev/null -w "%{http_code}\n" "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin,ethereum&vs_currencies=eur"

Qué verás: 200. Si ves 429 u otro número, la API te está limitando o no responde: espera un poco y repite antes de seguir.

2. (Opcional) Mira el código de la función: ./gestionar-crypto-s3-rds.sh extraer y abre lambda-crypto-s3-rds.py. No hay que cambiar nada: el bucket y la RDS le llegan por variables de entorno.

3. Crea todo y despliega el código:

./gestionar-crypto-s3-rds.sh crear

Qué verás, en orden (los textos pueden variar ligeramente): "Verificando prerequisitos"; "Detectando Configuración de RDS" con "RDS detectado automáticamente" (host, usuario, contraseña, base crypto y tabla coins); "Configurando Bucket S3" con "Usando bucket del stack ETL: ..." (sin el Paso 0 se para aquí sin crear nada); "Preparando el código y la plantilla"; "Creando Paquete Lambda" (instala pymysql, "Tamaño del paquete"; se hace antes de crear nada, así que si falla no queda nada a medias); "Stack de CloudFormation" ("Creando el stack cunef-etl-crypto-rds ..." con puntos de progreso y "Stack ... creado"; tarda 1-2 minutos); "Desplegando Función Lambda" con "Actualizando función existente...", "Código actualizado" y "Configuración actualizada"; y la pregunta ¿Deseas probar la función ahora? (s/n):. Responde s.

Tras la prueba verás un JSON con "statusCode": 200; en body.s3 las rutas guardadas y en body.rds "success": true con "records_inserted": 10, "database": "crypto" y "table": "coins". El script añade "Datos guardados en RDS exitosamente" y "Registros insertados: 10". Si esas dos líneas no aparecen, rds.success no fue true: el script avisa con ⚠ La parte de RDS no se completó y el motivo; lee también rds.message. El script espera a que la configuración de la función esté activa antes de probar; si aun así el motivo dice Host: NO CONFIGURADO, espera 30 segundos y repite la prueba con ./gestionar-crypto-s3-rds.sh probar.

4. Comprueba el estado cuando quieras:

./gestionar-crypto-s3-rds.sh estado

Qué verás: una línea por elemento con ✓ o ⚠ (RDS y bucket de la infraestructura base, stack, función con su estado, tamaño de código y si tiene la RDS configurada, rol, datos en S3, reglas de EventBridge, grupo de logs), la fecha de la última ejecución, las últimas líneas del log y una última línea "Siguiente paso: ...". Las filas de la tabla se miran en Adminer.

5. Prueba la función a mano:

aws lambda invoke --function-name crypto-price-tracker-rds \
  --cli-binary-format raw-in-base64-out --payload '{}' \
  --region eu-north-1 out.json
cat out.json

Qué verás: "StatusCode": 200 del CLI y, en out.json, statusCode 200 con rds.success en true. Esta vez no le pasas el bucket en el evento: lo toma de su variable de entorno S3_BUCKET. (./gestionar-crypto-s3-rds.sh probar hace lo mismo pasando el bucket y resumiendo el resultado.)

6. Comprueba los dos destinos:

aws s3 ls s3://$BUCKET/crypto/ --recursive --human-readable

En Adminer (abre $ADMINER y entra como en la carpeta 05.01: Sistema MySQL, Servidor $RDS, usuario admin, contraseña CunefAdmin!; base crypto, enlace SQL command):

SELECT COUNT(*) FROM crypto.coins;
SELECT * FROM crypto.coins ORDER BY timestamp DESC LIMIT 10;

Qué verás: en S3, crypto/raw/history/crypto_prices_....json y crypto/raw/crypto_prices_latest.json. En Adminer, 10 tras la primera ejecución (10 más por cada ejecución siguiente) y las filas con las columnas id, timestamp, coin_id, currency, price, market_cap, volume_24h, change_24h, last_updated_at, created_at. Para Power BI (si la presentación te lo pide) usa el mismo servidor, usuario y contraseña que en el Ejercicio 1 (carpeta 05.02, paso 6) y la base crypto.

7. (Opcional) Programar la ejecución cada minuto: ./gestionar-crypto-s3-rds.sh programar (y desprogramar al terminar), o los comandos a mano de la carpeta Tema 5 · 6 · Programar con EventBridge con FN=crypto-price-tracker-rds. Se apaga sola a las 4 h (ver Apagado automático); bórrala al terminar. En esta variante, cada minuto añade dos ficheros y diez filas.

Apagado automático

La programación de EventBridge se apaga sola a las 4 horas: una regla de cada minuto que se olvida sigue ejecutando la función (y llamando a CoinGecko) para siempre. La regla se desactiva, no se borra; solo desprogramar o eliminar la borran.

Quiero... Comando
Programar la función (4 h por defecto) ./gestionar-crypto-s3-rds.sh programar (cada minuto) o, por ejemplo, ./gestionar-crypto-s3-rds.sh programar 5 --horas 2
Ver cuánto queda ./gestionar-crypto-s3-rds.sh estado (línea Apagado automático: se apagará a las HH:MM UTC (dentro de N min))
Ampliar el plazo otras 4 h ./gestionar-crypto-s3-rds.sh extender (otro plazo: extender --horas 8)
Que no se apague nunca ./gestionar-crypto-s3-rds.sh programar --permanente o extender --permanente (¡la función seguirá ejecutándose hasta que la quites!)
Reactivar tras el apagado ./gestionar-crypto-s3-rds.sh programar (reactiva la regla y renueva el plazo)
Quitar la regla / borrarlo todo ./gestionar-crypto-s3-rds.sh desprogramar / ./gestionar-crypto-s3-rds.sh eliminar (funcionan también con la regla desactivada)

Cómo funciona: programar guarda el plazo (hora UTC de vencimiento, o permanente) en la variable de entorno APAGAR_TRAS de la función. En cada ejecución programada, la función la mira y, si ya venció, desactiva su propia regla (su rol de IAM solo puede desactivar esa regla) y no ejecuta el ETL. Se nota en la primera ejecución tras el vencimiento (con rate(1 hour) puede tardar hasta 1 h). probar y las invocaciones a mano no se ven afectadas. Si editas el código con extraer, conserva la función apagado_automatico y su llamada al principio de lambda_handler.

Errores frecuentes

Limpieza

Hazla cuando termines:

./gestionar-crypto-s3-rds.sh eliminar

Te enseña qué va a borrar y pide confirmación (con --si no pregunta). Borra, forzando si hace falta y de forma repetible (puedes lanzarlo otra vez sin riesgo): las reglas de EventBridge de la función y su permiso, los ficheros crypto/raw/ que la función guardó en el bucket, la tabla crypto.coins de la RDS (y la base crypto si queda vacía; la hace borrar la propia función justo antes de eliminarse), el stack cunef-etl-crypto-rds (función y rol; si CloudFormation se atasca, reintenta y retiene solo lo imprescindible), el rol sobrante LambdaCryptoTrackerRDSRole de versiones antiguas (si existe) y el grupo de logs. No toca el stack cunef-etl (bucket, RDS y Adminer) ni otros ejercicios.

Qué verás: cinco bloques ("1/5 Programación de EventBridge", "2/5 Datos del ejercicio", "3/5 Stack...", "4/5 Recursos sueltos", "5/5 Comprobación final") y, al final, ✓ Todo eliminado. No queda nada de este ejercicio en AWS. Si algo no se pudo borrar, lo dice con ⚠ y termina con error: repite el comando. Para comprobar la RDS, en Adminer: SHOW DATABASES; (no debe aparecer crypto).

Opcional: ficheros de CloudShell (cd ~ && rm -rf 05.05-cryptoas3yrds 05.05-cryptoas3yrds.zip).

No borres la infraestructura base todavía si vas a hacer más actividades (05.07 y 05.08 también la usan). El borrado de la infraestructura base (carpeta 05.01, sección Limpieza) debe ser el último paso de todo el Tema 5.

Cómo sabes que has terminado


Anterior: Tema 5 · 4 · CoinGecko a DynamoDB · Siguiente: Tema 5 · 6 · Programar con EventBridge