This patch adds a migrate() function for libvirt, which is a encapsulation for "virsh migrate" command. Signed-off-by: Tang Chen <tangchen@xxxxxxxxxxxxxx> --- client/virt/libvirt_vm.py | 212 +++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 212 insertions(+), 0 deletions(-) diff --git a/client/virt/libvirt_vm.py b/client/virt/libvirt_vm.py index c825661..773e170 100644 --- a/client/virt/libvirt_vm.py +++ b/client/virt/libvirt_vm.py @@ -293,6 +293,36 @@ def virsh_domain_exists(name, uri = ""): logging.warning("VM %s does not exist", name) return False +def virsh_migrate(name, migrate_cmd, params = None, uri = ""): + """ + Migrate a guest to another host. + + @params name: VM name + @params migrate_cmd: Migrate command to be executed + @param params: A dict containing VM params + """ + uri_arg = "" + if uri: + uri_arg = "-c " + uri + destpwd = params.get("destpwd") + destuser = params.get("destuser") + try: + cmd = "virsh %s %s" % (uri_arg, migrate_cmd) + session = aexpect.ShellSession(cmd, linesep="\n") + virt_utils._remote_login(session, destuser, destpwd, "", timeout=60) + return True + # If migration succeeds, migrate command will terminate the session + # automically. So we have to catch the LoginProcessTerminatedError. + except virt_utils.LoginProcessTerminatedError, e: + logging.info("%s", e) + session.close() + if str(e).find("status: 0") >= 0: + return True + else: + return False + except error.CmdError: + logging.error("Migrating VM %s failed", name) + return False class VM(virt_vm.BaseVM): """ @@ -978,6 +1008,188 @@ class VM(virt_vm.BaseVM): fcntl.lockf(lockfile, fcntl.LOCK_UN) lockfile.close() + def __make_migrate_command(self, name=None, params=None): + """ + Generate a migrate command line. + + @param name: The name of the object + @param params: A dict containing VM params + + @note: The params dict should contain: + live -- yes/no + method -- direct/p2p/p2p_tunnelled + persistent -- yes/no + undefinesource -- yes/no + suspend -- yes/no + copy-storage -- all/inc + change-protection -- yes/no + verbose -- /yes/no + domain -- VM name + desturi -- Destination URI + migrateuri -- Migration URI + dname -- VM name on destination + timeout -- timeout > 0 + xml -- Path to xml file to be used on destination + """ + def add_live(): + return " --live" + + def add_method(method): + if method == "direct": + return " --direct" + elif method == "p2p": + return " --p2p" + # Cannot use --tunnelled without --p2p. + elif method == "p2p_tunnelled": + return " --p2p --tunnelled" + else: + logging.warning("Unknown migrate method, using default.") + return "" + + def add_persistent(): + return " --persistent" + + def add_undefinesource(): + return " --undefinesource" + + def add_suspend(): + return " --suspend" + + def add_copy_storage(copy_storage_mode): + if copy_storage_mode == "all": + return " --copy-storage-all" + elif copy_storage_mode == "inc": + return " --copy-storage-inc" + else: + logging.warning("Unknown copy storage mode, using default.") + return "" + + def add_change_protection(): + return " --change-protection" + + def add_verbose(): + return " --verbose" + + # Domain name must be specified. + def add_domain(domain_name): + if virsh_domain_exists(domain_name): + return " --domain %s" % domain_name + else: + raise virt_vm.VMMigrateError("Wrong domain name.") + + # Destination uri must be specified. + def add_desturi(desturi): + if desturi: + return " --desturi %s" % desturi + else: + raise virt_vm.VMMigrateError("Wrong destination uri.") + + def add_migrateuri(migrateuri): + if migrateuri: + return " --migrateuri %s" % migrateuri + else: + return "" + + def add_dname(dname): + if dname: + return " --dname %s" % dname + else: + return "" + + def add_timeout(timeout): + if int(timeout) > 0: + return " --timeout %s" % timeout + else: + logging.warning("Invalid timeout value. Ingoring it.") + return "" + + def add_xml(xml_file): + if os.path.isfile(xml_file): + return " --xml %s" % xml_file + else: + logging.warning("%s: No such xml file is found. Ingoring it.", xml_file) + return "" + + migrate_cmd = "migrate " + + if name is None: + name = self.name + if params is None: + params = self.params + + live = params.get("live") + if live == "yes": + migrate_cmd += add_live() + + method = params.get("method") + if method: + migrate_cmd += add_method(method) + + persistent = params.get("persistent") + if persistent == "yes": + migrate_cmd += add_persistent() + + undefinesource = params.get("undefinesource") + if undefinesource == "yes": + migrate_cmd += add_undefinesource() + + suspend = params.get("suspend") + if suspend == "yes": + migrate_cmd += add_suspend() + + copy_storage_mode = params.get("copy_storage_mode") + if copy_storage_mode: + migrate_cmd += add_copy_storage(copy_storage_mode) + + change_protection = params.get("change_protection") + if change_protection == "yes": + migrate_cmd += add_change_protection() + + verbose = params.get("verbose") + if verbose == "yes": + migrate_cmd += add_verbose() + + # --domain and --desturi must be specified. + domain_name = params.get("main_vm") + if domain_name: + migrate_cmd += add_domain(domain_name) + + desturi = params.get("desturi") + if desturi: + migrate_cmd += add_desturi(desturi) + + migrateuri = params.get("migrateuri") + if migrateuri: + migrate_cmd += add_migrateuri(migrateuri) + + dname = params.get("dname") + if dname: + migrate_cmd += add_dname(dname) + + timeout = params.get("timeout") + if timeout: + migrate_cmd += add_timeout(timeout) + + xml_file = params.get("xml_file") + if xml_file: + migrate_cmd += add_xml(xml_file) + + logging.info("Migrate command: %s" % migrate_cmd) + return migrate_cmd + + def migrate(self, name=None): + """ + Migrate a VM to a remote host. + """ + migrate_cmd = "" + + migrate_cmd = self.__make_migrate_command(name, self.params) + + ret = virsh_migrate(self.name, migrate_cmd, self.params, self.connect_uri) + if ret == True: + return True + else: + return False def destroy(self, gracefully=True, free_mac_addresses=True): """ -- 1.7.3.1 -- Best Regards, Tang chen -- 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