X-Git-Url: https://gerrit.fd.io/r/gitweb?p=csit.git;a=blobdiff_plain;f=resources%2Flibraries%2Fpython%2FQemuUtils.py;h=735feab4031460c8b298123b25cd663f0bf72e52;hp=e5f7c5905e6cca70e33b4a04329790d15da42013;hb=e001fdea995835f1ef75a5e21607ba02d78e4068;hpb=33bd6f2425ddff8e4167d36ea61b64ac81da3a65 diff --git a/resources/libraries/python/QemuUtils.py b/resources/libraries/python/QemuUtils.py index e5f7c5905e..735feab403 100644 --- a/resources/libraries/python/QemuUtils.py +++ b/resources/libraries/python/QemuUtils.py @@ -22,57 +22,16 @@ from re import match from distutils.version import StrictVersion from robot.api import logger -from resources.libraries.python.ssh import exec_cmd, exec_cmd_no_error from resources.libraries.python.Constants import Constants +from resources.libraries.python.DpdkUtil import DpdkUtil from resources.libraries.python.DUTSetup import DUTSetup -from resources.libraries.python.topology import NodeType, Topology +from resources.libraries.python.OptionString import OptionString from resources.libraries.python.VppConfigGenerator import VppConfigGenerator from resources.libraries.python.VPPUtil import VPPUtil +from resources.libraries.python.ssh import exec_cmd, exec_cmd_no_error +from resources.libraries.python.topology import NodeType, Topology -__all__ = ["QemuOptions", "QemuUtils"] - - -class QemuOptions(object): - """QEMU option class. - - The class can handle input parameters that acts as QEMU command line - parameters. The only variable is a list of dictionaries where dictionaries - can be added multiple times. This emulates the QEMU behavior where one - command line parameter can be used multiple times (1..N). Example can be - device or object (so it is not an issue to have one memory - block of 2G and and second memory block of 512M but from other numa). - - Class does support get value or string representation that will return - space separated, dash prefixed string of key value pairs used for command - line. - """ - - # Use one instance of class per tests. - ROBOT_LIBRARY_SCOPE = 'TEST CASE' - - def __init__(self): - self.variables = list() - - def add(self, variable, value): - """Add parameter to the list. - - :param variable: QEMU parameter name (without dash). - :param value: Paired value. - :type variable: str - :type value: str or int - """ - self.variables.append({str(variable): value}) - - def __str__(self): - """Return space separated string of key value pairs. - - The format is suitable to be pasted to qemu command line. - - :returns: Space separated string of key value pairs. - :rtype: str - """ - return " ".join(["-{k} {v}".format(k=d.keys()[0], v=d.values()[0]) - for d in self.variables]) +__all__ = ["QemuUtils"] class QemuUtils(object): @@ -81,8 +40,8 @@ class QemuUtils(object): # Use one instance of class per tests. ROBOT_LIBRARY_SCOPE = 'TEST CASE' - def __init__(self, node=None, qemu_id=1, smp=1, mem=512, vnf=None, - img='/var/lib/vm/vhost-nested.img', bin_path='/usr/bin'): + def __init__(self, node, qemu_id=1, smp=1, mem=512, vnf=None, + img=Constants.QEMU_VM_IMAGE): """Initialize QemuUtil class. :param node: Node to run QEMU on. @@ -91,17 +50,17 @@ class QemuUtils(object): :param mem: Amount of memory. :param vnf: Network function workload. :param img: QEMU disk image or kernel image path. - :param bin_path: QEMU binary path. :type node: dict :type qemu_id: int :type smp: int :type mem: int :type vnf: str :type img: str - :type bin_path: str """ self._vhost_id = 0 + self._node = node self._vm_info = { + 'host': node['host'], 'type': NodeType.VM, 'port': 10021 + qemu_id, 'serial': 4555 + qemu_id, @@ -109,12 +68,13 @@ class QemuUtils(object): 'password': 'cisco', 'interfaces': {}, } - if node: - self.qemu_set_node(node) + if node['port'] != 22: + self._vm_info['host_port'] = node['port'] + self._vm_info['host_username'] = node['username'] + self._vm_info['host_password'] = node['password'] # Input Options. self._opt = dict() self._opt['qemu_id'] = qemu_id - self._opt['bin_path'] = bin_path self._opt['mem'] = int(mem) self._opt['smp'] = int(smp) self._opt['img'] = img @@ -133,7 +93,7 @@ class QemuUtils(object): else: raise RuntimeError('QEMU: Unknown VM image option!') # Computed parameters for QEMU command line. - self._params = QemuOptions() + self._params = OptionString(prefix='-') self.add_params() def add_params(self): @@ -148,36 +108,38 @@ class QemuUtils(object): def add_default_params(self): """Set default QEMU command line parameters.""" - self._params.add('daemonize', '') - self._params.add('nodefaults', '') - self._params.add('name', 'vnf{qemu},debug-threads=on'. - format(qemu=self._opt.get('qemu_id'))) - self._params.add('no-user-config', '') - self._params.add('monitor', 'none') - self._params.add('display', 'none') - self._params.add('vga', 'none') - self._params.add('enable-kvm', '') - self._params.add('pidfile', '{pidfile}'. - format(pidfile=self._temp.get('pidfile'))) - self._params.add('cpu', 'host') - self._params.add('machine', 'pc,accel=kvm,usb=off,mem-merge=off') - self._params.add('smp', '{smp},sockets=1,cores={smp},threads=1'. - format(smp=self._opt.get('smp'))) - self._params.add('object', - 'memory-backend-file,id=mem,size={mem}M,' - 'mem-path=/dev/hugepages,share=on'. - format(mem=self._opt.get('mem'))) - self._params.add('m', '{mem}M'. - format(mem=self._opt.get('mem'))) - self._params.add('numa', 'node,memdev=mem') - self._params.add('balloon', 'none') + self._params.add('daemonize') + self._params.add('nodefaults') + self._params.add_with_value('name', 'vnf{qemu},debug-threads=on'.format( + qemu=self._opt.get('qemu_id'))) + self._params.add('no-user-config') + self._params.add_with_value('monitor', 'none') + self._params.add_with_value('display', 'none') + self._params.add_with_value('vga', 'none') + self._params.add('enable-kvm') + self._params.add_with_value('pidfile', self._temp.get('pidfile')) + self._params.add_with_value('cpu', 'host') + self._params.add_with_value( + 'machine', 'pc,accel=kvm,usb=off,mem-merge=off') + self._params.add_with_value( + 'smp', '{smp},sockets=1,cores={smp},threads=1'.format( + smp=self._opt.get('smp'))) + self._params.add_with_value( + 'object', 'memory-backend-file,id=mem,size={mem}M,' + 'mem-path=/dev/hugepages,share=on'.format(mem=self._opt.get('mem'))) + self._params.add_with_value( + 'm', '{mem}M'.format(mem=self._opt.get('mem'))) + self._params.add_with_value('numa', 'node,memdev=mem') + self._params.add_with_value('balloon', 'none') def add_nestedvm_params(self): """Set NestedVM QEMU parameters.""" - self._params.add('net', 'nic,macaddr=52:54:00:00:{qemu:02x}:ff'. - format(qemu=self._opt.get('qemu_id'))) - self._params.add('net', 'user,hostfwd=tcp::{info[port]}-:22'. - format(info=self._vm_info)) + self._params.add_with_value( + 'net', 'nic,macaddr=52:54:00:00:{qemu:02x}:ff'.format( + qemu=self._opt.get('qemu_id'))) + self._params.add_with_value( + 'net', 'user,hostfwd=tcp::{info[port]}-:22'.format( + info=self._vm_info)) # TODO: Remove try except after fully migrated to Bionic or # qemu_set_node is removed. try: @@ -185,33 +147,37 @@ class QemuUtils(object): if self.qemu_version(version='2.10') else '' except AttributeError: locking = '' - self._params.add('drive', - 'file={img},format=raw,cache=none,if=virtio{locking}'. - format(img=self._opt.get('img'), locking=locking)) - self._params.add('qmp', 'unix:{qmp},server,nowait'. - format(qmp=self._temp.get('qmp'))) - self._params.add('chardev', 'socket,host=127.0.0.1,port={info[serial]},' - 'id=gnc0,server,nowait'.format(info=self._vm_info)) - self._params.add('device', 'isa-serial,chardev=gnc0') - self._params.add('chardev', - 'socket,path={qga},server,nowait,id=qga0'. - format(qga=self._temp.get('qga'))) - self._params.add('device', 'isa-serial,chardev=qga0') + self._params.add_with_value( + 'drive', 'file={img},format=raw,cache=none,if=virtio{locking}'. + format(img=self._opt.get('img'), locking=locking)) + self._params.add_with_value( + 'qmp', 'unix:{qmp},server,nowait'.format(qmp=self._temp.get('qmp'))) + self._params.add_with_value( + 'chardev', 'socket,host=127.0.0.1,port={info[serial]},' + 'id=gnc0,server,nowait'.format(info=self._vm_info)) + self._params.add_with_value('device', 'isa-serial,chardev=gnc0') + self._params.add_with_value( + 'chardev', 'socket,path={qga},server,nowait,id=qga0'.format( + qga=self._temp.get('qga'))) + self._params.add_with_value('device', 'isa-serial,chardev=qga0') def add_kernelvm_params(self): """Set KernelVM QEMU parameters.""" - self._params.add('chardev', 'file,id=char0,path={log}'. - format(log=self._temp.get('log'))) - self._params.add('device', 'isa-serial,chardev=char0') - self._params.add('fsdev', 'local,id=root9p,path=/,security_model=none') - self._params.add('device', - 'virtio-9p-pci,fsdev=root9p,mount_tag=/dev/root') - self._params.add('kernel', '$(readlink -m {img}* | tail -1)'. - format(img=self._opt.get('img'))) - self._params.add('append', - '"ro rootfstype=9p rootflags=trans=virtio ' - 'console=ttyS0 tsc=reliable hugepages=256 ' - 'init={init}"'.format(init=self._temp.get('ini'))) + self._params.add_with_value( + 'chardev', 'file,id=char0,path={log}'.format( + log=self._temp.get('log'))) + self._params.add_with_value('device', 'isa-serial,chardev=char0') + self._params.add_with_value( + 'fsdev', 'local,id=root9p,path=/,security_model=none') + self._params.add_with_value( + 'device', 'virtio-9p-pci,fsdev=root9p,mount_tag=/dev/root') + self._params.add_with_value( + 'kernel', '$(readlink -m {img}* | tail -1)'.format( + img=self._opt.get('img'))) + self._params.add_with_value( + 'append', '"ro rootfstype=9p rootflags=trans=virtio console=ttyS0' + ' tsc=reliable hugepages=256 init={init}"'.format( + init=self._temp.get('ini'))) def create_kernelvm_config_vpp(self, **kwargs): """Create QEMU VPP config files. @@ -241,11 +207,12 @@ class QemuUtils(object): format(smp=self._opt.get('smp')-1)) vpp_config.add_dpdk_dev('0000:00:06.0', '0000:00:07.0') vpp_config.add_dpdk_log_level('debug') - vpp_config.add_dpdk_no_tx_checksum_offload() - vpp_config.add_dpdk_no_multi_seg() + if not kwargs['jumbo_frames']: + vpp_config.add_dpdk_no_multi_seg() + vpp_config.add_dpdk_no_tx_checksum_offload() vpp_config.add_plugin('disable', 'default') vpp_config.add_plugin('enable', 'dpdk_plugin.so') - vpp_config.apply_config(startup, restart_vpp=False) + vpp_config.write_config(startup) # Create VPP running configuration. template = '{res}/{tpl}.exec'.format(res=Constants.RESOURCES_TPL_VM, @@ -255,9 +222,62 @@ class QemuUtils(object): with open(template, 'r') as src_file: src = Template(src_file.read()) - exec_cmd_no_error(self._node, "echo '{out}' | sudo tee {running}". - format(out=src.safe_substitute(**kwargs), - running=running)) + exec_cmd_no_error( + self._node, "echo '{out}' | sudo tee {running}".format( + out=src.safe_substitute(**kwargs), running=running)) + + def create_kernelvm_config_testpmd_io(self, **kwargs): + """Create QEMU testpmd-io command line. + + :param kwargs: Key-value pairs to construct command line parameters. + :type kwargs: dict + """ + testpmd_path = ('{path}/{arch}-native-linuxapp-gcc/app'. + format(path=Constants.QEMU_VM_DPDK, + arch=Topology.get_node_arch(self._node))) + testpmd_cmd = DpdkUtil.get_testpmd_cmdline( + eal_corelist='0-{smp}'.format(smp=self._opt.get('smp') - 1), + eal_driver=False, + eal_in_memory=True, + pmd_num_mbufs=16384, + pmd_rxq=kwargs['queues'], + pmd_txq=kwargs['queues'], + pmd_tx_offloads=False, + pmd_disable_hw_vlan=False, + pmd_max_pkt_len=9200 if kwargs['jumbo_frames'] else None, + pmd_nb_cores=str(self._opt.get('smp') - 1)) + + self._opt['vnf_bin'] = ('{testpmd_path}/{testpmd_cmd}'. + format(testpmd_path=testpmd_path, + testpmd_cmd=testpmd_cmd)) + + def create_kernelvm_config_testpmd_mac(self, **kwargs): + """Create QEMU testpmd-mac command line. + + :param kwargs: Key-value pairs to construct command line parameters. + :type kwargs: dict + """ + testpmd_path = ('{path}/{arch}-native-linuxapp-gcc/app'. + format(path=Constants.QEMU_VM_DPDK, + arch=Topology.get_node_arch(self._node))) + testpmd_cmd = DpdkUtil.get_testpmd_cmdline( + eal_corelist='0-{smp}'.format(smp=self._opt.get('smp') - 1), + eal_driver=False, + eal_in_memory=True, + pmd_num_mbufs=16384, + pmd_fwd_mode='mac', + pmd_eth_peer_0='0,{mac}'.format(mac=kwargs['vif1_mac']), + pmd_eth_peer_1='1,{mac}'.format(mac=kwargs['vif2_mac']), + pmd_rxq=kwargs['queues'], + pmd_txq=kwargs['queues'], + pmd_tx_offloads=False, + pmd_disable_hw_vlan=False, + pmd_max_pkt_len=9200 if kwargs['jumbo_frames'] else None, + pmd_nb_cores=str(self._opt.get('smp') - 1)) + + self._opt['vnf_bin'] = ('{testpmd_path}/{testpmd_cmd}'. + format(testpmd_path=testpmd_path, + testpmd_cmd=testpmd_cmd)) def create_kernelvm_init(self, **kwargs): """Create QEMU init script. @@ -267,16 +287,16 @@ class QemuUtils(object): """ template = '{res}/init.sh'.format(res=Constants.RESOURCES_TPL_VM) init = self._temp.get('ini') - exec_cmd_no_error(self._node, 'rm -f {init}'.format(init=init), - sudo=True) + exec_cmd_no_error( + self._node, 'rm -f {init}'.format(init=init), sudo=True) with open(template, 'r') as src_file: src = Template(src_file.read()) - exec_cmd_no_error(self._node, "echo '{out}' | sudo tee {init}". - format(out=src.safe_substitute(**kwargs), - init=init)) - exec_cmd_no_error(self._node, "chmod +x {init}". - format(init=init), sudo=True) + exec_cmd_no_error( + self._node, "echo '{out}' | sudo tee {init}".format( + out=src.safe_substitute(**kwargs), init=init)) + exec_cmd_no_error( + self._node, "chmod +x {init}".format(init=init), sudo=True) def configure_kernelvm_vnf(self, **kwargs): """Create KernelVM VNF configurations. @@ -286,22 +306,13 @@ class QemuUtils(object): """ if 'vpp' in self._opt.get('vnf'): self.create_kernelvm_config_vpp(**kwargs) + elif 'testpmd_io' in self._opt.get('vnf'): + self.create_kernelvm_config_testpmd_io(**kwargs) + elif 'testpmd_mac' in self._opt.get('vnf'): + self.create_kernelvm_config_testpmd_mac(**kwargs) else: raise RuntimeError('QEMU: Unsupported VNF!') - self.create_kernelvm_init(vnf_bin=self._opt.get('vnf_bin')) - - def qemu_set_node(self, node): - """Set node to run QEMU on. - - :param node: Node to run QEMU on. - :type node: dict - """ - self._node = node - self._vm_info['host'] = node['host'] - if node['port'] != 22: - self._vm_info['host_port'] = node['port'] - self._vm_info['host_username'] = node['username'] - self._vm_info['host_password'] = node['password'] + self.create_kernelvm_init(vnf_bin=self._opt['vnf_bin']) def get_qemu_pids(self): """Get QEMU CPU pids. @@ -311,34 +322,40 @@ class QemuUtils(object): """ command = ("grep -rwl 'CPU' /proc/$(sudo cat {pidfile})/task/*/comm ". format(pidfile=self._temp.get('pidfile'))) - command += (r"| xargs dirname | sed -e 's/\/.*\///g'") + command += (r"| xargs dirname | sed -e 's/\/.*\///g' | uniq") stdout, _ = exec_cmd_no_error(self._node, command) return stdout.splitlines() def qemu_set_affinity(self, *host_cpus): """Set qemu affinity by getting thread PIDs via QMP and taskset to list - of CPU cores. + of CPU cores. Function tries to execute 3 times to avoid race condition + in getting thread PIDs. :param host_cpus: List of CPU cores. :type host_cpus: list """ - try: - qemu_cpus = self.get_qemu_pids() - - if len(qemu_cpus) != len(host_cpus): - raise ValueError('Host CPU count must match Qemu Thread count!') - - for qemu_cpu, host_cpu in zip(qemu_cpus, host_cpus): - command = ('taskset -pc {host_cpu} {thread}'. - format(host_cpu=host_cpu, thread=qemu_cpu)) - message = ('QEMU: Set affinity failed on {host}!'. - format(host=self._node['host'])) - exec_cmd_no_error(self._node, command, sudo=True, - message=message) - except (RuntimeError, ValueError): + for _ in range(3): + try: + qemu_cpus = self.get_qemu_pids() + + if len(qemu_cpus) != len(host_cpus): + sleep(1) + continue + for qemu_cpu, host_cpu in zip(qemu_cpus, host_cpus): + command = ('taskset -pc {host_cpu} {thread}'. + format(host_cpu=host_cpu, thread=qemu_cpu)) + message = ('QEMU: Set affinity failed on {host}!'. + format(host=self._node['host'])) + exec_cmd_no_error(self._node, command, sudo=True, + message=message) + break + except (RuntimeError, ValueError): + self.qemu_kill_all() + raise + else: self.qemu_kill_all() - raise + raise RuntimeError('Failed to set Qemu threads affinity!') def qemu_set_scheduler_policy(self): """Set scheduler policy to SCHED_RR with priority 1 for all Qemu CPU @@ -376,30 +393,26 @@ class QemuUtils(object): :type queues: int """ self._vhost_id += 1 - self._params.add('chardev', - 'socket,id=char{vhost},path={socket}{server}'. - format(vhost=self._vhost_id, socket=socket, - server=',server' if server is True else '')) - self._params.add('netdev', - 'vhost-user,id=vhost{vhost},' - 'chardev=char{vhost},queues={queues}'. - format(vhost=self._vhost_id, queues=queues)) + self._params.add_with_value( + 'chardev', 'socket,id=char{vhost},path={socket}{server}'.format( + vhost=self._vhost_id, socket=socket, + server=',server' if server is True else '')) + self._params.add_with_value( + 'netdev', 'vhost-user,id=vhost{vhost},chardev=char{vhost},' + 'queues={queues}'.format(vhost=self._vhost_id, queues=queues)) mac = ('52:54:00:00:{qemu:02x}:{vhost:02x}'. format(qemu=self._opt.get('qemu_id'), vhost=self._vhost_id)) queue_size = ('rx_queue_size={queue_size},tx_queue_size={queue_size}'. format(queue_size=queue_size)) if queue_size else '' mbuf = 'on,host_mtu=9200' - self._params.add('device', - 'virtio-net-pci,netdev=vhost{vhost},' - 'mac={mac},bus=pci.0,addr={addr}.0,mq=on,' - 'vectors={vectors},csum=off,gso=off,' - 'guest_tso4=off,guest_tso6=off,guest_ecn=off,' - 'mrg_rxbuf={mbuf},{queue_size}'. - format(addr=self._vhost_id+5, - vhost=self._vhost_id, mac=mac, - mbuf=mbuf if jumbo_frames else 'off', - queue_size=queue_size, - vectors=(2 * queues + 2))) + self._params.add_with_value( + 'device', 'virtio-net-pci,netdev=vhost{vhost},mac={mac},bus=pci.0,' + 'addr={addr}.0,mq=on,vectors={vectors},csum=off,gso=off,' + 'guest_tso4=off,guest_tso6=off,guest_ecn=off,mrg_rxbuf={mbuf},' + '{queue_size}'.format( + addr=self._vhost_id+5, vhost=self._vhost_id, mac=mac, + mbuf=mbuf if jumbo_frames else 'off', queue_size=queue_size, + vectors=(2 * queues + 2))) # Add interface MAC and socket to the node dict. if_data = {'mac_address': mac, 'socket': socket} @@ -426,14 +439,14 @@ class QemuUtils(object): format(cmd=cmd, qmp=self._temp.get('qmp'))) message = ('QMP execute "{cmd}" failed on {host}'. format(cmd=cmd, host=self._node['host'])) - stdout, _ = exec_cmd_no_error(self._node, command, sudo=False, - message=message) + stdout, _ = exec_cmd_no_error( + self._node, command, sudo=False, message=message) # Skip capabilities negotiation messages. out_list = stdout.splitlines() if len(out_list) < 3: - raise RuntimeError('Invalid QMP output on {host}'. - format(host=self._node['host'])) + raise RuntimeError( + 'Invalid QMP output on {host}'.format(host=self._node['host'])) return json.loads(out_list[2]) def _qemu_qga_flush(self): @@ -442,8 +455,8 @@ class QemuUtils(object): 'sudo -S socat - UNIX-CONNECT:{qga}'. format(qga=self._temp.get('qga'))) message = ('QGA flush failed on {host}'.format(host=self._node['host'])) - stdout, _ = exec_cmd_no_error(self._node, command, sudo=False, - message=message) + stdout, _ = exec_cmd_no_error( + self._node, command, sudo=False, message=message) return json.loads(stdout.split('\n', 1)[0]) if stdout else dict() @@ -460,8 +473,8 @@ class QemuUtils(object): format(cmd=cmd, qga=self._temp.get('qga'))) message = ('QGA execute "{cmd}" failed on {host}'. format(cmd=cmd, host=self._node['host'])) - stdout, _ = exec_cmd_no_error(self._node, command, sudo=False, - message=message) + stdout, _ = exec_cmd_no_error( + self._node, command, sudo=False, message=message) return json.loads(stdout.split('\n', 1)[0]) if stdout else dict() @@ -530,6 +543,8 @@ class QemuUtils(object): :param retries: Number of retries. :type retries: int """ + vpp_ver = VPPUtil.vpp_show_version(self._node) + for _ in range(retries): command = ('tail -1 {log}'.format(log=self._temp.get('log'))) stdout = None @@ -538,8 +553,11 @@ class QemuUtils(object): sleep(1) except RuntimeError: pass - if VPPUtil.vpp_show_version(self._node) in stdout: + if vpp_ver in stdout or 'Press enter to exit' in stdout: break + if 'reboot: Power down' in stdout: + raise RuntimeError('QEMU: NF failed to run on {host}!'. + format(host=self._node['host'])) else: raise RuntimeError('QEMU: Timeout, VM not booted on {host}!'. format(host=self._node['host'])) @@ -565,8 +583,8 @@ class QemuUtils(object): mac = interface.get('mac_address') if_name = mac_name.get(mac) if if_name is None: - logger.trace('Interface name for MAC {mac} not found'. - format(mac=mac)) + logger.trace( + 'Interface name for MAC {mac} not found'.format(mac=mac)) else: interface['name'] = if_name @@ -576,18 +594,19 @@ class QemuUtils(object): :returns: VM node info. :rtype: dict """ - command = ('{bin_path}/qemu-system-{arch} {params}'. - format(bin_path=self._opt.get('bin_path'), - arch=Topology.get_node_arch(self._node), - params=self._params)) + cmd_opts = OptionString() + cmd_opts.add('{bin_path}/qemu-system-{arch}'.format( + bin_path=Constants.QEMU_BIN_PATH, + arch=Topology.get_node_arch(self._node))) + cmd_opts.extend(self._params) message = ('QEMU: Start failed on {host}!'. format(host=self._node['host'])) try: - DUTSetup.check_huge_page(self._node, '/dev/hugepages', - self._opt.get('mem')) + DUTSetup.check_huge_page( + self._node, '/dev/hugepages', self._opt.get('mem')) - exec_cmd_no_error(self._node, command, timeout=300, sudo=True, - message=message) + exec_cmd_no_error( + self._node, cmd_opts, timeout=300, sudo=True, message=message) self._wait_until_vm_boot() except RuntimeError: self.qemu_kill_all() @@ -602,19 +621,15 @@ class QemuUtils(object): format(pidfile=self._temp.get('pidfile')), sudo=True) for value in self._temp.values(): + exec_cmd(self._node, 'cat {value}'.format(value=value), sudo=True) exec_cmd(self._node, 'rm -f {value}'.format(value=value), sudo=True) - def qemu_kill_all(self, node=None): - """Kill all qemu processes on DUT node if specified. - - :param node: Node to kill all QEMU processes on. - :type node: dict - """ - if node: - self.qemu_set_node(node) + def qemu_kill_all(self): + """Kill all qemu processes on DUT node if specified.""" exec_cmd(self._node, 'pkill -SIGKILL qemu', sudo=True) for value in self._temp.values(): + exec_cmd(self._node, 'cat {value}'.format(value=value), sudo=True) exec_cmd(self._node, 'rm -f {value}'.format(value=value), sudo=True) def qemu_version(self, version=None): @@ -625,9 +640,9 @@ class QemuUtils(object): :returns: Qemu version or Boolean if version is higher than parameter. :rtype: str or bool """ - command = ('{bin_path}/qemu-system-{arch} --version'. - format(bin_path=self._opt.get('bin_path'), - arch=Topology.get_node_arch(self._node))) + command = ('{bin_path}/qemu-system-{arch} --version'.format( + bin_path=Constants.QEMU_BIN_PATH, + arch=Topology.get_node_arch(self._node))) try: stdout, _ = exec_cmd_no_error(self._node, command, sudo=True) ver = match(r'QEMU emulator version ([\d.]*)', stdout).group(1) @@ -636,36 +651,3 @@ class QemuUtils(object): except RuntimeError: self.qemu_kill_all() raise - - @staticmethod - def build_qemu(node, force_install=False, apply_patch=False): - """Build QEMU from sources. - - :param node: Node to build QEMU on. - :param force_install: If True, then remove previous build. - :param apply_patch: If True, then apply patches from qemu_patches dir. - :type node: dict - :type force_install: bool - :type apply_patch: bool - :raises RuntimeError: If building QEMU failed. - """ - directory = (' --directory={install_dir}{patch}'. - format(install_dir=Constants.QEMU_INSTALL_DIR, - patch='-patch' if apply_patch else '-base')) - version = (' --version={install_version}'. - format(install_version=Constants.QEMU_INSTALL_VERSION)) - force = ' --force' if force_install else '' - patch = ' --patch' if apply_patch else '' - target_list = (' --target-list={arch}-softmmu'. - format(arch=Topology.get_node_arch(node))) - - command = ("sudo -E sh -c " - "'{fw_dir}/{lib_sh}/qemu_build.sh{version}{directory}" - "{force}{patch}{target_list}'". - format(fw_dir=Constants.REMOTE_FW_DIR, - lib_sh=Constants.RESOURCES_LIB_SH, - version=version, directory=directory, force=force, - patch=patch, target_list=target_list)) - message = ('QEMU: Build failed on {host}!'.format(host=node['host'])) - exec_cmd_no_error(node, command, sudo=False, message=message, - timeout=1000)