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

  1. Conocimientos básicos de Python.
  2. Python 2.7.16 y Boto3 instalados en el servidor Linux.
  3. Cuenta de AWS(Créala si no tienes una).
  4. ‘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

  1. Comprobar los requisitos previos.
  2. Crear un Script.
  3. Ejecutar el Script.

Comprobar los prerrequisitos

Comprueba el Python

python –versión

Versión Python

Comprueba Pip

pip –versión

Versión de la pipa

Comprobar Boto3

pip show boto3

Versión 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 = ihiHd8+NzLJK5DFfTz4i6EwcN6hbV2A5cMfurscg
  • -da = Clave de acceso de la cuenta AWS de destino = AKIAQ6GAIA5XJXFLMTQR
  • -ds = Clave secreta de la cuenta AWS de destino = ihiHd8+NzLJK5DFfTz4i6EwcN6hbV2A5cMfurscg
  • -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

  1. Caso 1: Las dos tablas, origen y destino, no existen.
  2. Caso 2: La tabla de origen no existe, pero la de destino sí.
  3. Caso 3: La tabla de origen existe, pero la de destino no.
  4. 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».

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

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.

La tabla de destino no existe

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.

Las dos mesas

Las dos tablas existen

Copia de seguridad de la tabla de destino antes de copiar nuevos elementos

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.

También te podría gustar...