Use setVcpusFlags API to set domain vcpu with flags, domain could be active or not. Flags could be '0', 'live', 'config', 'maximum' and their combinations, use '|' between flags for combinations. A sample conf file also added. Signed-off-by: Wayne Sun <gsun@xxxxxxxxxx> --- cases/set_vcpus_flags.conf | 56 ++++++++ repos/domain/set_vcpus_flags.py | 283 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 339 insertions(+), 0 deletions(-) create mode 100644 cases/set_vcpus_flags.conf create mode 100644 repos/domain/set_vcpus_flags.py diff --git a/cases/set_vcpus_flags.conf b/cases/set_vcpus_flags.conf new file mode 100644 index 0000000..7da13a2 --- /dev/null +++ b/cases/set_vcpus_flags.conf @@ -0,0 +1,56 @@ +domain:install_linux_cdrom + guestname + $defaultname + guestos + $defaultos + guestarch + $defaultarch + vcpu + $defaultvcpu + memory + $defaultmem + hddriver + $defaulthd + nicdriver + $defaultnic + imageformat + qcow2 + +domain:set_vcpus_flags + guestname + $defaultname + vcpu + 4 + flags + 0|config|live + username + $username + password + $password + +domain:destroy + guestname + $defaultname + +domain:set_vcpus_flags + guestname + $defaultname + vcpu + 5 + flags + 0|config + +domain:set_vcpus_flags + guestname + $defaultname + vcpu + 6 + flags + maximum + +domain:undefine + guestname + $defaultname + +options cleanup=enable + diff --git a/repos/domain/set_vcpus_flags.py b/repos/domain/set_vcpus_flags.py new file mode 100644 index 0000000..ca614cc --- /dev/null +++ b/repos/domain/set_vcpus_flags.py @@ -0,0 +1,283 @@ +#!/usr/bin/env python +# Test set domain vcpu with flags. Flags could be 0, live, config, +# maximum and their combinations, use '|' for combinations. If +# domain is active, username and password should be provided, else +# not. + +import time +import commands +from xml.dom import minidom + +import libvirt +from libvirt import libvirtError + +from src import sharedmod +from utils import utils + +required_params = ('guestname', 'vcpu', 'flags', ) +optional_params = { + 'username': 'root', + 'password': '', + } + +def check_domain_running(conn, guestname): + """ check if the domain exists, may or may not be active """ + guest_names = [] + ids = conn.listDomainsID() + for id in ids: + obj = conn.lookupByID(id) + guest_names.append(obj.name()) + + if guestname not in guest_names: + logger.info("%s is not running" % guestname) + return 1 + else: + return 0 + +def redefine_vcpu_number(domobj, guestname, vcpu): + """dump domain xml description to change the vcpu number, + then, define the domain again + """ + guestxml = domobj.XMLDesc(0) + logger.debug('''original guest %s xml :\n%s''' %(guestname, guestxml)) + + doc = minidom.parseString(guestxml) + + newvcpu = doc.createElement('vcpu') + newvcpuval = doc.createTextNode(str(vcpu)) + newvcpu.appendChild(newvcpuval) + newvcpu.setAttribute('current', '1') + + domain = doc.getElementsByTagName('domain')[0] + oldvcpu = doc.getElementsByTagName('vcpu')[0] + + domain.replaceChild(newvcpu, oldvcpu) + + return doc.toxml() + +def check_current_vcpu(domobj, state, flag, username, password): + """dump domain xml description to get current vcpu number and + check vcpu in domain if domain is active + """ + if len(flag) == 1 and flag[0] == '0': + if state: + flag.append('config') + else: + flag.append('live') + + if len(flag) == 1 and flag[0] == 'maximum': + if state: + flag.append('config') + else: + logger.error("'maximum' on live domain is not supported'") + return False + + if 'live' in flag: + if 'maximum' in flag: + logger.error("'live' with 'maximum' is not supported'") + return False + + guestxml = domobj.XMLDesc(1) + logger.debug("domain %s xml is :\n%s" %(domobj.name(), guestxml)) + + xml = minidom.parseString(guestxml) + vcpu = xml.getElementsByTagName('vcpu')[0] + if vcpu.hasAttribute('current'): + attr = vcpu.getAttributeNode('current') + current_vcpu = int(attr.nodeValue) + else: + logger.info("no 'current' attribute in vcpu element") + return False + + if not state: + if password == '' and username == 'root': + logger.error("check will fail with empty root password") + return False + + logger.info("check cpu number in domain") + ip = utils.mac_to_ip(mac, 180) + + cmd = "cat /proc/cpuinfo | grep processor | wc -l" + ret, output = utils.remote_exec_pexpect(ip, username, password, cmd) + if not ret: + logger.info("cpu number in domain is %s" % output) + if int(output) == current_vcpu: + logger.info("cpu in domain is equal to current vcpu value") + else: + logger.error("current vcpu is not equal as check in domain") + return False + else: + logger.error("check in domain fail") + return False + + if 'config' in flag: + guestxml = domobj.XMLDesc(2) + logger.debug("domain %s xml is :\n%s" %(domobj.name(), guestxml)) + + xml = minidom.parseString(guestxml) + vcpu = xml.getElementsByTagName('vcpu')[0] + if 'maximum' in flag: + current_vcpu = int(vcpu.childNodes[0].data) + else: + if vcpu.hasAttribute('current'): + attr = vcpu.getAttributeNode('current') + conf_vcpu = int(attr.nodeValue) + if 'live' in flag: + if not current_vcpu == conf_vcpu: + return False + else: + current_vcpu = conf_vcpu + else: + logger.info("no 'current' attribute in vcpu element") + return False + + return current_vcpu + +def set_vcpus_offline(domobj, guestname, vcpu): + """offline set the domain vcpu as given and current value as 1, + then boot up the domain + """ + timeout = 60 + logger.info('destroy domain') + + try: + domobj.destroy() + except libvirtError, e: + logger.error("libvirt call failed: " + str(e)) + logger.error("fail to destroy domain") + return 1 + + newguestxml = redefine_vcpu_number(domobj, guestname, vcpu) + logger.debug('''new guest %s xml :\n%s''' %(guestname, newguestxml)) + + logger.info("undefine the original guest") + try: + domobj.undefine() + except libvirtError, e: + logger.error("libvirt call failed: " + str(e)) + logger.error("fail to undefine guest %" % guestname) + return 1 + + logger.info("define guest with new xml") + try: + conn = domobj._conn + conn.defineXML(newguestxml) + except libvirtError, e: + logger.error("libvirt call failed: " + str(e)) + logger.error("fail to define guest %s" % guestname) + return 1 + + try: + logger.info('boot guest up ...') + domobj.create() + except libvirtError, e: + logger.error("libvirt call failed: " + str(e)) + logger.error("fail to start domain %s" % guestname) + return 1 + + timeout = 600 + + while timeout: + time.sleep(10) + timeout -= 10 + + logger.debug("get ip by mac address") + ip = utils.mac_to_ip(mac, 180) + logger.debug("the ip address of vm %s is %s" % (guestname, ip)) + + if not ip: + logger.info(str(timeout) + "s left") + else: + logger.info("vm %s power on successfully" % guestname) + logger.info("the ip address of vm %s is %s" % (guestname, ip)) + break + + if timeout <= 0: + logger.info("fail to power on vm %s" % guestname) + return 1 + + return 0 + +def set_vcpus_flags(params): + """set domain vcpu with flags and check + """ + global logger + logger = params['logger'] + params.pop('logger') + guestname = params['guestname'] + vcpu = int(params['vcpu']) + flags = params['flags'] + username = params.get('username', 'root') + password = params.get('password', '') + + logger.info("the name of virtual machine is %s" % guestname) + logger.info("the vcpu given is %s" % vcpu) + + logger.info("the flags is %s" % flags) + flags_string = flags.split("|") + + flags = 0 + for flag in flags_string: + if flag == '0': + flags |= 0 + elif flag == 'live': + flags |= libvirt.VIR_DOMAIN_AFFECT_LIVE + elif flag == 'config': + flags |= libvirt.VIR_DOMAIN_AFFECT_CONFIG + elif flag == 'maximum': + flags |= libvirt.VIR_DOMAIN_VCPU_MAXIMUM + else: + logger.error("unknown flag") + return 1 + + conn = sharedmod.libvirtobj['conn'] + + domobj = conn.lookupByName(guestname) + logger.debug("get the mac address of vm %s" % guestname) + global mac + mac = utils.get_dom_mac_addr(guestname) + logger.debug("the mac address of vm %s is %s" % (guestname, mac)) + + num = vcpu + 1 + try: + max_vcpus = int(conn.getMaxVcpus('kvm')) + logger.debug("hypervisor supported max vcpu is %s" % max_vcpus) + except libvirtError, e: + logger.error("libvirt call failed: " + str(e)) + return 1 + + if num > max_vcpus: + logger.error("vcpu must smaller than max number: %s" % max_vcpus) + return 1 + + state = check_domain_running(conn, guestname) + + if state: + try: + logger.info("set domain maximum vcpu as: %s" % num) + domobj.setVcpusFlags(num, libvirt.VIR_DOMAIN_VCPU_MAXIMUM) + except libvirtError, e: + logger.error("libvirt call failed: " + str(e)) + return 1 + else: + logger.info("set domain vcpu to %s and restart with current cpu as 1" % + num) + ret = set_vcpus_offline(domobj, guestname, num) + if ret != 0: + return 1 + + try: + logger.info("set vcpus to %s with flag: %s" % (vcpu, flags)) + domobj.setVcpusFlags(vcpu, flags) + logger.info("set vcpu with flag succeed") + except libvirtError, e: + logger.error("libvirt call failed: " + str(e)) + return 1 + + ret = check_current_vcpu(domobj, state, flags_string, username, password) + if ret == 'False': + logger.error("check set vcpu failed") + return 1 + elif ret == vcpu: + logger.info("check set vcpu succeed") + return 0 -- 1.7.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list