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 / tema3 / 03.07-dynamodbcli

Tema 3 · 7 · DynamoDB: tabla Usuarios, CLI, Python y exportar/importar con S3

Presentación del Tema 3: «Creación de base de datos DynamoDB», «Acceso desde AWS CLI», «Ejemplo aplicaciones uso DynamoDB – Ejercicio 1» (Python: dynamodb-cli.py) y «Ejercicio 3» (exportar e importar con S3). Duración: unos 10 minutos con dynamodb-cli.py y unos 10 minutos más (casi todo espera) con S3: ~2,5 min la exportación y ~3 min la importación, incluso con 7 ítems (medido). Coste: con tablas pequeñas, céntimos; PITR cuesta 0,21 USD por GB-mes mientras esté activo.

¿Dudas con un script? Todos los scripts de esta carpeta traen su propia ayuda: python3 dynamodb-cli.py --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. 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 = 03.07-dynamodbcli. 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=03.07-dynamodbcli. 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 trabajar con una base no relacional, Amazon DynamoDB: crear la tabla Usuarios (consola o CLI), leer y escribir ítems con la AWS CLI y con un script de Python (boto3) desde CloudShell, y por último exportar la tabla a S3 y reimportarla en una tabla nueva.

CloudShell ──aws dynamodb ... / dynamodb-cli.py──> tabla Usuarios (UserID, String)
tabla Usuarios ──export (PITR)──> S3 (AWSDynamoDB/<código>/data/*.json.gz) ──import──> tabla nueva

Qué se crea en AWS: la tabla Usuarios (modo on-demand), opcionalmente un bucket de S3, la exportación a S3 (carpeta AWSDynamoDB/), una tabla nueva al importar y un grupo de logs /aws-dynamodb/imports. dynamodb-cli.py en sí no crea nada: lee o escribe un ítem en una tabla que ya existe.

Qué contiene esta carpeta

Fichero Para qué sirve En qué paso se usa
dynamodb-cli.py Script de Python con boto3 para leer o escribir UN ítem en DynamoDB desde la terminal Pasos 4 a 6
README.md Esta guía (incluye los comandos de la AWS CLI y de la exportación/importación) Siempre

Antes de empezar

Comprobación previa en CloudShell:

aws sts get-caller-identity
echo "$AWS_REGION"

Qué verás: un JSON con tu cuenta y eu-north-1. Si imprime otra región, cierra CloudShell, cambia la región de la consola a Estocolmo y ábrelo de nuevo.

Cómo llevar los ficheros a donde toque

Se hace en CloudShell, porque necesita credenciales de AWS.

  1. En tu PC, comprime esta carpeta (clic derecho sobre 03.07-dynamodbcli > Comprimir en archivo ZIP, o Enviar a > Carpeta comprimida en zip en Windows 10). Obtienes 03.07-dynamodbcli.zip.
  2. En la consola de AWS (región eu-north-1) abre CloudShell, pulsa Actions > Upload file y sube el zip.
  3. Descomprime y deja el script listo:
unzip -o 03.07-dynamodbcli.zip && cd 03.07-dynamodbcli && chmod -R u+rwX .
sed -i 's/\r$//' *.py
chmod +x *.py
ls

Si ya subiste g214-materiales.zip (README principal), no necesitas este zip: entra con cd ~/g214-materiales/tema3/03.07-dynamodbcli y, si algún fichero da Permission denied, ejecuta allí chmod -R u+rwX . && chmod +x *.py.

sed quita los finales de línea de Windows (si no, bash falla con bad interpreter o $'\r': command not found) y chmod +x da permiso de ejecución (un zip creado en Windows no lo conserva; sin él, ./dynamodb-cli.py da Permission denied). Qué verás: ls muestra README.md y dynamodb-cli.py.

Alternativa para subir solo el script: Actions > Upload file y elige dynamodb-cli.py, y luego sed -i 's/\r$//' dynamodb-cli.py && chmod +x dynamodb-cli.py. Si cierras CloudShell, al volver entra con cd 03.07-dynamodbcli (si no encuentras la carpeta, vuelve a subir el zip).

Paso a paso

Paso 1. Crear la tabla Usuarios. En la presentación se crea desde la consola. El mismo resultado por CLI, en CloudShell:

aws dynamodb create-table --table-name Usuarios \
  --attribute-definitions AttributeName=UserID,AttributeType=S \
  --key-schema AttributeName=UserID,KeyType=HASH \
  --billing-mode PAY_PER_REQUEST --region eu-north-1
aws dynamodb wait table-exists --table-name Usuarios --region eu-north-1

Qué verás: TableStatus: CREATING y, tras wait (unos 25 s), la tabla ACTIVE en modo PAY_PER_REQUEST (on-demand). La consola, con Use default settings, puede elegir otro modo de capacidad; para el laboratorio da igual. Los tres ítems de la presentación (u001 a u003) se añaden con put-item o desde la consola. Modo de capacidad: aprovisionado (reservas lecturas y escrituras por segundo y las pagas aunque no las uses) o bajo demanda, PAY_PER_REQUEST (pagas solo por petición); para el laboratorio vale cualquiera.

Paso 2. Búsqueda en la consola. Resultado esperado del Scan con filtro UserID = u001 sobre los tres ítems: Items returned 1, Items scanned 3, RCUs consumed 2 y Efficiency 33,33 %; con Query solo se lee el ítem pedido.

Paso 3. Comandos aws dynamodb ... de la presentación. Resultados medidos: get-item de un ítem pequeño consume 0.5 unidades de lectura (1.0 con --consistent-read); query por clave, 0.5; scan de la tabla, 2.0 (también con 3 ó 7 ítems: cuesta 0,5 por cada partición de la tabla) y sin cambio con --projection-expression (la proyección reduce los datos devueltos, no el consumo). Límites que conviene saber: un ítem pesa como máximo 400 KB y batch-write-item admite 25 ítems por llamada. Dos consejos, porque esos comandos no llevan --region:

Paso 4. Comprobar boto3.

python3 -c "import boto3; print(boto3.__version__)"

Qué verás: un número de versión. Si sale ModuleNotFoundError: No module named 'boto3', instálalo con pip3 install --user boto3. Si en una máquina Amazon Linux 2023 limpia el sistema responde pip3: command not found, instala pip primero (sudo dnf install -y python3-pip) y repite pip3 install --user boto3. Un aviso PythonDeprecationWarning sobre Python 3.9 es normal y no impide que el script funcione (dynamodb-cli.py ya lo silencia). La presentación solo dicen «sube el fichero, chmod +x y ejecuta»: si falla con Falta la libreria boto3, es esto. En CloudShell no suele hacer falta nada de esto (no se ha podido comprobar en un CloudShell real: si algo falla, avisa).

Opciones de dynamodb-cli.py:

Opción Qué hace Por defecto
--mode get Lee un ítem por UserID (no interactivo) Sin --mode, el script pregunta qué hacer
--mode put Crea o actualiza un ítem. Aun así te pregunta los datos por teclado
--userid U Valor de la clave a consultar en modo get (se llama --userid aunque tu clave tenga otro nombre) u001, que solo vale con clave de texto: con --key-type Number indica siempre el valor
--table T Nombre de la tabla (distingue mayúsculas) Usuarios
--region R Región de la tabla eu-north-1 (no la de CloudShell)
--key-name N Nombre de la clave de partición de la tabla (distingue mayúsculas) UserID
--key-type String|Number Tipo de esa clave String
--quiet Quita los mensajes [INFO] Con mensajes
-h, --help Muestra ayuda y «Uso rápido»

Paso 5. Leer un ítem.

./dynamodb-cli.py --mode get --userid u001

Qué verás (en la salida real, las líneas de resultado llevan un icono delante y el orden de los atributos puede variar):

[INFO] Inicializando recurso DynamoDB en región eu-north-1…
[INFO] Consultando tabla 'Usuarios' con ConsistentRead=True…
[INFO] Key = {'UserID': 'u001'}
Se encontró el usuario con UserID='u001':
{
  "UserID": "u001",
  "Nombre": "Elena",
  ...
}

Si el UserID no existe: Conexión correcta, pero no existe UserID='...'. (código de salida 1). Si hay un error de AWS: Error al conectar o consultar DynamoDB: y el mensaje de AWS (código 2). Si no hay credenciales (por ejemplo, lo ejecutas en tu PC sin aws configure), el script dice No hay credenciales de AWS validas para este script y cómo arreglarlo (código 2). El código de salida se ve con echo $? justo después. Añade --quiet para ocultar las líneas [INFO].

Sin argumentos, ./dynamodb-cli.py pregunta: Seleccione modo: con 1) GET y 2) PUT (Opción [1/2, ENTER=1]); con GET pide UserID a consultar [ENTER = u001]. Con Enter en ambas preguntas lee u001.

Con una tabla de clave numérica (por ejemplo users con id numérica, la de la Práctica 2) hay que decírselo; si no, DynamoDB responde The provided key element does not match the schema:

./dynamodb-cli.py --mode get --userid 1002 --table users --key-name id --key-type Number

Qué verás: igual que arriba, con [INFO] Key = {'id': 1002} y Se encontró el usuario con id='1002': seguido del ítem. Si escribes algo que no es un número en --userid con --key-type Number, el script responde Clave no valida para el tipo Number: No es un número válido. (código de salida 2).

Paso 6. Escribir un ítem.

./dynamodb-cli.py --mode put

El script te guía: primero la clave (UserID por defecto; obligatoria y de tipo String, salvo que uses --key-type Number) y luego atributos, de uno en uno, con su nombre, su tipo (String, Number o Boolean) y su valor. Un Enter en Nombre atributo termina. Ejemplo con un usuario de prueba u900 (no es ninguno de los que te pide la presentación):

UserID (obligatorio, String): u900
Nombre atributo (ENTER para terminar): Nombre
Tipo [String/Number/Boolean]: String
Valor para 'Nombre' (String): Prueba
Nombre atributo (ENTER para terminar): Edad
Tipo [String/Number/Boolean]: Number
Valor para 'Edad' (Number): 30
Nombre atributo (ENTER para terminar):

Qué verás al terminar: Petición que se va a ejecutar (CLI): seguido del comando equivalente de la AWS CLI, por ejemplo:

aws dynamodb put-item --table-name Usuarios --region eu-north-1 --item '{"UserID": {"S": "u900"}, "Nombre": {"S": "Prueba"}, "Edad": {"N": "30"}}'

y después [INFO] con Enviando put_item a 'Usuarios'… y Item creado/actualizado correctamente. Fíjate en cómo viaja cada tipo (S, N, BOOL): es lo que explica la presentación.

Reglas del script:

Paso 7. Comprobar con la AWS CLI y borrar la prueba.

aws dynamodb get-item --table-name Usuarios --key '{"UserID":{"S":"u900"}}' --region eu-north-1
aws dynamodb delete-item --table-name Usuarios --key '{"UserID":{"S":"u900"}}' --region eu-north-1

Qué verás: el primer comando devuelve un JSON con Item y cada valor con su tipo; el segundo no imprime nada. Si solo querías probar el script, borra así tu ítem de prueba. También puedes verlo en la consola de DynamoDB (tabla > Explore table items) o en el visor de 03.08.

Paso 8. Exportar e importar con S3 (ejercicio 3 de DynamoDB). Se hace en la consola (la presentación tiene el paso a paso); aquí tienes lo que no cuentan las diapositivas. En la presentación, el ejercicio 2 (visor web, actividad 03.08) va antes que este: si quieres seguir ese orden exacto, haz 03.08 antes de este paso (si no, el Count será 7 en vez de 8; ver «Comprobar»).

aws dynamodb update-continuous-backups --table-name Usuarios --region eu-north-1   --point-in-time-recovery-specification PointInTimeRecoveryEnabled=true
aws dynamodb export-table-to-point-in-time --table-arn <ARN-de-Usuarios> --s3-bucket <bucket>   --export-format DYNAMODB_JSON --region eu-north-1
aws dynamodb list-exports --region eu-north-1        # ExportStatus COMPLETED al cabo de ~2,5 min
aws s3 ls s3://<bucket>/AWSDynamoDB/ --recursive      # el código de la carpeta
aws dynamodb import-table --region eu-north-1   --s3-bucket-source S3Bucket=<bucket>,S3KeyPrefix=AWSDynamoDB/<código>/data/   --input-format DYNAMODB_JSON --input-compression-type GZIP   --table-creation-parameters '{"TableName":"Usuarios-copia","AttributeDefinitions":[{"AttributeName":"UserID","AttributeType":"S"}],"KeySchema":[{"AttributeName":"UserID","KeyType":"HASH"}],"BillingMode":"PAY_PER_REQUEST"}'
aws dynamodb list-imports --region eu-north-1         # ImportStatus COMPLETED al cabo de ~3 min

Son los mismos pasos que la consola. import-table crea siempre una tabla nueva; si ImportStatus queda en FAILED, mira ItemValidationError y borra la tabla vacía que queda.

Errores frecuentes

Síntoma Causa Solución
Permission denied al lanzar ./dynamodb-cli.py El script no tiene permiso de ejecución chmod +x dynamodb-cli.py (o python3 dynamodb-cli.py ...)
bad interpreter o $'\r': command not found Finales de línea de Windows sed -i 's/\r$//' *.py y repite
ModuleNotFoundError: No module named 'boto3' (o el mensaje Falta la libreria boto3) Falta la librería pip3 install --user boto3
pip3: command not found (Amazon Linux 2023 limpia) AL2023 no trae pip sudo dnf install -y python3-pip y repite pip3 install --user boto3; un PythonDeprecationWarning sobre Python 3.9 es normal
Error al conectar o consultar DynamoDB: con un mensaje de recurso no encontrado La tabla no existe con ese nombre (distingue mayúsculas) o está en otra región. El script usa eu-north-1, no la de CloudShell Revisa aws dynamodb list-tables --region eu-north-1 y usa --table y --region
El mismo error con The provided key element does not match the schema La clave de partición de la tabla no se llama UserID o no es String, y no se lo has dicho al script Añade --key-name <nombre> y --key-type String o Number, por ejemplo --key-name id --key-type Number
No hay credenciales de AWS validas para este script No hay credenciales: no estás en CloudShell y no has hecho aws configure Usa CloudShell, o configura la AWS CLI en tu PC
list-tables sale vacío con los comandos de la presentación Esos comandos no llevan --region y CloudShell está en otra región echo "$AWS_REGION" o añade --region eu-north-1
En la consola, ItemCount de la tabla marca 0 aunque hayas cargado ítems DynamoDB actualiza ese contador cada varias horas Cuenta con aws dynamodb scan --table-name <tabla> --select COUNT --region eu-north-1
scan consume 2.0 y get-item 0.5 con tablas de 3 ítems No es un error: el scan cuesta 0,5 por cada partición de la tabla Nada que arreglar; es el argumento de coste de la presentación
PointInTimeRecoveryUnavailableException al exportar La tabla no tiene PITR activado Actívalo (pestaña Backups o update-continuous-backups) y repite
Table already exists al importar Importaste sobre un nombre de tabla que ya existe Usa un nombre de tabla nuevo
La importación desde S3 queda en FAILED (ItemValidationError) y aparece una tabla nueva vacía El nombre de la partition key de la tabla nueva no es el de los datos exportados (UserID) Borra la tabla vacía y repite con UserID; el detalle está en CloudWatch Logs, grupo /aws-dynamodb/imports

Limpieza

Hazla al terminar el ejercicio (y, en el caso de Usuarios, después de terminar 03.08, que la usa para el visor).

1. Tablas de DynamoDB: Usuarios y la tabla que creaste al importar desde S3 (Usuarios-copia si usaste la CLI).

aws dynamodb list-tables --region eu-north-1
aws dynamodb delete-table --table-name Usuarios --region eu-north-1

Repite delete-table con cada nombre. Si usas la consola y te ofrece crear una copia de seguridad antes de borrar, desmárcala. Si activaste PITR, se desactiva al borrar la tabla; si prefieres conservar la tabla, desactívalo antes: aws dynamodb update-continuous-backups --table-name Usuarios --point-in-time-recovery-specification PointInTimeRecoveryEnabled=false --region eu-north-1 (PITR cuesta 0,21 USD por GB-mes). Una importación fallida deja además una tabla nueva vacía: bórrala también.

2. Logs de la importación (la importación crea un grupo de logs que nadie borra):

aws logs delete-log-group --log-group-name /aws-dynamodb/imports --region eu-north-1

3. S3 de la exportación: en tu bucket, borra la carpeta AWSDynamoDB/ que creó la exportación (consola de S3 > marca la carpeta > Delete, o aws s3 rm s3://<tu-bucket>/AWSDynamoDB/ --recursive). Si creaste el bucket solo para esto, vacíalo y bórralo (aws s3 rb s3://<tu-bucket> --force).

4. Verificación:

aws dynamodb list-tables --region eu-north-1
aws logs describe-log-groups --log-group-name-prefix /aws-dynamodb --region eu-north-1 --query "logGroups[].logGroupName"

Qué debes ver: list-tables sin tus tablas de este tema y ningún grupo de logs /aws-dynamodb/imports.

Cómo sabes que has terminado

Anterior: 03.06 · ACID y rigidez de esquema · Siguiente: 03.08 · Visor web de DynamoDB