Turn verify_host_resolvable() into a wrapper around ipapython.dnsutil

The code was duplicate and less generic anyway.
As a side-effect I had to re-wrap dns.exception.DNSException into a
PublicError so it can be displayed to the user.

DNSError is now a super class for other DNS-related errors. Errors from
DNS resolver are re-raised as DNSResolverError.

https://fedorahosted.org/freeipa/ticket/5710

Reviewed-By: Martin Basti <mbasti@redhat.com>
This commit is contained in:
Petr Spacek
2016-05-17 17:28:36 +02:00
committed by Martin Basti
parent dc405005f5
commit 70794c7b1d
3 changed files with 72 additions and 61 deletions

View File

@@ -93,7 +93,9 @@ current block assignments:
- **4300 - 4399** `CertificateError` and its subclasses - **4300 - 4399** `CertificateError` and its subclasses
- **4400 - 4999** *Reserved for future use* - **4400 - 4499** `DNSError` and (some of) its subclasses
- **4500 - 4999** *Reserved for future use*
- **5000 - 5999** `GenericError` and its subclasses - **5000 - 5999** `GenericError` and its subclasses
@@ -1164,21 +1166,6 @@ class DefaultGroupError(ExecutionError):
errno = 4018 errno = 4018
format = _('The default users group cannot be removed') format = _('The default users group cannot be removed')
class DNSNotARecordError(ExecutionError):
"""
**4019** Raised when a hostname is not a DNS A/AAAA record
For example:
>>> raise DNSNotARecordError()
Traceback (most recent call last):
...
DNSNotARecordError: Host does not have corresponding DNS A/AAAA record
"""
errno = 4019
format = _('Host does not have corresponding DNS A/AAAA record')
class ManagedGroupError(ExecutionError): class ManagedGroupError(ExecutionError):
""" """
@@ -1598,24 +1585,6 @@ class DatabaseTimeout(DatabaseError):
format = _('LDAP timeout') format = _('LDAP timeout')
class DNSDataMismatch(ExecutionError):
"""
**4212** Raised when an DNS query didn't return expected answer
in a configured time limit.
For example:
>>> raise DNSDataMismatch(expected="zone3.test. 86400 IN A 192.0.2.1", \
got="zone3.test. 86400 IN A 192.168.1.1")
Traceback (most recent call last):
...
DNSDataMismatch: DNS check failed: Expected {zone3.test. 86400 IN A 192.0.2.1} got {zone3.test. 86400 IN A 192.168.1.1}
"""
errno = 4212
format = _('DNS check failed: Expected {%(expected)s} got {%(got)s}')
class TaskTimeout(DatabaseError): class TaskTimeout(DatabaseError):
""" """
**4213** Raised when an LDAP task times out **4213** Raised when an LDAP task times out
@@ -1833,6 +1802,67 @@ class CertificateInvalidError(CertificateError):
format = _('%(name)s certificate is not valid') format = _('%(name)s certificate is not valid')
class DNSError(ExecutionError):
"""
**4400** Base class for DNS execution errors (*4400 - 4499*).
These are typically wrapper exceptions around dns.exception.DNSException.
"""
errno = 4400
class DNSNotARecordError(DNSError):
"""
**4019** Raised when a hostname is not a DNS A/AAAA record
For example:
>>> raise DNSNotARecordError(hostname='x')
Traceback (most recent call last):
...
DNSNotARecordError: Host 'x' does not have corresponding DNS A/AAAA record
"""
errno = 4019 # this exception was defined before DNSError
format = _(
'Host \'%(hostname)s\' does not have corresponding DNS A/AAAA record')
class DNSDataMismatch(DNSError):
"""
**4212** Raised when an DNS query didn't return expected answer
in a configured time limit.
For example:
>>> raise DNSDataMismatch(expected="zone3.test. 86400 IN A 192.0.2.1", \
got="zone3.test. 86400 IN A 192.168.1.1")
Traceback (most recent call last):
...
DNSDataMismatch: DNS check failed: Expected {zone3.test. 86400 IN A 192.0.2.1} got {zone3.test. 86400 IN A 192.168.1.1}
"""
errno = 4212 # this exception was defined before DNSError
format = _('DNS check failed: Expected {%(expected)s} got {%(got)s}')
class DNSResolverError(DNSError):
"""
**4401** Wrapper around dns.exception.DNSException.
Raised when an error occured in dns.resolver.
For example:
>>> raise DNSResolverError(exception=ValueError("this is bad"))
Traceback (most recent call last):
...
DNSResolverError: this is bad
"""
errno = 4401
format = _('%(exception)s')
############################################################################## ##############################################################################
# 5000 - 5999: Generic errors # 5000 - 5999: Generic errors

View File

@@ -42,8 +42,8 @@ from ipalib.text import _
from ipapython.ssh import SSHPublicKey from ipapython.ssh import SSHPublicKey
from ipapython.dn import DN, RDN from ipapython.dn import DN, RDN
from ipapython.dnsutil import DNSName from ipapython.dnsutil import DNSName
from ipapython.dnsutil import resolve_ip_addresses
from ipapython.graph import Graph from ipapython.graph import Graph
from ipapython.ipa_log_manager import root_logger
if six.PY3: if six.PY3:
unicode = str unicode = str
@@ -67,30 +67,12 @@ def json_serialize(obj):
def verify_host_resolvable(fqdn): def verify_host_resolvable(fqdn):
""" try:
See if the hostname has a DNS A/AAAA record. if not resolve_ip_addresses(fqdn):
""" raise errors.DNSNotARecordError(hostname=fqdn)
if not isinstance(fqdn, DNSName): except dns.exception.DNSException as ex:
fqdn = DNSName(fqdn) # wrap DNSException in a PublicError
raise errors.DNSResolverError(exception=ex)
fqdn = fqdn.make_absolute()
for rdtype in ('A', 'AAAA'):
try:
answers = resolver.query(fqdn, rdtype)
root_logger.debug(
'IPA: found %d %s records for %s: %s' % (len(answers),
rdtype, fqdn, ' '.join(str(answer) for answer in answers))
)
except DNSException:
root_logger.debug(
'IPA: DNS %s record lookup failed for %s' %
(rdtype, fqdn)
)
continue
else:
return
# dns lookup failed in both tries
raise errors.DNSNotARecordError()
def has_soa_or_ns_record(domain): def has_soa_or_ns_record(domain):

View File

@@ -311,8 +311,7 @@ class TestCRUD(XMLRPC_test):
def test_try_add_not_in_dns(self, host): def test_try_add_not_in_dns(self, host):
host.ensure_missing() host.ensure_missing()
command = host.make_create_command(force=False) command = host.make_create_command(force=False)
with raises_exact(errors.DNSNotARecordError( with raises_exact(errors.DNSNotARecordError(hostname=host)):
reason=u'Host does not have corresponding DNS A/AAAA record')):
command() command()
def test_add_host_with_null_password(self, host): def test_add_host_with_null_password(self, host):