]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
qa/cephfs: run nsenter commands with superuser privileges
authorRishabh Dave <ridave@redhat.com>
Wed, 29 Apr 2020 18:10:16 +0000 (23:40 +0530)
committerRishabh Dave <ridave@redhat.com>
Tue, 2 Jun 2020 11:37:49 +0000 (17:07 +0530)
And add a method that sets self.fuse_daemon.subproc.pid to the PID of
the process that doesn't have sudo in its arguments. For example, when
"sudo ceph-fuse /mnt/cephfs" is run on the shell, it launches process
with arguments "ceph-fuse /mnt/cephfs". The added method gets PID of
latter/child process and sets that as the fuse daemon's PID. Not doing
so kills the former/parent process but the not the child process.

Also, since we are around cleanup this method a bit.

Fixes: https://tracker.ceph.com/issues/45339
Signed-off-by: Rishabh Dave <ridave@redhat.com>
qa/tasks/vstart_runner.py

index d957ef0862b4d038478ec93eca9a7917b3eaaf39..eb840a24af8998924f56fe06f86c3ddcb4e9c29d 100644 (file)
@@ -53,6 +53,7 @@ from teuthology.orchestra.run import Raw, quote
 from teuthology.orchestra.daemon import DaemonGroup
 from teuthology.orchestra.remote import Remote
 from teuthology.config import config as teuth_config
+from teuthology.contextutil import safe_while
 import six
 import logging
 
@@ -164,6 +165,11 @@ class LocalRemoteProcess(object):
         self.subproc = subproc
         self.stdout = stdout or BytesIO()
         self.stderr = stderr or BytesIO()
+        # this variable is meant for instance of this class named fuse_daemon.
+        # child process of the command launched with sudo must be killed,
+        # since killing parent process alone has no impact on the child
+        # process.
+        self.fuse_pid = -1
 
         self.check_status = check_status
         self.exitstatus = self.returncode = None
@@ -222,7 +228,10 @@ class LocalRemoteProcess(object):
         if self.subproc.pid and not self.finished:
             log.info("kill: killing pid {0} ({1})".format(
                 self.subproc.pid, self.args))
-            safe_kill(self.subproc.pid)
+            if self.fuse_pid != -1:
+                safe_kill(self.fuse_pid)
+            else:
+                safe_kill(self.subproc.pid)
         else:
             log.info("kill: already terminated ({0})".format(self.args))
 
@@ -585,8 +594,7 @@ class LocalKernelMount(KernelMount):
                 if asok_conf:
                     d = asok_conf.groups(1)[0]
                     break
-        path = "{0}/client.{1}.{2}.asok".format(d, self.client_id, self.fuse_daemon.subproc.pid)
-        log.info("I think my launching pid was {0}".format(self.fuse_daemon.subproc.pid))
+        path = "{0}/client.{1}.*.asok".format(d, self.client_id)
         return path
 
     def mount(self, mount_path=None, mount_fs_name=None, mount_options=[]):
@@ -689,8 +697,7 @@ class LocalFuseMount(FuseMount):
                 if asok_conf:
                     d = asok_conf.groups(1)[0]
                     break
-        path = "{0}/client.{1}.{2}.asok".format(d, self.client_id, self.fuse_daemon.subproc.pid)
-        log.info("I think my launching pid was {0}".format(self.fuse_daemon.subproc.pid))
+        path = "{0}/client.{1}.*.asok".format(d, self.client_id)
         return path
 
     def mount(self, mount_path=None, mount_fs_name=None, mountpoint=None, mount_options=[]):
@@ -725,29 +732,26 @@ class LocalFuseMount(FuseMount):
         pre_mount_conns = list_connections()
         log.info("Pre-mount connections: {0}".format(pre_mount_conns))
 
-        prefix = [os.path.join(BIN_PREFIX, "ceph-fuse")]
+        prefix = ['sudo', 'nsenter',
+                  '--net=/var/run/netns/{0}'.format(self.netns_name),
+                  '--setuid', str(os.getuid()),
+                  os.path.join(BIN_PREFIX, "ceph-fuse")]
         if os.getuid() != 0:
             prefix += ["--client_die_on_failed_dentry_invalidate=false"]
-
         if mount_path is not None:
             prefix += ["--client_mountpoint={0}".format(mount_path)]
-
         if mount_fs_name is not None:
             prefix += ["--client_fs={0}".format(mount_fs_name)]
-
         prefix += mount_options;
+        fuse_cmd_args = prefix + ["-f", "--name",
+                                  "client.{0}".format(self.client_id),
+                                  self.mountpoint]
 
-        self.fuse_daemon = self.client_remote.run(args=
-                                            ['nsenter',
-                                             '--net=/var/run/netns/{0}'.format(self.netns_name),
-                                            ] + prefix + [
-                                                "-f",
-                                                "--name",
-                                                "client.{0}".format(self.client_id),
-                                                self.mountpoint
-                                            ], wait=False)
-
-        log.info("Mounting client.{0} with pid {1}".format(self.client_id, self.fuse_daemon.subproc.pid))
+        self.fuse_daemon = self.client_remote.run(args=fuse_cmd_args,
+                                                  wait=False)
+        self._set_fuse_daemon_pid()
+        log.info("Mounting client.{0} with pid "
+                 "{1}".format(self.client_id, self.fuse_daemon.subproc.pid))
 
         # Wait for the connection reference to appear in /sys
         waited = 0
@@ -780,6 +784,20 @@ class LocalFuseMount(FuseMount):
         self.gather_mount_info()
 
         self.mounted = True
+    def _set_fuse_daemon_pid(self):
+        # NOTE: When a command <args> is launched with sudo, two processes are
+        # launched, one with sudo in <args> and other without. Make sure we
+        # get the PID of latter one.
+        with safe_while(sleep=1, tries=15) as proceed:
+            while proceed():
+                try:
+                    sock = self.find_admin_socket()
+                except (RuntimeError, CommandFailedError):
+                    continue
+
+                self.fuse_daemon.fuse_pid = int(re.match(".*\.(\d+)\.asok$",
+                                                         sock).group(1))
+                break
 
     def _run_python(self, pyscript, py_version='python'):
         """