]> git.ipfire.org Git - thirdparty/libcgroup.git/commitdiff
samples: Add a python example that creates a systemd scope
authorTom Hromatka <tom.hromatka@oracle.com>
Fri, 19 May 2023 22:16:46 +0000 (16:16 -0600)
committerTom Hromatka <tom.hromatka@oracle.com>
Mon, 3 Jul 2023 15:00:19 +0000 (09:00 -0600)
Signed-off-by: Tom Hromatka <tom.hromatka@oracle.com>
Reviewed-by: Kamalesh Babulal <kamalesh.babulal@oracle.com>
configure.ac
samples/Makefile.am
samples/python/Makefile.am [new file with mode: 0644]
samples/python/create_systemd_scope.py [new file with mode: 0755]

index 42d77e7be0d889170d62f7e2aae7fba14226dbab..98fe27970677721877832b936a29f078d366b9d9 100644 (file)
@@ -253,6 +253,7 @@ AC_CONFIG_FILES([Makefile
        samples/Makefile
        samples/c/Makefile
        samples/config/Makefile
+       samples/python/Makefile
        include/Makefile
        include/libcgroup/init.h
        doc/Makefile
index 5c5566c597f16ae6ce1083073d5e4e13ed20dbfe..a0454b7ed394b31b6ff79c5124d119c7032666cf 100644 (file)
@@ -1,2 +1,2 @@
-DIST_SUBDIRS = config c
+DIST_SUBDIRS = config c python
 SUBDIRS = $(DIST_SUBDIRS)
diff --git a/samples/python/Makefile.am b/samples/python/Makefile.am
new file mode 100644 (file)
index 0000000..17aaf89
--- /dev/null
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: LGPL-2.1-only
+#
+# libcgroup python samples Makefile.am
+#
+# Copyright (c) 2023 Oracle and/or its affiliates.
+# Author: Tom Hromatka <tom.hromatka@oracle.com>
+#
+
+if WITH_SAMPLES
+
+EXTRA_DIST = create_systemd_scope.py
+
+endif
+
+clean-local: clean-local-check
+.PHONY: clean-local-check
+clean-local-check:
+       -rm -f *.pyc
diff --git a/samples/python/create_systemd_scope.py b/samples/python/create_systemd_scope.py
new file mode 100755 (executable)
index 0000000..e29e866
--- /dev/null
@@ -0,0 +1,185 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: LGPL-2.1-only
+#
+# Sample program that shows how to use libcgroup to create a systemd scope
+#
+#  This program is designed to meet the requirements outlined in the systemd
+# cmdline example [1] via the libcgroup C APIs.
+#
+# [1] https://github.com/libcgroup/libcgroup/blob/main/samples/cmdline/systemd-with-idle-process.md
+#
+#
+# Copyright (c) 2023 Oracle and/or its affiliates.
+# Author: Tom Hromatka <tom.hromatka@oracle.com>
+#
+
+#
+# To run this program:
+#       1. Compile the libcgroup library
+#           $ ./bootstrap.sh
+#           $ make
+#       2. Note the path to your libcgroup python library
+#           $ pushd src/python/build/lib*
+#           $ export TMPPATH=$(pwd)
+#           $ popd
+#       2. Run the program
+#           $ # Note that there are more options.  Run `create_systemd_scope.py -h`
+#           $ # for more info
+#           $ sudo PYTHONPATH=$TMPPATH \
+#             ./samples/python/create_systemd_scope.py \
+#             --slice <yourslicename> --scope <yourscopename>
+#
+
+from libcgroup import Cgroup, Version, LogLevel
+import multiprocessing
+import argparse
+import signal
+import time
+import sys
+import os
+
+TMP_CGNAME = "tmp"
+HIGH_CGNAME = "high-priority"
+MED_CGNAME = "medium-priority"
+LOW_CGNAME = "low-priority"
+
+
+def parse_args():
+    parser = argparse.ArgumentParser('libcgroup sample program to create a systemd scope')
+
+    delegated_parser = parser.add_mutually_exclusive_group(required=False)
+    delegated_parser.add_argument('-d', '--delegated', help='Create a delegated scope',
+                                  action='store_true', dest='delegated')
+    delegated_parser.add_argument('-n', '--notdelegated',
+                                  help='Create a scope that is not delegated',
+                                  action='store_false', dest='delegated')
+    parser.set_defaults(delegated=True)
+
+    parser.add_argument('-p', '--pid', help='PID to place within the scope. If not provided,'
+                        'libcgroup will place a temporary process in the scope',
+                        required=False, type=int, default=None)
+    parser.add_argument('-s', '--scope', help='Name of the scope to be created',
+                        required=True, type=str, default=None)
+    parser.add_argument('-t', '--slice', help='Name of the slice where the scope will reside',
+                        required=True, type=str, default=None)
+    parser.add_argument('-v', '--verbose', help='Enable verbose logging within libcgroup',
+                        required=False, action='store_true')
+
+    args = parser.parse_args()
+
+    return args
+
+
+def create_scope(args):
+    print('\n----------------------------------------------------------------')
+    print('Creating systemd scope, {}/{},'.format(args.slice, args.scope))
+    if args.pid:
+        print('and placing PID, {}, in the scope'.format(args.pid))
+    else:
+        print('and libcgroup will place an idle process in the scope')
+    print('----------------------------------------------------------------\n')
+
+    Cgroup.create_scope(args.scope, args.slice, args.delegated, pid=args.pid)
+    Cgroup.write_default_systemd_scope(args.slice, args.scope, True)
+
+
+def create_tmp_cgroup():
+    cg = Cgroup(TMP_CGNAME, Version.CGROUP_V2)
+    cg.create()
+
+
+def move_pids_to_tmp_cgroup():
+    cg = Cgroup('/', Version.CGROUP_V2)
+    pids = cg.get_processes()
+    for pid in pids:
+        Cgroup.move_process(pid, TMP_CGNAME)
+
+
+def create_high_priority_cgroup():
+    cg = Cgroup(HIGH_CGNAME, Version.CGROUP_V2)
+    cg.add_setting('cpu.weight', '600')
+    cg.add_setting('memory.low', '1G')
+    cg.create()
+
+
+def create_medium_priority_cgroup():
+    cg = Cgroup(MED_CGNAME, Version.CGROUP_V2)
+    cg.add_setting('cpu.weight', '300')
+    cg.add_setting('memory.high', '3G')
+    cg.create()
+
+
+def create_low_priority_cgroup():
+    cg = Cgroup(LOW_CGNAME, Version.CGROUP_V2)
+    cg.add_setting('cpu.weight', '100')
+    cg.add_setting('memory.max', '2G')
+    cg.create()
+
+
+def __infinite_loop():
+    while True:
+        time.sleep(10)
+
+
+def create_process_in_cgroup(cgname):
+    p = multiprocessing.Process(target=__infinite_loop, )
+    p.start()
+
+    Cgroup.move_process(p.pid, cgname)
+
+    return p.pid
+
+
+def delete_tmp_cgroup():
+    cg = Cgroup(TMP_CGNAME, Version.CGROUP_V2)
+    pids = cg.get_processes()
+
+    for pid in pids:
+        os.kill(pid, signal.SIGKILL)
+
+    # I have observed "Device or resource busy" errors when deleting the
+    # cgroup immediately after the os.kill() instruction.  Give the kill
+    # command a little time to succeed
+    time.sleep(1)
+
+    cg.delete()
+
+
+def main(args):
+    if args.verbose:
+        Cgroup.log_level(LogLevel.CGROUP_LOG_DEBUG)
+
+    create_scope(args)
+    create_tmp_cgroup()
+    move_pids_to_tmp_cgroup()
+
+    create_high_priority_cgroup()
+    create_medium_priority_cgroup()
+    create_low_priority_cgroup()
+
+    high_pid = create_process_in_cgroup(HIGH_CGNAME)
+    med_pid = create_process_in_cgroup(MED_CGNAME)
+    low_pid = create_process_in_cgroup(LOW_CGNAME)
+
+    delete_tmp_cgroup()
+
+    print('\n----------------------------------------------------------------')
+    print('Cgroup setup completed successfully')
+    print('\t* The scope {} was placed under slice {}'.format(args.scope, args.slice))
+    print('\t* Libcgroup initially placed an idle process in the scope,\n'
+          '\t  but it has been removed by this program')
+    print('\t* PID {} has been placed in the {} cgroup'.format(high_pid, HIGH_CGNAME))
+    print('\t* PID {} has been placed in the {} cgroup'.format(med_pid, MED_CGNAME))
+    print('\t* PID {} has been placed in the {} cgroup'.format(low_pid, LOW_CGNAME))
+    print('\nThis program will wait for the aforementioned child processes to\n'
+          'exit before exiting itself. Systemd will automatically delete the\n'
+          'scope when there are no longer any processes running within the\n'
+          'scope.  Systemd will not automatically delete the slice.')
+    print('----------------------------------------------------------------\n')
+
+
+if __name__ == '__main__':
+    args = parse_args()
+    sys.exit(main(args))
+
+# vim: set et ts=4 sw=4: