#9972 Nightly failure in test_replica_promotion.py::TestReplicaPromotionRandomPassword::test_replica_two_step_install
Closed: fixed by sumenon. Opened by frenaud.

Issue

The nightly test test_replica_promotion.py::TestReplicaPromotionRandomPassword::test_replica_two_step_install is failing when it gets executed in the downstream CI.

Logs in https://$ARTIFACTS_SERVER/idm-ci/freeipa_upstream_nightly/Nightly-latest-testing-repo/master/2026-04-08_09-50/latest-testing-repo/test_replica_promotion_TestReplicaPromotionRandomPassword/2/report.html?sort=result

Steps to Reproduce

  1. Launch the test test_integration/test_replica_promotion.py::TestReplicaPromotionRandomPassword

Actual behavior

The test fails in a call to ipa host-add replica.ipa.test --random because the replica doesn't have a DNS A record.

args = (<ipatests.test_integration.test_replica_promotion.TestReplicaPromotionRandomPassword object at 0x7f72497edd10>,)
    def wrapped(*args):
>       func(*args)
args       = (<ipatests.test_integration.test_replica_promotion.TestReplicaPromotionRandomPassword object at 0x7f72497edd10>,)
func       = <function TestReplicaPromotionRandomPassword.test_replica_two_step_install at 0x7f724983be20>
pytest_ipa/integration/tasks.py:1865: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test_integration/test_replica_promotion.py:1431: in test_replica_two_step_install
    randpasswd = tasks.host_add_with_random_password(self.master,
        replica    = <ipatests.pytest_ipa.integration.host.Host replica.ufreeipa.test (replica)>
        self       = <ipatests.test_integration.test_replica_promotion.TestReplicaPromotionRandomPassword object at 0x7f72497edd10>
pytest_ipa/integration/tasks.py:3389: in host_add_with_random_password
    cmd = host.run_command(
        host       = <ipatests.pytest_ipa.integration.host.Host master.ufreeipa.test (master)>
        new_host   = <ipatests.pytest_ipa.integration.host.Host replica.ufreeipa.test (replica)>
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
self = <ipatests.pytest_ipa.integration.host.Host master.ufreeipa.test (master)>
argv = ['ipa', 'host-add', 'replica.ufreeipa.test', '--random'], set_env = True
stdin_text = None, log_stdout = True, raiseonerr = True, cwd = None, bg = False
encoding = 'utf-8', ok_returncode = 0
    def run_command(self, argv, set_env=True, stdin_text=None,
                    log_stdout=True, raiseonerr=True,
                    cwd=None, bg=False, encoding='utf-8', ok_returncode=0):
        """Wrapper around run_command to log stderr on raiseonerr=True
        :param ok_returncode: return code considered to be correct,
                              you can pass an integer or sequence of integers
        """
        result = super().run_command(
            argv, set_env=set_env, stdin_text=stdin_text,
            log_stdout=log_stdout, raiseonerr=False, cwd=cwd, bg=bg,
            encoding=encoding
        )
        # in FIPS mode SSH may print noise to stderr, remove the string
        # "FIPS mode initialized" + optional newline.
        result.stderr_bytes = FIPS_NOISE_RE.sub(b'', result.stderr_bytes)
        try:
            result_ok = result.returncode in ok_returncode
        except TypeError:
            result_ok = result.returncode == ok_returncode
        if not result_ok and raiseonerr:
            result.log.error('stderr: %s', result.stderr_text)
>           raise subprocess.CalledProcessError(
                result.returncode, argv,
                result.stdout_text, result.stderr_text
            )
E           subprocess.CalledProcessError: Command '['ipa', 'host-add', 'replica.ufreeipa.test', '--random']' returned non-zero exit status 1.
__class__  = <class 'ipatests.pytest_ipa.integration.host.Host'>
argv       = ['ipa', 'host-add', 'replica.ufreeipa.test', '--random']
bg         = False
cwd        = None
encoding   = 'utf-8'
log_stdout = True
ok_returncode = 0
raiseonerr = True
result     = <pytest_multihost.transport.SSHCommand object at 0x7f7248e91fd0>
result_ok  = False
self       = <ipatests.pytest_ipa.integration.host.Host master.ufreeipa.test (master)>
set_env    = True
stdin_text = None
pytest_ipa/integration/host.py:202: CalledProcessError
----------------------------- Captured stderr call -----------------------------
ipa: ERROR: stderr: ipa: ERROR: Host 'replica.ufreeipa.test' does not have corresponding DNS A/AAAA record

Expected behavior

The test should setup the DNS A record.

Additional info:

The issue happens because the test uses a flaky method add_a_record() in order to add the DNS A record. The method checks first if a DNS record exists, if not it adds the DNS A record.
If there is a SSHFP record for the replica, the method doesn't add the DNS A record:

INFO     ipatests.pytest_ipa.integration.host.Host.master.IPAOpenSSHTransport:transport.py:391 RUN ['ipa', 'dnsrecord-show', 'ufreeipa.test', 'replica.ufreeipa.test.']
DEBUG    ipatests.pytest_ipa.integration.host.Host.master.cmd75:transport.py:513 RUN ['ipa', 'dnsrecord-show', 'ufreeipa.test', 'replica.ufreeipa.test.']
DEBUG    ipatests.pytest_ipa.integration.host.Host.master.cmd75:transport.py:557   Record name: replica
DEBUG    ipatests.pytest_ipa.integration.host.Host.master.cmd75:transport.py:557   SSHFP record: 1 1 BBEC26C3C5384FA8B1B519A159F9D88406702189, 1 2 11C78E3D1E1EB527BC50B527CF12748BB9950ACB82ED0B8850AFD528 895C38AC, 3 1 E7CA3FC0672182B7BA02F8CC27D9234E09920F0F, 3 2 26948CFBDD60A2A791A01951D344C3F53B1BE4F96094753CB937C7C5 7F9DC987, 4 1 E146E06CD141B951BB1EF4130186ADC7EE9238CC, 4 2 B5669079EEC95784C19E712C61750F3270B1F8AF24B6B6B07347586B 58B3E8D7
DEBUG    ipatests.pytest_ipa.integration.host.Host.master.cmd75:transport.py:217 Exit code: 0
INFO     ipatests.pytest_ipa.integration.host.Host.master.IPAOpenSSHTransport:transport.py:391 RUN ['kinit', 'admin']
DEBUG    ipatests.pytest_ipa.integration.host.Host.master.cmd76:transport.py:513 RUN ['kinit', 'admin']
DEBUG    ipatests.pytest_ipa.integration.host.Host.master.cmd76:transport.py:557 Password for admin@UFREEIPA.TEST: 
DEBUG    ipatests.pytest_ipa.integration.host.Host.master.cmd76:transport.py:217 Exit code: 0
INFO     ipatests.pytest_ipa.integration.host.Host.master.IPAOpenSSHTransport:transport.py:391 RUN ['ipa', 'host-add', 'replica.ufreeipa.test', '--random']
DEBUG    ipatests.pytest_ipa.integration.host.Host.master.cmd77:transport.py:513 RUN ['ipa', 'host-add', 'replica.ufreeipa.test', '--random']
DEBUG    ipatests.pytest_ipa.integration.host.Host.master.cmd77:transport.py:557 ipa: ERROR: Host 'replica.ufreeipa.test' does not have corresponding DNS A/AAAA record
DEBUG    ipatests.pytest_ipa.integration.host.Host.master.cmd77:transport.py:217 Exit code: 1

The method add_a_rec should be modified and check if a DNS A record exists.

https://pagure.io/freeipa/blob/master/f/ipatests/pytest_ipa/integration/tasks.py#_1614-1628:

def add_a_record(master, host):
    # Find out if the record is already there
    cmd = master.run_command(['ipa',
                              'dnsrecord-show',
                              master.domain.name,
                              host.hostname + "."],
                              raiseonerr=False) 
    # If not, add it
    if cmd.returncode != 0:           <<<<< HERE the command can return 0 if another type of record exists
        master.run_command(['ipa',
                            'dnsrecord-add',
                            master.domain.name,
                            host.hostname + ".",
                            '--a-rec', host.ip])

Metadata Update from @frenaud:
- Issue assigned to frenaud
- Issue tagged with: tests

Metadata Update from @frenaud:
- Custom field on_review adjusted to https://github.com/freeipa/freeipa/pull/8317

master:

  • 628404016d7ab8bcfc6f940e7ef40928f375168e ipatests: fix the method add_a_record
  • 1b4c20c464a8a6c8dc6b929822f9ebe6ee150b61 Temp commit

ipa-4-12:

  • 93fdac93d76be43739976d30ac1e2de8cf8bd148 ipatests: fix the method add_a_record

ipa-4-13:

  • 922a24a9ba2f626077ccdb699069775cc01a6bce ipatests: fix the method add_a_record

Metadata Update from @sumenon:
- Issue close_status updated to: fixed
- Issue status updated to: Closed (was: Open)

Metadata