From: Kyr Shatskyy Date: Tue, 9 Dec 2025 22:42:08 +0000 (+0100) Subject: qa/tasks/dnsmasq: preserve nameserver for future use X-Git-Tag: testing/wip-pdonnell-testing-20260127.160833-debug~22^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=927c01be7986c39fd20b2643630f91e37042cf8f;p=ceph-ci.git qa/tasks/dnsmasq: preserve nameserver for future use While backing the resolv.conf up, we preserve nameserver address for future use when it's needed to compose a dnsmasq config, so current host resolution remains working. Fixes: https://tracker.ceph.com/issues/74211 Fixes: https://tracker.ceph.com/issues/43744 Signed-off-by: Kyr Shatskyy --- diff --git a/qa/tasks/dnsmasq.py b/qa/tasks/dnsmasq.py index df8ccecb1f5..ea6b0bbf5ac 100644 --- a/qa/tasks/dnsmasq.py +++ b/qa/tasks/dnsmasq.py @@ -3,6 +3,7 @@ Task for dnsmasq configuration """ import contextlib import logging +import re from teuthology import misc from teuthology.exceptions import ConfigError @@ -31,11 +32,16 @@ def install_dnsmasq(remote): packaging.remove_package('dnsmasq', remote) @contextlib.contextmanager -def backup_resolv(remote, path): +def backup_resolv(remote, path, table): """ Store a backup of resolv.conf in the testdir and restore it after the task. + Reserve 'nameserver' values per remote name in lookup 'table' for future use. """ - remote.run(args=['cp', '/etc/resolv.conf', path]) + resolv_conf = remote.sh(f"cat /etc/resolv.conf | tee {path}") + nameserver_re = re.compile(r'\s*nameserver\s+([^\s]*)') + for line in resolv_conf.split('\n'): + if m := nameserver_re.match(line): + table.setdefault(remote.name, {}).setdefault('nameserver', []).append(m[1]) try: yield finally: @@ -44,7 +50,7 @@ def backup_resolv(remote, path): remote.run(args=['rm', path]) @contextlib.contextmanager -def replace_resolv(remote, path): +def replace_resolv(remote, path, table): """ Update resolv.conf to point the nameserver at localhost. """ @@ -60,28 +66,36 @@ def replace_resolv(remote, path): remote.run(args=['rm', path]) @contextlib.contextmanager -def setup_dnsmasq(remote, testdir, cnames): +def setup_dnsmasq(remote, testdir, cnames, table): """ configure dnsmasq on the given remote, adding each cname given """ log.info('Configuring dnsmasq on remote %s..', remote.name) + # banner first + dnsmasq = ["# This file is generated by dnsmasq teuthology task", ""] + + # lookup previously used nameservers for the remote in the table + servers = table.get(remote.name, {}).get('nameserver', None) + if servers: + log.info('Reusing nameservers: %s', servers) + dnsmasq.extend(f"server={a}" for a in servers) + else: + log.info('No predefined nameservers found, using 8.8.x.x') + dnsmasq.extend(["server=8.8.8.8", "server=8.8.4.4"]) - # add address entries for each cname - dnsmasq = "server=8.8.8.8\nserver=8.8.4.4\n" - address_template = "address=/{cname}/{ip_address}\n" for cname, ip_address in cnames.items(): - dnsmasq += address_template.format(cname=cname, ip_address=ip_address) + dnsmasq.append(f"address=/{cname}/{ip_address}") - # write to temporary dnsmasq file - dnsmasq_tmp = '/'.join((testdir, 'ceph.tmp')) - remote.write_file(dnsmasq_tmp, dnsmasq) - - # move into /etc/dnsmasq.d/ + dnsmasq.append('') + dnsmasq_data = "\n".join(dnsmasq) dnsmasq_path = '/etc/dnsmasq.d/ceph' - remote.run(args=['sudo', 'mv', dnsmasq_tmp, dnsmasq_path]) + remote.sudo_write_file(dnsmasq_path, dnsmasq_data) # restore selinux context if necessary remote.run(args=['sudo', 'restorecon', dnsmasq_path], check_status=False) # restart dnsmasq remote.run(args=['sudo', 'systemctl', 'restart', 'dnsmasq']) + # some pause is required for dnsmasq to become operational, + # though, trying to just print out the config now instead + remote.sh(f'cat {dnsmasq_path}') # verify dns name is set remote.run(args=['ping', '-c', '4', next(iter(cnames.keys()))]) @@ -157,14 +171,15 @@ def task(ctx, config): testdir = misc.get_testdir(ctx) resolv_bak = '/'.join((testdir, 'resolv.bak')) resolv_tmp = '/'.join((testdir, 'resolv.tmp')) + resolv_tbl = dict() # { remote.name -> nameserver list } lookup table # run subtasks for each unique remote subtasks = [] for remote, cnames in remote_names.items(): subtasks.extend([ lambda r=remote: install_dnsmasq(r) ]) - subtasks.extend([ lambda r=remote: backup_resolv(r, resolv_bak) ]) - subtasks.extend([ lambda r=remote: replace_resolv(r, resolv_tmp) ]) - subtasks.extend([ lambda r=remote, cn=cnames: setup_dnsmasq(r, testdir, cn) ]) + subtasks.extend([ lambda r=remote: backup_resolv(r, resolv_bak, resolv_tbl) ]) + subtasks.extend([ lambda r=remote: replace_resolv(r, resolv_tmp, resolv_tbl) ]) + subtasks.extend([ lambda r=remote, cn=cnames: setup_dnsmasq(r, testdir, cn, resolv_tbl) ]) with contextutil.nested(*subtasks): yield