Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(4)

Unified Diff: client/tests/kvm/kvm_test_utils.py

Issue 6246035: Merge remote branch 'cros/upstream' into master (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/autotest.git@master
Patch Set: patch Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 014f26573eaf077905ad7064480b8eaddd8fdc89..b5c4a24e642e92a0b49396f25d22f2de6533edff 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, signal
+import time, os, logging, re, 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
@@ -35,7 +35,7 @@ def get_living_vm(env, vm_name):
@param vm_name: Name of the desired VM object.
@return: A VM object.
"""
- vm = kvm_utils.env_get_vm(env, vm_name)
+ vm = env.get_vm(vm_name)
if not vm:
raise error.TestError("VM '%s' not found in environment" % vm_name)
if not vm.is_alive():
@@ -44,21 +44,47 @@ def get_living_vm(env, vm_name):
return vm
-def wait_for_login(vm, nic_index=0, timeout=240, start=0, step=2):
+def wait_for_login(vm, nic_index=0, timeout=240, start=0, step=2, serial=None):
"""
Try logging into a VM repeatedly. Stop on success or when timeout expires.
@param vm: VM object.
@param nic_index: Index of NIC to access in the VM.
@param timeout: Time to wait before giving up.
+ @param serial: Whether to use a serial connection instead of a remote
+ (ssh, rss) one.
@return: A shell session object.
"""
- logging.info("Trying to log into guest '%s', timeout %ds", vm.name, timeout)
- session = kvm_utils.wait_for(lambda: vm.remote_login(nic_index=nic_index),
- timeout, start, step)
+ end_time = time.time() + timeout
+ session = None
+ if serial:
+ type = 'serial'
+ logging.info("Trying to log into guest %s using serial connection,"
+ " timeout %ds", vm.name, timeout)
+ time.sleep(start)
+ while time.time() < end_time:
+ try:
+ session = vm.serial_login()
+ break
+ except kvm_utils.LoginError, e:
+ logging.debug(e)
+ time.sleep(step)
+ else:
+ type = 'remote'
+ logging.info("Trying to log into guest %s using remote connection,"
+ " timeout %ds", vm.name, timeout)
+ time.sleep(start)
+ while time.time() < end_time:
+ try:
+ session = vm.login(nic_index=nic_index)
+ break
+ except (kvm_utils.LoginError, kvm_vm.VMError), e:
+ logging.debug(e)
+ time.sleep(step)
if not session:
- raise error.TestFail("Could not log into guest '%s'" % vm.name)
- logging.info("Logged into guest '%s'" % vm.name)
+ raise error.TestFail("Could not log into guest %s using %s connection" %
+ (vm.name, type))
+ logging.info("Logged into guest %s using %s connection", vm.name, type)
return session
@@ -112,16 +138,14 @@ def reboot(vm, session, method="shell", sleep_before_reset=10, nic_index=0,
# Try logging into the guest until timeout expires
logging.info("Guest is down. Waiting for it to go up again, timeout %ds",
timeout)
- session = kvm_utils.wait_for(lambda: vm.remote_login(nic_index=nic_index),
- timeout, 0, 2)
- if not session:
- raise error.TestFail("Could not log into guest after reboot")
+ session = vm.wait_for_login(nic_index, timeout=timeout)
logging.info("Guest is up again")
return session
def migrate(vm, env=None, mig_timeout=3600, mig_protocol="tcp",
- mig_cancel=False):
+ mig_cancel=False, offline=False, stable_check=False,
+ clean=False, save_path=None, dest_host='localhost', mig_port=None):
"""
Migrate a VM locally and re-register it in the environment.
@@ -131,7 +155,10 @@ def migrate(vm, env=None, mig_timeout=3600, mig_protocol="tcp",
@param mig_timeout: timeout value for migration.
@param mig_protocol: migration protocol
@param mig_cancel: Test migrate_cancel or not when protocol is tcp.
- @return: The post-migration VM.
+ @param dest_host: Destination host (defaults to 'localhost').
+ @param mig_port: Port that will be used for migration.
+ @return: The post-migration VM, in case of same host migration, True in
+ case of multi-host migration.
"""
def mig_finished():
o = vm.monitor.info("migrate")
@@ -169,38 +196,31 @@ 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()
+ if dest_host == 'localhost':
+ dest_vm = vm.clone()
- 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
- 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 (dest_host == 'localhost') and stable_check:
+ # Pause the dest vm after creation
+ dest_vm.params['extra_params'] = (dest_vm.params.get('extra_params','')
+ + ' -S')
- 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")
+ if dest_host == 'localhost':
+ dest_vm.create(migration_mode=mig_protocol, mac_source=vm)
+
+ try:
try:
if mig_protocol == "tcp":
- uri = "tcp:localhost:%d" % dest_vm.migration_port
+ if dest_host == 'localhost':
+ uri = "tcp:localhost:%d" % dest_vm.migration_port
+ else:
+ uri = 'tcp:%s:%d' % (dest_host, mig_port)
elif mig_protocol == "unix":
uri = "unix:%s" % dest_vm.migration_file
+ elif mig_protocol == "exec":
+ uri = '"exec:nc localhost %s"' % dest_vm.migration_port
+
+ if offline:
+ vm.monitor.cmd("stop")
vm.monitor.migrate(uri)
if mig_cancel:
@@ -210,14 +230,43 @@ def migrate(vm, env=None, mig_timeout=3600, mig_protocol="tcp",
"Waiting for migration "
"cancellation"):
raise error.TestFail("Failed to cancel migration")
- dest_vm.destroy(gracefully=False)
+ if offline:
+ vm.monitor.cmd("cont")
+ if dest_host == 'localhost':
+ dest_vm.destroy(gracefully=False)
return vm
else:
wait_for_migration()
+ if (dest_host == 'localhost') and stable_check:
+ save_path = None or "/tmp"
+ save1 = os.path.join(save_path, "src")
+ save2 = os.path.join(save_path, "dst")
+
+ vm.save_to_file(save1)
+ dest_vm.save_to_file(save2)
+
+ # Fail if we see deltas
+ md5_save1 = utils.hash_file(save1)
+ md5_save2 = utils.hash_file(save2)
+ if md5_save1 != md5_save2:
+ raise error.TestFail("Mismatch of VM state before "
+ "and after migration")
+
+ if (dest_host == 'localhost') and offline:
+ dest_vm.monitor.cmd("cont")
except:
- dest_vm.destroy()
+ if dest_host == 'localhost':
+ dest_vm.destroy()
raise
+ finally:
+ if (dest_host == 'localhost') and stable_check and clean:
+ logging.debug("Cleaning the state files")
+ if os.path.isfile(save1):
+ os.remove(save1)
+ if os.path.isfile(save2):
+ os.remove(save2)
+
# Report migration status
if mig_succeeded():
logging.info("Migration finished successfully")
@@ -226,19 +275,23 @@ def migrate(vm, env=None, mig_timeout=3600, mig_protocol="tcp",
else:
raise error.TestFail("Migration ended with unknown status")
- if "paused" in dest_vm.monitor.info("status"):
- logging.debug("Destination VM is paused, resuming it...")
- dest_vm.monitor.cmd("cont")
+ if dest_host == 'localhost':
+ if "paused" in dest_vm.monitor.info("status"):
+ logging.debug("Destination VM is paused, resuming it...")
+ dest_vm.monitor.cmd("cont")
# 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)
+ if (dest_host == 'localhost') and (env is not None):
+ env.register_vm(vm.name, dest_vm)
# Return the new cloned VM
- return dest_vm
+ if dest_host == 'localhost':
+ return dest_vm
+ else:
+ return vm
def stop_windows_service(session, service, timeout=120):
@@ -252,7 +305,7 @@ def stop_windows_service(session, service, timeout=120):
"""
end_time = time.time() + timeout
while time.time() < end_time:
- o = session.get_command_output("sc stop %s" % service, timeout=60)
+ o = session.cmd_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):
@@ -274,7 +327,7 @@ def start_windows_service(session, service, timeout=120):
"""
end_time = time.time() + timeout
while time.time() < end_time:
- o = session.get_command_output("sc start %s" % service, timeout=60)
+ o = session.cmd_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' "
@@ -306,31 +359,26 @@ def get_time(session, time_command, time_filter_re, time_format):
"""
if len(re.findall("ntpdate|w32tm", time_command)) == 0:
host_time = time.time()
- session.sendline(time_command)
- (match, s) = session.read_up_to_prompt()
- if not match:
- raise error.TestError("Could not get guest time")
+ s = session.cmd_output(time_command)
try:
s = re.findall(time_filter_re, s)[0]
except IndexError:
- logging.debug("The time string from guest is:\n%s" % s)
+ logging.debug("The time string from guest is:\n%s", s)
raise error.TestError("The time string from guest is unexpected.")
except Exception, e:
- logging.debug("(time_filter_re, time_string): (%s, %s)" %
- (time_filter_re, s))
+ logging.debug("(time_filter_re, time_string): (%s, %s)",
+ time_filter_re, s)
raise e
guest_time = time.mktime(time.strptime(s, time_format))
else:
- s , o = session.get_command_status_output(time_command)
- if s != 0:
- raise error.TestError("Could not get guest time")
+ o = session.cmd(time_command)
if re.match('ntpdate', time_command):
- offset = re.findall('offset (.*) sec',o)[0]
+ offset = re.findall('offset (.*) sec', o)[0]
host_main, host_mantissa = re.findall(time_filter_re, o)[0]
- host_time = time.mktime(time.strptime(host_main, time_format)) \
- + float("0.%s" % host_mantissa)
+ host_time = (time.mktime(time.strptime(host_main, time_format)) +
+ float("0.%s" % host_mantissa))
guest_time = host_time + float(offset)
else:
guest_time = re.findall(time_filter_re, o)[0]
@@ -381,7 +429,7 @@ def get_memory_info(lvms):
return meminfo
-def run_autotest(vm, session, control_path, timeout, outputdir):
+def run_autotest(vm, session, control_path, timeout, outputdir, params):
"""
Run an autotest control file inside a guest (linux only utility).
@@ -391,6 +439,9 @@ def run_autotest(vm, session, control_path, timeout, outputdir):
@param timeout: Timeout under which the autotest control file must complete.
@param outputdir: Path on host where we should copy the guest autotest
results to.
+
+ The following params is used by the migration
+ @param params: Test params used in the migration test
"""
def copy_if_hash_differs(vm, local_path, remote_path):
"""
@@ -400,10 +451,9 @@ def run_autotest(vm, session, control_path, timeout, outputdir):
@param local_path: Local path.
@param remote_path: Remote path.
"""
- copy = False
local_hash = utils.hash_file(local_path)
basename = os.path.basename(local_path)
- output = session.get_command_output("md5sum %s" % remote_path)
+ output = session.cmd_output("md5sum %s" % remote_path)
if "such file" in output:
remote_hash = "0"
elif output:
@@ -414,14 +464,9 @@ def run_autotest(vm, session, control_path, timeout, outputdir):
# Let's be a little more lenient here and see if it wasn't a
# temporary problem
remote_hash = "0"
-
if remote_hash != local_hash:
logging.debug("Copying %s to guest", basename)
- copy = True
-
- if copy:
- if not vm.copy_files_to(local_path, remote_path):
- raise error.TestFail("Could not copy %s to guest" % local_path)
+ vm.copy_files_to(local_path, remote_path)
def extract(vm, remote_path, dest_dir="."):
@@ -435,10 +480,7 @@ def run_autotest(vm, session, control_path, timeout, outputdir):
basename = os.path.basename(remote_path)
logging.info("Extracting %s...", basename)
e_cmd = "tar xjvf %s -C %s" % (remote_path, dest_dir)
- s, o = session.get_command_status_output(e_cmd, timeout=120)
- if s != 0:
- logging.error("Uncompress output:\n%s", o)
- raise error.TestFail("Failed to extract %s on guest" % basename)
+ session.cmd(e_cmd, timeout=120)
def get_results():
@@ -449,9 +491,8 @@ def run_autotest(vm, session, control_path, timeout, outputdir):
guest_results_dir = os.path.join(outputdir, "guest_autotest_results")
if not os.path.exists(guest_results_dir):
os.mkdir(guest_results_dir)
- if not vm.copy_files_from("%s/results/default/*" % autotest_path,
- guest_results_dir):
- logging.error("Could not copy autotest results from guest")
+ vm.copy_files_from("%s/results/default/*" % autotest_path,
+ guest_results_dir)
def get_results_summary():
@@ -459,7 +500,7 @@ def run_autotest(vm, session, control_path, timeout, outputdir):
Get the status of the tests that were executed on the host and close
the session where autotest was being executed.
"""
- output = session.get_command_output("cat results/*/status")
+ output = session.cmd_output("cat results/*/status")
try:
results = scan_results.parse_results(output)
# Report test results
@@ -477,6 +518,11 @@ def run_autotest(vm, session, control_path, timeout, outputdir):
raise error.TestError("Invalid path to autotest control file: %s" %
control_path)
+ migrate_background = params.get("migrate_background") == "yes"
+ if migrate_background:
+ mig_timeout = float(params.get("mig_timeout", "3600"))
+ mig_protocol = params.get("migration_protocol", "tcp")
+
compressed_autotest_path = "/tmp/autotest.tar.bz2"
# To avoid problems, let's make the test use the current AUTODIR
@@ -501,33 +547,56 @@ def run_autotest(vm, session, control_path, timeout, outputdir):
# Extract autotest.tar.bz2
extract(vm, compressed_autotest_path, "/")
- if not vm.copy_files_to(control_path,
- os.path.join(autotest_path, 'control')):
- raise error.TestFail("Could not copy the test control file to guest")
+ vm.copy_files_to(control_path, os.path.join(autotest_path, 'control'))
# Run the test
logging.info("Running autotest control file %s on guest, timeout %ss",
os.path.basename(control_path), timeout)
- session.get_command_output("cd %s" % autotest_path)
- session.get_command_output("rm -f control.state")
- session.get_command_output("rm -rf results/*")
- logging.info("---------------- Test output ----------------")
- status = session.get_command_status("bin/autotest control",
- timeout=timeout,
- print_func=logging.info)
- logging.info("------------- End of test output ------------")
- if status is None:
- if not vm.is_alive():
- raise error.TestError("Autotest job on guest failed "
- "(VM terminated during job)")
- if not session.is_alive():
+ session.cmd("cd %s" % autotest_path)
+ try:
+ session.cmd("rm -f control.state")
+ session.cmd("rm -rf results/*")
+ except kvm_subprocess.ShellError:
+ pass
+ try:
+ bg = None
+ try:
+ logging.info("---------------- Test output ----------------")
+ if migrate_background:
+ mig_timeout = float(params.get("mig_timeout", "3600"))
+ mig_protocol = params.get("migration_protocol", "tcp")
+
+ bg = kvm_utils.Thread(session.cmd_output,
+ kwargs={'cmd': "bin/autotest control",
+ 'timeout': timeout,
+ 'print_func': logging.info})
+
+ bg.start()
+
+ while bg.is_alive():
+ logging.info("Tests is not ended, start a round of"
+ "migration ...")
+ vm.migrate(timeout=mig_timeout, protocol=mig_protocol)
+ else:
+ session.cmd_output("bin/autotest control", timeout=timeout,
+ print_func=logging.info)
+ finally:
+ logging.info("------------- End of test output ------------")
+ if migrate_background and bg:
+ bg.join()
+ except kvm_subprocess.ShellTimeoutError:
+ if vm.is_alive():
get_results()
+ get_results_summary()
+ raise error.TestError("Timeout elapsed while waiting for job to "
+ "complete")
+ else:
raise error.TestError("Autotest job on guest failed "
- "(Remote session terminated during job)")
+ "(VM terminated during job)")
+ except kvm_subprocess.ShellProcessTerminatedError:
get_results()
- get_results_summary()
- raise error.TestError("Timeout elapsed while waiting for job to "
- "complete")
+ raise error.TestError("Autotest job on guest failed "
+ "(Remote session terminated during job)")
results = get_results_summary()
get_results()
@@ -589,21 +658,25 @@ def raw_ping(command, timeout, session, output_func):
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:
+ output = ""
+ try:
+ output = session.cmd_output(command, timeout=timeout,
+ print_func=output_func)
+ except kvm_subprocess.ShellTimeoutError:
# 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:
+ try:
+ output2 = session.read_up_to_prompt(print_func=output_func)
+ output += output2
+ except kvm_subprocess.ExpectTimeoutError, e:
+ output += e.output
# 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:
+ try:
+ o2 = session.read_up_to_prompt()
+ except kvm_subprocess.ExpectError:
status = -1
else:
try:
@@ -670,7 +743,7 @@ def get_linux_ifname(session, mac_address):
@mac_address: the macaddress of nic
"""
- output = session.get_command_output("ifconfig -a")
+ output = session.cmd_output("ifconfig -a")
try:
ethname = re.findall("(\w+)\s+Link.*%s" % mac_address, output,

Powered by Google App Engine
This is Rietveld 408576698