1"""
2virtio_console test
3
4@copyright: 2010 Red Hat, Inc.
5"""
6import array, logging, os, random, re, select, shutil, socket, sys, tempfile
7import threading, time, traceback
8from collections import deque
9from threading import Thread
10
11from autotest_lib.client.common_lib import error
12from autotest_lib.client.bin import utils
13from autotest_lib.client.virt import virt_utils, virt_test_utils, kvm_monitor
14from autotest_lib.client.virt import virt_env_process, aexpect
15
16
17def run_virtio_console(test, params, env):
18    """
19    KVM virtio_console test
20
21    1) Starts VMs with the specified number of virtio console devices
22    2) Start smoke test
23    3) Start loopback test
24    4) Start performance test
25
26    This test uses an auxiliary script, virtio_console_guest.py, that is copied
27    to guests. This script has functions to send and write data to virtio
28    console ports. Details of each test can be found on the docstrings for the
29    test_* functions.
30
31    @param test: kvm test object
32    @param params: Dictionary with the test parameters
33    @param env: Dictionary with test environment
34    """
35    class SubTest(object):
36        """
37        Collect result of subtest of main test.
38        """
39        def __init__(self):
40            """
41            Initialize object
42            """
43            self.result = []
44            self.passed = 0
45            self.failed = 0
46            self.cleanup_func = None
47            self.cleanup_args = None
48
49
50        def set_cleanup_func(self, func, args):
51            """
52            Set cleanup function which is called when subtest fails.
53
54            @param func: Function which should be called when test fails.
55            @param args: Arguments of cleanup function.
56            """
57            self.cleanup_func = func
58            self.cleanup_args = args
59
60
61        def get_cleanup_func(self):
62            """
63            Returns the tupple of cleanup_func and clenaup_args
64
65            @return: Tupple of self.cleanup_func and self.cleanup_args
66            """
67            return (self.cleanup_func, self.cleanup_args)
68
69
70        def do_test(self, function, args=None, fatal=False, cleanup=True):
71            """
72            Execute subtest function.
73
74            @param function: Object of function.
75            @param args: List of arguments of function.
76            @param fatal: If true exception is forwarded to main test.
77            @param cleanup: If true call cleanup function after crash of test.
78            @return: Return what returned executed subtest.
79            @raise TestError: If collapse of test is fatal raise forward
80                        exception from subtest.
81            """
82            if args is None:
83                args = []
84            res = [None, function.func_name, args]
85            try:
86                logging.info("Starting test %s" % function.func_name)
87                ret = function(*args)
88                res[0] = True
89                logging.info(self.result_to_string(res))
90                self.result.append(res)
91                self.passed += 1
92                return ret
93            except:
94                exc_type, exc_value, exc_traceback = sys.exc_info()
95                logging.error("In function (" + function.func_name + "):")
96                logging.error("Call from:\n" +
97                              traceback.format_stack()[-2][:-1])
98                logging.error("Exception from:\n" +
99                              "".join(traceback.format_exception(
100                                                        exc_type, exc_value,
101                                                        exc_traceback.tb_next)))
102                # Clean up environment after subTest crash
103                res[0] = False
104                logging.info(self.result_to_string(res))
105                self.result.append(res)
106                self.failed += 1
107
108                if cleanup:
109                    try:
110                        self.cleanup_func(*self.cleanup_args)
111                    except:
112                        error.TestFail("Cleanup function crashed as well")
113                if fatal:
114                    raise
115
116
117        def is_failed(self):
118            """
119            @return: If any of subtest not pass return True.
120            """
121            if self.failed > 0:
122                return True
123            else:
124                return False
125
126
127        def get_result(self):
128            """
129            @return: Result of subtests.
130               Format:
131                 tuple(pass/fail,function_name,call_arguments)
132            """
133            return self.result
134
135
136        def result_to_string_debug(self, result):
137            """
138            @param result: Result of test.
139            """
140            sargs = ""
141            for arg in result[2]:
142                sargs += str(arg) + ","
143            sargs = sargs[:-1]
144            if result[0]:
145                status = "PASS"
146            else:
147                status = "FAIL"
148            return ("Subtest (%s(%s)): --> %s") % (result[1], sargs, status)
149
150
151        def result_to_string(self, result):
152            """
153            @param result: Result of test.
154            """
155            if result[0]:
156                status = "PASS"
157            else:
158                status = "FAIL"
159            return ("Subtest (%s): --> %s") % (result[1], status)
160
161
162        def headline(self, msg):
163            """
164            Add headline to result output.
165
166            @param msg: Test of headline
167            """
168            self.result.append([msg])
169
170
171        def _gen_res(self, format_func):
172            """
173            Format result with formatting function
174
175            @param format_func: Func for formating result.
176            """
177            result = ""
178            for res in self.result:
179                if (len(res) == 3):
180                    result += format_func(res) + "\n"
181                else:
182                    result += res[0] + "\n"
183            return result
184
185
186        def get_full_text_result(self):
187            """
188            @return string with text form of result
189            """
190            return self._gen_res(lambda str: self.result_to_string_debug(str))
191
192
193        def get_text_result(self):
194            """
195            @return string with text form of result
196            """
197            return self._gen_res(lambda str: self.result_to_string(str))
198
199
200    class Port(object):
201        """
202        Define structure to keep information about used port.
203        """
204        def __init__(self, sock, name, port_type, path):
205            """
206            @param vm: virtual machine object that port owned
207            @param sock: Socket of port if port is open.
208            @param name: Name of port for guest side.
209            @param port_type: Type of port yes = console, no= serialport.
210            @param path: Path to port on host side.
211            """
212            self.sock = sock
213            self.name = name
214            self.port_type = port_type
215            self.path = path
216            self.is_open = False
217
218
219        def for_guest(self):
220            """
221            Format data for communication with guest side.
222            """
223            return [self.name, self.port_type]
224
225
226        def open(self):
227            """
228            Open port on host side.
229            """
230            attempt = 11
231            while attempt > 0:
232                try:
233                    self.sock = socket.socket(socket.AF_UNIX,
234                                              socket.SOCK_STREAM)
235                    self.sock.connect(self.path)
236                    self.sock.setsockopt(1,socket.SO_SNDBUF, 2048)
237                    self.is_open = True
238                    return
239                except Exception, inst:
240                    attempt -= 1
241                    time.sleep(1)
242            raise error.TestFail("Can't open the %s sock" % self.name)
243
244
245        def clean_port(self):
246            """
247            Clean all data from opened port on host side.
248            """
249            if self.is_open:
250                self.close()
251            self.open()
252            ret = select.select([self.sock], [], [], 1.0)
253            if ret[0]:
254                buf = self.sock.recv(1024)
255                logging.debug("Rest in socket: " + buf)
256
257
258        def close(self):
259            """
260            Close port.
261            """
262            self.sock.shutdown(socket.SHUT_RDWR)
263            self.sock.close()
264            self.is_open = False
265
266
267        def __str__(self):
268            """
269            Convert to text.
270            """
271            return ("%s,%s,%s,%s,%d" % ("Socket", self.name, self.port_type,
272                                        self.path, self.is_open))
273
274
275    class ThSend(Thread):
276        """
277        Random data sender thread.
278        """
279        def __init__(self, port, data, event, quiet=False):
280            """
281            @param port: Destination port.
282            @param data: The data intend to be send in a loop.
283            @param event: Exit event.
284            @param quiet: If true don't raise event when crash.
285            """
286            Thread.__init__(self)
287            self.port = port
288            # FIXME: socket.send(data>>127998) without read blocks thread
289            if len(data) > 102400:
290                data = data[0:102400]
291                logging.error("Data is too long, using only first %d bytes",
292                              len(data))
293            self.data = data
294            self.exitevent = event
295            self.idx = 0
296            self.quiet = quiet
297
298
299        def run(self):
300            logging.debug("ThSend %s: run", self.getName())
301            try:
302                while not self.exitevent.isSet():
303                    self.idx += self.port.send(self.data)
304                logging.debug("ThSend %s: exit(%d)", self.getName(),
305                              self.idx)
306            except Exception, ints:
307                if not self.quiet:
308                    raise ints
309                logging.debug(ints)
310
311
312    class ThSendCheck(Thread):
313        """
314        Random data sender thread.
315        """
316        def __init__(self, port, event, queues, blocklen=1024):
317            """
318            @param port: Destination port
319            @param event: Exit event
320            @param queues: Queues for the control data (FIFOs)
321            @param blocklen: Block length
322            """
323            Thread.__init__(self)
324            self.port = port
325            self.queues = queues
326            # FIXME: socket.send(data>>127998) without read blocks thread
327            if blocklen > 102400:
328                blocklen = 102400
329                logging.error("Data is too long, using blocklen = %d",
330                              blocklen)
331            self.blocklen = blocklen
332            self.exitevent = event
333            self.idx = 0
334
335
336        def run(self):
337            logging.debug("ThSendCheck %s: run", self.getName())
338            too_much_data = False
339            while not self.exitevent.isSet():
340                # FIXME: workaround the problem with qemu-kvm stall when too
341                # much data is sent without receiving
342                for queue in self.queues:
343                    while not self.exitevent.isSet() and len(queue) > 1048576:
344                        too_much_data = True
345                        time.sleep(0.1)
346                ret = select.select([], [self.port.sock], [], 1.0)
347                if ret[1]:
348                    # Generate blocklen of random data add them to the FIFO
349                    # and send them over virtio_console
350                    buf = ""
351                    for i in range(self.blocklen):
352                        ch = "%c" % random.randrange(255)
353                        buf += ch
354                        for queue in self.queues:
355                            queue.append(ch)
356                    target = self.idx + self.blocklen
357                    while not self.exitevent.isSet() and self.idx < target:
358                        try:
359                            idx = self.port.sock.send(buf)
360                        except Exception, inst:
361                            # Broken pipe
362                            if inst.errno == 32:
363                                logging.debug("ThSendCheck %s: Broken pipe "
364                                              "(migration?), reconnecting",
365                                              self.getName())
366                                attempt = 10
367                                while (attempt > 1
368                                       and not self.exitevent.isSet()):
369                                    self.port.is_open = False
370                                    self.port.open()
371                                    try:
372                                        idx = self.port.sock.send(buf)
373                                    except:
374                                        attempt += 1
375                                        time.sleep(10)
376                                    else:
377                                        attempt = 0
378                        buf = buf[idx:]
379                        self.idx += idx
380            logging.debug("ThSendCheck %s: exit(%d)", self.getName(),
381                          self.idx)
382            if too_much_data:
383                logging.error("ThSendCheck: working around the 'too_much_data'"
384                              "bug")
385
386
387    class ThRecv(Thread):
388        """
389        Recieves data and throws it away.
390        """
391        def __init__(self, port, event, blocklen=1024, quiet=False):
392            """
393            @param port: Data source port.
394            @param event: Exit event.
395            @param blocklen: Block length.
396            @param quiet: If true don't raise event when crash.
397            """
398            Thread.__init__(self)
399            self.port = port
400            self._port_timeout = self.port.gettimeout()
401            self.port.settimeout(0.1)
402            self.exitevent = event
403            self.blocklen = blocklen
404            self.idx = 0
405            self.quiet = quiet
406
407
408        def run(self):
409            logging.debug("ThRecv %s: run", self.getName())
410            try:
411                while not self.exitevent.isSet():
412                    # TODO: Workaround, it didn't work with select :-/
413                    try:
414                        self.idx += len(self.port.recv(self.blocklen))
415                    except socket.timeout:
416                        pass
417                self.port.settimeout(self._port_timeout)
418                logging.debug("ThRecv %s: exit(%d)", self.getName(), self.idx)
419            except Exception, ints:
420                if not self.quiet:
421                    raise ints
422                logging.debug(ints)
423
424
425    class ThRecvCheck(Thread):
426        """
427        Random data receiver/checker thread.
428        """
429        def __init__(self, port, buffer, event, blocklen=1024, sendlen=0):
430            """
431            @param port: Source port.
432            @param buffer: Control data buffer (FIFO).
433            @param length: Amount of data we want to receive.
434            @param blocklen: Block length.
435            @param sendlen: Block length of the send function (on guest)
436            """
437            Thread.__init__(self)
438            self.port = port
439            self.buffer = buffer
440            self.exitevent = event
441            self.blocklen = blocklen
442            self.idx = 0
443            self.sendlen = sendlen + 1  # >=
444
445
446        def run(self):
447            logging.debug("ThRecvCheck %s: run", self.getName())
448            attempt = 10
449            sendidx = -1
450            minsendidx = self.sendlen
451            while not self.exitevent.isSet():
452                ret = select.select([self.port.sock], [], [], 1.0)
453                if ret[0] and (not self.exitevent.isSet()):
454                    buf = self.port.sock.recv(self.blocklen)
455                    if buf:
456                        # Compare the received data with the control data
457                        for ch in buf:
458                            ch_ = self.buffer.popleft()
459                            if ch == ch_:
460                                self.idx += 1
461                            else:
462                                # TODO BUG: data from the socket on host can
463                                # be lost during migration
464                                while ch != ch_:
465                                    if sendidx > 0:
466                                        sendidx -= 1
467                                        ch_ = self.buffer.popleft()
468                                    else:
469                                        self.exitevent.set()
470                                        logging.error("ThRecvCheck %s: "
471                                                      "Failed to recv %dth "
472                                                      "character",
473                                                      self.getName(), self.idx)
474                                        logging.error("ThRecvCheck %s: "
475                                                      "%s != %s",
476                                                      self.getName(),
477                                                      repr(ch), repr(ch_))
478                                        logging.error("ThRecvCheck %s: "
479                                                      "Recv = %s",
480                                                      self.getName(), repr(buf))
481                                        # sender might change the buffer :-(
482                                        time.sleep(1)
483                                        ch_ = ""
484                                        for buf in self.buffer:
485                                            ch_ += buf
486                                            ch_ += ' '
487                                        logging.error("ThRecvCheck %s: "
488                                                      "Queue = %s",
489                                                      self.getName(), repr(ch_))
490                                        logging.info("ThRecvCheck %s: "
491                                                    "MaxSendIDX = %d",
492                                                    self.getName(),
493                                                    (self.sendlen - sendidx))
494                                        raise error.TestFail("ThRecvCheck %s: "
495                                                             "incorrect data",
496                                                             self.getName())
497                        attempt = 10
498                    else:   # ! buf
499                        # Broken socket
500                        if attempt > 0:
501                            attempt -= 1
502                            logging.debug("ThRecvCheck %s: Broken pipe "
503                                          "(migration?), reconnecting. ",
504                                          self.getName())
505                            # TODO BUG: data from the socket on host can be lost
506                            if sendidx >= 0:
507                                minsendidx = min(minsendidx, sendidx)
508                                logging.debug("ThRecvCheck %s: Previous data "
509                                              "loss was %d.",
510                                              self.getName(),
511                                              (self.sendlen - sendidx))
512                            sendidx = self.sendlen
513                            self.port.is_open = False
514                            self.port.open()
515            if sendidx >= 0:
516                minsendidx = min(minsendidx, sendidx)
517            if (self.sendlen - minsendidx):
518                logging.error("ThRecvCheck %s: Data loss occured during socket"
519                              "reconnection. Maximal loss was %d per one "
520                              "migration.", self.getName(),
521                              (self.sendlen - minsendidx))
522            logging.debug("ThRecvCheck %s: exit(%d)", self.getName(),
523                          self.idx)
524
525
526    def process_stats(stats, scale=1.0):
527        """
528        Process and print the stats.
529
530        @param stats: List of measured data.
531        """
532        if not stats:
533            return None
534        for i in range((len(stats) - 1), 0, -1):
535            stats[i] = stats[i] - stats[i - 1]
536            stats[i] /= scale
537        stats[0] /= scale
538        stats = sorted(stats)
539        return stats
540
541
542    def _init_guest(vm, timeout=10):
543        """
544        Execute virtio_console_guest.py on guest, wait until it is initialized.
545
546        @param vm: Informations about the guest.
547        @param timeout: Timeout that will be used to verify if the script
548                started properly.
549        """
550        logging.debug("compile virtio_console_guest.py on guest %s",
551                      vm[0].name)
552
553        (match, data) = _on_guest("python -OO /tmp/virtio_console_guest.py -c"
554                       "&& echo -n 'PASS: Compile virtio_guest finished' ||"
555                       "echo -n 'FAIL: Compile virtio_guest failed'",
556                        vm, timeout)
557
558        if match != 0:
559            raise error.TestFail("Command console_switch.py on guest %s "
560                                 "failed.\nreturn code: %s\n output:\n%s" %
561                                 (vm[0].name, match, data))
562        logging.debug("Starting virtio_console_guest.py on guest %s",
563                      vm[0].name)
564        vm[1].sendline()
565        (match, data) = _on_guest("python /tmp/virtio_console_guest.pyo &&"
566                       "echo -n 'PASS: virtio_guest finished' ||"
567                       "echo -n 'FAIL: virtio_guest failed'",
568                       vm, timeout)
569        if match != 0:
570            raise error.TestFail("Command console_switch.py on guest %s "
571                                 "failed.\nreturn code: %s\n output:\n%s" %
572                                 (vm[0].name, match, data))
573        # Let the system rest
574        time.sleep(2)
575
576
577    def init_guest(vm, consoles):
578        """
579        Prepares guest, executes virtio_console_guest.py and initializes test.
580
581        @param vm: Informations about the guest.
582        @param consoles: Informations about consoles.
583        """
584        conss = []
585        for mode in consoles:
586            for cons in mode:
587                conss.append(cons.for_guest())
588        _init_guest(vm, 10)
589        on_guest("virt.init(%s)" % (conss), vm, 10)
590
591
592    def _search_kernel_crashlog(vm_port, timeout=2):
593        """
594        Find kernel crash message.
595
596        @param vm_port : Guest output port.
597        @param timeout: Timeout used to verify expected output.
598
599        @return: Kernel crash log or None.
600        """
601        data = vm_port.read_nonblocking()
602        match = re.search("BUG:", data, re.MULTILINE)
603        if match is None:
604            return None
605
606        match = re.search(r"BUG:.*---\[ end trace .* \]---",
607                  data, re.DOTALL |re.MULTILINE)
608        if match is None:
609            data += vm_port.read_until_last_line_matches(
610                                ["---\[ end trace .* \]---"],timeout)
611
612        match = re.search(r"(BUG:.*---\[ end trace .* \]---)",
613                  data, re.DOTALL |re.MULTILINE)
614        return match.group(0)
615
616
617
618    def _on_guest(command, vm, timeout=2):
619        """
620        Execute given command inside the script's main loop, indicating the vm
621        the command was executed on.
622
623        @param command: Command that will be executed.
624        @param vm: Informations about the guest.
625        @param timeout: Timeout used to verify expected output.
626
627        @return: Tuple (match index, data, kernel_crash)
628        """
629        logging.debug("Executing '%s' on virtio_console_guest.py loop," +
630                      " vm: %s, timeout: %s", command, vm[0].name, timeout)
631        vm[1].sendline(command)
632        try:
633            (match, data) = vm[1].read_until_last_line_matches(["PASS:",
634                                                                "FAIL:"],
635                                                               timeout)
636
637        except aexpect.ExpectError, e:
638            match = None
639            data = "Cmd process timeout. Data in console: " + e.output
640
641        kcrash_data = _search_kernel_crashlog(vm[3])
642        if kcrash_data is not None:
643            logging.error(kcrash_data)
644            vm[4] = True
645
646        return (match, data)
647
648
649    def on_guest(command, vm, timeout=2):
650        """
651        Wrapper around the _on_guest command which executes the command on
652        guest. Unlike _on_guest command when the command fails it raises the
653        test error.
654
655        @param command: Command that will be executed.
656        @param vm: Informations about the guest.
657        @param timeout: Timeout used to verify expected output.
658
659        @return: Tuple (match index, data)
660        """
661        match, data = _on_guest(command, vm, timeout)
662        if match == 1 or match is None:
663            raise error.TestFail("Failed to execute '%s' on"
664                                 " virtio_console_guest.py, "
665                                 "vm: %s, output:\n%s" %
666                                 (command, vm[0].name, data))
667
668        return (match, data)
669
670
671    def _guest_exit_threads(vm, send_pts, recv_pts):
672        """
673        Safely executes on_guest("virt.exit_threads()") using workaround of
674        the stuck thread in loopback in mode=virt.LOOP_NONE .
675
676        @param vm: Informations about the guest.
677        @param send_pts: list of possible send sockets we need to work around.
678        @param recv_pts: list of possible recv sockets we need to read-out.
679        """
680        # in LOOP_NONE mode it might stuck in read/write
681        match, tmp = _on_guest("virt.exit_threads()", vm, 10)
682        if match is None:
683            logging.debug("Workaround the stuck thread on guest")
684            # Thread is stucked in read/write
685            for send_pt in send_pts:
686                send_pt.sock.sendall(".")
687        elif match != 0:
688            # Something else
689            raise error.TestFail("Unexpected fail\nMatch: %s\nData:\n%s"
690                                 % (match, tmp))
691
692        # Read-out all remaining data
693        for recv_pt in recv_pts:
694            while select.select([recv_pt.sock], [], [], 0.1)[0]:
695                recv_pt.sock.recv(1024)
696
697        # This will cause fail in case anything went wrong.
698        on_guest("print 'PASS: nothing'", vm, 10)
699
700
701    def _vm_create(no_console=3, no_serialport=3, spread=True):
702        """
703        Creates the VM and connects the specified number of consoles and serial
704        ports.
705        Ports are allocated by 2 per 1 virtio-serial-pci device starting with
706        console. (3+2 => CC|CS|S; 0+2 => SS; 3+4 => CC|CS|SS|S, ...) This way
707        it's easy to test communication on the same or different
708        virtio-serial-pci device.
709        Further in tests the consoles are being picked always from the first
710        available one (3+2: 2xC => CC|cs|s <communication on the same PCI>;
711        2xC,1xS => CC|cS|s <communication between 2 PCI devs)
712
713        @param no_console: Number of desired virtconsoles.
714        @param no_serialport: Number of desired virtserialports.
715        @return: Tuple with (guest information, consoles information)
716                guest informations = [vm, session, tmp_dir, kcrash]
717                consoles informations = [consoles[], serialports[]]
718        """
719        consoles = []
720        serialports = []
721        tmp_dir = tempfile.mkdtemp(prefix="virtio-console-", dir="/tmp/")
722        params['extra_params'] = standard_extra_params
723
724        if not spread:
725            pci = "virtio-serial-pci0"
726            params['extra_params'] += (" -device virtio-serial-pci,id="
727                                           + pci)
728            pci += ".0"
729        for i in range(0, no_console):
730            # Spread consoles between multiple PCI devices (2 per a dev)
731            if not i % 2 and spread:
732                pci = "virtio-serial-pci%d" % (i / 2)
733                params['extra_params'] += (" -device virtio-serial-pci,id="
734                                           + pci)
735                pci += ".0"
736            params['extra_params'] += (" -chardev socket,path=%s/%d,id=vc%d,"
737                                       "server,nowait" % (tmp_dir, i, i))
738            params['extra_params'] += (" -device virtconsole,chardev=vc%d,"
739                                      "name=console-%d,id=console-%d,bus=%s"
740                                      % (i, i, i, pci))
741
742        for i in  range(no_console, no_console + no_serialport):
743            # Spread serial ports between multiple PCI devices (2 per each dev)
744            if not i % 2  and spread:
745                pci = "virtio-serial-pci%d" % (i / 2)
746                params['extra_params'] += (" -device virtio-serial-pci,id="
747                                           + pci)
748                pci += ".0"
749            params['extra_params'] += (" -chardev socket,path=%s/%d,id=vs%d,"
750                                       "server,nowait" % (tmp_dir, i, i))
751            params['extra_params'] += (" -device virtserialport,chardev=vs%d,"
752                                       "name=serialport-%d,id=serialport-%d,"
753                                       "bus=%s" % (i, i, i, pci))
754
755        (vm, session, sserial) = _restore_vm()
756
757        # connect the sockets
758        for i in range(0, no_console):
759            consoles.append(Port(None ,"console-%d" % i,
760                                 "yes", "%s/%d" % (tmp_dir, i)))
761        for i in range(no_console, no_console + no_serialport):
762            serialports.append(Port(None ,"serialport-%d" % i,
763                                    "no", "%s/%d" % (tmp_dir, i)))
764
765        kcrash = False
766
767        return [vm, session, tmp_dir, sserial, kcrash], [consoles, serialports]
768
769
770    def _restore_vm():
771        """
772        Restore old virtual machine when VM is destroyed.
773        """
774        logging.debug("Booting guest %s", params.get("main_vm"))
775        virt_env_process.preprocess_vm(test, params, env,
776                                        params.get("main_vm"))
777
778        vm = env.get_vm(params.get("main_vm"))
779
780        kernel_bug = None
781        try:
782            session = virt_test_utils.wait_for_login(vm, 0,
783                                    float(params.get("boot_timeout", 100)),
784                                    0, 2)
785        except (error.TestFail):
786            kernel_bug = _search_kernel_crashlog(vm.serial_console, 10)
787            if kernel_bug is not None:
788                logging.error(kernel_bug)
789            raise
790
791        kernel_bug = _search_kernel_crashlog(vm.serial_console, 10)
792        if kernel_bug is not None:
793            logging.error(kernel_bug)
794
795        sserial = virt_test_utils.wait_for_login(vm, 0,
796                                         float(params.get("boot_timeout", 20)),
797                                         0, 2, serial=True)
798        return [vm, session, sserial]
799
800
801    def topen(vm, port):
802        """
803        Open virtioconsole port.
804
805        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
806        @param port: Port identifier.
807        """
808        on_guest("virt.open('%s')" % (port.name), vm, 10)
809        port.open()
810
811
812    def tcheck_zero_sym(vm):
813        """
814        Check if port /dev/vport0p0 was created.
815
816        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
817        """
818        on_guest("virt.check_zero_sym()", vm, 10)
819
820
821    def tmulti_open(vm, port):
822        """
823        Multiopen virtioconsole port.
824
825        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
826        @param port: Port identifier.
827        """
828        on_guest("virt.close('%s')" % (port.name), vm, 10)
829        on_guest("virt.open('%s')" % (port.name), vm, 10)
830        (match, data) = _on_guest("virt.open('%s')" % (port.name), vm, 10)
831        # Console is permitted to open the device multiple times
832        if port.port_type == "yes": #is console?
833            if match != 0: #Multiopen not pass
834                raise error.TestFail("Unexpected fail of opening the console"
835                                     " device for the 2nd time.\n%s" % data)
836        else:
837            if match != 1: #Multiopen not fail:
838                raise error.TestFail("Unexpetded pass of opening the"
839                                     " serialport device for the 2nd time.")
840            elif not "[Errno 24]" in data:
841                raise error.TestFail("Multiple opening fail but with another"
842                                     " exception %s" % data)
843        port.open()
844
845
846    def tclose(vm, port):
847        """
848        Close socket.
849
850        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
851        @param port: Port to open.
852        """
853        on_guest("virt.close('%s')" % (port.name), vm, 10)
854        port.close()
855
856
857    def tpolling(vm, port):
858        """
859        Test try polling function.
860
861        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
862        @param port: Port used in test.
863        """
864        # Poll (OUT)
865        on_guest("virt.poll('%s', %s)" % (port.name, select.POLLOUT), vm,
866                 2)
867
868        # Poll (IN, OUT)
869        port.sock.sendall("test")
870        for test in [select.POLLIN, select.POLLOUT]:
871            on_guest("virt.poll('%s', %s)" % (port.name, test), vm, 10)
872
873        # Poll (IN HUP)
874        # I store the socket informations and close the socket
875        port.close()
876        for test in [select.POLLIN, select.POLLHUP]:
877            on_guest("virt.poll('%s', %s)" % (port.name, test), vm, 10)
878
879        # Poll (HUP)
880        on_guest("virt.recv('%s', 4, 1024, False)" % (port.name), vm, 10)
881        on_guest("virt.poll('%s', %s)" % (port.name, select.POLLHUP), vm,
882                 2)
883
884        # Reconnect the socket
885        port.open()
886        # Redefine socket in consoles
887        on_guest("virt.poll('%s', %s)" % (port.name, select.POLLOUT), vm,
888                 2)
889
890
891    def tsigio(vm, port):
892        """
893        Test try sigio function.
894
895        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
896        @param port: Port used in test.
897        """
898        if port.is_open:
899            port.close()
900
901        # Enable sigio on specific port
902        on_guest("virt.async('%s', True, 0)" %
903                 (port.name) , vm, 10)
904        on_guest("virt.get_sigio_poll_return('%s')" % (port.name) , vm, 10)
905
906        #Test sigio when port open
907        on_guest("virt.set_pool_want_return('%s', select.POLLOUT)" %
908                 (port.name), vm, 10)
909        port.open()
910        match = _on_guest("virt.get_sigio_poll_return('%s')" %
911                          (port.name) , vm, 10)[0]
912        if match == 1:
913            raise error.TestFail("Problem with HUP on console port.")
914
915        #Test sigio when port receive data
916        on_guest("virt.set_pool_want_return('%s', select.POLLOUT |"
917                 " select.POLLIN)" % (port.name), vm, 10)
918        port.sock.sendall("0123456789")
919        on_guest("virt.get_sigio_poll_return('%s')" % (port.name) , vm, 10)
920
921        #Test sigio port close event
922        on_guest("virt.set_pool_want_return('%s', select.POLLHUP |"
923                 " select.POLLIN)" % (port.name), vm, 10)
924        port.close()
925        on_guest("virt.get_sigio_poll_return('%s')" % (port.name) , vm, 10)
926
927        #Test sigio port open event and persistence of written data on port.
928        on_guest("virt.set_pool_want_return('%s', select.POLLOUT |"
929                 " select.POLLIN)" % (port.name), vm, 10)
930        port.open()
931        on_guest("virt.get_sigio_poll_return('%s')" % (port.name) , vm, 10)
932
933        #Test event when erase data.
934        on_guest("virt.clean_port('%s')" % (port.name), vm, 10)
935        port.close()
936        on_guest("virt.set_pool_want_return('%s', select.POLLOUT)"
937                 % (port.name), vm, 10)
938        port.open()
939        on_guest("virt.get_sigio_poll_return('%s')" % (port.name) , vm, 10)
940
941        # Disable sigio on specific port
942        on_guest("virt.async('%s', False, 0)" %
943                 (port.name) , vm, 10)
944
945
946    def tlseek(vm, port):
947        """
948        Tests the correct handling of lseek (expected fail)
949
950        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
951        @param port: Port used in test.
952        """
953        # The virt.lseek returns PASS when the seek fails
954        on_guest("virt.lseek('%s', 0, 0)" % (port.name), vm, 10)
955
956
957    def trw_host_offline(vm, port):
958        """
959        Guest read/write from host when host is disconnected.
960
961        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
962        @param port: Port used in test.
963        """
964        if port.is_open:
965            port.close()
966
967        on_guest("virt.recv('%s', 0, 1024, False)" % port.name, vm, 10)
968        match, tmp = _on_guest("virt.send('%s', 10, True)" % port.name,
969                                                             vm, 10)
970        if match is not None:
971            raise error.TestFail("Write on guest while host disconnected "
972                                 "didn't time out.\nOutput:\n%s"
973                                 % tmp)
974
975        port.open()
976
977        if (port.sock.recv(1024) < 10):
978            raise error.TestFail("Didn't received data from guest")
979        # Now the _on_guest("virt.send('%s'... command should be finished
980        on_guest("print('PASS: nothing')", vm, 10)
981
982
983    def trw_host_offline_big_data(vm, port):
984        """
985        Guest read/write from host when host is disconnected.
986
987        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
988        @param port: Port used in test.
989        """
990        if port.is_open:
991            port.close()
992
993        port.clean_port()
994        port.close()
995        on_guest("virt.clean_port('%s'),1024" % port.name, vm, 10)
996        match, tmp = _on_guest("virt.send('%s', (1024**3)*3, True, "
997                               "is_static=True)" % port.name, vm, 30)
998        if match is None:
999            raise error.TestFail("Write on guest while host disconnected "
1000                                 "didn't time out.\nOutput:\n%s"
1001                                 % tmp)
1002
1003        time.sleep(20)
1004
1005        port.open()
1006
1007        rlen = 0
1008        while rlen < (1024**3*3):
1009            ret = select.select([port.sock], [], [], 10.0)
1010            if (ret[0] != []):
1011                rlen += len(port.sock.recv(((4096))))
1012            elif rlen != (1024**3*3):
1013                raise error.TestFail("Not all data was received,"
1014                                     "only %d from %d" % (rlen, 1024**3*3))
1015        on_guest("print('PASS: nothing')", vm, 10)
1016
1017
1018    def trw_notconnect_guest(vm, port, consoles):
1019        """
1020        Host send data to guest port and guest not read any data from port.
1021
1022        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
1023        @param port: Port used in test.
1024        """
1025        vm[0].destroy(gracefully = False)
1026        (vm[0], vm[1], vm[3]) = _restore_vm()
1027        if not port.is_open:
1028            port.open()
1029        else:
1030            port.close()
1031            port.open()
1032
1033        port.sock.settimeout(20.0)
1034
1035        loads = utils.SystemLoad([(os.getpid(), 'autotest'),
1036                                  (vm[0].get_pid(), 'VM'), 0])
1037        loads.start()
1038
1039        try:
1040            sent1 = 0
1041            for i in range(1000000):
1042                sent1 += port.sock.send("a")
1043        except socket.timeout:
1044            logging.info("Data sending to closed port timed out.")
1045
1046        logging.info("Bytes sent to client: %d" % (sent1))
1047        logging.info("\n" + loads.get_cpu_status_string()[:-1])
1048
1049        on_guest('echo -n "PASS:"', vm, 10)
1050
1051        logging.info("Open and then close port %s" % (port.name))
1052        init_guest(vm, consoles)
1053        # Test of live and open and close port again
1054        _clean_ports(vm, consoles)
1055        on_guest("virt.close('%s')" % (port.name), vm, 10)
1056
1057        # With serialport it is a different behavior
1058        on_guest("guest_exit()", vm, 10)
1059        port.sock.settimeout(20.0)
1060
1061        loads.start()
1062        try:
1063            sent2 = 0
1064            for i in range(40000):
1065                sent2 = port.sock.send("a")
1066        except socket.timeout:
1067            logging.info("Data sending to closed port timed out.")
1068
1069        logging.info("Bytes sent to client: %d" % (sent2))
1070        logging.info("\n" + loads.get_cpu_status_string()[:-1])
1071        loads.stop()
1072        if (sent1 != sent2):
1073            logging.warning("Inconsistent behavior: First sent %d bytes and "
1074                            "second sent %d bytes" % (sent1, sent2))
1075
1076        port.sock.settimeout(None)
1077        (vm[0], vm[1], vm[3]) = _restore_vm()
1078
1079        init_guest(vm, consoles)
1080        _clean_ports(vm, consoles)
1081
1082
1083    def trw_blocking_mode(vm, port):
1084        """
1085        Guest read\write data in blocking mode.
1086
1087        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
1088        @param port: Port used in test.
1089        """
1090        # Blocking mode
1091        if not port.is_open:
1092            port.open()
1093        on_guest("virt.blocking('%s', True)" % port.name, vm, 10)
1094        # Recv should timed out
1095        match, tmp = _on_guest("virt.recv('%s', 10, 1024, False)" %
1096                               port.name, vm, 10)
1097        if match == 0:
1098            raise error.TestFail("Received data even when none was sent\n"
1099                                 "Data:\n%s" % tmp)
1100        elif match is not None:
1101            raise error.TestFail("Unexpected fail\nMatch: %s\nData:\n%s" %
1102                                 (match, tmp))
1103        port.sock.sendall("1234567890")
1104        # Now guest received the data end escaped from the recv()
1105        on_guest("print('PASS: nothing')", vm, 10)
1106
1107
1108    def trw_nonblocking_mode(vm, port):
1109        """
1110        Guest read\write data in nonblocking mode.
1111
1112        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
1113        @param port: Port used in test.
1114        """
1115        # Non-blocking mode
1116        if not port.is_open:
1117            port.open()
1118        on_guest("virt.blocking('%s', False)" % port.name, vm, 10)
1119        # Recv should return FAIL with 0 received data
1120        match, tmp = _on_guest("virt.recv('%s', 10, 1024, False)" %
1121                              port.name, vm, 10)
1122        if match == 0:
1123            raise error.TestFail("Received data even when none was sent\n"
1124                                 "Data:\n%s" % tmp)
1125        elif match is None:
1126            raise error.TestFail("Timed out, probably in blocking mode\n"
1127                                 "Data:\n%s" % tmp)
1128        elif match != 1:
1129            raise error.TestFail("Unexpected fail\nMatch: %s\nData:\n%s" %
1130                                 (match, tmp))
1131        port.sock.sendall("1234567890")
1132        on_guest("virt.recv('%s', 10, 1024, False)" % port.name, vm, 10)
1133
1134
1135    def tbasic_loopback(vm, send_port, recv_port, data="Smoke test data"):
1136        """
1137        Easy loop back test with loop over only two ports.
1138
1139        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
1140        @param port: Port used in test.
1141        """
1142        if not send_port.is_open:
1143            send_port.open()
1144        if not recv_port.is_open:
1145            recv_port.open()
1146        on_guest("virt.loopback(['%s'], ['%s'], 1024, virt.LOOP_NONE)" %
1147                     (send_port.name, recv_port.name), vm, 10)
1148        send_port.sock.sendall(data)
1149        tmp = ""
1150        i = 0
1151        while i <= 10:
1152            i += 1
1153            ret = select.select([recv_port.sock], [], [], 1.0)
1154            if ret:
1155                tmp += recv_port.sock.recv(1024)
1156            if len(tmp) >= len(data):
1157                break
1158        if tmp != data:
1159            raise error.TestFail("Incorrect data: '%s' != '%s'",
1160                                 data, tmp)
1161        _guest_exit_threads(vm, [send_port], [recv_port])
1162
1163
1164    def trmmod(vm, consoles):
1165        """
1166        Remove and load virtio_console kernel modules.
1167
1168        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
1169        @param consoles: Consoles which should be close before rmmod.
1170        """
1171        on_guest("guest_exit()", vm, 5)
1172
1173        on_guest("rmmod -f virtio_console && echo -n PASS: rmmod "
1174                 "|| echo -n FAIL: rmmod", vm, 10)
1175        on_guest("modprobe virtio_console "
1176                 "&& echo -n PASS: modprobe || echo -n FAIL: modprobe",
1177                 vm, 10)
1178
1179        init_guest(vm, consoles)
1180        try:
1181            cname = consoles[0][0].name
1182        except (IndexError):
1183            cname = consoles[1][0].name
1184        on_guest("virt.clean_port('%s'),1024" % cname, vm, 2)
1185
1186
1187    def tmax_serial_ports(vm, consoles):
1188        """
1189        Test maximum count of ports in guest machine.
1190
1191        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
1192        @param consoles: Consoles which should be close before rmmod.
1193        """
1194        logging.debug("Count of serial ports: 30")
1195        vm[0].destroy(gracefully = False)
1196        (vm, consoles) = _vm_create(0, 30, False)
1197        try:
1198            init_guest(vm, consoles)
1199        except error.TestFail, ints:
1200            logging.info("Count of serial ports: 30")
1201            raise ints
1202        clean_reload_vm(vm, consoles, expected=True)
1203
1204
1205    def tmax_console_ports(vm, consoles):
1206        """
1207        Test maximum count of ports in guest machine.
1208
1209        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
1210        @param consoles: Consoles which should be close before rmmod.
1211        """
1212        logging.debug("Count of console ports: 30")
1213        vm[0].destroy(gracefully = False)
1214        (vm, consoles) = _vm_create(30, 0, False)
1215        try:
1216            init_guest(vm, consoles)
1217        except error.TestFail, ints:
1218            logging.info("Count of console ports: 30")
1219            raise ints
1220        clean_reload_vm(vm, consoles, expected=True)
1221
1222
1223    def tmax_mix_serial_conosle_port(vm, consoles):
1224        """
1225        Test maximim count of ports in guest machine.
1226
1227        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
1228        @param consoles: Consoles which should be close before rmmod.
1229        """
1230        logging.debug("Count of ports (serial+console): 30")
1231        vm[0].destroy(gracefully = False)
1232        (vm, consoles) = _vm_create(15, 15, False)
1233        try:
1234            init_guest(vm, consoles)
1235        except error.TestFail, ints:
1236            logging.info("Count of ports (serial+console): 30")
1237            raise ints
1238        clean_reload_vm(vm, consoles, expected=True)
1239
1240
1241    def tshutdown(vm, consoles):
1242        """
1243        Try to gently shutdown the machine. Virtio_console shouldn't block this.
1244
1245        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
1246        @param consoles: Consoles which should be close before rmmod.
1247        """
1248        ports = []
1249        for console in consoles[0]:
1250            ports.append(console)
1251        for console in consoles[1]:
1252            ports.append(console)
1253        for port in ports:
1254            port.open()
1255        # If more than one, send data on the other ports
1256        for port in ports[1:]:
1257            on_guest("virt.close('%s')" % (port.name), vm, 2)
1258            on_guest("virt.open('%s')" % (port.name), vm, 2)
1259            try:
1260                os.system("dd if=/dev/random of='%s' bs=4096 >/dev/null 2>&1 &"
1261                          % port.path)
1262            except:
1263                pass
1264        # Just start sending, it won't finish anyway...
1265        _on_guest("virt.send('%s', 1024**3, True, is_static=True)"
1266                  % ports[0].name, vm, 1)
1267
1268        # Let the computer transfer some bytes :-)
1269        time.sleep(2)
1270
1271        # Power off the computer
1272        vm[0].destroy(gracefully=True)
1273        clean_reload_vm(vm, consoles, expected=True)
1274
1275
1276    def __tmigrate(vm, consoles, parms, offline=True):
1277        """
1278        An actual migration test. It creates loopback on guest from first port
1279        to all remaining ports. Than it sends and validates the data.
1280        During this it tries to migrate the vm n-times.
1281
1282        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
1283        @param consoles: Field of virtio ports with the minimum of 2 items.
1284        @param parms: [media, no_migration, send-, recv-, loopback-buffer_len]
1285        """
1286        # PREPARE
1287        send_pt = consoles[parms[0]][0]
1288        recv_pts = consoles[parms[0]][1:]
1289        # TODO BUG: sendlen = max allowed data to be lost per one migration
1290        # TODO BUG: using SMP the data loss is upto 4 buffers
1291        # 2048 = char. dev. socket size, parms[2] = host->guest send buffer size
1292        sendlen = 2*2*max(2048, parms[2])
1293        if not offline: # TODO BUG: online migration causes more loses
1294            # TODO: Online migration lose n*buffer. n depends on the console
1295            # troughput. FIX or analyse it's cause.
1296            sendlen = 1000 * sendlen
1297        for p in recv_pts:
1298            if not p.is_open:
1299                p.open()
1300
1301        if not send_pt.is_open:
1302            send_pt.open()
1303
1304        threads = []
1305        queues = []
1306        verified = []
1307        for i in range(0, len(recv_pts)):
1308            queues.append(deque())
1309            verified.append(0)
1310
1311        tmp = "'%s'" % recv_pts[0].name
1312        for recv_pt in recv_pts[1:]:
1313            tmp += ", '%s'" % (recv_pt.name)
1314        on_guest("virt.loopback(['%s'], [%s], %d, virt.LOOP_POLL)"
1315                 % (send_pt.name, tmp, parms[4]), vm, 10)
1316
1317        exit_event = threading.Event()
1318
1319        # TEST
1320        thread = ThSendCheck(send_pt, exit_event, queues,
1321                             parms[2])
1322        thread.start()
1323        threads.append(thread)
1324
1325        for i in range(len(recv_pts)):
1326            thread = ThRecvCheck(recv_pts[i], queues[i], exit_event,
1327                                 parms[3], sendlen=sendlen)
1328            thread.start()
1329            threads.append(thread)
1330
1331        i=0
1332        while i < 6:
1333            tmp = "%d data sent; " % threads[0].idx
1334            for thread in threads[1:]:
1335                tmp += "%d, " % thread.idx
1336            logging.debug("test_loopback: %s data received and verified",
1337                         tmp[:-2])
1338            i+=1
1339            time.sleep(2)
1340
1341
1342        for j in range(parms[1]):
1343            vm[0] = virt_test_utils.migrate(vm[0], env, 3600, "exec", 0,
1344                                             offline)
1345            if not vm[1]:
1346                raise error.TestFail("Could not log into guest after migration")
1347            vm[1] = virt_test_utils.wait_for_login(vm[0], 0,
1348                                        float(params.get("boot_timeout", 100)),
1349                                        0, 2)
1350            # OS is sometime a bit dizzy. DL=30
1351            _init_guest(vm, 30)
1352
1353            i=0
1354            while i < 6:
1355                tmp = "%d data sent; " % threads[0].idx
1356                for thread in threads[1:]:
1357                    tmp += "%d, " % thread.idx
1358                logging.debug("test_loopback: %s data received and verified",
1359                             tmp[:-2])
1360                i+=1
1361                time.sleep(2)
1362            if not threads[0].is_alive():
1363                if exit_event.isSet():
1364                    raise error.TestFail("Exit event emited, check the log for"
1365                                         "send/recv thread failure.")
1366                else:
1367                    raise error.TestFail("Send thread died unexpectedly in "
1368                                         "migration %d", (j+1))
1369            for i in range(0, len(recv_pts)):
1370                if not threads[i+1].is_alive():
1371                    raise error.TestFail("Recv thread %d died unexpectedly in "
1372                                         "migration %d", i, (j+1))
1373                if verified[i] == threads[i+1].idx:
1374                    raise error.TestFail("No new data in %d console were "
1375                                         "transfered after migration %d"
1376                                         , i, (j+1))
1377                verified[i] = threads[i+1].idx
1378            logging.info("%d out of %d migration(s) passed" % ((j+1), parms[1]))
1379            # TODO detect recv-thread failure and throw out whole test
1380
1381        # FINISH
1382        exit_event.set()
1383        # Send thread might fail to exit when the guest stucks
1384        i = 30
1385        while threads[0].is_alive():
1386            if i <= 0:
1387                raise error.TestFail("Send thread did not finish")
1388            time.sleep(1)
1389            i -= 1
1390        tmp = "%d data sent; " % threads[0].idx
1391        for thread in threads[1:]:
1392            thread.join()
1393            tmp += "%d, " % thread.idx
1394        logging.info("test_loopback: %s data received and verified during %d "
1395                     "migrations", tmp[:-2], parms[1])
1396
1397        # CLEANUP
1398        _guest_exit_threads(vm, [send_pt], recv_pts)
1399        del exit_event
1400        del threads[:]
1401
1402
1403    def _tmigrate(vm, consoles, parms, offline):
1404        """
1405        Wrapper which parses the params for __migrate test.
1406
1407        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
1408        @param consoles: Field of virtio ports with the minimum of 2 items.
1409        @param parms: test parameters, multiple recievers allowed.
1410            '[{serialport,console}]:$no_migrations:send_buf_len:recv_buf_len:
1411             loopback_buf_len;...'
1412        """
1413        for param in parms.split(';'):
1414            if not param:
1415                continue
1416            if offline:
1417                logging.info("test_migrate_offline: params: %s", param)
1418            else:
1419                logging.info("test_migrate_online: params: %s", param)
1420            param = param.split(':')
1421            media = 1
1422            if param[0].isalpha():
1423                if param[0] == "console":
1424                    param[0] = 0
1425                else:
1426                    param[0] = 1
1427            else:
1428                param = [0] + param
1429            for i in range(1,5):
1430                if not param[i].isdigit():
1431                    param[i] = 1
1432                else:
1433                    param[i] = int(param[i])
1434
1435            __tmigrate(vm, consoles, param, offline=offline)
1436
1437
1438    def tmigrate_offline(vm, consoles, parms):
1439        """
1440        Tests whether the virtio-{console,port} are able to survive the offline
1441        migration.
1442
1443        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
1444        @param consoles: Field of virtio ports with the minimum of 2 items.
1445        @param parms: test parameters, multiple recievers allowed.
1446            '[{serialport,console}]:$no_migrations:send_buf_len:recv_buf_len:
1447             loopback_buf_len;...'
1448        """
1449        _tmigrate(vm, consoles, parms, offline=True)
1450
1451
1452    def tmigrate_online(vm, consoles, parms):
1453        """
1454        Tests whether the virtio-{console,port} are able to survive the online
1455        migration.
1456
1457        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
1458        @param consoles: Field of virtio ports with the minimum of 2 items.
1459        @param parms: test parameters, multiple recievers allowed.
1460            '[{serialport,console}]:$no_migrations:send_buf_len:recv_buf_len:
1461             loopback_buf_len;...'
1462        """
1463        _tmigrate(vm, consoles, parms, offline=False)
1464
1465
1466    def _virtio_dev_create(vm, ports_name, pciid, id, console="no"):
1467        """
1468        Add virtio serialport device.
1469
1470        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
1471        @param ports_name: Structure of ports.
1472        @param pciid: Id of virtio-serial-pci device.
1473        @param id: Id of port.
1474        @param console: if "yes" inicialize console.
1475        """
1476        port = "serialport-"
1477        port_type = "virtserialport"
1478        if console == "yes":
1479            port = "console-"
1480            port_type = "virtconsole"
1481        port += "%d%d" % (pciid, id)
1482        ret = vm[0].monitors[0].cmd("device_add %s,"
1483                                    "bus=virtio-serial-pci%d.0,"
1484                                    "id=%s,"
1485                                    "name=%s"
1486                                    % (port_type, pciid, port, port))
1487        ports_name.append([ port, console])
1488        if ret != "":
1489            logging.error(ret)
1490
1491
1492    def _virtio_dev_del(vm, ports_name, pciid, id):
1493        """
1494        Del virtio serialport device.
1495
1496        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
1497        @param ports_name: Structure of ports.
1498        @param pciid: Id of virtio-serial-pci device.
1499        @param id: Id of port.
1500        """
1501        port = filter(lambda x: x[0].endswith("-%d%d" % (pciid, id)),
1502                      ports_name)
1503        ret = vm[0].monitors[0].cmd("device_del %s"
1504                                        % (port[0][0]))
1505        ports_name.remove(port[0])
1506        if ret != "":
1507            logging.error(ret)
1508
1509
1510    def thotplug(vm, consoles, console="no", timeout=1):
1511        """
1512        Try hotplug function of virtio-consoles ports.
1513
1514        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
1515        @param consoles: Consoles.
1516        @param console: If "yes" inicialize console.
1517        @param timeout: Timeout between hotplug operations.
1518        """
1519        logging.info("Timeout between hotplug operations t=%fs" % timeout)
1520        _reset_vm(vm, consoles, 1, 1)
1521        ports_name = []
1522        ports_name.append(['serialport-1','no'])
1523        ports_name.append(['console-0','yes'])
1524
1525        logging.info("Test correct initialization of hotplug ports")
1526        for id in range(1,5): #count of pci device
1527            ret = vm[0].monitors[0].cmd("device_add virtio-serial-pci,"
1528                                        "id=virtio-serial-pci%d" % (id))
1529            if ret != "":
1530                logging.error(ret)
1531            for i in range(id*5+5): #max port 30
1532                _virtio_dev_create(vm, ports_name, id, i, console)
1533                time.sleep(timeout)
1534
1535        # Test correct initialization of hotplug ports
1536        time.sleep(10) # Timeout for port initialization
1537        _init_guest(vm, 10)
1538        on_guest('virt.init(%s)' % (ports_name), vm, 10)
1539
1540        logging.info("Delete ports when ports are used")
1541        # Delete ports when ports are used.
1542        if not consoles[0][0].is_open:
1543            consoles[0][0].open()
1544        if not consoles[1][0].is_open:
1545            consoles[1][0].open()
1546        on_guest("virt.loopback(['%s'], ['%s'], 1024,"
1547                 "virt.LOOP_POLL)" % (consoles[0][0].name,
1548                                      consoles[1][0].name), vm, 10)
1549        exit_event = threading.Event()
1550        send = ThSend(consoles[0][0].sock, "Data", exit_event, quiet = True)
1551        recv = ThRecv(consoles[1][0].sock, exit_event, quiet = True)
1552        send.start()
1553        time.sleep(2)
1554        recv.start()
1555
1556        # Try to delete ports under load
1557        ret = vm[0].monitors[0].cmd("device_del serialport-1")
1558        ret += vm[0].monitors[0].cmd("device_del console-0")
1559        ports_name.remove(['serialport-1','no'])
1560        ports_name.remove(['console-0','yes'])
1561        if ret != "":
1562            logging.error(ret)
1563
1564        exit_event.set()
1565        send.join()
1566        recv.join()
1567        on_guest("virt.exit_threads()", vm, 10)
1568        on_guest('guest_exit()', vm, 10)
1569
1570        logging.info("Trying to add maximum count of ports to one pci device")
1571        # Try to add ports
1572        for i in range(30): # max port 30
1573            _virtio_dev_create(vm, ports_name, 0, i, console)
1574            time.sleep(timeout)
1575        _init_guest(vm, 10)
1576        time.sleep(10)
1577        on_guest('virt.init(%s)' % (ports_name), vm, 20)
1578        on_guest('guest_exit()', vm, 10)
1579
1580        logging.info("Trying delete and add again part of ports")
1581        # Try to delete ports
1582        for i in range(25): # max port 30
1583            _virtio_dev_del(vm, ports_name, 0, i)
1584            time.sleep(timeout)
1585        _init_guest(vm, 10)
1586        on_guest('virt.init(%s)' % (ports_name), vm, 10)
1587        on_guest('guest_exit()', vm, 10)
1588
1589        # Try to add ports
1590        for i in range(5): # max port 30
1591            _virtio_dev_create(vm, ports_name, 0, i, console)
1592            time.sleep(timeout)
1593        _init_guest(vm, 10)
1594        on_guest('virt.init(%s)' % (ports_name), vm, 10)
1595        on_guest('guest_exit()', vm, 10)
1596
1597        logging.info("Trying to add and delete one port 100 times")
1598        # Try 100 times add and delete one port.
1599        for i in range(100):
1600            _virtio_dev_del(vm, ports_name, 0, 0)
1601            time.sleep(timeout)
1602            _virtio_dev_create(vm, ports_name, 0, 0, console)
1603            time.sleep(timeout)
1604        _init_guest(vm, 10)
1605        on_guest('virt.init(%s)' % (ports_name), vm, 10)
1606        on_guest('guest_exit()', vm, 10)
1607
1608
1609    def thotplug_no_timeout(vm, consoles, console="no"):
1610        """
1611        Start hotplug test without any timeout.
1612
1613        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
1614        @param consoles: Consoles which should be close before rmmod.
1615        @param console: If "yes" inicialize console.
1616        """
1617        thotplug(vm, consoles, console, 0)
1618
1619
1620    def thotplug_virtio_pci(vm, consoles):
1621        """
1622        Test hotplug of virtio-serial-pci.
1623
1624        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
1625        @param consoles: Consoles which should be close before rmmod.
1626        """
1627        vm[0].destroy(gracefully = False)
1628        (vm, consoles) = _vm_create(1, 1, False)
1629        id = 1
1630        ret = vm[0].monitors[0].cmd("device_add virtio-serial-pci,"
1631                                    "id=virtio-serial-pci%d" % (id))
1632        time.sleep(10)
1633        ret += vm[0].monitors[0].cmd("device_del virtio-serial-pci%d" % (id))
1634        time.sleep(10)
1635        ret += vm[0].monitors[0].cmd("device_add virtio-serial-pci,"
1636                                    "id=virtio-serial-pci%d" % (id))
1637        if ret != "":
1638            logging.error(ret)
1639
1640
1641    def tloopback(vm, consoles, params):
1642        """
1643        Virtio console loopback subtest.
1644
1645        Creates loopback on the vm machine between send_pt and recv_pts
1646        ports and sends length amount of data through this connection.
1647        It validates the correctness of the data sent.
1648
1649        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
1650        @param consoles: Field of virtio ports with the minimum of 2 items.
1651        @param params: test parameters, multiple recievers allowed.
1652            '$source_console_type@buffer_length:
1653             $destination_console_type1@$buffer_length:...:
1654             $loopback_buffer_length;...'
1655        """
1656        # PREPARE
1657        for param in params.split(';'):
1658            if not param:
1659                continue
1660            logging.info("test_loopback: params: %s", param)
1661            param = param.split(':')
1662            idx_serialport = 0
1663            idx_console = 0
1664            buf_len = []
1665            if (param[0].startswith('console')):
1666                send_pt = consoles[0][idx_console]
1667                idx_console += 1
1668            else:
1669                send_pt = consoles[1][idx_serialport]
1670                idx_serialport += 1
1671            if (len(param[0].split('@')) == 2):
1672                buf_len.append(int(param[0].split('@')[1]))
1673            else:
1674                buf_len.append(1024)
1675            recv_pts = []
1676            for parm in param[1:]:
1677                if (parm.isdigit()):
1678                    buf_len.append(int(parm))
1679                    break   # buf_len is the last portion of param
1680                if (parm.startswith('console')):
1681                    recv_pts.append(consoles[0][idx_console])
1682                    idx_console += 1
1683                else:
1684                    recv_pts.append(consoles[1][idx_serialport])
1685                    idx_serialport += 1
1686                if (len(parm[0].split('@')) == 2):
1687                    buf_len.append(int(parm[0].split('@')[1]))
1688                else:
1689                    buf_len.append(1024)
1690            # There must be sum(idx_*) consoles + last item as loopback buf_len
1691            if len(buf_len) == (idx_console + idx_serialport):
1692                buf_len.append(1024)
1693
1694            for p in recv_pts:
1695                if not p.is_open:
1696                    p.open()
1697
1698            if not send_pt.is_open:
1699                send_pt.open()
1700
1701            if len(recv_pts) == 0:
1702                raise error.TestFail("test_loopback: incorrect recv consoles"
1703                                     "definition")
1704
1705            threads = []
1706            queues = []
1707            for i in range(0, len(recv_pts)):
1708                queues.append(deque())
1709
1710            tmp = "'%s'" % recv_pts[0].name
1711            for recv_pt in recv_pts[1:]:
1712                tmp += ", '%s'" % (recv_pt.name)
1713            on_guest("virt.loopback(['%s'], [%s], %d, virt.LOOP_POLL)"
1714                     % (send_pt.name, tmp, buf_len[-1]), vm, 10)
1715
1716            exit_event = threading.Event()
1717
1718            # TEST
1719            thread = ThSendCheck(send_pt, exit_event, queues,
1720                                   buf_len[0])
1721            thread.start()
1722            threads.append(thread)
1723
1724            for i in range(len(recv_pts)):
1725                thread = ThRecvCheck(recv_pts[i], queues[i], exit_event,
1726                                       buf_len[i + 1])
1727                thread.start()
1728                threads.append(thread)
1729
1730            time.sleep(60)
1731            exit_event.set()
1732            threads[0].join()
1733            tmp = "%d data sent; " % threads[0].idx
1734            for thread in threads[1:]:
1735                thread.join()
1736                tmp += "%d, " % thread.idx
1737            logging.info("test_loopback: %s data received and verified",
1738                         tmp[:-2])
1739
1740            # Read-out all remaining data
1741            for recv_pt in recv_pts:
1742                while select.select([recv_pt.sock], [], [], 0.1)[0]:
1743                    recv_pt.sock.recv(1024)
1744
1745            _guest_exit_threads(vm, [send_pt], recv_pts)
1746
1747            del exit_event
1748            del threads[:]
1749
1750
1751    def tperf(vm, consoles, params):
1752        """
1753        Tests performance of the virtio_console tunel. First it sends the data
1754        from host to guest and than back. It provides informations about
1755        computer utilisation and statistic informations about the troughput.
1756
1757        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
1758        @param consoles: Field of virtio ports with the minimum of 2 items.
1759        @param params: test parameters:
1760                '$console_type@$buffer_length:$test_duration;...'
1761        """
1762        for param in params.split(';'):
1763            if not param:
1764                continue
1765            logging.info("test_perf: params: %s", param)
1766            param = param.split(':')
1767            duration = 60.0
1768            if len(param) > 1:
1769                try:
1770                    duration = float(param[1])
1771                except:
1772                    pass
1773            param = param[0].split('@')
1774            if len(param) > 1 and param[1].isdigit():
1775                buf_len = int(param[1])
1776            else:
1777                buf_len = 1024
1778            param = (param[0] == 'serialport')
1779            port = consoles[param][0]
1780
1781            if not port.is_open:
1782                port.open()
1783
1784            data = ""
1785            for i in range(buf_len):
1786                data += "%c" % random.randrange(255)
1787
1788            exit_event = threading.Event()
1789            time_slice = float(duration) / 100
1790
1791            # HOST -> GUEST
1792            on_guest('virt.loopback(["%s"], [], %d, virt.LOOP_NONE)' %
1793                     (port.name, buf_len), vm, 10)
1794            thread = ThSend(port.sock, data, exit_event)
1795            stats = array.array('f', [])
1796            loads = utils.SystemLoad([(os.getpid(), 'autotest'),
1797                                      (vm[0].get_pid(), 'VM'), 0])
1798            loads.start()
1799            _time = time.time()
1800            thread.start()
1801            for i in range(100):
1802                stats.append(thread.idx)
1803                time.sleep(time_slice)
1804            _time = time.time() - _time - duration
1805            logging.info("\n" + loads.get_cpu_status_string()[:-1])
1806            logging.info("\n" + loads.get_mem_status_string()[:-1])
1807            exit_event.set()
1808            thread.join()
1809
1810            # Let the guest read-out all the remaining data
1811            while not _on_guest("virt.poll('%s', %s)" %
1812                                (port.name, select.POLLIN), vm, 10)[0]:
1813                time.sleep(1)
1814
1815            _guest_exit_threads(vm, [port], [])
1816
1817            if (_time > time_slice):
1818                logging.error(
1819                "Test ran %fs longer which is more than one time slice", _time)
1820            else:
1821                logging.debug("Test ran %fs longer", _time)
1822            stats = process_stats(stats[1:], time_slice * 1048576)
1823            logging.debug("Stats = %s", stats)
1824            logging.info("Host -> Guest [MB/s] (min/med/max) = %.3f/%.3f/%.3f",
1825                        stats[0], stats[len(stats) / 2], stats[-1])
1826
1827            del thread
1828
1829            # GUEST -> HOST
1830            exit_event.clear()
1831            stats = array.array('f', [])
1832            on_guest("virt.send_loop_init('%s', %d)" % (port.name, buf_len),
1833                     vm, 30)
1834            thread = ThRecv(port.sock, exit_event, buf_len)
1835            thread.start()
1836            loads.start()
1837            on_guest("virt.send_loop()", vm, 10)
1838            _time = time.time()
1839            for i in range(100):
1840                stats.append(thread.idx)
1841                time.sleep(time_slice)
1842            _time = time.time() - _time - duration
1843            logging.info("\n" + loads.get_cpu_status_string()[:-1])
1844            logging.info("\n" + loads.get_mem_status_string()[:-1])
1845            on_guest("virt.exit_threads()", vm, 10)
1846            exit_event.set()
1847            thread.join()
1848            if (_time > time_slice): # Deviation is higher than 1 time_slice
1849                logging.error(
1850                "Test ran %fs longer which is more than one time slice", _time)
1851            else:
1852                logging.debug("Test ran %fs longer", _time)
1853            stats = process_stats(stats[1:], time_slice * 1048576)
1854            logging.debug("Stats = %s", stats)
1855            logging.info("Guest -> Host [MB/s] (min/med/max) = %.3f/%.3f/%.3f",
1856                         stats[0], stats[len(stats) / 2], stats[-1])
1857
1858            del thread
1859            del exit_event
1860
1861
1862    def _clean_ports(vm, consoles):
1863        """
1864        Read all data from all ports, in both sides of each port.
1865
1866        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
1867        @param consoles: Consoles which should be clean.
1868        """
1869        for ctype in consoles:
1870            for port in ctype:
1871                openned = port.is_open
1872                port.clean_port()
1873                on_guest("virt.clean_port('%s'),1024" % port.name, vm, 10)
1874                if not openned:
1875                    port.close()
1876                    on_guest("virt.close('%s'),1024" % port.name, vm, 10)
1877
1878
1879    def clean_ports(vm, consoles):
1880        """
1881        Clean state of all ports and set port to default state.
1882        Default state:
1883           No data on port or in port buffer.
1884           Read mode = blocking.
1885
1886        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
1887        @param consoles: Consoles which should be clean.
1888        """
1889        # Check if python is still alive
1890        logging.info("CLEANING")
1891        match, tmp = _on_guest("is_alive()", vm, 10)
1892        if (match is None) or (match != 0):
1893            logging.error("Python died/is stucked/have remaining threads")
1894            logging.debug(tmp)
1895            try:
1896                kernel_bug = _search_kernel_crashlog(vm[0].serial_console, 10)
1897                if kernel_bug is not None:
1898                    logging.error(kernel_bug)
1899                    raise error.TestFail("Kernel crash.")
1900
1901                if vm[4] == True:
1902                    raise error.TestFail("Kernel crash.")
1903                match, tmp = _on_guest("guest_exit()", vm, 10)
1904                if (match is None) or (match == 0):
1905                    vm[1].close()
1906                    vm[1] = virt_test_utils.wait_for_login(vm[0], 0,
1907                                        float(params.get("boot_timeout", 5)),
1908                                        0, 10)
1909                on_guest("killall -9 python "
1910                         "&& echo -n PASS: python killed"
1911                         "|| echo -n PASS: python was already dead",
1912                         vm, 10)
1913
1914                init_guest(vm, consoles)
1915                _clean_ports(vm, consoles)
1916
1917            except (error.TestFail, aexpect.ExpectError,
1918                    Exception), inst:
1919                logging.error(inst)
1920                logging.error("Virtio-console driver is irreparably"
1921                              " blocked. Every comd end with sig KILL."
1922                              "Trying to reboot vm to continue testing...")
1923                try:
1924                    vm[0].destroy(gracefully = True)
1925                    (vm[0], vm[1], vm[3]) = _restore_vm()
1926                except (kvm_monitor.MonitorProtocolError):
1927                    logging.error("Qemu is blocked. Monitor no longer "
1928                                  "communicates")
1929                    vm[0].destroy(gracefully = False)
1930                    os.system("kill -9 %d" % (vm[0].get_pid()))
1931                    (vm[0], vm[1], vm[3]) = _restore_vm()
1932                init_guest(vm, consoles)
1933                cname = ""
1934                try:
1935                    cname = consoles[0][0].name
1936                except (IndexError):
1937                    cname = consoles[1][0].name
1938                match = _on_guest("virt.clean_port('%s'),1024" %
1939                                  cname, vm, 10)[0]
1940
1941                if (match is None) or (match != 0):
1942                    raise error.TestFail("Virtio-console driver is irreparably "
1943                                         "blocked. Every comd ended with sig "
1944                                         "KILL. The restart didn't help")
1945                _clean_ports(vm, consoles)
1946
1947
1948    def _reset_vm(vm, consoles, no_console=1, no_serialport=1):
1949        """
1950        Destroy and reload vm.
1951
1952        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
1953        @param consoles: Consoles which should be close and than renew.
1954        @param no_console: Number of desired virtconsoles.
1955        @param no_serialport: Number of desired virtserialports.
1956        """
1957        vm[0].destroy(gracefully=False)
1958        shutil.rmtree(vm[2])    # Remove virtio sockets tmp directory
1959        (_vm, _consoles) = _vm_create(no_console, no_serialport)
1960        consoles[:] = _consoles[:]
1961        vm[:] = _vm[:]
1962
1963
1964    def clean_reload_vm(vm, consoles, expected=False):
1965        """
1966        Reloads and boots the damaged vm
1967
1968        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
1969        @param consoles: Consoles which should be clean.
1970        """
1971        if expected:
1972            logging.info("Scheduled vm reboot")
1973        else:
1974            logging.info("SCHWARZENEGGER is CLEANING")
1975        _reset_vm(vm, consoles, len(consoles[0]), len(consoles[1]))
1976        init_guest(vm, consoles)
1977
1978
1979    def test_smoke(test, vm, consoles, params, global_params):
1980        """
1981        Virtio console smoke test.
1982
1983        Tests the basic functionalities (poll, read/write with and without
1984        connected host, etc.
1985
1986        @param test: Main test object.
1987        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
1988        @param consoles: Field of virtio ports with the minimum of 2 items.
1989        @param params: Test parameters '$console_type:$data;...'
1990        @param global_params: Params defined by tests_base.conf.
1991        """
1992        # PREPARE
1993        if (global_params.get('smoke_test') == "yes"):
1994            for param in params.split(';'):
1995                if not param:
1996                    continue
1997                headline = "test_smoke: params: %s" % (param)
1998                logging.info(headline)
1999                param = param.split(':')
2000                if len(param) > 1:
2001                    data = param[1]
2002                else:
2003                    data = "Smoke test data"
2004                param = (param[0] == 'serialport')
2005                send_pt = consoles[param][0]
2006                recv_pt = consoles[param][1]
2007                subtest.headline(headline)
2008                subtest.do_test(tcheck_zero_sym, [vm], cleanup=False)
2009                subtest.do_test(topen, [vm, send_pt], True)
2010                subtest.do_test(tclose, [vm, send_pt], True)
2011                subtest.do_test(tmulti_open, [vm, send_pt])
2012                subtest.do_test(tpolling, [vm, send_pt])
2013                subtest.do_test(tsigio, [vm, send_pt])
2014                subtest.do_test(tlseek, [vm, send_pt])
2015                subtest.do_test(trw_host_offline, [vm, send_pt])
2016                subtest.do_test(trw_host_offline_big_data, [vm, send_pt],
2017                                cleanup=False)
2018                subtest.do_test(trw_notconnect_guest,
2019                                [vm, send_pt, consoles])
2020                subtest.do_test(trw_nonblocking_mode, [vm, send_pt])
2021                subtest.do_test(trw_blocking_mode, [vm, send_pt])
2022                subtest.do_test(tbasic_loopback, [vm, send_pt, recv_pt, data],
2023                                True)
2024
2025
2026    def test_multiport(test, vm, consoles, params, global_params):
2027        """
2028        This is group of test which test virtio_console in maximal load and
2029        with multiple ports.
2030
2031        @param test: Main test object.
2032        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
2033        @param consoles: Field of virtio ports with the minimum of 2 items.
2034        @param params: Test parameters '$console_type:$data;...'
2035        @param global_params: Params defined by tests_base.conf.
2036        """
2037        subtest.headline("test_multiport:")
2038        # Test Loopback
2039        if (global_params.get('loopback_test') == "yes"):
2040            subtest.do_test(tloopback, [vm, consoles, params[0]])
2041
2042        # Test Performance
2043        if (global_params.get('perf_test') == "yes"):
2044            subtest.do_test(tperf, [vm, consoles, params[1]])
2045
2046
2047    def test_destructive(test, vm, consoles, global_params, params):
2048        """
2049        This is group of tests which might be destructive.
2050
2051        @param test: Main test object.
2052        @param vm: Target virtual machine [vm, session, tmp_dir, ser_session].
2053        @param consoles: Field of virtio ports with the minimum of 2 items.
2054        @param global_params: Params defined by tests_base.conf.
2055        @param params: Dictionary of subtest params from tests_base.conf.
2056        """
2057        subtest.headline("test_destructive:")
2058        # Uses stronger clean up function
2059        (_cleanup_func, _cleanup_args) = subtest.get_cleanup_func()
2060        subtest.set_cleanup_func(clean_reload_vm, [vm, consoles])
2061
2062        if (global_params.get('rmmod_test') == "yes"):
2063            subtest.do_test(trmmod,[vm, consoles])
2064        if (global_params.get('max_ports_test') == "yes"):
2065            subtest.do_test(tmax_serial_ports, [vm, consoles])
2066            subtest.do_test(tmax_console_ports, [vm, consoles])
2067            subtest.do_test(tmax_mix_serial_conosle_port, [vm, consoles])
2068        if (global_params.get('shutdown_test') == "yes"):
2069            subtest.do_test(tshutdown, [vm, consoles])
2070        if (global_params.get('migrate_offline_test') == "yes"):
2071            subtest.do_test(tmigrate_offline,
2072                            [vm, consoles, params['tmigrate_offline_params']])
2073        if (global_params.get('migrate_online_test') == "yes"):
2074            subtest.do_test(tmigrate_online,
2075                            [vm, consoles, params['tmigrate_online_params']])
2076        if (global_params.get('hotplug_serial_test') == "yes"):
2077            subtest.do_test(thotplug, [vm, consoles])
2078            subtest.do_test(thotplug_no_timeout, [vm, consoles])
2079        if (global_params.get('hotplug_console_test') == "yes"):
2080            subtest.do_test(thotplug, [vm, consoles, "yes"])
2081            subtest.do_test(thotplug_no_timeout, [vm, consoles, "yes"])
2082        if (global_params.get('hotplug_pci_test') == "yes"):
2083            subtest.do_test(thotplug_virtio_pci, [vm, consoles])
2084
2085        subtest.set_cleanup_func(_cleanup_func, _cleanup_args)
2086
2087
2088    # INITIALIZE
2089    if "extra_params" in params:
2090        standard_extra_params = params['extra_params']
2091    else:
2092        standard_extra_params = ""
2093
2094    tsmoke_params = params.get('virtio_console_smoke', '')
2095    tloopback_params = params.get('virtio_console_loopback', '')
2096    tperf_params = params.get('virtio_console_perf', '')
2097    tmigrate_offline_params = params.get('virtio_console_migration_offline', '')
2098    tmigrate_online_params = params.get('virtio_console_migration_online', '')
2099
2100    # destructive params
2101    tdestructive_params = {}
2102    tdestructive_params['tmigrate_offline_params'] = tmigrate_offline_params
2103    tdestructive_params['tmigrate_online_params'] = tmigrate_online_params
2104
2105    no_serialports = int(params.get('virtio_console_no_serialports', 0))
2106    no_consoles = int(params.get('virtio_console_no_consoles', 0))
2107    # consoles required for Smoke test
2108    if tsmoke_params.count('serialport'):
2109        no_serialports = max(2, no_serialports)
2110    if tsmoke_params.count('console'):
2111        no_consoles = max(2, no_consoles)
2112    # consoles required for Loopback test
2113    for param in tloopback_params.split(';'):
2114        no_serialports = max(no_serialports, param.count('serialport'))
2115        no_consoles = max(no_consoles, param.count('console'))
2116    # consoles required for Performance test
2117    if tperf_params.count('serialport'):
2118        no_serialports = max(1, no_serialports)
2119    if tperf_params.count('console'):
2120        no_consoles = max(1, no_consoles)
2121    # consoles required for Migration offline test
2122    if tmigrate_offline_params.count('serial'):
2123        no_serialports = max(2, no_serialports)
2124    if tmigrate_offline_params.count('console'):
2125        no_consoles = max(2, no_consoles)
2126    if tmigrate_online_params.count('serial'):
2127        no_serialports = max(2, no_serialports)
2128    if tmigrate_online_params.count('console'):
2129        no_consoles = max(2, no_consoles)
2130
2131    if no_serialports + no_consoles == 0:
2132        raise error.TestFail("No tests defined, probably incorrect "
2133                             "configuration in tests_base.cfg")
2134
2135    vm, consoles = _vm_create(no_consoles, no_serialports)
2136
2137    # Copy virtio_console_guest.py into guests
2138    pwd = os.path.join(os.environ['AUTODIR'], 'tests/kvm')
2139    vksmd_src = os.path.join(pwd, "scripts/virtio_console_guest.py")
2140    dst_dir = "/tmp"
2141
2142    vm[0].copy_files_to(vksmd_src, dst_dir)
2143
2144    # ACTUAL TESTING
2145    # Defines all available consoles; tests udev and sysfs
2146
2147    subtest = SubTest()
2148    try:
2149        init_guest(vm, consoles)
2150
2151        subtest.set_cleanup_func(clean_ports, [vm, consoles])
2152        # Test Smoke
2153        test_smoke(subtest, vm, consoles, tsmoke_params, params)
2154
2155        # Test multiport functionality and performance.
2156        test_multiport(subtest, vm, consoles, [tloopback_params, tperf_params],
2157                       params)
2158
2159        #Test destructive test.
2160        test_destructive(subtest, vm, consoles, params, tdestructive_params)
2161    finally:
2162        logging.info(("Summary: %d tests passed  %d test failed :\n" %
2163                      (subtest.passed, subtest.failed)) +
2164                      subtest.get_text_result())
2165
2166    if subtest.is_failed():
2167        raise error.TestFail("%d out of %d virtio console tests failed" %
2168                             (subtest.failed, (subtest.passed+subtest.failed)))
2169
2170
2171    # CLEANUP
2172    vm[1].close()
2173    vm[0].destroy(gracefully=False)
2174    shutil.rmtree(vm[2])
2175