diff --git a/changelogs/fragments/unit-tests_test_ec2_eni_info_only.yaml b/changelogs/fragments/unit-tests_test_ec2_eni_info_only.yaml new file mode 100644 index 00000000000..3ce084db8c2 --- /dev/null +++ b/changelogs/fragments/unit-tests_test_ec2_eni_info_only.yaml @@ -0,0 +1,3 @@ +--- +minor_changes: +- "ec2_eni_info - Add unit-tests coverage (https://github.com/ansible-collections/amazon.aws/pull/1236)." diff --git a/plugins/modules/ec2_eni_info.py b/plugins/modules/ec2_eni_info.py index 6eb24c22f95..bf05b017e2e 100644 --- a/plugins/modules/ec2_eni_info.py +++ b/plugins/modules/ec2_eni_info.py @@ -205,27 +205,36 @@ from ansible_collections.amazon.aws.plugins.module_utils.ec2 import boto3_tag_list_to_ansible_dict -def list_eni(connection, module): +def build_request_args(eni_id, filters): - params = {} - # Options are mutually exclusive - if module.params.get("eni_id"): - params['NetworkInterfaceIds'] = [module.params.get("eni_id")] - elif module.params.get("filters"): - params['Filters'] = ansible_dict_to_boto3_filter_list(module.params.get("filters")) - else: - params['Filters'] = [] + request_args = { + 'NetworkInterfaceIds': [eni_id] if eni_id else [], + 'Filters': ansible_dict_to_boto3_filter_list(filters), + } + request_args = {k: v for k, v in request_args.items() if v} + + return request_args + + +def get_network_interfaces(connection, module, request_args): try: - network_interfaces_result = connection.describe_network_interfaces(aws_retry=True, **params)['NetworkInterfaces'] + network_interfaces_result = connection.describe_network_interfaces(aws_retry=True, **request_args) except is_boto3_error_code('InvalidNetworkInterfaceID.NotFound'): module.exit_json(network_interfaces=[]) except (ClientError, NoCredentialsError) as e: # pylint: disable=duplicate-except module.fail_json_aws(e) + return network_interfaces_result + + +def list_eni(connection, module, request_args): + + network_interfaces_result = get_network_interfaces(connection, module, request_args) + # Modify boto3 tags list to be ansible friendly dict and then camel_case camel_network_interfaces = [] - for network_interface in network_interfaces_result: + for network_interface in network_interfaces_result['NetworkInterfaces']: network_interface['TagSet'] = boto3_tag_list_to_ansible_dict(network_interface['TagSet']) network_interface['Tags'] = network_interface['TagSet'] if 'Name' in network_interface['Tags']: @@ -234,51 +243,13 @@ def list_eni(connection, module): network_interface['Id'] = network_interface['NetworkInterfaceId'] camel_network_interfaces.append(camel_dict_to_snake_dict(network_interface, ignore_list=['Tags', 'TagSet'])) - module.exit_json(network_interfaces=camel_network_interfaces) - - -def get_eni_info(interface): - - # Private addresses - private_addresses = [] - for ip in interface.private_ip_addresses: - private_addresses.append({'private_ip_address': ip.private_ip_address, 'primary_address': ip.primary}) - - interface_info = {'id': interface.id, - 'subnet_id': interface.subnet_id, - 'vpc_id': interface.vpc_id, - 'description': interface.description, - 'owner_id': interface.owner_id, - 'status': interface.status, - 'mac_address': interface.mac_address, - 'private_ip_address': interface.private_ip_address, - 'source_dest_check': interface.source_dest_check, - 'groups': dict((group.id, group.name) for group in interface.groups), - 'private_ip_addresses': private_addresses - } - - if hasattr(interface, 'publicDnsName'): - interface_info['association'] = {'public_ip_address': interface.publicIp, - 'public_dns_name': interface.publicDnsName, - 'ip_owner_id': interface.ipOwnerId - } - - if interface.attachment is not None: - interface_info['attachment'] = {'attachment_id': interface.attachment.id, - 'instance_id': interface.attachment.instance_id, - 'device_index': interface.attachment.device_index, - 'status': interface.attachment.status, - 'attach_time': interface.attachment.attach_time, - 'delete_on_termination': interface.attachment.delete_on_termination, - } - - return interface_info + return camel_network_interfaces def main(): argument_spec = dict( eni_id=dict(type='str'), - filters=dict(default=None, type='dict') + filters=dict(default={}, type='dict'), ) mutually_exclusive = [ ['eni_id', 'filters'] @@ -292,7 +263,14 @@ def main(): connection = module.client('ec2', retry_decorator=AWSRetry.jittered_backoff()) - list_eni(connection, module) + request_args = build_request_args( + eni_id=module.params["eni_id"], + filters=module.params["filters"], + ) + + result = list_eni(connection, module, request_args) + + module.exit_json(network_interfaces=result) if __name__ == '__main__': diff --git a/tests/unit/plugins/modules/test_ec2_eni_info.py b/tests/unit/plugins/modules/test_ec2_eni_info.py new file mode 100644 index 00000000000..a0997ea6518 --- /dev/null +++ b/tests/unit/plugins/modules/test_ec2_eni_info.py @@ -0,0 +1,126 @@ +# (c) 2022 Red Hat Inc. + +# This file is part of Ansible +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from unittest.mock import MagicMock, patch, ANY, call +import pytest + +from ansible_collections.amazon.aws.plugins.modules import ec2_eni_info + +module_name = "ansible_collections.amazon.aws.plugins.modules.ec2_eni_info" + + +@pytest.mark.parametrize("eni_id,filters,expected", [('', {}, {}), ('eni-1234567890', {}, {'NetworkInterfaceIds': ['eni-1234567890']})]) +def test_build_request_args(eni_id, filters, expected): + assert ec2_eni_info.build_request_args(eni_id, filters) == expected + + +def test_get_network_interfaces(): + connection = MagicMock() + module = MagicMock() + + connection.describe_network_interfaces.return_value = { + 'NetworkInterfaces': [ + { + "AvailabilityZone": "us-east-2b", + "Description": "", + "NetworkInterfaceId": "eni-1234567890", + "PrivateIpAddresses": [ + { + "Primary": "True", + "PrivateIpAddress": "11.22.33.44" + } + ], + "RequesterManaged": False, + "SourceDestCheck": True, + "Status": "available", + "SubnetId": "subnet-07d906b8358869bda", + "TagSet": [], + "VpcId": "vpc-0cb60952be96c9cd8" + } + ] + } + + request_args = {'NetworkInterfaceIds': ['eni-1234567890']} + + network_interfaces_result = ec2_eni_info.get_network_interfaces(connection, module, request_args) + + connection.describe_network_interfaces.call_count == 1 + connection.describe_network_interfaces.assert_called_with(aws_retry=True, **request_args) + assert len(network_interfaces_result['NetworkInterfaces']) == 1 + + +@patch(module_name + '.get_network_interfaces') +def test_list_eni(m_get_network_interfaces): + connection = MagicMock() + module = MagicMock() + + m_get_network_interfaces.return_value = { + 'NetworkInterfaces': [ + { + "AvailabilityZone": "us-east-2b", + "Description": "", + "NetworkInterfaceId": "eni-1234567890", + "PrivateIpAddresses": [ + { + "Primary": "True", + "PrivateIpAddress": "11.22.33.44" + } + ], + "RequesterManaged": False, + "SourceDestCheck": True, + "Status": "available", + "SubnetId": "subnet-07d906b8358869bda", + "TagSet": [], + "VpcId": "vpc-0cb60952be96c9cd8" + }, + { + "AvailabilityZone": "us-east-2b", + "Description": "", + "NetworkInterfaceId": "eni-0987654321", + "PrivateIpAddresses": [ + { + "Primary": "True", + "PrivateIpAddress": "11.22.33.44" + } + ], + "RequesterManaged": False, + "SourceDestCheck": True, + "Status": "available", + "SubnetId": "subnet-07d906b8358869bda", + "TagSet": [{ + 'Key': 'Name', + 'Value': 'my-test-eni-name' + }, ], + "VpcId": "vpc-0cb60952be96c9cd8" + }, + ] + } + + request_args = { + 'Filters': [{ + 'Name': 'owner-id', + 'Values': [ + '1234567890' + ] + }] + } + + camel_network_interfaces = ec2_eni_info.list_eni(connection, module, request_args) + + m_get_network_interfaces.call_count == 1 + m_get_network_interfaces.assert_has_calls( + [ + call(connection, module, request_args), + ] + ) + assert len(camel_network_interfaces) == 2 + + assert camel_network_interfaces[0]['id'] == 'eni-1234567890' + assert camel_network_interfaces[0]['tags'] == {} + assert camel_network_interfaces[0].get('name') is None + + assert camel_network_interfaces[1]['id'] == 'eni-0987654321' + assert camel_network_interfaces[1]['tags'] == {'Name': 'my-test-eni-name'} + assert camel_network_interfaces[1]['name'] == 'my-test-eni-name'