diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-18 05:52:22 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-18 05:52:22 +0000 |
commit | 38b7c80217c4e72b1d8988eb1e60bb6e77334114 (patch) | |
tree | 356e9fd3762877d07cde52d21e77070aeff7e789 /ansible_collections/community/dns/plugins/modules | |
parent | Adding upstream version 7.7.0+dfsg. (diff) | |
download | ansible-38b7c80217c4e72b1d8988eb1e60bb6e77334114.tar.xz ansible-38b7c80217c4e72b1d8988eb1e60bb6e77334114.zip |
Adding upstream version 9.4.0+dfsg.upstream/9.4.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'ansible_collections/community/dns/plugins/modules')
16 files changed, 890 insertions, 107 deletions
diff --git a/ansible_collections/community/dns/plugins/modules/hetzner_dns_record.py b/ansible_collections/community/dns/plugins/modules/hetzner_dns_record.py index b17e0842c..23c873322 100644 --- a/ansible_collections/community/dns/plugins/modules/hetzner_dns_record.py +++ b/ansible_collections/community/dns/plugins/modules/hetzner_dns_record.py @@ -27,6 +27,7 @@ description: extends_documentation_fragment: - community.dns.hetzner - community.dns.hetzner.record_default_ttl + - community.dns.hetzner.record_notes - community.dns.hetzner.record_type_choices - community.dns.hetzner.zone_id_type - community.dns.module_record diff --git a/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_info.py b/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_info.py index 9d77a38d5..edf65aaca 100644 --- a/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_info.py +++ b/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_info.py @@ -37,6 +37,11 @@ attributes: author: - Markus Bergholz (@markuman) <markuman+spambelongstogoogle@gmail.com> - Felix Fontein (@felixfontein) + +seealso: + - module: community.dns.hetzner_dns_record_set_info + - plugin: community.dns.hetzner_dns_records + plugin_type: inventory ''' EXAMPLES = ''' @@ -58,7 +63,7 @@ records: description: The list of fetched records. type: list elements: dict - returned: success and I(what) is not C(single_record) + returned: success and O(what) is not V(single_record) contains: record: description: The record name. @@ -75,7 +80,7 @@ records: ttl: description: - The TTL. - - Will return C(none) if the zone's default TTL is used. + - Will return V(none) if the zone's default TTL is used. type: int sample: 3600 value: diff --git a/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_set.py b/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_set.py index 0766e6465..ce3ad313a 100644 --- a/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_set.py +++ b/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_set.py @@ -23,6 +23,7 @@ description: extends_documentation_fragment: - community.dns.hetzner - community.dns.hetzner.record_default_ttl + - community.dns.hetzner.record_notes - community.dns.hetzner.record_type_choices - community.dns.hetzner.zone_id_type - community.dns.module_record_set @@ -128,10 +129,9 @@ EXAMPLES = ''' zone: foo.com record: foo.com type: CAA - ttl: 3600 value: - - "128 issue letsencrypt.org" - - "128 iodef mailto:webmaster@foo.com" + - '128 issue "letsencrypt.org"' + - '128 iodef "mailto:webmaster@foo.com"' hetzner_token: access_token - name: Add an MX record diff --git a/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_set_info.py b/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_set_info.py index 5c70d1fb0..2df5d0f77 100644 --- a/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_set_info.py +++ b/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_set_info.py @@ -37,6 +37,11 @@ attributes: author: - Markus Bergholz (@markuman) <markuman+spambelongstogoogle@gmail.com> - Felix Fontein (@felixfontein) + +seealso: + - module: community.dns.hetzner_dns_record_info + - plugin: community.dns.hetzner_dns_records + plugin_type: inventory ''' EXAMPLES = ''' @@ -57,7 +62,7 @@ RETURN = ''' set: description: The fetched record set. Is empty if record set does not exist. type: dict - returned: success and I(what) is C(single_record) + returned: success and O(what) is V(single_record) contains: record: description: The record name. @@ -76,7 +81,7 @@ set: description: - The TTL. - If there are records in this set with different TTLs, the minimum of the TTLs will be presented here. - - Will return C(none) if the zone's default TTL is used. + - Will return V(none) if the zone's default TTL is used. type: int sample: 3600 ttls: @@ -109,7 +114,7 @@ sets: description: The list of fetched record sets. type: list elements: dict - returned: success and I(what) is not C(single_record) + returned: success and O(what) is not V(single_record) contains: record: description: The record name. @@ -128,7 +133,7 @@ sets: description: - The TTL. - If there are records in this set with different TTLs, the minimum of the TTLs will be presented here. - - Will return C(none) if the zone's default TTL is used. + - Will return V(none) if the zone's default TTL is used. type: int sample: 3600 ttls: diff --git a/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_sets.py b/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_sets.py index 52857186c..e7d515efe 100644 --- a/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_sets.py +++ b/ansible_collections/community/dns/plugins/modules/hetzner_dns_record_sets.py @@ -22,6 +22,7 @@ description: extends_documentation_fragment: - community.dns.hetzner + - community.dns.hetzner.record_notes - community.dns.hetzner.record_type_choices_record_sets_module - community.dns.hetzner.zone_id_type - community.dns.module_record_sets diff --git a/ansible_collections/community/dns/plugins/modules/hetzner_dns_zone_info.py b/ansible_collections/community/dns/plugins/modules/hetzner_dns_zone_info.py index 44cc88af5..9f4626e06 100644 --- a/ansible_collections/community/dns/plugins/modules/hetzner_dns_zone_info.py +++ b/ansible_collections/community/dns/plugins/modules/hetzner_dns_zone_info.py @@ -121,7 +121,7 @@ zone_info: status: description: - Status of the zone. - - Can be one of C(verified), C(failed) and C(pending). + - Can be one of V(verified), V(failed) and V(pending). type: str sample: verified # choices: diff --git a/ansible_collections/community/dns/plugins/modules/hosttech_dns_record.py b/ansible_collections/community/dns/plugins/modules/hosttech_dns_record.py index 0756b6a4c..1473f6624 100644 --- a/ansible_collections/community/dns/plugins/modules/hosttech_dns_record.py +++ b/ansible_collections/community/dns/plugins/modules/hosttech_dns_record.py @@ -28,6 +28,7 @@ description: extends_documentation_fragment: - community.dns.hosttech - community.dns.hosttech.record_default_ttl + - community.dns.hosttech.record_notes - community.dns.hosttech.record_type_choices - community.dns.hosttech.zone_id_type - community.dns.module_record diff --git a/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_info.py b/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_info.py index 84ee8e3b2..71004464e 100644 --- a/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_info.py +++ b/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_info.py @@ -36,6 +36,11 @@ attributes: author: - Felix Fontein (@felixfontein) + +seealso: + - module: community.dns.hosttech_dns_record_set_info + - plugin: community.dns.hosttech_dns_records + plugin_type: inventory ''' EXAMPLES = ''' @@ -57,7 +62,7 @@ records: description: The list of fetched records. type: list elements: dict - returned: success and I(what) is not C(single_record) + returned: success and O(what) is not V(single_record) contains: record: description: The record name. diff --git a/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_set.py b/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_set.py index d16c82ad7..7da02aec4 100644 --- a/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_set.py +++ b/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_set.py @@ -24,6 +24,7 @@ description: extends_documentation_fragment: - community.dns.hosttech - community.dns.hosttech.record_default_ttl + - community.dns.hosttech.record_notes - community.dns.hosttech.record_type_choices - community.dns.hosttech.zone_id_type - community.dns.module_record_set @@ -128,8 +129,8 @@ EXAMPLES = ''' type: CAA ttl: 3600 value: - - "128 issue letsencrypt.org" - - "128 iodef mailto:webmaster@foo.com" + - '128 issue "letsencrypt.org"' + - '128 iodef "mailto:webmaster@foo.com"' hosttech_token: access_token - name: Add an MX record diff --git a/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_set_info.py b/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_set_info.py index 5b7c576b8..60a54809d 100644 --- a/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_set_info.py +++ b/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_set_info.py @@ -19,7 +19,7 @@ version_added: 0.1.0 description: - "Retrieves DNS record sets in Hosttech DNS service." - - This module was renamed from C(community.dns.hosttech_dns_record_info) to C(community.dns.hosttech_dns_record_set_info) + - This module was renamed from C(community.dns.hosttech_dns_record_info) to M(community.dns.hosttech_dns_record_set_info) in community.dns 2.0.0. extends_documentation_fragment: @@ -38,6 +38,11 @@ attributes: author: - Felix Fontein (@felixfontein) + +seealso: + - module: community.dns.hosttech_dns_record_info + - plugin: community.dns.hosttech_dns_records + plugin_type: inventory ''' EXAMPLES = ''' @@ -58,7 +63,7 @@ RETURN = ''' set: description: The fetched record set. Is empty if record set does not exist. type: dict - returned: success and I(what) is C(single_record) + returned: success and O(what=single_record) contains: record: description: The record name. @@ -109,7 +114,7 @@ sets: description: The list of fetched record sets. type: list elements: dict - returned: success and I(what) is not C(single_record) + returned: success and O(what=single_record) contains: record: description: The record name. diff --git a/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_sets.py b/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_sets.py index c985779ca..583cfa58e 100644 --- a/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_sets.py +++ b/ansible_collections/community/dns/plugins/modules/hosttech_dns_record_sets.py @@ -23,6 +23,7 @@ description: extends_documentation_fragment: - community.dns.hosttech + - community.dns.hosttech.record_notes - community.dns.hosttech.record_type_choices_record_sets_module - community.dns.hosttech.zone_id_type - community.dns.module_record_sets diff --git a/ansible_collections/community/dns/plugins/modules/hosttech_dns_records.py b/ansible_collections/community/dns/plugins/modules/hosttech_dns_records.py index c985779ca..583cfa58e 100644 --- a/ansible_collections/community/dns/plugins/modules/hosttech_dns_records.py +++ b/ansible_collections/community/dns/plugins/modules/hosttech_dns_records.py @@ -23,6 +23,7 @@ description: extends_documentation_fragment: - community.dns.hosttech + - community.dns.hosttech.record_notes - community.dns.hosttech.record_type_choices_record_sets_module - community.dns.hosttech.zone_id_type - community.dns.module_record_sets diff --git a/ansible_collections/community/dns/plugins/modules/hosttech_dns_zone_info.py b/ansible_collections/community/dns/plugins/modules/hosttech_dns_zone_info.py index 6621893a7..d364d0694 100644 --- a/ansible_collections/community/dns/plugins/modules/hosttech_dns_zone_info.py +++ b/ansible_collections/community/dns/plugins/modules/hosttech_dns_zone_info.py @@ -80,22 +80,22 @@ zone_info: description: - Whether DNSSEC is enabled for the zone or not. type: bool - returned: When I(hosttech_token) has been specified. + returned: When O(hosttech_token) has been specified. dnssec_email: description: - The email address contacted when the DNSSEC key is changed. - - Is C(none) if DNSSEC is not enabled. + - Is V(none) if DNSSEC is not enabled. type: str - returned: When I(hosttech_token) has been specified. + returned: When O(hosttech_token) has been specified. ds_records: description: - The DS records. - See L(Section 5 of RFC 4034,https://datatracker.ietf.org/doc/html/rfc4034#section-5) and L(Section 2.1 of RFC 4034,https://datatracker.ietf.org/doc/html/rfc4034#section-2.1) for details. - - Is C(none) if DNSSEC is not enabled. + - Is V(none) if DNSSEC is not enabled. type: list elements: dict - returned: When I(hosttech_token) has been specified. + returned: When O(hosttech_token) has been specified. contains: algorithm: description: diff --git a/ansible_collections/community/dns/plugins/modules/nameserver_info.py b/ansible_collections/community/dns/plugins/modules/nameserver_info.py new file mode 100644 index 000000000..62ba30961 --- /dev/null +++ b/ansible_collections/community/dns/plugins/modules/nameserver_info.py @@ -0,0 +1,168 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright (c) 2022, Felix Fontein <felix@fontein.de> +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: nameserver_info +short_description: Look up nameservers for a DNS name +version_added: 2.6.0 +description: + - Retrieve all nameservers that are responsible for a DNS name. +extends_documentation_fragment: + - community.dns.attributes + - community.dns.attributes.info_module +author: + - Felix Fontein (@felixfontein) +options: + name: + description: + - A list of DNS names whose nameservers to retrieve. + required: true + type: list + elements: str + resolve_addresses: + description: + - Whether to resolve the nameserver names to IP addresses. + type: bool + default: false + query_retry: + description: + - Number of retries for DNS query timeouts. + type: int + default: 3 + query_timeout: + description: + - Timeout per DNS query in seconds. + type: float + default: 10 + always_ask_default_resolver: + description: + - When set to V(true) (default), will use the default resolver to find the authoritative nameservers + of a subzone. See O(server) for how to configure the default resolver. + - When set to V(false), will use the authoritative nameservers of the parent zone to find the + authoritative nameservers of a subzone. This only makes sense when the nameservers were recently + changed and have not yet propagated. + type: bool + default: true + servfail_retries: + description: + - How often to retry on SERVFAIL errors. + type: int + default: 0 + server: + description: + - The DNS server(s) to use to look up the result. Must be a list of one or more IP addresses. + - By default, the system's standard resolver is used. + type: list + elements: str + version_added: 2.7.0 +requirements: + - dnspython >= 1.15.0 (maybe older versions also work) +''' + +EXAMPLES = r''' +- name: Retrieve name servers of two DNS names + community.dns.nameserver_info: + name: + - www.example.com + - example.org + register: result + +- name: Show nameservers for www.example.com + ansible.builtin.debug: + msg: '{{ result.results[0].nameserver }}' +''' + +RETURN = r''' +results: + description: + - Information on the nameservers for every DNS name provided in O(name). + returned: always + type: list + elements: dict + contains: + name: + description: + - The DNS name this entry is for. + returned: always + type: str + sample: www.example.com + nameservers: + description: + - A list of nameservers for this DNS name. + returned: success + type: list + elements: str + sample: + - ns1.example.com + - ns2.example.com + sample: + - name: www.example.com + nameservers: + - ns1.example.com + - ns2.example.com + - name: example.org + nameservers: + - ns1.example.org + - ns2.example.org + - ns3.example.org +''' + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.dns.plugins.module_utils.resolver import ( + ResolveDirectlyFromNameServers, + assert_requirements_present, + guarded_run, +) + + +def main(): + module = AnsibleModule( + argument_spec=dict( + name=dict(required=True, type='list', elements='str'), + resolve_addresses=dict(type='bool', default=False), + query_retry=dict(type='int', default=3), + query_timeout=dict(type='float', default=10), + always_ask_default_resolver=dict(type='bool', default=True), + servfail_retries=dict(type='int', default=0), + server=dict(type='list', elements='str'), + ), + supports_check_mode=True, + ) + assert_requirements_present(module) + + names = module.params['name'] + resolve_addresses = module.params['resolve_addresses'] + + resolver = ResolveDirectlyFromNameServers( + timeout=module.params['query_timeout'], + timeout_retries=module.params['query_retry'], + servfail_retries=module.params['servfail_retries'], + always_ask_default_resolver=module.params['always_ask_default_resolver'], + server_addresses=module.params['server'], + ) + results = [None] * len(names) + for index, name in enumerate(names): + results[index] = { + 'name': name, + } + + def f(): + for index, name in enumerate(names): + results[index]['nameservers'] = sorted(resolver.resolve_nameservers(name, resolve_addresses=resolve_addresses)) + + guarded_run(f, module, generate_additional_results=lambda: dict(results=results)) + module.exit_json(results=results) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/dns/plugins/modules/nameserver_record_info.py b/ansible_collections/community/dns/plugins/modules/nameserver_record_info.py new file mode 100644 index 000000000..f9374acae --- /dev/null +++ b/ansible_collections/community/dns/plugins/modules/nameserver_record_info.py @@ -0,0 +1,568 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright (c) 2022, Felix Fontein <felix@fontein.de> +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = r''' +--- +module: nameserver_record_info +short_description: Look up all records of a type from all nameservers for a DNS name +version_added: 2.6.0 +description: + - Given a DNS name and a record type, will retrieve all nameservers that are responsible for + this DNS name, and from them all records for this name of the given type. +extends_documentation_fragment: + - community.dns.attributes + - community.dns.attributes.info_module +author: + - Felix Fontein (@felixfontein) +options: + name: + description: + - A list of DNS names whose nameservers to retrieve. + required: true + type: list + elements: str + type: + description: + - The record type to retrieve. + required: true + type: str + choices: + - A + - ALL + - AAAA + - CAA + - CNAME + - DNAME + - DNSKEY + - DS + - HINFO + - LOC + - MX + - NAPTR + - NS + - NSEC + - NSEC3 + - NSEC3PARAM + - PTR + - RP + - RRSIG + - SOA + - SPF + - SRV + - SSHFP + - TLSA + - TXT + query_retry: + description: + - Number of retries for DNS query timeouts. + type: int + default: 3 + query_timeout: + description: + - Timeout per DNS query in seconds. + type: float + default: 10 + always_ask_default_resolver: + description: + - When set to V(true) (default), will use the default resolver to find the authoritative nameservers + of a subzone. See O(server) for how to configure the default resolver. + - When set to V(false), will use the authoritative nameservers of the parent zone to find the + authoritative nameservers of a subzone. This only makes sense when the nameservers were recently + changed and have not yet propagated. + type: bool + default: true + servfail_retries: + description: + - How often to retry on SERVFAIL errors. + type: int + default: 0 + server: + description: + - The DNS server(s) to use to look up the result. Must be a list of one or more IP addresses. + - By default, the system's standard resolver is used. + type: list + elements: str + version_added: 2.7.0 +requirements: + - dnspython >= 1.15.0 (maybe older versions also work) +notes: + - dnspython before 2.0.0 does not correctly support (un-)escaping UTF-8 in TXT-like records. This can + result in wrongly decoded TXT records. Please use dnspython 2.0.0 or later to fix this issue; see also + U(https://github.com/rthalley/dnspython/issues/321). + Unfortunately dnspython 2.0.0 requires Python 3.6 or newer. +''' + +EXAMPLES = r''' +- name: Retrieve TXT values from all nameservers for two DNS names + community.dns.nameserver_record_info: + name: + - www.example.com + - example.org + type: TXT + register: result + +- name: Show TXT values for www.example.com for all nameservers + ansible.builtin.debug: + msg: '{{ result.results[0].result }}' +''' + +RETURN = r''' +results: + description: + - Information on the records for every DNS name provided in O(name). + returned: always + type: list + elements: dict + contains: + name: + description: + - The DNS name this entry is for. + returned: always + type: str + sample: www.example.com + result: + description: + - A list of values per nameserver. + returned: success + type: list + elements: dict + sample: + - nameserver: ns1.example.com + values: + - X + - nameserver: ns2.example.com + values: + - X + contains: + nameserver: + description: + - The nameserver. + returned: success + type: str + sample: ns1.example.com + values: + description: + - The records of type O(type). + - Depending on O(type), different fields are returned. + - For O(type=TXT) and O(type=SPF), also the concatenated value is returned as RV(results[].result[].values[].value). + returned: success + type: list + elements: dict + sample: + - address: 127.0.0.1 + contains: + address: + description: + - A IPv4 respectively IPv6 address. + type: str + returned: if O(type=A) or O(type=AAAA) + algorithm: + description: + - The algorithm ID. + type: int + returned: if O(type=DNSKEY) or O(type=DS) or O(type=NSEC3) or O(type=NSEC3PARAM) or O(type=RRSIG) or O(type=SSHFP) + altitude: + description: + - The altitude. + type: float + returned: if O(type=LOC) + cert: + description: + - The certificate. + type: str + returned: if O(type=TLSA) + cpu: + description: + - The CPU. + type: str + returned: if O(type=HINFO) + digest: + description: + - The digest. + type: str + returned: if O(type=DS) + digest_type: + description: + - The digest's type. + type: int + returned: if O(type=DS) + exchange: + description: + - The exchange server. + type: str + returned: if O(type=MX) + expiration: + description: + - The expiration Unix timestamp. + type: int + returned: if O(type=RRSIG) + expire: + description: + - Number of seconds after which secondary name servers should stop answering request + for this zone if the main name server does not respond. + type: int + returned: if O(type=SOA) + fingerprint: + description: + - The fingerprint. + type: str + returned: if O(type=SSHFP) + flags: + description: + - Flags. + - This is actually of type C(string) for O(type=NAPTR). + type: int + returned: if O(type=CAA) or O(type=DNSKEY) or O(type=NAPTR) or O(type=NSEC3) or O(type=NSEC3PARAM) + fp_type: + description: + - The fingerprint's type. + type: int + returned: if O(type=SSHFP) + horizontal_precision: + description: + - The horizontal precision of the location. + type: float + returned: if O(type=LOC) + inception: + description: + - The inception Unix timestamp. + type: int + returned: if O(type=RRSIG) + iterations: + description: + - The number of iterations. + type: int + returned: if O(type=NSEC3) or O(type=NSEC3PARAM) + key: + description: + - The key. + type: str + returned: if O(type=DNSKEY) + key_tag: + description: + - The key's tag. + type: int + returned: if O(type=DS) or O(type=RRSIG) + labels: + description: + - The labels. + type: int + returned: if O(type=RRSIG) + latitude: + description: + - The location's latitude. + type: list + elements: int + returned: if O(type=LOC) + longitude: + description: + - The location's longitude. + type: list + elements: int + returned: if O(type=LOC) + mbox: + description: + - The mbox. + type: str + returned: if O(type=RP) + minimum: + description: + - Used to calculate the TTL for purposes of negative caching. + type: int + returned: if O(type=SOA) + mname: + description: + - Primary main name server for this zone. + type: str + returned: if O(type=SOA) + mtype: + description: + - The mtype. + type: int + returned: if O(type=TLSA) + next: + description: + - The next value. + type: str + returned: if O(type=NSEC) or O(type=NSEC3) + order: + description: + - The order value. + type: int + returned: if O(type=NAPTR) + original_ttl: + description: + - The original TTL. + type: int + returned: if O(type=RRSIG) + os: + description: + - The operating system. + type: str + returned: if O(type=HINFO) + port: + description: + - The port. + type: int + returned: if O(type=SRV) + preference: + description: + - The preference value for this record. + type: int + returned: if O(type=MX) or O(type=NAPTR) + priority: + description: + - The priority value for this record. + type: int + returned: if O(type=SRV) + protocol: + description: + - The protocol. + type: int + returned: if O(type=DNSKEY) + refresh: + description: + - Number of seconds after which secondary name servers should query the main + name server for the SOA record to detect zone changes. + type: int + returned: if O(type=SOA) + regexp: + description: + - A regular expression. + type: str + returned: if O(type=NAPTR) + replacement: + description: + - The replacement. + type: str + returned: if O(type=NAPTR) + retry: + description: + - Number of seconds after which secondary name servers should retry to request + the serial number from the main name server if the main name server does not respond. + type: int + returned: if O(type=SOA) + rname: + description: + - E-mail address of the administrator responsible for this zone. + type: str + returned: if O(type=SOA) + salt: + description: + - The salt. + type: str + returned: if O(type=NSEC3) or O(type=NSEC3PARAM) + selector: + description: + - The selector. + type: int + returned: if O(type=TLSA) + serial: + description: + - Serial number for this zone. + type: int + returned: if O(type=SOA) + service: + description: + - The service. + type: str + returned: if O(type=NAPTR) + signature: + description: + - The signature. + type: str + returned: if O(type=RRSIG) + signer: + description: + - The signer. + type: str + returned: if O(type=RRSIG) + size: + description: + - The size of the location. + type: float + returned: if O(type=LOC) + strings: + description: + - List of strings for this record. + - See RV(results[].result[].values[].value) for the concatenated result. + type: list + elements: str + returned: if O(type=SPF) or O(type=TXT) + tag: + description: + - The tag. + type: str + returned: if O(type=CAA) + target: + description: + - The target. + type: str + returned: if O(type=CNAME) or O(type=DNAME) or O(type=NS) or O(type=PTR) or O(type=SRV) + txt: + description: + - The TXT value. + type: str + returned: if O(type=RP) + type_covered: + description: + - The type covered. + type: str + returned: if O(type=RRSIG) + usage: + description: + - The usage flag. + type: int + returned: if O(type=TLSA) + value: + description: + - The value. + - For O(type=SPF) or O(type=TXT), this is the concatenation of RV(results[].result[].values[].strings). + type: str + returned: if O(type=CAA) or O(type=SPF) or O(type=TXT) + vertical_precision: + description: + - The vertical precision of the location. + type: float + returned: if O(type=LOC) + weight: + description: + - The service's weight. + type: int + returned: if O(type=SRV) + windows: + description: + - The windows. + type: str + returned: if O(type=NSEC) or O(type=NSEC3) + sample: + - name: www.example.com + result: + - nameserver: ns1.example.com + values: + - address: 127.0.0.1 + - nameserver: ns2.example.com + values: + - address: 127.0.0.1 + - name: example.org + result: + - nameserver: ns1.example.org + values: + - address: 127.0.0.1 + - address: 127.0.0.2 + - nameserver: ns2.example.org + values: + - address: 127.0.0.2 + - nameserver: ns3.example.org + values: + - address: 127.0.0.1 +''' + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.community.dns.plugins.module_utils.resolver import ( + ResolveDirectlyFromNameServers, + assert_requirements_present, + guarded_run, +) + +from ansible_collections.community.dns.plugins.module_utils.dnspython_records import ( + NAME_TO_RDTYPE, + convert_rdata_to_dict, +) + + +def main(): + module = AnsibleModule( + argument_spec=dict( + name=dict(required=True, type='list', elements='str'), + type=dict( + required=True, + type='str', + choices=[ + 'A', + 'ALL', + 'AAAA', + 'CAA', + 'CNAME', + 'DNAME', + 'DNSKEY', + 'DS', + 'HINFO', + 'LOC', + 'MX', + 'NAPTR', + 'NS', + 'NSEC', + 'NSEC3', + 'NSEC3PARAM', + 'PTR', + 'RP', + 'RRSIG', + 'SOA', + 'SPF', + 'SRV', + 'SSHFP', + 'TLSA', + 'TXT', + ], + ), + query_retry=dict(type='int', default=3), + query_timeout=dict(type='float', default=10), + always_ask_default_resolver=dict(type='bool', default=True), + servfail_retries=dict(type='int', default=0), + server=dict(type='list', elements='str'), + ), + supports_check_mode=True, + ) + assert_requirements_present(module) + + names = module.params['name'] + record_type = module.params['type'] + + resolver = ResolveDirectlyFromNameServers( + timeout=module.params['query_timeout'], + timeout_retries=module.params['query_retry'], + servfail_retries=module.params['servfail_retries'], + always_ask_default_resolver=module.params['always_ask_default_resolver'], + server_addresses=module.params['server'], + ) + results = [None] * len(names) + for index, name in enumerate(names): + results[index] = { + 'name': name, + } + + rdtype = NAME_TO_RDTYPE[record_type] + + def f(): + for index, name in enumerate(names): + result = [] + results[index]['result'] = result + records_for_nameservers = resolver.resolve(name, rdtype=rdtype) + for nameserver, records in records_for_nameservers.items(): + ns_result = { + 'nameserver': nameserver, + } + result.append(ns_result) + values = [] + if records is not None: + for data in records: + values.append(convert_rdata_to_dict(data)) + ns_result['values'] = values + result.sort(key=lambda v: v['nameserver']) + + guarded_run(f, module, generate_additional_results=lambda: dict(results=results)) + module.exit_json(results=results) + + +if __name__ == "__main__": + main() diff --git a/ansible_collections/community/dns/plugins/modules/wait_for_txt.py b/ansible_collections/community/dns/plugins/modules/wait_for_txt.py index 1a09c5ed6..7252ae883 100644 --- a/ansible_collections/community/dns/plugins/modules/wait_for_txt.py +++ b/ansible_collections/community/dns/plugins/modules/wait_for_txt.py @@ -40,7 +40,7 @@ options: suboptions: name: description: - - A DNS name, like C(www.example.com). + - A DNS name, like V(www.example.com). type: str required: true values: @@ -51,17 +51,17 @@ options: required: true mode: description: - - Comparison modes for the values in I(values). - - If C(subset), I(values) should be a (not necessarily proper) subset of the TXT values set for + - Comparison modes for the values in O(records[].values). + - If V(subset), O(records[].values) should be a (not necessarily proper) subset of the TXT values set for the DNS name. - - If C(superset), I(values) should be a (not necessarily proper) superset of the TXT values set + - If V(superset), O(records[].values) should be a (not necessarily proper) superset of the TXT values set for the DNS name. This includes the case that no TXT entries are set. - - If C(superset_not_empty), I(values) should be a (not necessarily proper) superset of the TXT + - If V(superset_not_empty), O(records[].values) should be a (not necessarily proper) superset of the TXT values set for the DNS name, assuming at least one TXT record is present. - - If C(equals), I(values) should be the same set of strings as the TXT values for the DNS name + - If V(equals), O(records[].values) should be the same set of strings as the TXT values for the DNS name (up to order). - - If C(equals_ordered), I(values) should be the same ordered list of strings as the TXT values + - If V(equals_ordered), O(records[].values) should be the same ordered list of strings as the TXT values for the DNS name. type: str default: subset @@ -93,13 +93,26 @@ options: default: 10 always_ask_default_resolver: description: - - When set to C(true) (default), will use the default resolver to find the authoritative nameservers - of a subzone. - - When set to C(false), will use the authoritative nameservers of the parent zone to find the + - When set to V(true) (default), will use the default resolver to find the authoritative nameservers + of a subzone. See O(server) for how to configure the default resolver. + - When set to V(false), will use the authoritative nameservers of the parent zone to find the authoritative nameservers of a subzone. This only makes sense when the nameservers were recently - changed and haven't propagated. + changed and have not yet propagated. type: bool default: true + servfail_retries: + description: + - How often to retry on SERVFAIL errors. + type: int + default: 0 + version_added: 2.6.0 + server: + description: + - The DNS server(s) to use to look up the result. Must be a list of one or more IP addresses. + - By default, the system's standard resolver is used. + type: list + elements: str + version_added: 2.7.0 requirements: - dnspython >= 1.15.0 (maybe older versions also work) ''' @@ -124,7 +137,7 @@ RETURN = r''' records: description: - Results on the TXT records queried. - - The entries are in a 1:1 correspondence to the entries of the I(records) parameter, + - The entries are in a 1:1 correspondence to the entries of the O(records) parameter, in exactly the same order. returned: always type: list @@ -180,7 +193,6 @@ completed: ''' import time -import traceback try: from time import monotonic @@ -188,16 +200,15 @@ except ImportError: from time import clock as monotonic from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.common.text.converters import to_native, to_text +from ansible.module_utils.common.text.converters import to_text from ansible_collections.community.dns.plugins.module_utils.resolver import ( ResolveDirectlyFromNameServers, - ResolverError, assert_requirements_present, + guarded_run, ) try: - import dns.exception import dns.rdatatype except ImportError: pass # handled in assert_requirements_present() @@ -238,97 +249,107 @@ def validate_check(record_values, expected_values, comparison_mode): raise Exception('Internal error!') -def main(): - module = AnsibleModule( - argument_spec=dict( - records=dict(required=True, type='list', elements='dict', options=dict( - name=dict(required=True, type='str'), - values=dict(required=True, type='list', elements='str'), - mode=dict(type='str', default='subset', choices=['subset', 'superset', 'superset_not_empty', 'equals', 'equals_ordered']), - )), - query_retry=dict(type='int', default=3), - query_timeout=dict(type='float', default=10), - timeout=dict(type='float'), - max_sleep=dict(type='float', default=10), - always_ask_default_resolver=dict(type='bool', default=True), - ), - supports_check_mode=True, - ) - assert_requirements_present(module) +class Waiter(object): + def __init__(self, module): + self.module = module + + self.resolver = ResolveDirectlyFromNameServers( + timeout=self.module.params['query_timeout'], + timeout_retries=self.module.params['query_retry'], + servfail_retries=self.module.params['servfail_retries'], + always_ask_default_resolver=self.module.params['always_ask_default_resolver'], + server_addresses=self.module.params['server'], + ) + self.records = self.module.params['records'] + self.timeout = self.module.params['timeout'] + self.max_sleep = self.module.params['max_sleep'] + + self.results = [None] * len(self.records) + for index in range(len(self.records)): + self.results[index] = { + 'name': self.records[index]['name'], + 'done': False, + 'check_count': 0, + } + self.finished_checks = 0 + + def _run(self): + self.start_time = monotonic() - resolver = ResolveDirectlyFromNameServers( - timeout=module.params['query_timeout'], - timeout_retries=module.params['query_retry'], - always_ask_default_resolver=module.params['always_ask_default_resolver'], - ) - records = module.params['records'] - timeout = module.params['timeout'] - max_sleep = module.params['max_sleep'] - - results = [None] * len(records) - for index in range(len(records)): - results[index] = { - 'name': records[index]['name'], - 'done': False, - 'check_count': 0, - } - finished_checks = 0 - - start_time = monotonic() - try: step = 0 while True: has_timeout = False - if timeout is not None: - expired = monotonic() - start_time - has_timeout = expired > timeout + if self.timeout is not None: + expired = monotonic() - self.start_time + has_timeout = expired > self.timeout done = True - for index, record in enumerate(records): - if results[index]['done']: + for index, record in enumerate(self.records): + if self.results[index]['done']: continue - txts = lookup(resolver, record['name']) - results[index]['values'] = txts - results[index]['check_count'] += 1 + txts = lookup(self.resolver, record['name']) + self.results[index]['values'] = txts + self.results[index]['check_count'] += 1 if txts and all(validate_check(txt, record['values'], record['mode']) for txt in txts.values()): - results[index]['done'] = True - finished_checks += 1 + self.results[index]['done'] = True + self.finished_checks += 1 else: done = False if done: - module.exit_json( + self.module.exit_json( msg='All checks passed', - records=results, - completed=finished_checks) + **self._generate_additional_results() + ) if has_timeout: - module.fail_json( - msg='Timeout ({0} out of {1} check(s) passed).'.format(finished_checks, len(records)), - records=results, - completed=finished_checks) + self.module.fail_json( + msg='Timeout ({0} out of {1} check(s) passed).'.format(self.finished_checks, len(self.records)), + **self._generate_additional_results() + ) # Simple quadratic sleep with maximum wait of max_sleep seconds - wait = min(2 + step * 0.5, max_sleep) - if timeout is not None: + wait = min(2 + step * 0.5, self.max_sleep) + if self.timeout is not None: # Make sure we do not exceed the timeout by much by waiting - expired = monotonic() - start_time - wait = max(min(wait, timeout - expired + 0.1), 0.1) + expired = monotonic() - self.start_time + wait = max(min(wait, self.timeout - expired + 0.1), 0.1) time.sleep(wait) step += 1 - except ResolverError as e: - module.fail_json( - msg='Unexpected resolving error: {0}'.format(to_native(e)), - records=results, - completed=finished_checks, - exception=traceback.format_exc()) - except dns.exception.DNSException as e: - module.fail_json( - msg='Unexpected DNS error: {0}'.format(to_native(e)), - records=results, - completed=finished_checks, - exception=traceback.format_exc()) + + def _generate_additional_results(self): + return dict( + records=self.results, + completed=self.finished_checks, + ) + + def run(self): + guarded_run(self._run, self.module, generate_additional_results=self._generate_additional_results) + + +def main(): + module = AnsibleModule( + argument_spec=dict( + records=dict(required=True, type='list', elements='dict', options=dict( + name=dict(required=True, type='str'), + values=dict(required=True, type='list', elements='str'), + mode=dict(type='str', default='subset', choices=['subset', 'superset', 'superset_not_empty', 'equals', 'equals_ordered']), + )), + query_retry=dict(type='int', default=3), + query_timeout=dict(type='float', default=10), + timeout=dict(type='float'), + max_sleep=dict(type='float', default=10), + always_ask_default_resolver=dict(type='bool', default=True), + servfail_retries=dict(type='int', default=0), + server=dict(type='list', elements='str'), + ), + supports_check_mode=True, + ) + assert_requirements_present(module) + + waiter = Waiter(module) + waiter.run() if __name__ == "__main__": |