From ecac835c8d0d37ed8532d1611e4afb215281d662 Mon Sep 17 00:00:00 2001 From: Mohit Alonja Date: Sat, 15 Aug 2020 04:47:25 -0400 Subject: [PATCH] support int/str types for DynamoDB GlobalSecondaryIndex in CF templates (#2828) --- .../utils/cloudformation/template_deployer.py | 26 ++++++++++- tests/integration/test_cloudformation.py | 46 +++++++++++++++++-- 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/localstack/utils/cloudformation/template_deployer.py b/localstack/utils/cloudformation/template_deployer.py index 41de2ede34cbc..b1491700ce407 100644 --- a/localstack/utils/cloudformation/template_deployer.py +++ b/localstack/utils/cloudformation/template_deployer.py @@ -220,6 +220,28 @@ def replace(params, **kwargs): return replace +def get_ddb_provisioned_throughput(params, **kwargs): + args = params.get('ProvisionedThroughput') + if args: + if isinstance(args['ReadCapacityUnits'], str): + args['ReadCapacityUnits'] = int(args['ReadCapacityUnits']) + if isinstance(args['WriteCapacityUnits'], str): + args['WriteCapacityUnits'] = int(args['WriteCapacityUnits']) + return args + + +def get_ddb_global_sec_indexes(params, **kwargs): + args = params.get('GlobalSecondaryIndexes') + if args: + for index in args: + provisoned_throughput = index['ProvisionedThroughput'] + if isinstance(provisoned_throughput['ReadCapacityUnits'], str): + provisoned_throughput['ReadCapacityUnits'] = int(provisoned_throughput['ReadCapacityUnits']) + if isinstance(provisoned_throughput['WriteCapacityUnits'], str): + provisoned_throughput['WriteCapacityUnits'] = int(provisoned_throughput['WriteCapacityUnits']) + return args + + # maps resource types to functions and parameters for creation RESOURCE_TO_FUNCTION = { 'S3::Bucket': { @@ -406,9 +428,9 @@ def replace(params, **kwargs): 'TableName': 'TableName', 'AttributeDefinitions': 'AttributeDefinitions', 'KeySchema': 'KeySchema', - 'ProvisionedThroughput': 'ProvisionedThroughput', + 'ProvisionedThroughput': get_ddb_provisioned_throughput, 'LocalSecondaryIndexes': 'LocalSecondaryIndexes', - 'GlobalSecondaryIndexes': 'GlobalSecondaryIndexes', + 'GlobalSecondaryIndexes': get_ddb_global_sec_indexes, 'StreamSpecification': lambda params, **kwargs: ( common.merge_dicts(params.get('StreamSpecification'), {'StreamEnabled': True}, default=None)) }, diff --git a/tests/integration/test_cloudformation.py b/tests/integration/test_cloudformation.py index 0f9cdeafe0fa9..5a6944e1ed09b 100644 --- a/tests/integration/test_cloudformation.py +++ b/tests/integration/test_cloudformation.py @@ -557,8 +557,8 @@ def handler(event, context): - AttributeName: startTime KeyType: RANGE ProvisionedThroughput: - ReadCapacityUnits: 5 - WriteCapacityUnits: 5 + ReadCapacityUnits: '5' + WriteCapacityUnits: '5' StreamSpecification: StreamViewType: NEW_IMAGE GlobalSecondaryIndexes: @@ -571,8 +571,8 @@ def handler(event, context): Projection: ProjectionType: ALL ProvisionedThroughput: - ReadCapacityUnits: 5 - WriteCapacityUnits: 5 + ReadCapacityUnits: '5' + WriteCapacityUnits: '5' Outputs: Name: Value: @@ -1736,3 +1736,41 @@ def test_delete_stack_across_regions(self): ) cloudformation.delete_stack(StackName='myteststack') + + def test_globalindex_read_write_provisioned_throughput_dynamodb_table(self): + cf_client = aws_stack.connect_to_service('cloudformation') + ddb_client = aws_stack.connect_to_service('dynamodb') + stack_name = 'test_dynamodb' + + response = cf_client.create_stack( + StackName=stack_name, + TemplateBody=TEST_DEPLOY_BODY_3, + Parameters=[ + { + 'ParameterKey': 'tableName', + 'ParameterValue': 'dynamodb' + }, + { + 'ParameterKey': 'env', + 'ParameterValue': 'test' + } + ] + ) + self.assertEqual(response['ResponseMetadata']['HTTPStatusCode'], 200) + response = ddb_client.describe_table( + TableName='dynamodb-test' + ) + + if response['Table']['ProvisionedThroughput']: + throughput = response['Table']['ProvisionedThroughput'] + self.assertTrue(isinstance(throughput['ReadCapacityUnits'], int)) + self.assertTrue(isinstance(throughput['WriteCapacityUnits'], int)) + + for global_index in response['Table']['GlobalSecondaryIndexes']: + index_provisioned = global_index['ProvisionedThroughput'] + test_read_capacity = index_provisioned['ReadCapacityUnits'] + test_write_capacity = index_provisioned['WriteCapacityUnits'] + + self.assertTrue(isinstance(test_read_capacity, int)) + self.assertTrue(isinstance(test_write_capacity, int)) + cf_client.delete_stack(StackName=stack_name)