This commit adds a Cgroup() class for managing cgroups. This class provides static methods for interacting with libcgroup's interfaces including cgset, cgget, cgcreate, etc.
Example usages: # create a cgroup in the cpuset controller named foo Cgroup.create(config, 'cpuset', 'foo') # set cpu.shares for foobar to 500 Cgroup.set(config, 'foobar', 'cpu.shares', '500') # get the limit_in_bytes for AnotherCgroup. Have libcgroup # strip off all of the decorations so that only the value is # returned limit_in_bytes = Cgroup.get(config, controller=None, cgname='AnotherCgroup', setting='memory.limit_in_bytes', print_headers=False, values_only=True) Providing invalid parameters to a Cgroup method will result in a ValueError while a failure to execute a command will result in a RunError. Signed-off-by: Tom Hromatka <tom.hroma...@oracle.com> --- tests/ftests/cgroup.py | 172 +++++++++++++++++++++++++++++++++++++++++++++++++ tests/ftests/consts.py | 2 + 2 files changed, 174 insertions(+) create mode 100644 tests/ftests/cgroup.py diff --git a/tests/ftests/cgroup.py b/tests/ftests/cgroup.py new file mode 100644 index 0000000..20495af --- /dev/null +++ b/tests/ftests/cgroup.py @@ -0,0 +1,172 @@ +# +# Cgroup class for the libcgroup functional tests +# +# Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved. +# Author: Tom Hromatka <tom.hroma...@oracle.com> +# + +# +# This library is free software; you can redistribute it and/or modify it +# under the terms of version 2.1 of the GNU Lesser General Public License as +# published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License +# for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library; if not, see <http://www.gnu.org/licenses>. +# + +import consts +import os +from run import Run + +class Cgroup(object): + @staticmethod + def build_cmd_path(in_container, cmd): + if in_container: + return os.path.join('/', consts.LIBCG_MOUNT_POINT, + 'src/tools/.libs/{}'.format(cmd)) + else: + return cmd + + # TODO - add support for all of the cgcreate options + @staticmethod + def create(config, controller_list, cgname, in_container=True): + if isinstance(controller_list, str): + controller_list = [controller_list] + + cmd = list() + cmd.append(Cgroup.build_cmd_path(in_container, 'cgcreate')) + + controllers_and_path = '{}:{}'.format( + ','.join(controller_list), cgname) + + cmd.append('-g') + cmd.append(controllers_and_path) + + if in_container: + config.container.run(cmd) + else: + Run.run(cmd) + + @staticmethod + def delete(config, controller_list, cgname, in_container=True, recursive=False): + if isinstance(controller_list, str): + controller_list = [controller_list] + + cmd = list() + cmd.append(Cgroup.build_cmd_path(in_container, 'cgdelete')) + + if recursive: + cmd.append('-r') + + controllers_and_path = '{}:{}'.format( + ''.join(controller_list), cgname) + + cmd.append('-g') + cmd.append(controllers_and_path) + + if in_container: + config.container.run(cmd) + else: + Run.run(cmd) + + @staticmethod + def set(config, cgname, setting, value, in_container=True): + cmd = list() + cmd.append(Cgroup.build_cmd_path(in_container, 'cgset')) + + if isinstance(setting, str) and isinstance(value, str): + cmd.append('-r') + cmd.append('{}={}'.format(setting, value)) + elif isinstance(setting, list) and isinstance(value, list): + if len(setting) != len(value): + raise ValueError('Settings list length must equal values list length') + + for idx, stg in enumerate(setting): + cmd.append('-r') + cmd.append('{}={}'.format(stg, value[idx])) + + cmd.append(cgname) + + if in_container: + config.container.run(cmd) + else: + Run.run(cmd) + + @staticmethod + # valid cpuset commands: + # Read one setting: + # cgget -r cpuset.cpus tomcpuset + # Read two settings: + # cgget -r cpuset.cpus -r cpuset.cpu_exclusive tomcpuset + # Read one setting from two cgroups: + # cgget -r cpuset.cpu_exclusive tomcgroup1 tomcgroup2 + # Read two settings from two cgroups: + # cgget -r cpuset.cpu_exclusive -r cpuset.cpu_exclusive tomcgroup1 tomcgroup2 + # + # Read all of the settings in a cgroup + # cgget -g cpuset tomcpuset + # Read all of the settings in multiple controllers + # cgget -g cpuset -g cpu -g memory tomcgroup + # Read all of the settings from a cgroup at a specific path + # cgget -g memory:tomcgroup/tomcgroup + def get(config, controller=None, cgname=None, setting=None, + in_container=True, print_headers=True, values_only=False, + all_controllers=False): + cmd = list() + cmd.append(Cgroup.build_cmd_path(in_container, 'cgget')) + + if not print_headers: + cmd.append('-n') + if values_only: + cmd.append('-v') + + if setting is not None: + if isinstance(setting, str): + # the user provided a simple string. use it as is + cmd.append('-r') + cmd.append(setting) + elif isinstance(setting, list): + for sttng in setting: + cmd.append('-r') + cmd.append(sttng) + else: + raise ValueError('Unsupported setting value') + + if controller is not None: + if isinstance(controller, str) and ':' in controller: + # the user provided a controller:cgroup. use it as is + cmd.append('-g') + cmd.append(controller) + elif isinstance(controller, str): + # the user provided a controller only. use it as is + cmd.append('-g') + cmd.append(controller) + elif isinstance(controller, list): + for ctrl in controller: + cmd.append('-g') + cmd.append(ctrl) + else: + raise ValueError('Unsupported controller value') + + if all_controllers: + cmd.append('-a') + + if cgname is not None: + if isinstance(cgname, str): + # use the string as is + cmd.append(cgname) + elif isinstance(cgname, list): + for cg in cgname: + cmd.append(cg) + + if in_container: + ret = config.container.run(cmd) + else: + ret = Run.run(cmd) + + return ret diff --git a/tests/ftests/consts.py b/tests/ftests/consts.py index 8122356..b21687f 100644 --- a/tests/ftests/consts.py +++ b/tests/ftests/consts.py @@ -25,3 +25,5 @@ LOG_CRITICAL = 1 LOG_WARNING = 5 LOG_DEBUG = 8 DEFAULT_LOG_LEVEL = 5 + +LIBCG_MOUNT_POINT = 'libcg' -- 1.8.3.1 _______________________________________________ Libcg-devel mailing list Libcg-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/libcg-devel