Cómo copiar elementos de una tabla de DynamoDB a otra tabla de DynamoDB utilizando Python en AWS
Puedes utilizar Python para copiar elementos de una tabla de DynamoDB a otra. El mismo script puede utilizarse para copiar elementos entre tablas de DynamoDB en diferentes cuentas. Antes de continuar con este artículo, se supone que tienes conocimientos básicos de Python. No es necesario que escribas nada por tu cuenta, basta con que ejecutes el script para realizar la operación de copia. Si necesitas entender el script y el código escrito en él, entonces necesitas tener un conocimiento básico de Python.
Puedes ejecutar este script desde cualquier máquina con acceso a internet y con Python instalado en ella. Necesitas tener Python y Boto3 instalados en tu sistema. Este script está probado con Python 2.7.16, puedes probar con diferentes versiones disponibles de Python 2.7.
También se puede utilizar el servicio AWS Data Pipeline para copiar elementos de una tabla de DynamoDB a otra, pero es un proceso un poco tedioso. Así que escribí este script por mi cuenta para simplificar la tarea.
Ahora, vamos a empezar.
Requisitos previos
- Conocimientos básicos de Python.
- Python 2.7.16 y Boto3 instalados en el servidor Linux.
- Cuenta de AWS(Créala si no tienes una).
- ‘access_key’ & ‘secret_key’ de un Usuario IAM de AWS con permisos suficientes/completos en DynamoDB. (Haz clic aquí para aprender a crear un usuario IAM con ‘access_key’ & ‘secret_key’ en AWS, )
Qué vamos a hacer
- Comprobar los requisitos previos.
- Crear un Script.
- Ejecutar el Script.
Comprobar los prerrequisitos
Comprueba el Python
python –versión
Comprueba Pip
pip –versión
Comprobar Boto3
pip show boto3
Crear un script
Crea un nuevo archivo con el siguiente código en tu sistema local. El código también está disponible en mi Github Repo. El siguiente es el enlace al código en Github.
Enlace Github:https://github.com/shivalkarrahul/DevOps/blob/master/aws/python/aws-copy-dynamo-db-table/copy-dynamodb-table.py
Archivo: copy-dynamodb-table.py
import boto3 import os import sys import argparse import datetime global args parser = argparse.ArgumentParser() parser.add_argument('-sa', '--source_aws_access_key_id', required=True, action="store", dest="source_aws_access_key_id", help="Source AWS Account aws_access_key_id", default=None) parser.add_argument('-ss', '--source_aws_secret_access_key', required=True, action="store", dest="source_aws_secret_access_key", help="Source AWS Account aws_secret_access_key", default=None) parser.add_argument('-da', '--destination_aws_access_key_id', required=True, action="store", dest="destination_aws_access_key_id", help="Destination AWS Account aws_access_key_id", default=None) parser.add_argument('-ds', '--destination_aws_secret_access_key', required=True, action="store", dest="destination_aws_secret_access_key", help="Destination AWS Account aws_secret_access_key", default=None) parser.add_argument('-st', '--sourceTableName', required=True, action="store", dest="sourceTableName", help="Source AWS Account DyanamoDB Table", default=None) parser.add_argument('-dt', '--destinationTableName', required=True, action="store", dest="destinationTableName", help="Destination AWS Account DyanamoDB Table", default=None) args = parser.parse_args() source_aws_access_key_id = args.source_aws_access_key_id source_aws_secret_access_key = args.source_aws_secret_access_key destination_aws_access_key_id = args.destination_aws_access_key_id destination_aws_secret_access_key = args.destination_aws_secret_access_key sourceTableName=args.sourceTableName destinationTableName=args.destinationTableName sourceTableExists = "false" destinationTableExists = "false" print("Printing values") print("source_aws_access_key_id", source_aws_access_key_id) print("source_aws_secret_access_key", source_aws_secret_access_key) print("destination_aws_access_key_id", destination_aws_access_key_id) print("destination_aws_secret_access_key", destination_aws_secret_access_key) print("sourceTableName", sourceTableName) print("destinationTableName", destinationTableName) timeStamp = datetime.datetime.now() backupName = destinationTableName + str(timeStamp.strftime("-%Y_%m_%d_%H_%M_%S")) item_count = 1000 #Specify total number of items to be copied here, this helps when a specified number of items need to be copied counter = 1 # Don't not change this source_session = boto3.Session(region_name='eu-west-3', aws_access_key_id=source_aws_access_key_id, aws_secret_access_key=source_aws_secret_access_key) source_dynamo_client = source_session.client('dynamodb') target_session = boto3.Session(region_name='eu-west-3', aws_access_key_id=destination_aws_access_key_id, aws_secret_access_key=destination_aws_secret_access_key) target_dynamodb = target_session.resource('dynamodb') dynamoclient = boto3.client('dynamodb', region_name='eu-west-3', #Specify the region here aws_access_key_id=source_aws_access_key_id, #Add you source account's access key here aws_secret_access_key=source_aws_secret_access_key) #Add you source account's secret key here dynamotargetclient = boto3.client('dynamodb', region_name='eu-west-3', #Specify the region here aws_access_key_id=destination_aws_access_key_id, #Add you destination account's access key here aws_secret_access_key=destination_aws_secret_access_key) #Add you destination account's secret key here # response = dynamotargetclient.list_tables() # print("List of tables", response) dynamopaginator = dynamoclient.get_paginator('scan') def validateTables(sourceTable, destinationTable): print("Inside validateTables") try: dynamoclient.describe_table(TableName=sourceTable) sourceTableExists = "true" except dynamotargetclient.exceptions.ResourceNotFoundException: sourceTableExists = "false" try: dynamotargetclient.describe_table(TableName=destinationTable) destinationTableExists = "true" except dynamotargetclient.exceptions.ResourceNotFoundException: destinationTableExists = "false" return {'sourceTableExists': sourceTableExists, 'destinationTableExists':destinationTableExists} def copyTable(sourceTable, destinationTable,item_count,counter): print("Inside copyTable") print("Coping", sourceTable, "to", destinationTable) print('Start Reading the Source Table') try: dynamoresponse = dynamopaginator.paginate( TableName=sourceTable, Select='ALL_ATTRIBUTES', ReturnConsumedCapacity='NONE', ConsistentRead=True ) except dynamotargetclient.exceptions.ResourceNotFoundException: print("Table does not exist") print("Exiting") sys.exit() print('Finished Reading the Table') print('Proceed with writing to the Destination Table') print("Writing first", item_count , "items" ) print(dynamoresponse) for page in dynamoresponse: for item in page['Items']: if (counter == item_count): print("exiting") sys.exit() else: print('writing item no', counter) dynamotargetclient.put_item( TableName=destinationTable, Item=item ) counter = counter + 1 def backupTable(destTableName, backupTimeStamp): print("Inside backupTable") print("Taking backup of = ", destTableName) print("Backup Name = ", backupTimeStamp) response = dynamotargetclient.create_backup( TableName=destTableName, BackupName=backupTimeStamp ) print("Backup ARN =", response["BackupDetails"]["BackupArn"]) def deleteDestinationTable(destTableName): print("Inside deleteDestinationTable") try: dynamotargetclient.delete_table(TableName=destTableName) waiter = dynamotargetclient.get_waiter('table_not_exists') waiter.wait(TableName=destTableName) print("Table deleted") except dynamotargetclient.exceptions.ResourceNotFoundException: print("Table does not exist") def doesNotExist(): print("Inside doesNotExist") print("Destination table does not exist ") print("Exiting the execution") # sys.exit() def createDestinationTable(sourceTable): print("Inside createDestinationTable") source_table = source_session.resource('dynamodb').Table(sourceTable) target_table = target_dynamodb.create_table( TableName=destinationTableName, KeySchema=source_table.key_schema, AttributeDefinitions=source_table.attribute_definitions, ProvisionedThroughput={ 'ReadCapacityUnits': 5, 'WriteCapacityUnits': 5 }) target_table.wait_until_exists() target_table.reload() result = validateTables(sourceTableName, destinationTableName) print("value of sourceTableExists = ", result['sourceTableExists']) print("value of destinationTableExists = ", result['destinationTableExists']) if (result['sourceTableExists'] == "false" ) and (result['destinationTableExists'] == "false" ): print("Both the tables do not exist") elif (result['sourceTableExists'] == "false" ) and (result['destinationTableExists'] == "true" ): print("Source Table does not exist") elif (result['sourceTableExists'] == "true" ) and (result['destinationTableExists'] == "false" ): createDestinationTable(sourceTableName) copyTable(sourceTableName, destinationTableName, item_count, counter) elif (result['sourceTableExists'] == "true" ) and (result['destinationTableExists'] == "true" ): backupTable(destinationTableName, backupName) deleteDestinationTable(destinationTableName) createDestinationTable(sourceTableName) copyTable(sourceTableName, destinationTableName, item_count, counter) else: print("Something is wrong")
Sintaxis:
python copy-dynamodb-table.py -sa <cuenta-fuente-acceso-aquí> -ss <cuenta-fuente-secreto-aquí> -da <cuenta-destino-acceso-aquí> -ds <cuenta-destino-secreto-aquí> -st <nombre-de-la-tabla-fuente-aquí> -dt <nombre-de-la-tabla-destino-aquí>
Ejecuta el script.
Puedes consultar la sintaxis anterior y pasar los argumentos al script.
Comando:
python copiar-tabla-dinamodb.py -sa AKI12345IA5XJXFLMTQR -ss ihiHd8+NzLJ567890z4i6EwcN6hbV2A5cMfurscg -daAKI12345IA5XJXFLMTQR -ds ihiHd8+NzLJ567890z4i6EwcN6hbV2A5cMfurscg -st mi-tabla-fuente -dt mi-tabla-destino
Aquí,
- -sa =Clave de acceso de la cuenta AWS de origen = AKIAQ6GAIA5XJXFLMTQR
- -ss = Clave secreta de la cuenta AWS de origen = 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
- -da = Clave de acceso de la cuenta AWS de destino = AKIAQ6GAIA5XJXFLMTQR
- -ds = Clave secreta de la cuenta AWS de destino = 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
- -st = Tabla de origen = mi-tabla-fuente
- -dt = Tabla de destino = mi-tabla-destino
Debes utilizar tus claves, las claves aquí me pertenecen.
El script cubre 4 casos de uso diferentes
- Caso 1: Las dos tablas, origen y destino, no existen.
- Caso 2: La tabla de origen no existe, pero la de destino sí.
- Caso 3: La tabla de origen existe, pero la de destino no.
- Caso práctico 4: Las dos tablas, Origen y Destino, existen.
Veamos estos casos de uso uno por uno.
Caso 1: Las dos tablas, origen y destino, no existen.
Si no tienes tablas de DynamoDB en tu cuenta e intentas ejecutar el script, éste saldrá con el mensaje «Las dos tablas no existen».
Caso 2: La tabla de origen no existe pero la de destino sí.
Si intentas pasar la tabla que no existe como tabla de origen, el script saldrá con el mensaje «La tabla de origen no existe».
Caso 3: La tabla de origen existe pero la de destino no.
En los dos casos de uso anteriores, no se realiza ninguna operación. Ahora bien, si pasas la tabla de origen que existe pero la tabla de destino no existe, el script creará una tabla con el nombre que especifiques como tabla de destino y copiará los elementos de la tabla de origen a la tabla de destino recién creada.
Caso 4: Las dos tablas, origen y destino, existen.
En este caso, se hace una copia de seguridad de la tabla de destino antes de copiar los elementos de la tabla de origen y luego se elimina la tabla de destino. Una vez eliminada la tabla, se crea una nueva tabla con el nombre que especifiques en el parámetro de destino y, a continuación, los elementos de la tabla de origen se copian en la tabla de destino recién creada.
Conclusión
En este artículo, hemos visto el script de Python para copiar elementos de una tabla de DynamoDB a otra tabla de DynamoDB. El script cubre cuatro casos de uso diferentes que pueden surgir al copiar elementos de una tabla a otra. Ahora puedes utilizar este script para copiar elementos de una tabla DynamoDB a otra en la misma cuenta de AWS o en otra diferente.