1#!/usr/local/bin/python3.8 2# Copyright: Ansible Project 3# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 4 5from __future__ import absolute_import, division, print_function 6__metaclass__ = type 7 8 9DOCUMENTATION = r''' 10module: route53_info 11short_description: Retrieves route53 details using AWS methods 12version_added: 1.0.0 13description: 14 - Gets various details related to Route53 zone, record set or health check details. 15 - This module was called C(route53_facts) before Ansible 2.9. The usage did not change. 16options: 17 query: 18 description: 19 - Specifies the query action to take. 20 required: True 21 choices: [ 22 'change', 23 'checker_ip_range', 24 'health_check', 25 'hosted_zone', 26 'record_sets', 27 'reusable_delegation_set', 28 ] 29 type: str 30 change_id: 31 description: 32 - The ID of the change batch request. 33 - The value that you specify here is the value that 34 ChangeResourceRecordSets returned in the Id element 35 when you submitted the request. 36 - Required if I(query=change). 37 required: false 38 type: str 39 hosted_zone_id: 40 description: 41 - The Hosted Zone ID of the DNS zone. 42 - Required if I(query) is set to I(hosted_zone) and I(hosted_zone_method) is set to I(details). 43 - Required if I(query) is set to I(record_sets). 44 required: false 45 type: str 46 max_items: 47 description: 48 - Maximum number of items to return for various get/list requests. 49 required: false 50 type: str 51 next_marker: 52 description: 53 - "Some requests such as list_command: hosted_zones will return a maximum 54 number of entries - EG 100 or the number specified by I(max_items). 55 If the number of entries exceeds this maximum another request can be sent 56 using the NextMarker entry from the first response to get the next page 57 of results." 58 required: false 59 type: str 60 delegation_set_id: 61 description: 62 - The DNS Zone delegation set ID. 63 required: false 64 type: str 65 start_record_name: 66 description: 67 - "The first name in the lexicographic ordering of domain names that you want 68 the list_command: record_sets to start listing from." 69 required: false 70 type: str 71 type: 72 description: 73 - The type of DNS record. 74 required: false 75 choices: [ 'A', 'CNAME', 'MX', 'AAAA', 'TXT', 'PTR', 'SRV', 'SPF', 'CAA', 'NS' ] 76 type: str 77 dns_name: 78 description: 79 - The first name in the lexicographic ordering of domain names that you want 80 the list_command to start listing from. 81 required: false 82 type: str 83 resource_id: 84 description: 85 - The ID/s of the specified resource/s. 86 - Required if I(query=health_check) and I(health_check_method=tags). 87 - Required if I(query=hosted_zone) and I(hosted_zone_method=tags). 88 required: false 89 aliases: ['resource_ids'] 90 type: list 91 elements: str 92 health_check_id: 93 description: 94 - The ID of the health check. 95 - Required if C(query) is set to C(health_check) and 96 C(health_check_method) is set to C(details) or C(status) or C(failure_reason). 97 required: false 98 type: str 99 hosted_zone_method: 100 description: 101 - "This is used in conjunction with query: hosted_zone. 102 It allows for listing details, counts or tags of various 103 hosted zone details." 104 required: false 105 choices: [ 106 'details', 107 'list', 108 'list_by_name', 109 'count', 110 'tags', 111 ] 112 default: 'list' 113 type: str 114 health_check_method: 115 description: 116 - "This is used in conjunction with query: health_check. 117 It allows for listing details, counts or tags of various 118 health check details." 119 required: false 120 choices: [ 121 'list', 122 'details', 123 'status', 124 'failure_reason', 125 'count', 126 'tags', 127 ] 128 default: 'list' 129 type: str 130author: Karen Cheng (@Etherdaemon) 131extends_documentation_fragment: 132- amazon.aws.aws 133- amazon.aws.ec2 134 135''' 136 137EXAMPLES = r''' 138# Simple example of listing all hosted zones 139- name: List all hosted zones 140 community.aws.route53_info: 141 query: hosted_zone 142 register: hosted_zones 143 144# Getting a count of hosted zones 145- name: Return a count of all hosted zones 146 community.aws.route53_info: 147 query: hosted_zone 148 hosted_zone_method: count 149 register: hosted_zone_count 150 151- name: List the first 20 resource record sets in a given hosted zone 152 community.aws.route53_info: 153 profile: account_name 154 query: record_sets 155 hosted_zone_id: ZZZ1111112222 156 max_items: 20 157 register: record_sets 158 159- name: List first 20 health checks 160 community.aws.route53_info: 161 query: health_check 162 health_check_method: list 163 max_items: 20 164 register: health_checks 165 166- name: Get health check last failure_reason 167 community.aws.route53_info: 168 query: health_check 169 health_check_method: failure_reason 170 health_check_id: 00000000-1111-2222-3333-12345678abcd 171 register: health_check_failure_reason 172 173- name: Retrieve reusable delegation set details 174 community.aws.route53_info: 175 query: reusable_delegation_set 176 delegation_set_id: delegation id 177 register: delegation_sets 178 179- name: setup of example for using next_marker 180 community.aws.route53_info: 181 query: hosted_zone 182 max_items: 1 183 register: first_info 184 185- name: example for using next_marker 186 community.aws.route53_info: 187 query: hosted_zone 188 next_marker: "{{ first_info.NextMarker }}" 189 max_items: 1 190 when: "{{ 'NextMarker' in first_info }}" 191 192- name: retrieve host entries starting with host1.workshop.test.io 193 block: 194 - name: grab zone id 195 community.aws.route53_zone: 196 zone: "test.io" 197 register: AWSINFO 198 199 - name: grab Route53 record information 200 community.aws.route53_info: 201 type: A 202 query: record_sets 203 hosted_zone_id: "{{ AWSINFO.zone_id }}" 204 start_record_name: "host1.workshop.test.io" 205 register: RECORDS 206''' 207 208try: 209 import botocore 210except ImportError: 211 pass # Handled by AnsibleAWSModule 212 213from ansible.module_utils._text import to_native 214 215from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule 216 217 218def get_hosted_zone(client, module): 219 params = dict() 220 221 if module.params.get('hosted_zone_id'): 222 params['Id'] = module.params.get('hosted_zone_id') 223 else: 224 module.fail_json(msg="Hosted Zone Id is required") 225 226 return client.get_hosted_zone(**params) 227 228 229def reusable_delegation_set_details(client, module): 230 params = dict() 231 if not module.params.get('delegation_set_id'): 232 if module.params.get('max_items'): 233 params['MaxItems'] = module.params.get('max_items') 234 235 if module.params.get('next_marker'): 236 params['Marker'] = module.params.get('next_marker') 237 238 results = client.list_reusable_delegation_sets(**params) 239 else: 240 params['DelegationSetId'] = module.params.get('delegation_set_id') 241 results = client.get_reusable_delegation_set(**params) 242 243 return results 244 245 246def list_hosted_zones(client, module): 247 params = dict() 248 249 if module.params.get('max_items'): 250 params['MaxItems'] = module.params.get('max_items') 251 252 if module.params.get('next_marker'): 253 params['Marker'] = module.params.get('next_marker') 254 255 if module.params.get('delegation_set_id'): 256 params['DelegationSetId'] = module.params.get('delegation_set_id') 257 258 paginator = client.get_paginator('list_hosted_zones') 259 zones = paginator.paginate(**params).build_full_result()['HostedZones'] 260 return { 261 "HostedZones": zones, 262 "list": zones, 263 } 264 265 266def list_hosted_zones_by_name(client, module): 267 params = dict() 268 269 if module.params.get('hosted_zone_id'): 270 params['HostedZoneId'] = module.params.get('hosted_zone_id') 271 272 if module.params.get('dns_name'): 273 params['DNSName'] = module.params.get('dns_name') 274 275 if module.params.get('max_items'): 276 params['MaxItems'] = module.params.get('max_items') 277 278 return client.list_hosted_zones_by_name(**params) 279 280 281def change_details(client, module): 282 params = dict() 283 284 if module.params.get('change_id'): 285 params['Id'] = module.params.get('change_id') 286 else: 287 module.fail_json(msg="change_id is required") 288 289 results = client.get_change(**params) 290 return results 291 292 293def checker_ip_range_details(client, module): 294 return client.get_checker_ip_ranges() 295 296 297def get_count(client, module): 298 if module.params.get('query') == 'health_check': 299 results = client.get_health_check_count() 300 else: 301 results = client.get_hosted_zone_count() 302 303 return results 304 305 306def get_health_check(client, module): 307 params = dict() 308 309 if not module.params.get('health_check_id'): 310 module.fail_json(msg="health_check_id is required") 311 else: 312 params['HealthCheckId'] = module.params.get('health_check_id') 313 314 if module.params.get('health_check_method') == 'details': 315 results = client.get_health_check(**params) 316 elif module.params.get('health_check_method') == 'failure_reason': 317 results = client.get_health_check_last_failure_reason(**params) 318 elif module.params.get('health_check_method') == 'status': 319 results = client.get_health_check_status(**params) 320 321 return results 322 323 324def get_resource_tags(client, module): 325 params = dict() 326 327 if module.params.get('resource_id'): 328 params['ResourceIds'] = module.params.get('resource_id') 329 else: 330 module.fail_json(msg="resource_id or resource_ids is required") 331 332 if module.params.get('query') == 'health_check': 333 params['ResourceType'] = 'healthcheck' 334 else: 335 params['ResourceType'] = 'hostedzone' 336 337 return client.list_tags_for_resources(**params) 338 339 340def list_health_checks(client, module): 341 params = dict() 342 343 if module.params.get('max_items'): 344 params['MaxItems'] = module.params.get('max_items') 345 346 if module.params.get('next_marker'): 347 params['Marker'] = module.params.get('next_marker') 348 349 paginator = client.get_paginator('list_health_checks') 350 health_checks = paginator.paginate(**params).build_full_result()['HealthChecks'] 351 return { 352 "HealthChecks": health_checks, 353 "list": health_checks, 354 } 355 356 357def record_sets_details(client, module): 358 params = dict() 359 360 if module.params.get('hosted_zone_id'): 361 params['HostedZoneId'] = module.params.get('hosted_zone_id') 362 else: 363 module.fail_json(msg="Hosted Zone Id is required") 364 365 if module.params.get('max_items'): 366 params['MaxItems'] = module.params.get('max_items') 367 368 if module.params.get('start_record_name'): 369 params['StartRecordName'] = module.params.get('start_record_name') 370 371 if module.params.get('type') and not module.params.get('start_record_name'): 372 module.fail_json(msg="start_record_name must be specified if type is set") 373 elif module.params.get('type'): 374 params['StartRecordType'] = module.params.get('type') 375 376 paginator = client.get_paginator('list_resource_record_sets') 377 record_sets = paginator.paginate(**params).build_full_result()['ResourceRecordSets'] 378 return { 379 "ResourceRecordSets": record_sets, 380 "list": record_sets, 381 } 382 383 384def health_check_details(client, module): 385 health_check_invocations = { 386 'list': list_health_checks, 387 'details': get_health_check, 388 'status': get_health_check, 389 'failure_reason': get_health_check, 390 'count': get_count, 391 'tags': get_resource_tags, 392 } 393 394 results = health_check_invocations[module.params.get('health_check_method')](client, module) 395 return results 396 397 398def hosted_zone_details(client, module): 399 hosted_zone_invocations = { 400 'details': get_hosted_zone, 401 'list': list_hosted_zones, 402 'list_by_name': list_hosted_zones_by_name, 403 'count': get_count, 404 'tags': get_resource_tags, 405 } 406 407 results = hosted_zone_invocations[module.params.get('hosted_zone_method')](client, module) 408 return results 409 410 411def main(): 412 argument_spec = dict( 413 query=dict(choices=[ 414 'change', 415 'checker_ip_range', 416 'health_check', 417 'hosted_zone', 418 'record_sets', 419 'reusable_delegation_set', 420 ], required=True), 421 change_id=dict(), 422 hosted_zone_id=dict(), 423 max_items=dict(), 424 next_marker=dict(), 425 delegation_set_id=dict(), 426 start_record_name=dict(), 427 type=dict(choices=[ 428 'A', 'CNAME', 'MX', 'AAAA', 'TXT', 'PTR', 'SRV', 'SPF', 'CAA', 'NS' 429 ]), 430 dns_name=dict(), 431 resource_id=dict(type='list', aliases=['resource_ids'], elements='str'), 432 health_check_id=dict(), 433 hosted_zone_method=dict(choices=[ 434 'details', 435 'list', 436 'list_by_name', 437 'count', 438 'tags' 439 ], default='list'), 440 health_check_method=dict(choices=[ 441 'list', 442 'details', 443 'status', 444 'failure_reason', 445 'count', 446 'tags', 447 ], default='list'), 448 ) 449 450 module = AnsibleAWSModule( 451 argument_spec=argument_spec, 452 supports_check_mode=True, 453 mutually_exclusive=[ 454 ['hosted_zone_method', 'health_check_method'], 455 ], 456 check_boto3=False, 457 ) 458 if module._name == 'route53_facts': 459 module.deprecate("The 'route53_facts' module has been renamed to 'route53_info'", date='2021-12-01', collection_name='community.aws') 460 461 try: 462 route53 = module.client('route53') 463 except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: 464 module.fail_json_aws(e, msg='Failed to connect to AWS') 465 466 invocations = { 467 'change': change_details, 468 'checker_ip_range': checker_ip_range_details, 469 'health_check': health_check_details, 470 'hosted_zone': hosted_zone_details, 471 'record_sets': record_sets_details, 472 'reusable_delegation_set': reusable_delegation_set_details, 473 } 474 475 results = dict(changed=False) 476 try: 477 results = invocations[module.params.get('query')](route53, module) 478 except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: 479 module.fail_json(msg=to_native(e)) 480 481 module.exit_json(**results) 482 483 484if __name__ == '__main__': 485 main() 486