]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
qa: clean up dnsmasq task and fix EPERM error 20680/head
authorCasey Bodley <cbodley@redhat.com>
Mon, 19 Feb 2018 18:36:05 +0000 (13:36 -0500)
committerCasey Bodley <cbodley@redhat.com>
Thu, 1 Mar 2018 20:55:57 +0000 (15:55 -0500)
Signed-off-by: Casey Bodley <cbodley@redhat.com>
qa/tasks/dnsmasq.py

index ee01b17955e658357444057d9072cc4a8cc29253..7f675f3bc29f04b2ef3927634dea756e6cda6a6f 100644 (file)
@@ -7,42 +7,89 @@ import logging
 from teuthology import misc
 from teuthology.exceptions import ConfigError
 from teuthology import contextutil
+from teuthology import packaging
 from util import get_remote_for_role
 
 log = logging.getLogger(__name__)
 
 @contextlib.contextmanager
-def setup_dnsmasq(remote, cnames):
+def install_dnsmasq(remote):
+    """
+    If dnsmasq is not installed, install it for the duration of the task.
+    """
+    try:
+        existing = packaging.get_package_version(remote, 'dnsmasq')
+    except:
+        existing = None
+
+    if existing is None:
+        packaging.install_package('dnsmasq', remote)
+    try:
+        yield
+    finally:
+        if existing is None:
+            packaging.remove_package('dnsmasq', remote)
+
+@contextlib.contextmanager
+def backup_resolv(remote, path):
+    """
+    Store a backup of resolv.conf in the testdir and restore it after the task.
+    """
+    remote.run(args=['cp', '/etc/resolv.conf', path])
+    try:
+        yield
+    finally:
+        # restore with 'cp' to avoid overwriting its security context
+        remote.run(args=['sudo', 'cp', path, '/etc/resolv.conf'])
+        remote.run(args=['rm', path])
+
+@contextlib.contextmanager
+def replace_resolv(remote, path):
+    """
+    Update resolv.conf to point the nameserver at localhost.
+    """
+    misc.write_file(remote, path, "nameserver 127.0.0.1\n")
+    try:
+        # install it
+        remote.run(args=['sudo', 'cp', path, '/etc/resolv.conf'])
+        yield
+    finally:
+        remote.run(args=['rm', path])
+
+@contextlib.contextmanager
+def setup_dnsmasq(remote, testdir, cnames):
     """ configure dnsmasq on the given remote, adding each cname given """
     log.info('Configuring dnsmasq on remote %s..', remote.name)
 
-    # back up existing resolv.conf
-    resolv_conf = misc.get_file(remote, '/etc/resolv.conf')
-    # point resolv.conf to local dnsmasq
-    misc.sudo_write_file(remote, '/etc/resolv.conf',
-                         "nameserver 127.0.0.1\n")
-
-    # add address entries to /etc/dnsmasq.d/ceph
+    # 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.iteritems():
         dnsmasq += address_template.format(cname=cname, ip_address=ip_address)
-    misc.sudo_write_file(remote, '/etc/dnsmasq.d/ceph', dnsmasq)
 
-    remote.run(args=['cat', '/etc/dnsmasq.d/ceph'])
+    # write to temporary dnsmasq file
+    dnsmasq_tmp = '/'.join((testdir, 'ceph.tmp'))
+    misc.write_file(remote, dnsmasq_tmp, dnsmasq)
+
+    # move into /etc/dnsmasq.d/
+    dnsmasq_path = '/etc/dnsmasq.d/ceph'
+    remote.run(args=['sudo', 'mv', dnsmasq_tmp, dnsmasq_path])
+    # restore selinux context if necessary
+    remote.run(args=['sudo', 'restorecon', dnsmasq_path], check_status=False)
+
     # restart dnsmasq
     remote.run(args=['sudo', 'systemctl', 'restart', 'dnsmasq'])
-    remote.run(args=['sudo', 'systemctl', 'status', 'dnsmasq'])
     # verify dns name is set
     remote.run(args=['ping', '-c', '4', cnames.keys()[0]])
 
-    yield
-
-    log.info('Removing dnsmasq configuration from remote %s..', remote.name)
-    # restore resolv.conf
-    misc.sudo_write_file(remote, '/etc/resolv.conf', resolv_conf)
-    # restart dnsmasq
-    remote.run(args=['sudo', 'systemctl', 'restart', 'dnsmasq'])
+    try:
+        yield
+    finally:
+        log.info('Removing dnsmasq configuration from remote %s..', remote.name)
+        # remove /etc/dnsmasq.d/ceph
+        remote.run(args=['sudo', 'rm', dnsmasq_path])
+        # restart dnsmasq
+        remote.run(args=['sudo', 'systemctl', 'restart', 'dnsmasq'])
 
 @contextlib.contextmanager
 def task(ctx, config):
@@ -65,6 +112,13 @@ def task(ctx, config):
             client.0:
               client.0.example.com: client.0
               client.1.example.com: client.1
+
+    Cnames that end with a . are treated as prefix for the existing hostname.
+    For example, if the remote for client.0 has a hostname of 'example.com',
+    this task will add cnames for dev.example.com and test.example.com:
+
+        - dnsmasq:
+            client.0: [dev., test.]
     """
     # apply overrides
     overrides = config.get('overrides', {})
@@ -82,6 +136,8 @@ def task(ctx, config):
         if isinstance(cnames, list):
             # when given a list of cnames, point to local ip
             for cname in cnames:
+                if cname.endswith('.'):
+                    cname += remote.hostname
                 names[cname] = remote.ip_address
         elif isinstance(cnames, dict):
             # when given a dict, look up the remote ip for each
@@ -89,14 +145,23 @@ def task(ctx, config):
                 r = get_remote_for_role(ctx, client)
                 if r is None:
                     raise ConfigError('no remote for role %s' % client)
+                if cname.endswith('.'):
+                    cname += r.hostname
                 names[cname] = r.ip_address
 
         remote_names[remote] = names
 
-    # run a subtask for each unique remote
+    testdir = misc.get_testdir(ctx)
+    resolv_bak = '/'.join((testdir, 'resolv.bak'))
+    resolv_tmp = '/'.join((testdir, 'resolv.tmp'))
+
+    # run subtasks for each unique remote
     subtasks = []
     for remote, cnames in remote_names.iteritems():
-        subtasks.extend([ lambda r=remote, cn=cnames: setup_dnsmasq(r, cn) ])
+        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) ])
 
     with contextutil.nested(*subtasks):
         yield