[libvirt] [Libvirt-test-API][PATCH 4/6] add migrate.py testcases based on Daniel Berrage's migration testing scenarios

Nan Zhang nzhang at redhat.com
Fri Jul 1 12:51:13 UTC 2011


On 06/28/2011 01:54 PM, Guannan.ren wrote:
> ---
>   repos/domain/migrate.py |  335 +++++++++++++++++++++++++++++++++++++++++++++++
>   1 files changed, 335 insertions(+), 0 deletions(-)
>   create mode 100644 repos/domain/migrate.py
>
> diff --git a/repos/domain/migrate.py b/repos/domain/migrate.py
> new file mode 100644
> index 0000000..3f80bd0
> --- /dev/null
> +++ b/repos/domain/migrate.py
> @@ -0,0 +1,335 @@
> +#!/usr/bin/env python
> +"""this script is for migration testing
> +   domain:migrate
> +       target_machine
> +           10.66.5.5
> +       username
> +           root
> +       password
> +           redhat
> +       guestname
> +           rhel6
> +       prestate
> +           running
> +       poststate
> +           running
> +       presrcconfig
> +           false
> +       postsrcconfig
> +           false
> +       predstconfig
> +           false
> +       postdstconfig
> +           false
> +       flags
> +           0|live
> +
> +prestate and poststate is the domain state:<running|paused>
> +presrconfig, postsrconfig, predstconfig, postdstconfig is<true|false>
> +flags is the migration flags combination<0|peer2peer|tunnelled|live|paused \
> +                                         |persist_dest|undefine_source|>
> +
> +"""
> +__author__ = 'Guannan Ren: gren at redhat.com'
> +__date__ = 'Sun June 26, 2011'
> +__version__ = '0.1.0'
> +__credits__ = 'Copyright (C) 2011 Red Hat, Inc.'
> +__all__ = ['usage', 'migrate']
> +
> +import os
> +import re
> +import sys
> +import pexpect
> +import string
> +import commands
> +
> +def append_path(path):
> +    """Append root path of package"""
> +    if path in sys.path:
> +        pass
> +    else:
> +        sys.path.append(path)
> +
> +pwd = os.getcwd()
> +result = re.search('(.*)libvirt-test-API', pwd)
> +append_path(result.group(0))
> +
> +from lib import connectAPI
> +from lib.domainAPI import *
> +from utils.Python import utils
> +from utils.Python import xmlbuilder
> +from exception import LibvirtAPI
> +
> +SSH_KEYGEN = "ssh-keygen -t rsa"
> +SSH_COPY_ID = "ssh-copy-id"
> +GUEST_XML = "/etc/libvirt/qemu/%s.xml"
> +
> +def exec_command(logger, command, flag):
> +    """execute shell command
> +    """
> +    status, ret = commands.getstatusoutput(command)
> +    if not flag and status:
> +        logger.error("executing "+ "\"" +  command  + "\"" + " failed")
> +        logger.error(ret)
> +    return status, ret
> +
> +
> +def env_clean(src, dst, srcdom, dstdom, target_machine, guestname, logger):
> +
> +    logger.info("destroy and undefine %s on both side if it exsits", guestname)
> +    exec_command(logger, "virsh destroy %s" % guestname, 1)
> +    exec_command(logger, "virsh undefine %s" % guestname, 1)
> +    REMOTE_DESTROY = "ssh %s \"virsh destroy %s\"" % (target_machine, guestname)
> +    exec_command(logger, REMOTE_DESTROY, 1)
> +    REMOTE_UNDEFINE = "ssh %s \"virsh undefine %s\"" % (target_machine, guestname)
> +    exec_command(logger, REMOTE_UNDEFINE, 1)
> +
> +    src.close()
> +    logger.info("close local hypervisor connection")
> +    dst.close()
> +    logger.info("close remote hypervisor connection")
> +
> +    REMOVE_SSH = "ssh %s \"rm -rf /root/.ssh/*\"" % (target_machine)
> +    logger.info("remove ssh key on remote machine")
> +    status, ret = exec_command(logger, REMOVE_SSH, 0)
> +    if status:
> +        logger.error("failed to remove ssh key")
> +
> +    REMOVE_LOCAL_SSH = "rm -rf /root/.ssh/*"
> +    logger.info("remove local ssh key")
> +    status, ret = exec_command(logger, REMOVE_LOCAL_SSH, 0)
> +    if status:
> +        logger.error("failed to remove local ssh key")
> +
> +
> +def check_params(params):
> +    """check out the arguments requried for migration"""
> +    logger = params['logger']
> +    keys = ['target_machine', 'username', 'password', 'guestname', 'flags']
> +    for key in keys:
> +        if key not in params:
> +            logger.error("Argument %s is required" % key)
> +            return 1
> +    return 0
> +
> +def ssh_keygen(logger):
> +    """using pexpect to generate RSA"""
> +    logger.info("generate ssh RSA \"%s\"" % SSH_KEYGEN)
> +    child = pexpect.spawn(SSH_KEYGEN)
> +    while True:
> +        index = child.expect(['Enter file in which to save the key ',
> +                              'Enter passphrase ',
> +                              'Enter same passphrase again: ',
> +                               pexpect.EOF,
> +                               pexpect.TIMEOUT])
> +        if index == 0:
> +            child.sendline("\r")
> +        elif index == 1:
> +            child.sendline("\r")
> +        elif index == 2:
> +            child.sendline("\r")
> +        elif index == 3:
> +            logger.debug(string.strip(child.before))
> +            child.close()
> +            return 0
> +        elif index == 4:
> +            logger.error("ssh_keygen timeout")
> +            logger.debug(string.strip(child.before))
> +            child.close()
> +            return 1
> +
> +    return 0
> +
> +def ssh_tunnel(hostname, username, password, logger):
> +    """setup a tunnel to a give host"""
> +    logger.info("setup ssh tunnel with host %s" % hostname)
> +    user_host = "%s@%s" % (username, hostname)
> +    child = pexpect.spawn(SSH_COPY_ID, [ user_host])
> +    while True:
> +        index = child.expect(['yes\/no', 'password: ',
> +                               pexpect.EOF,
> +                               pexpect.TIMEOUT])
> +        if index == 0:
> +            child.sendline("yes")
> +        elif index == 1:
> +            child.sendline(password)
> +        elif index == 2:
> +            logger.debug(string.strip(child.before))
> +            child.close()
> +            return 0
> +        elif index == 3:
> +            logger.error("setup tunnel timeout")
> +            logger.debug(string.strip(child.before))
> +            child.close()
> +            return 1
> +
> +    return 0
> +
> +def remote_guest_define(target_machine, username, guestname, logger):
> +    """copy guest xml description to target machine and define it"""
> +    xml_file = GUEST_XML % guestname
> +
> +    if not os.path.exists(xml_file):
> +        logger.error("guest %s xml file doesn't exsits" % guestname)
> +        return 1
> +
> +    SCP_CMD = "scp %s %s@%s:/tmp" %(xml_file, username, target_machine)
> +    status, ret = exec_command(logger, SCP_CMD, 0)
> +    if status:
> +        logger.error("copy guest file failed")
> +        return 1
> +
> +    VIRSH_DEFINE = "ssh %s \"virsh define /tmp/%s.xml\"" % (target_machine, guestname)
> +    status, ret = exec_command(logger, VIRSH_DEFINE, 0)
> +    if status:
> +        logger.error("faied to define guest on target machine")
> +        return 1
> +
> +    return 0
> +
> +def migrate(params):
> +    """ migrate a guest back and forth between two machines"""
> +    logger = params['logger']
> +    params_check_result = check_params(params)
> +    if params_check_result:
> +        return 1
> +
> +    target_machine = params['target_machine']
> +    username = params['username']
> +    password = params['password']
> +    guestname = params['guestname']
> +    poststate = params['poststate']
> +    presrcconfig = params['presrcconfig']
> +    postsrcconfig = params['postsrcconfig']
> +    predstconfig = params['predstconfig']
> +    postdstconfig = params['postdstconfig']
> +    flags = params['flags']
> +
> +
> +    logger.info("the flags is %s" % flags)
> +    flags_string = flags.split("|")
> +
> +    migflags = 0
> +    for flag in flags_string:
> +        if flag == '0':
> +            migflags |= 0
> +        elif flag == 'peer2peer':
> +            migflags |= VIR_MIGRATE_PEER2PEER
> +        elif flag == 'tunnelled':
> +            migflags |= VIR_MIGRATE_TUNNELLED
> +        elif flag == 'live':
> +            migflags |= VIR_MIGRATE_LIVE
> +        elif flag == 'persist_dest':
> +            migflags |= VIR_MIGRATE_PERSIST_DEST
> +        elif flag == 'undefine_source':
> +            migflags |= VIR_MIGRATE_UNDEFINE_SOURCE
> +        elif flag == 'paused':
> +            migflags |= VIR_MIGRATE_PAUSED
> +        else:
> +            logger.error("unknown flag")
> +            return 1
> +
> +    #generate ssh key pair
> +    ret = ssh_keygen(logger)
> +    if ret:
> +        logger.error("failed to generate RSA key")
> +        return 1
> +    #setup ssh tunnel with target machine
> +    ret = ssh_tunnel(target_machine, username, password, logger)
> +    if ret:
> +        logger.error("faild to setup ssh tunnel with target machine %s" % target_machine)
> +        return 1
> +
> +    commands.getstatusoutput("ssh-add")
> +
> +    srcuri = "qemu:///system"
> +    dsturi = "qemu+ssh://%s/system" % target_machine
> +
> +    # Connect to local hypervisor connection URI
> +    util = utils.Utils()
> +    conn = connectAPI.ConnectAPI()
> +    src = conn.open(srcuri)
> +    dst = conn.open(dsturi)
> +
> +    srcdom = DomainAPI(src)
> +    dstdom = DomainAPI(dst)
> +
> +    if predstconfig == "true":
> +        ret = remote_guest_define(target_machine, username, guestname, logger)
> +        if ret:
> +            env_clean(src, dst, srcdom, dstdom, target_machine, guestname, logger)
> +            return 1
> +
> +
> +    try:
> +        if(migflags&  VIR_MIGRATE_PEER2PEER):
> +            logger.info("use migrate_to_uri() API to migrate")
> +            srcdom.migrate_to_uri(guestname, dsturi, migflags)
> +        else:
> +            logger.info("use migrate() to migrate")
> +            srcdom.migrate(guestname, dst, migflags)
> +    except LibvirtAPI, e:
> +        logger.error("API error message: %s, error code is %s" % \
> +                     (e.response()['message'], e.response()['code']))
> +        logger.error("Migration Failed")
> +        env_clean(src, dst, srcdom, dstdom, target_machine, guestname, logger)
> +        return 1
> +
> +    if postsrcconfig == "true":
> +        if srcdom.is_active(guestname):
> +            logger.error("Source VM is still active")
> +            env_clean(src, dst, srcdom, dstdom, target_machine, guestname, logger)
> +            return 1
> +        if not srcdom.is_persistent(guestname):
> +            logger.error("Source VM missing config")
> +            env_clean(src, dst, srcdom, dstdom, target_machine, guestname, logger)
> +            return 1
> +    else:
> +        guest_names = srcdom.get_list()
> +        guest_names += srcdom.get_defined_list()
> +        if guestname in guest_names:
> +            logger.error("Source VM still exists")
> +            env_clean(src, dst, srcdom, dstdom, target_machine, guestname, logger)
> +            return 1
> +
> +    if not dstdom.is_active(guestname):
> +        logger.error("Dst VM is not active")
> +        env_clean(src, dst, srcdom, dstdom, target_machine, guestname, logger)
> +        return 1
> +
> +    if postdstconfig == "true":
> +        if not dstdom.is_persistent(guestname):
> +            logger.error("Dst VM missing config")
> +            env_clean(src, dst, srcdom, dstdom, target_machine, guestname, logger)
> +            return 1
> +
> +    dstdom_state = dstdom.get_state(guestname)
> +    if dstdom_state != poststate:
> +        logger.error("Dst VM wrong state %s, should be %s", dstdom_state, poststate)
> +        env_clean(src, dst, srcdom, dstdom, target_machine, guestname, logger)
> +        return 1
> +
> +    logger.info("Migration PASS")
> +    env_clean(src, dst, srcdom, dstdom, target_machine, guestname, logger)
> +    return 0
> +
> +
> +
> +
> +
> +
> +
> +
> +
> +
> +
> +
> +
> +
> +
> +
> +
> +
> +
> +
> +
ACK, but too many redundant blank lines at the end of file.

- nzhang




More information about the libvir-list mailing list