From: Satheesh Rajendran <[email protected]>

created a new file for cgroup library and moved the cgroup related
functions from client/tests/cgroup/cgroup_common.py and client/base_utils.py 
to client/cgroup_utils.py
This patchset address the below issue
https://github.com/autotest/autotest/issues/574

Signed-off-by: Satheesh Rajendran <[email protected]>
---
 client/base_utils.py   |   14 --
 client/cgroup_utils.py |  427 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 427 insertions(+), 14 deletions(-)
 create mode 100755 client/cgroup_utils.py

diff --git a/client/base_utils.py b/client/base_utils.py
index 10cecad..efddbbb 100644
--- a/client/base_utils.py
+++ b/client/base_utils.py
@@ -724,20 +724,6 @@ def probe_cpus():
     return utils.system_output(cmd).splitlines()
 
 
-def get_cgroup_mountpoint(controller):
-    controller_list = [ 'cpuacct', 'cpu', 'memory', 'cpuset',
-                        'devices', 'freezer', 'blkio', 'netcls' ]
-
-    if controller not in controller_list:
-        raise error.TestError("Doesn't support controller <%s>" % controller)
-
-    f_cgcon = open("/proc/mounts", "rU")
-    cgconf_txt = f_cgcon.read()
-    f_cgcon.close()
-    mntpt = re.findall(r"\s(\S*cgroup/%s)" % controller, cgconf_txt)
-    return mntpt[0]
-
-
 def ping_default_gateway():
     """Ping the default gateway."""
 
diff --git a/client/cgroup_utils.py b/client/cgroup_utils.py
new file mode 100755
index 0000000..8e6021d
--- /dev/null
+++ b/client/cgroup_utils.py
@@ -0,0 +1,427 @@
+##!/usr/bin/python
+# -*- coding: utf-8 -*-
+"""
+Helpers for cgroup testing.
+
+@copyright: 2011 Red Hat Inc.
+@author: Lukas Doktor <[email protected]>
+"""
+import logging, os, shutil, subprocess, time, re
+from tempfile import mkdtemp
+from autotest.client import utils
+from autotest.client.shared import error
+
+class Cgroup(object):
+    """
+    Cgroup handling class.
+    """
+    def __init__(self, module, _client):
+        """
+        Constructor
+        @param module: Name of the cgroup module
+        @param _client: Test script pwd + name
+        """
+        self.module = module
+        self._client = _client
+        self.root = None
+        self.cgroups = []
+
+
+    def __del__(self):
+        """
+        Destructor
+        """
+        self.cgroups.sort(reverse=True)
+        for pwd in self.cgroups[:]:
+            for task in self.get_property("tasks", pwd):
+                if task:
+                    self.set_root_cgroup(int(task))
+            self.rm_cgroup(pwd)
+
+    def initialize(self, modules):
+        """
+        Initializes object for use.
+
+        @param modules: Array of all available cgroup modules.
+        """
+        self.root = modules.get_pwd(self.module)
+        if not self.root:
+            raise error.TestError("cg.initialize(): Module %s not found"
+                                                                % self.module)
+
+
+    def mk_cgroup(self, pwd=None):
+        """
+        Creates new temporary cgroup
+        @param pwd: where to create this cgroup (default: self.root)
+        @return: 0 when PASSED
+        """
+        if pwd == None:
+            pwd = self.root
+        if isinstance(pwd, int):
+            pwd = self.cgroups[pwd]
+        try:
+            pwd = mkdtemp(prefix='cgroup-', dir=pwd) + '/'
+        except Exception, inst:
+            raise error.TestError("cg.mk_cgroup(): %s" % inst)
+        self.cgroups.append(pwd)
+        return pwd
+
+
+    def rm_cgroup(self, pwd):
+        """
+        Removes cgroup.
+
+        @param pwd: cgroup directory.
+        """
+        if isinstance(pwd, int):
+            pwd = self.cgroups[pwd]
+        try:
+            os.rmdir(pwd)
+            self.cgroups.remove(pwd)
+        except ValueError:
+            logging.warn("cg.rm_cgroup(): Removed cgroup which wasn't created"
+                         "using this Cgroup")
+        except Exception, inst:
+            raise error.TestError("cg.rm_cgroup(): %s" % inst)
+
+
+    def test(self, cmd):
+        """
+        Executes cgroup_client.py with cmd parameter.
+
+        @param cmd: command to be executed
+        @return: subprocess.Popen() process
+        """
+        logging.debug("cg.test(): executing paralel process '%s'", cmd)
+        cmd = self._client + ' ' + cmd
+        process = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE,
+                                   stdout=subprocess.PIPE,
+                                   stderr=subprocess.PIPE, close_fds=True)
+        return process
+
+
+    def is_cgroup(self, pid, pwd):
+        """
+        Checks if the 'pid' process is in 'pwd' cgroup
+        @param pid: pid of the process
+        @param pwd: cgroup directory
+        @return: 0 when is 'pwd' member
+        """
+        if isinstance(pwd, int):
+            pwd = self.cgroups[pwd]
+        if open(pwd + '/tasks').readlines().count("%d\n" % pid) > 0:
+            return 0
+        else:
+            return -1
+
+
+    def is_root_cgroup(self, pid):
+        """
+        Checks if the 'pid' process is in root cgroup (WO cgroup)
+        @param pid: pid of the process
+        @return: 0 when is 'root' member
+        """
+        return self.is_cgroup(pid, self.root)
+
+
+    def set_cgroup(self, pid, pwd=None):
+        """
+        Sets cgroup membership
+        @param pid: pid of the process
+        @param pwd: cgroup directory
+        """
+        if pwd == None:
+            pwd = self.root
+        if isinstance(pwd, int):
+            pwd = self.cgroups[pwd]
+        try:
+            open(pwd+'/tasks', 'w').write(str(pid))
+        except Exception, inst:
+            raise error.TestError("cg.set_cgroup(): %s" % inst)
+        if self.is_cgroup(pid, pwd):
+            raise error.TestError("cg.set_cgroup(): Setting %d pid into %s "
+                                 "cgroup failed" % (pid, pwd))
+
+    def set_root_cgroup(self, pid):
+        """
+        Resets the cgroup membership (sets to root)
+        @param pid: pid of the process
+        @return: 0 when PASSED
+        """
+        return self.set_cgroup(pid, self.root)
+
+
+    def get_property(self, prop, pwd=None):
+        """
+        Gets the property value
+        @param prop: property name (file)
+        @param pwd: cgroup directory
+        @return: [] values or None when FAILED
+        """
+        if pwd == None:
+            pwd = self.root
+        if isinstance(pwd, int):
+            pwd = self.cgroups[pwd]
+        try:
+            # Remove tailing '\n' from each line
+            ret = [_[:-1] for _ in open(pwd+prop, 'r').readlines()]
+            if ret:
+                return ret
+            else:
+                return [""]
+        except Exception, inst:
+            raise error.TestError("cg.get_property(): %s" % inst)
+
+
+    def set_property_h(self, prop, value, pwd=None, check=True, 
checkprop=None):
+        """
+        Sets the one-line property value concerning the K,M,G postfix
+        @param prop: property name (file)
+        @param value: desired value
+        @param pwd: cgroup directory
+        @param check: check the value after setup / override checking value
+        @param checkprop: override prop when checking the value
+        """
+        _value = value
+        try:
+            value = str(value)
+            human = {'B': 1,
+                     'K': 1024,
+                     'M': 1048576,
+                     'G': 1073741824,
+                     'T': 1099511627776
+                    }
+            if human.has_key(value[-1]):
+                value = int(value[:-1]) * human[value[-1]]
+        except Exception:
+            logging.warn("cg.set_prop() fallback into cg.set_property.")
+            value = _value
+        self.set_property(prop, value, pwd, check, checkprop)
+
+
+    def set_property(self, prop, value, pwd=None, check=True, checkprop=None):
+        """
+        Sets the property value
+        @param prop: property name (file)
+        @param value: desired value
+        @param pwd: cgroup directory
+        @param check: check the value after setup / override checking value
+        @param checkprop: override prop when checking the value
+        """
+        value = str(value)
+        if pwd == None:
+            pwd = self.root
+        if isinstance(pwd, int):
+            pwd = self.cgroups[pwd]
+        try:
+            open(pwd+prop, 'w').write(value)
+        except Exception, inst:
+            raise error.TestError("cg.set_property(): %s" % inst)
+        if check != False:
+            if check == True:
+                check = value
+            if checkprop == None:
+                checkprop = prop
+            _values = self.get_property(checkprop, pwd)
+            if check not in _values:
+                raise error.TestError("cg.set_property(): Setting failed: "
+                                      "desired = %s, real values = %s"
+                                      % (repr(check), repr(_values)))
+
+
+    def smoke_test(self):
+        """
+        Smoke test
+        Module independent basic tests
+        """
+        pwd = self.mk_cgroup()
+
+        ps = self.test("smoke")
+        if ps == None:
+            raise error.TestError("cg.smoke_test: Couldn't create process")
+
+        if (ps.poll() != None):
+            raise error.TestError("cg.smoke_test: Process died unexpectidly")
+
+        # New process should be a root member
+        if self.is_root_cgroup(ps.pid):
+            raise error.TestError("cg.smoke_test: Process is not a root 
member")
+
+        # Change the cgroup
+        self.set_cgroup(ps.pid, pwd)
+
+        # Try to remove used cgroup
+        try:
+            self.rm_cgroup(pwd)
+        except error.TestError:
+            pass
+        else:
+            raise error.TestError("cg.smoke_test: Unexpected successful 
deletion"
+                                 " of the used cgroup")
+
+        # Return the process into the root cgroup
+        self.set_root_cgroup(ps.pid)
+
+        # It should be safe to remove the cgroup now
+        self.rm_cgroup(pwd)
+
+        # Finish the process
+        ps.stdin.write('\n')
+        time.sleep(2)
+        if (ps.poll() == None):
+            raise error.TestError("cg.smoke_test: Process is not finished")
+
+
+class CgroupModules(object):
+    """
+    Handles the list of different cgroup filesystems.
+    """
+    def __init__(self):
+        self.modules = []
+        self.modules.append([])
+        self.modules.append([])
+        self.modules.append([])
+        self.mountdir = mkdtemp(prefix='cgroup-') + '/'
+
+    def __del__(self):
+        """
+        Unmount all cgroups and remove the mountdir
+        """
+        for i in range(len(self.modules[0])):
+            if self.modules[2][i]:
+                try:
+                    utils.system('umount %s -l' % self.modules[1][i])
+                except Exception, failure_detail:
+                    logging.warn("CGM: Couldn't unmount %s directory: %s",
+                                 self.modules[1][i], failure_detail)
+        try:
+            shutil.rmtree(self.mountdir)
+        except Exception:
+            logging.warn("CGM: Couldn't remove the %s directory", 
self.mountdir)
+
+    def init(self, _modules):
+        """
+        Checks the mounted modules and if necessary mounts them into tmp
+            mountdir.
+        @param _modules: Desired modules.
+        @return: Number of initialized modules.
+        """
+        logging.debug("Desired cgroup modules: %s", _modules)
+        mounts = []
+        proc_mounts = open('/proc/mounts', 'r')
+        line = proc_mounts.readline().split()
+        while line:
+            if line[2] == 'cgroup':
+                mounts.append(line)
+            line = proc_mounts.readline().split()
+        proc_mounts.close()
+
+        for module in _modules:
+            # Is it already mounted?
+            i = False
+            for mount in mounts:
+                if  module in mount[3].split(','):
+                    self.modules[0].append(module)
+                    self.modules[1].append(mount[1] + '/')
+                    self.modules[2].append(False)
+                    i = True
+                    break
+            if not i:
+                # Not yet mounted
+                os.mkdir(self.mountdir + module)
+                cmd = ('mount -t cgroup -o %s %s %s' %
+                       (module, module, self.mountdir + module))
+                try:
+                    utils.run(cmd)
+                    self.modules[0].append(module)
+                    self.modules[1].append(self.mountdir + module)
+                    self.modules[2].append(True)
+                except error.CmdError:
+                    logging.info("Cgroup module '%s' not available", module)
+
+        logging.debug("Initialized cgroup modules: %s", self.modules[0])
+        return len(self.modules[0])
+
+
+    def get_pwd(self, module):
+        """
+        Returns the mount directory of 'module'
+        @param module: desired module (memory, ...)
+        @return: mount directory of 'module' or None
+        """
+        try:
+            i = self.modules[0].index(module)
+        except Exception, inst:
+            logging.error("module %s not found: %s", module, inst)
+            return None
+        return self.modules[1][i]
+
+
+def get_load_per_cpu(_stats=None):
+    """
+    Gather load per cpu from /proc/stat
+    @param _stats: previous values
+    @return: list of diff/absolute values of CPU times [SUM, CPU1, CPU2, ...]
+    """
+    stats = []
+    f_stat = open('/proc/stat', 'r')
+    if _stats:
+        for i in range(len(_stats)):
+            stats.append(int(f_stat.readline().split()[1]) - _stats[i])
+    else:
+        line = f_stat.readline()
+        while line:
+            if line.startswith('cpu'):
+                stats.append(int(line.split()[1]))
+            else:
+                break
+            line = f_stat.readline()
+    return stats
+
+
+def get_cgroup_mountpoint(controller):
+    controller_list = [ 'cpuacct', 'cpu', 'memory', 'cpuset',
+                        'devices', 'freezer', 'blkio', 'netcls' ]
+
+    if controller not in controller_list:
+        raise error.TestError("Doesn't support controller <%s>" % controller)
+
+    f_cgcon = open("/proc/mounts", "rU")
+    cgconf_txt = f_cgcon.read()
+    f_cgcon.close()
+    mntpt = re.findall(r"\s(\S*cgroup/%s)" % controller, cgconf_txt)
+    return mntpt[0]
+
+
+def resolve_task_cgroup_path(pid, controller):
+    """
+    Resolving cgroup mount path of a particular task
+
+    @params: pid : process id of a task for which the cgroup path required
+    @params: controller: takes one of the controller names in controller list  
+
+    @return: resolved path for cgroup controllers of a given pid
+    """
+
+    # Initialise cgroup controller list
+    controller_list = [ 'cpuacct', 'cpu', 'memory', 'cpuset',
+                        'devices', 'freezer', 'blkio', 'netcls' ]
+
+    if controller not in controller_list:
+        raise error.TestError("Doesn't support controller <%s>" % controller)
+
+    root_path = get_cgroup_mountpoint(controller)
+
+    proc_cgroup = "/proc/%d/cgroup" % pid
+    if not os.path.isfile(proc_cgroup):
+        raise NameError('File %s does not exist\n Check whether cgroup \
+                                    installed in the system' % proc_cgroup)
+
+    f = open(proc_cgroup, 'r')
+    proc_cgroup_txt = f.read()
+    f.close
+
+    mount_path = re.findall(r":%s:(\S*)\n" % controller, proc_cgroup_txt)
+    path = root_path + mount_path[0]
+    return path
-- 
1.7.1

_______________________________________________
Autotest-kernel mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/autotest-kernel

Reply via email to