diff --git a/plugins/modules/ec2_vpc_route_table_info.py b/plugins/modules/ec2_vpc_route_table_info.py index 9ff9959c271..413ef95f560 100644 --- a/plugins/modules/ec2_vpc_route_table_info.py +++ b/plugins/modules/ec2_vpc_route_table_info.py @@ -14,7 +14,9 @@ description: - Gather information about ec2 VPC route tables in AWS - This module was called C(ec2_vpc_route_table_facts) before Ansible 2.9. The usage did not change. -author: "Rob White (@wimnat)" +author: +- "Rob White (@wimnat)" +- "Mark Chappell (@tremble)" options: filters: description: @@ -51,52 +53,77 @@ ''' try: - import boto.vpc - from boto.exception import BotoServerError + import botocore except ImportError: - pass # Handled by HAS_BOTO + 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.core import AnsibleAWSModule -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AnsibleAWSError -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import connect_to_aws -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import get_aws_connection_info -from ansible_collections.amazon.aws.plugins.module_utils.ec2 import HAS_BOTO +from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import AWSRetry +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import ansible_dict_to_boto3_filter_list +from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict + + +@AWSRetry.jittered_backoff() +def describe_route_tables_with_backoff(connection, **params): + try: + paginator = connection.get_paginator('describe_route_tables') + return paginator.paginate(**params).build_full_result() + except is_boto3_error_code('InvalidRouteTableID.NotFound'): + return None + + +def normalize_route(route): + # Historically these were all there, but set to null when empty' + for legacy_key in ['DestinationCidrBlock', 'GatewayId', 'InstanceId', + 'Origin', 'State', 'NetworkInterfaceId']: + if legacy_key not in route: + route[legacy_key] = None + route['InterfaceId'] = route['NetworkInterfaceId'] + return route -def get_route_table_info(route_table): +def normalize_association(assoc): + # Name change between boto v2 and boto v3, return both + assoc['Id'] = assoc['RouteTableAssociationId'] + return assoc - # Add any routes to array - routes = [] - associations = [] - for route in route_table.routes: - routes.append(route.__dict__) - for association in route_table.associations: - associations.append(association.__dict__) - route_table_info = {'id': route_table.id, - 'routes': routes, - 'associations': associations, - 'tags': route_table.tags, - 'vpc_id': route_table.vpc_id - } +def normalize_route_table(table): + table['tags'] = boto3_tag_list_to_ansible_dict(table['Tags']) + table['Associations'] = [normalize_association(assoc) for assoc in table['Associations']] + table['Routes'] = [normalize_route(route) for route in table['Routes']] + table['Id'] = table['RouteTableId'] + del table['Tags'] + return camel_dict_to_snake_dict(table, ignore_list=['tags']) - return route_table_info + +def normalize_results(results): + """ + We used to be a boto v2 module, make sure that the old return values are + maintained and the shape of the return values are what people expect + """ + + routes = [normalize_route_table(route) for route in results['RouteTables']] + del results['RouteTables'] + results = camel_dict_to_snake_dict(results) + results['route_tables'] = routes + return results def list_ec2_vpc_route_tables(connection, module): - filters = module.params.get("filters") - route_table_dict_array = [] + filters = ansible_dict_to_boto3_filter_list(module.params.get("filters")) try: - all_route_tables = connection.get_all_route_tables(filters=filters) - except BotoServerError as e: + results = describe_route_tables_with_backoff(connection, Filters=filters) + except (botocore.exceptions.BotoCoreError, botocore.exceptions.ClientError) as e: module.fail_json_aws(e, msg="Failed to get route tables") - for route_table in all_route_tables: - route_table_dict_array.append(get_route_table_info(route_table)) - - module.exit_json(route_tables=route_table_dict_array) + results = normalize_results(results) + module.exit_json(changed=False, **results) def main(): @@ -110,18 +137,7 @@ def main(): module.deprecate("The 'ec2_vpc_route_table_facts' module has been renamed to 'ec2_vpc_route_table_info'", date='2021-12-01', collection_name='community.aws') - if not HAS_BOTO: - module.fail_json(msg='boto required for this module') - - region, ec2_url, aws_connect_params = get_aws_connection_info(module) - - if region: - try: - connection = connect_to_aws(boto.vpc, region, **aws_connect_params) - except (boto.exception.NoAuthHandlerFound, AnsibleAWSError) as e: - module.fail_json(msg=str(e)) - else: - module.fail_json(msg="region must be specified") + connection = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff(retries=10)) list_ec2_vpc_route_tables(connection, module)