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.09-adicionalcclima

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 = CUNEF y actividad = 05.09-adicionalcclima. Si algún día hay que borrar recursos a mano, se localizan todos de golpe con aws 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

Cómo llevar los ficheros a CloudShell

  1. 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).
  2. En CloudShell (región eu-north-1): Actions → Upload file y elige 05.09-adicionalcclima.zip.
  3. 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 con cd ~/g214-materiales/tema5/05.09-adicionalcclima y, si algún fichero da Permission 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

Limpieza

Hazla cuando termines, en este orden, y solo borra lo que hayas creado tú:

  1. Regla de EventBridge (si creaste una): aws events remove-targets --rule NOMBRE --ids 1 --region eu-north-1 y aws events delete-rule --name NOMBRE --region eu-north-1 (o EventBridge → Rules → Delete).

  2. 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-c
    

    Un error NoSuchEntity significa que ese elemento ya no existía.

  3. La tabla DynamoDB (y sus datos): aws dynamodb delete-table --table-name Clima --region eu-north-1.

  4. 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


Anterior: Tema 5 · 8 · Adicional B (Euribor) · Siguiente: (ninguna, es la última actividad del Tema 5)