[libvirt] [libvirt-test-API][PATCH] Add connection_getDomainCapabilities test case
hongming
honzhang at redhat.com
Fri Mar 27 02:52:11 UTC 2015
On 03/26/2015 05:06 PM, jiahu wrote:
> This case will test getDomainCapabilities API, and
> connection_getDomainCapabilities test case was added to
> test_connection.conf
> ---
> cases/test_connection.conf | 10 +
> repos/virconn/connection_getDomainCapabilities.py | 438 ++++++++++++++++++++++
> 2 files changed, 448 insertions(+)
> create mode 100644 repos/virconn/connection_getDomainCapabilities.py
>
> diff --git a/cases/test_connection.conf b/cases/test_connection.conf
> index 7552024..5719937 100644
> --- a/cases/test_connection.conf
> +++ b/cases/test_connection.conf
> @@ -47,3 +47,13 @@ virconn:free_pages
> 0
> pagesize
> 4k,2M
> +
> +virconn:connection_getDomainCapabilities
> + emulatorbin
> + /usr/libexec/qemu-kvm
> + arch
> + x86_64
> + machine
> + pc-i440fx-rhel7.0.0
> + virttype
> + kvm
> diff --git a/repos/virconn/connection_getDomainCapabilities.py b/repos/virconn/connection_getDomainCapabilities.py
> new file mode 100644
> index 0000000..f0cfa1f
> --- /dev/null
> +++ b/repos/virconn/connection_getDomainCapabilities.py
> @@ -0,0 +1,438 @@
> +#!/usr/bin/env python
> +# test getDomainCapabilities() API for libvirtd
> +
> +import os
> +import libvirt
> +import hashlib
> +import fcntl
> +
> +from xml.dom import minidom
> +from libvirt import libvirtError
> +from src import sharedmod
> +from utils import utils
> +
> +required_params = ('emulatorbin','arch','machine','virttype',)
> +optional_params = {}
> +
> +QEMU_CAPS = ""
> +API_FILE = "/tmp/caps_from_api.xml"
> +CMD = "rm -rf %s"
> +OVMF = "/usr/share/OVMF/OVMF_CODE.fd"
> +IOMMU = "/sys/kernel/iommu_groups/"
> +VFIO = "/dev/vfio/vfio"
> +KVM = "/dev/kvm"
> +KVM_CHECK_EXTENSION = 44547
> +KVM_CAP_IOMMU = 18
> +maxcpu = 0
> +
> +ovmf_f = False
> +drive = False
> +drive_forma = False
> +drive_readonly = False
> +blk_sg_io = False
> +usb_storage = False
> +device = False
> +scsi_generic = False
> +vfio_pci = False
> +
> +def clean_env(logger):
> + """
> + clean testing environment
> + """
> + status, output = utils.exec_cmd(CMD % API_FILE, shell=True)
> + if status != 0:
> + logger.error("Can not delete %s" % API_FILE)
> + else:
> + logger.debug("Deleted %s successfully" % API_FILE)
> +
> +def get_hypervisor_ver(emulatorbin,logger):
> + """
> + Obtain qemu-kvm's version, and return a number value of version
> + """
> + RPM = "rpm -qf %s"
> + status, package = utils.exec_cmd(RPM % emulatorbin, shell=True)
> + if not status:
> + logger.debug("The package is %s" % package)
> + else:
> + logger.debug("The package is %s" % package)
> + return 0
> + package = package[0].split('-')
> + version = ""
> + for item in package:
> + if not item.isalnum():
> + for v in item.split("."):
> + version = version + v.rjust(3,"0")
> + break
> + return int(version)
> +
> +def validate_caps_from_hv(emulatorbin,logger):
> + """
> + Validate the relative caps between libvirt and qemu-kvm
> + """
> + F1 = "%s -h| grep \"\-drive\""
> + F2 = "%s -h| grep \"format=\""
> + F3 = "%s -h| grep \"readonly=\""
> + F4 = "%s -h| grep \"^\\-device\""
> + l = [F1,F2,F3,F4]
> + flags = []
> + for item in l:
> + status, temp = utils.exec_cmd(item % emulatorbin, shell=True)
> + if not status:
> + flags.append(True)
> + logger.debug("Got: %s from vh" % temp)
> + else:
> + flags.append(False)
> + logger.debug("Got: %s from vh" % temp)
> + if get_hypervisor_ver(emulatorbin,logger) >= 11000:
> + flags.append(True)
> + else:
> + flags.append(False)
> + libvirt_f = [drive,drive_forma,drive_readonly,device,blk_sg_io]
> + if flags == libvirt_f:
> + return True
> + else:
> + return False
> +
> +def generate_hash(emulatorbin,logger):
> + """
> + generate file name using sha256
> + """
> + global QEMU_CAPS
> + QEMU_CAPS = "/var/cache/libvirt/qemu/capabilities/"
> + file_name = hashlib.sha256(emulatorbin).hexdigest()
> + QEMU_CAPS = QEMU_CAPS + file_name + ".xml"
> + logger.debug("Cache file is %s" % QEMU_CAPS)
> +
> +def get_maxcpu(machine,logger):
> + """
> + return maxcpu for given machine type from QEMU_CAPS xml
> + """
> + global maxcpu
> + xml = minidom.parse(QEMU_CAPS)
> + qemu = xml.getElementsByTagName('qemuCaps')[0]
> + for item in qemu.getElementsByTagName('machine'):
> + if item.getAttribute('name') == machine:
> + maxcpu = int(item.getAttribute('maxCpus'))
> + return True
> +
> +def get_os_flags(logger):
> + """
> + Read results from QEMU_CAPS file and set three flags
> + """
> + global drive, drive_forma, drive_readonly
> + xml = minidom.parse(QEMU_CAPS)
> + qemu = xml.getElementsByTagName('qemuCaps')[0]
> + for item in qemu.getElementsByTagName('flag'):
> + if item.getAttribute('name') == "drive":
> + drive = True
> + if item.getAttribute('name') == "drive-format":
> + drive_forma = True
> + if item.getAttribute('name') == "drive-readonly":
> + drive_readonly = True
> + logger.debug("drive = %s; drive_format = %s; drive_readonly = %s"\
> + % (drive,drive_forma,drive_readonly))
> + return True
> +
> +def get_disk_flags(logger):
> + """
> + Read results from QEMU_CAPS file and set two flags
> + """
> + global blk_sg_io,usb_storage
> + xml = minidom.parse(QEMU_CAPS)
> + qemu = xml.getElementsByTagName('qemuCaps')[0]
> + for item in qemu.getElementsByTagName('flag'):
> + if item.getAttribute('name') == "blk-sg-io":
> + blk_sg_io = True
> + if item.getAttribute('name') == "usb-storage":
> + usb_storage = True
> + logger.debug("blk_sg_io = %s; usb_storage = %s" % (blk_sg_io,usb_storage))
> + return True
> +
> +def get_hostdev_flags(logger):
> + """
> + Read results from QEMU_CAPS file and set three flags
> + """
> + global device, scsi_generic,vfio_pci
> + xml = minidom.parse(QEMU_CAPS)
> + for item in xml.getElementsByTagName('flag'):
> + if item.getAttribute('name') == "device":
> + device = True
> + if item.getAttribute('name') == "scsi-generic":
> + scsi_generic = True
> + if item.getAttribute('name') == "vfio-pci":
> + vfio_pci = True
> + logger.debug("device = %s; scsi_generic = %s; vfio_pci = %s"\
> + % (device,scsi_generic,vfio_pci))
> + return True
> +
> +def supportsPassthroughVFIO(logger):
> + """
> + check the vfio mode
> + """
> + if not os.path.exists(IOMMU):
> + logger.error("File %s is not exist" % IOMMU)
> + return False
> + if not os.path.exists(VFIO):
> + logger.error("Module %s is not exist" % VFIO)
> + return False
> + if len(os.listdir(IOMMU)) > 0:
> + return True
> + return False
> +
> +def supportsPassthroughKVM(logger):
> + """
> + check the legacy kvm mode
> + """
> + if not os.path.exists(KVM):
> + logger.error("File %s is not exist" % KVM)
> + return False
> + with open(KVM, "r") as kvmfd:
> + if fcntl.ioctl(kvmfd,KVM_CHECK_EXTENSION,KVM_CAP_IOMMU) == 1:
> + return True
> + return False
> +
> +def check_common_values(given_list,logger):
> + """
> + Check path/machine/arch/vcpu parameters
> + """
> + xml = minidom.parse(API_FILE)
> + dom = xml.getElementsByTagName('domainCapabilities')[0]
> + #get path/machine/arch/vcpu from xml generated by api
> + path = dom.getElementsByTagName('path')[0].childNodes[0].data
> + domain = dom.getElementsByTagName('domain')[0].childNodes[0].data
> + machine = dom.getElementsByTagName('machine')[0].childNodes[0].data
> + arch = dom.getElementsByTagName('arch')[0].childNodes[0].data
> + vcpu = dom.getElementsByTagName('vcpu')[0].getAttribute('max')
> + #put all of them to a list
> + list1 = [str(path),str(machine),str(arch),int(vcpu)]
> + logger.debug("Got 4 common parameters: %s" % list1)
> + if given_list == list1:
> + logger.debug("Checking common value: Pass")
> + else:
> + logger.debug("Checking common value: Fail")
> + return False
> + return True
> +
> +def check_os(arch, logger):
> + """
> + check the os part
> + """
> + alltype = ["rom","pflash"]
> + allreadonly = ["yes","no"]
> + type_api = []
> + readonly_api = []
> + xml = minidom.parse(API_FILE)
> + dom = xml.getElementsByTagName('domainCapabilities')[0]
> + os = dom.getElementsByTagName('os')[0]
> + loader = os.getElementsByTagName('loader')[0]
> + ovmf1 = os.getElementsByTagName('value')[0]
> + ovmf1 = ovmf1.childNodes[0].data
> + logger.debug("Got OVMF path is %s" % ovmf1)
> + if ovmf_f and ovmf1 == OVMF:
> + pass
> + else:
> + return False
> + enum = loader.getElementsByTagName('enum')
> + for item in enum:
> + if item.getAttribute('name') == "type":
> + value = item.getElementsByTagName("value")
> + for temp in value:
> + type_api.append(str(temp.childNodes[0].data))
> + if item.getAttribute('name') == "readonly":
> + value = item.getElementsByTagName("value")
> + for temp in value:
> + readonly_api.append(str(temp.childNodes[0].data))
> + if not (drive & drive_forma):
> + alltype.remove("pflash")
> + if not drive_readonly:
> + allreadonly = []
> + logger.debug("Got type list: %s" % type_api)
> + logger.debug("Got readonly list: %s" % readonly_api)
> + if not type_api == alltype:
> + return False
> + if not readonly_api == allreadonly:
> + return False
> + return True
> +
> +def check_disk(logger):
> + """
> + check the disk part in <devices>
> + """
> + alldevice = ["disk","cdrom","floppy","lun"]
> + allbus = ["ide","fdc","scsi","virtio","usb"]
> + device_api = []
> + bus_api = []
> + xml = minidom.parse(API_FILE)
> + dom = xml.getElementsByTagName('domainCapabilities')[0]
> + devices = dom.getElementsByTagName('devices')[0]
> + disk = devices.getElementsByTagName('disk')[0]
> + enum = disk.getElementsByTagName('enum')
> + for item in enum:
> + if item.getAttribute('name') == "diskDevice":
> + value = item.getElementsByTagName("value")
> + for temp in value:
> + device_api.append(str(temp.childNodes[0].data))
> + if item.getAttribute('name') == "bus":
> + value = item.getElementsByTagName("value")
> + for temp in value:
> + bus_api.append(str(temp.childNodes[0].data))
> + if not blk_sg_io:
> + alldevice.remove("lun")
> + if not usb_storage:
> + allbus.remove("usb")
> + logger.debug("Got diskDevice list: %s" % device_api)
> + logger.debug("Got bus list: %s" % bus_api)
> + if not device_api == alldevice:
> + return False
> + if not bus_api == allbus:
> + return False
> + return True
> +
> +def check_hostdev(logger):
> + """
> + check the hostdev part in <devices>
> + """
> + allmode = ["subsystem"]
> + allpolicy = ["default","mandatory","requisite","optional"]
> + allsubsys = ["usb","pci","scsi"]
> + allbackend = ["default","default","vfio","kvm"]
> + mode_api = []
> + policy_api = []
> + subsys_api = []
> + backend_api = []
> + caps_api = []
> + xml = minidom.parse(API_FILE)
> + dom = xml.getElementsByTagName('domainCapabilities')[0]
> + devices = dom.getElementsByTagName('devices')[0]
> + hostdev = devices.getElementsByTagName('hostdev')[0]
> + enum = hostdev.getElementsByTagName('enum')
> + for item in enum:
> + if item.getAttribute('name') == "mode":
> + value = item.getElementsByTagName("value")
> + for temp in value:
> + mode_api.append(str(temp.childNodes[0].data))
> + if item.getAttribute('name') == "startupPolicy":
> + value = item.getElementsByTagName("value")
> + for temp in value:
> + policy_api.append(str(temp.childNodes[0].data))
> + if item.getAttribute('name') == "subsysType":
> + value = item.getElementsByTagName("value")
> + for temp in value:
> + subsys_api.append(str(temp.childNodes[0].data))
> + if item.getAttribute('name') == "capsType":
> + value = item.getElementsByTagName("value")
> + for temp in value:
> + caps_api.append(str(temp.childNodes[0].data))
> + if item.getAttribute('name') == "pciBackend":
> + value = item.getElementsByTagName("value")
> + for temp in value:
> + backend_api.append(str(temp.childNodes[0].data))
> + #WIP, we need more codes to check vfio
> + if not (drive & device & scsi_generic):
> + allsubsys.remove("scsi")
> + if not (supportsPassthroughKVM(logger) & device):
> + allbackend.remove("default")
> + allbackend.remove("kvm")
> + if not (supportsPassthroughVFIO(logger) & vfio_pci):
> + allbackend.remove("default")
> + allbackend.remove("vfio")
> + logger.debug("Got mode list: %s" % mode_api)
> + logger.debug("Got startupPolicy list: %s" % policy_api)
> + logger.debug("Got subsysType list: %s" % subsys_api)
> + logger.debug("Got capsType list: %s" % caps_api)
> + logger.debug("Got pciBackend list: %s" % backend_api)
> + if not mode_api == allmode:
> + return False
> + if not policy_api == allpolicy:
> + return False
> + if not subsys_api == allsubsys:
> + return False
> + if not backend_api == allbackend:
> + return False
> + return True
> +
> +def connection_getDomainCapabilities(params):
> + """
> + test API for getDomainCapabilities in class virConnect
> + """
> + global ovmf_f
> + logger = params['logger']
> + emulatorbin = params['emulatorbin']
> + arch = params['arch']
> + machine = params['machine']
> + virttype = params['virttype']
> +
> + try:
> + logger.info("The specified emulatorbin is %s" \
> + % emulatorbin)
> + logger.info("The specified architecture is %s" \
> + % arch)
> + logger.info("The specified machine is %s" \
> + % machine)
> + logger.info("The specified virttype is %s" \
> + % virttype)
> +
> + generate_hash(emulatorbin, logger)
> + if not os.path.exists(QEMU_CAPS):
> + logger.error("cache file, %s is not exist" % QEMU_CAPS)
> + return 1
> + if os.path.exists(OVMF):
> + ovmf_f = True
> + else:
> + logger.warning("cache file, %s is not exist" % OVMF)
> + if not get_maxcpu(machine,logger):
> + logger.debug("get maxcpu: Fail")
> + return 1
> + if not get_os_flags(logger):
> + logger.debug("get os: Fail")
> + return 1
> + if not get_disk_flags(logger):
> + logger.debug("get disk: Fail")
> + return 1
> + if not get_hostdev_flags(logger):
> + logger.debug("get hostdev: Fail")
> + return 1
> + if not validate_caps_from_hv(emulatorbin,logger):
> + logger.error("Failed to compare caps")
> + return 1
> + else:
> + logger.debug("Successed to compare caps")
> +
> + conn = sharedmod.libvirtobj['conn']
> + caps_from_api = conn.getDomainCapabilities\
> +(emulatorbin,arch,machine,virttype,0)
> +
> + logger.debug("The return of API: %s" % caps_from_api)
> + fd = open(API_FILE,"w+")
> + fd.write(caps_from_api)
> + fd.flush()
> +
> + given_list = [emulatorbin,machine,arch,maxcpu]
> + if not check_common_values(given_list,logger):
> + logger.info("Failed to validate common elements")
> + return 1
> + else:
> + logger.info("Successed to validate common elements")
> + if not check_os(arch,logger):
> + logger.info("Failed to validate os block")
> + return 1
> + else:
> + logger.info("Successed to validate os block")
> + if not check_disk(logger):
> + logger.info("Failed to validate disk block")
> + return 1
> + else:
> + logger.info("Successed to validate disk block")
> + if not check_hostdev(logger):
> + logger.info("Failed to validate hostdev block")
> + return 1
> + else:
> + logger.info("Successed to validate hostdev block")
> +
> + except libvirtError, e:
> + logger.error("API error message: %s" % e.message)
> + clean_env(logger)
> + return 1
> +
> + clean_env(logger)
> + return 0
ACK and Pushed
Thanks
Hongming
More information about the libvir-list
mailing list