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