diff --git a/tripleo_ipa/ansible_plugins/filter/dns_data.py b/tripleo_ipa/ansible_plugins/filter/dns_data.py new file mode 100644 index 0000000..869c98d --- /dev/null +++ b/tripleo_ipa/ansible_plugins/filter/dns_data.py @@ -0,0 +1,107 @@ +#!/usr/bin/python +# +# Copyright 2023 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from ipaddress import ip_address, IPv4Address + + +def _parse_host_entry(entry): + if len(entry.split()) >= 2: + value = entry.split()[0] + try: + ip = ip_address(value) + record_type = 'A' if (type(ip) is IPv4Address) else 'AAAA' + except ValueError: + return "", "", "Invalid", "" + + host = entry.split()[1] + host_split = host.split('.', 1) + if (len(host_split) == 2): + name = host_split[0] + zone = host_split[1] + return value, name, record_type, zone + return "", "", "Invalid", "" + + +def _parse_hosts_entries(hosts_entries, cdomain): + """Extract parameters to add dns entries from hosts_data + + --- + :param hosts_data: is a list of strings, with each string being a line + in the /etc/hosts file. + + :returns: two lists. a list of dicts containing the parameters needed for + ansible-freeipa dnsrecord to add, and a list of dicts containing + dnszones to add. + """ + zones = set() + records = list() + ips = set() + for host_entry in hosts_entries: + value, name, record_type, zone = _parse_host_entry(host_entry) + + print("cdomain is " + cdomain) + if record_type == "Invalid": + continue + + if not zone.endswith(cdomain): + print("zone " + zone + " not added") + continue + + # add forward zone + if zone not in zones: + print("adding " + zone) + zones.add(zone) + + # add ips to get reverse zones + if value not in ips: + ips.add(value) + + # add forward record + if (record_type == "A"): + record = {"record_name": name, + "zone_name": zone, + "record_type": record_type, + "create_reverse": "true", + "a_rec": value} + else: + record = {"record_name": name, + "zone_name": zone, + "record_type": record_type, + "create_reverse": "true", + "aaaa_rec": value} + records.append(record) + + return [list(zones), list(ips), records] + + +def get_dns_zones(hosts_entries, cdomain): + return _parse_hosts_entries(hosts_entries, cdomain)[0] + + +def get_ips(hosts_entries, cdomain): + return _parse_hosts_entries(hosts_entries, cdomain)[1] + + +def get_dns_entries(hosts_entries, cdomain): + return _parse_hosts_entries(hosts_entries, cdomain)[2] + + +class FilterModule(object): + def filters(self): + return { + 'get_dns_entries': get_dns_entries, + 'get_ips': get_ips, + 'get_dns_zones': get_dns_zones} diff --git a/tripleo_ipa/molecule/default/tests/test_default.py b/tripleo_ipa/molecule/default/tests/test_default.py index bc0fe82..9501264 100644 --- a/tripleo_ipa/molecule/default/tests/test_default.py +++ b/tripleo_ipa/molecule/default/tests/test_default.py @@ -197,7 +197,7 @@ def test_dns(host, ip, name): result = host.check_output( 'ipa dnsrecord-find {} --name={}'.format( zone_name, record_name)) - assert 'record: {}'.format(ip) in result + assert ip in result @pytest.mark.parametrize('ip, name', [ @@ -234,12 +234,15 @@ def test_dns_absent(host, ip, name): ('172.16.0.195', 'overcloud-novacompute-0.tenant'), ('192.168.24.128', 'overcloud-novacompute-0.ctlplane')]) def test_reverse_dns(host, ip, name): - reverse = ipaddress.ip_address(ip).reverse_pointer - record, zone = reverse.split('.', 1) + split_char = '.' + addr = ipaddress.ip_address(ip) + k = 1 if (addr.version == 4) else 16 + temp = addr.reverse_pointer.split(split_char) + record, zone = split_char.join(temp[:k]), split_char.join(temp[k:]) result = host.check_output( 'ipa dnsrecord-find {} --name={}'.format( zone, record)) - assert 'record: {}'.format(name) in result + assert name in result @pytest.mark.parametrize('ip, name', [ diff --git a/tripleo_ipa/molecule/deregister/prepare.yml b/tripleo_ipa/molecule/deregister/prepare.yml index e9251d9..ef7979c 100644 --- a/tripleo_ipa/molecule/deregister/prepare.yml +++ b/tripleo_ipa/molecule/deregister/prepare.yml @@ -74,3 +74,22 @@ search_regex: "(INFO The ipa-server-install command was successful|ERROR The ipa-server-install command failed)" timeout: 900 become: true + + - name: Wait for FreeIPA LDAP port to open + wait_for: + host=10.88.0.22 + port=389 + delay=1 + timeout=300 + ignore_errors: true + + - name: Check the status of ipactl to make sure all services are started + command: "sudo podman exec freeipa-server-container ipactl status" + retries: 10 + delay: 3 + register: result + until: result.rc == 0 + + - name: Print ipactl status + debug: + msg: "{{ result.stdout }}" diff --git a/tripleo_ipa/roles/tripleo_ipa_dns/tasks/dns.yaml b/tripleo_ipa/roles/tripleo_ipa_dns/tasks/dns.yaml deleted file mode 100644 index 1339753..0000000 --- a/tripleo_ipa/roles/tripleo_ipa_dns/tasks/dns.yaml +++ /dev/null @@ -1,123 +0,0 @@ ---- -# Copyright 2020 Red Hat, Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -- name: set forward dns record values - set_fact: - record_value: "{{ item.split()[0] }}" - record_name: "{{ item.split()[1].split('.', 1)[0] }}" - zone_name: "{{ item.split()[1].split('.', 1)[1] }}" - when: item.split() | length >= 2 and item.split()[1].split('.') | length >= 2 - -- name: set alternative record values - set_fact: - record_value: "no record value" - record_name: "no record name" - zone_name: "no record zone name provided" - when: item.split() | length < 2 or item.split()[1].split('.') | length < 2 - -- name: Notify about not adding entries - debug: - msg: | - "{{ item }}" not added to DNS due to not being managed by us. - Entries with domains outside of cloud_domain are skipped. - when: not zone_name is match("^(|.+\.)" + cloud_domain + "$") - -- name: add entries - block: - - name: set record type - set_fact: - record_type: "{{ 'A' if record_value| ansible.netcommon.ipv4 else 'AAAA' }}" - - - name: add dns zone - ipadnszone: - name: "{{ zone_name }}" - become: true - - - name: Modify or add forward dns - block: - - name: try modifying forward dns record - ipadnsrecord: - zone_name: "{{ zone_name }}" - record_name: "{{ record_name }}" - record_type: "{{ record_type }}" - a_rec: "{{ record_value }}" - a_ip_address: "" - when: record_type == 'A' - become: true - - - name: try modifying forward dns record - ipadnsrecord: - zone_name: "{{ zone_name }}" - record_name: "{{ record_name }}" - record_type: "{{ record_type }}" - aaaa_rec: "{{ record_value }}" - aaaa_ip_address: "" - when: record_type == 'AAAA' - become: true - rescue: - - name: add forward dns record - ipadnsrecord: - zone_name: "{{ zone_name }}" - record_name: "{{ record_name }}" - record_type: "{{ record_type }}" - record_value: "{{ record_value }}" - become: true - - - name: get reverse record data - set_fact: - reverse_addr: "{{ record_value | ipaddr('revdns') }}" - - - name: set reverse record entries for ipv4 - set_fact: - reverse_record_zone: "{{ reverse_addr.split('.', tripleo_ipa_ptr_zone_split_ipv4|int)[-1] }}" - reverse_record_name: "{{ '.'.join(reverse_addr.split('.', tripleo_ipa_ptr_zone_split_ipv4|int)[:-1]) }}" - when: record_type == 'A' - - - name: set reverse record entries for ipv6 - set_fact: - reverse_record_zone: "{{ reverse_addr.split('.', tripleo_ipa_ptr_zone_split_ipv6|int)[-1] }}" - reverse_record_name: "{{ '.'.join(reverse_addr.split('.', tripleo_ipa_ptr_zone_split_ipv6|int)[:-1]) }}" - when: record_type == 'AAAA' - - - name: add reverse record dns zone - ipadnszone: - name: "{{ reverse_record_zone }}" - register: reverse_zone_result - failed_when: reverse_zone_result.failed and 'already exists in DNS' not in reverse_zone_result.msg - become: true - - - name: Modify or add reverse dns record - block: - - name: try modifying reverse dns record - ipadnsrecord: - zone_name: "{{ reverse_record_zone }}" - record_name: "{{ reverse_record_name }}" - record_type: "PTR" - ptr_rec: "{{ record_name }}.{{ zone_name }}." - ptr_hostname: "" - become: true - rescue: - - name: add reverse dns record - ipadnsrecord: - zone_name: "{{ reverse_record_zone }}" - record_name: "{{ reverse_record_name }}" - record_type: "PTR" - record_value: "{{ record_name }}.{{ zone_name }}." - register: reverse_record_result - failed_when: reverse_zone_result.failed and 'already exists in DNS' not in reverse_zone_result.msg - become: true - when: zone_name is match("^(|.+\.)" + cloud_domain + "$") diff --git a/tripleo_ipa/roles/tripleo_ipa_dns/tasks/main.yml b/tripleo_ipa/roles/tripleo_ipa_dns/tasks/main.yml index bf484c0..07cddb1 100644 --- a/tripleo_ipa/roles/tripleo_ipa_dns/tasks/main.yml +++ b/tripleo_ipa/roles/tripleo_ipa_dns/tasks/main.yml @@ -20,7 +20,40 @@ # - host_entry (host entries string, in a format similar to /etc/hosts) -- name: add dns records - include_tasks: - file: dns.yaml - loop: "{{ hosts_entry }}" +- name: get dns zones and entries to add + set_fact: + dns_zones: "{{ hosts_entry | get_dns_zones(cdomain=cloud_domain) }}" + ips_for_reverse: "{{ hosts_entry | get_ips(cdomain=cloud_domain) }}" + dns_entries: "{{ hosts_entry | get_dns_entries(cdomain=cloud_domain) }}" + no_reverse_ips: [] + +- name: add dns zones + loop: "{{ dns_zones }}" + ipadnszone: + name: "{{ item }}" + become: true + +- name: add reverse dns zones fixing errors + include_tasks: reverse_zones.yml + vars: + ip: "{{ item }}" + loop: "{{ ips_for_reverse }}" + +- name: set create_reverse to false for elements of no_reverse_ips + set_fact: + u_dns_entries: "{{ u_dns_entries |d([]) + [item|combine({'create_reverse': _rev|from_yaml})] }}" + loop: "{{ dns_entries }}" + vars: + _rev: | + {% if (item.record_type == 'A') and (item.a_rec in no_reverse_ips) %} + False + {% elif (item.record_type == 'AAAA') and (item.aaaa_rec in no_reverse_ips) %} + False + {% else %} + True + {% endif %} + +- name: add dns forward and reverse records + ipadnsrecord: + records: "{{ u_dns_entries }}" + become: true diff --git a/tripleo_ipa/roles/tripleo_ipa_dns/tasks/reverse_zones.yml b/tripleo_ipa/roles/tripleo_ipa_dns/tasks/reverse_zones.yml new file mode 100644 index 0000000..48e38fc --- /dev/null +++ b/tripleo_ipa/roles/tripleo_ipa_dns/tasks/reverse_zones.yml @@ -0,0 +1,10 @@ +- name: block to add reverse zone + block: + - name: add reverse zone + ipadnszone: + name_from_ip: "{{ ip }}" + become: true + rescue: + - name: add ip to no_reverse_ips + set_fact: + no_reverse_ips: "{{ no_reverse_ips + [ip] }}"