Skip to content

Commit

Permalink
new module dynamodb_table_info to retrieve dynamodb table info
Browse files Browse the repository at this point in the history
  • Loading branch information
abikouo committed Dec 18, 2023
1 parent f4b0ba5 commit 4895327
Show file tree
Hide file tree
Showing 4 changed files with 343 additions and 0 deletions.
1 change: 1 addition & 0 deletions meta/runtime.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ action_groups:
- dms_endpoint
- dms_replication_subnet_group
- dynamodb_table
- dynamodb_table_info
- dynamodb_ttl
- ec2_ami_copy
- ec2_asg
Expand Down
269 changes: 269 additions & 0 deletions plugins/modules/dynamodb_table_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

# Copyright: Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

DOCUMENTATION = r"""
---
module: dynamodb_table_info
version_added: 7.1.0
short_description: Returns information about a Dynamo DB table
description:
- Returns information about the Dynamo DB table, including the current status of the table
when it was created, the primary key schema, and any indexes on the table.
author:
- Aubin Bikouo (@abikouo)
options:
name:
description:
- The name of the table to describe.
required: true
type: str
extends_documentation_fragment:
- amazon.aws.common.modules
- amazon.aws.region.modules
- amazon.aws.boto3
"""

EXAMPLES = r"""
- name: Return information about the DynamoDB table named 'my-table'
community.aws.dynamodb_table_info:
name: my-table
"""

RETURN = r"""
table:
description: The returned table params from the describe API call.
returned: success
type: complex
contains:
table_name:
description: The name of the table.
returned: always
type: str
table_status:
description: The current state of the table.
returned: always
type: str
sample: 'ACTIVE'
creation_date_time:
description: The date and time when the table was created, in UNIX epoch time format.
returned: always
type: str
table_size_bytes:
description: The total size of the specified table, in bytes.
returned: always
type: int
item_count:
description: The number of items in the specified table.
returned: always
type: int
table_arn:
description: The Amazon Resource Name (ARN) that uniquely identifies the table.
returned: always
type: str
table_id:
description: Unique identifier for the table for which the backup was created.
returned: always
type: str
attribute_definitions:
description: A list of attributes for describing the key schema for the table and indexes.
returned: always
type: complex
contains:
attribute_name:
description: A name for the attribute.
type: str
returned: always
attribute_type:
description: The data type for the attribute, S (String), N (Number) and B (Binary).
type: str
returned: always
key_schema:
description: A list of key schemas that specify the attributes that make up the primary key of a table, or the key attributes of an index.
returned: always
type: complex
contains:
attribute_name:
description: The name of a key attribute.
type: str
returned: always
key_type:
description: The role that this key attribute will assume, 'HASH' for partition key, 'RANGE' for sort key
type: str
returned: always
billing_mode:
description: Controls how you are charged for read and write throughput and how you manage capacity.
returned: always
type: str
local_secondary_indexes:
description: Represents one or more local secondary indexes on the table.
returned: if any, on the table
type: list
elements: dict
global_secondary_indexes:
description: The global secondary indexes of table.
returned: if any, on the table
type: list
elements: dict
stream_specification:
description: The current DynamoDB Streams configuration for the table.
returned: if any, on the table
type: complex
contains:
stream_enabled:
description: Indicates whether DynamoDB Streams is enabled (true) or disabled (false) on the table.
type: bool
returned: always
sample: true
stream_view_type:
description: When an item in the table is modified, stream_view_type determines what information is written to the stream for this table.
type: str
returned: always
sample: KEYS_ONLY
latest_stream_label:
description: A timestamp, in ISO 8601 format, for this stream.
type: str
returned: if any on the table
latest_stream_arn:
description: The Amazon Resource Name (ARN) that uniquely identifies the latest stream for this table.
returned: if any on the table
type: str
global_table_version:
description: Represents the version of global tables in use, if the table is replicated across AWS Regions.
type: str
returned: if the table is replicated
replicas:
description: Represents replicas of the table.
type: list
elements: dict
returned: if any on the table
source_backup_arn:
description: The Amazon Resource Name (ARN) of the backup from which the table was restored.
type: str
returned: if any, on the table
source_table_arn:
description: The ARN of the source table of the backup that is being restored.
type: str
returned: if any, on the table
restore_date_time:
description: Point in time or source backup time.
type: str
returned: if any, on table
restore_in_progress:
description: Indicates if a restore is in progress or not.
type: bool
returned: if any, on table
table_class:
description: The table class of the specified table.
type: str
returned: if any on the table
sample: STANDARD_INFREQUENT_ACCESS
deletion_protection_enabled:
description: Indicates whether deletion protection is enabled (true) or disabled (false) on the table.
type: bool
returned: always
sample: true
provisioned_throughput:
description: The provisioned throughput settings for the table.
type: dict
returned: always
sample: '{"number_of_decreases_today": 0, "read_capacity_units": 1, "write_capacity_units": 1}'
tags:
description: A dict of tags associated with the DynamoDB table.
returned: always
type: dict
"""

try:
import botocore
except ImportError:
pass # Handled by AnsibleAWSModule

from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict

from ansible_collections.amazon.aws.plugins.module_utils.botocore import is_boto3_error_code
from ansible_collections.amazon.aws.plugins.module_utils.retries import AWSRetry
from ansible_collections.amazon.aws.plugins.module_utils.tagging import boto3_tag_list_to_ansible_dict

from ansible_collections.community.aws.plugins.module_utils.modules import AnsibleCommunityAWSModule as AnsibleAWSModule


# ResourceNotFoundException is expected here if the table doesn't exist
@AWSRetry.jittered_backoff(catch_extra_error_codes=["LimitExceededException", "ResourceInUseException"])
def _describe_table(client, **params):
return client.describe_table(**params)


def describe_dynamodb_table(module):
table_name = module.params.get("name")
retry_decorator = AWSRetry.jittered_backoff(
catch_extra_error_codes=["LimitExceededException", "ResourceInUseException", "ResourceNotFoundException"],
)
client = module.client("dynamodb", retry_decorator=retry_decorator)
try:
table = _describe_table(client, TableName=table_name)
except is_boto3_error_code("ResourceNotFoundException"):
module.exit_json(table={})
except (
botocore.exceptions.ClientError,
botocore.exceptions.BotoCoreError,
) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Failed to describe table")

table = table["Table"]
try:
tags = client.list_tags_of_resource(aws_retry=True, ResourceArn=table["TableArn"])["Tags"]
except is_boto3_error_code("AccessDeniedException"):
module.warn("Permission denied when listing tags")
tags = []
except (
botocore.exceptions.ClientError,
botocore.exceptions.BotoCoreError,
) as e: # pylint: disable=duplicate-except
module.fail_json_aws(e, msg="Failed to list table tags")

table = camel_dict_to_snake_dict(table)
table["tags"] = boto3_tag_list_to_ansible_dict(tags)

if "table_class_summary" in table:
table["table_class"] = table["table_class_summary"]["table_class"]
del table["table_class_summary"]

# 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:
table["billing_mode"] = table["billing_mode_summary"]["billing_mode"]
del table["billing_mode_summary"]
else:
table["billing_mode"] = "PROVISIONED"

# Restore summary
if "restore_summary" in table:
table["source_backup_arn"] = table["restore_summary"].get("source_backup_arn", "")
table["source_table_arn"] = table["restore_summary"].get("source_table_arn", "")
table["restore_date_time"] = table["restore_summary"].get("restore_date_time", "")
table["restore_in_progress"] = table["restore_summary"].get("restore_in_progress")
del table["restore_summary"]

module.exit_json(table=table)


def main():
argument_spec = dict(
name=dict(
required=True,
),
)

module = AnsibleAWSModule(
argument_spec=argument_spec,
supports_check_mode=True,
)

describe_dynamodb_table(module)


if __name__ == "__main__":
main()
21 changes: 21 additions & 0 deletions tests/integration/targets/dynamodb_table/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@
that:
- create_table is successful
- create_table is changed

- name: Ensure the table was not created
dynamodb_table_info:
name: "{{ table_name }}"
register: table_info

- name: Assert the table was not created
assert:
that:
- not table_info.table

- name: Create table
dynamodb_table:
Expand Down Expand Up @@ -65,6 +75,17 @@
- create_table.table_name == table_name
- create_table.write_capacity == 1

- name: Ensure the table was not created
dynamodb_table_info:
name: "{{ table_name }}"
register: table_info

- name: Assert the table was created
assert:
that:
- table_info.table
- 'table_info.table.attribute_definitions == [{"attribute_name": table_index, "attribute_type": table_index_type[0]}]'

- name: Create table - idempotent - check_mode
dynamodb_table:
state: present
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@
- create_table is successful
- create_table is changed

- name: Ensure the table was not created
dynamodb_table_info:
name: "{{ table_name_on_demand }}"
register: _table

- name: Assert the table does not exist
assert:
that:
- not _table.table

- name: Create table - pay-per-request
dynamodb_table:
state: present
Expand All @@ -32,6 +42,17 @@
- create_table is changed
- create_table.billing_mode == "PAY_PER_REQUEST"

- name: Ensure the table was created
dynamodb_table_info:
name: "{{ table_name_on_demand }}"
register: _table

- name: Assert the table has been created with the expected billing modw
assert:
that:
- _table.table
- _table.table.billing_mode == 'PAY_PER_REQUEST'

- name: Create table - pay-per-request - check failure
dynamodb_table:
state: present
Expand Down Expand Up @@ -71,6 +92,16 @@
- create_complex_table is successful
- create_complex_table is changed

- name: Ensure the table was not created
dynamodb_table_info:
name: "{{ table_name_on_demand_complex }}"
register: _complex_table

- name: Assert the table does not exist
assert:
that:
- not _complex_table.table

- name: Create complex table - check failure on index
dynamodb_table:
state: present
Expand Down Expand Up @@ -120,6 +151,17 @@
- create_complex_table.table_name == table_name_on_demand_complex
- create_complex_table.tags == tags_default

- name: Ensure the table was not created
dynamodb_table_info:
name: "{{ table_name_on_demand_complex }}"
register: _complex_table

- name: Assert the table has been created
assert:
that:
- _complex_table.table
- _complex_table.table.billing_mode == 'PAY_PER_REQUEST'

- name: Update complex table billing_mode
dynamodb_table:
state: present
Expand All @@ -140,3 +182,13 @@
- convert_complex_table is changed
- '"billing_mode" in convert_complex_table'
- convert_complex_table.billing_mode == "PROVISIONED"

- name: Read table info
dynamodb_table_info:
name: "{{ table_name_on_demand_complex }}"
register: _complex_table

- name: Assert the table has been updated
assert:
that:
- _complex_table.table.billing_mode == 'PROVISIONED'

0 comments on commit 4895327

Please sign in to comment.