public inbox for kvm@vger.kernel.org
 help / color / mirror / Atom feed
* About implementation of KVM server-side migration in autotest
@ 2009-12-01  7:08 Yolkfull Chow
  0 siblings, 0 replies; only message in thread
From: Yolkfull Chow @ 2009-12-01  7:08 UTC (permalink / raw)
  To: mgoldish; +Cc: lmr, kvm, autotest

Hi Michael and Lucas,

Would you please give me some comments/suggestions based on
my initial design of it? Thanks in advance. :)


============ KVM server-side migration design =================

1 for generating migration test dicts, two methods:

1.1 use existent framework of kvm client test
1.2 new a script named kvm_migration.py under dir kvm, initial version could be:

kvm_migration.py
--------
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)
--------  

   But there will be a problem:  where can we edit the config file
   to generate differnt dicts for migration test? Hard code the parameters in control.srv? 

   It will be easier to resolve the problem of making up kvm_tests.cfg for both client
   machines. 

2 just pass 'start_vm_for_migration = yes' to dest host

3 source host will wait until dest host telling it's ready using socket
  communication (any existent implement/function in autotest framework? )

4 and then change the role of 'source machine' and 'dest machine' to implement ping-pong
  migrate.

Initial version of control.srv for server-migration:

-----
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.insert(0, KVM_DIR)
import 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")
    cfg = kvm_config.config(filename)
    
    # Make only dictionaries that migration needs
    cfg.parse_string("only migrate")
    
    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)
--------

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2009-12-01  7:08 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-12-01  7:08 About implementation of KVM server-side migration in autotest Yolkfull Chow

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox