new file mode 100644
@@ -0,0 +1,146 @@
+import sys, os, time, logging, commands
+from autotest_lib.client.bin import test
+from autotest_lib.client.common_lib import error
+import kvm_utils, kvm_preprocessing, common, kvm_vm, kvm_test_utils
+
+
+class kvm_migration(test.test):
+ """
+ KVM migration test.
+
+ @copyright: Red Hat 2008-2009
+ @see: http://www.linux-kvm.org/page/KVM-Autotest/Client_Install
+ (Online doc - Getting started with KVM testing)
+ """
+ version = 1
+ def initialize(self):
+ pass
+
+
+ def setup(self):
+ """
+ Setup environment like NFS mount etc.
+ """
+ pass
+
+
+ def run_once(self, params):
+ """
+ Setup remote machine and then execute migration.
+ """
+ # Check whether remote machine is ready
+ dsthost = params.get("dsthost")
+ srchost = params.get("srchost")
+ image_path = os.path.join(self.bindir, "images")
+
+ rootdir = params.get("rootdir")
+ iso = os.path.join(rootdir, 'iso')
+ images = os.path.join(rootdir, 'images')
+ qemu = os.path.join(rootdir, 'qemu')
+ qemu_img = os.path.join(rootdir, 'qemu-img')
+
+ def link_if_not_exist(ldir, target, link_name):
+ t = target
+ l = os.path.join(ldir, link_name)
+ if not os.path.exists(l):
+ os.symlink(t,l)
+ link_if_not_exist(self.bindir, '../../', 'autotest')
+ link_if_not_exist(self.bindir, iso, 'isos')
+ link_if_not_exist(self.bindir, images, 'images')
+ link_if_not_exist(self.bindir, qemu, 'qemu')
+ link_if_not_exist(self.bindir, qemu_img, 'qemu-img')
+
+ try:
+ image_real_path = os.readlink(image_path)
+ except OSError:
+ raise error.TestError("Readlink of image dir failed")
+
+ def setup_dest(srchost, path):
+ """
+ Mount NFS directory from source host.
+ """
+ cmd = "mount |grep -q %s" % srchost
+ if os.system(cmd):
+ mnt_cmd = "mount %s:%s %s" % (srchost,
+ path,
+ path)
+ s, o = commands.getstatusoutput(mnt_cmd)
+ if s != 0:
+ raise error.TestError("Mount srchost failed: %s" % o)
+
+ def setup_source(path):
+ """
+ Setup NFS mount point.
+ """
+ export_string = "%s *(rw,no_root_squash)" % path
+ export_file = '/etc/exports'
+ f = open(export_file)
+ if not export_string in f.read().strip():
+ try:
+ f.write(export_string)
+ except IOError:
+ raise error.TestError("Failed to write to exports file")
+
+ cmd = "service nfs restart && exportfs -a"
+ if os.system(cmd):
+ raise error.TestError("Failed to restart NFS on source")
+
+ # if params.get("role") == "dest":
+ # setup_dest(srchost, image_real_path)
+ # elif params.get("role") == "source":
+ # setup_source(image_real_path)
+
+ # Report the parameters we've received and write them as keyvals
+ logging.debug("Test parameters:")
+ keys = params.keys()
+ keys.sort()
+ for key in keys:
+ logging.debug(" %s = %s", key, params[key])
+ self.write_test_keyval({key: params[key]})
+
+ # Open the environment file
+ env_filename = os.path.join(self.bindir, params.get("env", "env"))
+ env = kvm_utils.load_env(env_filename, {})
+ logging.debug("Contents of environment: %s" % str(env))
+
+
+ # Preprocess
+ kvm_preprocessing.preprocess(self, params, env)
+ kvm_utils.dump_env(env, env_filename)
+
+ try:
+ try:
+ # Get the living VM
+ vm = kvm_test_utils.get_living_vm(env, params.get("main_vm"))
+
+ if params.get("role") == "source":
+ s, o = vm.send_monitor_cmd("help info")
+ if not "info migrate" in o:
+ raise error.TestError("Migration is not supported")
+
+ session = kvm_test_utils.wait_for_login(vm)
+ migration_test_command = params.get("migration_test_command")
+ reference_output = session.get_command_output(migration_test_command)
+
+ kvm_test_utils.migrate(vm, dsthost, vm.migration_port, env)
+ session.close()
+ elif params.get("role") == "dest":
+ try:
+ mig_timeout = int(params.get("mig_timeout"))
+ session = kvm_test_utils.wait_for_login(vm,
+ timeout=mig_timeout)
+ except:
+ raise error.TestFail("Could not log into migrated guest")
+
+ except Exception, e:
+ logging.error("Test failed: %s", e)
+ logging.debug("Postprocessing on error...")
+ kvm_preprocessing.postprocess_on_error(self, params, env)
+ kvm_utils.dump_env(env, env_filename)
+ raise
+
+ finally:
+ # Postprocess
+ kvm_preprocessing.postprocess(self, params, env)
+ logging.debug("Contents of environment: %s", str(env))
+ kvm_utils.dump_env(env, env_filename)
@@ -74,7 +74,7 @@ def preprocess_vm(test, params, env, name):
logging.debug("VM's qemu command differs from requested one; "
"restarting it...")
start_vm = True
-
+
if start_vm and not vm.create(name, params, test.bindir, for_migration):
raise error.TestError("Could not start VM")
@@ -105,7 +105,7 @@ def reboot(vm, session, method="shell", sleep_before_reset=10, nic_index=0,
return session
-def migrate(vm, env=None):
+def migrate(vm, rem_host, rem_port, env=None, mig_timeout=90):
"""
Migrate a VM locally and re-register it in the environment.
@@ -132,13 +132,14 @@ def migrate(vm, env=None):
if not "info migrate" in o:
raise error.TestError("Migration is not supported")
- # Clone the source VM and ask the clone to wait for incoming migration
- dest_vm = vm.clone()
- dest_vm.create(for_migration=True)
+ if rem_host == "localhost":
+ # Clone the source VM and ask the clone to wait for incoming migration
+ dest_vm = vm.clone()
+ dest_vm.create(for_migration=True)
try:
# Define the migration command
- cmd = "migrate -d tcp:localhost:%d" % dest_vm.migration_port
+ cmd = "migrate -d tcp:%s:%d" % (rem_host, rem_port)
logging.debug("Migrating with command: %s" % cmd)
# Migrate
@@ -149,7 +150,7 @@ def migrate(vm, env=None):
raise error.TestFail("Migration command failed")
# Wait for migration to finish
- if not kvm_utils.wait_for(mig_finished, 90, 2, 2,
+ if not kvm_utils.wait_for(mig_finished, mig_timeout, 2, 2,
"Waiting for migration to finish..."):
raise error.TestFail("Timeout elapsed while waiting for migration "
"to finish")
@@ -165,15 +166,17 @@ def migrate(vm, env=None):
# 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 rem_host == "localhost":
+ # Replace the source VM with the new cloned VM
+ if env is not None:
+ kvm_utils.env_register_vm(env, vm.name, dest_vm)
- # Return the new cloned VM
- return dest_vm
+ # Return the new cloned VM
+ return dest_vm
except:
- dest_vm.destroy()
+ if rem_host == "localhost":
+ dest_vm.destroy()
raise
@@ -81,6 +81,7 @@ variants:
migration_bg_command = "cd /tmp; nohup tcpdump -q -t ip host localhost"
migration_bg_check_command = pgrep tcpdump
migration_bg_kill_command = pkill tcpdump
+ mig_timeout = 90
kill_vm_on_error = yes
iterations = 2
used_mem = 1024
@@ -396,9 +396,9 @@ class VM:
qemu_command = self.make_qemu_command()
# Is this VM supposed to accept incoming migrations?
+ # Find available migration port
+ self.migration_port = kvm_utils.find_free_port(5200, 6000)
if for_migration:
- # Find available migration port
- self.migration_port = kvm_utils.find_free_port(5200, 6000)
# Add -incoming option to the qemu command
qemu_command += " -incoming tcp:0:%d" % self.migration_port
@@ -43,7 +43,7 @@ def run_migration(test, params, env):
session2.close()
# Migrate the VM
- dest_vm = kvm_test_utils.migrate(vm, env)
+ dest_vm = kvm_test_utils.migrate(vm, "localhost", vm.migration_port, env)
# Log into the guest again
logging.info("Logging into guest after migration...")
new file mode 120000
@@ -0,0 +1 @@
+kvm
\ No newline at end of file
new file mode 100644
@@ -0,0 +1,98 @@
+AUTHOR = "Yolkfull Chow <yzhou@redhat.com>"
+TIME = "SHORT"
+NAME = "Migration across Multi-machine"
+TEST_CATEGORY = "Functional"
+TEST_CLASS = 'Virtualization'
+TEST_TYPE = "Server"
+DOC = """
+Migrate KVM guest between two hosts.
+
+Arguments to run_test:
+
+@dict - a dictionary containing all parameters that migration need.
+"""
+
+import sys, os, commands
+from autotest_lib.server import utils
+
+KVM_DIR = os.path.join('/root/devel/upstream/server-mig', 'client/tests/kvm')
+sys.path.append(KVM_DIR)
+import common, kvm_config
+
+rootdir = '/tmp/kvm_autotest_root'
+
+def run(pair):
+ print "KVM migration running on srchost [%s] and desthost [%s]\n" % (
+ pair[0], pair[1])
+
+ source = hosts.create_host(pair[0])
+ dest = hosts.create_host(pair[1])
+
+ source_at = autotest.Autotest(source)
+ #source_at.install(source)
+ dest_at = autotest.Autotest(dest)
+ #dest_at.install(dest)
+
+ # ----------------------------------------------------------
+ # Get test set (dictionary list) from the configuration file
+ # ----------------------------------------------------------
+ filename = os.path.join(KVM_DIR, "kvm_tests.cfg")
+ if not os.path.exists(filename):
+ print "[ERROR] Test config file doesn't found"
+ cfg = kvm_config.config(filename)
+
+ filename = os.path.join(KVM_DIR, "kvm_address_pools.cfg")
+ if os.path.exists(filename):
+ cfg.parse_file(filename)
+ hostname = os.uname()[1].split(".")[0]
+ if cfg.filter("^" + hostname):
+ cfg.parse_string("only ^%s" % hostname)
+ else:
+ cfg.parse_string("only ^default_host")
+
+ list = cfg.get_list()
+
+ # Control file template for client machine
+ control_string = "job.run_test('kvm_migration', params=%s)"
+
+ for vm_dict in list:
+
+ vm_dict['srchost'] = source.ip
+ vm_dict['dsthost'] = dest.ip
+ vm_dict['display'] = 'vnc'
+ vm_dict['rootdir'] = rootdir
+
+ source_dict = vm_dict.copy()
+ dest_dict = vm_dict.copy()
+
+ source_dict['role'] = "source"
+
+ dest_dict['role'] = "dest"
+ dest_dict['start_vm_for_migration'] = "yes"
+
+ # Report the parameters we've received
+ print "Test parameters:"
+ keys = vm_dict.keys()
+ keys.sort()
+ for key in keys:
+ print " " + str(key) + " = " + str(vm_dict[key])
+
+ source_control_file = ''.join([control_string % source_dict])
+ dest_control_file = ''.join([control_string % dest_dict])
+
+ dest_command = subcommand(dest_at.run,
+ [dest_control_file, dest.hostname])
+ source_command = subcommand(source_at.run,
+ [source_control_file, source.hostname])
+
+ parallel([dest_command, source_command])
+
+# grab the pairs (and failures)
+(pairs, failures) = utils.form_ntuples_from_machines(machines, 2)
+
+# log the failures
+for failure in failures:
+ job.record("FAIL", failure[0], "kvm", failure[1])
+
+# now run through each pair and run
+job.parallel_simple(run, pairs, log=False)