v1: add 2 vcpupin cases
* use pinVcpuFlags to pin domain vcpu to host cpu
* 2 cases cover config and live flags
* cpulist with '^', '-' and ',' is supported to give multiple
host cpus
* vcpus and vcpuPinInfo are used as part of the checking
* a sample conf is added
v2: move format cpulist functions to utils
* the format cpulist functions could be reused for cases need
parse param with '-', '^' and ','.
Signed-off-by: Wayne Sun <gsun@xxxxxxxxxx>
---
cases/vcpupin.conf | 67 +++++++++++++++++++++++
repos/setVcpus/vcpupin_config.py | 109 ++++++++++++++++++++++++++++++++++++++
repos/setVcpus/vcpupin_live.py | 101 +++++++++++++++++++++++++++++++++++
utils/utils.py | 71 ++++++++++++++++++++++++
4 files changed, 348 insertions(+), 0 deletions(-)
create mode 100644 cases/vcpupin.conf
create mode 100644 repos/setVcpus/vcpupin_config.py
create mode 100644 repos/setVcpus/vcpupin_live.py
diff --git a/cases/vcpupin.conf b/cases/vcpupin.conf
new file mode 100644
index 0000000..880247f
--- /dev/null
+++ b/cases/vcpupin.conf
@@ -0,0 +1,67 @@
+domain:install_linux_cdrom
+ guestname
+ $defaultname
+ guestos
+ $defaultos
+ guestarch
+ $defaultarch
+ vcpu
+ 4
+ memory
+ $defaultmem
+ hddriver
+ $defaulthd
+ nicdriver
+ $defaultnic
+ imageformat
+ qcow2
+
+setVcpus:vcpupin_live
+ guestname
+ $defaultname
+ vcpu
+ 0
+ cpulist
+ 2,4-6,^4
+
+setVcpus:vcpupin_live
+ guestname
+ $defaultname
+ vcpu
+ 1
+ cpulist
+ 3
+
+domain:destroy
+ guestname
+ $defaultname
+
+setVcpus:vcpupin_config
+ guestname
+ $defaultname
+ vcpu
+ 2
+ cpulist
+ 0-8,^1
+
+setVcpus:vcpupin_config
+ guestname
+ $defaultname
+ vcpu
+ 3
+ cpulist
+ ^2,0-8
+
+domain:start
+ guestname
+ $defaultname
+
+domain:destroy
+ guestname
+ $defaultname
+
+domain:undefine
+ guestname
+ $defaultname
+
+options cleanup=enable
diff --git a/repos/setVcpus/vcpupin_config.py b/repos/setVcpus/vcpupin_config.py
new file mode 100644
index 0000000..80df659
--- /dev/null
+++ b/repos/setVcpus/vcpupin_config.py
@@ -0,0 +1,109 @@
+#!/usr/bin/env python
+# Test domain vcpu pin with flag VIR_DOMAIN_AFFECT_CONFIG, check
+# domain config xml with vcpupin configuration.
+
+import re
+from xml.dom import minidom
+
+import libvirt
+from libvirt import libvirtError
+
+from src import sharedmod
+from utils import utils
+
+required_params = ('guestname', 'vcpu', 'cpulist',)
+optional_params = {}
+
+def vcpupin_check(domobj, vcpu, cpumap):
+ """check domain config xml with vcpupin element
+ """
+ guestxml = domobj.XMLDesc(2)
+ logger.debug("domain %s xml :\n%s" %(domobj.name(), guestxml))
+
+ doc = minidom.parseString(guestxml)
+ vcpupin = doc.getElementsByTagName('vcpupin')
+ if not vcpupin:
+ logger.error("no vcpupin element in domain xml")
+ return 1
+
+ for i in range(len(vcpupin)):
+ if vcpupin[i].hasAttribute('vcpu') and \
+ vcpupin[i].hasAttribute('cpuset'):
+ vcpu_attr = vcpupin[i].getAttributeNode('vcpu')
+ cpu_attr = vcpupin[i].getAttributeNode('cpuset')
+ if int(vcpu_attr.nodeValue) == vcpu:
+ cpulist = cpu_attr.nodeValue
+ if cpulist == '':
+ cpumap_tmp = ()
+ for i in range(maxcpu):
+ cpumap_tmp += (False,)
+ else:
+ cpumap_tmp = utils.param_to_tuple(cpulist, maxcpu)
+
+ if cpumap_tmp == cpumap:
+ logger.info("cpuset is as expected in domain xml")
+ return 0
+ else:
+ logger.error("cpuset is not as expected in domain xml")
+ return 1
+
+ if i == len(vcpupin) - 1:
+ logger.error("the vcpupin element with given vcpu is not found")
+ return 1
+
+def vcpupin_config(params):
+ """pin domain vcpu to host cpu with config flag
+ """
+ global logger
+ logger = params['logger']
+ params.pop('logger')
+ guestname = params['guestname']
+ vcpu = int(params['vcpu'])
+ cpulist = params['cpulist']
+
+ logger.info("the name of virtual machine is %s" % guestname)
+ logger.info("the given vcpu is %s" % vcpu)
+ logger.info("the given cpulist is %s" % cpulist)
+
+ global maxcpu
+ maxcpu = utils.get_host_cpus()
+ logger.info("%s physical cpu on host" % maxcpu)
+
+ conn = sharedmod.libvirtobj['conn']
+
+ try:
+ domobj = conn.lookupByName(guestname)
+ cpumap = utils.param_to_tuple(cpulist, maxcpu)
+
+ if not cpumap:
+ logger.error("cpulist: Invalid format")
+ return 1
+
+ logger.debug("cpumap for vcpu pin is:")
+ logger.debug(cpumap)
+
+ logger.info("pin domain vcpu %s to host cpulist %s with flag: %s" %
+ (vcpu, cpulist, libvirt.VIR_DOMAIN_AFFECT_CONFIG))
+ domobj.pinVcpuFlags(vcpu, cpumap, libvirt.VIR_DOMAIN_AFFECT_CONFIG)
+
+ logger.info("check vcpu pin info")
+ ret = domobj.vcpuPinInfo(libvirt.VIR_DOMAIN_AFFECT_CONFIG)
+ logger.debug("vcpu pin info is:")
+ logger.debug(ret)
+ if ret[vcpu] == cpumap:
+ logger.info("vcpu pin info is expected")
+ else:
+ logger.error("vcpu pin info is not expected")
+ return 1
+ except libvirtError, e:
+ logger.error("libvirt call failed: " + str(e))
+ return 1
+
+ logger.info("check domain vcpupin configuration in xml")
+ ret = vcpupin_check(domobj, vcpu, cpumap)
+ if ret:
+ logger.error("domain vcpu pin check failed")
+ return 1
+ else:
+ logger.info("domain vcpu pin check succeed")
+ return 0
diff --git a/repos/setVcpus/vcpupin_live.py b/repos/setVcpus/vcpupin_live.py
new file mode 100644
index 0000000..c3dfe8e
--- /dev/null
+++ b/repos/setVcpus/vcpupin_live.py
@@ -0,0 +1,101 @@
+#!/usr/bin/env python
+# Test domain vcpu pin with flag VIR_DOMAIN_AFFECT_LIVE, check
+# vcpu subprocess status under domain task list on host.
+
+import re
+
+import libvirt
+from libvirt import libvirtError
+
+from src import sharedmod
+from utils import utils
+
+required_params = ('guestname', 'vcpu', 'cpulist',)
+optional_params = {}
+
+def vcpupin_check(guestname, vcpu, cpumap):
+ """check vcpu subprocess status of the running virtual machine
+ grep Cpus_allowed_list /proc/PID/task/*/status
+ """
+ tmp_str = ''
+ cmd = "cat /var/run/libvirt/qemu/%s.pid" % guestname
+ status, pid = utils.exec_cmd(cmd, shell=True)
+ if status:
+ logger.error("failed to get the pid of domain %s" % guestname)
+ return 1
+
+ cmd = "grep Cpus_allowed_list /proc/%s/task/*/status" % pid[0]
+ status, output = utils.exec_cmd(cmd, shell=True)
+ logger.debug("command '%s' output is:" % cmd)
+ for i in range(len(output)):
+ tmp_str += ''.join(output[i]) + '\n'
+ logger.debug(tmp_str)
+
+ task_list = output[1:]
+ vcpu_task = task_list[int(vcpu)]
+ cpulist = vcpu_task.split('\t')[1]
+ ret = utils.param_to_tuple(cpulist, maxcpu)
+
+ if ret == cpumap:
+ logger.info("vcpu process cpus allowed list is expected")
+ return 0
+ else:
+ logger.error("vcpu process cpus allowed list is not expected")
+ return 1
+
+def vcpupin_live(params):
+ """pin domain vcpu to host cpu with live flag
+ """
+ global logger
+ logger = params['logger']
+ params.pop('logger')
+ guestname = params['guestname']
+ vcpu = int(params['vcpu'])
+ cpulist = params['cpulist']
+
+ logger.info("the name of virtual machine is %s" % guestname)
+ logger.info("the given vcpu is %s" % vcpu)
+ logger.info("the given cpulist is %s" % cpulist)
+
+ global maxcpu
+ maxcpu = utils.get_host_cpus()
+ logger.info("%s physical cpu on host" % maxcpu)
+
+ conn = sharedmod.libvirtobj['conn']
+
+ try:
+ domobj = conn.lookupByName(guestname)
+ cpumap = utils.param_to_tuple(cpulist, maxcpu)
+ if not cpumap:
+ logger.error("cpulist: Invalid format")
+ return 1
+
+ logger.debug("cpumap for vcpu pin is:")
+ logger.debug(cpumap)
+
+ logger.info("pin domain vcpu %s to host cpu %s with flag: %s" %
+ (vcpu, cpulist, libvirt.VIR_DOMAIN_AFFECT_LIVE))
+ domobj.pinVcpuFlags(vcpu, cpumap, libvirt.VIR_DOMAIN_AFFECT_LIVE)
+
+ logger.info("check vcpus info")
+ ret = domobj.vcpus()
+ logger.debug("vcpus info is:")
+ logger.debug(ret)
+ if ret[1][vcpu] == cpumap:
+ logger.info("vcpus info is expected")
+ else:
+ logger.error("vcpus info is not expected")
+ return 1
+
+ except libvirtError, e:
+ logger.error("libvirt call failed: " + str(e))
+ return 1
+
+ logger.info("check vcpu pin status on host")
+ ret = vcpupin_check(guestname, vcpu, cpumap)
+ if ret:
+ logger.error("domain vcpu pin failed")
+ return 1
+ else:
+ logger.info("domain vcpu pin succeed")
+ return 0
diff --git a/utils/utils.py b/utils/utils.py
index e242847..36171cf 100644
--- a/utils/utils.py
+++ b/utils/utils.py
@@ -645,6 +645,77 @@ def run_mount_app(hostname, username, password,
print "mount fail"
return 1
+def format_parammap(paramlist, map_test, length):
+ """paramlist contains numbers which can be divided by '-', '^' and
+ ',', map_test is a tuple for getting it's content (True or False)
+ and form the new tuple base on numbers in paramlist, length is
+ the length of the return tuple
+ """
+ parammap = ()
+
+ try:
+ if re.match('\^', paramlist):
+ unuse = int(re.split('\^', paramlist)[1])
+ for i in range(length):
+ if i == unuse:
+ parammap += (False,)
+ else:
+ parammap += (map_test[i],)
+
+ elif '-' in paramlist:
+ param = re.split('-', paramlist)
+ if not len(param) == 2:
+ return False
+ if not int(param[1]) < length:
+ print "paramlist: out of max range"
+ return False
+ if int(param[1]) < int(param[0]):
+ return False
+
+ for i in range(length):
+ if i in range(int(param[0]), int(param[1])+1):
+ parammap += (True,)
+ else:
+ parammap += (map_test[i],)
+
+ else:
+ for i in range(length):
+ if i == int(paramlist):
+ parammap += (True,)
+ else:
+ parammap += (map_test[i],)
+
+ return parammap
+ except ValueError, e:
+ print "ValueError: " + str(e)
+ return False
+
+def param_to_tuple(paramlist, length):
+ """paramlist contains numbers which can be divided by '-', '^' and
+ ',', length is the length of the return tuple, return tuple only
+ have True or False value
+ """
+ map_test = ()
+ for i in range(length):
+ map_test += (False,)
+
+ if ',' in paramlist:
+ param = re.split(',', paramlist)
+ for i in range(len(param)):
+ parammap = format_parammap(param[i], map_test, length)
+ if parammap:
+ map_test = parammap
+ else:
+ return False
+ return parammap
+
+ else:
+ parammap = format_parammap(paramlist, map_test, length)
+ if parammap:
+ return parammap
+ else:
+ return False
+
def run_wget_app(hostname, username, password, file_url, logger):
"""Simple test for wget app on specified host"""
cmd_line = "wget -P /tmp %s -o /tmp/wget.log" % (file_url)