| Index: client/tests/kvm/scripts/virtio_guest.py
|
| diff --git a/client/tests/kvm/scripts/virtio_guest.py b/client/tests/kvm/scripts/virtio_guest.py
|
| deleted file mode 100644
|
| index 4862ef2b920674e3ca4de6af2ceda036efc810ae..0000000000000000000000000000000000000000
|
| --- a/client/tests/kvm/scripts/virtio_guest.py
|
| +++ /dev/null
|
| @@ -1,513 +0,0 @@
|
| -#!/usr/bin/python
|
| -# -*- coding: utf-8 -*-
|
| -"""
|
| -Auxiliary script used to send data between ports on guests.
|
| -
|
| -@copyright: 2008-2009 Red Hat Inc.
|
| -@author: Jiri Zupka (jzupka@redhat.com)
|
| -@author: Lukas Doktor (ldoktor@redhat.com)
|
| -"""
|
| -#from _pydev_SimpleXMLRPCServer import fcntl
|
| -
|
| -"""
|
| -TODO:
|
| -virt.init([consoles]) # sysfs, udev, OK
|
| -virt.open(name)
|
| -virt.close(name)
|
| -virt.poll(name, eventmask, timeout) # poll.register(), poll.poll(),
|
| -return event
|
| -virt.send(name, length) # host disconnected
|
| -virt.recv(name, length) # host disconnected
|
| -virt.blocking(name, true) # true = blocking, false = nonblocking
|
| -virt.loopback(in_names, out_names, type="None") # use select/poll
|
| -"""
|
| -
|
| -import threading
|
| -from threading import Thread
|
| -import os, time, select, re, random, sys, array, fcntl, array, subprocess
|
| -
|
| -DEBUGPATH = "/sys/kernel/debug"
|
| -SYSFSPATH = "/sys/class/virtio-ports/"
|
| -
|
| -
|
| -class virtio_guest():
|
| -
|
| - LOOP_NONE = 0
|
| - LOOP_POLL = 1
|
| - LOOP_SELECT = 2
|
| -
|
| - def __init__(self):
|
| - self.files = {}
|
| - self.exit_thread = threading.Event()
|
| - self.threads = []
|
| - self.ports = {}
|
| -
|
| -
|
| - 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:
|
| - f = open("%s/virtio-ports/%s" % (DEBUGPATH, name), 'r')
|
| - port = {}
|
| - for line in iter(f):
|
| - 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"]))
|
| -
|
| - ports[port['name']] = port
|
| - f.close()
|
| -
|
| - return ports
|
| -
|
| -
|
| - def init(self, in_files):
|
| - """
|
| - Init and check port properties.
|
| - """
|
| - self.ports = self._get_port_status()
|
| -
|
| - 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)
|
| -
|
| - 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 == virtio_guest.LOOP_POLL):
|
| - self._poll_mode()
|
| - elif (self.method == virtio_guest.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)
|
| - 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 as inst:
|
| - print "FAIL: Failed to open file %s" % (name)
|
| - raise inst
|
| - return f
|
| -
|
| -
|
| - 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)
|
| -
|
| - str = ""
|
| - if (mask[0][1] & select.POLLIN):
|
| - str += "IN "
|
| - if (mask[0][1] & select.POLLPRI):
|
| - str += "PRI IN "
|
| - if (mask[0][1] & select.POLLOUT):
|
| - str += "OUT "
|
| - if (mask[0][1] & select.POLLERR):
|
| - str += "ERR "
|
| - if (mask[0][1] & select.POLLHUP):
|
| - str += "HUP "
|
| - if (mask[0][1] & select.POLLMSG):
|
| - str += "MSG "
|
| -
|
| - if (mask[0][1] & expected) == expected:
|
| - print "PASS: Events: " + str
|
| - else:
|
| - print "FAIL: Events: " + str
|
| -
|
| -
|
| - 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
|
| - """
|
| - path = self.ports[port]["path"]
|
| - fd = self.files[path]
|
| -
|
| - 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 as inst:
|
| - print "FAIL: Setting (non)blocking mode: " + str(inst)
|
| - return
|
| -
|
| - print ("PASS: set blocking mode to %s mode" %
|
| - ("blocking" if mode else "nonblocking"))
|
| -
|
| -
|
| - 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]
|
| - try:
|
| - os.close(descriptor)
|
| - except Exception as inst:
|
| - print "FAIL: Closing the file: " + str(inst)
|
| - return
|
| - print "PASS: Close"
|
| -
|
| -
|
| - def open(self, in_files):
|
| - """
|
| - Direct open devices.
|
| -
|
| - @param in_files: Array of files.
|
| - @return: Array of descriptors.
|
| - """
|
| - name = self.ports[in_files]["path"]
|
| - try:
|
| - self.files[name] = os.open(name, os.O_RDWR)
|
| - print "PASS: Open all filles correctly."
|
| - except Exception as 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 as inst:
|
| - print inst
|
| - if not writes:
|
| - writes = 0
|
| - if mode:
|
| - while (writes < length):
|
| - try:
|
| - writes += os.write(in_f[0], data)
|
| - except Exception as 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 as inst:
|
| - print inst
|
| - if mode:
|
| - while (len(recvs) < length):
|
| - try:
|
| - recvs += os.read(in_f[0], buffer)
|
| - except Exception as 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 compile():
|
| - """
|
| - Compile virtio_guest.py to speed up.
|
| - """
|
| - import py_compile
|
| - py_compile.compile(sys.path[0] + "/virtio_guest.py")
|
| - print "PASS: compile"
|
| - exit(0)
|
| -
|
| -
|
| -def main():
|
| - """
|
| - Main (infinite) loop of virtio_guest.
|
| - """
|
| - if (len(sys.argv) > 1) and (sys.argv[1] == "-c"):
|
| - compile()
|
| -
|
| - virt = virtio_guest()
|
| - print "PASS: Start"
|
| -
|
| - while True:
|
| - str = raw_input()
|
| - exec str
|
| -
|
| -
|
| -if __name__ == "__main__":
|
| - main()
|
|
|