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 | 185 +++++++++++++++++++++++++++++++++++++++++++++++++ tests/ftests/consts.py | 2 + 2 files changed, 187 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..887c4db --- /dev/null +++ b/tests/ftests/cgroup.py @@ -0,0 +1,185 @@ +#!/usr/bin/env python +# +# 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 +import types + +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/%s' % cmd) + else: + return cmd + + @staticmethod + def concatenate_controllers(controller_list): + if type(controller_list) is types.StringType: + # controller is already a string. return it as is + return controller_list + + out_str = "" + for controller in controller_list: + out_str += "%s," % controller + + # remove the trailing "," + out_str = out_str[:-1] + return out_str + + # TODO - add support for all of the cgcreate options + @staticmethod + def create(config, controller_list, cgname, in_container=True): + cmd = list() + cmd.append(Cgroup.build_cmd_path(in_container, 'cgcreate')) + + controllers_and_path = "%s:%s" % \ + (Cgroup.concatenate_controllers(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): + cmd = list() + cmd.append(Cgroup.build_cmd_path(in_container, 'cgdelete')) + + if recursive: + cmd.append('-r') + + controllers_and_path = "%s:%s" % \ + (Cgroup.concatenate_controllers(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 type(setting) is types.StringType and \ + type(value) is types.StringType: + cmd.append('-r') + cmd.append('%s=%s' % (setting, value)) + elif type(setting) is types.ListType and \ + type(value) is types.ListType: + 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('%s=%s' % (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 type(setting) is types.StringType: + # the user provided a simple string. use it as is + cmd.append('-r') + cmd.append(setting) + elif type(setting) is types.ListType: + for sttng in setting: + cmd.append('-r') + cmd.append(sttng) + else: + raise ValueError('Unsupported setting value') + + if controller is not None: + if type(controller) is types.StringType and \ + ':' in controller: + # the user provided a controller:cgroup. use it as is + cmd.append('-g') + cmd.append(controller) + elif type(controller) is types.StringType: + # the user provided a controller only. use it as is + cmd.append('-g') + cmd.append(controller) + elif type(controller) is types.ListType: + 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 type(cgname) is types.StringType: + # use the string as is + cmd.append(cgname) + elif type(cgname) is types.ListType: + 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 754e192..2f7607c 100644 --- a/tests/ftests/consts.py +++ b/tests/ftests/consts.py @@ -26,3 +26,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