Index: client/tests/kvm/kvm_test_utils.py |
diff --git a/client/tests/kvm/kvm_test_utils.py b/client/tests/kvm/kvm_test_utils.py |
index 5412aacd258e6ee370cb5e0dfd66c60f7c43aea6..014f26573eaf077905ad7064480b8eaddd8fdc89 100644 |
--- a/client/tests/kvm/kvm_test_utils.py |
+++ b/client/tests/kvm/kvm_test_utils.py |
@@ -21,7 +21,7 @@ More specifically: |
@copyright: 2008-2009 Red Hat Inc. |
""" |
-import time, os, logging, re, commands |
+import time, os, logging, re, commands, signal |
from autotest_lib.client.common_lib import error |
from autotest_lib.client.bin import utils |
import kvm_utils, kvm_vm, kvm_subprocess, scan_results |
@@ -157,9 +157,11 @@ def migrate(vm, env=None, mig_timeout=3600, mig_protocol="tcp", |
def mig_cancelled(): |
o = vm.monitor.info("migrate") |
if isinstance(o, str): |
- return "Migration status: cancelled" in o |
+ return ("Migration status: cancelled" in o or |
+ "Migration status: canceled" in o) |
else: |
- return o.get("status") == "cancelled" |
+ return (o.get("status") == "cancelled" or |
+ o.get("status") == "canceled") |
def wait_for_migration(): |
if not kvm_utils.wait_for(mig_finished, mig_timeout, 2, 2, |
@@ -167,79 +169,122 @@ def migrate(vm, env=None, mig_timeout=3600, mig_protocol="tcp", |
raise error.TestFail("Timeout expired while waiting for migration " |
"to finish") |
+ dest_vm = vm.clone() |
- migration_file = os.path.join("/tmp/", |
- mig_protocol + time.strftime("%Y%m%d-%H%M%S")) |
- if mig_protocol == "tcp": |
- mig_extra_params = " -incoming tcp:0:%d" |
- elif mig_protocol == "unix": |
- mig_extra_params = " -incoming unix:%s" |
- elif mig_protocol == "exec": |
+ if mig_protocol == "exec": |
# Exec is a little different from other migrate methods - first we |
# ask the monitor the migration, then the vm state is dumped to a |
# compressed file, then we start the dest vm with -incoming pointing |
# to it |
- mig_extra_params = " -incoming \"exec: gzip -c -d %s\"" % migration_file |
- uri = "\"exec:gzip -c > %s\"" % migration_file |
- vm.monitor.cmd("stop") |
- o = vm.monitor.migrate(uri) |
- wait_for_migration() |
- |
- # Clone the source VM and ask the clone to wait for incoming migration |
- dest_vm = vm.clone() |
- if not dest_vm.create(extra_params=mig_extra_params): |
- raise error.TestError("Could not create dest VM") |
- |
- try: |
- if mig_protocol == "tcp": |
- uri = "tcp:localhost:%d" % dest_vm.migration_port |
- elif mig_protocol == "unix": |
- uri = "unix:%s" % dest_vm.migration_file |
+ try: |
+ exec_file = "/tmp/exec-%s.gz" % kvm_utils.generate_random_string(8) |
+ exec_cmd = "gzip -c -d %s" % exec_file |
+ uri = '"exec:gzip -c > %s"' % exec_file |
+ vm.monitor.cmd("stop") |
+ vm.monitor.migrate(uri) |
+ wait_for_migration() |
- if mig_protocol != "exec": |
- o = vm.monitor.migrate(uri) |
+ if not dest_vm.create(migration_mode=mig_protocol, |
+ migration_exec_cmd=exec_cmd, mac_source=vm): |
+ raise error.TestError("Could not create dest VM") |
+ finally: |
+ logging.debug("Removing migration file %s", exec_file) |
+ try: |
+ os.remove(exec_file) |
+ except OSError: |
+ pass |
+ else: |
+ if not dest_vm.create(migration_mode=mig_protocol, mac_source=vm): |
+ raise error.TestError("Could not create dest VM") |
+ try: |
+ if mig_protocol == "tcp": |
+ uri = "tcp:localhost:%d" % dest_vm.migration_port |
+ elif mig_protocol == "unix": |
+ uri = "unix:%s" % dest_vm.migration_file |
+ vm.monitor.migrate(uri) |
- if mig_protocol == "tcp" and mig_cancel: |
+ if mig_cancel: |
time.sleep(2) |
- o = vm.monitor.cmd("migrate_cancel") |
+ vm.monitor.cmd("migrate_cancel") |
if not kvm_utils.wait_for(mig_cancelled, 60, 2, 2, |
- "Waiting for migration cancel"): |
- raise error.TestFail("Fail to cancel migration") |
+ "Waiting for migration " |
+ "cancellation"): |
+ raise error.TestFail("Failed to cancel migration") |
dest_vm.destroy(gracefully=False) |
return vm |
+ else: |
+ wait_for_migration() |
+ except: |
+ dest_vm.destroy() |
+ raise |
+ |
+ # Report migration status |
+ if mig_succeeded(): |
+ logging.info("Migration finished successfully") |
+ elif mig_failed(): |
+ raise error.TestFail("Migration failed") |
+ else: |
+ raise error.TestFail("Migration ended with unknown status") |
- wait_for_migration() |
+ if "paused" in dest_vm.monitor.info("status"): |
+ logging.debug("Destination VM is paused, resuming it...") |
+ dest_vm.monitor.cmd("cont") |
- # Report migration status |
- if mig_succeeded(): |
- logging.info("Migration finished successfully") |
- elif mig_failed(): |
- raise error.TestFail("Migration failed") |
- else: |
- raise error.TestFail("Migration ended with unknown status") |
+ # Kill the source VM |
+ vm.destroy(gracefully=False) |
- o = dest_vm.monitor.info("status") |
- if "paused" in o: |
- logging.debug("Destination VM is paused, resuming it...") |
- dest_vm.monitor.cmd("cont") |
+ # Replace the source VM with the new cloned VM |
+ if env is not None: |
+ kvm_utils.env_register_vm(env, vm.name, dest_vm) |
- if os.path.exists(migration_file): |
- logging.debug("Removing migration file %s", migration_file) |
- os.remove(migration_file) |
+ # Return the new cloned VM |
+ return dest_vm |
- # Kill the source VM |
- vm.destroy(gracefully=False) |
- # Replace the source VM with the new cloned VM |
- if env is not None: |
- kvm_utils.env_register_vm(env, vm.name, dest_vm) |
+def stop_windows_service(session, service, timeout=120): |
+ """ |
+ Stop a Windows service using sc. |
+ If the service is already stopped or is not installed, do nothing. |
- # Return the new cloned VM |
- return dest_vm |
+ @param service: The name of the service |
+ @param timeout: Time duration to wait for service to stop |
+ @raise error.TestError: Raised if the service can't be stopped |
+ """ |
+ end_time = time.time() + timeout |
+ while time.time() < end_time: |
+ o = session.get_command_output("sc stop %s" % service, timeout=60) |
+ # FAILED 1060 means the service isn't installed. |
+ # FAILED 1062 means the service hasn't been started. |
+ if re.search(r"\bFAILED (1060|1062)\b", o, re.I): |
+ break |
+ time.sleep(1) |
+ else: |
+ raise error.TestError("Could not stop service '%s'" % service) |
- except: |
- dest_vm.destroy() |
- raise |
+ |
+def start_windows_service(session, service, timeout=120): |
+ """ |
+ Start a Windows service using sc. |
+ If the service is already running, do nothing. |
+ If the service isn't installed, fail. |
+ |
+ @param service: The name of the service |
+ @param timeout: Time duration to wait for service to start |
+ @raise error.TestError: Raised if the service can't be started |
+ """ |
+ end_time = time.time() + timeout |
+ while time.time() < end_time: |
+ o = session.get_command_output("sc start %s" % service, timeout=60) |
+ # FAILED 1060 means the service isn't installed. |
+ if re.search(r"\bFAILED 1060\b", o, re.I): |
+ raise error.TestError("Could not start service '%s' " |
+ "(service not installed)" % service) |
+ # FAILED 1056 means the service is already running. |
+ if re.search(r"\bFAILED 1056\b", o, re.I): |
+ break |
+ time.sleep(1) |
+ else: |
+ raise error.TestError("Could not start service '%s'" % service) |
def get_time(session, time_command, time_filter_re, time_format): |
@@ -505,3 +550,131 @@ def run_autotest(vm, session, control_path, timeout, outputdir): |
e_msg = ("Tests %s failed during control file execution" % |
" ".join(bad_results)) |
raise error.TestFail(e_msg) |
+ |
+ |
+def get_loss_ratio(output): |
+ """ |
+ Get the packet loss ratio from the output of ping |
+. |
+ @param output: Ping output. |
+ """ |
+ try: |
+ return int(re.findall('(\d+)% packet loss', output)[0]) |
+ except IndexError: |
+ logging.debug(output) |
+ return -1 |
+ |
+ |
+def raw_ping(command, timeout, session, output_func): |
+ """ |
+ Low-level ping command execution. |
+ |
+ @param command: Ping command. |
+ @param timeout: Timeout of the ping command. |
+ @param session: Local executon hint or session to execute the ping command. |
+ """ |
+ if session is None: |
+ process = kvm_subprocess.run_bg(command, output_func=output_func, |
+ timeout=timeout) |
+ |
+ # Send SIGINT signal to notify the timeout of running ping process, |
+ # Because ping have the ability to catch the SIGINT signal so we can |
+ # always get the packet loss ratio even if timeout. |
+ if process.is_alive(): |
+ kvm_utils.kill_process_tree(process.get_pid(), signal.SIGINT) |
+ |
+ status = process.get_status() |
+ output = process.get_output() |
+ |
+ process.close() |
+ return status, output |
+ else: |
+ session.sendline(command) |
+ status, output = session.read_up_to_prompt(timeout=timeout, |
+ print_func=output_func) |
+ if not status: |
+ # Send ctrl+c (SIGINT) through ssh session |
+ session.send("\003") |
+ status, output2 = session.read_up_to_prompt(print_func=output_func) |
+ output += output2 |
+ if not status: |
+ # We also need to use this session to query the return value |
+ session.send("\003") |
+ |
+ session.sendline(session.status_test_command) |
+ s2, o2 = session.read_up_to_prompt() |
+ if not s2: |
+ status = -1 |
+ else: |
+ try: |
+ status = int(re.findall("\d+", o2)[0]) |
+ except: |
+ status = -1 |
+ |
+ return status, output |
+ |
+ |
+def ping(dest=None, count=None, interval=None, interface=None, |
+ packetsize=None, ttl=None, hint=None, adaptive=False, |
+ broadcast=False, flood=False, timeout=0, |
+ output_func=logging.debug, session=None): |
+ """ |
+ Wrapper of ping. |
+ |
+ @param dest: Destination address. |
+ @param count: Count of icmp packet. |
+ @param interval: Interval of two icmp echo request. |
+ @param interface: Specified interface of the source address. |
+ @param packetsize: Packet size of icmp. |
+ @param ttl: IP time to live. |
+ @param hint: Path mtu discovery hint. |
+ @param adaptive: Adaptive ping flag. |
+ @param broadcast: Broadcast ping flag. |
+ @param flood: Flood ping flag. |
+ @param timeout: Timeout for the ping command. |
+ @param output_func: Function used to log the result of ping. |
+ @param session: Local executon hint or session to execute the ping command. |
+ """ |
+ if dest is not None: |
+ command = "ping %s " % dest |
+ else: |
+ command = "ping localhost " |
+ if count is not None: |
+ command += " -c %s" % count |
+ if interval is not None: |
+ command += " -i %s" % interval |
+ if interface is not None: |
+ command += " -I %s" % interface |
+ if packetsize is not None: |
+ command += " -s %s" % packetsize |
+ if ttl is not None: |
+ command += " -t %s" % ttl |
+ if hint is not None: |
+ command += " -M %s" % hint |
+ if adaptive: |
+ command += " -A" |
+ if broadcast: |
+ command += " -b" |
+ if flood: |
+ command += " -f -q" |
+ output_func = None |
+ |
+ return raw_ping(command, timeout, session, output_func) |
+ |
+ |
+def get_linux_ifname(session, mac_address): |
+ """ |
+ Get the interface name through the mac address. |
+ |
+ @param session: session to the virtual machine |
+ @mac_address: the macaddress of nic |
+ """ |
+ |
+ output = session.get_command_output("ifconfig -a") |
+ |
+ try: |
+ ethname = re.findall("(\w+)\s+Link.*%s" % mac_address, output, |
+ re.IGNORECASE)[0] |
+ return ethname |
+ except: |
+ return None |