Tema 5 · 9 · Ejercicio adicional C: meteorología (Open-Meteo) a DynamoDB
Presentación del Tema 5: «Ejercicio C · ETL meteorológico a DynamoDB» (ejercicios adicionales; solo si tu docente te lo pide). Duración: a tu ritmo (el entorno se prepara en 15 min). Coste: prácticamente nulo (Lambda y DynamoDB en modo bajo demanda con este volumen). Esta actividad no necesita la infraestructura base (carpeta 05.01).
Etiquetas de lo que creas. Todo recurso que crees a mano (máquina, volumen, bucket, base de datos, tabla, función...) ponle estas etiquetas, al crearlo (apartado Tags / Etiquetas) o después desde su pestaña de etiquetas:
curso=G214,universidad=CUNEFyactividad=05.09-adicionalcclima. Si algún día hay que borrar recursos a mano, se localizan todos de golpe conaws resourcegroupstaggingapi get-resources --region eu-north-1 --tag-filters Key=actividad,Values=05.09-adicionalcclima. 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
Un ETL completo sobre una API pública real: una Lambda propia pide a Open-Meteo la temperatura y la precipitación horarias de varias ciudades y las guarda en una tabla de DynamoDB (Clima, clave ciudad + ts). Esta actividad no trae script ni plantilla: creas tú la tabla y la función con la receta de abajo. Este README prepara el entorno, te da el esqueleto corregido del código (adicional-c-clima.py, el mismo) y cómo comprobarlo; el diseño completo, la comparación query/scan y las reglas son el entregable y los haces tú.
Qué se crea en AWS: una tabla DynamoDB Clima (On-demand), una función Lambda propia y un rol de IAM propio. Entregable: regla de EventBridge y comparación query / scan.
Qué contiene esta carpeta
| Fichero | Para qué sirve | En qué paso se usa |
|---|---|---|
adicional-c-clima.py |
Esqueleto corregido de la Lambda: pide a Open-Meteo la predicción horaria de cada ciudad de la variable CIUDADES y escribe un ítem por ciudad y hora en la tabla Clima (valores como Decimal; avisa en logs si la temperatura supera 25 °C). No es la solución completa: faltan la regla de EventBridge y la comparación query / scan. No lo despliega ningún script. |
Paso 4 (es el código de tu función) |
README.md |
Este documento. | Siempre |
Antes de empezar
- No depende de la carpeta 05.01 (tiene su propia tabla). Solo necesitas una cuenta de AWS con permisos para crear recursos.
- Región eu-north-1 (Estocolmo).
- Usa nombres de función y rol que no choquen con los del laboratorio (no reutilices
crypto-price-tracker*). Aquí se usanetl-adicional-cyrol-etl-adicional-c.
Cómo llevar los ficheros a CloudShell
- En tu PC, comprime esta carpeta entera (
05.09-adicionalcclima): clic derecho → Comprimir en archivo ZIP (Windows 11), Enviar a > Carpeta comprimida en zip (Windows 10) o Comprimir (Mac). - En CloudShell (región eu-north-1): Actions → Upload file y elige
05.09-adicionalcclima.zip. - Ejecuta:
cd ~
unzip -o 05.09-adicionalcclima.zip && cd 05.09-adicionalcclima && chmod -R u+rwX .
ls
Si ya subiste
g214-materiales.zip(README principal), no necesitas este zip: entra concd ~/g214-materiales/tema5/05.09-adicionalcclimay, si algún fichero daPermission denied, ejecuta allíchmod -R u+rwX . && chmod +x *.sh.
Qué verás: adicional-c-clima.py y README.md. (No hay .sh, no hace falta chmod.)
Paso a paso
1. Prueba la API desde CloudShell (URL entre comillas y en una sola línea):
curl -s "https://api.open-meteo.com/v1/forecast?latitude=40.4168&longitude=-3.7038&hourly=temperature_2m,precipitation" | head -c 800
Qué verás: un JSON con hourly (time, temperature_2m, precipitation): 168 valores horarios (7 días) por ciudad. La API da una predicción: la tabla solo tendrá de hoy a +7 días. Para tener también el pasado (y poder consultar "las últimas 24 horas") añade &past_days=1 a la URL del código.
2. Crea la tabla antes de ejecutar (clave de partición ciudad, de ordenación ts, modo On-demand):
aws dynamodb create-table --table-name Clima \
--attribute-definitions AttributeName=ciudad,AttributeType=S AttributeName=ts,AttributeType=S \
--key-schema AttributeName=ciudad,KeyType=HASH AttributeName=ts,KeyType=RANGE \
--billing-mode PAY_PER_REQUEST --region eu-north-1
aws dynamodb describe-table --table-name Clima --region eu-north-1 --query Table.TableStatus
Qué verás: el JSON de la tabla y, en el segundo comando, "ACTIVE" (si dice CREATING, espera unos segundos y repite).
3. Crea un rol propio con acceso a tu tabla (una sola vez; solo Clima: escritura por lotes, Query y Scan; la cuenta se lee con sts):
ROLE=rol-etl-adicional-c
cat > confianza.json <<'EOF'
{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"lambda.amazonaws.com"},"Action":"sts:AssumeRole"}]}
EOF
ROLE_ARN=$(aws iam create-role --role-name $ROLE \
--assume-role-policy-document file://confianza.json --query Role.Arn --output text)
aws iam attach-role-policy --role-name $ROLE \
--policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
echo "$ROLE_ARN"
sleep 10
ACC=$(aws sts get-caller-identity --query Account --output text)
cat > politica.json <<EOF
{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["dynamodb:PutItem","dynamodb:BatchWriteItem","dynamodb:Query","dynamodb:Scan","dynamodb:DescribeTable"],"Resource":"arn:aws:dynamodb:eu-north-1:$ACC:table/Clima"}]}
EOF
aws iam put-role-policy --role-name $ROLE --policy-name permisos-mios \
--policy-document file://politica.json
Qué verás: el ARN del rol (arn:aws:iam::<cuenta>:role/rol-etl-adicional-c). Los demás comandos no imprimen nada. El rol base solo escribe logs; la política añade únicamente acceso a la tabla Clima.
4. Empaqueta y crea la función (sin librerías extra; boto3 ya viene en Lambda). Sube el timeout a 60 s: con cinco ciudades hay cinco peticiones HTTP y 840 escrituras por lotes por ejecución. Medido: el código tarda ~1 s desde una EC2 y 2,6-3 s en Lambda con 128 MB; con el timeout por defecto de 3 s da Task timed out o pasa por los pelos, así que no dependas de él.
cp adicional-c-clima.py lambda_function.py
zip -q funcion.zip lambda_function.py
aws lambda create-function --function-name etl-adicional-c --runtime python3.12 \
--handler lambda_function.lambda_handler --role "$ROLE_ARN" \
--zip-file fileb://funcion.zip --timeout 60 --memory-size 256 --region eu-north-1
Qué verás: un JSON con la configuración de la función ("FunctionName": "etl-adicional-c", "Timeout": 60). Si dice que el rol no se puede asumir, espera unos segundos y repite.
5. Define la variable CIUDADES en la consola (el JSON lleva llaves, comillas y comas: es más cómodo ahí). Ve a Lambda → etl-adicional-c → Configuration → Environment variables → Edit → Add environment variable, clave CIUDADES y valor (cinco capitales o más):
{"Madrid": [40.4168, -3.7038], "Barcelona": [41.3851, 2.1734], "Sevilla": [37.3891, -5.9845], "Valencia": [39.4699, -0.3763], "Bilbao": [43.263, -2.935]}
Qué verás: la variable aparece en la lista de variables de entorno. (Las coordenadas de ejemplo son orientativas; esta lista está probada: 5 ciudades, {"escritos": 840}; usa las de las ciudades que quieras.) Sin esta variable el código falla al arrancar con KeyError: 'CIUDADES'.
6. Invócala y mira los logs:
aws lambda invoke --function-name etl-adicional-c --cli-binary-format raw-in-base64-out \
--payload '{}' --region eu-north-1 salida.json
cat salida.json
aws logs tail /aws/lambda/etl-adicional-c --since 10m --region eu-north-1
Qué verás: {"escritos": 840} con cinco ciudades (5 x 168 horas); repetir la ejecución no duplica (misma clave ciudad + ts). En los logs, líneas AVISO <ciudad> <hora>: <temp> C cuando se supera el umbral de 25 °C del esqueleto (salta en varias capitales; ajústalo si quieres ver otro resultado). Si la función lanza una excepción, invoke muestra "FunctionError": "Unhandled" y el detalle está en salida.json y en los logs.
7. Comprueba la tabla:
aws dynamodb scan --table-name Clima --select COUNT --region eu-north-1 --query Count --output text
aws dynamodb query --table-name Clima --key-condition-expression "ciudad = :c" \
--expression-attribute-values '{":c":{"S":"Madrid"}}' --select COUNT \
--return-consumed-capacity TOTAL --region eu-north-1
Qué verás: el primero, 840; el segundo, Count 168 para Madrid (168 horas por ciudad). Valores de referencia para la comparación query / scan del entregable: un query de una ciudad y un día (Count 24) consume unas 0,5 unidades de capacidad; el scan equivalente con filtro, unas 6 (--return-consumed-capacity TOTAL).
8. Entregable (lo haces tú): la regla de EventBridge (ver la carpeta 05.06 para los comandos de una regla, con tu función etl-adicional-c) y la comparación query / scan.
Errores frecuentes
Task timed out after 3.00 seconds. La función se creó con el tiempo máximo por defecto (3 s) y no le dio tiempo. Súbelo a 60 s:aws lambda update-function-configuration --function-name etl-adicional-c --timeout 60 --region eu-north-1(o Configuration → General configuration). Con el comando del paso 4 ya lo llevas.HTTP Error 502/504o429. La API pública está saturada. En este código la función falla (no haytry/except): invócala de nuevo pasado un minuto.Float types are not supported. DynamoDB no admitefloaten boto3: guarda los números comoDecimal(str(valor))(como hace el esqueleto) o como cadena.KeyError: 'CIUDADES'oJSONDecodeError. Falta la variable de entorno del paso 5, o el JSON está mal escrito (comillas dobles, corchetes y comas).AccessDeniedExceptional escribir en DynamoDB. Tu rol no tiene la política del paso 3, o la tabla no se llamaClima(el código y la política usan ese nombre).ResourceNotFoundException. La tablaClimano existe o está en otra región: repite el paso 2 en eu-north-1.- Pocos o ningún dato de ayer. La API da una predicción de 7 días: añade
&past_days=1a la URL del código.
Limpieza
Hazla cuando termines, en este orden, y solo borra lo que hayas creado tú:
-
Regla de EventBridge (si creaste una):
aws events remove-targets --rule NOMBRE --ids 1 --region eu-north-1yaws events delete-rule --name NOMBRE --region eu-north-1(o EventBridge → Rules → Delete). -
La función y su rol:
aws lambda delete-function --function-name etl-adicional-c --region eu-north-1 aws iam detach-role-policy --role-name rol-etl-adicional-c \ --policy-arn arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole aws iam delete-role-policy --role-name rol-etl-adicional-c --policy-name permisos-mios aws iam delete-role --role-name rol-etl-adicional-cUn error
NoSuchEntitysignifica que ese elemento ya no existía. -
La tabla DynamoDB (y sus datos):
aws dynamodb delete-table --table-name Clima --region eu-north-1. -
Opcional: el grupo de logs (
aws logs delete-log-group --log-group-name /aws/lambda/etl-adicional-c --region eu-north-1) y los ficheros de CloudShell (cd ~ && rm -rf 05.09-adicionalcclima 05.09-adicionalcclima.zip).
Esta actividad no usa la infraestructura base, así que no depende de que la borres. Si la tienes creada por otras actividades, su borrado (carpeta 05.01, sección Limpieza) debe ser el último paso de todo el Tema 5.
Cómo sabes que has terminado
- [ ] La tabla
ClimaestáACTIVE. - [ ] La invocación devolvió
{"escritos": 840}con cinco ciudades (5 x 168 horas) y repetirla no cambia el recuento. - [ ] Entregaste lo que pide la diapositiva (código, regla de EventBridge y comparación query / scan).
- [ ] Has hecho la limpieza de esta actividad (regla, función, rol y tabla
Clima).
Anterior: Tema 5 · 8 · Adicional B (Euribor) · Siguiente: (ninguna, es la última actividad del Tema 5)