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

Reply via email to