]> git.ipfire.org Git - thirdparty/libcgroup.git/commitdiff
ftests: Rework test 071 to use cgroup_write_systemd_default_cgroup()
authorTom Hromatka <tom.hromatka@oracle.com>
Wed, 24 May 2023 13:34:51 +0000 (07:34 -0600)
committerTom Hromatka <tom.hromatka@oracle.com>
Mon, 3 Jul 2023 15:00:19 +0000 (09:00 -0600)
cgroup_write_systemd_default_cgroup() populates libcgroup's /var/run
file with the default slice/scope.  No verification is done at the time
of writing.

cgroup_set_default_systemd_cgroup() reads the /var/run file and verifies
that it points to a valid path.  If so, it populates libcgroup's global
variable, systemd_default_cgroup.  systemd_default_cgroup is then used
in any subsequent building of libcgroup paths.

Previously, test 071 tested cgroup_set_default_systemd_cgroup() but it
didn't exercise cgroup_write_systemd_default_cgroup().  Rework test 071
to exercise the most likely combinations of writing/setting the default
path that a user would encounter.

-----------------------------------------------------------------
Test Results:
Run Date:                          May 24 07:32:54
Passed:                                  1 test(s)
Skipped:                                 0 test(s)
Failed:                                  0 test(s)
-----------------------------------------------------------------
Timing Results:
Test                                       Time (sec)
-----------------------------------------------------
setup                                            0.00
071-sudo-set_default_systemd_cgroup.py           4.67
teardown                                         0.00
-----------------------------------------------------
Total Run Time                                   4.67

Signed-off-by: Tom Hromatka <tom.hromatka@oracle.com>
Reviewed-by: Kamalesh Babulal <kamalesh.babulal@oracle.com>
tests/ftests/071-sudo-set_default_systemd_cgroup.py

index 29c822e69fd1c8129b8d44c042a53215ecc551fe..231199beb74487641c11aad0b7d8a34730b62223 100755 (executable)
@@ -5,30 +5,24 @@
 #
 # Copyright (c) 2023 Oracle and/or its affiliates.
 # Author: Kamalesh Babulal <kamalesh.babulal@oracle.com>
+# Author: Tom Hromatka <tom.hromatka@oracle.com>
 #
 
-from cgroup import Cgroup as CgroupCli, Mode
-from libcgroup import Version, Cgroup
+from libcgroup import Version, Cgroup, Mode
+from cgroup import Cgroup as CgroupCli
+from process import Process
 import consts
 import ftests
+import time
 import sys
 import os
 
 
-CONTROLLER = 'cpu'
-SYSTEMD_CGNAME = '071_cg_in_scope'
 OTHER_CGNAME = '071_cg_not_in_scope'
-
 SLICE = 'libcgtests.slice'
 SCOPE = 'test071.scope'
 
-CONFIG_FILE_NAME = os.path.join(os.getcwd(), '071cgconfig.conf')
-SYSTEMD_DEFAULT_CGROUP_DIR = '/var/run/libcgroup'
-SYSTEMD_DEFAULT_CGROUP_FILE = '/var/run/libcgroup/systemd'
-
-# List of libcgroup.Cgroup objects
-CGRPS_LIST = list()
-MODE = Mode.CGROUP_MODE_UNK
+CONTROLLER = 'cpu'
 
 
 def prereqs(config):
@@ -42,116 +36,130 @@ def prereqs(config):
     return result, cause
 
 
-def create_cgrp(config, CGNAME, controller=CONTROLLER, ignore_systemd=False):
-    global CGRPS_LIST, MODE
-
-    result = consts.TEST_PASSED
-    cause = None
-
-    cgrp = Cgroup(CGNAME, Version.CGROUP_V1)
-    if controller is not None:
-        cgrp.add_controller(controller)
-    cgrp.create()
-
-    if not CgroupCli.exists(config, controller, CGNAME, ignore_systemd=ignore_systemd):
-        result = consts.TEST_FAILED
-        if MODE == Mode.CGROUP_MODE_UNIFIED:
-            cause = 'Failed to create {}'.format(os.path.join('/sys/fs/cgroup', CGNAME))
-        else:
-            cause = (
-                        'Failed to create {}'
-                        ''.format(os.path.join('/sys/fs/cgroup', (controller or ''), CGNAME))
-                    )
-        return result, cause
-
-    CGRPS_LIST.append(cgrp)
-
-    return result, cause
-
-
 def setup(config):
-    global MODE
+    pass
+
 
+def test(config):
     result = consts.TEST_PASSED
     cause = None
 
-    # probe the current cgroup set up mode
-    MODE = Cgroup.cgroup_mode()
-
-    if not os.path.isdir(SYSTEMD_DEFAULT_CGROUP_DIR):
-        os.mkdir(SYSTEMD_DEFAULT_CGROUP_DIR)
+    #
+    # Test 1 - Ensure __set_default_systemd_cgroup() throws an exception if
+    #          libcgroup doesn't set a default (slice/scope) cgroup path
+    #
+    try:
+        Cgroup.__set_default_systemd_cgroup()
+    except RuntimeError as re:
+        if 'Failed to set' not in str(re):
+            result = consts.TEST_FAILED
+            cause = 'Expected \'Failed to set\' to be in the exception, ' \
+                    'received {}'.format(str(re))
+    else:
+        result = consts.TEST_FAILED
+        cause = '__set_default_systemd_cgroup() erroneously passed'
+
+    #
+    # Test 2 - write_default_systemd_scope() should succeed if the slice/scope
+    #          are invalid and we're not setting it as the default.  If we
+    #          create a cgroup at this point, it should be created at the root
+    #          cgroup level, and the default slice/scope should have no bearing
+    #
+    Cgroup.write_default_systemd_scope(SLICE, SCOPE, False)
+
+    pid = config.process.create_process(config)
+    cg = Cgroup(OTHER_CGNAME, Version.CGROUP_V2)
+    cg.add_controller(CONTROLLER)
+    cg.create()
+    Cgroup.move_process(pid, OTHER_CGNAME, CONTROLLER)
+    cg_pid = cg.get_processes()[0]
+
+    if pid != cg_pid:
+        result = consts.TEST_FAILED
+        tmp_cause = 'Expected pid {} to be in {} cgroup, but received pid {} ' \
+                    'via python bindings instead'.format(pid, OTHER_CGNAME, cg_pid)
+        cause = '\n'.join(filter(None, [cause, tmp_cause]))
 
-    # Emulate the systemd slice/scope creation
-    f = open(SYSTEMD_DEFAULT_CGROUP_FILE, 'w')
-    f.write(os.path.join(SLICE, SCOPE))
-    f.close()
+    cli_pid = CgroupCli.get_pids_in_cgroup(config, OTHER_CGNAME, CONTROLLER)[0]
 
-    if not os.path.exists(SYSTEMD_DEFAULT_CGROUP_FILE):
+    if pid != cli_pid:
         result = consts.TEST_FAILED
-        cause = 'Failed to create %s' % SYSTEMD_DEFAULT_CGROUP_FILE
-        return result, cause
-
-    # create /sys/fs/cgroup/cpu/libcgtests.slice (v1) or /sys/fs/cgroup/libcgtests.slice (v2)
-    result, cause = create_cgrp(config, SLICE, ignore_systemd=True)
-    if result == consts.TEST_FAILED:
-        return result, cause
-
-    # create /sys/fs/cgroup/cpu/libcgtests.slice/test071.scope (v1) or
-    #        /sys/fs/cgroup/libcgtests.slice/tests071.scope (v2)
-    result, cause = create_cgrp(config, os.path.join(SLICE, SCOPE), ignore_systemd=True)
-    if result == consts.TEST_FAILED:
-        return result, cause
-
-    # In hybrid mode /sys/fs/cgroup/unified/libcgtests.slice/test071.scope
-    # is created by the systemd and we relay on it for checking if the
-    # slice and scope were set as default systemd cgroup (new cgroup root)
-    if MODE == Mode.CGROUP_MODE_HYBRID:
-        result, cause = create_cgrp(config, SLICE, None, ignore_systemd=True)
-        if result == consts.TEST_FAILED:
-            return result, cause
-
-        result, cause = create_cgrp(config, os.path.join(SLICE, SCOPE), None, ignore_systemd=True)
-
-    return result, cause
+        tmp_cause = 'Expected pid {} to be in {} cgroup, but received pid {} ' \
+                    'via CLI instead'.format(pid, OTHER_CGNAME, cli_pid)
+        cause = '\n'.join(filter(None, [cause, tmp_cause]))
+
+    Process.kill(config, pid)
+    cg.delete()
+
+    #
+    # Test 3 - Write the slice/scope and attempt to set them as the default.
+    #          This should fail because they haven't been created yet, and thus
+    #          it's an invalid path
+    #
+    try:
+        Cgroup.write_default_systemd_scope(SLICE, SCOPE, True)
+    except RuntimeError as re:
+        if 'Failed to set' not in str(re):
+            result = consts.TEST_FAILED
+            tmp_cause = 'Expected \'Failed to set\' to be in the exception, ' \
+                        'received {}'.format(str(re))
+            cause = '\n'.join(filter(None, [cause, tmp_cause]))
+    else:
+        result = consts.TEST_FAILED
+        tmp_cause = 'write_default_systemd_scope() erroneously passed'
+        cause = '\n'.join(filter(None, [cause, tmp_cause]))
 
+    #
+    # Test 4 - Create a systemd scope and set it as the default.  Everything
+    #          should work properly in this case
+    #
+    pid = None
+    if Cgroup.cgroup_mode() != Mode.CGROUP_MODE_LEGACY:
+        pid = config.process.create_process(config)
+        Cgroup.create_scope(SCOPE, SLICE, pid=pid)
+        Cgroup.write_default_systemd_scope(SLICE, SCOPE)
 
-def test(config):
-    result = consts.TEST_PASSED
-    cause = None
+        cg = Cgroup('/', Version.CGROUP_V2)
+        cg_pid = cg.get_processes()[0]
 
-    # Create cgroup before setting the default systemd cgroup
-    result, cause = create_cgrp(config, OTHER_CGNAME, ignore_systemd=True)
-    if result == consts.TEST_FAILED:
-        return result, cause
+        if pid != cg_pid:
+            result = consts.TEST_FAILED
+            tmp_cause = 'Expected pid {} to be in \'/\' cgroup, but received pid {} ' \
+                        'instead'.format(pid, cg_pid)
+            cause = '\n'.join(filter(None, [cause, tmp_cause]))
 
-    Cgroup.__set_default_systemd_cgroup()
+        path = Cgroup.get_current_controller_path(pid)
+        if path != os.path.join('/', SLICE, SCOPE):
+            result = consts.TEST_FAILED
+            tmp_cause = 'Expected pid path to be: {}, but received path {} ' \
+                        'instead'.format(os.path.join('/', SLICE, SCOPE), path)
+            cause = '\n'.join(filter(None, [cause, tmp_cause]))
 
-    # Create cgroup after setting the default systemd cgroup
-    result, cause = create_cgrp(config, SYSTEMD_CGNAME)
-    if result == consts.TEST_FAILED:
-        return result, cause
+        cli_pid = CgroupCli.get_pids_in_cgroup(config, os.path.join(SLICE, SCOPE), CONTROLLER)[0]
 
-    return result, cause
+        if pid != cli_pid:
+            result = consts.TEST_FAILED
+            tmp_cause = 'Expected pid {} to be in {} cgroup, but received pid {} ' \
+                        'via CLI instead'.format(pid, os.path.join(SLICE, SCOPE), cli_pid)
+            cause = '\n'.join(filter(None, [cause, tmp_cause]))
 
+    return result, cause, pid
 
-def teardown(config):
-    global CGRPS_LIST
 
-    # the last object in the list is created with the default
-    # systemd cgroup set for others we need unset it
-    cgroup = CGRPS_LIST.pop()
-    cgroup.delete()
+def teardown(config, pid):
+    if pid:
+        Process.kill(config, pid)
 
-    # unset the default systemd cgroup by deleting the
-    # /var/run/libcgroup/systemd and calling
-    # __set_default_systemd_cgroup()
-    if os.path.exists(SYSTEMD_DEFAULT_CGROUP_FILE):
-        os.unlink(SYSTEMD_DEFAULT_CGROUP_FILE)
+    # Give systemd a chance to remove the scope
+    time.sleep(0.5)
 
-    Cgroup.__set_default_systemd_cgroup()
+    Cgroup.clear_default_systemd_scope()
 
-    for cgroup in reversed(CGRPS_LIST):
-        cgroup.delete()
+    try:
+        cg = Cgroup(SLICE, Version.CGROUP_V2)
+        cg.delete()
+    except RuntimeError:
+        pass
 
 
 def main(config):
@@ -159,14 +167,13 @@ def main(config):
     if result != consts.TEST_PASSED:
         return [result, cause]
 
-    [result, cause] = setup(config)
-    if result != consts.TEST_PASSED:
-        return [result, cause]
+    setup(config)
 
     try:
-        [result, cause] = test(config)
+        pid = None
+        [result, cause, pid] = test(config)
     finally:
-        teardown(config)
+        teardown(config, pid)
 
     return [result, cause]