add tagging to dynamodb_table.py (#20946)

* add tagging to dynamodb_table.py

* fix doc syntax

* address PR comments

* add boto3 has tagging check
This commit is contained in:
Corey Christous 2017-03-28 07:18:20 -04:00 committed by ansibot
parent a5b12ff269
commit 34a3ab94d8

View file

@ -31,6 +31,7 @@ description:
author: Alan Loi (@loia)
requirements:
- "boto >= 2.37.0"
- "boto3 >= 1.4.4 (for tagging)"
options:
state:
description:
@ -84,6 +85,18 @@ options:
required: false
default: []
version_added: "2.1"
tags:
version_added: "2.3"
description:
- a hash/dictionary of tags to add to the new instance or for starting/stopping instance by tag; '{"key":"value"}' and '{"key":"value","key":"value"}'
required: false
default: null
wait_for_active_timeout:
version_added: "2.3"
description:
- how long before wait gives up, in seconds. only used when tags is set
required: false
default: 60
extends_documentation_fragment:
- aws
- ec2
@ -100,6 +113,8 @@ EXAMPLES = '''
range_key_type: NUMBER
read_capacity: 2
write_capacity: 2
tags:
tag_name: tag_value
# Update capacity on existing dynamo table
- dynamodb_table:
@ -138,6 +153,7 @@ table_status:
sample: ACTIVE
'''
import time
import traceback
try:
@ -159,6 +175,13 @@ try:
except ImportError:
HAS_BOTO = False
try:
import botocore
from ansible.module_utils.ec2 import ansible_dict_to_boto3_tag_list, boto3_conn
HAS_BOTO3 = True
except ImportError:
HAS_BOTO3 = False
from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.ec2 import AnsibleAWSError, connect_to_aws, ec2_argument_spec, get_aws_connection_info
@ -169,7 +192,7 @@ INDEX_OPTIONS = INDEX_REQUIRED_OPTIONS + ['hash_key_type', 'range_key_name', 'ra
INDEX_TYPE_OPTIONS = ['all', 'global_all', 'global_include', 'global_keys_only', 'include', 'keys_only']
def create_or_update_dynamo_table(connection, module):
def create_or_update_dynamo_table(connection, module, boto3_dynamodb=None, boto3_sts=None):
table_name = module.params.get('name')
hash_key_name = module.params.get('hash_key_name')
hash_key_type = module.params.get('hash_key_type')
@ -178,6 +201,9 @@ def create_or_update_dynamo_table(connection, module):
read_capacity = module.params.get('read_capacity')
write_capacity = module.params.get('write_capacity')
all_indexes = module.params.get('indexes')
region = module.params.get('region')
tags = module.params.get('tags')
wait_for_active_timeout = module.params.get('wait_for_active_timeout')
for index in all_indexes:
validate_index(index, module)
@ -192,7 +218,7 @@ def create_or_update_dynamo_table(connection, module):
indexes, global_indexes = get_indexes(all_indexes)
result = dict(
region=module.params.get('region'),
region=region,
table_name=table_name,
hash_key_name=hash_key_name,
hash_key_type=hash_key_type,
@ -217,6 +243,13 @@ def create_or_update_dynamo_table(connection, module):
if not module.check_mode:
result['table_status'] = table.describe()['Table']['TableStatus']
if tags:
# only tables which are active can be tagged
wait_until_table_active(module, table, wait_for_active_timeout)
account_id = get_account_id(boto3_sts)
boto3_dynamodb.tag_resource(ResourceArn='arn:aws:dynamodb:' + region + ':' + account_id + ':table/' + table_name, Tags=ansible_dict_to_boto3_tag_list(tags))
result['tags'] = tags
except BotoServerError:
result['msg'] = 'Failed to create/update dynamo table due to error: ' + traceback.format_exc()
module.fail_json(**result)
@ -224,6 +257,19 @@ def create_or_update_dynamo_table(connection, module):
module.exit_json(**result)
def get_account_id(boto3_sts):
return boto3_sts.get_caller_identity()["Account"]
def wait_until_table_active(module, table, wait_timeout):
max_wait_time = time.time() + wait_timeout
while (max_wait_time > time.time()) and (table.describe()['Table']['TableStatus'] != 'ACTIVE'):
time.sleep(5)
if max_wait_time <= time.time():
# waiting took too long
module.fail_json(msg="timed out waiting for table to exist")
def delete_dynamo_table(connection, module):
table_name = module.params.get('name')
@ -398,6 +444,8 @@ def main():
read_capacity=dict(default=1, type='int'),
write_capacity=dict(default=1, type='int'),
indexes=dict(default=[], type='list'),
tags = dict(type='dict'),
wait_for_active_timeout = dict(default=60, type='int'),
))
module = AnsibleModule(
@ -407,6 +455,9 @@ def main():
if not HAS_BOTO:
module.fail_json(msg='boto required for this module')
if not HAS_BOTO3 and module.params.get('tags'):
module.fail_json(msg='boto3 required when using tags for this module')
region, ec2_url, aws_connect_params = get_aws_connection_info(module)
if not region:
module.fail_json(msg='region must be specified')
@ -416,9 +467,22 @@ def main():
except (NoAuthHandlerFound, AnsibleAWSError) as e:
module.fail_json(msg=str(e))
if module.params.get('tags'):
try:
region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True)
boto3_dynamodb = boto3_conn(module, conn_type='client', resource='dynamodb', region=region, endpoint=ec2_url, **aws_connect_kwargs)
if not hasattr(boto3_dynamodb, 'tag_resource'):
module.fail_json(msg='boto3 connection does not have tag_resource(), likely due to using an old version')
boto3_sts = boto3_conn(module, conn_type='client', resource='sts', region=region, endpoint=ec2_url, **aws_connect_kwargs)
except botocore.exceptions.NoCredentialsError as e:
module.fail_json(msg='cannot connect to AWS', exception=traceback.format_exc(e))
else:
boto3_dynamodb = None
boto3_sts = None
state = module.params.get('state')
if state == 'present':
create_or_update_dynamo_table(connection, module)
create_or_update_dynamo_table(connection, module, boto3_dynamodb, boto3_sts)
elif state == 'absent':
delete_dynamo_table(connection, module)