In order to organize better the kvm functional subtests, move them to a 'tests' subdirectory. In order to add a test, one would need to put a file 'testname.py' on 'tests', implementing a function run_testname() on that file. This way we don't have to 'register' tests on the kvm tests subdirectory, and a predictable name schema for future functional tests. I know I will have to split this into smaller patches, meanwhile this patch shows the work so far. Signed-off-by: Lucas Meneghel Rodrigues <lmr@xxxxxxxxxx> --- client/tests/kvm/control | 6 +- client/tests/kvm/kvm.py | 50 +--- client/tests/kvm/kvm_install.py | 338 ------------------------ client/tests/kvm/kvm_tests.py | 476 ---------------------------------- client/tests/kvm/stepmaker.py | 17 -- client/tests/kvm/tests/autotest.py | 165 ++++++++++++ client/tests/kvm/tests/boot.py | 50 ++++ client/tests/kvm/tests/install.py | 338 ++++++++++++++++++++++++ client/tests/kvm/tests/linux_s3.py | 56 ++++ client/tests/kvm/tests/migration.py | 79 ++++++ client/tests/kvm/tests/stepmaker.py | 22 ++ client/tests/kvm/tests/steps.py | 215 +++++++++++++++ client/tests/kvm/tests/yum_update.py | 65 +++++ 13 files changed, 1002 insertions(+), 875 deletions(-) delete mode 100755 client/tests/kvm/kvm_install.py delete mode 100644 client/tests/kvm/kvm_tests.py create mode 100644 client/tests/kvm/tests/__init__.py create mode 100644 client/tests/kvm/tests/autotest.py create mode 100644 client/tests/kvm/tests/boot.py create mode 100755 client/tests/kvm/tests/install.py create mode 100644 client/tests/kvm/tests/linux_s3.py create mode 100644 client/tests/kvm/tests/migration.py create mode 100644 client/tests/kvm/tests/stepmaker.py create mode 100644 client/tests/kvm/tests/steps.py create mode 100644 client/tests/kvm/tests/yum_update.py diff --git a/client/tests/kvm/control b/client/tests/kvm/control index c030a14..5a2b1df 100644 --- a/client/tests/kvm/control +++ b/client/tests/kvm/control @@ -88,9 +88,9 @@ link_if_not_exist(pwd, qemu_img, 'qemu-img') # Build and install kvm # --------------------- params = { - "name": "kvm_install", - "shortname": "kvm_install", - "type": "kvm_install", + "name": "install", + "shortname": "install", + "type": "install", "mode": "release", ## Install from a tarball diff --git a/client/tests/kvm/kvm.py b/client/tests/kvm/kvm.py index 9428162..c46516d 100644 --- a/client/tests/kvm/kvm.py +++ b/client/tests/kvm/kvm.py @@ -1,13 +1,7 @@ import sys, os, time, shelve, random, resource, logging, cPickle from autotest_lib.client.bin import test from autotest_lib.client.common_lib import error - - -class test_routine: - def __init__(self, module_name, routine_name): - self.module_name = module_name - self.routine_name = routine_name - self.routine = None +import kvm_utils, kvm_preprocessing def dump_env(obj, filename): @@ -41,29 +35,11 @@ class kvm(test.test): """ version = 1 def initialize(self): - # Define the test routines corresponding to different values - # of the 'type' field - self.test_routines = { - # type module name routine - "steps": test_routine("kvm_guest_wizard", "run_steps"), - "stepmaker": test_routine("stepmaker", "run_stepmaker"), - "boot": test_routine("kvm_tests", "run_boot"), - "migration": test_routine("kvm_tests", "run_migration"), - "yum_update": test_routine("kvm_tests", "run_yum_update"), - "autotest": test_routine("kvm_tests", "run_autotest"), - "kvm_install": test_routine("kvm_install", "run_kvm_install"), - "linux_s3": test_routine("kvm_tests", "run_linux_s3"), - } - - # Make it possible to import modules from the test's bindir + self.subtest_dir = os.path.join(self.bindir, 'tests') sys.path.append(self.bindir) def run_once(self, params): - import logging - import kvm_utils - import kvm_preprocessing - # Seed the random number generator random.seed() @@ -90,25 +66,17 @@ class kvm(test.test): try: # Get the test routine corresponding to the specified test type type = params.get("type") - routine_obj = self.test_routines.get(type) - # If type could not be found in self.test_routines... - if not routine_obj: - message = "Unsupported test type: %s" % type - logging.error(message) - raise error.TestError(message) - # If we don't have the test routine yet... - if not routine_obj.routine: - # Dynamically import the module - module = __import__(routine_obj.module_name) - # Get the needed routine - routine_name = "module." + routine_obj.routine_name - routine_obj.routine = eval(routine_name) - + # Load the tests directory (which was turned into a py module) + test_module = __import__("tests.%s" % type) + # Verify if we have the correspondent source file for it + module_path = os.path.join(self.subtest_dir, '%s.py' % type) + if not os.path.isfile(module_path): + raise error.TestError("No %s.py test file found" % type) # Preprocess kvm_preprocessing.preprocess(self, params, env) dump_env(env, env_filename) # Run the test function - routine_obj.routine(self, params, env) + eval("test_module.%s.run_%s(self, params, env)" % (type, type)) dump_env(env, env_filename) except Exception, e: diff --git a/client/tests/kvm/kvm_install.py b/client/tests/kvm/kvm_install.py deleted file mode 100755 index 10ed7da..0000000 --- a/client/tests/kvm/kvm_install.py +++ /dev/null @@ -1,338 +0,0 @@ -import time, os, sys, urllib, re, signal, logging, datetime -from autotest_lib.client.bin import utils, test -from autotest_lib.client.common_lib import error -import kvm_utils - - -def load_kvm_modules(module_dir): - """ - Unload previously loaded kvm modules, then load modules present on any - sub directory of module_dir. Function will walk through module_dir until - it finds the modules. - - @param module_dir: Directory where the KVM modules are located. - """ - vendor = "intel" - if os.system("grep vmx /proc/cpuinfo 1>/dev/null") != 0: - vendor = "amd" - logging.debug("Detected CPU vendor as '%s'" %(vendor)) - - logging.debug("Killing any qemu processes that might be left behind") - utils.system("pkill qemu", ignore_status=True) - - logging.info("Unloading previously loaded KVM modules") - kvm_utils.unload_module("kvm") - if utils.module_is_loaded("kvm"): - message = "Failed to remove old KVM modules" - logging.error(message) - raise error.TestError(message) - - logging.info("Loading new KVM modules...") - kvm_module_path = None - kvm_vendor_module_path = None - for folder, subdirs, files in os.walk(module_dir): - if "kvm.ko" in files: - kvm_module_path = os.path.join(folder, "kvm.ko") - kvm_vendor_module_path = os.path.join(folder, "kvm-%s.ko" % vendor) - abort = False - if not os.path.isfile(kvm_module_path): - logging.error("Could not find KVM module that was supposed to be" - " built on the source dir") - abort = True - elif not os.path.isfile(kvm_vendor_module_path): - logging.error("Could not find KVM (%s) module that was supposed to be" - " built on the source dir", vendor) - abort = True - if abort: - raise error.TestError("Could not load KVM modules.") - utils.system("/sbin/insmod %s" % kvm_module_path) - time.sleep(1) - utils.system("/sbin/insmod %s" % kvm_vendor_module_path) - - if not utils.module_is_loaded("kvm"): - message = "Failed to load the KVM modules built for the test" - logging.error(message) - raise error.TestError(message) - - -def create_symlinks(test_bindir, prefix): - """ - Create symbolic links for the appropriate qemu and qemu-img commands on - the kvm test bindir. - - @param test_bindir: KVM test bindir - @param prefix: KVM prefix path - """ - qemu_path = os.path.join(test_bindir, "qemu") - qemu_img_path = os.path.join(test_bindir, "qemu-img") - if os.path.lexists(qemu_path): - os.unlink(qemu_path) - if os.path.lexists(qemu_img_path): - os.unlink(qemu_img_path) - kvm_qemu = os.path.join(prefix, "bin", "qemu-system-x86_64") - if not os.path.isfile(kvm_qemu): - raise error.TestError('Invalid qemu path') - kvm_qemu_img = os.path.join(prefix, "bin", "qemu-img") - if not os.path.isfile(kvm_qemu_img): - raise error.TestError('Invalid qemu-img path') - os.symlink(kvm_qemu, qemu_path) - os.symlink(kvm_qemu_img, qemu_img_path) - - -class SourceDirInstaller: - """ - Class that handles building/installing KVM directly from a tarball or - a single source code dir. - """ - def __init__(self, test, params): - """ - Initializes class attributes, and retrieves KVM code. - - @param test: kvm test object - @param params: Dictionary with test arguments - """ - install_mode = params["mode"] - srcdir = params.get("srcdir") - # KVM build prefix - self.test_bindir = test.bindir - prefix = os.path.join(test.bindir, 'build') - self.prefix = os.path.abspath(prefix) - # Are we going to load modules? - load_modules = params.get('load_modules') - if not load_modules: - self.load_modules = True - elif load_modules == 'yes': - self.load_modules = True - elif load_modules == 'no': - self.load_modules = False - - if install_mode == 'localsrc': - if not srcdir: - raise error.TestError("Install from source directory specified" - "but no source directory provided on the" - "control file.") - else: - self.srcdir = srcdir - self.repo_type = kvm_utils.check_kvm_source_dir(self.srcdir) - return - else: - srcdir = test.srcdir - if not os.path.isdir(srcdir): - os.makedirs(srcdir) - - if install_mode == 'release': - release_tag = params.get("release_tag") - release_dir = params.get("release_dir") - logging.info("Installing KVM from release tarball") - if not release_tag: - release_tag = kvm_utils.get_latest_kvm_release_tag(release_dir) - tarball = os.path.join(release_dir, "kvm-%s.tar.gz" % release_tag) - logging.info("Retrieving release kvm-%s" % release_tag) - tarball = utils.unmap_url("/", tarball, "/tmp") - - elif install_mode == 'snapshot': - logging.info("Installing KVM from snapshot") - snapshot_dir = params.get("snapshot_dir") - if not snapshot_dir: - raise error.TestError("Snapshot dir not provided") - snapshot_date = params.get("snapshot_date") - if not snapshot_date: - # Take yesterday's snapshot - d = (datetime.date.today() - - datetime.timedelta(1)).strftime("%Y%m%d") - else: - d = snapshot_date - tarball = os.path.join(snapshot_dir, "kvm-snapshot-%s.tar.gz" % d) - logging.info("Retrieving kvm-snapshot-%s" % d) - tarball = utils.unmap_url("/", tarball, "/tmp") - - elif install_mode == 'localtar': - tarball = params.get("tarball") - if not tarball: - raise error.TestError("KVM Tarball install specified but no" - " tarball provided on control file.") - logging.info("Installing KVM from a local tarball") - logging.info("Using tarball %s") - tarball = utils.unmap_url("/", params.get("tarball"), "/tmp") - - os.chdir(srcdir) - self.srcdir = os.path.join(srcdir, utils.extract_tarball(tarball)) - self.repo_type = kvm_utils.check_kvm_source_dir(self.srcdir) - - - def __build(self): - os.chdir(self.srcdir) - cfg = "./configure --prefix=%s" % self.prefix - if self.repo_type == 1: - steps = [cfg, "make clean", "make -j %s" % utils.count_cpus()] - if not os.path.exists('qemu/pc-bios/bios.bin'): - steps.append("make -C bios") - steps.append("make -C extboot") - steps.append("cp -f bios/BIOS-bochs-latest" - " qemu/pc-bios/bios.bin") - steps.append("cp -f vgabios/VGABIOS-lgpl-latest.bin" - " qemu/pc-bios/vgabios.bin") - steps.append("cp -f vgabios/VGABIOS-lgpl-latest.cirrus.bin" - " qemu/pc-bios/vgabios-cirrus.bin") - steps.append("cp -f extboot/extboot.bin" - " qemu/pc-bios/extboot.bin") - elif self.repo_type == 2: - steps = [cfg, "make clean", "make -j %s" % utils.count_cpus()] - - logging.info("Building KVM") - for step in steps: - utils.system(step) - - - def __install(self): - os.chdir(self.srcdir) - logging.info("Installing KVM userspace") - if self.repo_type == 1: - utils.system("make -C qemu install") - elif self.repo_type == 2: - utils.system("make install") - create_symlinks(self.test_bindir, self.prefix) - - - def __load_modules(self): - load_kvm_modules(self.srcdir) - - - def install(self): - self.__build() - self.__install() - if self.load_modules: - self.__load_modules() - - -class GitInstaller: - def __init__(self, test, params): - """ - Initialize class parameters and retrieves code from git repositories. - - @param test: kvm test object. - @param params: Dictionary with test parameters. - """ - install_mode = params["mode"] - srcdir = params.get("srcdir", test.bindir) - if not srcdir: - os.makedirs(srcdir) - self.srcdir = srcdir - # KVM build prefix - self.test_bindir = test.bindir - prefix = os.path.join(test.bindir, 'build') - self.prefix = os.path.abspath(prefix) - # Are we going to load modules? - load_modules = params.get('load_modules') - if not load_modules: - self.load_modules = True - elif load_modules == 'yes': - self.load_modules = True - elif load_modules == 'no': - self.load_modules = False - - kernel_repo = params.get("git_repo") - user_repo = params.get("user_git_repo") - kmod_repo = params.get("kmod_repo") - - branch = params.get("git_branch", "master") - lbranch = params.get("lbranch") - - tag = params.get("git_tag", "HEAD") - user_tag = params.get("user_git_tag", "HEAD") - kmod_tag = params.get("kmod_git_tag", "HEAD") - - if not kernel_repo: - message = "KVM git repository path not specified" - logging.error(message) - raise error.TestError(message) - if not user_repo: - message = "KVM user git repository path not specified" - logging.error(message) - raise error.TestError(message) - - kernel_srcdir = os.path.join(srcdir, "kvm") - kvm_utils.get_git_branch(kernel_repo, branch, kernel_srcdir, tag, - lbranch) - self.kernel_srcdir = kernel_srcdir - - userspace_srcdir = os.path.join(srcdir, "kvm_userspace") - kvm_utils.get_git_branch(user_repo, branch, userspace_srcdir, user_tag, - lbranch) - self.userspace_srcdir = userspace_srcdir - - if kmod_repo: - kmod_srcdir = os.path.join (srcdir, "kvm_kmod") - kvm_utils.get_git_branch(kmod_repo, branch, kmod_srcdir, user_tag, - lbranch) - self.kmod_srcdir = kmod_srcdir - - - def __build(self): - if self.kmod_srcdir: - logging.info('Building KVM modules') - os.chdir(self.kmod_srcdir) - utils.system('./configure') - utils.system('make clean') - utils.system('make sync LINUX=%s' % self.kernel_srcdir) - utils.system('make -j %s' % utils.count_cpus()) - logging.info('Building KVM userspace code') - os.chdir(self.userspace_srcdir) - utils.system('./configure --prefix=%s' % self.prefix) - utils.system('make clean') - utils.system('make -j %s' % utils.count_cpus()) - else: - os.chdir(self.userspace_srcdir) - utils.system('./configure --prefix=%s' % self.prefix) - logging.info('Building KVM modules') - utils.system('make clean') - utils.system('make -C kernel LINUX=%s sync' % self.kernel_srcdir) - logging.info('Building KVM userspace code') - utils.system('make -j %s' % utils.count_cpus()) - - - def __install(self): - os.chdir(self.userspace_srcdir) - utils.system('make install') - create_symlinks(self.test_bindir, self.prefix) - - - def __load_modules(self): - if self.kmod_srcdir: - load_kvm_modules(self.kmod_srcdir) - else: - load_kvm_modules(self.userspace_srcdir) - - - def install(self): - self.__build() - self.__install() - if self.load_modules: - self.__load_modules() - - -def run_kvm_install(test, params, env): - """ - Installs KVM using the selected install mode. Most install methods will - take kvm source code, build it and install it to a given location. - - @param test: kvm test object. - @param params: Dictionary with test parameters. - @param env: Test environment. - """ - install_mode = params.get("mode") - srcdir = params.get("srcdir", test.srcdir) - params["srcdir"] = srcdir - - if install_mode == 'noinstall': - logging.info("Skipping installation") - return - elif install_mode in ['localsrc', 'localtar', 'release', 'snapshot']: - installer = SourceDirInstaller(test, params) - elif install_mode == 'git': - installer = GitInstaller(test, params) - else: - raise error.TestError('Invalid or unsupported' - ' install mode: %s' % install_mode) - - installer.install() diff --git a/client/tests/kvm/kvm_tests.py b/client/tests/kvm/kvm_tests.py deleted file mode 100644 index 4270cae..0000000 --- a/client/tests/kvm/kvm_tests.py +++ /dev/null @@ -1,476 +0,0 @@ -import time, os, logging -from autotest_lib.client.common_lib import utils, error -import kvm_utils, ppm_utils, scan_results - -""" -KVM test definitions. - -@copyright: 2008-2009 Red Hat Inc. -""" - - -def run_boot(test, params, env): - """ - KVM reboot test: - 1) Log into a guest - 2) Send a reboot command to the guest - 3) Wait until it's up. - 4) Log into the guest to verify it's up again. - - @param test: kvm test object - @param params: Dictionary with the test parameters - @param env: Dictionary with test environment. - """ - vm = kvm_utils.env_get_vm(env, params.get("main_vm")) - if not vm: - raise error.TestError("VM object not found in environment") - if not vm.is_alive(): - raise error.TestError("VM seems to be dead; Test requires a living VM") - - logging.info("Waiting for guest to be up...") - - session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2) - if not session: - raise error.TestFail("Could not log into guest") - - logging.info("Logged in") - - if params.get("reboot") == "yes": - # Send the VM's reboot command - session.sendline(vm.get_params().get("cmd_reboot")) - logging.info("Reboot command sent; waiting for guest to go down...") - - if not kvm_utils.wait_for(lambda: not session.is_responsive(), - 120, 0, 1): - raise error.TestFail("Guest refuses to go down") - - session.close() - - logging.info("Guest is down; waiting for it to go up again...") - - session = kvm_utils.wait_for(vm.ssh_login, 120, 0, 2) - if not session: - raise error.TestFail("Could not log into guest after reboot") - - logging.info("Guest is up again") - - session.close() - - -def run_migration(test, params, env): - """ - KVM migration test: - - 1) Get two live VMs. One will be the 'source', the other will be the - 'destination'. - 2) Verify if the source VM supports migration. If it does, proceed with - the test - 3) Send a migration command to the source vm and wait until it's finished. - 4) Kill off the source vm - 3) Log into the destination vm after the migration is finished. - 4) Compare the output of a reference command executed on the source with - the output of the same command on the destination machine - - @param test: kvm test object. - @param params: Dictionary with test parameters. - @param env: Dictionary with the test environment. - """ - src_vm_name = params.get("migration_src") - vm = kvm_utils.env_get_vm(env, src_vm_name) - if not vm: - raise error.TestError("VM '%s' not found in environment" % src_vm_name) - if not vm.is_alive(): - raise error.TestError("VM '%s' seems to be dead; Test requires a" - " living VM" % src_vm_name) - - dest_vm_name = params.get("migration_dst") - dest_vm = kvm_utils.env_get_vm(env, dest_vm_name) - if not dest_vm: - raise error.TestError("VM '%s' not found in environment" % dest_vm_name) - if not dest_vm.is_alive(): - raise error.TestError("VM '%s' seems to be dead; Test requires a" - " living VM" % dest_vm_name) - - pre_scrdump_filename = os.path.join(test.debugdir, "migration_pre.ppm") - post_scrdump_filename = os.path.join(test.debugdir, "migration_post.ppm") - - # See if migration is supported - s, o = vm.send_monitor_cmd("help info") - if not "info migrate" in o: - raise error.TestError("Migration is not supported") - - # Log into guest and get the output of migration_test_command - logging.info("Waiting for guest to be up...") - - session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2) - if not session: - raise error.TestFail("Could not log into guest") - - logging.info("Logged in") - - reference_output = session.get_command_output(params.get("migration_test_" - "command")) - session.close() - - # Define the migration command - cmd = "migrate -d tcp:localhost:%d" % dest_vm.migration_port - logging.debug("Migration command: %s" % cmd) - - # Migrate - s, o = vm.send_monitor_cmd(cmd) - if s: - logging.error("Migration command failed (command: %r, output: %r)" % - (cmd, o)) - raise error.TestFail("Migration command failed") - - # Define some helper functions - def mig_finished(): - s, o = vm.send_monitor_cmd("info migrate") - if s: - return False - if "Migration status: active" in o: - return False - return True - - def mig_succeeded(): - s, o = vm.send_monitor_cmd("info migrate") - if s == 0 and "Migration status: completed" in o: - return True - return False - - def mig_failed(): - s, o = vm.send_monitor_cmd("info migrate") - if s == 0 and "Migration status: failed" in o: - return True - return False - - # Wait for migration to finish - if not kvm_utils.wait_for(mig_finished, 90, 2, 2, - "Waiting for migration to finish..."): - raise error.TestFail("Timeout elapsed while waiting for migration to" - "finish") - - # Report migration status - if mig_succeeded(): - logging.info("Migration finished successfully") - else: - if mig_failed(): - message = "Migration failed" - else: - message = "Migration ended with unknown status" - raise error.TestFail(message) - - # Get 'post' screendump - dest_vm.send_monitor_cmd("screendump %s" % post_scrdump_filename) - - # Get 'pre' screendump - vm.send_monitor_cmd("screendump %s" % pre_scrdump_filename) - - # Kill the source VM - vm.send_monitor_cmd("quit", block=False) - - # Hack: it seems that the first attempt to communicate with the SSH port - # following migration always fails (or succeeds after a very long time). - # So just connect to the port once so the following call to ssh_login - # succeeds. - dest_vm.is_sshd_running(timeout=0.0) - - # Log into guest and get the output of migration_test_command - logging.info("Logging into guest after migration...") - - session = dest_vm.ssh_login() - if not session: - raise error.TestFail("Could not log into guest after migration") - - logging.info("Logged in after migration") - - output = session.get_command_output(params.get("migration_test_command")) - session.close() - - # Compare output to reference output - if output != reference_output: - logging.info("Command output before migration differs from command" - " output after migration") - logging.info("Command: %s" % params.get("migration_test_command")) - logging.info("Output before:" + - kvm_utils.format_str_for_message(reference_output)) - logging.info("Output after:" + kvm_utils.format_str_for_message(output)) - raise error.TestFail("Command produced different output before and" - " after migration") - - -def run_autotest(test, params, env): - """ - Run an autotest test inside a guest. - - @param test: kvm test object. - @param params: Dictionary with test parameters. - @param env: Dictionary with the test environment. - """ - vm = kvm_utils.env_get_vm(env, params.get("main_vm")) - if not vm: - raise error.TestError("VM object not found in environment") - if not vm.is_alive(): - raise error.TestError("VM seems to be dead; Test requires a living VM") - - logging.info("Logging into guest...") - - session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2) - if not session: - raise error.TestFail("Could not log into guest") - - logging.info("Logged in") - - # Collect some info - test_name = params.get("test_name") - test_timeout = int(params.get("test_timeout", 300)) - test_control_file = params.get("test_control_file", "control") - tarred_autotest_path = "/tmp/autotest.tar.bz2" - tarred_test_path = "/tmp/%s.tar.bz2" % test_name - - # tar the contents of bindir/autotest - cmd = "cd %s; tar cvjf %s autotest/*" - cmd += " --exclude=autotest/tests" - cmd += " --exclude=autotest/results" - cmd += " --exclude=autotest/tmp" - cmd += " --exclude=autotest/control" - cmd += " --exclude=*.pyc" - cmd += " --exclude=*.svn" - cmd += " --exclude=*.git" - kvm_utils.run_bg(cmd % (test.bindir, tarred_autotest_path), timeout=30) - - # tar the contents of bindir/autotest/tests/<test_name> - cmd = "cd %s; tar cvjf %s %s/*" - cmd += " --exclude=*.pyc" - cmd += " --exclude=*.svn" - cmd += " --exclude=*.git" - kvm_utils.run_bg(cmd % (os.path.join(test.bindir, "autotest", "tests"), - tarred_test_path, test_name), timeout=30) - - # Check if we need to copy autotest.tar.bz2 - copy = False - output = session.get_command_output("ls -l autotest.tar.bz2") - if "such file" in output: - copy = True - else: - size = int(output.split()[4]) - if size != os.path.getsize(tarred_autotest_path): - copy = True - # Perform the copy - if copy: - logging.info("Copying autotest.tar.bz2 to guest" - " (file is missing or has a different size)...") - if not vm.scp_to_remote(tarred_autotest_path, ""): - raise error.TestFail("Could not copy autotest.tar.bz2 to guest") - - # Check if we need to copy <test_name>.tar.bz2 - copy = False - output = session.get_command_output("ls -l %s.tar.bz2" % test_name) - if "such file" in output: - copy = True - else: - size = int(output.split()[4]) - if size != os.path.getsize(tarred_test_path): - copy = True - # Perform the copy - if copy: - logging.info("Copying %s.tar.bz2 to guest (file is missing or has a" - " different size)..." % test_name) - if not vm.scp_to_remote(tarred_test_path, ""): - raise error.TestFail("Could not copy %s.tar.bz2 to guest" % - test_name) - - # Extract autotest.tar.bz2 - logging.info("Extracting autotest.tar.bz2...") - status = session.get_command_status("tar xvfj autotest.tar.bz2") - if status != 0: - raise error.TestFail("Could not extract autotest.tar.bz2") - - # mkdir autotest/tests - session.sendline("mkdir autotest/tests") - - # Extract <test_name>.tar.bz2 into autotest/tests - logging.info("Extracting %s.tar.bz2..." % test_name) - status = session.get_command_status("tar xvfj %s.tar.bz2 -C " - "autotest/tests" % test_name) - if status != 0: - raise error.TestFail("Could not extract %s.tar.bz2" % test_name) - - # Cleaning up old remaining results - session.sendline("rm -rf autotest/results/*") - # Copying the selected control file (located inside - # test.bindir/autotest_control to the autotest dir - control_file_path = os.path.join(test.bindir, "autotest_control", - test_control_file) - if not vm.scp_to_remote(control_file_path, "autotest/control"): - raise error.TestFail("Could not copy the test control file to guest") - # Run the test - logging.info("Running test '%s'..." % test_name) - session.sendline("cd autotest") - session.sendline("rm -f control.state") - session.read_up_to_prompt() - session.sendline("bin/autotest control") - logging.info("---------------- Test output ----------------") - match = session.read_up_to_prompt(timeout=test_timeout, - print_func=logging.info)[0] - logging.info("---------------- End of test output ----------------") - if not match: - raise error.TestFail("Timeout elapsed while waiting for test to " - "complete") - # Get the results generated by autotest - output = session.get_command_output("cat results/*/status") - - # Parse test results - result_list = scan_results.parse_results(output) - - # Report test results and check for FAIL/ERROR status - logging.info("Results (test, status, duration, info):") - status_error = False - status_fail = False - if result_list == []: - status_fail = True - message_fail = ("Test '%s' did not produce any recognizable " - "results" % test_name) - for result in result_list: - logging.info(str(result)) - if result[1] == "FAIL": - status_fail = True - message_fail = ("Test '%s' ended with FAIL " - "(info: '%s')" % (result[0], result[3])) - if result[1] == "ERROR": - status_error = True - message_error = ("Test '%s' ended with ERROR " - "(info: '%s')" % (result[0], result[3])) - if result[1] == "ABORT": - status_error = True - message_error = ("Test '%s' ended with ABORT " - "(info: '%s')" % (result[0], result[3])) - - # Copy test results to the local bindir/guest_results - logging.info("Copying results back from guest...") - guest_results_dir = os.path.join(test.outputdir, "guest_results") - if not os.path.exists(guest_results_dir): - os.mkdir(guest_results_dir) - if not vm.scp_from_remote("autotest/results/default/*", guest_results_dir): - logging.error("Could not copy results back from guest") - - # Fail the test if necessary - if status_fail: - raise error.TestFail(message_fail) - elif status_error: - raise error.TestError(message_error) - - -def internal_yum_update(session, command, prompt, timeout): - """ - Helper function to perform the yum update test. - - @param session: SSH session stablished to the host - @param command: Command to be sent to the SSH connection - @param prompt: Machine prompt - @param timeout: How long to wait until we get an appropriate output from - the SSH session. - """ - session.sendline(command) - end_time = time.time() + timeout - while time.time() < end_time: - (match, text) = session.read_until_last_line_matches( - ["[Ii]s this [Oo][Kk]", prompt], timeout=timeout) - if match == 0: - logging.info("Got 'Is this ok'; sending 'y'") - session.sendline("y") - elif match == 1: - logging.info("Got shell prompt") - return True - else: - logging.info("Timeout or process exited") - return False - - -def run_yum_update(test, params, env): - """ - Runs yum update and yum update kernel on the remote host (yum enabled - hosts only). - - @param test: kvm test object. - @param params: Dictionary with test parameters. - @param env: Dictionary with the test environment. - """ - vm = kvm_utils.env_get_vm(env, params.get("main_vm")) - if not vm: - message = "VM object not found in environment" - logging.error(message) - raise error.TestError(message) - if not vm.is_alive(): - message = "VM seems to be dead; Test requires a living VM" - logging.error(message) - raise error.TestError(message) - - logging.info("Logging into guest...") - - session = kvm_utils.wait_for(vm.ssh_login, 120, 0, 2) - if not session: - message = "Could not log into guest" - logging.error(message) - raise error.TestFail(message) - - logging.info("Logged in") - - internal_yum_update(session, "yum update", params.get("ssh_prompt"), 600) - internal_yum_update(session, "yum update kernel", - params.get("ssh_prompt"), 600) - - session.close() - - -def run_linux_s3(test, params, env): - """ - Suspend a guest Linux OS to memory. - - @param test: kvm test object. - @param params: Dictionary with test parameters. - @param env: Dictionary with the test environment. - """ - vm = kvm_utils.env_get_vm(env, params.get("main_vm")) - if not vm: - raise error.TestError("VM object not found in environment") - if not vm.is_alive(): - raise error.TestError("VM seems to be dead; Test requires a living VM") - - logging.info("Waiting for guest to be up...") - - session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2) - if not session: - raise error.TestFail("Could not log into guest") - - logging.info("Logged in") - logging.info("Checking that VM supports S3") - - status = session.get_command_status("grep -q mem /sys/power/state") - if status == None: - logging.error("Failed to check if S3 exists") - elif status != 0: - raise error.TestFail("Guest does not support S3") - - logging.info("Waiting for a while for X to start") - time.sleep(10) - - src_tty = session.get_command_output("fgconsole").strip() - logging.info("Current virtual terminal is %s" % src_tty) - if src_tty not in map(str, range(1,10)): - raise error.TestFail("Got a strange current vt (%s)" % src_tty) - - dst_tty = "1" - if src_tty == "1": - dst_tty = "2" - - logging.info("Putting VM into S3") - command = "chvt %s && echo mem > /sys/power/state && chvt %s" % (dst_tty, - src_tty) - status = session.get_command_status(command, timeout=120) - if status != 0: - raise error.TestFail("Suspend to mem failed") - - logging.info("VM resumed after S3") - - session.close() diff --git a/client/tests/kvm/stepmaker.py b/client/tests/kvm/stepmaker.py index 8f16ffd..6a8d86c 100644 --- a/client/tests/kvm/stepmaker.py +++ b/client/tests/kvm/stepmaker.py @@ -338,20 +338,3 @@ class StepMaker(stepeditor.StepMakerWindow): pass -def run_stepmaker(test, params, env): - vm = kvm_utils.env_get_vm(env, params.get("main_vm")) - if not vm: - raise error.TestError("VM object not found in environment") - if not vm.is_alive(): - raise error.TestError("VM seems to be dead; Step Maker requires a" - " living VM") - - steps_filename = params.get("steps") - if not steps_filename: - raise error.TestError("Steps filename not specified") - steps_filename = os.path.join(test.bindir, "steps", steps_filename) - if os.path.exists(steps_filename): - raise error.TestError("Steps file %s already exists" % steps_filename) - - StepMaker(vm, steps_filename, test.debugdir, params) - gtk.main() diff --git a/client/tests/kvm/tests/__init__.py b/client/tests/kvm/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/client/tests/kvm/tests/autotest.py b/client/tests/kvm/tests/autotest.py new file mode 100644 index 0000000..e40e93d --- /dev/null +++ b/client/tests/kvm/tests/autotest.py @@ -0,0 +1,165 @@ +import os, logging +from autotest_lib.client.common_lib import error +import kvm_utils, scan_results + + +def run_autotest(test, params, env): + """ + Run an autotest test inside a guest. + + @param test: kvm test object. + @param params: Dictionary with test parameters. + @param env: Dictionary with the test environment. + """ + vm = kvm_utils.env_get_vm(env, params.get("main_vm")) + if not vm: + raise error.TestError("VM object not found in environment") + if not vm.is_alive(): + raise error.TestError("VM seems to be dead; Test requires a living VM") + + logging.info("Logging into guest...") + + session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2) + if not session: + raise error.TestFail("Could not log into guest") + + logging.info("Logged in") + + # Collect some info + test_name = params.get("test_name") + test_timeout = int(params.get("test_timeout", 300)) + test_control_file = params.get("test_control_file", "control") + tarred_autotest_path = "/tmp/autotest.tar.bz2" + tarred_test_path = "/tmp/%s.tar.bz2" % test_name + + # tar the contents of bindir/autotest + cmd = "cd %s; tar cvjf %s autotest/*" + cmd += " --exclude=autotest/tests" + cmd += " --exclude=autotest/results" + cmd += " --exclude=autotest/tmp" + cmd += " --exclude=autotest/control" + cmd += " --exclude=*.pyc" + cmd += " --exclude=*.svn" + cmd += " --exclude=*.git" + kvm_utils.run_bg(cmd % (test.bindir, tarred_autotest_path), timeout=30) + + # tar the contents of bindir/autotest/tests/<test_name> + cmd = "cd %s; tar cvjf %s %s/*" + cmd += " --exclude=*.pyc" + cmd += " --exclude=*.svn" + cmd += " --exclude=*.git" + kvm_utils.run_bg(cmd % (os.path.join(test.bindir, "autotest", "tests"), + tarred_test_path, test_name), timeout=30) + + # Check if we need to copy autotest.tar.bz2 + copy = False + output = session.get_command_output("ls -l autotest.tar.bz2") + if "such file" in output: + copy = True + else: + size = int(output.split()[4]) + if size != os.path.getsize(tarred_autotest_path): + copy = True + # Perform the copy + if copy: + logging.info("Copying autotest.tar.bz2 to guest" + " (file is missing or has a different size)...") + if not vm.scp_to_remote(tarred_autotest_path, ""): + raise error.TestFail("Could not copy autotest.tar.bz2 to guest") + + # Check if we need to copy <test_name>.tar.bz2 + copy = False + output = session.get_command_output("ls -l %s.tar.bz2" % test_name) + if "such file" in output: + copy = True + else: + size = int(output.split()[4]) + if size != os.path.getsize(tarred_test_path): + copy = True + # Perform the copy + if copy: + logging.info("Copying %s.tar.bz2 to guest (file is missing or has a" + " different size)..." % test_name) + if not vm.scp_to_remote(tarred_test_path, ""): + raise error.TestFail("Could not copy %s.tar.bz2 to guest" % + test_name) + + # Extract autotest.tar.bz2 + logging.info("Extracting autotest.tar.bz2...") + status = session.get_command_status("tar xvfj autotest.tar.bz2") + if status != 0: + raise error.TestFail("Could not extract autotest.tar.bz2") + + # mkdir autotest/tests + session.sendline("mkdir autotest/tests") + + # Extract <test_name>.tar.bz2 into autotest/tests + logging.info("Extracting %s.tar.bz2..." % test_name) + status = session.get_command_status("tar xvfj %s.tar.bz2 -C " + "autotest/tests" % test_name) + if status != 0: + raise error.TestFail("Could not extract %s.tar.bz2" % test_name) + + # Cleaning up old remaining results + session.sendline("rm -rf autotest/results/*") + # Copying the selected control file (located inside + # test.bindir/autotest_control to the autotest dir + control_file_path = os.path.join(test.bindir, "autotest_control", + test_control_file) + if not vm.scp_to_remote(control_file_path, "autotest/control"): + raise error.TestFail("Could not copy the test control file to guest") + # Run the test + logging.info("Running test '%s'..." % test_name) + session.sendline("cd autotest") + session.sendline("rm -f control.state") + session.read_up_to_prompt() + session.sendline("bin/autotest control") + logging.info("---------------- Test output ----------------") + match = session.read_up_to_prompt(timeout=test_timeout, + print_func=logging.info)[0] + logging.info("---------------- End of test output ----------------") + if not match: + raise error.TestFail("Timeout elapsed while waiting for test to " + "complete") + # Get the results generated by autotest + output = session.get_command_output("cat results/*/status") + + # Parse test results + result_list = scan_results.parse_results(output) + + # Report test results and check for FAIL/ERROR status + logging.info("Results (test, status, duration, info):") + status_error = False + status_fail = False + if result_list == []: + status_fail = True + message_fail = ("Test '%s' did not produce any recognizable " + "results" % test_name) + for result in result_list: + logging.info(str(result)) + if result[1] == "FAIL": + status_fail = True + message_fail = ("Test '%s' ended with FAIL " + "(info: '%s')" % (result[0], result[3])) + if result[1] == "ERROR": + status_error = True + message_error = ("Test '%s' ended with ERROR " + "(info: '%s')" % (result[0], result[3])) + if result[1] == "ABORT": + status_error = True + message_error = ("Test '%s' ended with ABORT " + "(info: '%s')" % (result[0], result[3])) + + # Copy test results to the local bindir/guest_results + logging.info("Copying results back from guest...") + guest_results_dir = os.path.join(test.outputdir, "guest_results") + if not os.path.exists(guest_results_dir): + os.mkdir(guest_results_dir) + if not vm.scp_from_remote("autotest/results/default/*", guest_results_dir): + logging.error("Could not copy results back from guest") + + # Fail the test if necessary + if status_fail: + raise error.TestFail(message_fail) + elif status_error: + raise error.TestError(message_error) diff --git a/client/tests/kvm/tests/boot.py b/client/tests/kvm/tests/boot.py new file mode 100644 index 0000000..cd9c766 --- /dev/null +++ b/client/tests/kvm/tests/boot.py @@ -0,0 +1,50 @@ +import logging +from autotest_lib.client.common_lib import error +import kvm_utils + +def run_boot(test, params, env): + """ + KVM reboot test: + 1) Log into a guest + 2) Send a reboot command to the guest + 3) Wait until it's up. + 4) Log into the guest to verify it's up again. + + @param test: kvm test object + @param params: Dictionary with the test parameters + @param env: Dictionary with test environment. + """ + vm = kvm_utils.env_get_vm(env, params.get("main_vm")) + if not vm: + raise error.TestError("VM object not found in environment") + if not vm.is_alive(): + raise error.TestError("VM seems to be dead; Test requires a living VM") + + logging.info("Waiting for guest to be up...") + + session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2) + if not session: + raise error.TestFail("Could not log into guest") + + logging.info("Logged in") + + if params.get("reboot") == "yes": + # Send the VM's reboot command + session.sendline(vm.get_params().get("cmd_reboot")) + logging.info("Reboot command sent; waiting for guest to go down...") + + if not kvm_utils.wait_for(lambda: not session.is_responsive(), + 120, 0, 1): + raise error.TestFail("Guest refuses to go down") + + session.close() + + logging.info("Guest is down; waiting for it to go up again...") + + session = kvm_utils.wait_for(vm.ssh_login, 120, 0, 2) + if not session: + raise error.TestFail("Could not log into guest after reboot") + + logging.info("Guest is up again") + + session.close() diff --git a/client/tests/kvm/tests/install.py b/client/tests/kvm/tests/install.py new file mode 100755 index 0000000..d97f099 --- /dev/null +++ b/client/tests/kvm/tests/install.py @@ -0,0 +1,338 @@ +import time, os, sys, urllib, re, signal, logging, datetime +from autotest_lib.client.bin import utils, test +from autotest_lib.client.common_lib import error +import kvm_utils + + +def load_kvm_modules(module_dir): + """ + Unload previously loaded kvm modules, then load modules present on any + sub directory of module_dir. Function will walk through module_dir until + it finds the modules. + + @param module_dir: Directory where the KVM modules are located. + """ + vendor = "intel" + if os.system("grep vmx /proc/cpuinfo 1>/dev/null") != 0: + vendor = "amd" + logging.debug("Detected CPU vendor as '%s'" %(vendor)) + + logging.debug("Killing any qemu processes that might be left behind") + utils.system("pkill qemu", ignore_status=True) + + logging.info("Unloading previously loaded KVM modules") + kvm_utils.unload_module("kvm") + if utils.module_is_loaded("kvm"): + message = "Failed to remove old KVM modules" + logging.error(message) + raise error.TestError(message) + + logging.info("Loading new KVM modules...") + kvm_module_path = None + kvm_vendor_module_path = None + for folder, subdirs, files in os.walk(module_dir): + if "kvm.ko" in files: + kvm_module_path = os.path.join(folder, "kvm.ko") + kvm_vendor_module_path = os.path.join(folder, "kvm-%s.ko" % vendor) + abort = False + if not os.path.isfile(kvm_module_path): + logging.error("Could not find KVM module that was supposed to be" + " built on the source dir") + abort = True + elif not os.path.isfile(kvm_vendor_module_path): + logging.error("Could not find KVM (%s) module that was supposed to be" + " built on the source dir", vendor) + abort = True + if abort: + raise error.TestError("Could not load KVM modules.") + utils.system("/sbin/insmod %s" % kvm_module_path) + time.sleep(1) + utils.system("/sbin/insmod %s" % kvm_vendor_module_path) + + if not utils.module_is_loaded("kvm"): + message = "Failed to load the KVM modules built for the test" + logging.error(message) + raise error.TestError(message) + + +def create_symlinks(test_bindir, prefix): + """ + Create symbolic links for the appropriate qemu and qemu-img commands on + the kvm test bindir. + + @param test_bindir: KVM test bindir + @param prefix: KVM prefix path + """ + qemu_path = os.path.join(test_bindir, "qemu") + qemu_img_path = os.path.join(test_bindir, "qemu-img") + if os.path.lexists(qemu_path): + os.unlink(qemu_path) + if os.path.lexists(qemu_img_path): + os.unlink(qemu_img_path) + kvm_qemu = os.path.join(prefix, "bin", "qemu-system-x86_64") + if not os.path.isfile(kvm_qemu): + raise error.TestError('Invalid qemu path') + kvm_qemu_img = os.path.join(prefix, "bin", "qemu-img") + if not os.path.isfile(kvm_qemu_img): + raise error.TestError('Invalid qemu-img path') + os.symlink(kvm_qemu, qemu_path) + os.symlink(kvm_qemu_img, qemu_img_path) + + +class SourceDirInstaller: + """ + Class that handles building/installing KVM directly from a tarball or + a single source code dir. + """ + def __init__(self, test, params): + """ + Initializes class attributes, and retrieves KVM code. + + @param test: kvm test object + @param params: Dictionary with test arguments + """ + install_mode = params["mode"] + srcdir = params.get("srcdir") + # KVM build prefix + self.test_bindir = test.bindir + prefix = os.path.join(test.bindir, 'build') + self.prefix = os.path.abspath(prefix) + # Are we going to load modules? + load_modules = params.get('load_modules') + if not load_modules: + self.load_modules = True + elif load_modules == 'yes': + self.load_modules = True + elif load_modules == 'no': + self.load_modules = False + + if install_mode == 'localsrc': + if not srcdir: + raise error.TestError("Install from source directory specified" + "but no source directory provided on the" + "control file.") + else: + self.srcdir = srcdir + self.repo_type = kvm_utils.check_kvm_source_dir(self.srcdir) + return + else: + srcdir = test.srcdir + if not os.path.isdir(srcdir): + os.makedirs(srcdir) + + if install_mode == 'release': + release_tag = params.get("release_tag") + release_dir = params.get("release_dir") + logging.info("Installing KVM from release tarball") + if not release_tag: + release_tag = kvm_utils.get_latest_kvm_release_tag(release_dir) + tarball = os.path.join(release_dir, "kvm-%s.tar.gz" % release_tag) + logging.info("Retrieving release kvm-%s" % release_tag) + tarball = utils.unmap_url("/", tarball, "/tmp") + + elif install_mode == 'snapshot': + logging.info("Installing KVM from snapshot") + snapshot_dir = params.get("snapshot_dir") + if not snapshot_dir: + raise error.TestError("Snapshot dir not provided") + snapshot_date = params.get("snapshot_date") + if not snapshot_date: + # Take yesterday's snapshot + d = (datetime.date.today() - + datetime.timedelta(1)).strftime("%Y%m%d") + else: + d = snapshot_date + tarball = os.path.join(snapshot_dir, "kvm-snapshot-%s.tar.gz" % d) + logging.info("Retrieving kvm-snapshot-%s" % d) + tarball = utils.unmap_url("/", tarball, "/tmp") + + elif install_mode == 'localtar': + tarball = params.get("tarball") + if not tarball: + raise error.TestError("KVM Tarball install specified but no" + " tarball provided on control file.") + logging.info("Installing KVM from a local tarball") + logging.info("Using tarball %s") + tarball = utils.unmap_url("/", params.get("tarball"), "/tmp") + + os.chdir(srcdir) + self.srcdir = os.path.join(srcdir, utils.extract_tarball(tarball)) + self.repo_type = kvm_utils.check_kvm_source_dir(self.srcdir) + + + def __build(self): + os.chdir(self.srcdir) + cfg = "./configure --prefix=%s" % self.prefix + if self.repo_type == 1: + steps = [cfg, "make clean", "make -j %s" % utils.count_cpus()] + if not os.path.exists('qemu/pc-bios/bios.bin'): + steps.append("make -C bios") + steps.append("make -C extboot") + steps.append("cp -f bios/BIOS-bochs-latest" + " qemu/pc-bios/bios.bin") + steps.append("cp -f vgabios/VGABIOS-lgpl-latest.bin" + " qemu/pc-bios/vgabios.bin") + steps.append("cp -f vgabios/VGABIOS-lgpl-latest.cirrus.bin" + " qemu/pc-bios/vgabios-cirrus.bin") + steps.append("cp -f extboot/extboot.bin" + " qemu/pc-bios/extboot.bin") + elif self.repo_type == 2: + steps = [cfg, "make clean", "make -j %s" % utils.count_cpus()] + + logging.info("Building KVM") + for step in steps: + utils.system(step) + + + def __install(self): + os.chdir(self.srcdir) + logging.info("Installing KVM userspace") + if self.repo_type == 1: + utils.system("make -C qemu install") + elif self.repo_type == 2: + utils.system("make install") + create_symlinks(self.test_bindir, self.prefix) + + + def __load_modules(self): + load_kvm_modules(self.srcdir) + + + def install(self): + self.__build() + self.__install() + if self.load_modules: + self.__load_modules() + + +class GitInstaller: + def __init__(self, test, params): + """ + Initialize class parameters and retrieves code from git repositories. + + @param test: kvm test object. + @param params: Dictionary with test parameters. + """ + install_mode = params["mode"] + srcdir = params.get("srcdir", test.bindir) + if not srcdir: + os.makedirs(srcdir) + self.srcdir = srcdir + # KVM build prefix + self.test_bindir = test.bindir + prefix = os.path.join(test.bindir, 'build') + self.prefix = os.path.abspath(prefix) + # Are we going to load modules? + load_modules = params.get('load_modules') + if not load_modules: + self.load_modules = True + elif load_modules == 'yes': + self.load_modules = True + elif load_modules == 'no': + self.load_modules = False + + kernel_repo = params.get("git_repo") + user_repo = params.get("user_git_repo") + kmod_repo = params.get("kmod_repo") + + branch = params.get("git_branch", "master") + lbranch = params.get("lbranch") + + tag = params.get("git_tag", "HEAD") + user_tag = params.get("user_git_tag", "HEAD") + kmod_tag = params.get("kmod_git_tag", "HEAD") + + if not kernel_repo: + message = "KVM git repository path not specified" + logging.error(message) + raise error.TestError(message) + if not user_repo: + message = "KVM user git repository path not specified" + logging.error(message) + raise error.TestError(message) + + kernel_srcdir = os.path.join(srcdir, "kvm") + kvm_utils.get_git_branch(kernel_repo, branch, kernel_srcdir, tag, + lbranch) + self.kernel_srcdir = kernel_srcdir + + userspace_srcdir = os.path.join(srcdir, "kvm_userspace") + kvm_utils.get_git_branch(user_repo, branch, userspace_srcdir, user_tag, + lbranch) + self.userspace_srcdir = userspace_srcdir + + if kmod_repo: + kmod_srcdir = os.path.join (srcdir, "kvm_kmod") + kvm_utils.get_git_branch(kmod_repo, branch, kmod_srcdir, user_tag, + lbranch) + self.kmod_srcdir = kmod_srcdir + + + def __build(self): + if self.kmod_srcdir: + logging.info('Building KVM modules') + os.chdir(self.kmod_srcdir) + utils.system('./configure') + utils.system('make clean') + utils.system('make sync LINUX=%s' % self.kernel_srcdir) + utils.system('make -j %s' % utils.count_cpus()) + logging.info('Building KVM userspace code') + os.chdir(self.userspace_srcdir) + utils.system('./configure --prefix=%s' % self.prefix) + utils.system('make clean') + utils.system('make -j %s' % utils.count_cpus()) + else: + os.chdir(self.userspace_srcdir) + utils.system('./configure --prefix=%s' % self.prefix) + logging.info('Building KVM modules') + utils.system('make clean') + utils.system('make -C kernel LINUX=%s sync' % self.kernel_srcdir) + logging.info('Building KVM userspace code') + utils.system('make -j %s' % utils.count_cpus()) + + + def __install(self): + os.chdir(self.userspace_srcdir) + utils.system('make install') + create_symlinks(self.test_bindir, self.prefix) + + + def __load_modules(self): + if self.kmod_srcdir: + load_kvm_modules(self.kmod_srcdir) + else: + load_kvm_modules(self.userspace_srcdir) + + + def install(self): + self.__build() + self.__install() + if self.load_modules: + self.__load_modules() + + +def run_install(test, params, env): + """ + Installs KVM using the selected install mode. Most install methods will + take kvm source code, build it and install it to a given location. + + @param test: kvm test object. + @param params: Dictionary with test parameters. + @param env: Test environment. + """ + install_mode = params.get("mode") + srcdir = params.get("srcdir", test.srcdir) + params["srcdir"] = srcdir + + if install_mode == 'noinstall': + logging.info("Skipping installation") + return + elif install_mode in ['localsrc', 'localtar', 'release', 'snapshot']: + installer = SourceDirInstaller(test, params) + elif install_mode == 'git': + installer = GitInstaller(test, params) + else: + raise error.TestError('Invalid or unsupported' + ' install mode: %s' % install_mode) + + installer.install() diff --git a/client/tests/kvm/tests/linux_s3.py b/client/tests/kvm/tests/linux_s3.py new file mode 100644 index 0000000..07c251a --- /dev/null +++ b/client/tests/kvm/tests/linux_s3.py @@ -0,0 +1,56 @@ +import logging, time +from autotest_lib.client.common_lib import error +import kvm_utils + + +def run_linux_s3(test, params, env): + """ + Suspend a guest Linux OS to memory. + + @param test: kvm test object. + @param params: Dictionary with test parameters. + @param env: Dictionary with the test environment. + """ + vm = kvm_utils.env_get_vm(env, params.get("main_vm")) + if not vm: + raise error.TestError("VM object not found in environment") + if not vm.is_alive(): + raise error.TestError("VM seems to be dead; Test requires a living VM") + + logging.info("Waiting for guest to be up...") + + session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2) + if not session: + raise error.TestFail("Could not log into guest") + + logging.info("Logged in") + logging.info("Checking that VM supports S3") + + status = session.get_command_status("grep -q mem /sys/power/state") + if status == None: + logging.error("Failed to check if S3 exists") + elif status != 0: + raise error.TestFail("Guest does not support S3") + + logging.info("Waiting for a while for X to start") + time.sleep(10) + + src_tty = session.get_command_output("fgconsole").strip() + logging.info("Current virtual terminal is %s" % src_tty) + if src_tty not in map(str, range(1,10)): + raise error.TestFail("Got a strange current vt (%s)" % src_tty) + + dst_tty = "1" + if src_tty == "1": + dst_tty = "2" + + logging.info("Putting VM into S3") + command = "chvt %s && echo mem > /sys/power/state && chvt %s" % (dst_tty, + src_tty) + status = session.get_command_status(command, timeout=120) + if status != 0: + raise error.TestFail("Suspend to mem failed") + + logging.info("VM resumed after S3") + + session.close() diff --git a/client/tests/kvm/tests/migration.py b/client/tests/kvm/tests/migration.py new file mode 100644 index 0000000..95888f1 --- /dev/null +++ b/client/tests/kvm/tests/migration.py @@ -0,0 +1,79 @@ +import logging, os +from autotest_lib.client.common_lib import error +import kvm_utils + + +def run_migration(test, params, env): + """ + KVM migration test: + + 1) Get two live VMs. One will be the 'source', the other will be the + 'destination'. + 2) Verify if the source VM supports migration. If it does, proceed with + the test + 3) Send a migration command to the source vm and wait until it's finished. + 4) Kill off the source vm + 3) Log into the destination vm after the migration is finished. + 4) Compare the output of a reference command executed on the source with + the output of the same command on the destination machine + + @param test: kvm test object. + @param params: Dictionary with test parameters. + @param env: Dictionary with the test environment. + """ + src_vm_name = params.get("migration_src") + vm = kvm_utils.env_get_vm(env, src_vm_name) + if not vm: + raise error.TestError("VM '%s' not found in environment" % src_vm_name) + if not vm.is_alive(): + raise error.TestError("VM '%s' seems to be dead; Test requires a" + " living VM" % src_vm_name) + + dest_vm_name = params.get("migration_dst") + dest_vm = kvm_utils.env_get_vm(env, dest_vm_name) + if not dest_vm: + raise error.TestError("VM '%s' not found in environment" % dest_vm_name) + if not dest_vm.is_alive(): + raise error.TestError("VM '%s' seems to be dead; Test requires a" + " living VM" % dest_vm_name) + + pre_scrdump_filename = os.path.join(test.debugdir, "migration_pre.ppm") + post_scrdump_filename = os.path.join(test.debugdir, "migration_post.ppm") + + # See if migration is supported + s, o = vm.send_monitor_cmd("help info") + if not "info migrate" in o: + raise error.TestError("Migration is not supported") + + # Log into guest and get the output of migration_test_command + logging.info("Waiting for guest to be up...") + + session = kvm_utils.wait_for(vm.ssh_login, 240, 0, 2) + if not session: + raise error.TestFail("Could not log into guest") + + logging.info("Logged in") + + reference_output = session.get_command_output(params.get("migration_test_" + "command")) + session.close() + + # Define the migration command + cmd = "migrate -d tcp:localhost:%d" % dest_vm.migration_port + logging.debug("Migration command: %s" % cmd) + + # Migrate + s, o = vm.send_monitor_cmd(cmd) + if s: + logging.error("Migration command failed (command: %r, output: %r)" % + (cmd, o)) + raise error.TestFail("Migration command failed") + + # Define some helper functions + def mig_finished(): + s, o = vm.send_monitor_cmd("info migrate") + if s: + return False + if "Migration status: active" in o: + return False + return True diff --git a/client/tests/kvm/tests/stepmaker.py b/client/tests/kvm/tests/stepmaker.py new file mode 100644 index 0000000..3a3a92d --- /dev/null +++ b/client/tests/kvm/tests/stepmaker.py @@ -0,0 +1,22 @@ +import os, gtk +from autotest_lib.client.common_lib import error +import kvm_utils, stepmaker + + +def run_stepmaker(test, params, env): + vm = kvm_utils.env_get_vm(env, params.get("main_vm")) + if not vm: + raise error.TestError("VM object not found in environment") + if not vm.is_alive(): + raise error.TestError("VM seems to be dead; Step Maker requires a" + " living VM") + + steps_filename = params.get("steps") + if not steps_filename: + raise error.TestError("Steps filename not specified") + steps_filename = os.path.join(test.bindir, "steps", steps_filename) + if os.path.exists(steps_filename): + raise error.TestError("Steps file %s already exists" % steps_filename) + + stepmaker.StepMaker(vm, steps_filename, test.debugdir, params) + gtk.main() diff --git a/client/tests/kvm/tests/steps.py b/client/tests/kvm/tests/steps.py new file mode 100644 index 0000000..ec76186 --- /dev/null +++ b/client/tests/kvm/tests/steps.py @@ -0,0 +1,215 @@ +import os, time, md5, re, shutil, logging +from autotest_lib.client.common_lib import utils, error +import kvm_utils, ppm_utils + + +def handle_var(vm, params, varname): + var = params.get(varname) + if not var: + return False + vm.send_string(var) + return True + + +def barrier_2(vm, words, fail_if_stuck_for, stuck_detection_history, + output_dir, data_scrdump_filename, current_step_num): + if len(words) < 7: + logging.error("Bad barrier_2 command line") + return False + + cmd, dx, dy, x1, y1, md5sum, timeout = words[:7] + dx, dy, x1, y1, timeout = map(int, [dx, dy, x1, y1, timeout]) + + # Timeout/5 is the time it took stepmaker to complete this step. + # Divide that number by 10 to poll 10 times, just in case + # current machine is stronger then the "stepmaker machine". + # Limit to 1 (min) and 10 (max) seconds between polls. + sleep_duration = float(timeout) / 50.0 + if sleep_duration < 1.0: sleep_duration = 1.0 + if sleep_duration > 10.0: sleep_duration = 10.0 + + scrdump_filename = os.path.join(output_dir, "scrdump.ppm") + cropped_scrdump_filename = os.path.join(output_dir, "cropped_scrdump.ppm") + expected_scrdump_filename = os.path.join(output_dir, "scrdump_expected.ppm") + expected_cropped_scrdump_filename = os.path.join(output_dir, + "cropped_scrdump_expected.ppm") + comparison_filename = os.path.join(output_dir, "comparison.ppm") + + end_time = time.time() + timeout + end_time_stuck = time.time() + fail_if_stuck_for + start_time = time.time() + + prev_whole_image_md5sums = [] + + failure_message = None + + # Main loop + while True: + # Check for timeouts + if time.time() > end_time: + failure_message = "regular timeout" + break + if time.time() > end_time_stuck: + failure_message = "guest is stuck" + break + + # Make sure vm is alive + if not vm.is_alive(): + failure_message = "VM is dead" + break + + # Request screendump + (status, output) = vm.send_monitor_cmd("screendump %s" % + scrdump_filename) + if status: + logging.error("Could not fetch screendump") + continue + + # Make sure image is valid + if not ppm_utils.image_verify_ppm_file(scrdump_filename): + failure_message = "got invalid screendump" + break + + # Read image file + (w, h, data) = ppm_utils.image_read_from_ppm_file(scrdump_filename) + + # Compare md5sum of barrier region with the expected md5sum + calced_md5sum = ppm_utils.get_region_md5sum(w, h, data, x1, y1, dx, dy, + cropped_scrdump_filename) + if calced_md5sum == md5sum: + return True + + # Compute md5sum of whole image in order to compare it with + # previous ones + whole_image_md5sum = ppm_utils.image_md5sum(w, h, data) + # If md5sum is already in queue... + if whole_image_md5sum in prev_whole_image_md5sums: + # Remove md5sum from queue + prev_whole_image_md5sums.remove(whole_image_md5sum) + else: + # Extend 'stuck' timeout + end_time_stuck = time.time() + fail_if_stuck_for + # Insert md5sum at beginning of queue + prev_whole_image_md5sums.insert(0, whole_image_md5sum) + # Limit queue length to stuck_detection_history + prev_whole_image_md5sums = \ + prev_whole_image_md5sums[:stuck_detection_history] + + # Sleep for a while + time.sleep(sleep_duration) + + # Failure + message = ("Barrier failed at step %s after %.2f seconds (%s)" % + (current_step_num, time.time() - start_time, failure_message)) + + # What should we do with this failure? + if words[-1] == "optional": + logging.info(message) + return False + else: + # Collect information and put it in output_dir + if data_scrdump_filename and os.path.exists(data_scrdump_filename): + # Read expected screendump image + (ew, eh, edata) = \ + ppm_utils.image_read_from_ppm_file(data_scrdump_filename) + # Write it in output_dir + ppm_utils.image_write_to_ppm_file(expected_scrdump_filename, + ew, eh, edata) + # Write the cropped version as well + ppm_utils.get_region_md5sum(ew, eh, edata, x1, y1, dx, dy, + expected_cropped_scrdump_filename) + # Perform comparison + (w, h, data) = ppm_utils.image_read_from_ppm_file(scrdump_filename) + if w == ew and h == eh: + (w, h, data) = ppm_utils.image_comparison(w, h, data, edata) + ppm_utils.image_write_to_ppm_file(comparison_filename, w, h, + data) + # Print error messages and fail the test + long_message = message + "\n(see analysis at %s)" % output_dir + logging.error(long_message) + raise error.TestFail, message + + +def run_steps(test, params, env): + """ + Performs a VM installation using step files. + + @param test: kvm test instance. + @param params: Dictionary with test parameters. + @param env: Test environment. + """ + vm = kvm_utils.env_get_vm(env, params.get("main_vm")) + if not vm: + raise error.TestError("VM object not found in environment") + if not vm.is_alive(): + e_msg = "VM seems to be dead. Guestwizard requires a living VM" + raise error.TestError(e_msg) + + steps_filename = params.get("steps") + if not steps_filename: + raise error.TestError("Steps filename not specified") + steps_filename = os.path.join(test.bindir, "steps", steps_filename) + if not os.path.exists(steps_filename): + raise error.TestError("Steps file not found: %s" % steps_filename) + + fail_if_stuck_for = params.get("fail_if_stuck_for") + if fail_if_stuck_for: + fail_if_stuck_for = float(fail_if_stuck_for) + else: + fail_if_stuck_for = 1e308 + + stuck_detection_history = params.get("stuck_detection_history") + if stuck_detection_history: + stuck_detection_history = int(stuck_detection_history) + else: + stuck_detection_history = 2 + + sf = open(steps_filename, "r") + lines = sf.readlines() + sf.close() + + vm.send_monitor_cmd("cont") + + current_step_num = 0 + current_screendump = None + skip_current_step = False + + # Iterate over the lines in the file + for line in lines: + line = line.strip() + if not line: + continue + logging.info(line) + + if line.startswith("#"): + continue + + words = line.split() + if words[0] == "step": + current_step_num += 1 + current_screendump = None + skip_current_step = False + elif words[0] == "screendump": + current_screendump = words[1] + elif skip_current_step: + continue + elif words[0] == "sleep": + time.sleep(float(words[1])) + elif words[0] == "key": + vm.send_key(words[1]) + elif words[0] == "var": + if not handle_var(vm, params, words[1]): + logging.error("Variable not defined: %s" % words[1]) + elif words[0] == "barrier_2": + if current_screendump: + scrdump_filename = ( + os.path.join(ppm_utils.get_data_dir(steps_filename), + current_screendump)) + else: + scrdump_filename = None + if not barrier_2(vm, words, fail_if_stuck_for, + stuck_detection_history, test.debugdir, + scrdump_filename, current_step_num): + skip_current_step = True + else: + vm.send_key(words[0]) diff --git a/client/tests/kvm/tests/yum_update.py b/client/tests/kvm/tests/yum_update.py new file mode 100644 index 0000000..b7e46dd --- /dev/null +++ b/client/tests/kvm/tests/yum_update.py @@ -0,0 +1,65 @@ +import logging, time +from autotest_lib.client.common_lib import error +import kvm_utils + + +def internal_yum_update(session, command, prompt, timeout): + """ + Helper function to perform the yum update test. + + @param session: SSH session stablished to the host + @param command: Command to be sent to the SSH connection + @param prompt: Machine prompt + @param timeout: How long to wait until we get an appropriate output from + the SSH session. + """ + session.sendline(command) + end_time = time.time() + timeout + while time.time() < end_time: + (match, text) = session.read_until_last_line_matches( + ["[Ii]s this [Oo][Kk]", prompt], timeout=timeout) + if match == 0: + logging.info("Got 'Is this ok'; sending 'y'") + session.sendline("y") + elif match == 1: + logging.info("Got shell prompt") + return True + else: + logging.info("Timeout or process exited") + return False + + +def run_yum_update(test, params, env): + """ + Runs yum update and yum update kernel on the remote host (yum enabled + hosts only). + + @param test: kvm test object. + @param params: Dictionary with test parameters. + @param env: Dictionary with the test environment. + """ + vm = kvm_utils.env_get_vm(env, params.get("main_vm")) + if not vm: + message = "VM object not found in environment" + logging.error(message) + raise error.TestError(message) + if not vm.is_alive(): + message = "VM seems to be dead; Test requires a living VM" + logging.error(message) + raise error.TestError(message) + + logging.info("Logging into guest...") + + session = kvm_utils.wait_for(vm.ssh_login, 120, 0, 2) + if not session: + message = "Could not log into guest" + logging.error(message) + raise error.TestFail(message) + + logging.info("Logged in") + + internal_yum_update(session, "yum update", params.get("ssh_prompt"), 600) + internal_yum_update(session, "yum update kernel", + params.get("ssh_prompt"), 600) + + session.close() -- 1.6.2.2 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html