Lookup ipa-ca record with NSS

DNS data management now uses NSS's getaddrinfo() instead of direct DNS
queries to resolve the ipa-ca record. This fixes missing ipa-ca records
when the current hostname is not resolvable in DNS but has correct
records in /etc/hosts.

Reduce timeout to 15 seconds and tighten timeout loop.

The changeset can speed up installation by almost 60 seconds.
ipa-server-install without built-in DNS calls into DNS data management
twice with a timeout of 30 seconds for each call.

Fixes: https://pagure.io/freeipa/issue/8529
Related: https://pagure.io/freeipa/issue/8521
Related: https://pagure.io/freeipa/issue/8501
Signed-off-by: Christian Heimes <cheimes@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
This commit is contained in:
Christian Heimes 2020-10-06 13:12:41 +02:00
parent 5d95794edf
commit 731c5b2110
2 changed files with 48 additions and 10 deletions

View File

@ -15,13 +15,13 @@ from dns import (
rdatatype,
zone,
)
from dns.exception import DNSException
from time import sleep, time
from ipalib import errors
from ipalib.dns import record_name_format
from ipapython.dnsutil import DNSName, resolve_rrsets
from ipapython.dnsutil import DNSName
from ipaserver.install import installutils
if six.PY3:
unicode=str
@ -55,7 +55,7 @@ IPA_DEFAULT_NTP_SRV_REC = (
(DNSName("_ntp._udp"), 123),
)
CA_RECORDS_DNS_TIMEOUT = 30 # timeout in seconds
CA_RECORDS_DNS_TIMEOUT = 15 # timeout in seconds
class IPADomainIsNotManagedByIPAError(Exception):
@ -139,16 +139,20 @@ class IPASystemRecords:
def __add_ca_records_from_hostname(self, zone_obj, hostname):
assert isinstance(hostname, DNSName) and hostname.is_absolute()
r_name = DNSName('ipa-ca') + self.domain_abs
rrsets = []
rrsets = None
end_time = time() + CA_RECORDS_DNS_TIMEOUT
while time() < end_time:
while True:
try:
rrsets = resolve_rrsets(hostname, (rdatatype.A, rdatatype.AAAA))
except DNSException: # logging is done inside resolve_rrsets
# function logs errors
rrsets = installutils.resolve_rrsets_nss(hostname)
except OSError:
# also retry on EAI_AGAIN, EAI_FAIL
pass
if rrsets:
break
sleep(5)
if time() >= end_time:
break
sleep(3)
if not rrsets:
logger.error('unable to resolve host name %s to IP address, '

View File

@ -39,7 +39,7 @@ from contextlib import contextmanager
from configparser import ConfigParser as SafeConfigParser
from configparser import NoOptionError
from dns import rdatatype
from dns import rrset, rdatatype, rdataclass
from dns.exception import DNSException
import ldap
import six
@ -55,7 +55,7 @@ from ipalib.util import validate_hostname
from ipalib import api, errors, x509
from ipalib.install import dnsforwarders
from ipapython.dn import DN
from ipapython.dnsutil import resolve
from ipapython.dnsutil import DNSName, resolve
from ipaserver.install import certs, service, sysupgrade
from ipaplatform import services
from ipaplatform.paths import paths
@ -480,6 +480,40 @@ def resolve_ip_addresses_nss(fqdn):
return ip_addresses
def resolve_rrsets_nss(fqdn):
"""Get list of dnspython RRsets from NSS"""
if not isinstance(fqdn, DNSName):
fqdn = DNSName.from_text(fqdn)
ip_addresses = resolve_ip_addresses_nss(fqdn.to_text())
# split IP addresses into IPv4 and IPv6
ipv4 = []
ipv6 = []
for ip_address in ip_addresses:
if ip_address.version == 4:
ipv4.append(str(ip_address))
elif ip_address.version == 6:
ipv6.append(str(ip_address))
# construct an RRset for each address type. TTL is irrelevant
ttl = 3600
rrs = []
if ipv4:
rrs.append(
rrset.from_text_list(
fqdn, ttl, rdataclass.IN, rdatatype.A, ipv4
)
)
if ipv6:
rrs.append(
rrset.from_text_list(
fqdn, ttl, rdataclass.IN, rdatatype.AAAA, ipv6
)
)
return rrs
def get_server_ip_address(host_name, unattended, setup_dns, ip_addresses):
hostaddr = resolve_ip_addresses_nss(host_name)
if hostaddr.intersection(