About implementation of KVM server-side migration in autotest

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxxx>"
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)
--------
--
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

[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux