1""" 2High-level KVM test utility functions. 3 4This module is meant to reduce code size by performing common test procedures. 5Generally, code here should look like test code. 6More specifically: 7 - Functions in this module should raise exceptions if things go wrong 8 (unlike functions in kvm_utils.py and kvm_vm.py which report failure via 9 their returned values). 10 - Functions in this module may use logging.info(), in addition to 11 logging.debug() and logging.error(), to log messages the user may be 12 interested in (unlike kvm_utils.py and kvm_vm.py which use 13 logging.debug() for anything that isn't an error). 14 - Functions in this module typically use functions and classes from 15 lower-level modules (e.g. kvm_utils.py, kvm_vm.py, kvm_subprocess.py). 16 - Functions in this module should not be used by lower-level modules. 17 - Functions in this module should be used in the right context. 18 For example, a function should not be used where it may display 19 misleading or inaccurate info or debug messages. 20 21@copyright: 2008-2009 Red Hat Inc. 22""" 23 24import time, os, logging, re, signal 25from autotest_lib.client.common_lib import error 26from autotest_lib.client.bin import utils 27from autotest_lib.client.tools import scan_results 28import aexpect, virt_utils, virt_vm 29 30 31def get_living_vm(env, vm_name): 32 """ 33 Get a VM object from the environment and make sure it's alive. 34 35 @param env: Dictionary with test environment. 36 @param vm_name: Name of the desired VM object. 37 @return: A VM object. 38 """ 39 vm = env.get_vm(vm_name) 40 if not vm: 41 raise error.TestError("VM '%s' not found in environment" % vm_name) 42 if not vm.is_alive(): 43 raise error.TestError("VM '%s' seems to be dead; test requires a " 44 "living VM" % vm_name) 45 return vm 46 47 48def wait_for_login(vm, nic_index=0, timeout=240, start=0, step=2, serial=None): 49 """ 50 Try logging into a VM repeatedly. Stop on success or when timeout expires. 51 52 @param vm: VM object. 53 @param nic_index: Index of NIC to access in the VM. 54 @param timeout: Time to wait before giving up. 55 @param serial: Whether to use a serial connection instead of a remote 56 (ssh, rss) one. 57 @return: A shell session object. 58 """ 59 end_time = time.time() + timeout 60 session = None 61 if serial: 62 type = 'serial' 63 logging.info("Trying to log into guest %s using serial connection," 64 " timeout %ds", vm.name, timeout) 65 time.sleep(start) 66 while time.time() < end_time: 67 try: 68 session = vm.serial_login() 69 break 70 except virt_utils.LoginError, e: 71 logging.debug(e) 72 time.sleep(step) 73 else: 74 type = 'remote' 75 logging.info("Trying to log into guest %s using remote connection," 76 " timeout %ds", vm.name, timeout) 77 time.sleep(start) 78 while time.time() < end_time: 79 try: 80 session = vm.login(nic_index=nic_index) 81 break 82 except (virt_utils.LoginError, virt_vm.VMError), e: 83 logging.debug(e) 84 time.sleep(step) 85 if not session: 86 raise error.TestFail("Could not log into guest %s using %s connection" % 87 (vm.name, type)) 88 logging.info("Logged into guest %s using %s connection", vm.name, type) 89 return session 90 91 92def reboot(vm, session, method="shell", sleep_before_reset=10, nic_index=0, 93 timeout=240): 94 """ 95 Reboot the VM and wait for it to come back up by trying to log in until 96 timeout expires. 97 98 @param vm: VM object. 99 @param session: A shell session object. 100 @param method: Reboot method. Can be "shell" (send a shell reboot 101 command) or "system_reset" (send a system_reset monitor command). 102 @param nic_index: Index of NIC to access in the VM, when logging in after 103 rebooting. 104 @param timeout: Time to wait before giving up (after rebooting). 105 @return: A new shell session object. 106 """ 107 if method == "shell": 108 # Send a reboot command to the guest's shell 109 session.sendline(vm.get_params().get("reboot_command")) 110 logging.info("Reboot command sent. Waiting for guest to go down") 111 elif method == "system_reset": 112 # Sleep for a while before sending the command 113 time.sleep(sleep_before_reset) 114 # Clear the event list of all QMP monitors 115 monitors = [m for m in vm.monitors if m.protocol == "qmp"] 116 for m in monitors: 117 m.clear_events() 118 # Send a system_reset monitor command 119 vm.monitor.cmd("system_reset") 120 logging.info("Monitor command system_reset sent. Waiting for guest to " 121 "go down") 122 # Look for RESET QMP events 123 time.sleep(1) 124 for m in monitors: 125 if not m.get_event("RESET"): 126 raise error.TestFail("RESET QMP event not received after " 127 "system_reset (monitor '%s')" % m.name) 128 else: 129 logging.info("RESET QMP event received") 130 else: 131 logging.error("Unknown reboot method: %s", method) 132 133 # Wait for the session to become unresponsive and close it 134 if not virt_utils.wait_for(lambda: not session.is_responsive(timeout=30), 135 120, 0, 1): 136 raise error.TestFail("Guest refuses to go down") 137 session.close() 138 139 # Try logging into the guest until timeout expires 140 logging.info("Guest is down. Waiting for it to go up again, timeout %ds", 141 timeout) 142 session = vm.wait_for_login(nic_index, timeout=timeout) 143 logging.info("Guest is up again") 144 return session 145 146 147def migrate(vm, env=None, mig_timeout=3600, mig_protocol="tcp", 148 mig_cancel=False, offline=False, stable_check=False, 149 clean=False, save_path=None, dest_host='localhost', mig_port=None): 150 """ 151 Migrate a VM locally and re-register it in the environment. 152 153 @param vm: The VM to migrate. 154 @param env: The environment dictionary. If omitted, the migrated VM will 155 not be registered. 156 @param mig_timeout: timeout value for migration. 157 @param mig_protocol: migration protocol 158 @param mig_cancel: Test migrate_cancel or not when protocol is tcp. 159 @param dest_host: Destination host (defaults to 'localhost'). 160 @param mig_port: Port that will be used for migration. 161 @return: The post-migration VM, in case of same host migration, True in 162 case of multi-host migration. 163 """ 164 def mig_finished(): 165 o = vm.monitor.info("migrate") 166 if isinstance(o, str): 167 return "status: active" not in o 168 else: 169 return o.get("status") != "active" 170 171 def mig_succeeded(): 172 o = vm.monitor.info("migrate") 173 if isinstance(o, str): 174 return "status: completed" in o 175 else: 176 return o.get("status") == "completed" 177 178 def mig_failed(): 179 o = vm.monitor.info("migrate") 180 if isinstance(o, str): 181 return "status: failed" in o 182 else: 183 return o.get("status") == "failed" 184 185 def mig_cancelled(): 186 o = vm.monitor.info("migrate") 187 if isinstance(o, str): 188 return ("Migration status: cancelled" in o or 189 "Migration status: canceled" in o) 190 else: 191 return (o.get("status") == "cancelled" or 192 o.get("status") == "canceled") 193 194 def wait_for_migration(): 195 if not virt_utils.wait_for(mig_finished, mig_timeout, 2, 2, 196 "Waiting for migration to finish"): 197 raise error.TestFail("Timeout expired while waiting for migration " 198 "to finish") 199 200 if dest_host == 'localhost': 201 dest_vm = vm.clone() 202 203 if (dest_host == 'localhost') and stable_check: 204 # Pause the dest vm after creation 205 dest_vm.params['extra_params'] = (dest_vm.params.get('extra_params','') 206 + ' -S') 207 208 if dest_host == 'localhost': 209 dest_vm.create(migration_mode=mig_protocol, mac_source=vm) 210 211 try: 212 try: 213 if mig_protocol == "tcp": 214 if dest_host == 'localhost': 215 uri = "tcp:localhost:%d" % dest_vm.migration_port 216 else: 217 uri = 'tcp:%s:%d' % (dest_host, mig_port) 218 elif mig_protocol == "unix": 219 uri = "unix:%s" % dest_vm.migration_file 220 elif mig_protocol == "exec": 221 uri = '"exec:nc localhost %s"' % dest_vm.migration_port 222 223 if offline: 224 vm.monitor.cmd("stop") 225 vm.monitor.migrate(uri) 226 227 if mig_cancel: 228 time.sleep(2) 229 vm.monitor.cmd("migrate_cancel") 230 if not virt_utils.wait_for(mig_cancelled, 60, 2, 2, 231 "Waiting for migration " 232 "cancellation"): 233 raise error.TestFail("Failed to cancel migration") 234 if offline: 235 vm.monitor.cmd("cont") 236 if dest_host == 'localhost': 237 dest_vm.destroy(gracefully=False) 238 return vm 239 else: 240 wait_for_migration() 241 if (dest_host == 'localhost') and stable_check: 242 save_path = None or "/tmp" 243 save1 = os.path.join(save_path, "src") 244 save2 = os.path.join(save_path, "dst") 245 246 vm.save_to_file(save1) 247 dest_vm.save_to_file(save2) 248 249 # Fail if we see deltas 250 md5_save1 = utils.hash_file(save1) 251 md5_save2 = utils.hash_file(save2) 252 if md5_save1 != md5_save2: 253 raise error.TestFail("Mismatch of VM state before " 254 "and after migration") 255 256 if (dest_host == 'localhost') and offline: 257 dest_vm.monitor.cmd("cont") 258 except: 259 if dest_host == 'localhost': 260 dest_vm.destroy() 261 raise 262 263 finally: 264 if (dest_host == 'localhost') and stable_check and clean: 265 logging.debug("Cleaning the state files") 266 if os.path.isfile(save1): 267 os.remove(save1) 268 if os.path.isfile(save2): 269 os.remove(save2) 270 271 # Report migration status 272 if mig_succeeded(): 273 logging.info("Migration finished successfully") 274 elif mig_failed(): 275 raise error.TestFail("Migration failed") 276 else: 277 raise error.TestFail("Migration ended with unknown status") 278 279 if dest_host == 'localhost': 280 if "paused" in dest_vm.monitor.info("status"): 281 logging.debug("Destination VM is paused, resuming it") 282 dest_vm.monitor.cmd("cont") 283 284 # Kill the source VM 285 vm.destroy(gracefully=False) 286 287 # Replace the source VM with the new cloned VM 288 if (dest_host == 'localhost') and (env is not None): 289 env.register_vm(vm.name, dest_vm) 290 291 # Return the new cloned VM 292 if dest_host == 'localhost': 293 return dest_vm 294 else: 295 return vm 296 297 298def stop_windows_service(session, service, timeout=120): 299 """ 300 Stop a Windows service using sc. 301 If the service is already stopped or is not installed, do nothing. 302 303 @param service: The name of the service 304 @param timeout: Time duration to wait for service to stop 305 @raise error.TestError: Raised if the service can't be stopped 306 """ 307 end_time = time.time() + timeout 308 while time.time() < end_time: 309 o = session.cmd_output("sc stop %s" % service, timeout=60) 310 # FAILED 1060 means the service isn't installed. 311 # FAILED 1062 means the service hasn't been started. 312 if re.search(r"\bFAILED (1060|1062)\b", o, re.I): 313 break 314 time.sleep(1) 315 else: 316 raise error.TestError("Could not stop service '%s'" % service) 317 318 319def start_windows_service(session, service, timeout=120): 320 """ 321 Start a Windows service using sc. 322 If the service is already running, do nothing. 323 If the service isn't installed, fail. 324 325 @param service: The name of the service 326 @param timeout: Time duration to wait for service to start 327 @raise error.TestError: Raised if the service can't be started 328 """ 329 end_time = time.time() + timeout 330 while time.time() < end_time: 331 o = session.cmd_output("sc start %s" % service, timeout=60) 332 # FAILED 1060 means the service isn't installed. 333 if re.search(r"\bFAILED 1060\b", o, re.I): 334 raise error.TestError("Could not start service '%s' " 335 "(service not installed)" % service) 336 # FAILED 1056 means the service is already running. 337 if re.search(r"\bFAILED 1056\b", o, re.I): 338 break 339 time.sleep(1) 340 else: 341 raise error.TestError("Could not start service '%s'" % service) 342 343 344def get_time(session, time_command, time_filter_re, time_format): 345 """ 346 Return the host time and guest time. If the guest time cannot be fetched 347 a TestError exception is raised. 348 349 Note that the shell session should be ready to receive commands 350 (i.e. should "display" a command prompt and should be done with all 351 previous commands). 352 353 @param session: A shell session. 354 @param time_command: Command to issue to get the current guest time. 355 @param time_filter_re: Regex filter to apply on the output of 356 time_command in order to get the current time. 357 @param time_format: Format string to pass to time.strptime() with the 358 result of the regex filter. 359 @return: A tuple containing the host time and guest time. 360 """ 361 if len(re.findall("ntpdate|w32tm", time_command)) == 0: 362 host_time = time.time() 363 s = session.cmd_output(time_command) 364 365 try: 366 s = re.findall(time_filter_re, s)[0] 367 except IndexError: 368 logging.debug("The time string from guest is:\n%s", s) 369 raise error.TestError("The time string from guest is unexpected.") 370 except Exception, e: 371 logging.debug("(time_filter_re, time_string): (%s, %s)", 372 time_filter_re, s) 373 raise e 374 375 guest_time = time.mktime(time.strptime(s, time_format)) 376 else: 377 o = session.cmd(time_command) 378 if re.match('ntpdate', time_command): 379 offset = re.findall('offset (.*) sec', o)[0] 380 host_main, host_mantissa = re.findall(time_filter_re, o)[0] 381 host_time = (time.mktime(time.strptime(host_main, time_format)) + 382 float("0.%s" % host_mantissa)) 383 guest_time = host_time - float(offset) 384 else: 385 guest_time = re.findall(time_filter_re, o)[0] 386 offset = re.findall("o:(.*)s", o)[0] 387 if re.match('PM', guest_time): 388 hour = re.findall('\d+ (\d+):', guest_time)[0] 389 hour = str(int(hour) + 12) 390 guest_time = re.sub('\d+\s\d+:', "\d+\s%s:" % hour, 391 guest_time)[:-3] 392 else: 393 guest_time = guest_time[:-3] 394 guest_time = time.mktime(time.strptime(guest_time, time_format)) 395 host_time = guest_time + float(offset) 396 397 return (host_time, guest_time) 398 399 400def get_memory_info(lvms): 401 """ 402 Get memory information from host and guests in format: 403 Host: memfree = XXXM; Guests memsh = {XXX,XXX,...} 404 405 @params lvms: List of VM objects 406 @return: String with memory info report 407 """ 408 if not isinstance(lvms, list): 409 raise error.TestError("Invalid list passed to get_stat: %s " % lvms) 410 411 try: 412 meminfo = "Host: memfree = " 413 meminfo += str(int(utils.freememtotal()) / 1024) + "M; " 414 meminfo += "swapfree = " 415 mf = int(utils.read_from_meminfo("SwapFree")) / 1024 416 meminfo += str(mf) + "M; " 417 except Exception, e: 418 raise error.TestFail("Could not fetch host free memory info, " 419 "reason: %s" % e) 420 421 meminfo += "Guests memsh = {" 422 for vm in lvms: 423 shm = vm.get_shared_meminfo() 424 if shm is None: 425 raise error.TestError("Could not get shared meminfo from " 426 "VM %s" % vm) 427 meminfo += "%dM; " % shm 428 meminfo = meminfo[0:-2] + "}" 429 430 return meminfo 431 432 433def run_autotest(vm, session, control_path, timeout, outputdir, params): 434 """ 435 Run an autotest control file inside a guest (linux only utility). 436 437 @param vm: VM object. 438 @param session: A shell session on the VM provided. 439 @param control_path: A path to an autotest control file. 440 @param timeout: Timeout under which the autotest control file must complete. 441 @param outputdir: Path on host where we should copy the guest autotest 442 results to. 443 444 The following params is used by the migration 445 @param params: Test params used in the migration test 446 """ 447 def copy_if_hash_differs(vm, local_path, remote_path): 448 """ 449 Copy a file to a guest if it doesn't exist or if its MD5sum differs. 450 451 @param vm: VM object. 452 @param local_path: Local path. 453 @param remote_path: Remote path. 454 455 @return: Whether the hash differs (True) or not (False). 456 """ 457 hash_differs = False 458 local_hash = utils.hash_file(local_path) 459 basename = os.path.basename(local_path) 460 output = session.cmd_output("md5sum %s" % remote_path) 461 if "such file" in output: 462 remote_hash = "0" 463 elif output: 464 remote_hash = output.split()[0] 465 else: 466 logging.warning("MD5 check for remote path %s did not return.", 467 remote_path) 468 # Let's be a little more lenient here and see if it wasn't a 469 # temporary problem 470 remote_hash = "0" 471 if remote_hash != local_hash: 472 hash_differs = True 473 logging.debug("Copying %s to guest " 474 "(remote hash: %s, local hash:%s)", 475 basename, remote_hash, local_hash) 476 vm.copy_files_to(local_path, remote_path) 477 return hash_differs 478 479 480 def extract(vm, remote_path, dest_dir): 481 """ 482 Extract the autotest .tar.bz2 file on the guest, ensuring the final 483 destination path will be dest_dir. 484 485 @param vm: VM object 486 @param remote_path: Remote file path 487 @param dest_dir: Destination dir for the contents 488 """ 489 basename = os.path.basename(remote_path) 490 logging.debug("Extracting %s on VM %s", basename, vm.name) 491 session.cmd("rm -rf %s" % dest_dir) 492 dirname = os.path.dirname(remote_path) 493 session.cmd("cd %s" % dirname) 494 session.cmd("mkdir -p %s" % os.path.dirname(dest_dir)) 495 e_cmd = "tar xjvf %s -C %s" % (basename, os.path.dirname(dest_dir)) 496 output = session.cmd(e_cmd, timeout=120) 497 autotest_dirname = "" 498 for line in output.splitlines(): 499 autotest_dirname = line.split("/")[0] 500 break 501 if autotest_dirname != os.path.basename(dest_dir): 502 session.cmd("cd %s" % os.path.dirname(dest_dir)) 503 session.cmd("mv %s %s" % 504 (autotest_dirname, os.path.basename(dest_dir))) 505 506 507 def get_results(guest_autotest_path): 508 """ 509 Copy autotest results present on the guest back to the host. 510 """ 511 logging.debug("Trying to copy autotest results from guest") 512 guest_results_dir = os.path.join(outputdir, "guest_autotest_results") 513 if not os.path.exists(guest_results_dir): 514 os.mkdir(guest_results_dir) 515 vm.copy_files_from("%s/results/default/*" % guest_autotest_path, 516 guest_results_dir) 517 518 519 def get_results_summary(guest_autotest_path): 520 """ 521 Get the status of the tests that were executed on the host and close 522 the session where autotest was being executed. 523 """ 524 session.cmd("cd %s" % guest_autotest_path) 525 output = session.cmd_output("cat results/*/status") 526 try: 527 results = scan_results.parse_results(output) 528 # Report test results 529 logging.info("Results (test, status, duration, info):") 530 for result in results: 531 logging.info(str(result)) 532 session.close() 533 return results 534 except Exception, e: 535 logging.error("Error processing guest autotest results: %s", e) 536 return None 537 538 539 if not os.path.isfile(control_path): 540 raise error.TestError("Invalid path to autotest control file: %s" % 541 control_path) 542 543 migrate_background = params.get("migrate_background") == "yes" 544 if migrate_background: 545 mig_timeout = float(params.get("mig_timeout", "3600")) 546 mig_protocol = params.get("migration_protocol", "tcp") 547 548 compressed_autotest_path = "/tmp/autotest.tar.bz2" 549 destination_autotest_path = "/usr/local/autotest" 550 551 # To avoid problems, let's make the test use the current AUTODIR 552 # (autotest client path) location 553 autotest_path = os.environ['AUTODIR'] 554 autotest_basename = os.path.basename(autotest_path) 555 autotest_parentdir = os.path.dirname(autotest_path) 556 557 # tar the contents of bindir/autotest 558 cmd = ("cd %s; tar cvjf %s %s/*" % 559 (autotest_parentdir, compressed_autotest_path, autotest_basename)) 560 # Until we have nested virtualization, we don't need the kvm test :) 561 cmd += " --exclude=%s/tests/kvm" % autotest_basename 562 cmd += " --exclude=%s/results" % autotest_basename 563 cmd += " --exclude=%s/tmp" % autotest_basename 564 cmd += " --exclude=%s/control*" % autotest_basename 565 cmd += " --exclude=*.pyc" 566 cmd += " --exclude=*.svn" 567 cmd += " --exclude=*.git" 568 utils.run(cmd) 569 570 # Copy autotest.tar.bz2 571 update = copy_if_hash_differs(vm, compressed_autotest_path, 572 compressed_autotest_path) 573 574 # Extract autotest.tar.bz2 575 if update: 576 extract(vm, compressed_autotest_path, destination_autotest_path) 577 578 vm.copy_files_to(control_path, 579 os.path.join(destination_autotest_path, 'control')) 580 581 # Run the test 582 logging.info("Running autotest control file %s on guest, timeout %ss", 583 os.path.basename(control_path), timeout) 584 session.cmd("cd %s" % destination_autotest_path) 585 try: 586 session.cmd("rm -f control.state") 587 session.cmd("rm -rf results/*") 588 except aexpect.ShellError: 589 pass 590 try: 591 bg = None 592 try: 593 logging.info("---------------- Test output ----------------") 594 if migrate_background: 595 mig_timeout = float(params.get("mig_timeout", "3600")) 596 mig_protocol = params.get("migration_protocol", "tcp") 597 598 bg = virt_utils.Thread(session.cmd_output, 599 kwargs={'cmd': "bin/autotest control", 600 'timeout': timeout, 601 'print_func': logging.info}) 602 603 bg.start() 604 605 while bg.is_alive(): 606 logging.info("Autotest job did not end, start a round of " 607 "migration") 608 vm.migrate(timeout=mig_timeout, protocol=mig_protocol) 609 else: 610 session.cmd_output("bin/autotest control", timeout=timeout, 611 print_func=logging.info) 612 finally: 613 logging.info("------------- End of test output ------------") 614 if migrate_background and bg: 615 bg.join() 616 except aexpect.ShellTimeoutError: 617 if vm.is_alive(): 618 get_results(destination_autotest_path) 619 get_results_summary(destination_autotest_path) 620 raise error.TestError("Timeout elapsed while waiting for job to " 621 "complete") 622 else: 623 raise error.TestError("Autotest job on guest failed " 624 "(VM terminated during job)") 625 except aexpect.ShellProcessTerminatedError: 626 get_results(destination_autotest_path) 627 raise error.TestError("Autotest job on guest failed " 628 "(Remote session terminated during job)") 629 630 results = get_results_summary(destination_autotest_path) 631 get_results(destination_autotest_path) 632 633 # Make a list of FAIL/ERROR/ABORT results (make sure FAIL results appear 634 # before ERROR results, and ERROR results appear before ABORT results) 635 bad_results = [r[0] for r in results if r[1] == "FAIL"] 636 bad_results += [r[0] for r in results if r[1] == "ERROR"] 637 bad_results += [r[0] for r in results if r[1] == "ABORT"] 638 639 # Fail the test if necessary 640 if not results: 641 raise error.TestFail("Autotest control file run did not produce any " 642 "recognizable results") 643 if bad_results: 644 if len(bad_results) == 1: 645 e_msg = ("Test %s failed during control file execution" % 646 bad_results[0]) 647 else: 648 e_msg = ("Tests %s failed during control file execution" % 649 " ".join(bad_results)) 650 raise error.TestFail(e_msg) 651 652 653def get_loss_ratio(output): 654 """ 655 Get the packet loss ratio from the output of ping 656. 657 @param output: Ping output. 658 """ 659 try: 660 return int(re.findall('(\d+)% packet loss', output)[0]) 661 except IndexError: 662 logging.debug(output) 663 return -1 664 665 666def raw_ping(command, timeout, session, output_func): 667 """ 668 Low-level ping command execution. 669 670 @param command: Ping command. 671 @param timeout: Timeout of the ping command. 672 @param session: Local executon hint or session to execute the ping command. 673 """ 674 if session is None: 675 process = aexpect.run_bg(command, output_func=output_func, 676 timeout=timeout) 677 678 # Send SIGINT signal to notify the timeout of running ping process, 679 # Because ping have the ability to catch the SIGINT signal so we can 680 # always get the packet loss ratio even if timeout. 681 if process.is_alive(): 682 virt_utils.kill_process_tree(process.get_pid(), signal.SIGINT) 683 684 status = process.get_status() 685 output = process.get_output() 686 687 process.close() 688 return status, output 689 else: 690 output = "" 691 try: 692 output = session.cmd_output(command, timeout=timeout, 693 print_func=output_func) 694 except aexpect.ShellTimeoutError: 695 # Send ctrl+c (SIGINT) through ssh session 696 session.send("\003") 697 try: 698 output2 = session.read_up_to_prompt(print_func=output_func) 699 output += output2 700 except aexpect.ExpectTimeoutError, e: 701 output += e.output 702 # We also need to use this session to query the return value 703 session.send("\003") 704 705 session.sendline(session.status_test_command) 706 try: 707 o2 = session.read_up_to_prompt() 708 except aexpect.ExpectError: 709 status = -1 710 else: 711 try: 712 status = int(re.findall("\d+", o2)[0]) 713 except: 714 status = -1 715 716 return status, output 717 718 719def ping(dest=None, count=None, interval=None, interface=None, 720 packetsize=None, ttl=None, hint=None, adaptive=False, 721 broadcast=False, flood=False, timeout=0, 722 output_func=logging.debug, session=None): 723 """ 724 Wrapper of ping. 725 726 @param dest: Destination address. 727 @param count: Count of icmp packet. 728 @param interval: Interval of two icmp echo request. 729 @param interface: Specified interface of the source address. 730 @param packetsize: Packet size of icmp. 731 @param ttl: IP time to live. 732 @param hint: Path mtu discovery hint. 733 @param adaptive: Adaptive ping flag. 734 @param broadcast: Broadcast ping flag. 735 @param flood: Flood ping flag. 736 @param timeout: Timeout for the ping command. 737 @param output_func: Function used to log the result of ping. 738 @param session: Local executon hint or session to execute the ping command. 739 """ 740 if dest is not None: 741 command = "ping %s " % dest 742 else: 743 command = "ping localhost " 744 if count is not None: 745 command += " -c %s" % count 746 if interval is not None: 747 command += " -i %s" % interval 748 if interface is not None: 749 command += " -I %s" % interface 750 if packetsize is not None: 751 command += " -s %s" % packetsize 752 if ttl is not None: 753 command += " -t %s" % ttl 754 if hint is not None: 755 command += " -M %s" % hint 756 if adaptive: 757 command += " -A" 758 if broadcast: 759 command += " -b" 760 if flood: 761 command += " -f -q" 762 output_func = None 763 764 return raw_ping(command, timeout, session, output_func) 765 766 767def get_linux_ifname(session, mac_address): 768 """ 769 Get the interface name through the mac address. 770 771 @param session: session to the virtual machine 772 @mac_address: the macaddress of nic 773 """ 774 775 output = session.cmd_output("ifconfig -a") 776 777 try: 778 ethname = re.findall("(\w+)\s+Link.*%s" % mac_address, output, 779 re.IGNORECASE)[0] 780 return ethname 781 except: 782 return None 783