Re: [PATCH] Adds cgroup handling library

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



ACK nice work.

May be cgroup_common should be more general and placed in client/common_lib
and can work general tools for manipulating with cgroups.

----- Original Message -----
> [new] cgroup_common.py
> * library for handling cgroups
> 
> Signed-off-by: Lukas Doktor <ldoktor@xxxxxxxxxx>
> ---
> client/tests/cgroup/cgroup.py | 5 +-
> client/tests/cgroup/cgroup_common.py | 327
> ++++++++++++++++++++++++++++++++++
> 2 files changed, 331 insertions(+), 1 deletions(-)
> create mode 100755 client/tests/cgroup/cgroup_common.py
> 
> diff --git a/client/tests/cgroup/cgroup.py
> b/client/tests/cgroup/cgroup.py
> index d043d65..112f012 100755
> --- a/client/tests/cgroup/cgroup.py
> +++ b/client/tests/cgroup/cgroup.py
> @@ -118,6 +118,7 @@ class cgroup(test.test):
> # Fill the memory without cgroup limitation
> # Should pass
> ################################################
> + logging.debug("test_memory: Memfill WO cgroup")
> ps = item.test("memfill %d" % mem)
> ps.stdin.write('\n')
> i = 0
> @@ -141,6 +142,7 @@ class cgroup(test.test):
> # memsw: should swap out part of the process and pass
> # WO memsw: should fail (SIGKILL)
> ################################################
> + logging.debug("test_memory: Memfill mem only limit")
> ps = item.test("memfill %d" % mem)
> if item.set_cgroup(ps.pid, pwd):
> logging.error("test_memory: Could not set cgroup")
> @@ -187,6 +189,7 @@ class cgroup(test.test):
> # Fill the memory with 1/2 memory+swap limit
> # Should fail
> ################################################
> + logging.debug("test_memory: Memfill mem + swap limit")
> if memsw:
> ps = item.test("memfill %d" % mem)
> if item.set_cgroup(ps.pid, pwd):
> @@ -226,11 +229,11 @@ class cgroup(test.test):
> logging.debug("test_memory: Memfill mem+swap cgroup passed")
> 
> # cleanup
> + logging.debug("test_memory: Cleanup")
> if item.rm_cgroup(pwd):
> logging.error("test_memory: Can't remove cgroup directory")
> return -1
> os.system("swapon -a")
> - logging.debug("test_memory: Cleanup passed")
> 
> logging.info("Leaving 'test_memory': PASSED")
> return 0
> diff --git a/client/tests/cgroup/cgroup_common.py
> b/client/tests/cgroup/cgroup_common.py
> new file mode 100755
> index 0000000..3fd1cf7
> --- /dev/null
> +++ b/client/tests/cgroup/cgroup_common.py
> @@ -0,0 +1,327 @@
> +#!/usr/bin/python
> +# -*- coding: utf-8 -*-
> +"""
> +Helpers for cgroup testing
> +
> +@copyright: 2011 Red Hat Inc.
> +@author: Lukas Doktor <ldoktor@xxxxxxxxxx>
> +"""
> +import os, logging
> +import subprocess
> +from tempfile import mkdtemp
> +import time
> +
> +class Cgroup:
> + """
> + 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
> +
> +
> + def initialize(self, modules):
> + """
> + Inicializes object for use
> + @param modules: array of all available cgroup modules
> + @return: 0 when PASSED
> + """
> + self.root = modules.get_pwd(self.module)
> + if self.root:
> + return 0
> + else:
> + logging.error("cg.initialize(): Module %s not found", self.module)
> + return -1
> + return 0
> +
> +
> + def mk_cgroup(self, root=None):
> + """
> + Creates new temporary cgroup
> + @param root: where to create this cgroup (default: self.root)
> + @return: 0 when PASSED
> + """
> + try:
> + if root:
> + pwd = mkdtemp(prefix='cgroup-', dir=root) + '/'
> + else:
> + pwd = mkdtemp(prefix='cgroup-', dir=self.root) + '/'
> + except Exception, inst:
> + logging.error("cg.mk_cgroup(): %s" , inst)
> + return None
> + return pwd
> +
> +
> + def rm_cgroup(self, pwd, supress=False):
> + """
> + Removes cgroup
> + @param pwd: cgroup directory
> + @param supress: supress output
> + @return: 0 when PASSED
> + """
> + try:
> + os.rmdir(pwd)
> + except Exception, inst:
> + if not supress:
> + logging.error("cg.rm_cgroup(): %s" , inst)
> + return -1
> + return 0
> +
> +
> + 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)
> + process = subprocess.Popen((self._client + ' ' + 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 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):
> + """
> + Sets cgroup membership
> + @param pid: pid of the process
> + @param pwd: cgroup directory
> + @return: 0 when PASSED
> + """
> + try:
> + open(pwd+'/tasks', 'w').write(str(pid))
> + except Exception, inst:
> + logging.error("cg.set_cgroup(): %s" , inst)
> + return -1
> + if self.is_cgroup(pid, pwd):
> + logging.error("cg.set_cgroup(): Setting %d pid into %s cgroup "
> + "failed", pid, pwd)
> + return -1
> + else:
> + return 0
> +
> + 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, supress=False):
> + """
> + Gets the property value
> + @param prop: property name (file)
> + @param pwd: cgroup directory
> + @param supress: supress the output
> + @return: String value or None when FAILED
> + """
> + if pwd == None:
> + pwd = self.root
> + try:
> + ret = open(pwd+prop, 'r').readlines()
> + except Exception, inst:
> + ret = None
> + if not supress:
> + logging.error("cg.get_property(): %s" , inst)
> + return ret
> +
> +
> + def set_property(self, prop, value, pwd=None, check=True):
> + """
> + Sets the property value
> + @param prop: property name (file)
> + @param value: desired value
> + @param pwd: cgroup directory
> + @param check: check the value after setup
> + @return: 0 when PASSED
> + """
> + value = str(value)
> + if pwd == None:
> + pwd = self.root
> + try:
> + open(pwd+prop, 'w').write(value)
> + except Exception, inst:
> + logging.error("cg.set_property(): %s" , inst)
> + return -1
> + if check:
> + # Get the first line - '\n'
> + _value = self.get_property(prop, pwd)[0][:-1]
> + if value != _value:
> + logging.error("cg.set_property(): Setting failed: desired = %s,"
> + " real value = %s", value, _value)
> + return -1
> + return 0
> +
> +
> + def smoke_test(self):
> + """
> + Smoke test
> + Module independent basic tests
> + """
> + part = 0
> + pwd = self.mk_cgroup()
> + if pwd == None:
> + logging.error("cg.smoke_test[%d]: Can't create cgroup", part)
> + return -1
> +
> + part += 1
> + ps = self.test("smoke")
> + if ps == None:
> + logging.error("cg.smoke_test[%d]: Couldn't create process", part)
> + return -1
> +
> + part += 1
> + if (ps.poll() != None):
> + logging.error("cg.smoke_test[%d]: Process died unexpectidly", part)
> + return -1
> +
> + # New process should be a root member
> + part += 1
> + if self.is_root_cgroup(ps.pid):
> + logging.error("cg.smoke_test[%d]: Process is not a root member",
> + part)
> + return -1
> +
> + # Change the cgroup
> + part += 1
> + if self.set_cgroup(ps.pid, pwd):
> + logging.error("cg.smoke_test[%d]: Could not set cgroup", part)
> + return -1
> +
> + # Try to remove used cgroup
> + part += 1
> + if self.rm_cgroup(pwd, supress=True) == 0:
> + logging.error("cg.smoke_test[%d]: Unexpected successful deletion of"
> + " the used cgroup", part)
> + return -1
> +
> + # Return the process into the root cgroup
> + part += 1
> + if self.set_root_cgroup(ps.pid):
> + logging.error("cg.smoke_test[%d]: Could not return the root cgroup "
> + "membership", part)
> + return -1
> +
> + # It should be safe to remove the cgroup now
> + part += 1
> + if self.rm_cgroup(pwd):
> + logging.error("cg.smoke_test[%d]: Can't remove cgroup direcotry",
> + part)
> + return -1
> +
> + # Finish the process
> + part += 1
> + ps.stdin.write('\n')
> + time.sleep(2)
> + if (ps.poll() == None):
> + logging.error("cg.smoke_test[%d]: Process is not finished", part)
> + return -1
> +
> + return 0
> +
> +
> +class CgroupModules:
> + """
> + 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 init(self, _modules):
> + """
> + Checks the mounted modules and if necessarily mounts them into tmp
> + mountdir.
> + @param _modules: desired modules
> + @return: Number of initialized modules
> + """
> + mounts = []
> + fp = open('/proc/mounts', 'r')
> + line = fp.readline().split()
> + while line:
> + if line[2] == 'cgroup':
> + mounts.append(line)
> + line = fp.readline().split()
> + fp.close()
> +
> + for module in _modules:
> + # Is it already mounted?
> + i = False
> + for mount in mounts:
> + if mount[3].find(module) != -1:
> + 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)
> + logging.info('mount -t cgroup -o %s %s %s', module, module,
> + self.mountdir+module)
> + if (os.system('mount -t cgroup -o %s %s %s'
> + % (module, module, self.mountdir+module)) == 0):
> + self.modules[0].append(module)
> + self.modules[1].append(self.mountdir+module)
> + self.modules[2].append(True)
> + else:
> + logging.error("Module '%s' is not available, mount failed",
> + module)
> + return len(self.modules[0])
> +
> +
> + def cleanup(self):
> + """
> + Unmount all cgroups and remove the mountdir
> + """
> + for i in range(len(self.modules[0])):
> + if self.modules[2][i]:
> + os.system('umount %s -l' % self.modules[1][i])
> + os.system('rm -rf %s' % self.mountdir)
> +
> +
> + 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]
> --
> 1.7.6
> 
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux