URL: https://github.com/freeipa/freeipa/pull/5069
Author: stanislavlevin
 Title: #5069: [Backport][ipa-4-8] [Azure] Add rawhide definitions
Action: opened

PR body:
"""
This PR was opened manually because PR #5047 was pushed to master and backport 
to `ipa-4-8` is required.
"""

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/5069/head:pr5069
git checkout pr5069
From 3b319c1ae96173a437960f2986ebc0716a614a41 Mon Sep 17 00:00:00 2001
From: Stanislav Levin <s...@altlinux.org>
Date: Tue, 18 Aug 2020 10:28:59 +0300
Subject: [PATCH 1/8] Azure: Add Rawhide definitions

- allow override variables template file with an externally
provided one. This allows to add new Azure Pipeline which will
point to a custom platform definition. Note: Azure's WebUI
variables are runtime variables and not available at parsing time,
that's why it's impossible to override template from WebUI in
this case.

- add Rawhide templates

- add Dockerfile for build Rawhie Docker image for tests phase
Note: 'fedora:rawhide' is too old, use for now
'registry.fedoraproject.org/fedora:rawhide'.
See, https://bugzilla.redhat.com/show_bug.cgi?id=1869612

Signed-off-by: Stanislav Levin <s...@altlinux.org>
---
 .../Dockerfiles/Dockerfile.build.rawhide      | 31 +++++++++++++++++++
 ipatests/azure/azure-pipelines-rawhide.yml    |  4 +++
 ipatests/azure/azure-pipelines.yml            |  6 +++-
 .../azure/templates/prepare-tox-fedora.yml    |  2 +-
 .../azure/templates/variables-rawhide.yml     | 23 ++++++++++++++
 5 files changed, 64 insertions(+), 2 deletions(-)
 create mode 100644 ipatests/azure/Dockerfiles/Dockerfile.build.rawhide
 create mode 100644 ipatests/azure/azure-pipelines-rawhide.yml
 create mode 100644 ipatests/azure/templates/variables-rawhide.yml

diff --git a/ipatests/azure/Dockerfiles/Dockerfile.build.rawhide b/ipatests/azure/Dockerfiles/Dockerfile.build.rawhide
new file mode 100644
index 0000000000..3318c33fd1
--- /dev/null
+++ b/ipatests/azure/Dockerfiles/Dockerfile.build.rawhide
@@ -0,0 +1,31 @@
+# replace with 'fedora:rawhide' on fix:
+# https://bugzilla.redhat.com/show_bug.cgi?id=1869612
+FROM registry.fedoraproject.org/fedora:rawhide
+MAINTAINER [FreeIPA Developers freeipa-devel@lists.fedorahosted.org]
+ENV container=docker LANG=en_US.utf8 LANGUAGE=en_US.utf8 LC_ALL=en_US.utf8
+
+ADD dist /root
+RUN echo 'deltarpm = false' >> /etc/dnf/dnf.conf \
+    && dnf update -y dnf \
+    && sed -i 's/%_install_langs \(.*\)/\0:fr/g' /etc/rpm/macros.image-language-conf \
+    && dnf install -y systemd \
+    && dnf install -y \
+        firewalld \
+        glibc-langpack-fr \
+        glibc-langpack-en \
+        iptables \
+        nss-tools \
+        openssh-server \
+        sudo \
+        wget \
+        /root/rpms/*.rpm \
+    && dnf clean all && rm -rf /root/rpms /root/srpms \
+    && sed -i 's/.*PermitRootLogin .*/#&/g' /etc/ssh/sshd_config \
+    && echo 'PermitRootLogin yes' >> /etc/ssh/sshd_config \
+    && systemctl enable sshd \
+    && for i in /usr/lib/systemd/system/*-domainname.service; \
+    do sed -i 's#^ExecStart=/#ExecStart=-/#' $i ; done
+
+STOPSIGNAL RTMIN+3
+VOLUME ["/freeipa", "/run", "/tmp"]
+ENTRYPOINT [ "/usr/sbin/init" ]
diff --git a/ipatests/azure/azure-pipelines-rawhide.yml b/ipatests/azure/azure-pipelines-rawhide.yml
new file mode 100644
index 0000000000..e6fd16bb99
--- /dev/null
+++ b/ipatests/azure/azure-pipelines-rawhide.yml
@@ -0,0 +1,4 @@
+extends:
+  template: azure-pipelines.yml
+  parameters:
+    VARIABLES_FILE: 'templates/variables-rawhide.yml'
diff --git a/ipatests/azure/azure-pipelines.yml b/ipatests/azure/azure-pipelines.yml
index bc7e6bf913..8e7207d1e9 100644
--- a/ipatests/azure/azure-pipelines.yml
+++ b/ipatests/azure/azure-pipelines.yml
@@ -1,10 +1,14 @@
+parameters:
+- name: VARIABLES_FILE
+  default: 'templates/variables.yml'
+
 trigger:
 - master
 
 variables:
 - template: templates/variables-common.yml
 # platform specific variables, links to
-- template: templates/variables.yml
+- template: ${{ parameters.VARIABLES_FILE }}
 
 jobs:
 - job: Build
diff --git a/ipatests/azure/templates/prepare-tox-fedora.yml b/ipatests/azure/templates/prepare-tox-fedora.yml
index ee034b0989..4e27ac7557 100644
--- a/ipatests/azure/templates/prepare-tox-fedora.yml
+++ b/ipatests/azure/templates/prepare-tox-fedora.yml
@@ -1,6 +1,6 @@
 steps:
 - script: |
     set -e
-    sudo dnf -y install nss-tools
+    sudo dnf -y install nss-tools python3-pip
     python3 -m pip install --user --upgrade pip setuptools pycodestyle
   displayName: Install Tox prerequisites
diff --git a/ipatests/azure/templates/variables-rawhide.yml b/ipatests/azure/templates/variables-rawhide.yml
new file mode 100644
index 0000000000..43201f1a34
--- /dev/null
+++ b/ipatests/azure/templates/variables-rawhide.yml
@@ -0,0 +1,23 @@
+variables:
+  IPA_PLATFORM: fedora
+  # the Docker public image to build IPA packages (rpms)
+  #
+  # replace with 'fedora:rawhide' on fix:
+  # https://bugzilla.redhat.com/show_bug.cgi?id=1869612
+  DOCKER_BUILD_IMAGE: 'registry.fedoraproject.org/fedora:rawhide'
+
+  # the Dockerfile to build Docker image for running IPA tests
+  DOCKER_DOCKERFILE: 'Dockerfile.build.rawhide'
+
+  # the template to install IPA's buildtime dependencies
+  PREPARE_BUILD_TEMPLATE: ${{ format('prepare-build-{0}.yml', variables.IPA_PLATFORM) }}
+
+  # the template to build IPA packages (rpms)
+  BUILD_TEMPLATE: ${{ format('build-{0}.yml', variables.IPA_PLATFORM) }}
+  PREPARE_TOX_TEMPLATE: ${{ format('prepare-tox-{0}.yml', variables.IPA_PLATFORM) }}
+  PREPARE_WEBUI_TEMPLATE: ${{ format('prepare-webui-{0}.yml', variables.IPA_PLATFORM) }}
+
+  TOX_COMMAND: tox
+
+  # Python version for UsePythonVersion@0 task
+  AZURE_PYTHON_VERSION: '3.9'

From 936bf6065f627545e1fe0a9fc4d69eca81956a2d Mon Sep 17 00:00:00 2001
From: Stanislav Levin <s...@altlinux.org>
Date: Tue, 18 Aug 2020 14:31:02 +0300
Subject: [PATCH 2/8] Azure: Drop dependency on UsePythonVersion task

Python is provided by the Docker container image and it's no
longer needed to bind mount host's Python into container.

Signed-off-by: Stanislav Levin <s...@altlinux.org>
---
 ipatests/azure/azure-pipelines.yml             | 8 --------
 ipatests/azure/templates/variables-fedora.yml  | 3 ---
 ipatests/azure/templates/variables-rawhide.yml | 3 ---
 3 files changed, 14 deletions(-)

diff --git a/ipatests/azure/azure-pipelines.yml b/ipatests/azure/azure-pipelines.yml
index 8e7207d1e9..38d26815a9 100644
--- a/ipatests/azure/azure-pipelines.yml
+++ b/ipatests/azure/azure-pipelines.yml
@@ -89,10 +89,6 @@ jobs:
     options: --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --privileged --env container=docker
   steps:
     - template: templates/${{ variables.PREPARE_BUILD_TEMPLATE }}
-    - task: UsePythonVersion@0
-      inputs:
-        versionSpec: ${{ variables.AZURE_PYTHON_VERSION }}
-        architecture: x64
     - template: templates/${{ variables.PREPARE_TOX_TEMPLATE }}
     - script: |
         set -e
@@ -116,10 +112,6 @@ jobs:
     options: --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --privileged --env container=docker
   steps:
     - template: templates/${{ variables.PREPARE_BUILD_TEMPLATE }}
-    - task: UsePythonVersion@0
-      inputs:
-        versionSpec: ${{ variables.AZURE_PYTHON_VERSION }}
-        architecture: x64
     - template: templates/${{ variables.PREPARE_WEBUI_TEMPLATE }}
     - script: |
         set -e
diff --git a/ipatests/azure/templates/variables-fedora.yml b/ipatests/azure/templates/variables-fedora.yml
index 9440942f73..3e8f878c22 100644
--- a/ipatests/azure/templates/variables-fedora.yml
+++ b/ipatests/azure/templates/variables-fedora.yml
@@ -15,6 +15,3 @@ variables:
   PREPARE_WEBUI_TEMPLATE: ${{ format('prepare-webui-{0}.yml', variables.IPA_PLATFORM) }}
 
   TOX_COMMAND: tox
-
-  # Python version for UsePythonVersion@0 task
-  AZURE_PYTHON_VERSION: '3.8'
diff --git a/ipatests/azure/templates/variables-rawhide.yml b/ipatests/azure/templates/variables-rawhide.yml
index 43201f1a34..6cbc78d18d 100644
--- a/ipatests/azure/templates/variables-rawhide.yml
+++ b/ipatests/azure/templates/variables-rawhide.yml
@@ -18,6 +18,3 @@ variables:
   PREPARE_WEBUI_TEMPLATE: ${{ format('prepare-webui-{0}.yml', variables.IPA_PLATFORM) }}
 
   TOX_COMMAND: tox
-
-  # Python version for UsePythonVersion@0 task
-  AZURE_PYTHON_VERSION: '3.9'

From 27708e3c7dc0d7537650e52f16f774681bd61bcc Mon Sep 17 00:00:00 2001
From: Stanislav Levin <s...@altlinux.org>
Date: Wed, 19 Aug 2020 17:51:07 +0300
Subject: [PATCH 3/8] Azure: base: Collect both install and uninstall logs

Some applications remove their logs on uninstallation.
As a result of this, Azure lost `install` logs.

Signed-off-by: Stanislav Levin <s...@altlinux.org>
---
 .../azure/scripts/azure-run-base-tests.sh     | 33 ++++++++++++-------
 1 file changed, 21 insertions(+), 12 deletions(-)

diff --git a/ipatests/azure/scripts/azure-run-base-tests.sh b/ipatests/azure/scripts/azure-run-base-tests.sh
index b3811dae69..a2129d2a45 100755
--- a/ipatests/azure/scripts/azure-run-base-tests.sh
+++ b/ipatests/azure/scripts/azure-run-base-tests.sh
@@ -5,6 +5,25 @@
 # distro-specifics
 source "${IPA_TESTS_SCRIPTS}/variables.sh"
 
+function collect_logs() {
+    if [ "$#" -ne 1 ]; then
+        printf "collect_logs: The path to output archive is required\n"
+        exit 1
+    fi
+    local out_file="$1"
+    printf "Collecting logs\n"
+    journalctl -b --no-pager > systemd_journal.log
+    tar --ignore-failed-read -czf "$out_file" \
+        /var/log/dirsrv \
+        "$HTTPD_LOGDIR" \
+        /var/log/ipa* \
+        /var/log/krb5kdc.log \
+        /var/log/pki \
+        /var/log/samba \
+        "$BIND_DATADIR" \
+        systemd_journal.log
+}
+
 server_password=Secret123
 
 echo "Installing FreeIPA master for the domain ${IPA_TESTS_DOMAIN} and realm ${IPA_TESTS_REALM}"
@@ -53,6 +72,7 @@ if [ "$install_result" -eq 0 ] ; then
 else
     echo "ipa-server-install failed with code ${install_result}, skip IPA tests"
 fi
+collect_logs ipaserver_install_logs.tar.gz
 
 echo "Potential Python 3 incompatibilities in the IPA framework:"
 grep -n -C5 BytesWarning "$HTTPD_ERRORLOG" || echo "Good, none detected"
@@ -75,23 +95,12 @@ ipa-server-install --uninstall -U
 # second uninstall to verify that --uninstall without installation works
 ipa-server-install --uninstall -U
 
+collect_logs ipaserver_uninstall_logs.tar.gz
 
 if [ "$install_result" -eq 0 ] ; then
     firewalld_cmd --remove-service={freeipa-ldap,freeipa-ldaps,dns}
 fi
 
-echo "Collect the logs"
-journalctl -b --no-pager > systemd_journal.log
-tar --ignore-failed-read --remove-files -czf var_log.tar.gz \
-    /var/log/dirsrv \
-    "$HTTPD_LOGDIR" \
-    /var/log/ipa* \
-    /var/log/krb5kdc.log \
-    /var/log/pki \
-    /var/log/samba \
-    "$BIND_DATADIR" \
-    systemd_journal.log
-
 echo "Report memory statistics"
 cat /sys/fs/cgroup/memory/memory.memsw.failcnt
 cat /sys/fs/cgroup/memory/memory.memsw.limit_in_bytes

From 9d479fa37e2a58e31cbbea8ae429fa03f7f00384 Mon Sep 17 00:00:00 2001
From: Stanislav Levin <s...@altlinux.org>
Date: Thu, 27 Aug 2020 12:07:40 +0300
Subject: [PATCH 4/8] nss: Raise exception earlier on unsupported DB type

For now FreeIPA handles explicit migration of NSS DB (dbm->sql).
But Mozilla's NSS can be built without the support of legacy database
(DBM). This implies that neither implicit nor explicit DB migration
to SQL will work. So, eventually, this support will be removed from
FreeIPA.

With this patch, the instantiation of NSS with legacy db(if not
supported by NSS) is forbidden.

Fixes: https://pagure.io/freeipa/issue/8474
Signed-off-by: Stanislav Levin <s...@altlinux.org>
---
 ipapython/certdb.py                    | 23 ++++++++++++++-----
 ipatests/test_ipapython/test_certdb.py | 31 +++++++++++++++++++++++++-
 2 files changed, 47 insertions(+), 7 deletions(-)

diff --git a/ipapython/certdb.py b/ipapython/certdb.py
index 43245cd292..8e0faffdd0 100644
--- a/ipapython/certdb.py
+++ b/ipapython/certdb.py
@@ -26,10 +26,11 @@
 import pwd
 import grp
 import re
+import shutil
 import stat
 import tempfile
+from ctypes.util import find_library
 from tempfile import NamedTemporaryFile
-import shutil
 
 import cryptography.x509
 
@@ -73,6 +74,10 @@
 )
 
 
+def nss_supports_dbm():
+    return bool(find_library("nssdbm3"))
+
+
 def get_ca_nickname(realm, format=CA_NICKNAME_FMT):
     return format % realm
 
@@ -252,15 +257,21 @@ class NSSDatabase:
     # Generic NSS DB code should be moved here.
 
     def __init__(self, nssdir=None, dbtype='auto'):
-        if nssdir is None:
-            self.secdir = tempfile.mkdtemp()
-            self._is_temporary = True
-        else:
+        if nssdir is not None:
             self.secdir = nssdir
             self._is_temporary = False
-            if dbtype == 'auto':
+            if dbtype == "auto":
                 dbtype = self._detect_dbtype()
 
+        if dbtype == "dbm" and not nss_supports_dbm():
+            raise ValueError(
+                "NSS is built without support of the legacy database(DBM)"
+            )
+
+        if nssdir is None:
+            self.secdir = tempfile.mkdtemp()
+            self._is_temporary = True
+
         self.pwd_file = os.path.join(self.secdir, 'pwdfile.txt')
         self.dbtype = None
         self.certdb = self.keydb = self.secmod = None
diff --git a/ipatests/test_ipapython/test_certdb.py b/ipatests/test_ipapython/test_certdb.py
index e4366de6da..7c0558da81 100644
--- a/ipatests/test_ipapython/test_certdb.py
+++ b/ipatests/test_ipapython/test_certdb.py
@@ -4,7 +4,11 @@
 
 import pytest
 
-from ipapython.certdb import NSSDatabase, TRUSTED_PEER_TRUST_FLAGS
+from ipapython.certdb import (
+    NSSDatabase,
+    TRUSTED_PEER_TRUST_FLAGS,
+    nss_supports_dbm,
+)
 from ipapython import ipautil
 from ipaplatform.osinfo import osinfo
 
@@ -40,6 +44,10 @@ def create_selfsigned(nssdb):
         os.unlink(noisefile)
 
 
+@pytest.mark.skipif(
+    not nss_supports_dbm(),
+    reason="NSS is built without support of the legacy database(DBM)",
+)
 def test_dbm_tmp():
     with NSSDatabase(dbtype='dbm') as nssdb:
         assert nssdb.dbtype == 'dbm'
@@ -60,6 +68,19 @@ def test_dbm_tmp():
         assert os.path.basename(nssdb.secmod) == 'secmod.db'
 
 
+@pytest.mark.skipif(
+    nss_supports_dbm(),
+    reason="NSS is built with support of the legacy database(DBM)",
+)
+def test_dbm_raise():
+    with pytest.raises(ValueError) as e:
+        NSSDatabase(dbtype="dbm")
+    assert (
+        str(e.value) == "NSS is built without support of the legacy "
+        "database(DBM)"
+    )
+
+
 def test_sql_tmp():
     with NSSDatabase(dbtype='sql') as nssdb:
         assert nssdb.dbtype == 'sql'
@@ -80,6 +101,10 @@ def test_sql_tmp():
         assert os.path.basename(nssdb.secmod) == 'pkcs11.txt'
 
 
+@pytest.mark.skipif(
+    not nss_supports_dbm(),
+    reason="NSS is built without support of the legacy database(DBM)",
+)
 def test_convert_db():
     with NSSDatabase(dbtype='dbm') as nssdb:
         assert nssdb.dbtype == 'dbm'
@@ -115,6 +140,10 @@ def test_convert_db():
         assert os.path.basename(nssdb.secmod) == 'pkcs11.txt'
 
 
+@pytest.mark.skipif(
+    not nss_supports_dbm(),
+    reason="NSS is built without support of the legacy database(DBM)",
+)
 def test_convert_db_nokey():
     with NSSDatabase(dbtype='dbm') as nssdb:
         assert nssdb.dbtype == 'dbm'

From f1253da215be1f4617fb924c13f54a6442d88558 Mon Sep 17 00:00:00 2001
From: Stanislav Levin <s...@altlinux.org>
Date: Wed, 26 Aug 2020 17:02:25 +0300
Subject: [PATCH 5/8] deps: Require `nss-tools` for make's fasttest target

Otherwise, tests fail with:
```
E               FileNotFoundError: [Errno 2] No such file or directory: '/usr/bin/certutil'
...
=================================== short test summary info ===================================
FAILED test_ipapython/test_certdb.py::test_dbm_tmp - FileNotFoundError: [Errno 2] No such fi...
FAILED test_ipapython/test_certdb.py::test_sql_tmp - FileNotFoundError: [Errno 2] No such fi...
FAILED test_ipapython/test_certdb.py::test_convert_db - FileNotFoundError: [Errno 2] No such...
FAILED test_ipapython/test_certdb.py::test_convert_db_nokey - FileNotFoundError: [Errno 2] N...
FAILED test_ipapython/test_certdb.py::test_auto_db - FileNotFoundError: [Errno 2] No such fi...
FAILED test_ipapython/test_certdb.py::test_delete_cert_and_key - FileNotFoundError: [Errno 2...
FAILED test_ipapython/test_certdb.py::test_check_validity - FileNotFoundError: [Errno 2] No ...
...
```

Signed-off-by: Stanislav Levin <s...@altlinux.org>
---
 freeipa.spec.in | 1 +
 1 file changed, 1 insertion(+)

diff --git a/freeipa.spec.in b/freeipa.spec.in
index 3b09d6aa56..70f5bf7ae9 100755
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -243,6 +243,7 @@ BuildRequires:  python3-wheel
 #
 %if 0%{?with_lint}
 BuildRequires:  jsl
+BuildRequires:  nss-tools
 BuildRequires:  rpmlint
 BuildRequires:  softhsm
 BuildRequires:  keyutils

From 71a8fe270c12ccd9ac65bfa4842dc6d8c0c82a34 Mon Sep 17 00:00:00 2001
From: Stanislav Levin <s...@altlinux.org>
Date: Thu, 27 Aug 2020 15:59:32 +0300
Subject: [PATCH 6/8] Azure: Increase verbosity for Tox task

This allows to debug issues happened during packages installation:

> -v, --verbose     increase verbosity of reporting output.
-vv mode turns off output redirection for package installation,
above level two verbosity flags are passed through to pip (with two less
level) (default: 0)

Signed-off-by: Stanislav Levin <s...@altlinux.org>
---
 ipatests/azure/azure-pipelines.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ipatests/azure/azure-pipelines.yml b/ipatests/azure/azure-pipelines.yml
index 38d26815a9..1ff4def3f3 100644
--- a/ipatests/azure/azure-pipelines.yml
+++ b/ipatests/azure/azure-pipelines.yml
@@ -96,7 +96,7 @@ jobs:
         export LANG=en_US.utf8
         export LC_CTYPE=en_US.utf8
         locale
-        $(TOX_COMMAND) -e py3,pypi,pylint3
+        $(TOX_COMMAND) -e py3,pypi,pylint3 -vv
       displayName: Tox
     - task: PublishTestResults@2
       inputs:

From e73a4e4a992dfe4b6f987087f3288313b5d24c8e Mon Sep 17 00:00:00 2001
From: Stanislav Levin <s...@altlinux.org>
Date: Thu, 27 Aug 2020 17:20:49 +0300
Subject: [PATCH 7/8] tox: Don't expand symlinks

`virtualenv` < 20.0.0 copies system python binary into virt
environment and then links `python` to it. While
`virtualenv` >= 20.0.0 directly links `python` to system python
binary (without copying).

`realpath` by default expands symlinks. Thereby, pip attempts to
install packages into the system's site-packages and
fails with 'Permission denied' (non-privileged user).

Fixes: https://pagure.io/freeipa/issue/8475
Signed-off-by: Stanislav Levin <s...@altlinux.org>
---
 .tox-install.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.tox-install.sh b/.tox-install.sh
index 95f5c1e70a..ff22b4d79f 100755
--- a/.tox-install.sh
+++ b/.tox-install.sh
@@ -2,8 +2,8 @@
 set -ex
 
 FLAVOR="$1"
-ENVPYTHON="$(realpath "$2")"
-ENVSITEPACKAGESDIR="$(realpath "$3")"
+ENVPYTHON="$(realpath -s "$2")"
+ENVSITEPACKAGESDIR="$(realpath -s "$3")"
 ENVDIR="$4"
 # 4...end are package requirements
 shift 4

From b7e6b511e3b71e872cf9bf37eb79dfb677927685 Mon Sep 17 00:00:00 2001
From: Stanislav Levin <s...@altlinux.org>
Date: Fri, 28 Aug 2020 16:31:10 +0300
Subject: [PATCH 8/8] dnspython: Add compatibility shim

`dnspython` 2.0.0 has many changes and several deprecations like:

```
> dns.resolver.resolve() has been added, allowing control of whether
search lists are used. dns.resolver.query() is retained for backwards
compatibility, but deprecated. The default for search list behavior can
be set at in the resolver object with the use_search_by_default
parameter. The default is False.

> dns.resolver.resolve_address() has been added, allowing easy
address-to-name lookups.
```

The new class `DNSResolver`:
- provides the compatibility layer
- defaults the previous behavior (the search list configured in the
  system's resolver configuration is used for relative names)
- defaults lifetime to 15sec (determines the number of seconds
  to spend trying to get an answer to the question)

Fixes: https://pagure.io/freeipa/issue/8383
Signed-off-by: Stanislav Levin <s...@altlinux.org>
---
 ipaclient/discovery.py                        |  6 +-
 ipaclient/install/client.py                   |  9 +-
 ipalib/util.py                                | 22 +++--
 ipapython/dnsutil.py                          | 92 ++++++++++++++++++-
 ipapython/ipautil.py                          | 19 ----
 ipaserver/install/bindinstance.py             | 11 ++-
 ipaserver/install/dns.py                      |  8 +-
 ipaserver/install/installutils.py             | 13 ++-
 ipaserver/install/server/replicainstall.py    | 10 +-
 ipaserver/plugins/cert.py                     |  4 +-
 ipaserver/plugins/dns.py                      | 24 +++--
 ipaserver/plugins/host.py                     |  6 +-
 ipatests/pytest_ipa/integration/tasks.py      |  5 +-
 .../test_integration/test_dns_locations.py    |  6 +-
 ipatests/test_integration/test_dnssec.py      |  6 +-
 15 files changed, 157 insertions(+), 84 deletions(-)

diff --git a/ipaclient/discovery.py b/ipaclient/discovery.py
index c322e97124..fb344a34a8 100644
--- a/ipaclient/discovery.py
+++ b/ipaclient/discovery.py
@@ -24,11 +24,11 @@
 
 import six
 
-from dns import resolver, rdatatype
+from dns import rdatatype
 from dns.exception import DNSException
 from ipalib import errors
 from ipalib.util import validate_domain_name
-from ipapython.dnsutil import query_srv
+from ipapython.dnsutil import query_srv, resolve
 
 from ipaplatform.paths import paths
 from ipapython.ipautil import valid_ip, realm_to_suffix
@@ -562,7 +562,7 @@ def ipadnssearchkrbrealm(self, domain=None):
         logger.debug("Search DNS for TXT record of %s", qname)
 
         try:
-            answers = resolver.query(qname, rdatatype.TXT)
+            answers = resolve(qname, rdatatype.TXT)
         except DNSException as e:
             logger.debug("DNS record not found: %s", e.__class__.__name__)
             answers = []
diff --git a/ipaclient/install/client.py b/ipaclient/install/client.py
index 5b4caa09a6..960e25e061 100644
--- a/ipaclient/install/client.py
+++ b/ipaclient/install/client.py
@@ -53,7 +53,7 @@
 from ipaplatform.constants import constants
 from ipaplatform.paths import paths
 from ipaplatform.tasks import tasks
-from ipapython import certdb, kernel_keyring, ipaldap, ipautil
+from ipapython import certdb, kernel_keyring, ipaldap, ipautil, dnsutil
 from ipapython.admintool import ScriptError
 from ipapython.dn import DN
 from ipapython.install import typing
@@ -1440,7 +1440,7 @@ def verify_dns_update(fqdn, ips):
         logger.debug('DNS resolver: Query: %s IN %s',
                      fqdn, dns.rdatatype.to_text(record_type))
         try:
-            answers = dns.resolver.query(fqdn, record_type)
+            answers = dnsutil.resolve(fqdn, record_type)
         except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN):
             logger.debug('DNS resolver: No record.')
         except dns.resolver.NoNameservers:
@@ -1460,10 +1460,9 @@ def verify_dns_update(fqdn, ips):
     missing_reverse = [str(ip) for ip in ips]
     for ip in ips:
         ip_str = str(ip)
-        addr = dns.reversename.from_address(ip_str)
-        logger.debug('DNS resolver: Query: %s IN PTR', addr)
+        logger.debug('DNS resolver: Query: %s IN PTR', ip_str)
         try:
-            answers = dns.resolver.query(addr, dns.rdatatype.PTR)
+            answers = dnsutil.resolve_address(ip_str)
         except (dns.resolver.NoAnswer, dns.resolver.NXDOMAIN):
             logger.debug('DNS resolver: No record.')
         except dns.resolver.NoNameservers:
diff --git a/ipalib/util.py b/ipalib/util.py
index 786cfa71eb..dc22c02789 100644
--- a/ipalib/util.py
+++ b/ipalib/util.py
@@ -42,7 +42,7 @@
 import subprocess
 
 import netaddr
-from dns import resolver, rdatatype
+from dns import rdatatype
 from dns.exception import DNSException
 from dns.resolver import NXDOMAIN
 from netaddr.core import AddrFormatError
@@ -67,8 +67,12 @@
 from ipaplatform.paths import paths
 from ipapython.ssh import SSHPublicKey
 from ipapython.dn import DN, RDN
-from ipapython.dnsutil import DNSName
-from ipapython.dnsutil import resolve_ip_addresses
+from ipapython.dnsutil import (
+    DNSName,
+    DNSResolver,
+    resolve,
+    resolve_ip_addresses,
+)
 from ipapython.admintool import ScriptError
 
 if sys.version_info >= (3, 2):
@@ -117,13 +121,13 @@ def has_soa_or_ns_record(domain):
     Returns True or False.
     """
     try:
-        resolver.query(domain, rdatatype.SOA)
+        resolve(domain, rdatatype.SOA)
         soa_record_found = True
     except DNSException:
         soa_record_found = False
 
     try:
-        resolver.query(domain, rdatatype.NS)
+        resolve(domain, rdatatype.NS)
         ns_record_found = True
     except DNSException:
         ns_record_found = False
@@ -797,7 +801,7 @@ def _resolve_record(owner, rtype, nameserver_ip=None, edns0=False,
     assert isinstance(nameserver_ip, str) or nameserver_ip is None
     assert isinstance(rtype, str)
 
-    res = dns.resolver.Resolver()
+    res = DNSResolver()
     if nameserver_ip:
         res.nameservers = [nameserver_ip]
     res.lifetime = timeout
@@ -815,7 +819,7 @@ def _resolve_record(owner, rtype, nameserver_ip=None, edns0=False,
     elif edns0:
         res.use_edns(0, 0, 4096)
 
-    return res.query(owner, rtype)
+    return res.resolve(owner, rtype)
 
 
 def _validate_edns0_forwarder(owner, rtype, ip_addr, timeout=10):
@@ -985,7 +989,7 @@ def detect_dns_zone_realm_type(api, domain):
     kerberos_record_name = kerberos_prefix + domain_suffix
 
     try:
-        result = resolver.query(kerberos_record_name, rdatatype.TXT)
+        result = resolve(kerberos_record_name, rdatatype.TXT)
         answer = result.response.answer
 
         # IPA domain will have only one _kerberos TXT record
@@ -1012,7 +1016,7 @@ def detect_dns_zone_realm_type(api, domain):
 
     try:
         # The presence of this record is enough, return foreign in such case
-        resolver.query(ad_specific_record_name, rdatatype.SRV)
+        resolve(ad_specific_record_name, rdatatype.SRV)
     except DNSException:
         # If we could not detect type with certainty, return unknown
         return 'unknown'
diff --git a/ipapython/dnsutil.py b/ipapython/dnsutil.py
index aec1ec231a..7c4ef7acea 100644
--- a/ipapython/dnsutil.py
+++ b/ipapython/dnsutil.py
@@ -27,6 +27,7 @@
 import dns.resolver
 import dns.rdataclass
 import dns.rdatatype
+import dns.reversename
 
 
 import six
@@ -39,6 +40,85 @@
 logger = logging.getLogger(__name__)
 
 
+ipa_resolver = None
+
+
+def get_ipa_resolver():
+    global ipa_resolver
+    if ipa_resolver is None:
+        ipa_resolver = DNSResolver()
+    return ipa_resolver
+
+
+def resolve(*args, **kwargs):
+    return get_ipa_resolver().resolve(*args, **kwargs)
+
+
+def resolve_address(*args, **kwargs):
+    return get_ipa_resolver().resolve_address(*args, **kwargs)
+
+
+def zone_for_name(*args, **kwargs):
+    if "resolver" not in kwargs:
+        kwargs["resolver"] = get_ipa_resolver()
+
+    return dns.resolver.zone_for_name(*args, **kwargs)
+
+
+def reset_default_resolver():
+    """Re-initialize ipa resolver.
+    """
+    global ipa_resolver
+    ipa_resolver = DNSResolver()
+
+
+class DNSResolver(dns.resolver.Resolver):
+    """DNS stub resolver compatible with both dnspython < 2.0.0
+    and dnspython >= 2.0.0.
+
+    Set `use_search_by_default` attribute to `True`, which
+    determines the default for whether the search list configured
+    in the system's resolver configuration is used for relative
+    names, and whether the resolver's domain may be added to relative
+    names.
+
+    Increase the default lifetime which determines the number of seconds
+    to spend trying to get an answer to the question. dnspython 2.0.0
+    changes this to 5sec, while the previous one was 30sec.
+    """
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.reset_ipa_defaults()
+        self.resolve = getattr(super(), "resolve", self.query)
+        self.resolve_address = getattr(
+            super(),
+            "resolve_address",
+            self._resolve_address
+        )
+
+    def reset_ipa_defaults(self):
+        self.use_search_by_default = True
+        # the default is 5sec
+        self.lifetime = 15
+
+    def reset(self):
+        super().reset()
+        self.reset_ipa_defaults()
+
+    def _resolve_address(self, ip_address, *args, **kwargs):
+        """Query nameservers for PTR records.
+
+        :param ip_address: IPv4 or IPv6 address
+        :type ip_address: str
+        """
+        return resolve(
+            dns.reversename.from_address(ip_address),
+            rdtype=dns.rdatatype.PTR,
+            *args,
+            **kwargs,
+        )
+
+
 class DNSZoneAlreadyExists(dns.exception.DNSException):
     supp_kwargs = {'zone', 'ns'}
     fmt = (u"DNS zone {zone} already exists in DNS "
@@ -321,7 +401,7 @@ def resolve_rrsets(fqdn, rdtypes):
     rrsets = []
     for rdtype in rdtypes:
         try:
-            answer = dns.resolver.query(fqdn, rdtype)
+            answer = resolve(fqdn, rdtype)
             logger.debug('found %d %s records for %s: %s',
                          len(answer),
                          rdtype,
@@ -363,7 +443,7 @@ def check_zone_overlap(zone, raise_on_error=True):
         return
 
     try:
-        containing_zone = dns.resolver.zone_for_name(zone)
+        containing_zone = zone_for_name(zone)
     except dns.exception.DNSException as e:
         msg = ("DNS check for domain %s failed: %s." % (zone, e))
         if raise_on_error:
@@ -374,7 +454,7 @@ def check_zone_overlap(zone, raise_on_error=True):
 
     if containing_zone == zone:
         try:
-            ns = [ans.to_text() for ans in dns.resolver.query(zone, 'NS')]
+            ns = [ans.to_text() for ans in resolve(zone, 'NS')]
         except dns.exception.DNSException as e:
             logger.debug("Failed to resolve nameserver(s) for domain %s: %s",
                          zone, e)
@@ -463,6 +543,8 @@ def query_srv(qname, resolver=None, **kwargs):
     :return: list of dns.rdtypes.IN.SRV.SRV instances
     """
     if resolver is None:
-        resolver = dns.resolver
-    answer = resolver.query(qname, rdtype=dns.rdatatype.SRV, **kwargs)
+        resolve_f = resolve
+    else:
+        resolve_f = getattr(resolver, "resolve", resolver.query)
+    answer = resolve_f(qname, rdtype=dns.rdatatype.SRV, **kwargs)
     return sort_prio_weight(answer)
diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py
index f29126c645..4d3bdead37 100644
--- a/ipapython/ipautil.py
+++ b/ipapython/ipautil.py
@@ -43,9 +43,6 @@
 import collections
 import urllib
 
-from dns import resolver, reversename
-from dns.exception import DNSException
-
 import six
 from six.moves import input
 
@@ -1112,22 +1109,6 @@ def check_port_bindable(port, socket_type=socket.SOCK_STREAM):
         s.close()
 
 
-def reverse_record_exists(ip_address):
-    """
-    Checks if IP address have some reverse record somewhere.
-    Does not care where it points.
-
-    Returns True/False
-    """
-    reverse = reversename.from_address(str(ip_address))
-    try:
-        resolver.query(reverse, "PTR")
-    except DNSException:
-        # really don't care what exception, PTR is simply unresolvable
-        return False
-    return True
-
-
 def config_replace_variables(filepath, replacevars=dict(), appendvars=dict(),
                              removevars=None):
     """
diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
index 90cc9b38bc..4c5e2d690b 100644
--- a/ipaserver/install/bindinstance.py
+++ b/ipaserver/install/bindinstance.py
@@ -30,9 +30,9 @@
 import sys
 import time
 
-import dns.resolver
 import ldap
 import six
+from dns.exception import DNSException
 
 from ipaserver.dns_data_management import (
     IPASystemRecords,
@@ -320,10 +320,15 @@ def read_reverse_zone(default, ip_address, allow_zone_overlap=False):
 def get_auto_reverse_zones(ip_addresses, allow_zone_overlap=False):
     auto_zones = []
     for ip in ip_addresses:
-        if ipautil.reverse_record_exists(ip):
+        try:
+            dnsutil.resolve_address(str(ip))
+        except DNSException:
+            pass
+        else:
             # PTR exist there is no reason to create reverse zone
             logger.info("Reverse record for IP address %s already exists", ip)
             continue
+
         default_reverse = get_reverse_zone_default(ip)
         if not allow_zone_overlap:
             try:
@@ -1135,7 +1140,7 @@ def __setup_resolv_conf(self):
         else:
             # python DNS might have global resolver cached in this variable
             # we have to re-initialize it because resolv.conf has changed
-            dns.resolver.reset_default_resolver()
+            dnsutil.reset_default_resolver()
 
     def __generate_rndc_key(self):
         installutils.check_entropy()
diff --git a/ipaserver/install/dns.py b/ipaserver/install/dns.py
index 132d89f223..f7d793e1de 100644
--- a/ipaserver/install/dns.py
+++ b/ipaserver/install/dns.py
@@ -12,13 +12,9 @@
 import enum
 import logging
 import os
-
-# absolute import is necessary because IPA module dns clashes with python-dns
-from dns import resolver
-import six
-
 import sys
 
+import six
 from subprocess import CalledProcessError
 
 from ipalib import api
@@ -294,7 +290,7 @@ def install_check(standalone, api, replica, options, hostname):
         if not options.forwarders:
             options.forwarders = []
         if options.auto_forwarders:
-            options.forwarders += resolver.get_default_resolver().nameservers
+            options.forwarders += dnsutil.get_ipa_resolver().nameservers
     elif standalone or not replica:
         options.forwarders = read_dns_forwarders()
 
diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py
index a3274d5797..a46acf9f5f 100644
--- a/ipaserver/install/installutils.py
+++ b/ipaserver/install/installutils.py
@@ -38,7 +38,7 @@
 from configparser import ConfigParser as SafeConfigParser
 from configparser import NoOptionError
 
-from dns import resolver, rdatatype
+from dns import rdatatype
 from dns.exception import DNSException
 import ldap
 import six
@@ -53,6 +53,7 @@
 from ipalib.util import validate_hostname
 from ipalib import api, errors, x509
 from ipapython.dn import DN
+from ipapython.dnsutil import resolve, get_ipa_resolver
 from ipaserver.install import certs, service, sysupgrade
 from ipaplatform import services
 from ipaplatform.paths import paths
@@ -187,7 +188,7 @@ def verify_fqdn(host_name, no_host_dns=False, local_hostname=True):
     # Verify this is NOT a CNAME
     try:
         logger.debug('Check if %s is not a CNAME', host_name)
-        resolver.query(host_name, rdatatype.CNAME)
+        resolve(host_name, rdatatype.CNAME)
         raise HostReverseLookupError("The IPA Server Hostname cannot be a CNAME, only A and AAAA names are allowed.")
     except DNSException:
         pass
@@ -284,11 +285,13 @@ def read_ip_addresses():
 def read_dns_forwarders():
     addrs = []
     if ipautil.user_input("Do you want to configure DNS forwarders?", True):
-        print("Following DNS servers are configured in /etc/resolv.conf: %s" %
-                ", ".join(resolver.get_default_resolver().nameservers))
+        print(
+            "Following DNS servers are configured in /etc/resolv.conf: %s"
+            % ", ".join(get_ipa_resolver().nameservers)
+        )
         if ipautil.user_input("Do you want to configure these servers as DNS "
                 "forwarders?", True):
-            addrs = resolver.default_resolver.nameservers[:]
+            addrs = get_ipa_resolver().nameservers[:]
             print("All DNS servers from /etc/resolv.conf were added. You can "
                   "enter additional addresses now:")
         while True:
diff --git a/ipaserver/install/server/replicainstall.py b/ipaserver/install/server/replicainstall.py
index 2990f4382d..c6c438a04a 100644
--- a/ipaserver/install/server/replicainstall.py
+++ b/ipaserver/install/server/replicainstall.py
@@ -9,8 +9,6 @@
 
 import dns.exception as dnsexception
 import dns.name as dnsname
-import dns.resolver as dnsresolver
-import dns.reversename as dnsreversename
 import os
 import shutil
 import socket
@@ -28,6 +26,7 @@
 from ipalib.install.kinit import kinit_keytab
 from ipapython import ipaldap, ipautil
 from ipapython.dn import DN
+from ipapython.dnsutil import DNSResolver
 from ipapython.admintool import ScriptError
 from ipapython.ipachangeconf import IPAChangeConf
 from ipaplatform import services
@@ -289,7 +288,7 @@ def check_dns_resolution(host_name, dns_servers):
         logger.error(
             'Could not resolve any DNS server hostname: %s', dns_servers)
         return False
-    resolver = dnsresolver.Resolver()
+    resolver = DNSResolver()
     resolver.nameservers = server_ips
 
     logger.debug('Search DNS server %s (%s) for %s',
@@ -299,7 +298,7 @@ def check_dns_resolution(host_name, dns_servers):
     addresses = set()
     for rtype in 'A', 'AAAA':
         try:
-            result = resolver.query(host_name, rtype)
+            result = resolver.resolve(host_name, rtype)
         except dnsexception.DNSException:
             rrset = []
         else:
@@ -327,8 +326,7 @@ def check_dns_resolution(host_name, dns_servers):
         checked.add(address)
         try:
             logger.debug('Check reverse address %s (%s)', address, host_name)
-            revname = dnsreversename.from_address(address)
-            rrset = resolver.query(revname, 'PTR').rrset
+            rrset = resolver.resolve_address(address).rrset
         except Exception as e:
             logger.debug('Check failed: %s %s', type(e).__name__, e)
             logger.error(
diff --git a/ipaserver/plugins/cert.py b/ipaserver/plugins/cert.py
index fe7ea34f5d..a5be24af90 100644
--- a/ipaserver/plugins/cert.py
+++ b/ipaserver/plugins/cert.py
@@ -1191,7 +1191,7 @@ def _san_ip_update_reachable(reachable, dnsname, cname_depth):
     """
     fqdn = dnsutil.DNSName(dnsname).make_absolute()
     try:
-        zone = dnsutil.DNSName(resolver.zone_for_name(fqdn))
+        zone = dnsutil.DNSName(dnsutil.zone_for_name(fqdn))
     except resolver.NoNameservers:
         return  # if there's no zone, there are no records
     name = fqdn.relativize(zone)
@@ -1225,7 +1225,7 @@ def _ip_ptr_records(ip):
     """
     rname = dnsutil.DNSName(reversename.from_address(ip))
     try:
-        zone = dnsutil.DNSName(resolver.zone_for_name(rname))
+        zone = dnsutil.DNSName(dnsutil.zone_for_name(rname))
         name = rname.relativize(zone)
         result = api.Command['dnsrecord_show'](zone, name)['result']
     except resolver.NoNameservers:
diff --git a/ipaserver/plugins/dns.py b/ipaserver/plugins/dns.py
index 275e3433e3..919402db1a 100644
--- a/ipaserver/plugins/dns.py
+++ b/ipaserver/plugins/dns.py
@@ -79,9 +79,15 @@
 from ipaplatform import services
 from ipapython.dn import DN
 from ipapython.ipautil import CheckedIPAddress
-from ipapython.dnsutil import check_zone_overlap, DNSZoneAlreadyExists
-from ipapython.dnsutil import DNSName
-from ipapython.dnsutil import related_to_auto_empty_zone
+from ipapython.dnsutil import (
+    check_zone_overlap,
+    DNSName,
+    DNSResolver,
+    DNSZoneAlreadyExists,
+    related_to_auto_empty_zone,
+    resolve,
+    zone_for_name,
+)
 from ipaserver.dns_data_management import (
     IPASystemRecords,
     IPADomainIsNotManagedByIPAError,
@@ -542,7 +548,7 @@ def get_reverse_zone(ipaddr):
     ip = netaddr.IPAddress(str(ipaddr))
     revdns = DNSName(unicode(ip.reverse_dns))
     try:
-        revzone = DNSName(dns.resolver.zone_for_name(revdns))
+        revzone = DNSName(zone_for_name(revdns))
     except dns.resolver.NoNameservers:
         raise errors.NotFound(
             reason=_(
@@ -3363,7 +3369,7 @@ def wait_for_modified_attr(self, ldap_rrset, rdtype, dns_name):
         :raises errors.DNSDataMismatch: if data in DNS and LDAP doesn't match
         :raises dns.exception.DNSException: if DNS resolution failed
         '''
-        resolver = dns.resolver.Resolver()
+        resolver = DNSResolver()
         resolver.set_flags(0)  # disable recursion (for NS RR checks)
         max_attempts = int(self.api.env['wait_for_dns'])
         warn_attempts = max_attempts // 2
@@ -3379,9 +3385,9 @@ def wait_for_modified_attr(self, ldap_rrset, rdtype, dns_name):
                 log_fn = logger.warning
             attempt += 1
             try:
-                dns_answer = resolver.query(dns_name, rdtype,
-                                            dns.rdataclass.IN,
-                                            raise_on_no_answer=False)
+                dns_answer = resolver.resolve(dns_name, rdtype,
+                                              dns.rdataclass.IN,
+                                              raise_on_no_answer=False)
                 dns_rrset = None
                 if rdtype == _NS:
                     # NS records can be in Authority section (sometimes)
@@ -4303,7 +4309,7 @@ def _warning_if_forwarders_do_not_work(self, result, new_zone,
         ipa_dns_ip = None
         for rdtype in (dns.rdatatype.A, dns.rdatatype.AAAA):
             try:
-                ans = dns.resolver.query(ipa_dns_masters[0], rdtype)
+                ans = resolve(ipa_dns_masters[0], rdtype)
             except dns.exception.DNSException:
                 continue
             else:
diff --git a/ipaserver/plugins/host.py b/ipaserver/plugins/host.py
index c31eb59613..6756374db9 100644
--- a/ipaserver/plugins/host.py
+++ b/ipaserver/plugins/host.py
@@ -22,8 +22,6 @@
 
 import logging
 
-import dns.resolver
-
 import six
 
 from ipalib import api, errors, util
@@ -64,7 +62,7 @@
     CheckedIPAddress,
     TMP_PWD_ENTROPY_BITS
 )
-from ipapython.dnsutil import DNSName
+from ipapython.dnsutil import DNSName, zone_for_name
 from ipapython.ssh import SSHPublicKey
 from ipapython.dn import DN
 from ipapython import kerberos
@@ -826,7 +824,7 @@ def pre_callback(self, ldap, dn, *keys, **options):
         if updatedns:
             # Remove A, AAAA, SSHFP and PTR records of the host
             fqdn_dnsname = DNSName(fqdn).make_absolute()
-            zone = DNSName(dns.resolver.zone_for_name(fqdn_dnsname))
+            zone = DNSName(zone_for_name(fqdn_dnsname))
             relative_hostname = fqdn_dnsname.relativize(zone)
 
             # Get all resources for this host
diff --git a/ipatests/pytest_ipa/integration/tasks.py b/ipatests/pytest_ipa/integration/tasks.py
index 21b196933f..fceac1b628 100755
--- a/ipatests/pytest_ipa/integration/tasks.py
+++ b/ipatests/pytest_ipa/integration/tasks.py
@@ -49,6 +49,7 @@
 
 from ipapython import certdb
 from ipapython import ipautil
+from ipapython.dnsutil import DNSResolver
 from ipaplatform.paths import paths
 from ipaplatform.services import knownservices
 from ipapython.dn import DN
@@ -1436,7 +1437,7 @@ def resolve_record(nameserver, query, rtype="SOA", retry=True, timeout=100):
     :timeout: max period of time while method will try to resolve query
      (requires retry=True)
     """
-    res = dns.resolver.Resolver()
+    res = DNSResolver()
     res.nameservers = [nameserver]
     res.lifetime = 10  # wait max 10 seconds for reply
 
@@ -1444,7 +1445,7 @@ def resolve_record(nameserver, query, rtype="SOA", retry=True, timeout=100):
 
     while time.time() < wait_until:
         try:
-            ans = res.query(query, rtype)
+            ans = res.resolve(query, rtype)
             return ans
         except dns.exception.DNSException:
             if not retry:
diff --git a/ipatests/test_integration/test_dns_locations.py b/ipatests/test_integration/test_dns_locations.py
index 1337418b10..aa662abd3f 100644
--- a/ipatests/test_integration/test_dns_locations.py
+++ b/ipatests/test_integration/test_dns_locations.py
@@ -12,7 +12,7 @@
 
 from ipatests.test_integration.base import IntegrationTest
 from ipatests.pytest_ipa.integration import tasks
-from ipapython.dnsutil import DNSName
+from ipapython.dnsutil import DNSName, DNSResolver
 from ipalib.constants import IPA_CA_RECORD
 
 logger = logging.getLogger(__name__)
@@ -45,14 +45,14 @@
 
 def resolve_records_from_server(rname, rtype, nameserver):
     error = None
-    res = dns.resolver.Resolver()
+    res = DNSResolver()
     res.nameservers = [nameserver]
     res.lifetime = 30
     logger.info("Query: %s %s, nameserver %s", rname, rtype, nameserver)
     # lets try to query 3x
     for _i in range(3):
         try:
-            ans = res.query(rname, rtype)
+            ans = res.resolve(rname, rtype)
             logger.info("Answer: %s", ans.rrset)
             return ans.rrset
         except (dns.resolver.NXDOMAIN, dns.resolver.Timeout) as e:
diff --git a/ipatests/test_integration/test_dnssec.py b/ipatests/test_integration/test_dnssec.py
index ccaa7f9b54..62ed62efc8 100644
--- a/ipatests/test_integration/test_dnssec.py
+++ b/ipatests/test_integration/test_dnssec.py
@@ -10,13 +10,13 @@
 import time
 
 import dns.dnssec
-import dns.resolver
 import dns.name
 
 from ipatests.test_integration.base import IntegrationTest
 from ipatests.pytest_ipa.integration import tasks
 from ipatests.pytest_ipa.integration.firewall import Firewall
 from ipaplatform.paths import paths
+from ipapython.dnsutil import DNSResolver
 
 logger = logging.getLogger(__name__)
 
@@ -33,7 +33,7 @@
 
 
 def resolve_with_dnssec(nameserver, query, rtype="SOA"):
-    res = dns.resolver.Resolver()
+    res = DNSResolver()
     res.nameservers = [nameserver]
     res.lifetime = 10  # wait max 10 seconds for reply
     # enable Authenticated Data + Checking Disabled flags
@@ -42,7 +42,7 @@ def resolve_with_dnssec(nameserver, query, rtype="SOA"):
     # enable EDNS v0 + enable DNSSEC-Ok flag
     res.use_edns(0, dns.flags.DO, 0)
 
-    ans = res.query(query, rtype)
+    ans = res.resolve(query, rtype)
     return ans
 
 
_______________________________________________
FreeIPA-devel mailing list -- freeipa-devel@lists.fedorahosted.org
To unsubscribe send an email to freeipa-devel-le...@lists.fedorahosted.org
Fedora Code of Conduct: 
https://docs.fedoraproject.org/en-US/project/code-of-conduct/
List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines
List Archives: 
https://lists.fedorahosted.org/archives/list/freeipa-devel@lists.fedorahosted.org

Reply via email to