1#!/usr/local/bin/python3.8 2# -*- coding: utf-8 -*- 3# Copyright: Ansible Project 4# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 5 6from __future__ import absolute_import, division, print_function 7__metaclass__ = type 8 9 10DOCUMENTATION = ''' 11--- 12module: ec2_metadata_facts 13version_added: 1.0.0 14short_description: gathers facts (instance metadata) about remote hosts within EC2 15author: 16 - Silviu Dicu (@silviud) 17 - Vinay Dandekar (@roadmapper) 18description: 19 - This module fetches data from the instance metadata endpoint in EC2 as per 20 U(https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html). 21 - The module must be called from within the EC2 instance itself. 22 - The module is configured to utilize the session oriented Instance Metadata Service v2 (IMDSv2) 23 U(https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html). 24 - If the HttpEndpoint parameter 25 U(https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_ModifyInstanceMetadataOptions.html#API_ModifyInstanceMetadataOptions_RequestParameters) 26 is set to disabled for the EC2 instance, the module will return an error while retrieving a session token. 27notes: 28 - Parameters to filter on ec2_metadata_facts may be added later. 29''' 30 31EXAMPLES = ''' 32# Gather EC2 metadata facts 33- amazon.aws.ec2_metadata_facts: 34 35- debug: 36 msg: "This instance is a t1.micro" 37 when: ansible_ec2_instance_type == "t1.micro" 38''' 39 40RETURN = ''' 41ansible_facts: 42 description: Dictionary of new facts representing discovered properties of the EC2 instance. 43 returned: changed 44 type: complex 45 contains: 46 ansible_ec2_ami_id: 47 description: The AMI ID used to launch the instance. 48 type: str 49 sample: "ami-XXXXXXXX" 50 ansible_ec2_ami_launch_index: 51 description: 52 - If you started more than one instance at the same time, this value indicates the order in which the instance was launched. 53 - The value of the first instance launched is 0. 54 type: str 55 sample: "0" 56 ansible_ec2_ami_manifest_path: 57 description: 58 - The path to the AMI manifest file in Amazon S3. 59 - If you used an Amazon EBS-backed AMI to launch the instance, the returned result is unknown. 60 type: str 61 sample: "(unknown)" 62 ansible_ec2_ancestor_ami_ids: 63 description: 64 - The AMI IDs of any instances that were rebundled to create this AMI. 65 - This value will only exist if the AMI manifest file contained an ancestor-amis key. 66 type: str 67 sample: "(unknown)" 68 ansible_ec2_block_device_mapping_ami: 69 description: The virtual device that contains the root/boot file system. 70 type: str 71 sample: "/dev/sda1" 72 ansible_ec2_block_device_mapping_ebsN: 73 description: 74 - The virtual devices associated with Amazon EBS volumes, if any are present. 75 - Amazon EBS volumes are only available in metadata if they were present at launch time or when the instance was last started. 76 - The N indicates the index of the Amazon EBS volume (such as ebs1 or ebs2). 77 type: str 78 sample: "/dev/xvdb" 79 ansible_ec2_block_device_mapping_ephemeralN: 80 description: The virtual devices associated with ephemeral devices, if any are present. The N indicates the index of the ephemeral volume. 81 type: str 82 sample: "/dev/xvdc" 83 ansible_ec2_block_device_mapping_root: 84 description: 85 - The virtual devices or partitions associated with the root devices, or partitions on the virtual device, 86 where the root (/ or C) file system is associated with the given instance. 87 type: str 88 sample: "/dev/sda1" 89 ansible_ec2_block_device_mapping_swap: 90 description: The virtual devices associated with swap. Not always present. 91 type: str 92 sample: "/dev/sda2" 93 ansible_ec2_fws_instance_monitoring: 94 description: "Value showing whether the customer has enabled detailed one-minute monitoring in CloudWatch." 95 type: str 96 sample: "enabled" 97 ansible_ec2_hostname: 98 description: 99 - The private IPv4 DNS hostname of the instance. 100 - In cases where multiple network interfaces are present, this refers to the eth0 device (the device for which the device number is 0). 101 type: str 102 sample: "ip-10-0-0-1.ec2.internal" 103 ansible_ec2_iam_info: 104 description: 105 - If there is an IAM role associated with the instance, contains information about the last time the instance profile was updated, 106 including the instance's LastUpdated date, InstanceProfileArn, and InstanceProfileId. Otherwise, not present. 107 type: complex 108 sample: "" 109 contains: 110 LastUpdated: 111 description: The last time which InstanceProfile is associated with the Instance changed. 112 type: str 113 InstanceProfileArn: 114 description: The ARN of the InstanceProfile associated with the Instance. 115 type: str 116 InstanceProfileId: 117 description: The Id of the InstanceProfile associated with the Instance. 118 type: str 119 ansible_ec2_iam_info_instanceprofilearn: 120 description: The IAM instance profile ARN. 121 type: str 122 sample: "arn:aws:iam::<account id>:instance-profile/<role name>" 123 ansible_ec2_iam_info_instanceprofileid: 124 description: IAM instance profile ID. 125 type: str 126 sample: "" 127 ansible_ec2_iam_info_lastupdated: 128 description: IAM info last updated time. 129 type: str 130 sample: "2017-05-12T02:42:27Z" 131 ansible_ec2_iam_instance_profile_role: 132 description: IAM instance role. 133 type: str 134 sample: "role_name" 135 ansible_ec2_iam_security_credentials_<role name>: 136 description: 137 - If there is an IAM role associated with the instance, role-name is the name of the role, 138 and role-name contains the temporary security credentials associated with the role. Otherwise, not present. 139 type: str 140 sample: "" 141 ansible_ec2_iam_security_credentials_<role name>_accesskeyid: 142 description: IAM role access key ID. 143 type: str 144 sample: "" 145 ansible_ec2_iam_security_credentials_<role name>_code: 146 description: IAM code. 147 type: str 148 sample: "Success" 149 ansible_ec2_iam_security_credentials_<role name>_expiration: 150 description: IAM role credentials expiration time. 151 type: str 152 sample: "2017-05-12T09:11:41Z" 153 ansible_ec2_iam_security_credentials_<role name>_lastupdated: 154 description: IAM role last updated time. 155 type: str 156 sample: "2017-05-12T02:40:44Z" 157 ansible_ec2_iam_security_credentials_<role name>_secretaccesskey: 158 description: IAM role secret access key. 159 type: str 160 sample: "" 161 ansible_ec2_iam_security_credentials_<role name>_token: 162 description: IAM role token. 163 type: str 164 sample: "" 165 ansible_ec2_iam_security_credentials_<role name>_type: 166 description: IAM role type. 167 type: str 168 sample: "AWS-HMAC" 169 ansible_ec2_instance_action: 170 description: Notifies the instance that it should reboot in preparation for bundling. 171 type: str 172 sample: "none" 173 ansible_ec2_instance_id: 174 description: The ID of this instance. 175 type: str 176 sample: "i-XXXXXXXXXXXXXXXXX" 177 ansible_ec2_instance_identity_document: 178 description: JSON containing instance attributes, such as instance-id, private IP address, etc. 179 type: str 180 sample: "" 181 ansible_ec2_instance_identity_document_accountid: 182 description: "" 183 type: str 184 sample: "012345678901" 185 ansible_ec2_instance_identity_document_architecture: 186 description: Instance system architecture. 187 type: str 188 sample: "x86_64" 189 ansible_ec2_instance_identity_document_availabilityzone: 190 description: The Availability Zone in which the instance launched. 191 type: str 192 sample: "us-east-1a" 193 ansible_ec2_instance_identity_document_billingproducts: 194 description: Billing products for this instance. 195 type: str 196 sample: "" 197 ansible_ec2_instance_identity_document_devpayproductcodes: 198 description: Product codes for the launched AMI. 199 type: str 200 sample: "" 201 ansible_ec2_instance_identity_document_imageid: 202 description: The AMI ID used to launch the instance. 203 type: str 204 sample: "ami-01234567" 205 ansible_ec2_instance_identity_document_instanceid: 206 description: The ID of this instance. 207 type: str 208 sample: "i-0123456789abcdef0" 209 ansible_ec2_instance_identity_document_instancetype: 210 description: The type of instance. 211 type: str 212 sample: "m4.large" 213 ansible_ec2_instance_identity_document_kernelid: 214 description: The ID of the kernel launched with this instance, if applicable. 215 type: str 216 sample: "" 217 ansible_ec2_instance_identity_document_pendingtime: 218 description: The instance pending time. 219 type: str 220 sample: "2017-05-11T20:51:20Z" 221 ansible_ec2_instance_identity_document_privateip: 222 description: 223 - The private IPv4 address of the instance. 224 - In cases where multiple network interfaces are present, this refers to the eth0 device (the device for which the device number is 0). 225 type: str 226 sample: "10.0.0.1" 227 ansible_ec2_instance_identity_document_ramdiskid: 228 description: The ID of the RAM disk specified at launch time, if applicable. 229 type: str 230 sample: "" 231 ansible_ec2_instance_identity_document_region: 232 description: The Region in which the instance launched. 233 type: str 234 sample: "us-east-1" 235 ansible_ec2_instance_identity_document_version: 236 description: Identity document version. 237 type: str 238 sample: "2010-08-31" 239 ansible_ec2_instance_identity_pkcs7: 240 description: Used to verify the document's authenticity and content against the signature. 241 type: str 242 sample: "" 243 ansible_ec2_instance_identity_rsa2048: 244 description: Used to verify the document's authenticity and content against the signature. 245 type: str 246 sample: "" 247 ansible_ec2_instance_identity_signature: 248 description: Data that can be used by other parties to verify its origin and authenticity. 249 type: str 250 sample: "" 251 ansible_ec2_instance_life_cycle: 252 description: The purchasing option of the instance. 253 type: str 254 sample: "on-demand" 255 ansible_ec2_instance_type: 256 description: The type of the instance. 257 type: str 258 sample: "m4.large" 259 ansible_ec2_local_hostname: 260 description: 261 - The private IPv4 DNS hostname of the instance. 262 - In cases where multiple network interfaces are present, this refers to the eth0 device (the device for which the device number is 0). 263 type: str 264 sample: "ip-10-0-0-1.ec2.internal" 265 ansible_ec2_local_ipv4: 266 description: 267 - The private IPv4 address of the instance. 268 - In cases where multiple network interfaces are present, this refers to the eth0 device (the device for which the device number is 0). 269 type: str 270 sample: "10.0.0.1" 271 ansible_ec2_mac: 272 description: 273 - The instance's media access control (MAC) address. 274 - In cases where multiple network interfaces are present, this refers to the eth0 device (the device for which the device number is 0). 275 type: str 276 sample: "00:11:22:33:44:55" 277 ansible_ec2_metrics_vhostmd: 278 description: Metrics; no longer available. 279 type: str 280 sample: "" 281 ansible_ec2_network_interfaces_macs_<mac address>_device_number: 282 description: 283 - The unique device number associated with that interface. The device number corresponds to the device name; 284 for example, a device-number of 2 is for the eth2 device. 285 - This category corresponds to the DeviceIndex and device-index fields that are used by the Amazon EC2 API and the EC2 commands for the AWS CLI. 286 type: str 287 sample: "0" 288 ansible_ec2_network_interfaces_macs_<mac address>_interface_id: 289 description: The elastic network interface ID. 290 type: str 291 sample: "eni-12345678" 292 ansible_ec2_network_interfaces_macs_<mac address>_ipv4_associations_<ip address>: 293 description: The private IPv4 addresses that are associated with each public-ip address and assigned to that interface. 294 type: str 295 sample: "" 296 ansible_ec2_network_interfaces_macs_<mac address>_ipv6s: 297 description: The IPv6 addresses associated with the interface. Returned only for instances launched into a VPC. 298 type: str 299 sample: "" 300 ansible_ec2_network_interfaces_macs_<mac address>_local_hostname: 301 description: The interface's local hostname. 302 type: str 303 sample: "" 304 ansible_ec2_network_interfaces_macs_<mac address>_local_ipv4s: 305 description: The private IPv4 addresses associated with the interface. 306 type: str 307 sample: "" 308 ansible_ec2_network_interfaces_macs_<mac address>_mac: 309 description: The instance's MAC address. 310 type: str 311 sample: "00:11:22:33:44:55" 312 ansible_ec2_network_interfaces_macs_<mac address>_owner_id: 313 description: 314 - The ID of the owner of the network interface. 315 - In multiple-interface environments, an interface can be attached by a third party, such as Elastic Load Balancing. 316 - Traffic on an interface is always billed to the interface owner. 317 type: str 318 sample: "01234567890" 319 ansible_ec2_network_interfaces_macs_<mac address>_public_hostname: 320 description: 321 - The interface's public DNS (IPv4). If the instance is in a VPC, 322 this category is only returned if the enableDnsHostnames attribute is set to true. 323 type: str 324 sample: "ec2-1-2-3-4.compute-1.amazonaws.com" 325 ansible_ec2_network_interfaces_macs_<mac address>_public_ipv4s: 326 description: The Elastic IP addresses associated with the interface. There may be multiple IPv4 addresses on an instance. 327 type: str 328 sample: "1.2.3.4" 329 ansible_ec2_network_interfaces_macs_<mac address>_security_group_ids: 330 description: The IDs of the security groups to which the network interface belongs. Returned only for instances launched into a VPC. 331 type: str 332 sample: "sg-01234567,sg-01234568" 333 ansible_ec2_network_interfaces_macs_<mac address>_security_groups: 334 description: Security groups to which the network interface belongs. Returned only for instances launched into a VPC. 335 type: str 336 sample: "secgroup1,secgroup2" 337 ansible_ec2_network_interfaces_macs_<mac address>_subnet_id: 338 description: The ID of the subnet in which the interface resides. Returned only for instances launched into a VPC. 339 type: str 340 sample: "subnet-01234567" 341 ansible_ec2_network_interfaces_macs_<mac address>_subnet_ipv4_cidr_block: 342 description: The IPv4 CIDR block of the subnet in which the interface resides. Returned only for instances launched into a VPC. 343 type: str 344 sample: "10.0.1.0/24" 345 ansible_ec2_network_interfaces_macs_<mac address>_subnet_ipv6_cidr_blocks: 346 description: The IPv6 CIDR block of the subnet in which the interface resides. Returned only for instances launched into a VPC. 347 type: str 348 sample: "" 349 ansible_ec2_network_interfaces_macs_<mac address>_vpc_id: 350 description: The ID of the VPC in which the interface resides. Returned only for instances launched into a VPC. 351 type: str 352 sample: "vpc-0123456" 353 ansible_ec2_network_interfaces_macs_<mac address>_vpc_ipv4_cidr_block: 354 description: The IPv4 CIDR block of the VPC in which the interface resides. Returned only for instances launched into a VPC. 355 type: str 356 sample: "10.0.0.0/16" 357 ansible_ec2_network_interfaces_macs_<mac address>_vpc_ipv4_cidr_blocks: 358 description: The IPv4 CIDR block of the VPC in which the interface resides. Returned only for instances launched into a VPC. 359 type: str 360 sample: "10.0.0.0/16" 361 ansible_ec2_network_interfaces_macs_<mac address>_vpc_ipv6_cidr_blocks: 362 description: The IPv6 CIDR block of the VPC in which the interface resides. Returned only for instances launched into a VPC. 363 type: str 364 sample: "" 365 ansible_ec2_placement_availability_zone: 366 description: The Availability Zone in which the instance launched. 367 type: str 368 sample: "us-east-1a" 369 ansible_ec2_placement_region: 370 description: The Region in which the instance launched. 371 type: str 372 sample: "us-east-1" 373 ansible_ec2_product_codes: 374 description: Product codes associated with the instance, if any. 375 type: str 376 sample: "aw0evgkw8e5c1q413zgy5pjce" 377 ansible_ec2_profile: 378 description: EC2 instance hardware profile. 379 type: str 380 sample: "default-hvm" 381 ansible_ec2_public_hostname: 382 description: 383 - The instance's public DNS. If the instance is in a VPC, this category is only returned if the enableDnsHostnames attribute is set to true. 384 type: str 385 sample: "ec2-1-2-3-4.compute-1.amazonaws.com" 386 ansible_ec2_public_ipv4: 387 description: The public IPv4 address. If an Elastic IP address is associated with the instance, the value returned is the Elastic IP address. 388 type: str 389 sample: "1.2.3.4" 390 ansible_ec2_public_key: 391 description: Public key. Only available if supplied at instance launch time. 392 type: str 393 sample: "" 394 ansible_ec2_ramdisk_id: 395 description: The ID of the RAM disk specified at launch time, if applicable. 396 type: str 397 sample: "" 398 ansible_ec2_reservation_id: 399 description: The ID of the reservation. 400 type: str 401 sample: "r-0123456789abcdef0" 402 ansible_ec2_security_groups: 403 description: 404 - The names of the security groups applied to the instance. After launch, you can only change the security groups of instances running in a VPC. 405 - Such changes are reflected here and in network/interfaces/macs/mac/security-groups. 406 type: str 407 sample: "securitygroup1,securitygroup2" 408 ansible_ec2_services_domain: 409 description: The domain for AWS resources for the region; for example, amazonaws.com for us-east-1. 410 type: str 411 sample: "amazonaws.com" 412 ansible_ec2_services_partition: 413 description: 414 - The partition that the resource is in. For standard AWS regions, the partition is aws. 415 - If you have resources in other partitions, the partition is aws-partitionname. 416 - For example, the partition for resources in the China (Beijing) region is aws-cn. 417 type: str 418 sample: "aws" 419 ansible_ec2_spot_termination_time: 420 description: 421 - The approximate time, in UTC, that the operating system for your Spot instance will receive the shutdown signal. 422 - This item is present and contains a time value only if the Spot instance has been marked for termination by Amazon EC2. 423 - The termination-time item is not set to a time if you terminated the Spot instance yourself. 424 type: str 425 sample: "2015-01-05T18:02:00Z" 426 ansible_ec2_user_data: 427 description: The instance user data. 428 type: str 429 sample: "#!/bin/bash" 430''' 431 432import json 433import re 434import socket 435import time 436 437from ansible.module_utils.basic import AnsibleModule 438from ansible.module_utils._text import to_text 439from ansible.module_utils.urls import fetch_url 440from ansible.module_utils.six.moves.urllib.parse import quote 441 442socket.setdefaulttimeout(5) 443 444 445class Ec2Metadata(object): 446 ec2_metadata_token_uri = 'http://169.254.169.254/latest/api/token' 447 ec2_metadata_uri = 'http://169.254.169.254/latest/meta-data/' 448 ec2_sshdata_uri = 'http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key' 449 ec2_userdata_uri = 'http://169.254.169.254/latest/user-data/' 450 ec2_dynamicdata_uri = 'http://169.254.169.254/latest/dynamic/' 451 452 def __init__(self, module, ec2_metadata_token_uri=None, ec2_metadata_uri=None, ec2_sshdata_uri=None, ec2_userdata_uri=None, ec2_dynamicdata_uri=None): 453 self.module = module 454 self.uri_token = ec2_metadata_token_uri or self.ec2_metadata_token_uri 455 self.uri_meta = ec2_metadata_uri or self.ec2_metadata_uri 456 self.uri_user = ec2_userdata_uri or self.ec2_userdata_uri 457 self.uri_ssh = ec2_sshdata_uri or self.ec2_sshdata_uri 458 self.uri_dynamic = ec2_dynamicdata_uri or self.ec2_dynamicdata_uri 459 self._data = {} 460 self._token = None 461 self._prefix = 'ansible_ec2_%s' 462 463 def _fetch(self, url): 464 encoded_url = quote(url, safe='%/:=&?~#+!$,;\'@()*[]') 465 headers = {} 466 if self._token: 467 headers = {'X-aws-ec2-metadata-token': self._token} 468 response, info = fetch_url(self.module, encoded_url, headers=headers, force=True) 469 470 if info.get('status') in (401, 403): 471 self.module.fail_json(msg='Failed to retrieve metadata from AWS: {0}'.format(info['msg']), response=info) 472 elif info.get('status') not in (200, 404): 473 time.sleep(3) 474 # request went bad, retry once then raise 475 self.module.warn('Retrying query to metadata service. First attempt failed: {0}'.format(info['msg'])) 476 response, info = fetch_url(self.module, encoded_url, headers=headers, force=True) 477 if info.get('status') not in (200, 404): 478 # fail out now 479 self.module.fail_json(msg='Failed to retrieve metadata from AWS: {0}'.format(info['msg']), response=info) 480 if response: 481 data = response.read() 482 else: 483 data = None 484 return to_text(data) 485 486 def _mangle_fields(self, fields, uri, filter_patterns=None): 487 filter_patterns = ['public-keys-0'] if filter_patterns is None else filter_patterns 488 489 new_fields = {} 490 for key, value in fields.items(): 491 split_fields = key[len(uri):].split('/') 492 # Parse out the IAM role name (which is _not_ the same as the instance profile name) 493 if len(split_fields) == 3 and split_fields[0:2] == ['iam', 'security-credentials'] and ':' not in split_fields[2]: 494 new_fields[self._prefix % "iam-instance-profile-role"] = split_fields[2] 495 if len(split_fields) > 1 and split_fields[1]: 496 new_key = "-".join(split_fields) 497 new_fields[self._prefix % new_key] = value 498 else: 499 new_key = "".join(split_fields) 500 new_fields[self._prefix % new_key] = value 501 for pattern in filter_patterns: 502 for key in dict(new_fields): 503 match = re.search(pattern, key) 504 if match: 505 new_fields.pop(key) 506 return new_fields 507 508 def fetch(self, uri, recurse=True): 509 raw_subfields = self._fetch(uri) 510 if not raw_subfields: 511 return 512 subfields = raw_subfields.split('\n') 513 for field in subfields: 514 if field.endswith('/') and recurse: 515 self.fetch(uri + field) 516 if uri.endswith('/'): 517 new_uri = uri + field 518 else: 519 new_uri = uri + '/' + field 520 if new_uri not in self._data and not new_uri.endswith('/'): 521 content = self._fetch(new_uri) 522 if field == 'security-groups' or field == 'security-group-ids': 523 sg_fields = ",".join(content.split('\n')) 524 self._data['%s' % (new_uri)] = sg_fields 525 else: 526 try: 527 dict = json.loads(content) 528 self._data['%s' % (new_uri)] = content 529 for (key, value) in dict.items(): 530 self._data['%s:%s' % (new_uri, key.lower())] = value 531 except Exception: 532 self._data['%s' % (new_uri)] = content # not a stringified JSON string 533 534 def fix_invalid_varnames(self, data): 535 """Change ':'' and '-' to '_' to ensure valid template variable names""" 536 new_data = data.copy() 537 for key, value in data.items(): 538 if ':' in key or '-' in key: 539 newkey = re.sub(':|-', '_', key) 540 new_data[newkey] = value 541 del new_data[key] 542 543 return new_data 544 545 def fetch_session_token(self, uri_token): 546 """Used to get a session token for IMDSv2""" 547 headers = {'X-aws-ec2-metadata-token-ttl-seconds': '60'} 548 response, info = fetch_url(self.module, uri_token, method='PUT', headers=headers, force=True) 549 550 if info.get('status') == 403: 551 self.module.fail_json(msg='Failed to retrieve metadata token from AWS: {0}'.format(info['msg']), response=info) 552 elif info.get('status') not in (200, 404): 553 time.sleep(3) 554 # request went bad, retry once then raise 555 self.module.warn('Retrying query to metadata service. First attempt failed: {0}'.format(info['msg'])) 556 response, info = fetch_url(self.module, uri_token, method='PUT', headers=headers, force=True) 557 if info.get('status') not in (200, 404): 558 # fail out now 559 self.module.fail_json(msg='Failed to retrieve metadata token from AWS: {0}'.format(info['msg']), response=info) 560 if response: 561 token_data = response.read() 562 else: 563 token_data = None 564 return to_text(token_data) 565 566 def run(self): 567 self._token = self.fetch_session_token(self.uri_token) # create session token for IMDS 568 self.fetch(self.uri_meta) # populate _data with metadata 569 data = self._mangle_fields(self._data, self.uri_meta) 570 data[self._prefix % 'user-data'] = self._fetch(self.uri_user) 571 data[self._prefix % 'public-key'] = self._fetch(self.uri_ssh) 572 573 self._data = {} # clear out metadata in _data 574 self.fetch(self.uri_dynamic) # populate _data with dynamic data 575 dyndata = self._mangle_fields(self._data, self.uri_dynamic) 576 data.update(dyndata) 577 data = self.fix_invalid_varnames(data) 578 579 # Maintain old key for backwards compatibility 580 if 'ansible_ec2_instance_identity_document_region' in data: 581 data['ansible_ec2_placement_region'] = data['ansible_ec2_instance_identity_document_region'] 582 return data 583 584 585def main(): 586 module = AnsibleModule( 587 argument_spec={}, 588 supports_check_mode=True, 589 ) 590 591 ec2_metadata_facts = Ec2Metadata(module).run() 592 ec2_metadata_facts_result = dict(changed=False, ansible_facts=ec2_metadata_facts) 593 594 module.exit_json(**ec2_metadata_facts_result) 595 596 597if __name__ == '__main__': 598 main() 599