# Tema 2 · 8 · Ejercicio B: publicar datos abiertos y pagar la salida Presentación del Tema 2: «Ejercicio B» (datos abiertos y coste de salida) y «Ejercicio B · paso a paso». Duración: unos 45 minutos. Coste: céntimos si borras el mismo día. > **¿Dudas con un script?** Todos los scripts de esta carpeta traen su propia ayuda: `./descargar-datos.sh --ayuda` · `./gestionar-datos-abiertos.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-datos-abiertos.sh crear` etiqueta el bucket con `curso` = `G214`, `universidad` = `CUNEF`, `actividad` = `02.08-ejerciciobdatosabiertos` y `script` = `gestionar-datos-abiertos.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=02.08-ejerciciobdatosabiertos`. 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 **Contexto.** El Ayuntamiento quiere publicar los datos horarios de calidad del aire para que cualquiera los descargue. Te piden montarlo en S3 y estimar la factura antes de aprobarlo. Publicas el mismo fichero de **tres formas** (cada una con un nivel de apertura distinto), mides su tamaño y calculas qué cuestan 10.000 descargas al mes, con y sin comprimir. | Vía | Cómo se publica | El bucket queda | |---|---|---| | 1 · URL firmada | `aws s3 presign` | Privado; la URL caduca. Es la opción correcta para compartir con una persona concreta | | 2 · Sitio web estático | Bucket policy de lectura + `index.html` + *Static website hosting* | Público (único caso del curso, solo porque el dato es público por definición). Solo HTTP | | 3 · CLI autenticada | `aws s3 cp` con credenciales | Privado; ni URL firmada ni bucket abierto | ## Qué se crea en AWS Un bucket `g214--aire` con `aire.csv`, `aire.csv.gz` e `index.html`, y (temporalmente) su bloqueo de acceso público desactivado y una política de lectura. ## Qué contiene esta carpeta | Fichero | Para qué sirve | Se usa en | |---|---|---| | `gestionar-datos-abiertos.sh` | **Todo el ejercicio en un script**: `crear` (descarga, bucket, URL firmada, `.gz` y sitio web con sus 4 pasos), `estado`, `eliminar` (cierra el acceso público y fuerza el borrado) y `extraer`. Ver «Camino rápido» | Todos los pasos | | `descargar-datos.sh` | Descarga la calidad del aire de Madrid (`aire.csv`, unos 20 MB) y el padrón del INE, con reintentos y validación; también `estado` y `eliminar` | Paso 1 (`aire`) | | `politica-sitio-web.json` | Política de lectura pública; lleva el marcador `TU-BUCKET` en el `Resource` que **debes sustituir** por tu bucket | Paso 4 | | `index.html` | Página de inicio del sitio web; enlaza `aire.csv` **y** `aire.csv.gz` | Paso 4 | ## Antes de empezar - [ ] Has hecho [`02.01-s3primerbucket`](../02.01-s3primerbucket/README.md) (bucket, CloudShell, `presign`). - [ ] CloudShell abierto en **eu-north-1**. Sube esta carpeta (zip de `02.08-ejerciciobdatosabiertos`, *Actions → Upload file*) y entra: ```bash unzip -o 02.08-ejerciciobdatosabiertos.zip cd 02.08-ejerciciobdatosabiertos chmod -R u+rwX . && chmod +x *.sh ``` > Si ya subiste `g214-materiales.zip` (README principal), no necesitas este zip: entra con `cd ~/g214-materiales/tema2/02.08-ejerciciobdatosabiertos` y, si algún fichero da `Permission denied`, ejecuta allí `chmod -R u+rwX . && chmod +x *.sh`. - [ ] Nombre de bucket único: `g214--aire` (en esta guía `MI-BUCKET` es el tuyo). ## Camino rápido: un solo script (`gestionar-datos-abiertos.sh`) Hace los pasos 1 a 6 por ti (también la vía 2, con sus cuatro pasos en orden) y se puede repetir sin riesgo. Los pasos «a mano» de abajo son los de las diapositivas; usa uno u otro camino. ```bash ./gestionar-datos-abiertos.sh # con terminal: menú numerado (sin terminal: muestra la ayuda) ./gestionar-datos-abiertos.sh crear # te pregunta tu apellido (propone un nombre) y recuerda el bucket en .gestionar-datos-abiertos.conf ./gestionar-datos-abiertos.sh crear --apellido garcia # sin preguntar: bucket g214-garcia-aire (o --bucket g214-garcia-aire) ./gestionar-datos-abiertos.sh crear --sin-web # sin abrir el bucket al público (solo las vías 1 y 3) ./gestionar-datos-abiertos.sh estado # bucket, objetos, bloqueo de acceso público, política, sitio web y ficheros locales (no modifica nada) ./gestionar-datos-abiertos.sh eliminar # pide confirmación; con --si no pregunta. Reactiva el bloqueo de acceso público, quita política y sitio web, fuerza el borrado y limpia los ficheros ./gestionar-datos-abiertos.sh extraer # escribe politica-sitio-web.json (con TU-BUCKET) e index.html, que lleva embebidos ./gestionar-datos-abiertos.sh ayuda ``` **Qué hace `crear`** (7 pasos numerados): comprueba la CLI v2, tus credenciales y la región; descarga y valida `aire.csv`; crea el bucket privado; sube `aire.csv` y te da la URL firmada de 1 hora (vía 1, comprobando que abre sin credenciales); comprime y sube `aire.csv.gz`; hace los cuatro pasos de la vía 2 en orden (quitar el bloqueo, política con tu bucket ya sustituido, `index.html`, `aws s3 website`) y comprueba por HTTP que el sitio responde; al final muestra los tamaños y los GB de salida de 10.000 descargas. **El bucket queda abierto al público hasta que ejecutes `eliminar`.** La parte de AWS de este script (probada en AWS real, con y sin `--sin-web`): si algo falla, te dice qué ha pasado y qué hacer. ## Paso a paso ### Paso 1 · Descarga los datos y crea el bucket ```bash ./descargar-datos.sh aire # aire.csv (20,2 MB = 19,2 MiB, datos horarios desde 2025 del portal de Madrid) aws s3 mb s3://g214-apellido-aire --region eu-north-1 aws s3 cp aire.csv s3://g214-apellido-aire/ --content-type text/csv ``` ### Paso 2 · Vía 1: URL firmada ```bash aws s3 presign s3://g214-apellido-aire/aire.csv --expires-in 3600 ``` **Qué verás:** una URL que abre el CSV sin credenciales durante una hora. El bucket sigue privado. ### Paso 3 · Vía 3: descarga autenticada ```bash aws s3 cp s3://g214-apellido-aire/aire.csv . ``` ### Paso 4 · Vía 2: sitio web estático (cuatro pasos, **en este orden**) `aws s3 website` **por sí solo no publica nada** (da `403`). ```bash # 1) quitar el bloqueo de acceso público (con él activo, la política pública se rechaza: BlockPublicPolicy) aws s3api put-public-access-block --bucket g214-apellido-aire \ --public-access-block-configuration BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false # 2) política de solo lectura: politica-sitio-web.json trae el marcador TU-BUCKET en el Resource; # sustitúyelo por el nombre de TU bucket (sin este cambio, put-bucket-policy falla: el bucket no existe) sed -i 's/TU-BUCKET/g214-apellido-aire/' politica-sitio-web.json # en CloudShell/Linux; en Mac: sed -i '' ... grep Resource politica-sitio-web.json # debe mostrar arn:aws:s3:::g214-apellido-aire/* aws s3api put-bucket-policy --bucket g214-apellido-aire --policy file://politica-sitio-web.json # 3) página de inicio (sin ella el sitio da 404 NoSuchKey) aws s3 cp index.html s3://g214-apellido-aire/ --content-type text/html # 4) activar el sitio web aws s3 website s3://g214-apellido-aire --index-document index.html ``` **Qué verás:** la dirección es `http://g214-apellido-aire.s3-website.eu-north-1.amazonaws.com`. **Solo HTTP**: el endpoint de sitio web no admite HTTPS. Si da `403` justo después de subir `index.html`, espera 10 segundos y repite. ### Paso 5 · Mide el fichero y calcula la factura **Unidades.** El ejercicio usa **MB y GB decimales**: tamaño en bytes ÷ 1.000.000 = MB; MB × 10.000 descargas ÷ 1.000 = GB de salida al mes. Con MiB y GiB (1024) saldrían otras cifras (unos 188 GiB y 7,9 USD): usa siempre el mismo convenio y comprueba en calculator.aws cuál aplica. ```bash wc -c aire.csv # tamaño en bytes ``` **Medidas reales:** `aire.csv` pesa 20.166.384 bytes (**20,2 MB**, 19,2 MiB). 10.000 descargas al mes del CSV son unos **201,7 GB** de salida: (201,7 − 100 GB gratis) × 0,09 USD/GB = **unos 9,15 USD/mes**. Los 100 GB gratuitos son por cuenta y no por bucket. Con un CSV de 50 MB serían 500 GB y unos 36 USD. ### Paso 6 · Comprime y repite el cálculo El `index.html` enlaza `aire.csv` **y** `aire.csv.gz`; sin este paso el segundo enlace da `404`: ```bash gzip -k aire.csv # deja aire.csv y crea aire.csv.gz (2.189.547 bytes) aws s3 cp aire.csv.gz s3://g214-apellido-aire/ --content-type application/gzip ``` **Qué verás:** el `.gz` pesa 2,2 MB, **un noveno** (factor 9,2). 10.000 descargas son unos 21,9 GB: caben en los 100 GB gratuitos, **0 USD**. ### Paso 7 · Responde por escrito - **¿Qué partida domina la factura, el almacenamiento o la salida de datos?** (La salida: almacenar 20 MB cuesta céntimos; servirlo 10.000 veces, 9,15 USD.) - **¿A partir de cuántas descargas conviene una CDN (CloudFront)?** Referencia de lista (verifícala en calculator.aws): CloudFront da **1 TB/mes de salida gratis** y después cobra unos **0,085 USD/GB** en Europa; el tráfico de S3 hacia CloudFront no se cobra. S3 empieza a cobrar a partir de 100 GB/mes (unas 5.000 descargas del CSV de 20,2 MB) y CloudFront no cobra hasta 1 TB/mes (unas 50.000 descargas): con 10.000 descargas son **9,15 USD desde S3 frente a 0 USD** con CDN. Por encima de 1 TB la CDN sigue siendo algo más barata por GB (0,085 frente a 0,09 USD) y además cachea el fichero cerca de los usuarios. **Entregable:** las URL de las vías 1 y 2, el comando de la vía 3, la estimación en PDF y la respuesta razonada. ## Errores frecuentes | Qué ves | Causa | Solución | |---|---|---| | El sitio web da `403` | Falta el paso 1, 2 o 3 de la vía 2, o el bloqueo sigue activo | Repite los pasos en orden; espera 10 s tras subir `index.html` | | El sitio web da `404 NoSuchKey` | No hay `index.html` | `aws s3 cp index.html s3://g214-apellido-aire/` | | El enlace `aire.csv.gz` del sitio da `404` | No has subido el `.gz` | Paso 6 | | `AccessDenied ... BlockPublicPolicy` al poner la política | El bloqueo de acceso público sigue activo | Haz primero el paso 1 de la vía 2 | | `put-bucket-policy` falla con `MalformedPolicy` o `Invalid bucket name` | `politica-sitio-web.json` sigue con el marcador `TU-BUCKET` | `sed -i 's/TU-BUCKET/g214-apellido-aire/' politica-sitio-web.json` y comprueba con `grep Resource politica-sitio-web.json` | | `aire.csv` pesa unos pocos KB | La descarga devolvió una página de error | `./descargar-datos.sh estado` dice el motivo; repite con `./descargar-datos.sh aire --forzar` | ## Limpieza (el bucket quedó abierto: ciérralo) Lo más fácil: `./gestionar-datos-abiertos.sh eliminar` (hace los dos pasos de abajo, quita política y sitio web, vacía el bucket y limpia los ficheros locales). A mano: ```bash # 1) volver a activar el bloqueo de acceso público (los cuatro a true) aws s3api put-public-access-block --bucket g214-apellido-aire \ --public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true # 2) borrar el bucket (sin versionado funciona) aws s3 rb s3://g214-apellido-aire --force aws s3 ls | grep g214 # no debe salir ningún bucket tuyo ``` ## Cómo sabes que has terminado - [ ] Has abierto el CSV con la URL firmada (vía 1), el sitio web (vía 2) y `aws s3 cp` (vía 3). - [ ] Tienes el cálculo de 10.000 descargas con y sin `.gz` y la respuesta sobre CloudFront. - [ ] Has vuelto a activar el bloqueo de acceso público y borrado el bucket. Anterior: [`02.07-ejercicioaciclodevida`](../02.07-ejercicioaciclodevida/README.md) · Siguiente: [`02.09-ejerciciocbicimad`](../02.09-ejerciciocbicimad/README.md)