The case will validate the getAllDomainStats API in class virConnect --- repos/virconn/connection_getAllDomainStats.py | 528 ++++++++++++++++++++++++++ 1 file changed, 528 insertions(+) create mode 100644 repos/virconn/connection_getAllDomainStats.py diff --git a/repos/virconn/connection_getAllDomainStats.py b/repos/virconn/connection_getAllDomainStats.py new file mode 100644 index 0000000..023564a --- /dev/null +++ b/repos/virconn/connection_getAllDomainStats.py @@ -0,0 +1,528 @@ +#!/usr/bin/env python +# test getAllDomainStats() API for libvirt + +import libvirt + +from xml.dom import minidom +from libvirt import libvirtError +from src import sharedmod +from utils import utils + +required_params = () +optional_params = {'stats': '','flags': ''} + +ds = {"state": libvirt.VIR_DOMAIN_STATS_STATE, + "cpu": libvirt.VIR_DOMAIN_STATS_CPU_TOTAL, + "balloon": libvirt.VIR_DOMAIN_STATS_BALLOON, + "vcpu": libvirt.VIR_DOMAIN_STATS_VCPU, + "interface": libvirt.VIR_DOMAIN_STATS_INTERFACE, + "block": libvirt.VIR_DOMAIN_STATS_BLOCK} + +fg = {"active": libvirt.VIR_CONNECT_GET_ALL_DOMAINS_STATS_ACTIVE, + "inactive": libvirt.VIR_CONNECT_GET_ALL_DOMAINS_STATS_INACTIVE, + "persistent": libvirt.VIR_CONNECT_GET_ALL_DOMAINS_STATS_PERSISTENT, + "transient": libvirt.VIR_CONNECT_GET_ALL_DOMAINS_STATS_TRANSIENT, + "running": libvirt.VIR_CONNECT_GET_ALL_DOMAINS_STATS_RUNNING, + "paused": libvirt.VIR_CONNECT_GET_ALL_DOMAINS_STATS_PAUSED, + "shutoff": libvirt.VIR_CONNECT_GET_ALL_DOMAINS_STATS_SHUTOFF, + "other": libvirt.VIR_CONNECT_GET_ALL_DOMAINS_STATS_OTHER, + "backing": libvirt.VIR_CONNECT_GET_ALL_DOMAINS_STATS_BACKING, + "enforce": libvirt.VIR_CONNECT_GET_ALL_DOMAINS_STATS_ENFORCE_STATS} + +def filer_domains(logger, flags): + """ + return a filtered domains set + """ + a = set(active_domains(logger)) + d = set(defined_domains(logger)) + if flags & libvirt.VIR_CONNECT_GET_ALL_DOMAINS_STATS_PERSISTENT and \ + flags & libvirt.VIR_CONNECT_GET_ALL_DOMAINS_STATS_TRANSIENT: + domains = a | d + elif flags & libvirt.VIR_CONNECT_GET_ALL_DOMAINS_STATS_PERSISTENT: + domains = d + elif flags & libvirt.VIR_CONNECT_GET_ALL_DOMAINS_STATS_TRANSIENT: + domains = a - d + else: + domains = a | d + if flags & libvirt.VIR_CONNECT_GET_ALL_DOMAINS_STATS_ACTIVE and \ + flags & libvirt.VIR_CONNECT_GET_ALL_DOMAINS_STATS_INACTIVE: + domains &= (a | d) + elif flags & libvirt.VIR_CONNECT_GET_ALL_DOMAINS_STATS_ACTIVE: + domains &= a + elif flags & libvirt.VIR_CONNECT_GET_ALL_DOMAINS_STATS_INACTIVE: + domains &= (d - a) + else: + domains &= a | d + return domains + +def active_domains(logger): + """ + return active domains on current uri + """ + NUM = "ls /run/libvirt/qemu|grep \".xml\"" + status, output = utils.exec_cmd(NUM, shell=True) + output = [item.replace(".xml","") for item in output] + if status == 0: + logger.debug("Got active domains: %s" % output) + return output + else: + logger.debug("Got active domains: %s" % output) + return output + +def defined_domains(logger): + """ + return defined domains on current uri + """ + NUM = "ls /etc/libvirt/qemu|grep \".xml\"" + status, output = utils.exec_cmd(NUM, shell=True) + output = [item.replace(".xml","") for item in output] + if status == 0: + logger.debug("Got defined domains: %s" % output) + return output + else: + logger.debug("Got defined domains: %s" % output) + return output + +def compare_value(logger,op1,op2): + """ + compare 2 variables value + """ + if op1 != op2: + logger.debug("Check %s: Fail" % op2) + return False + else: + logger.debug("Check %s: Pass" % op2) + return True + +def check_vcpu(logger,dom_name,dom_active,dom_eles): + """ + check vcpu info of given domain + """ + iDOM_XML = "/etc/libvirt/qemu/" + dom_name +".xml" + aDOM_XML = "/run/libvirt/qemu/" + dom_name +".xml" + if dom_active: + xml = minidom.parse(aDOM_XML) + dom = xml.getElementsByTagName('domain')[0] + vcpu = dom.getElementsByTagName('vcpu')[0] + vcpu_max = int(vcpu.childNodes[0].data) + if not vcpu.getAttribute('current'): + vcpu_cur = vcpu_max + else: + vcpu_cur = int(vcpu.getAttribute('current')) + + logger.debug("Checking vcpu.current: %d" \ + % dom_eles.get("vcpu.current")) + if not compare_value(logger,vcpu_cur, \ + dom_eles.get("vcpu.current")): + return False + logger.debug("Checking vcpu.maximum: %d" \ + % dom_eles.get("vcpu.maximum")) + if not compare_value(logger,vcpu_max, \ + dom_eles.get("vcpu.maximum")): + return False + else: + xml = minidom.parse(iDOM_XML) + vcpu = xml.getElementsByTagName('vcpu')[0] + vcpu_max = int(vcpu.childNodes[0].data) + logger.debug("Checking vcpu.maximum: %d" \ + % dom_eles.get("vcpu.maximum")) + if not compare_value(logger,vcpu_max, \ + dom_eles.get("vcpu.maximum")): + return False + #for each vcpu.state field + check_each_vcpu(logger,dom_name,dom_active,dom_eles) + return True + +def check_each_vcpu(logger,dom_name,dom_active,dom_eles): + """ + check each vcpu info, but ignore vcpu.*.time + """ + iDOM_XML = "/etc/libvirt/qemu/" + dom_name +".xml" + aDOM_XML = "/run/libvirt/qemu/" + dom_name +".xml" + vcpu_index = 0 + if dom_active: + vcpu_stat = 1 + xml = minidom.parse(aDOM_XML) + dom = xml.getElementsByTagName('vcpus')[0] + dom_pid = str(xml.getElementsByTagName("domstatus")[0].\ + getAttributeNode('pid').nodeValue) + vcpu = dom.getElementsByTagName('vcpu') + for vcpu_sub in vcpu: + proc_path = "/proc/" + vcpu_pre = "vcpu."+ str(vcpu_index) + "." + attr1 = dom_eles.get(vcpu_pre +"state") + logger.debug("Checking %sstate: %d" %(vcpu_pre, attr1)) + if not compare_value(logger,vcpu_stat, attr1): + return False + vcpu_index +=1 + else: + vcpu_stat = 0 + xml = minidom.parse(iDOM_XML) + vcpu = xml.getElementsByTagName('vcpu')[0] + vcpu_max = int(vcpu.childNodes[0].data) + vcpu_cur = vcpu.getAttributeNode('current') + if not vcpu_cur: + for i in range(0,vcpu_max): + vcpu_pre = "vcpu."+ str(i) + "." + logger.debug("Checking %sstate: %d" \ + %(vcpu_pre, dom_eles.get(vcpu_pre + "state"))) + if not compare_value(logger,vcpu_stat, \ + dom_eles.get(vcpu_pre + "state")): + return False + elif int(vcpu_cur.nodeValue) <= vcpu_max: + for i in range(0,int(vcpu_cur.nodeValue)): + vcpu_pre = "vcpu."+ str(i) + "." + logger.debug("Checking %sstate: %d" \ + %(vcpu_pre, dom_eles.get(vcpu_pre + "state"))) + if not compare_value(logger,vcpu_stat, \ + dom_eles.get(vcpu_pre + "state")): + return False + return True + +def check_balloon(logger,dom_name,dom_active,dom_eles): + """ + check balloon of given domain + """ + iDOM_XML = "/etc/libvirt/qemu/" + dom_name +".xml" + aDOM_XML = "/run/libvirt/qemu/" + dom_name +".xml" + if dom_active: + xml = minidom.parse(aDOM_XML) + dom = xml.getElementsByTagName('domain')[0] + mem_max = int(dom.getElementsByTagName('memory')[0]\ + .childNodes[0].data) + mem_cur = int(dom.getElementsByTagName('currentMemory')[0]\ + .childNodes[0].data) + logger.debug("Checking balloon.maximum: %d" \ + % dom_eles.get("balloon.maximum")) + if not compare_value(logger,mem_max, \ + dom_eles.get("balloon.maximum")): + return False + logger.debug("Checking balloon.current: %d" \ + % dom_eles.get("balloon.current")) + if not compare_value(logger,mem_cur, \ + dom_eles.get("balloon.current")): + return False + else: + xml = minidom.parse(iDOM_XML) + mem_max = int(xml.getElementsByTagName('memory')[0].\ + childNodes[0].data) + logger.debug("Checking balloon.maximum: %d" \ + % dom_eles.get("balloon.maximum")) + if not compare_value(logger,mem_max, \ + dom_eles.get("balloon.maximum")): + return False + return True + +def check_interface(logger,dom_name,dom_active, dom_eles): + """ + check interface info, only check the count and name attributes + other sub-attributes of net.* will be ignored + """ + iDOM_XML = "/etc/libvirt/qemu/" + dom_name +".xml" + aDOM_XML = "/run/libvirt/qemu/" + dom_name +".xml" + netfile = "/proc/net/dev" + if dom_active: + xml = minidom.parse(aDOM_XML) + dom = xml.getElementsByTagName('domain')[0] + dev = dom.getElementsByTagName('devices')[0] + nic = dev.getElementsByTagName('interface') + logger.debug("Checking net.count: %d" % dom_eles.get("net.count")) + if not compare_value(logger,len(nic),dom_eles.get("net.count")): + return False + for iface in nic: + if_name = iface.getElementsByTagName("target")[0].\ + getAttribute('dev') + if_name += ":" + logger.debug("Checking %s" % if_name) + content = open(netfile, 'r') + if if_name in str(content.readlines()): + logger.debug("Check %s: Pass" % if_name) + else: + logger.debug("Check %s: Fail" % if_name) + return False + content.close() + else: + pass + return True + +def count_disk_chain(logger,filepath,dom_active): + """ + count deep of disk chain + """ + CMD = "file %s" + num = 0 + while True: + status, output = utils.exec_cmd(CMD % filepath, shell=True) + if status != 0: + logger.debug("Can not see the back file") + if "has backing file" in output[0]: + num +=1 + filepath = output[0].split("(path")[1].split(")")[0].strip() + else: + break + if not dom_active: + break + return num + +def check_block(logger,dom_name,dom_active,dom_eles,backing_f): + """ + check the block info, only check count, name and path attributes, + other sub-attributes of block.* will be ignored + """ + iDOM_XML = "/etc/libvirt/qemu/" + dom_name +".xml" + aDOM_XML = "/run/libvirt/qemu/" + dom_name +".xml" + disk_index = 0 + if dom_active: + xml = minidom.parse(aDOM_XML) + dom = xml.getElementsByTagName('domain')[0] + dev = dom.getElementsByTagName('devices')[0] + disk = dev.getElementsByTagName('disk') + disk_count = len(disk) + for dk in disk: + disk_name = dk.getElementsByTagName('target')[0]\ + .getAttributeNode('dev').nodeValue + disk_sour = dk.getElementsByTagName('source')[0]\ + .getAttributeNode('file').nodeValue + if backing_f: + disk_count += count_disk_chain(logger,disk_sour,dom_active) + logger.debug("Checking disk.count: %d" % dom_eles.get("block.count")) + if not compare_value(logger,disk_count,dom_eles.get("block.count")): + return False + if not check_each_block(logger,dom_name,dom_eles,backing_f): + return False + else: + xml = minidom.parse(iDOM_XML) + dev = xml.getElementsByTagName('devices')[0] + disk = dev.getElementsByTagName('disk') + disk_count = len(disk) + logger.debug("Checking disk.count: %d" % dom_eles.get("block.count")) + if not compare_value(logger,disk_count,dom_eles.get("block.count")): + return False + for dk in disk: + disk_pre = "block."+ str(disk_index) + "." + disk_name = dk.getElementsByTagName('target')[0]\ + .getAttributeNode('dev').nodeValue + logger.debug("Checking %sname: %s" \ + % (disk_pre, dom_eles.get(disk_pre + "name"))) + if not compare_value(logger,disk_name,\ + dom_eles.get(disk_pre + "name")): + return False + disk_sour = dk.getElementsByTagName('source')[0]\ + .getAttributeNode('file').nodeValue + logger.debug("Checking %spath: %s" \ + % (disk_pre, dom_eles.get(disk_pre + "path"))) + if not compare_value(logger,disk_sour,\ + dom_eles.get(disk_pre + "path")): + return False + disk_index += 1 + return True + +def check_each_block(logger,dom_name,dom_eles,backing_f): + """ + for a active domain, this function will list all backing + block info + """ + aDOM_XML = "/run/libvirt/qemu/" + dom_name +".xml" + disk_index = 0 + xml = minidom.parse(aDOM_XML) + dom = xml.getElementsByTagName('domain')[0] + dev = dom.getElementsByTagName('devices')[0] + disk = dev.getElementsByTagName('disk') + for dk in disk: + disk_pre = "block."+ str(disk_index) + "." + disk_name = dk.getElementsByTagName('target')[0]\ + .getAttributeNode('dev').nodeValue + disk_sour = dk.getElementsByTagName('source')[0]\ + .getAttributeNode('file').nodeValue + logger.debug("Checking %s %s" % (disk_name,disk_sour)) + if not compare_value(logger,disk_name, \ + dom_eles.get(disk_pre + "name")): + return False + if not compare_value(logger,disk_sour, \ + dom_eles.get(disk_pre + "path")): + return False + if not backing_f: + disk_index += 1 + continue + while True: + temp = dk.getElementsByTagName('backingStore')[0] + if temp.hasChildNodes(): + temp_name = disk_name + temp_backingIndex = int(temp.getAttributeNode('index').\ + nodeValue) + temp_path = temp.getElementsByTagName('source')[0].\ + getAttributeNode('file').nodeValue + logger.debug("Checking %s %s %s" \ + % (temp_name, temp_backingIndex, temp_path)) + disk_index += 1 + disk_pre = "block."+ str(disk_index) + "." + if not compare_value(logger,temp_name, \ + dom_eles.get(disk_pre + "name")): + return False + if not compare_value(logger,temp_backingIndex, \ + dom_eles.get(disk_pre + "backingIndex")): + return False + if not compare_value(logger,temp_path, \ + dom_eles.get(disk_pre + "path")): + return False + else: + break + dk = temp + disk_index += 1 + return True + +def connection_getAllDomainStats(params): + """ + test API for getAllDomainStats in class virConnect, the script need + static values to compare with those returned by API,but they are + hard to calculate, so ignore below attributes temporarily: + cpu.time + cpu.user + cpu.system + *.*.time + net.*.rx.* + net.*.tx.* + block.*.rd + block.*.wr + block.*.fl + ... + for below two attributes, no good method to obtain values when + out of libvirt, pass them temporarily too. + state.state + state.reason + """ + balloon_f = False + vcpu_f = False + interface_f = False + block_f = False + backing_f = False + filter_f = True + + logger = params['logger'] + domstats = params.get('stats', "all") + domstats_string = domstats.split("|") + logger.info("The stats are %s" % domstats) + domstats = 0 + for domstat in domstats_string: + if domstat == 'state': + domstats |= ds.get('state') + elif domstat == 'cpu': + domstats |= ds.get('cpu') + elif domstat == 'balloon': + domstats |= ds.get('balloon') + balloon_f = True + elif domstat == 'vcpu': + domstats |= ds.get('vcpu') + vcpu_f = True + elif domstat == 'interface': + domstats |= ds.get('interface') + interface_f = True + elif domstat == 'block': + domstats |= ds.get('block') + block_f = True + elif domstat == "all": + domstats = 0 + balloon_f = True + vcpu_f = True + interface_f = True + block_f = True + else: + logger.error("Unknown flags") + return 1 + logger.info("The given stats is %d" % domstats) + + flags = params.get('flags',"all") + logger.info("The flags are %s" % flags) + flags_string = flags.split("|") + flags = 0 + for flag in flags_string: + if flag == 'active': + flags |= fg.get('active') + elif flag == 'inactive': + flags |= fg.get('inactive') + elif flag == 'persistent': + flags |= fg.get('persistent') + elif flag == 'transient': + flags |= fg.get('transient') + elif flag == 'running': + flags |= fg.get('running') + filter_f = False + elif flag == 'paused': + flags |= fg.get('paused') + filter_f = False + elif flag == 'shutoff': + flags |= fg.get('shutoff') + filter_f = False + elif flag == 'other': + flags |= fg.get('other') + filter_f = False + elif flag == 'backing': + flags |= fg.get('backing') + backing_f = True + elif flag == 'enforce': + flags |= fg.get('enforce') + elif flag == 'all': + flags = 0 + filter_f = False + else: + logger.error("Unknown flags") + return 1 + logger.info("The given flags is %d" % flags) + + try: + conn = sharedmod.libvirtobj['conn'] + + domstats_from_api = conn.getAllDomainStats(domstats,flags) + logger.info("Got the number of domain from API: %s" \ + % len(domstats_from_api)) + #filter expected domains + domains = filer_domains(logger,flags) + if not filter_f: + logger.info("Check the number of domain: Skip") + elif len(domains) == len(domstats_from_api): + logger.info("Available domains: %s" % list(domains)) + logger.info("Check the number of domain %s: Pass" \ + % len(domstats_from_api)) + else: + logger.info("Available domains: %s" % list(domains)) + logger.info("Check the number of domain %s: Fail" \ + % len(domstats_from_api)) + return 1 + + for dom in domstats_from_api: + dom_name = dom[0].name() + dom_active = dom[0].isActive() + dom_eles = dom[1] + logger.debug("Domain elements are %s" %(dom_eles)) + logger.info("Checking %s:" %(dom_name)) + if vcpu_f: + if not check_vcpu(logger,dom_name,dom_active,dom_eles): + logger.info("Failed to check vcpu states") + return 1 + else: + logger.info("Success to check vcpu state") + if balloon_f: + if not check_balloon(logger,dom_name,dom_active,dom_eles): + logger.info("Failed to check balloon state") + return 1 + else: + logger.info("Success to check balloon state") + if interface_f: + if not check_interface(logger,dom_name,dom_active,dom_eles): + logger.info("Failed to check interface state") + return 1 + else: + logger.info("Success to check interface state") + if block_f: + if not check_block(logger,dom_name,dom_active,\ + dom_eles,backing_f): + logger.info("Failed to check block state") + return 1 + else: + logger.info("Success to check block state") + + except libvirtError, e: + logger.error("API error message: %s" % e.message) + return 1 + + return 0 -- 1.8.3.1 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list