* Use exceptions instead of returns * cgroup and cgroup-kvm tests were modified to fit * other code cleanups Signed-off-by: Lukas Doktor <ldoktor@xxxxxxxxxx> --- client/tests/cgroup/cgroup.py | 169 +++++++++++++++++----------------- client/tests/cgroup/cgroup_common.py | 140 ++++++++++------------------ client/tests/kvm/tests/cgroup.py | 14 +-- 3 files changed, 138 insertions(+), 185 deletions(-) diff --git a/client/tests/cgroup/cgroup.py b/client/tests/cgroup/cgroup.py index 171f43e..8626c52 100644 --- a/client/tests/cgroup/cgroup.py +++ b/client/tests/cgroup/cgroup.py @@ -1,4 +1,12 @@ -import os, logging +#!/usr/bin/python +# -*- coding: utf-8 -*- +""" +Autotest test for testing cgroup functionalities + +@copyright: 2011 Red Hat Inc. +@author: Lukas Doktor <ldoktor@xxxxxxxxxx> +""" +import os, sys, logging import time from tempfile import NamedTemporaryFile @@ -6,6 +14,7 @@ from autotest_lib.client.bin import test, utils from autotest_lib.client.common_lib import error from cgroup_common import Cgroup as CG from cgroup_common import CgroupModules +from cgroup_common import _traceback class cgroup(test.test): """ @@ -15,7 +24,7 @@ class cgroup(test.test): """ version = 1 _client = "" - modules = CgroupModules() + modules = None def run_once(self): """ @@ -25,25 +34,26 @@ class cgroup(test.test): err = "" # Run available tests - for i in ['memory', 'cpuset']: - logging.info("---< 'test_%s' START >---", i) + for subtest in ['memory', 'cpuset']: + logging.info("---< 'test_%s' START >---", subtest) try: - if not self.modules.get_pwd(i): + if not self.modules.get_pwd(subtest): raise error.TestFail("module not available/mounted") - t_function = getattr(self, "test_%s" % i) + t_function = getattr(self, "test_%s" % subtest) t_function() - logging.info("---< 'test_%s' PASSED >---", i) + logging.info("---< 'test_%s' PASSED >---", subtest) except AttributeError: - err += "%s, " % i - logging.error("test_%s: Test doesn't exist", i) - logging.info("---< 'test_%s' FAILED >---", i) - except Exception, inst: - err += "%s, " % i - logging.error("test_%s: %s", i, inst) - logging.info("---< 'test_%s' FAILED >---", i) + err += "%s, " % subtest + logging.error("test_%s: Test doesn't exist", subtest) + logging.info("---< 'test_%s' FAILED >---", subtest) + except Exception: + err += "%s, " % subtest + tb = _traceback("test_%s" % subtest, sys.exc_info()) + logging.error("test_%s: FAILED%s", subtest, tb) + logging.info("---< 'test_%s' FAILED >---", subtest) if err: - logging.error('Some subtests failed (%s)' % err[:-2]) + logging.error('Some subtests failed (%s)', err[:-2]) raise error.TestFail('Some subtests failed (%s)' % err[:-2]) @@ -57,16 +67,16 @@ class cgroup(test.test): _modules = ['cpuset', 'ns', 'cpu', 'cpuacct', 'memory', 'devices', 'freezer', 'net_cls', 'blkio'] + self.modules = CgroupModules() if (self.modules.init(_modules) <= 0): raise error.TestFail('Can\'t mount any cgroup modules') def cleanup(self): - """ - Unmount all cgroups and remove directories - """ - logging.info('Cleanup') - self.modules.cleanup() + """ Cleanup """ + logging.debug('cgroup_test cleanup') + print "Cleanup" + del (self.modules) ############################# @@ -77,7 +87,7 @@ class cgroup(test.test): Memory test """ def cleanup(supress=False): - # cleanup + """ cleanup """ logging.debug("test_memory: Cleanup") err = "" if item.rm_cgroup(pwd): @@ -87,51 +97,46 @@ class cgroup(test.test): if err: if supress: - logging.warn("Some parts of cleanup failed%s" % err) + logging.warn("Some parts of cleanup failed%s", err) else: raise error.TestFail("Some parts of cleanup failed%s" % err) # Preparation item = CG('memory', self._client) - if item.initialize(self.modules): - raise error.TestFail("cgroup init failed") - - if item.smoke_test(): - raise error.TestFail("smoke_test failed") - + item.initialize(self.modules) + item.smoke_test() pwd = item.mk_cgroup() - if pwd == None: - raise error.TestFail("Can't create cgroup") logging.debug("test_memory: Memory filling test") - - f = open('/proc/meminfo','r') - mem = f.readline() + meminfo = open('/proc/meminfo','r') + mem = meminfo.readline() while not mem.startswith("MemFree"): - mem = f.readline() + mem = meminfo.readline() # Use only 1G or max of the free memory mem = min(int(mem.split()[1])/1024, 1024) mem = max(mem, 100) # at least 100M - memsw_limit_bytes = item.get_property("memory.memsw.limit_in_bytes", - supress=True) - if memsw_limit_bytes is not None: + try: + memsw_limit_bytes = item.get_property("memory.memsw.limit_in_bytes") + except error.TestFail: + # Doesn't support memsw limitation -> disabling + logging.info("System does not support 'memsw'") + utils.system("swapoff -a") + memsw = False + else: + # Supports memsw memsw = True # Clear swap utils.system("swapoff -a") utils.system("swapon -a") - f.seek(0) - swap = f.readline() + meminfo.seek(0) + swap = meminfo.readline() while not swap.startswith("SwapTotal"): - swap = f.readline() + swap = meminfo.readline() swap = int(swap.split()[1])/1024 if swap < mem / 2: logging.error("Not enough swap memory to test 'memsw'") memsw = False - else: - # Doesn't support swap + memory limitation, disable swap - logging.info("System does not support 'memsw'") - utils.system("swapoff -a") - memsw = False + meminfo.close() outf = NamedTemporaryFile('w+', prefix="cgroup_client-", dir="/tmp") logging.debug("test_memory: Initializition passed") @@ -170,10 +175,8 @@ class cgroup(test.test): ################################################ logging.debug("test_memory: Memfill mem only limit") ps = item.test("memfill %d %s" % (mem, outf.name)) - if item.set_cgroup(ps.pid, pwd): - raise error.TestFail("Could not set cgroup") - if item.set_prop("memory.limit_in_bytes", ("%dM" % (mem/2)), pwd): - raise error.TestFail("Could not set mem limit (mem)") + item.set_cgroup(ps.pid, pwd) + item.set_prop("memory.limit_in_bytes", ("%dM" % (mem/2)), pwd) ps.stdin.write('\n') i = 0 while ps.poll() == None: @@ -218,10 +221,8 @@ class cgroup(test.test): if memsw: logging.debug("test_memory: Memfill mem + swap limit") ps = item.test("memfill %d %s" % (mem, outf.name)) - if item.set_cgroup(ps.pid, pwd): - raise error.TestFail("Could not set cgroup (memsw)") - if item.set_prop("memory.memsw.limit_in_bytes", "%dM"%(mem/2), pwd): - raise error.TestFail("Could not set mem limit (memsw)") + item.set_cgroup(ps.pid, pwd) + item.set_prop("memory.memsw.limit_in_bytes", "%dM"%(mem/2), pwd) ps.stdin.write('\n') i = 0 while ps.poll() == None: @@ -265,9 +266,9 @@ class cgroup(test.test): Cpuset test 1) Initiate CPU load on CPU0, than spread into CPU* - CPU0 """ - class per_cpu_load: + class LoadPerCpu: """ - Handles the per_cpu_load stats + Handles the LoadPerCpu stats self.values [cpus, cpu0, cpu1, ...] """ def __init__(self): @@ -275,14 +276,14 @@ class cgroup(test.test): Init """ self.values = [] - self.f = open('/proc/stat', 'r') - line = self.f.readline() + self.stat = open('/proc/stat', 'r') + line = self.stat.readline() while line: if line.startswith('cpu'): self.values.append(int(line.split()[1])) else: break - line = self.f.readline() + line = self.stat.readline() def reload(self): """ @@ -295,11 +296,11 @@ class cgroup(test.test): Get the current values @return vals: array of current values [cpus, cpu0, cpu1..] """ - self.f.seek(0) - self.f.flush() + self.stat.seek(0) + self.stat.flush() vals = [] - for i in range(len(self.values)): - vals.append(int(self.f.readline().split()[1])) + for _ in range(len(self.values)): + vals.append(int(self.stat.readline().split()[1])) return vals def tick(self): @@ -316,11 +317,12 @@ class cgroup(test.test): return ret def cleanup(supress=False): - # cleanup + """ cleanup """ logging.debug("test_cpuset: Cleanup") err = "" try: for task in tasks: + i = 0 for i in range(10): task.terminate() if task.poll() != None: @@ -334,7 +336,7 @@ class cgroup(test.test): err += "\nCan't remove cgroup direcotry" if err: if supress: - logging.warn("Some parts of cleanup failed%s" % err) + logging.warn("Some parts of cleanup failed%s", err) else: raise error.TestFail("Some parts of cleanup failed%s" % err) @@ -343,8 +345,8 @@ class cgroup(test.test): if item.initialize(self.modules): raise error.TestFail("cgroup init failed") - # FIXME: new cpuset cgroup doesn't have any mems and cpus assigned - # thus smoke_test won't work + # in cpuset cgroup it's necessarily to set certain values before + # usage. Thus smoke_test will fail. #if item.smoke_test(): # raise error.TestFail("smoke_test failed") @@ -355,9 +357,6 @@ class cgroup(test.test): raise error.TestFail("Failed to get no_cpus or no_cpus = 1") pwd = item.mk_cgroup() - if pwd == None: - raise error.TestFail("Can't create cgroup") - # FIXME: new cpuset cgroup doesn't have any mems and cpus assigned try: tmp = item.get_prop("cpuset.cpus") item.set_property("cpuset.cpus", tmp, pwd) @@ -378,25 +377,27 @@ class cgroup(test.test): # Run no_cpus + 1 jobs for i in range(no_cpus + 1): tasks.append(item.test("cpu")) - if item.set_cgroup(tasks[i].pid, pwd): + try: + item.set_cgroup(tasks[i].pid, pwd) + except error.TestFail, inst: cleanup(True) - raise error.TestFail("Failed to set cgroup") + raise error.TestFail("Failed to set cgroup: %s", inst) tasks[i].stdin.write('\n') - stats = per_cpu_load() + stats = LoadPerCpu() # Use only the first CPU item.set_property("cpuset.cpus", 0, pwd) stats.reload() time.sleep(10) # [0] = all cpus - s1 = stats.tick()[1:] - s2 = s1[1:] - s1 = s1[0] - for _s in s2: - if s1 < _s: + stat1 = stats.tick()[1:] + stat2 = stat1[1:] + stat1 = stat1[0] + for _stat in stat2: + if stat1 < _stat: cleanup(True) raise error.TestFail("Unused processor had higher utilization\n" "used cpu: %s, remaining cpus: %s" - % (s1, s2)) + % (stat1, stat2)) if no_cpus == 2: item.set_property("cpuset.cpus", "1", pwd) @@ -404,15 +405,15 @@ class cgroup(test.test): item.set_property("cpuset.cpus", "1-%d"%(no_cpus-1), pwd) stats.reload() time.sleep(10) - s1 = stats.tick()[1:] - s2 = s1[0] - s1 = s1[1:] - for _s in s1: - if s2 > _s: + stat1 = stats.tick()[1:] + stat2 = stat1[0] + stat1 = stat1[1:] + for _stat in stat1: + if stat2 > _stat: cleanup(True) raise error.TestFail("Unused processor had higher utilization\n" "used cpus: %s, remaining cpu: %s" - % (s1, s2)) + % (stat1, stat2)) logging.debug("test_cpuset: Cpu allocation test passed") ################################################ diff --git a/client/tests/cgroup/cgroup_common.py b/client/tests/cgroup/cgroup_common.py index 6934926..7a514c6 100755 --- a/client/tests/cgroup/cgroup_common.py +++ b/client/tests/cgroup/cgroup_common.py @@ -6,11 +6,24 @@ Helpers for cgroup testing. @copyright: 2011 Red Hat Inc. @author: Lukas Doktor <ldoktor@xxxxxxxxxx> """ -import os, logging, subprocess, time, shutil +import logging, os, shutil, subprocess, time, traceback from tempfile import mkdtemp from autotest_lib.client.bin import utils from autotest_lib.client.common_lib import error +def _traceback(name, exc_info): + """ + Formats traceback into lines "name: line\nname: line" + @param name: desired line preposition + @param exc_info: sys.exc_info of the exception + @return: string which contains beautifully formatted exception + """ + out = "\n" + for line in traceback.format_exception(exc_info[0], exc_info[1], + exc_info[2]): + out += "%s: %s" % (name, line) + return out + class Cgroup(object): """ @@ -44,15 +57,11 @@ class Cgroup(object): Initializes 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 + if not self.root: + raise error.TestFail("cg.initialize(): Module %s not found" + % self.module) def mk_cgroup(self, root=None): @@ -67,19 +76,16 @@ class Cgroup(object): else: pwd = mkdtemp(prefix='cgroup-', dir=self.root) + '/' except Exception, inst: - logging.error("cg.mk_cgroup(): %s" , inst) - return None + raise error.TestFail("cg.mk_cgroup(): %s" % inst) self.cgroups.append(pwd) return pwd - def rm_cgroup(self, pwd, supress=False): + def rm_cgroup(self, pwd): """ Removes cgroup. @param pwd: cgroup directory. - @param supress: supress output. - @return: 0 when PASSED """ try: os.rmdir(pwd) @@ -88,10 +94,7 @@ class Cgroup(object): logging.warn("cg.rm_cgroup(): Removed cgroup which wasn't created" "using this Cgroup") except Exception, inst: - if not supress: - logging.error("cg.rm_cgroup(): %s" , inst) - return -1 - return 0 + raise error.TestFail("cg.rm_cgroup(): %s" % inst) def test(self, cmd): @@ -136,19 +139,14 @@ class Cgroup(object): 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 + raise error.TestFail("cg.set_cgroup(): %s" % inst) 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 + raise error.TestFail("cg.set_cgroup(): Setting %d pid into %s " + "cgroup failed" % (pid, pwd)) def set_root_cgroup(self, pid): """ @@ -159,29 +157,25 @@ class Cgroup(object): return self.set_cgroup(pid, self.root) - def get_prop(self, prop, pwd=None, supress=False): + def get_prop(self, prop, pwd=None): """ Gets one line of the property value @param prop: property name (file) @param pwd: cgroup directory - @param supress: supress the output @return: String value or None when FAILED """ - tmp = self.get_property(prop, pwd, supress) + tmp = self.get_property(prop, pwd) if tmp: if tmp[0][-1] == '\n': tmp[0] = tmp[0][:-1] return tmp[0] - else: - return None - def get_property(self, prop, pwd=None, supress=False): + def get_property(self, prop, pwd=None): """ Gets the property value @param prop: property name (file) @param pwd: cgroup directory - @param supress: supress the output @return: [] values or None when FAILED """ if pwd == None: @@ -189,10 +183,9 @@ class Cgroup(object): try: ret = open(pwd+prop, 'r').readlines() except Exception, inst: - ret = None - if not supress: - logging.error("cg.get_property(): %s" , inst) - return ret + raise error.TestFail("cg.get_property(): %s" % inst) + else: + return ret def set_prop(self, prop, value, pwd=None, check=True): @@ -202,7 +195,6 @@ class Cgroup(object): @param value: desired value @param pwd: cgroup directory @param check: check the value after setup - @return: 0 when PASSED """ _value = value try: @@ -216,9 +208,9 @@ class Cgroup(object): elif value[-1] == 'G': value = int(value[:-1]) * 1073741824 except: - logging.error("cg.set_prop() fallback into cg.set_property.") + logging.warn("cg.set_prop() fallback into cg.set_property.") value = _value - return self.set_property(prop, value, pwd, check) + self.set_property(prop, value, pwd, check) def set_property(self, prop, value, pwd=None, check=True): @@ -228,7 +220,6 @@ class Cgroup(object): @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: @@ -236,16 +227,14 @@ class Cgroup(object): try: open(pwd+prop, 'w').write(value) except Exception, inst: - logging.error("cg.set_property(): %s" , inst) - return -1 + raise error.TestFail("cg.set_property(): %s" % inst) 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 + raise error.TestFail("cg.set_property(): Setting failed: " + "desired = %s, real value = %s" + % (value, _value)) def smoke_test(self): @@ -253,66 +242,42 @@ class Cgroup(object): 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 + raise error.TestFail("cg.smoke_test: Couldn't create process") - part += 1 if (ps.poll() != None): - logging.error("cg.smoke_test[%d]: Process died unexpectidly", part) - return -1 + raise error.TestFail("cg.smoke_test: Process died unexpectidly") # 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 + raise error.TestFail("cg.smoke_test: Process is not a root member") # 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 + self.set_cgroup(ps.pid, pwd) # 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 + try: + self.rm_cgroup(pwd) + except error.TestFail: + pass + else: + raise error.TestFail("cg.smoke_test: Unexpected successful deletion" + " of the used cgroup") # 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 + self.set_root_cgroup(ps.pid) # 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 directory", - part) - return -1 + self.rm_cgroup(pwd) # 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 + raise error.TestFail("cg.smoke_test: Process is not finished") class CgroupModules(object): @@ -386,13 +351,6 @@ class CgroupModules(object): return len(self.modules[0]) - def cleanup(self): - """ - Kept for compatibility - """ - pass - - def get_pwd(self, module): """ Returns the mount directory of 'module' diff --git a/client/tests/kvm/tests/cgroup.py b/client/tests/kvm/tests/cgroup.py index d6418b5..415b334 100644 --- a/client/tests/kvm/tests/cgroup.py +++ b/client/tests/kvm/tests/cgroup.py @@ -185,18 +185,12 @@ def run_cgroup(test, params, env): raise error.TestError("Could not initialize blkio Cgroup") for i in range(2): pwd.append(blkio.mk_cgroup()) - if pwd[i] == None: - raise error.TestError("Can't create cgroup") - if blkio.set_cgroup(self.vms[i].get_shell_pid(), pwd[i]): - raise error.TestError("Could not set cgroup") + blkio.set_cgroup(self.vms[i].get_shell_pid(), pwd[i]) # Move all existing threads into cgroup for tmp in get_all_pids(self.vms[i].get_shell_pid()): - if blkio.set_cgroup(int(tmp), pwd[i]): - raise error.TestError("Could not set cgroup") - if self.blkio.set_property("blkio.weight", 100, pwd[0]): - raise error.TestError("Could not set blkio.weight") - if self.blkio.set_property("blkio.weight", 1000, pwd[1]): - raise error.TestError("Could not set blkio.weight") + blkio.set_cgroup(int(tmp), pwd[i]) + self.blkio.set_property("blkio.weight", 100, pwd[0]) + self.blkio.set_property("blkio.weight", 1000, pwd[1]) # Add dummy drives # TODO: implement also using QMP. -- 1.7.6.2 -- 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