From 463d01e8786879a4b3617fbdf350673d6290b8c8 Mon Sep 17 00:00:00 2001 From: Mark Woolley Date: Mon, 7 Feb 2022 17:40:48 +0000 Subject: [PATCH] Add dynamodb table class support (#880) Add dynamodb table class support SUMMARY Add support for defining a TableClass on DynamoDB tables. TableClass was introduced as part of botocore version 1.23.18 https://github.com/boto/botocore/blob/develop/CHANGELOG.rst#12318 Fixes: #829 ISSUE TYPE Feature Pull Request COMPONENT NAME dynamodb_table ADDITIONAL INFORMATION https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Client.create_table https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/dynamodb.html#DynamoDB.Client.update_table Reviewed-by: Alina Buzachis Reviewed-by: Mark Woolley Reviewed-by: Jill R (cherry picked from commit 15d69c91b1d40b0dfb1c98f11302f4f960864111) --- .../fragments/880-add-table-class-param.yml | 2 + plugins/modules/dynamodb_table.py | 70 +++++++++++++++++-- .../targets/dynamodb_table/meta/main.yml | 4 +- .../targets/dynamodb_table/tasks/main.yml | 52 +++++++++++++- 4 files changed, 122 insertions(+), 6 deletions(-) create mode 100644 changelogs/fragments/880-add-table-class-param.yml diff --git a/changelogs/fragments/880-add-table-class-param.yml b/changelogs/fragments/880-add-table-class-param.yml new file mode 100644 index 00000000000..21d08216cd6 --- /dev/null +++ b/changelogs/fragments/880-add-table-class-param.yml @@ -0,0 +1,2 @@ +minor_changes: + - dynamodb_table - the ``table_class`` parameter has been added (https://github.com/ansible-collections/community.aws/pull/880). diff --git a/plugins/modules/dynamodb_table.py b/plugins/modules/dynamodb_table.py index 1ea4391223c..839178256aa 100644 --- a/plugins/modules/dynamodb_table.py +++ b/plugins/modules/dynamodb_table.py @@ -121,6 +121,13 @@ default: [] type: list elements: dict + table_class: + description: + - The class of the table. + - Requires at least botocore version 1.23.18. + choices: ['STANDARD', 'STANDARD_INFREQUENT_ACCESS'] + type: str + version_added: 3.1.0 tags: description: - A hash/dictionary of tags to add to the new instance or for starting/stopping instance by tag. @@ -201,11 +208,49 @@ ''' RETURN = r''' +table: + description: The returned table params from the describe API call. + returned: success + type: complex + contains: {} + sample: { + "arn": "arn:aws:dynamodb:us-east-1:721066863947:table/ansible-test-table", + "attribute_definitions": [ + { + "attribute_name": "id", + "attribute_type": "N" + } + ], + "billing_mode": "PROVISIONED", + "creation_date_time": "2022-02-04T13:36:01.578000+00:00", + "id": "533b45fe-0870-4b66-9b00-d2afcfe96f19", + "item_count": 0, + "key_schema": [ + { + "attribute_name": "id", + "key_type": "HASH" + } + ], + "name": "ansible-test-14482047-alinas-mbp", + "provisioned_throughput": { + "number_of_decreases_today": 0, + "read_capacity_units": 1, + "write_capacity_units": 1 + }, + "size": 0, + "status": "ACTIVE", + "table_arn": "arn:aws:dynamodb:us-east-1:721066863947:table/ansible-test-table", + "table_id": "533b45fe-0870-4b66-9b00-d2afcfe96f19", + "table_name": "ansible-test-table", + "table_size_bytes": 0, + "table_status": "ACTIVE", + "tags": {} + } table_status: - description: The current status of the table. - returned: success - type: str - sample: ACTIVE + description: The current status of the table. + returned: success + type: str + sample: ACTIVE ''' try: @@ -410,6 +455,7 @@ def compatability_results(current_table): billing_mode=billing_mode, region=module.region, table_name=current_table.get('table_name', None), + table_class=current_table.get('table_class_summary', {}).get('table_class', None), table_status=current_table.get('table_status', None), tags=current_table.get('tags', {}), ) @@ -452,6 +498,9 @@ def get_dynamodb_table(): table['size'] = table['table_size_bytes'] table['tags'] = tags + if 'table_class_summary' in table: + table['table_class'] = table['table_class_summary']['table_class'] + # billing_mode_summary doesn't always seem to be set but is always set for PAY_PER_REQUEST # and when updating the billing_mode if 'billing_mode_summary' in table: @@ -753,6 +802,7 @@ def _update_table(current_table): changes = dict() additional_global_index_changes = list() + # Get throughput / billing_mode changes throughput_changes = _throughput_changes(current_table) if throughput_changes: changes['ProvisionedThroughput'] = throughput_changes @@ -766,6 +816,11 @@ def _update_table(current_table): if current_billing_mode != new_billing_mode: changes['BillingMode'] = new_billing_mode + # Update table_class use exisiting if none is defined + if module.params.get('table_class'): + if module.params.get('table_class') != current_table.get('table_class'): + changes['TableClass'] = module.params.get('table_class') + global_index_changes = _global_index_changes(current_table) if global_index_changes: changes['GlobalSecondaryIndexUpdates'] = global_index_changes @@ -868,6 +923,7 @@ def update_table(current_table): def create_table(): table_name = module.params.get('name') + table_class = module.params.get('table_class') hash_key_name = module.params.get('hash_key_name') billing_mode = module.params.get('billing_mode') @@ -901,6 +957,8 @@ def create_table(): # SSESpecification, ) + if table_class: + params['TableClass'] = table_class if billing_mode == "PROVISIONED": params['ProvisionedThroughput'] = throughput if local_indexes: @@ -982,6 +1040,7 @@ def main(): read_capacity=dict(type='int'), write_capacity=dict(type='int'), indexes=dict(default=[], type='list', elements='dict', options=index_options), + table_class=dict(type='str', choices=['STANDARD', 'STANDARD_INFREQUENT_ACCESS']), tags=dict(type='dict'), purge_tags=dict(type='bool', default=True), wait=dict(type='bool', default=True), @@ -999,6 +1058,9 @@ def main(): ) client = module.client('dynamodb', retry_decorator=retry_decorator) + if module.params.get('table_class'): + module.require_botocore_at_least('1.23.18', reason='to set table_class') + current_table = get_dynamodb_table() changed = False table = None diff --git a/tests/integration/targets/dynamodb_table/meta/main.yml b/tests/integration/targets/dynamodb_table/meta/main.yml index 07faa217762..504e72117b6 100644 --- a/tests/integration/targets/dynamodb_table/meta/main.yml +++ b/tests/integration/targets/dynamodb_table/meta/main.yml @@ -1,2 +1,4 @@ dependencies: - - prepare_tests + - role: setup_botocore_pip + vars: + botocore_version: "1.23.18" diff --git a/tests/integration/targets/dynamodb_table/tasks/main.yml b/tests/integration/targets/dynamodb_table/tasks/main.yml index cd41e031d64..21c7f465b20 100644 --- a/tests/integration/targets/dynamodb_table/tasks/main.yml +++ b/tests/integration/targets/dynamodb_table/tasks/main.yml @@ -574,7 +574,6 @@ - delete_table is not changed # ============================================== - - name: Create complex table - check_mode dynamodb_table: state: present @@ -585,9 +584,12 @@ range_key_type: "{{ range_index_type }}" read_capacity: 3 write_capacity: 3 + table_class: "STANDARD_INFREQUENT_ACCESS" tags: "{{ tags_default }}" indexes: "{{ indexes }}" register: create_complex_table + vars: + ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}" check_mode: True - name: Check results - Create complex table - check_mode @@ -606,9 +608,12 @@ range_key_type: "{{ range_index_type }}" read_capacity: 3 write_capacity: 3 + table_class: "STANDARD_INFREQUENT_ACCESS" tags: "{{ tags_default }}" indexes: "{{ indexes }}" register: create_complex_table + vars: + ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}" - name: Check results - Create complex table assert: @@ -633,6 +638,7 @@ - create_complex_table.range_key_type == range_index_type - create_complex_table.read_capacity == 3 - create_complex_table.table_name == table_name + - create_complex_table.table_class == "STANDARD_INFREQUENT_ACCESS" - create_complex_table.write_capacity == 3 - create_complex_table.tags == tags_default @@ -646,9 +652,12 @@ range_key_type: "{{ range_index_type }}" read_capacity: 3 write_capacity: 3 + table_class: "STANDARD_INFREQUENT_ACCESS" tags: "{{ tags_default }}" indexes: "{{ indexes }}" register: create_complex_table + vars: + ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}" check_mode: True - name: Check results - Create complex table - idempotent - check_mode @@ -667,9 +676,12 @@ range_key_type: "{{ range_index_type }}" read_capacity: 3 write_capacity: 3 + table_class: "STANDARD_INFREQUENT_ACCESS" tags: "{{ tags_default }}" indexes: "{{ indexes }}" register: create_complex_table + vars: + ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}" - name: Check results - Create complex table - idempotent assert: @@ -694,10 +706,48 @@ - create_complex_table.range_key_type == range_index_type - create_complex_table.read_capacity == 3 - create_complex_table.table_name == table_name + - create_complex_table.table_class == "STANDARD_INFREQUENT_ACCESS" - create_complex_table.write_capacity == 3 - create_complex_table.tags == tags_default # ============================================== + # Update table class on exisiting table + + - name: Update table class - check_mode + dynamodb_table: + state: present + name: "{{ table_name }}" + table_class: "STANDARD" + register: update_class + vars: + ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}" + check_mode: True + + - name: Check results - Update table class - check_mode + assert: + that: + - update_class is successful + - update_class is changed + + - name: Update table class + dynamodb_table: + state: present + name: "{{ table_name }}" + table_class: "STANDARD" + vars: + ansible_python_interpreter: "{{ botocore_virtualenv_interpreter }}" + register: update_class + + - name: Check results - Update table class + assert: + that: + - update_class is successful + - update_class is changed + - update_class.table_name == table_name + - update_class.table_class == "STANDARD" + + # ============================================== + # Update table index on exisiting table - name: Update table update index - check_mode dynamodb_table: