1#!/usr/bin/python 2# 3# This is a free software: you can redistribute it and/or modify 4# it under the terms of the GNU General Public License as published by 5# the Free Software Foundation, either version 3 of the License, or 6# (at your option) any later version. 7# 8# This Ansible library is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License 14# along with this library. If not, see <http://www.gnu.org/licenses/>. 15 16ANSIBLE_METADATA = {'metadata_version': '1.1', 17 'status': ['preview'], 18 'supported_by': 'community'} 19 20 21DOCUMENTATION = ''' 22--- 23module: ec2_eni_info 24short_description: Gather information about ec2 ENI interfaces in AWS 25description: 26 - Gather information about ec2 ENI interfaces in AWS 27 - This module was called C(ec2_eni_facts) before Ansible 2.9. The usage did not change. 28version_added: "2.0" 29author: "Rob White (@wimnat)" 30requirements: [ boto3 ] 31options: 32 filters: 33 description: 34 - A dict of filters to apply. Each dict item consists of a filter key and a filter value. 35 See U(https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeNetworkInterfaces.html) for possible filters. 36extends_documentation_fragment: 37 - aws 38 - ec2 39''' 40 41EXAMPLES = ''' 42# Note: These examples do not set authentication details, see the AWS Guide for details. 43 44# Gather information about all ENIs 45- ec2_eni_info: 46 47# Gather information about a particular ENI 48- ec2_eni_info: 49 filters: 50 network-interface-id: eni-xxxxxxx 51 52''' 53 54RETURN = ''' 55network_interfaces: 56 description: List of matching elastic network interfaces 57 returned: always 58 type: complex 59 contains: 60 association: 61 description: Info of associated elastic IP (EIP) 62 returned: always, empty dict if no association exists 63 type: dict 64 sample: { 65 allocation_id: "eipalloc-5sdf123", 66 association_id: "eipassoc-8sdf123", 67 ip_owner_id: "4415120123456", 68 public_dns_name: "ec2-52-1-0-63.compute-1.amazonaws.com", 69 public_ip: "52.1.0.63" 70 } 71 attachment: 72 description: Info about attached ec2 instance 73 returned: always, empty dict if ENI is not attached 74 type: dict 75 sample: { 76 attach_time: "2017-08-05T15:25:47+00:00", 77 attachment_id: "eni-attach-149d21234", 78 delete_on_termination: false, 79 device_index: 1, 80 instance_id: "i-15b8d3cadbafa1234", 81 instance_owner_id: "4415120123456", 82 status: "attached" 83 } 84 availability_zone: 85 description: Availability zone of ENI 86 returned: always 87 type: str 88 sample: "us-east-1b" 89 description: 90 description: Description text for ENI 91 returned: always 92 type: str 93 sample: "My favourite network interface" 94 groups: 95 description: List of attached security groups 96 returned: always 97 type: list 98 sample: [ 99 { 100 group_id: "sg-26d0f1234", 101 group_name: "my_ec2_security_group" 102 } 103 ] 104 id: 105 description: The id of the ENI (alias for network_interface_id) 106 returned: always 107 type: str 108 sample: "eni-392fsdf" 109 interface_type: 110 description: Type of the network interface 111 returned: always 112 type: str 113 sample: "interface" 114 ipv6_addresses: 115 description: List of IPv6 addresses for this interface 116 returned: always 117 type: list 118 sample: [] 119 mac_address: 120 description: MAC address of the network interface 121 returned: always 122 type: str 123 sample: "0a:f8:10:2f:ab:a1" 124 network_interface_id: 125 description: The id of the ENI 126 returned: always 127 type: str 128 sample: "eni-392fsdf" 129 owner_id: 130 description: AWS account id of the owner of the ENI 131 returned: always 132 type: str 133 sample: "4415120123456" 134 private_dns_name: 135 description: Private DNS name for the ENI 136 returned: always 137 type: str 138 sample: "ip-172-16-1-180.ec2.internal" 139 private_ip_address: 140 description: Private IP address for the ENI 141 returned: always 142 type: str 143 sample: "172.16.1.180" 144 private_ip_addresses: 145 description: List of private IP addresses attached to the ENI 146 returned: always 147 type: list 148 sample: [] 149 requester_id: 150 description: The ID of the entity that launched the ENI 151 returned: always 152 type: str 153 sample: "AIDAIONYVJQNIAZFT3ABC" 154 requester_managed: 155 description: Indicates whether the network interface is being managed by an AWS service. 156 returned: always 157 type: bool 158 sample: false 159 source_dest_check: 160 description: Indicates whether the network interface performs source/destination checking. 161 returned: always 162 type: bool 163 sample: false 164 status: 165 description: Indicates if the network interface is attached to an instance or not 166 returned: always 167 type: str 168 sample: "in-use" 169 subnet_id: 170 description: Subnet ID the ENI is in 171 returned: always 172 type: str 173 sample: "subnet-7bbf01234" 174 tag_set: 175 description: Dictionary of tags added to the ENI 176 returned: always 177 type: dict 178 sample: {} 179 vpc_id: 180 description: ID of the VPC the network interface it part of 181 returned: always 182 type: str 183 sample: "vpc-b3f1f123" 184''' 185 186try: 187 from botocore.exceptions import ClientError, NoCredentialsError 188 HAS_BOTO3 = True 189except ImportError: 190 HAS_BOTO3 = False 191 192from ansible.module_utils.basic import AnsibleModule 193from ansible.module_utils.ec2 import ansible_dict_to_boto3_filter_list, boto3_conn 194from ansible.module_utils.ec2 import boto3_tag_list_to_ansible_dict, camel_dict_to_snake_dict 195from ansible.module_utils.ec2 import ec2_argument_spec, get_aws_connection_info 196 197 198def list_eni(connection, module): 199 200 if module.params.get("filters") is None: 201 filters = [] 202 else: 203 filters = ansible_dict_to_boto3_filter_list(module.params.get("filters")) 204 205 try: 206 network_interfaces_result = connection.describe_network_interfaces(Filters=filters)['NetworkInterfaces'] 207 except (ClientError, NoCredentialsError) as e: 208 module.fail_json(msg=e.message) 209 210 # Modify boto3 tags list to be ansible friendly dict and then camel_case 211 camel_network_interfaces = [] 212 for network_interface in network_interfaces_result: 213 network_interface['TagSet'] = boto3_tag_list_to_ansible_dict(network_interface['TagSet']) 214 # Added id to interface info to be compatible with return values of ec2_eni module: 215 network_interface['Id'] = network_interface['NetworkInterfaceId'] 216 camel_network_interfaces.append(camel_dict_to_snake_dict(network_interface)) 217 218 module.exit_json(network_interfaces=camel_network_interfaces) 219 220 221def get_eni_info(interface): 222 223 # Private addresses 224 private_addresses = [] 225 for ip in interface.private_ip_addresses: 226 private_addresses.append({'private_ip_address': ip.private_ip_address, 'primary_address': ip.primary}) 227 228 interface_info = {'id': interface.id, 229 'subnet_id': interface.subnet_id, 230 'vpc_id': interface.vpc_id, 231 'description': interface.description, 232 'owner_id': interface.owner_id, 233 'status': interface.status, 234 'mac_address': interface.mac_address, 235 'private_ip_address': interface.private_ip_address, 236 'source_dest_check': interface.source_dest_check, 237 'groups': dict((group.id, group.name) for group in interface.groups), 238 'private_ip_addresses': private_addresses 239 } 240 241 if hasattr(interface, 'publicDnsName'): 242 interface_info['association'] = {'public_ip_address': interface.publicIp, 243 'public_dns_name': interface.publicDnsName, 244 'ip_owner_id': interface.ipOwnerId 245 } 246 247 if interface.attachment is not None: 248 interface_info['attachment'] = {'attachment_id': interface.attachment.id, 249 'instance_id': interface.attachment.instance_id, 250 'device_index': interface.attachment.device_index, 251 'status': interface.attachment.status, 252 'attach_time': interface.attachment.attach_time, 253 'delete_on_termination': interface.attachment.delete_on_termination, 254 } 255 256 return interface_info 257 258 259def main(): 260 argument_spec = ec2_argument_spec() 261 argument_spec.update( 262 dict( 263 filters=dict(default=None, type='dict') 264 ) 265 ) 266 267 module = AnsibleModule(argument_spec=argument_spec) 268 if module._name == 'ec2_eni_facts': 269 module.deprecate("The 'ec2_eni_facts' module has been renamed to 'ec2_eni_info'", version='2.13') 270 271 if not HAS_BOTO3: 272 module.fail_json(msg='boto3 required for this module') 273 274 region, ec2_url, aws_connect_params = get_aws_connection_info(module, boto3=True) 275 276 connection = boto3_conn(module, conn_type='client', resource='ec2', region=region, endpoint=ec2_url, **aws_connect_params) 277 278 list_eni(connection, module) 279 280 281if __name__ == '__main__': 282 main() 283