]> git.ipfire.org Git - thirdparty/libcgroup.git/commitdiff
ftests: Add cgcreate systemd scope support
authorTom Hromatka <tom.hromatka@oracle.com>
Tue, 4 Apr 2023 22:31:51 +0000 (22:31 +0000)
committerTom Hromatka <tom.hromatka@oracle.com>
Thu, 20 Apr 2023 20:17:30 +0000 (14:17 -0600)
Add support for creating systemd scopes via the cgcreate command
line tool.

Python's subprocess.Popen.communicate() will not return until the
spawned process and all of its children finish running.  This will
cause a cgcreate of a scope to hang because libcgroup creates an
idle process in the newly-created scope.  Add a timeout to the run()
method so that it can complete even when a child process remains.

Signed-off-by: Tom Hromatka <tom.hromatka@oracle.com>
Reviewed-by: Kamalesh Babulal <kamalesh.babulal@oracle.com>
(cherry picked from commit 5fc8e77fc70667a02af20ad62876f715d96c6241)

tests/ftests/cgroup.py
tests/ftests/run.py

index 3be9ba04e02b9350441d796b76440cc5bc84df4b..2d3d31672069d8ca1260bae2dcb235931c138afd 100644 (file)
@@ -127,7 +127,7 @@ class Cgroup(object):
     def create(config, controller_list, cgname, user_name=None,
                group_name=None, dperm=None, fperm=None, tperm=None,
                tasks_user_name=None, tasks_group_name=None, cghelp=False,
-               ignore_systemd=False):
+               ignore_systemd=False, create_scope=False, set_default_scope=False):
         if isinstance(controller_list, str):
             controller_list = [controller_list]
 
@@ -160,9 +160,20 @@ class Cgroup(object):
         if cghelp:
             cmd.append('-h')
 
+        # -b and -c are mutually exclusive but the safety check is done in libcgroup
+        # itself and thus doesn't need to be done here
+
         if ignore_systemd:
             cmd.append('-b')
 
+        if create_scope:
+            cmd.append('-c')
+
+        # -S requires -c to be provided, but this is checked in libcgroup itself
+
+        if set_default_scope:
+            cmd.append('-S')
+
         if controller_list:
             controllers_and_path = '{}:{}'.format(
                 ','.join(controller_list), cgname)
@@ -175,14 +186,23 @@ class Cgroup(object):
         if config.args.container:
             config.container.run(cmd)
         else:
-            Run.run(cmd)
+            if create_scope:
+                # creating a scope causes libcgroup to create a child process.
+                # subprocess.Popen.communicate() will not return until the created
+                # process and all of its children complete.  Get around this by
+                # timing out the operation
+                Run.run(cmd, timeout=5)
+            else:
+                Run.run(cmd)
 
     # This is a simple wrapper, that calls Cgroup.create() to create the
     # cgroup and cgroup_exists(), which builds the cgroup path and returns
     # True if the cgroup exists, False otherwise
     @staticmethod
-    def create_and_validate(config, ctrl_name, cgroup_name, ignore_systemd=False):
-        Cgroup.create(config, ctrl_name, cgroup_name, ignore_systemd=ignore_systemd)
+    def create_and_validate(config, ctrl_name, cgroup_name, ignore_systemd=False,
+                            create_scope=False, set_default_scope=False):
+        Cgroup.create(config, ctrl_name, cgroup_name, ignore_systemd=ignore_systemd,
+                      create_scope=create_scope, set_default_scope=set_default_scope)
         return Cgroup.exists(config, ctrl_name, cgroup_name, ignore_systemd=ignore_systemd)
 
     @staticmethod
index d7e844319d89f9e1dcd764d2a33b8cbb3b8bf3e6..b6bd3824920403bab609e6e99e682d994ecd3040 100644 (file)
@@ -6,13 +6,14 @@
 # Author: Tom Hromatka <tom.hromatka@oracle.com>
 #
 
+from subprocess import TimeoutExpired
 from log import Log
 import subprocess
 
 
 class Run(object):
     @staticmethod
-    def run(command, shell_bool=False, ignore_profiling_errors=True):
+    def run(command, shell_bool=False, ignore_profiling_errors=True, timeout=None):
         if shell_bool:
             if isinstance(command, str):
                 # nothing to do.  command is already formatted as a string
@@ -25,11 +26,34 @@ class Run(object):
         subproc = subprocess.Popen(command, shell=shell_bool,
                                    stdout=subprocess.PIPE,
                                    stderr=subprocess.PIPE)
-        out, err = subproc.communicate()
-        ret = subproc.returncode
 
-        out = out.strip().decode('UTF-8')
-        err = err.strip().decode('UTF-8')
+        if timeout:
+            try:
+                out, err = subproc.communicate(timeout=timeout)
+                ret = subproc.returncode
+
+                out = out.strip().decode('UTF-8')
+                err = err.strip().decode('UTF-8')
+            except TimeoutExpired as te:
+                if te.stdout:
+                    out = te.stdout.strip().decode('UTF-8')
+                else:
+                    out = ''
+                if te.stderr:
+                    err = te.stderr.strip().decode('UTF-8')
+                else:
+                    err = ''
+
+                if len(err):
+                    ret = -1
+                else:
+                    ret = 0
+        else:
+            out, err = subproc.communicate()
+            ret = subproc.returncode
+
+            out = out.strip().decode('UTF-8')
+            err = err.strip().decode('UTF-8')
 
         if shell_bool:
             Log.log_debug(