From: Tom Hromatka Date: Fri, 19 May 2023 22:16:46 +0000 (-0600) Subject: samples: Add a python example that creates a systemd scope X-Git-Tag: v3.1.0~31 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=459f02f92b99ae188024a4cb728081785caf8f4a;p=thirdparty%2Flibcgroup.git samples: Add a python example that creates a systemd scope Signed-off-by: Tom Hromatka Reviewed-by: Kamalesh Babulal --- diff --git a/configure.ac b/configure.ac index 42d77e7b..98fe2797 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/samples/Makefile.am b/samples/Makefile.am index 5c5566c5..a0454b7e 100644 --- a/samples/Makefile.am +++ b/samples/Makefile.am @@ -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 index 00000000..17aaf89b --- /dev/null +++ b/samples/python/Makefile.am @@ -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 +# + +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 index 00000000..e29e866b --- /dev/null +++ b/samples/python/create_systemd_scope.py @@ -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 +# + +# +# 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 --scope +# + +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: