From patchwork Sat Jan 22 02:03:47 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lucas Meneghel Rodrigues X-Patchwork-Id: 497561 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p0M23uXf006740 for ; Sat, 22 Jan 2011 02:04:15 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754620Ab1AVCEC (ORCPT ); Fri, 21 Jan 2011 21:04:02 -0500 Received: from mx1.redhat.com ([209.132.183.28]:8910 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754294Ab1AVCEB (ORCPT ); Fri, 21 Jan 2011 21:04:01 -0500 Received: from int-mx09.intmail.prod.int.phx2.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id p0M23xpU005599 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Fri, 21 Jan 2011 21:04:00 -0500 Received: from freedom.redhat.com (vpn-11-112.rdu.redhat.com [10.11.11.112]) by int-mx09.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id p0M23ntp030188; Fri, 21 Jan 2011 21:03:58 -0500 From: Lucas Meneghel Rodrigues To: autotest@test.kernel.org Cc: kvm@vger.kernel.org, Lucas Meneghel Rodrigues Subject: [PATCH 4/4] KVM test: Rename virtio_guest.py to virtio_console_guest.py Date: Sat, 22 Jan 2011 00:03:47 -0200 Message-Id: <1295661827-30803-5-git-send-email-lmr@redhat.com> In-Reply-To: <1295661827-30803-1-git-send-email-lmr@redhat.com> References: <1295661827-30803-1-git-send-email-lmr@redhat.com> X-Scanned-By: MIMEDefang 2.68 on 10.5.11.22 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Sat, 22 Jan 2011 02:04:15 +0000 (UTC) diff --git a/client/tests/kvm/scripts/virtio_console_guest.py b/client/tests/kvm/scripts/virtio_console_guest.py new file mode 100755 index 0000000..35efb7d --- /dev/null +++ b/client/tests/kvm/scripts/virtio_console_guest.py @@ -0,0 +1,715 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +""" +Auxiliary script used to send data between ports on guests. + +@copyright: 2010 Red Hat, Inc. +@author: Jiri Zupka (jzupka@redhat.com) +@author: Lukas Doktor (ldoktor@redhat.com) +""" +import threading +from threading import Thread +import os, time, select, re, random, sys, array +import fcntl, subprocess, traceback, signal + +DEBUGPATH = "/sys/kernel/debug" +SYSFSPATH = "/sys/class/virtio-ports/" + +exiting = False + +class VirtioGuest: + """ + Test tools of virtio_ports. + """ + LOOP_NONE = 0 + LOOP_POLL = 1 + LOOP_SELECT = 2 + + def __init__(self): + self.files = {} + self.exit_thread = threading.Event() + self.threads = [] + self.ports = {} + self.poll_fds = {} + self.catch_signal = None + self.use_config = threading.Event() + + + def _readfile(self, name): + """ + Read file and return content as string + + @param name: Name of file + @return: Content of file as string + """ + out = "" + try: + f = open(name, "r") + out = f.read() + f.close() + except: + print "FAIL: Cannot open file %s" % (name) + + return out + + + def _get_port_status(self): + """ + Get info about ports from kernel debugfs. + + @return: Ports dictionary of port properties + """ + ports = {} + not_present_msg = "FAIL: There's no virtio-ports dir in debugfs" + if (not os.path.ismount(DEBUGPATH)): + os.system('mount -t debugfs none %s' % (DEBUGPATH)) + try: + if not os.path.isdir('%s/virtio-ports' % (DEBUGPATH)): + print not_present_msg + except: + print not_present_msg + else: + viop_names = os.listdir('%s/virtio-ports' % (DEBUGPATH)) + for name in viop_names: + open_db_file = "%s/virtio-ports/%s" % (DEBUGPATH, name) + f = open(open_db_file, 'r') + port = {} + file = [] + for line in iter(f): + file.append(line) + try: + for line in file: + m = re.match("(\S+): (\S+)", line) + port[m.group(1)] = m.group(2) + + if (port['is_console'] == "yes"): + port["path"] = "/dev/hvc%s" % (port["console_vtermno"]) + # Console works like a serialport + else: + port["path"] = "/dev/%s" % name + + if (not os.path.exists(port['path'])): + print "FAIL: %s not exist" % port['path'] + + sysfspath = SYSFSPATH + name + if (not os.path.isdir(sysfspath)): + print "FAIL: %s not exist" % (sysfspath) + + info_name = sysfspath + "/name" + port_name = self._readfile(info_name).strip() + if (port_name != port["name"]): + print ("FAIL: Port info not match \n%s - %s\n%s - %s" % + (info_name , port_name, + "%s/virtio-ports/%s" % (DEBUGPATH, name), + port["name"])) + except AttributeError: + print ("In file " + open_db_file + + " are bad data\n"+ "".join(file).strip()) + print ("FAIL: Fail file data.") + return + + ports[port['name']] = port + f.close() + + return ports + + + def init(self, in_files): + """ + Init and check port properties. + """ + self.ports = self._get_port_status() + + if self.ports == None: + return + for item in in_files: + if (item[1] != self.ports[item[0]]["is_console"]): + print self.ports + print "FAIL: Host console is not like console on guest side\n" + print "PASS: Init and check virtioconsole files in system." + + + class Switch(Thread): + """ + Thread that sends data between ports. + """ + def __init__ (self, in_files, out_files, event, + cachesize=1024, method=0): + """ + @param in_files: Array of input files. + @param out_files: Array of output files. + @param method: Method of read/write access. + @param cachesize: Block to receive and send. + """ + Thread.__init__(self, name="Switch") + + self.in_files = in_files + self.out_files = out_files + self.exit_thread = event + self.method = method + + self.cachesize = cachesize + + + def _none_mode(self): + """ + Read and write to device in blocking mode + """ + data = "" + while not self.exit_thread.isSet(): + data = "" + for desc in self.in_files: + data += os.read(desc, self.cachesize) + if data != "": + for desc in self.out_files: + os.write(desc, data) + + + def _poll_mode(self): + """ + Read and write to device in polling mode. + """ + + pi = select.poll() + po = select.poll() + + for fd in self.in_files: + pi.register(fd, select.POLLIN) + + for fd in self.out_files: + po.register(fd, select.POLLOUT) + + while not self.exit_thread.isSet(): + data = "" + t_out = self.out_files + + readyf = pi.poll(1.0) + for i in readyf: + data += os.read(i[0], self.cachesize) + + if data != "": + while ((len(t_out) != len(readyf)) and not + self.exit_thread.isSet()): + readyf = po.poll(1.0) + for desc in t_out: + os.write(desc, data) + + + def _select_mode(self): + """ + Read and write to device in selecting mode. + """ + while not self.exit_thread.isSet(): + ret = select.select(self.in_files, [], [], 1.0) + data = "" + if ret[0] != []: + for desc in ret[0]: + data += os.read(desc, self.cachesize) + if data != "": + ret = select.select([], self.out_files, [], 1.0) + while ((len(self.out_files) != len(ret[1])) and not + self.exit_thread.isSet()): + ret = select.select([], self.out_files, [], 1.0) + for desc in ret[1]: + os.write(desc, data) + + + def run(self): + if (self.method == VirtioGuest.LOOP_POLL): + self._poll_mode() + elif (self.method == VirtioGuest.LOOP_SELECT): + self._select_mode() + else: + self._none_mode() + + + class Sender(Thread): + """ + Creates a thread which sends random blocks of data to dst port. + """ + def __init__(self, port, event, length): + """ + @param port: Destination port + @param length: Length of the random data block + """ + Thread.__init__(self, name="Sender") + self.port = port + self.exit_thread = event + self.data = array.array('L') + for i in range(max(length / self.data.itemsize, 1)): + self.data.append(random.randrange(sys.maxint)) + + def run(self): + while not self.exit_thread.isSet(): + os.write(self.port, self.data) + + + def _open(self, in_files): + """ + Open devices and return array of descriptors + + @param in_files: Files array + @return: Array of descriptor + """ + f = [] + + for item in in_files: + name = self.ports[item]["path"] + if (name in self.files): + f.append(self.files[name]) + else: + try: + self.files[name] = os.open(name, os.O_RDWR) + if (self.ports[item]["is_console"] == "yes"): + print os.system("stty -F %s raw -echo" % (name)) + print os.system("stty -F %s -a" % (name)) + f.append(self.files[name]) + except Exception, inst: + print "FAIL: Failed to open file %s" % (name) + raise inst + return f + + @staticmethod + def pollmask_to_str(mask): + """ + Conver pool mast to string + + @param mask: poll return mask + """ + str = "" + if (mask & select.POLLIN): + str += "IN " + if (mask & select.POLLPRI): + str += "PRI IN " + if (mask & select.POLLOUT): + str += "OUT " + if (mask & select.POLLERR): + str += "ERR " + if (mask & select.POLLHUP): + str += "HUP " + if (mask & select.POLLMSG): + str += "MSG " + return str + + + def poll(self, port, expected, timeout=500): + """ + Pool event from device and print event like text. + + @param file: Device. + """ + in_f = self._open([port]) + + p = select.poll() + p.register(in_f[0]) + + mask = p.poll(timeout) + + maskstr = VirtioGuest.pollmask_to_str(mask[0][1]) + if (mask[0][1] & expected) == expected: + print "PASS: Events: " + maskstr + else: + emaskstr = VirtioGuest.pollmask_to_str(expected) + print "FAIL: Events: " + maskstr + " Expected: " + emaskstr + + + def lseek(self, port, pos, how): + """ + Use lseek on the device. The device is unseekable so PASS is returned + when lseek command fails and vice versa. + + @param port: Name of the port + @param pos: Offset + @param how: Relativ offset os.SEEK_{SET,CUR,END} + """ + fd = self._open([port])[0] + + try: + os.lseek(fd, pos, how) + except Exception, inst: + if inst.errno == 29: + print "PASS: the lseek failed as expected" + else: + print inst + print "FAIL: unknown error" + else: + print "FAIL: the lseek unexpectedly passed" + + + def blocking(self, port, mode=False): + """ + Set port function mode blocking/nonblocking + + @param port: port to set mode + @param mode: False to set nonblock mode, True for block mode + """ + fd = self._open([port])[0] + + try: + fl = fcntl.fcntl(fd, fcntl.F_GETFL) + if not mode: + fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) + else: + fcntl.fcntl(fd, fcntl.F_SETFL, fl & ~os.O_NONBLOCK) + + except Exception, inst: + print "FAIL: Setting (non)blocking mode: " + str(inst) + return + + if mode: + print "PASS: set to blocking mode" + else: + print "PASS: set to nonblocking mode" + + + def __call__(self, sig, frame): + """ + Call function. Used for signal handle. + """ + if (sig == signal.SIGIO): + self.sigio_handler(sig, frame) + + + def sigio_handler(self, sig, frame): + """ + Handler for sigio operation. + + @param sig: signal which call handler. + @param frame: frame of caller + """ + if self.poll_fds: + p = select.poll() + map(p.register, self.poll_fds.keys()) + + masks = p.poll(1) + print masks + for mask in masks: + self.poll_fds[mask[0]][1] |= mask[1] + + + def get_sigio_poll_return(self, port): + """ + Return PASS, FAIL and poll walue in string format. + + @param port: Port to check poll information. + """ + fd = self._open([port])[0] + + maskstr = VirtioGuest.pollmask_to_str(self.poll_fds[fd][1]) + if (self.poll_fds[fd][0] ^ self.poll_fds[fd][1]): + emaskstr = VirtioGuest.pollmask_to_str(self.poll_fds[fd][0]) + print "FAIL: Events: " + maskstr + " Expected: " + emaskstr + else: + print "PASS: Events: " + maskstr + self.poll_fds[fd][1] = 0 + + + def set_pool_want_return(self, port, poll_value): + """ + Set value to static variable. + + @param port: Port which should be set excepted mask + @param poll_value: Value to check sigio signal. + """ + fd = self._open([port])[0] + self.poll_fds[fd] = [poll_value, 0] + print "PASS: Events: " + VirtioGuest.pollmask_to_str(poll_value) + + + def catching_signal(self): + """ + return: True if should set catch signal, False if ignore signal and + none when configuration is not changed. + """ + ret = self.catch_signal + self.catch_signal = None + return ret + + + def async(self, port, mode=True, exp_val = 0): + """ + Set port function mode async/sync. + + @param port: port which should be pooled. + @param mode: False to set sync mode, True for sync mode. + @param exp_val: Value which should be pooled. + """ + fd = self._open([port])[0] + + try: + fcntl.fcntl(fd, fcntl.F_SETOWN, os.getpid()) + fl = fcntl.fcntl(fd, fcntl.F_GETFL) + + self.use_config.clear() + if mode: + fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_ASYNC) + self.poll_fds[fd] = [exp_val, 0] + self.catch_signal = True + else: + del self.poll_fds[fd] + fcntl.fcntl(fd, fcntl.F_SETFL, fl & ~os.O_ASYNC) + self.catch_signal = False + + os.kill(os.getpid(), signal.SIGUSR1) + self.use_config.wait() + + except Exception, inst: + print "FAIL: Setting (a)sync mode: " + str(inst) + return + + if mode: + print "PASS: Set to async mode" + else: + print "PASS: Set to sync mode" + + + def close(self, file): + """ + Close open port. + + @param file: File to close. + """ + descriptor = None + path = self.ports[file]["path"] + if path != None: + if path in self.files.keys(): + descriptor = self.files[path] + del self.files[path] + if descriptor != None: + try: + os.close(descriptor) + except Exception, inst: + print "FAIL: Closing the file: " + str(inst) + return + print "PASS: Close" + + + def open(self, in_file): + """ + Direct open devices. + + @param in_file: Array of files. + @return: Array of descriptors. + """ + name = self.ports[in_file]["path"] + try: + self.files[name] = os.open(name, os.O_RDWR) + if (self.ports[in_file]["is_console"] == "yes"): + print os.system("stty -F %s raw -echo" % (name)) + print "PASS: Open all filles correctly." + except Exception, inst: + print "%s\nFAIL: Failed open file %s" % (str(inst), name) + + + def loopback(self, in_files, out_files, cachesize=1024, mode=LOOP_NONE): + """ + Start a switch thread. + + (There is a problem with multiple opens of a single file). + + @param in_files: Array of input files. + @param out_files: Array of output files. + @param cachesize: Cachesize. + """ + self.ports = self._get_port_status() + + in_f = self._open(in_files) + out_f = self._open(out_files) + + s = self.Switch(in_f, out_f, self.exit_thread, cachesize, mode) + s.start() + self.threads.append(s) + print "PASS: Start switch" + + + def exit_threads(self): + """ + Function end all running data switch. + """ + self.exit_thread.set() + for th in self.threads: + print "join" + th.join() + self.exit_thread.clear() + + del self.threads[:] + for desc in self.files.itervalues(): + os.close(desc) + self.files.clear() + print "PASS: All threads finished." + + + def die(self): + """ + Quit consoleswitch. + """ + self.exit_threads() + exit() + + + def send_loop_init(self, port, length): + """ + Prepares the sender thread. Requires clean thread structure. + """ + self.ports = self._get_port_status() + in_f = self._open([port]) + + self.threads.append(self.Sender(in_f[0], self.exit_thread, length)) + print "PASS: Sender prepare" + + + def send_loop(self): + """ + Start sender data transfer. Requires senderprepare run first. + """ + self.threads[0].start() + print "PASS: Sender start" + + + def send(self, port, length=1, mode=True): + """ + Send a data of some length + + @param port: Port to write data + @param length: Length of data + @param mode: True = loop mode, False = one shoot mode + """ + in_f = self._open([port]) + + data = "" + while len(data) < length: + data += "%c" % random.randrange(255) + try: + writes = os.write(in_f[0], data) + except Exception, inst: + print inst + if not writes: + writes = 0 + if mode: + while (writes < length): + try: + writes += os.write(in_f[0], data) + except Exception, inst: + print inst + if writes >= length: + print "PASS: Send data length %d" % writes + else: + print ("FAIL: Partial send: desired %d, transfered %d" % + (length, writes)) + + + def recv(self, port, length=1, buffer=1024, mode=True): + """ + Recv a data of some length + + @param port: Port to write data + @param length: Length of data + @param mode: True = loop mode, False = one shoot mode + """ + in_f = self._open([port]) + + recvs = "" + try: + recvs = os.read(in_f[0], buffer) + except Exception, inst: + print inst + if mode: + while (len(recvs) < length): + try: + recvs += os.read(in_f[0], buffer) + except Exception, inst: + print inst + if len(recvs) >= length: + print "PASS: Recv data length %d" % len(recvs) + else: + print ("FAIL: Partial recv: desired %d, transfered %d" % + (length, len(recvs))) + + + def clean_port(self, port, buffer=1024): + in_f = self._open([port]) + ret = select.select([in_f[0]], [], [], 1.0) + buf = "" + if ret[0]: + buf = os.read(in_f[0], buffer) + print ("PASS: Rest in socket: ") + str(buf[10]) + + +def is_alive(): + """ + Check is only main thread is alive and if guest react. + """ + if threading.activeCount() == 2: + print ("PASS: Guest is ok no thread alive") + else: + threads = "" + for thread in threading.enumerate(): + threads += thread.name + ", " + print ("FAIL: On guest run thread. Active thread:" + threads) + + +def compile(): + """ + Compile virtio_console_guest.py to speed up. + """ + import py_compile + py_compile.compile(sys.path[0] + "/virtio_console_guest.py") + print "PASS: compile" + sys.exit() + + +def guest_exit(): + global exiting + exiting = True + os.kill(os.getpid(), signal.SIGUSR1) + + +def worker(virt): + """ + Worker thread (infinite) loop of virtio_guest. + """ + global exiting + print "PASS: Start" + + while not exiting: + str = raw_input() + try: + exec str + except: + exc_type, exc_value, exc_traceback = sys.exc_info() + print "On Guest exception from: \n" + "".join( + traceback.format_exception(exc_type, + exc_value, + exc_traceback)) + + +def sigusr_handler(sig, frame): + pass + + +def main(): + """ + Main function with infinite loop to catch signal from system. + """ + if (len(sys.argv) > 1) and (sys.argv[1] == "-c"): + compile() + + global exiting + virt = VirtioGuest() + slave = Thread(target=worker, args=(virt, )) + slave.start() + signal.signal(signal.SIGUSR1, sigusr_handler) + while not exiting: + signal.pause() + catch = virt.catching_signal() + if catch: + signal.signal(signal.SIGIO, virt) + elif catch == False: + signal.signal(signal.SIGIO, signal.SIG_DFL) + if (catch != None): + virt.use_config.set() + print "PASS: guest_exit" + + +if __name__ == "__main__": + main() diff --git a/client/tests/kvm/scripts/virtio_guest.py b/client/tests/kvm/scripts/virtio_guest.py deleted file mode 100755 index 498bf6a..0000000 --- a/client/tests/kvm/scripts/virtio_guest.py +++ /dev/null @@ -1,715 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -""" -Auxiliary script used to send data between ports on guests. - -@copyright: 2010 Red Hat, Inc. -@author: Jiri Zupka (jzupka@redhat.com) -@author: Lukas Doktor (ldoktor@redhat.com) -""" -import threading -from threading import Thread -import os, time, select, re, random, sys, array -import fcntl, subprocess, traceback, signal - -DEBUGPATH = "/sys/kernel/debug" -SYSFSPATH = "/sys/class/virtio-ports/" - -exiting = False - -class VirtioGuest: - """ - Test tools of virtio_ports. - """ - LOOP_NONE = 0 - LOOP_POLL = 1 - LOOP_SELECT = 2 - - def __init__(self): - self.files = {} - self.exit_thread = threading.Event() - self.threads = [] - self.ports = {} - self.poll_fds = {} - self.catch_signal = None - self.use_config = threading.Event() - - - def _readfile(self, name): - """ - Read file and return content as string - - @param name: Name of file - @return: Content of file as string - """ - out = "" - try: - f = open(name, "r") - out = f.read() - f.close() - except: - print "FAIL: Cannot open file %s" % (name) - - return out - - - def _get_port_status(self): - """ - Get info about ports from kernel debugfs. - - @return: Ports dictionary of port properties - """ - ports = {} - not_present_msg = "FAIL: There's no virtio-ports dir in debugfs" - if (not os.path.ismount(DEBUGPATH)): - os.system('mount -t debugfs none %s' % (DEBUGPATH)) - try: - if not os.path.isdir('%s/virtio-ports' % (DEBUGPATH)): - print not_present_msg - except: - print not_present_msg - else: - viop_names = os.listdir('%s/virtio-ports' % (DEBUGPATH)) - for name in viop_names: - open_db_file = "%s/virtio-ports/%s" % (DEBUGPATH, name) - f = open(open_db_file, 'r') - port = {} - file = [] - for line in iter(f): - file.append(line) - try: - for line in file: - m = re.match("(\S+): (\S+)", line) - port[m.group(1)] = m.group(2) - - if (port['is_console'] == "yes"): - port["path"] = "/dev/hvc%s" % (port["console_vtermno"]) - # Console works like a serialport - else: - port["path"] = "/dev/%s" % name - - if (not os.path.exists(port['path'])): - print "FAIL: %s not exist" % port['path'] - - sysfspath = SYSFSPATH + name - if (not os.path.isdir(sysfspath)): - print "FAIL: %s not exist" % (sysfspath) - - info_name = sysfspath + "/name" - port_name = self._readfile(info_name).strip() - if (port_name != port["name"]): - print ("FAIL: Port info not match \n%s - %s\n%s - %s" % - (info_name , port_name, - "%s/virtio-ports/%s" % (DEBUGPATH, name), - port["name"])) - except AttributeError: - print ("In file " + open_db_file + - " are bad data\n"+ "".join(file).strip()) - print ("FAIL: Fail file data.") - return - - ports[port['name']] = port - f.close() - - return ports - - - def init(self, in_files): - """ - Init and check port properties. - """ - self.ports = self._get_port_status() - - if self.ports == None: - return - for item in in_files: - if (item[1] != self.ports[item[0]]["is_console"]): - print self.ports - print "FAIL: Host console is not like console on guest side\n" - print "PASS: Init and check virtioconsole files in system." - - - class Switch(Thread): - """ - Thread that sends data between ports. - """ - def __init__ (self, in_files, out_files, event, - cachesize=1024, method=0): - """ - @param in_files: Array of input files. - @param out_files: Array of output files. - @param method: Method of read/write access. - @param cachesize: Block to receive and send. - """ - Thread.__init__(self, name="Switch") - - self.in_files = in_files - self.out_files = out_files - self.exit_thread = event - self.method = method - - self.cachesize = cachesize - - - def _none_mode(self): - """ - Read and write to device in blocking mode - """ - data = "" - while not self.exit_thread.isSet(): - data = "" - for desc in self.in_files: - data += os.read(desc, self.cachesize) - if data != "": - for desc in self.out_files: - os.write(desc, data) - - - def _poll_mode(self): - """ - Read and write to device in polling mode. - """ - - pi = select.poll() - po = select.poll() - - for fd in self.in_files: - pi.register(fd, select.POLLIN) - - for fd in self.out_files: - po.register(fd, select.POLLOUT) - - while not self.exit_thread.isSet(): - data = "" - t_out = self.out_files - - readyf = pi.poll(1.0) - for i in readyf: - data += os.read(i[0], self.cachesize) - - if data != "": - while ((len(t_out) != len(readyf)) and not - self.exit_thread.isSet()): - readyf = po.poll(1.0) - for desc in t_out: - os.write(desc, data) - - - def _select_mode(self): - """ - Read and write to device in selecting mode. - """ - while not self.exit_thread.isSet(): - ret = select.select(self.in_files, [], [], 1.0) - data = "" - if ret[0] != []: - for desc in ret[0]: - data += os.read(desc, self.cachesize) - if data != "": - ret = select.select([], self.out_files, [], 1.0) - while ((len(self.out_files) != len(ret[1])) and not - self.exit_thread.isSet()): - ret = select.select([], self.out_files, [], 1.0) - for desc in ret[1]: - os.write(desc, data) - - - def run(self): - if (self.method == VirtioGuest.LOOP_POLL): - self._poll_mode() - elif (self.method == VirtioGuest.LOOP_SELECT): - self._select_mode() - else: - self._none_mode() - - - class Sender(Thread): - """ - Creates a thread which sends random blocks of data to dst port. - """ - def __init__(self, port, event, length): - """ - @param port: Destination port - @param length: Length of the random data block - """ - Thread.__init__(self, name="Sender") - self.port = port - self.exit_thread = event - self.data = array.array('L') - for i in range(max(length / self.data.itemsize, 1)): - self.data.append(random.randrange(sys.maxint)) - - def run(self): - while not self.exit_thread.isSet(): - os.write(self.port, self.data) - - - def _open(self, in_files): - """ - Open devices and return array of descriptors - - @param in_files: Files array - @return: Array of descriptor - """ - f = [] - - for item in in_files: - name = self.ports[item]["path"] - if (name in self.files): - f.append(self.files[name]) - else: - try: - self.files[name] = os.open(name, os.O_RDWR) - if (self.ports[item]["is_console"] == "yes"): - print os.system("stty -F %s raw -echo" % (name)) - print os.system("stty -F %s -a" % (name)) - f.append(self.files[name]) - except Exception, inst: - print "FAIL: Failed to open file %s" % (name) - raise inst - return f - - @staticmethod - def pollmask_to_str(mask): - """ - Conver pool mast to string - - @param mask: poll return mask - """ - str = "" - if (mask & select.POLLIN): - str += "IN " - if (mask & select.POLLPRI): - str += "PRI IN " - if (mask & select.POLLOUT): - str += "OUT " - if (mask & select.POLLERR): - str += "ERR " - if (mask & select.POLLHUP): - str += "HUP " - if (mask & select.POLLMSG): - str += "MSG " - return str - - - def poll(self, port, expected, timeout=500): - """ - Pool event from device and print event like text. - - @param file: Device. - """ - in_f = self._open([port]) - - p = select.poll() - p.register(in_f[0]) - - mask = p.poll(timeout) - - maskstr = VirtioGuest.pollmask_to_str(mask[0][1]) - if (mask[0][1] & expected) == expected: - print "PASS: Events: " + maskstr - else: - emaskstr = VirtioGuest.pollmask_to_str(expected) - print "FAIL: Events: " + maskstr + " Expected: " + emaskstr - - - def lseek(self, port, pos, how): - """ - Use lseek on the device. The device is unseekable so PASS is returned - when lseek command fails and vice versa. - - @param port: Name of the port - @param pos: Offset - @param how: Relativ offset os.SEEK_{SET,CUR,END} - """ - fd = self._open([port])[0] - - try: - os.lseek(fd, pos, how) - except Exception, inst: - if inst.errno == 29: - print "PASS: the lseek failed as expected" - else: - print inst - print "FAIL: unknown error" - else: - print "FAIL: the lseek unexpectedly passed" - - - def blocking(self, port, mode=False): - """ - Set port function mode blocking/nonblocking - - @param port: port to set mode - @param mode: False to set nonblock mode, True for block mode - """ - fd = self._open([port])[0] - - try: - fl = fcntl.fcntl(fd, fcntl.F_GETFL) - if not mode: - fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) - else: - fcntl.fcntl(fd, fcntl.F_SETFL, fl & ~os.O_NONBLOCK) - - except Exception, inst: - print "FAIL: Setting (non)blocking mode: " + str(inst) - return - - if mode: - print "PASS: set to blocking mode" - else: - print "PASS: set to nonblocking mode" - - - def __call__(self, sig, frame): - """ - Call function. Used for signal handle. - """ - if (sig == signal.SIGIO): - self.sigio_handler(sig, frame) - - - def sigio_handler(self, sig, frame): - """ - Handler for sigio operation. - - @param sig: signal which call handler. - @param frame: frame of caller - """ - if self.poll_fds: - p = select.poll() - map(p.register, self.poll_fds.keys()) - - masks = p.poll(1) - print masks - for mask in masks: - self.poll_fds[mask[0]][1] |= mask[1] - - - def get_sigio_poll_return(self, port): - """ - Return PASS, FAIL and poll walue in string format. - - @param port: Port to check poll information. - """ - fd = self._open([port])[0] - - maskstr = VirtioGuest.pollmask_to_str(self.poll_fds[fd][1]) - if (self.poll_fds[fd][0] ^ self.poll_fds[fd][1]): - emaskstr = VirtioGuest.pollmask_to_str(self.poll_fds[fd][0]) - print "FAIL: Events: " + maskstr + " Expected: " + emaskstr - else: - print "PASS: Events: " + maskstr - self.poll_fds[fd][1] = 0 - - - def set_pool_want_return(self, port, poll_value): - """ - Set value to static variable. - - @param port: Port which should be set excepted mask - @param poll_value: Value to check sigio signal. - """ - fd = self._open([port])[0] - self.poll_fds[fd] = [poll_value, 0] - print "PASS: Events: " + VirtioGuest.pollmask_to_str(poll_value) - - - def catching_signal(self): - """ - return: True if should set catch signal, False if ignore signal and - none when configuration is not changed. - """ - ret = self.catch_signal - self.catch_signal = None - return ret - - - def async(self, port, mode=True, exp_val = 0): - """ - Set port function mode async/sync. - - @param port: port which should be pooled. - @param mode: False to set sync mode, True for sync mode. - @param exp_val: Value which should be pooled. - """ - fd = self._open([port])[0] - - try: - fcntl.fcntl(fd, fcntl.F_SETOWN, os.getpid()) - fl = fcntl.fcntl(fd, fcntl.F_GETFL) - - self.use_config.clear() - if mode: - fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_ASYNC) - self.poll_fds[fd] = [exp_val, 0] - self.catch_signal = True - else: - del self.poll_fds[fd] - fcntl.fcntl(fd, fcntl.F_SETFL, fl & ~os.O_ASYNC) - self.catch_signal = False - - os.kill(os.getpid(), signal.SIGUSR1) - self.use_config.wait() - - except Exception, inst: - print "FAIL: Setting (a)sync mode: " + str(inst) - return - - if mode: - print "PASS: Set to async mode" - else: - print "PASS: Set to sync mode" - - - def close(self, file): - """ - Close open port. - - @param file: File to close. - """ - descriptor = None - path = self.ports[file]["path"] - if path != None: - if path in self.files.keys(): - descriptor = self.files[path] - del self.files[path] - if descriptor != None: - try: - os.close(descriptor) - except Exception, inst: - print "FAIL: Closing the file: " + str(inst) - return - print "PASS: Close" - - - def open(self, in_file): - """ - Direct open devices. - - @param in_file: Array of files. - @return: Array of descriptors. - """ - name = self.ports[in_file]["path"] - try: - self.files[name] = os.open(name, os.O_RDWR) - if (self.ports[in_file]["is_console"] == "yes"): - print os.system("stty -F %s raw -echo" % (name)) - print "PASS: Open all filles correctly." - except Exception, inst: - print "%s\nFAIL: Failed open file %s" % (str(inst), name) - - - def loopback(self, in_files, out_files, cachesize=1024, mode=LOOP_NONE): - """ - Start a switch thread. - - (There is a problem with multiple opens of a single file). - - @param in_files: Array of input files. - @param out_files: Array of output files. - @param cachesize: Cachesize. - """ - self.ports = self._get_port_status() - - in_f = self._open(in_files) - out_f = self._open(out_files) - - s = self.Switch(in_f, out_f, self.exit_thread, cachesize, mode) - s.start() - self.threads.append(s) - print "PASS: Start switch" - - - def exit_threads(self): - """ - Function end all running data switch. - """ - self.exit_thread.set() - for th in self.threads: - print "join" - th.join() - self.exit_thread.clear() - - del self.threads[:] - for desc in self.files.itervalues(): - os.close(desc) - self.files.clear() - print "PASS: All threads finished." - - - def die(self): - """ - Quit consoleswitch. - """ - self.exit_threads() - exit() - - - def send_loop_init(self, port, length): - """ - Prepares the sender thread. Requires clean thread structure. - """ - self.ports = self._get_port_status() - in_f = self._open([port]) - - self.threads.append(self.Sender(in_f[0], self.exit_thread, length)) - print "PASS: Sender prepare" - - - def send_loop(self): - """ - Start sender data transfer. Requires senderprepare run first. - """ - self.threads[0].start() - print "PASS: Sender start" - - - def send(self, port, length=1, mode=True): - """ - Send a data of some length - - @param port: Port to write data - @param length: Length of data - @param mode: True = loop mode, False = one shoot mode - """ - in_f = self._open([port]) - - data = "" - while len(data) < length: - data += "%c" % random.randrange(255) - try: - writes = os.write(in_f[0], data) - except Exception, inst: - print inst - if not writes: - writes = 0 - if mode: - while (writes < length): - try: - writes += os.write(in_f[0], data) - except Exception, inst: - print inst - if writes >= length: - print "PASS: Send data length %d" % writes - else: - print ("FAIL: Partial send: desired %d, transfered %d" % - (length, writes)) - - - def recv(self, port, length=1, buffer=1024, mode=True): - """ - Recv a data of some length - - @param port: Port to write data - @param length: Length of data - @param mode: True = loop mode, False = one shoot mode - """ - in_f = self._open([port]) - - recvs = "" - try: - recvs = os.read(in_f[0], buffer) - except Exception, inst: - print inst - if mode: - while (len(recvs) < length): - try: - recvs += os.read(in_f[0], buffer) - except Exception, inst: - print inst - if len(recvs) >= length: - print "PASS: Recv data length %d" % len(recvs) - else: - print ("FAIL: Partial recv: desired %d, transfered %d" % - (length, len(recvs))) - - - def clean_port(self, port, buffer=1024): - in_f = self._open([port]) - ret = select.select([in_f[0]], [], [], 1.0) - buf = "" - if ret[0]: - buf = os.read(in_f[0], buffer) - print ("PASS: Rest in socket: ") + str(buf[10]) - - -def is_alive(): - """ - Check is only main thread is alive and if guest react. - """ - if threading.activeCount() == 2: - print ("PASS: Guest is ok no thread alive") - else: - threads = "" - for thread in threading.enumerate(): - threads += thread.name + ", " - print ("FAIL: On guest run thread. Active thread:" + threads) - - -def compile(): - """ - Compile virtio_guest.py to speed up. - """ - import py_compile - py_compile.compile(sys.path[0] + "/virtio_guest.py") - print "PASS: compile" - sys.exit() - - -def guest_exit(): - global exiting - exiting = True - os.kill(os.getpid(), signal.SIGUSR1) - - -def worker(virt): - """ - Worker thread (infinite) loop of virtio_guest. - """ - global exiting - print "PASS: Start" - - while not exiting: - str = raw_input() - try: - exec str - except: - exc_type, exc_value, exc_traceback = sys.exc_info() - print "On Guest exception from: \n" + "".join( - traceback.format_exception(exc_type, - exc_value, - exc_traceback)) - - -def sigusr_handler(sig, frame): - pass - - -def main(): - """ - Main function with infinite loop to catch signal from system. - """ - if (len(sys.argv) > 1) and (sys.argv[1] == "-c"): - compile() - - global exiting - virt = VirtioGuest() - slave = Thread(target=worker, args=(virt, )) - slave.start() - signal.signal(signal.SIGUSR1, sigusr_handler) - while not exiting: - signal.pause() - catch = virt.catching_signal() - if catch: - signal.signal(signal.SIGIO, virt) - elif catch == False: - signal.signal(signal.SIGIO, signal.SIG_DFL) - if (catch != None): - virt.use_config.set() - print "PASS: guest_exit" - - -if __name__ == "__main__": - main() diff --git a/client/tests/kvm/tests/virtio_console.py b/client/tests/kvm/tests/virtio_console.py index 9e0611f..b1e8bc6 100644 --- a/client/tests/kvm/tests/virtio_console.py +++ b/client/tests/kvm/tests/virtio_console.py @@ -433,15 +433,15 @@ def run_virtio_console(test, params, env): def _init_guest(vm, timeout=2): """ - Execute virtio_guest.py on guest, wait until it is initialized. + Execute virtio_console_guest.py on guest, wait until it is initialized. @param vm: Informations about the guest. @param timeout: Timeout that will be used to verify if the script started properly. """ - logging.debug("compile virtio_guest.py on guest %s", vm[0].name) + logging.debug("compile virtio_console_guest.py on guest %s", vm[0].name) - (match, data) = _on_guest("python -OO /tmp/virtio_guest.py -c &&" + (match, data) = _on_guest("python -OO /tmp/virtio_console_guest.py -c &&" "echo -n 'PASS: Compile virtio_guest finished' ||" "echo -n 'FAIL: Compile virtio_guest failed'", vm, timeout) @@ -450,9 +450,9 @@ def run_virtio_console(test, params, env): raise error.TestFail("Command console_switch.py on guest %s failed." "\nreturn code: %s\n output:\n%s" % (vm[0].name, match, data)) - logging.debug("Starting virtio_guest.py on guest %s", vm[0].name) + logging.debug("Starting virtio_console_guest.py on guest %s", vm[0].name) vm[1].sendline() - (match, data) = _on_guest("python /tmp/virtio_guest.pyo &&" + (match, data) = _on_guest("python /tmp/virtio_console_guest.pyo &&" "echo -n 'PASS: virtio_guest finished' ||" "echo -n 'FAIL: virtio_guest failed'", vm, timeout) @@ -466,7 +466,7 @@ def run_virtio_console(test, params, env): def init_guest(vm, consoles): """ - Prepares guest, executes virtio_guest.py and initialize for testing + Prepares guest, executes virtio_console_guest.py and initialize for testing @param vm: Informations about the guest. @param consoles: Informations about consoles @@ -516,7 +516,7 @@ def run_virtio_console(test, params, env): @return: Tuple (match index, data) """ - logging.debug("Executing '%s' on virtio_guest.py loop, vm: %s," + + logging.debug("Executing '%s' on virtio_console_guest.py loop, vm: %s," + "timeout: %s", command, vm[0].name, timeout) vm[1].sendline(command) try: @@ -550,7 +550,7 @@ def run_virtio_console(test, params, env): """ match, data = _on_guest(command, vm, timeout) if match == 1 or match is None: - raise error.TestFail("Failed to execute '%s' on virtio_guest.py, " + raise error.TestFail("Failed to execute '%s' on virtio_console_guest.py, " "vm: %s, output:\n%s" % (command, vm[0].name, data)) @@ -1290,9 +1290,9 @@ def run_virtio_console(test, params, env): vm, consoles = _vm_create(no_consoles, no_serialports) - # Copy allocator.py into guests + # Copy virtio_console_guest.py into guests pwd = os.path.join(os.environ['AUTODIR'], 'tests/kvm') - vksmd_src = os.path.join(pwd, "scripts/virtio_guest.py") + vksmd_src = os.path.join(pwd, "scripts/virtio_console_guest.py") dst_dir = "/tmp" vm[0].copy_files_to(vksmd_src, dst_dir)