[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