virsh command "domxml-from-native" is used to convert qemu commandline generated into corresponding libvirt xml file. :domxml-from-native" is not able to parse the network parameters in qemu commandline correctly, so a base xml file with default network parameters is created at first and later modified based on qemu network parameters passed. The function virsh_login in virt_utils.py provides access to hypervisor's virsh shell
Signed-off-by: Yogananth Subramanian <[email protected]> --- client/virt/kvm_vm.py | 145 +++++++++++++++++++++++++++++++++++++++++---- client/virt/virt_utils.py | 26 ++++++++ 2 files changed, 160 insertions(+), 11 deletions(-) diff --git a/client/virt/kvm_vm.py b/client/virt/kvm_vm.py index a2f22b4..e9db86a 100644 --- a/client/virt/kvm_vm.py +++ b/client/virt/kvm_vm.py @@ -4,7 +4,8 @@ Utility classes and functions to handle Virtual Machine creation using qemu. @copyright: 2008-2009 Red Hat Inc. """ -import time, os, logging, fcntl, re, commands, glob +import time, os, logging, fcntl, re, commands, glob, tempfile +from xml.dom.minidom import parse from autotest_lib.client.common_lib import error from autotest_lib.client.bin import utils import virt_utils, virt_vm, virt_test_setup, kvm_monitor, aexpect @@ -43,6 +44,7 @@ class VM(virt_vm.BaseVM): self.device_id = [] self.tapfds = [] self.uuid = None + self.virsh = False self.spice_port = 8000 @@ -80,7 +82,20 @@ class VM(virt_vm.BaseVM): """ Return True if the qemu process is dead. """ - return not self.process or not self.process.is_alive() + if self.virsh: + virt=virt_utils.virsh_login(self.virsh_password, self.virsh_prompt, + self.virsh_hostname,self.virsh_driver,self.virsh_username) + if re.findall("Domain not found|shut off",virt.get_command_output( + 'domstate %s'%self.name)): + virt.sendline("undefine %s;quit"%self.name) + return True + else: + virt.sendline('quit') + return False + elif not self.process or not self.process.is_alive(): + return True + else: + return False def verify_status(self, status): @@ -779,9 +794,105 @@ class VM(virt_vm.BaseVM): qemu_command += (' -incoming "exec:nc -l %s"' % self.migration_port) - logging.info("Running qemu command:\n%s", qemu_command) - self.process = aexpect.run_bg(qemu_command, None, - logging.info, "(qemu) ") + if params.get("virsh") == "yes": + self.virsh = True + else: + self.virsh = False + + if self.virsh: + self.qemu_command = qemu_command + qemu_format = re.sub("'", '', qemu_command) + net_info = re.findall('-(device|netdev) ([^\s]+)', qemu_format) + qemu_format = re.sub('-(device|netdev|monitor|serial) ([^\s]+)' + , '', qemu_format) + qemu_format = qemu_format+" -net nic -net tap" + args_tmp = tempfile.mkdtemp(prefix='qemu_', dir='/tmp') + qemu_args = os.path.join(args_tmp, self.name+".args") + f = open(qemu_args, 'w') + f.write(qemu_format) + f.close() + self.virsh_driver = params.get("virsh_driver") + self.virsh_hostname = params.get("virsh_hostname") + self.virsh_username = params.get("virsh_username") + self.virsh_password = params.get("virsh_password") + self.virsh_prompt = params.get("virsh_prompt") + self.virsh_cmd = "virsh --connect %s+ssh://%s@%s/system" % ( + self.virsh_driver, self.virsh_username, + self.virsh_hostname) + virt = virt_utils.virsh_login(self.virsh_password, + self.virsh_prompt, self.virsh_hostname, + self.virsh_driver, self.virsh_username) + virt_tmp = tempfile.mkdtemp(prefix='virt_', dir='/tmp') + virt_xml = os.path.join(virt_tmp, self.name+".xml") + xml_create = "virsh domxml-from-native qemu-argv %s > %s"%( + qemu_args, virt_xml) + data = os.popen(xml_create).readlines() + xml_handle = open(virt_xml) + xml_pars = parse(xml_handle) + xml_pars.normalize() + + xml_nod = xml_pars.getElementsByTagName('os')[0] + chld_elem = xml_nod.getElementsByTagName("type")[0] + chld_elem.setAttribute('arch','x86_64') + xml_nod = xml_pars.getElementsByTagName('interface')[0] + xml_nod.setAttribute('type', 'network') + xml_sib = xml_pars.getElementsByTagName('interface')[0].\ + nextSibling + + xml_clnod = xml_nod.cloneNode(True) + net_dic = dict(re.findall("(netdev|mac|id)=([^,\s]+)", dict( + net_info)['device'])) + net_model = re.findall("(^\S+?),", dict(net_info)['device'])[0] + chld_elem = xml_clnod.getElementsByTagName("mac")[0] + chld_elem.setAttribute('address', net_dic['mac']) + new_nod = chld_elem.cloneNode(True) + new_nod.setAttribute('type', net_model) + new_nod.removeAttribute('address') + new_nod.tagName = "model" + xml_clnod.appendChild(new_nod) + + new_nod = chld_elem.cloneNode(True) + new_nod.setAttribute('network','default') + new_nod.removeAttribute('address') + new_nod.tagName = "source" + xml_clnod.appendChild(new_nod) + + new_nod = chld_elem.cloneNode(True) + new_nod.setAttribute('dev', net_dic['id']) + new_nod.removeAttribute('address') + new_nod.tagName = "target" + xml_clnod.appendChild(new_nod) + + xml_nod.parentNode.insertBefore(xml_clnod, xml_sib) + xml_nod.parentNode.removeChild(xml_nod) + + + + tmp_xml = xml_pars.toxml() + virt_xml = os.path.join(virt_tmp, "virt_"+self.name+".xml") + f = open(virt_xml,'w') + f.write(tmp_xml) + f.close() + + self.process = virt_utils.virsh_login(self.virsh_password, + self.virsh_prompt, self.virsh_hostname, + self.virsh_driver, self.virsh_username) + virt.sendline("define %s \n" % virt_xml) + logging.debug("Defining virsh with xml:\n%s" % virt_xml) + virt.sendline("start %s \n" % self.name) + start_output=virt.get_command_output("\n") + if "error:" in start_output: + e = virt_vm.VMCreateError("virsh start", "defined", + start_output) + virt.sendline("undefine %s" % self.name) + self.destroy() + raise e + + virt.sendline('quit') + else: + logging.debug("Running qemu command:\n%s"% qemu_command) + self.process = aexpect.run_bg(qemu_command, None, + logging.debug, "(qemu) ") for tapfd in self.tapfds: try: os.close(tapfd) @@ -810,11 +921,16 @@ class VM(virt_vm.BaseVM): monitor = kvm_monitor.QMPMonitor( monitor_name, self.get_monitor_filename(monitor_name)) - else: + if monitor_params.get("monitor_type") == "human": # Add a "human" monitor monitor = kvm_monitor.HumanMonitor( monitor_name, self.get_monitor_filename(monitor_name)) + else: + monitor = kvm_monitor.VirshMonitor( + monitor_name, self.name,self.virsh_password, + self.virsh_prompt, self.virsh_hostname, + self.virsh_driver, self.virsh_username) monitor.verify_responsive() break except kvm_monitor.MonitorError, e: @@ -844,11 +960,18 @@ class VM(virt_vm.BaseVM): # Establish a session with the serial console -- requires a version # of netcat that supports -U - self.serial_console = aexpect.ShellSession( - "nc -U %s" % self.get_serial_console_filename(), - auto_close=False, - output_func=virt_utils.log_line, - output_params=("serial-%s.log" % name,)) + if self.virsh: + self.serial_console = aexpect.ShellSession( + "virsh console %s" %self.name, + auto_close=False, + output_func=virt_utils.log_line, + output_params=("serial-%s.log" % name,)) + else: + self.serial_console = aexpect.ShellSession( + "nc -U %s" % self.get_serial_console_filename(), + auto_close=False, + output_func=virt_utils.log_line, + output_params=("serial-%s.log" % name,)) finally: fcntl.lockf(lockfile, fcntl.LOCK_UN) diff --git a/client/virt/virt_utils.py b/client/virt/virt_utils.py index d443a84..750b87e 100644 --- a/client/virt/virt_utils.py +++ b/client/virt/virt_utils.py @@ -669,6 +669,32 @@ def _remote_login(session, username, password, prompt, timeout=10): except aexpect.ExpectProcessTerminatedError, e: raise LoginProcessTerminatedError(e.status, e.output) +def virsh_login( password, prompt, host='localhost', driver='qemu', + username='root', linesep="\n", timeout=10): + """ + Log into a remote host (hypervisor) using required URIs . + + @param password: Password + @param prompt: Shell prompt (regular expression) + @param host: Hostname or IP address + @param driver: Hypervisor driver + @param username: Username + @param linesep: The line separator to use when sending lines + (e.g. '\\n' or '\\r\\n') + @timeout: Time in seconds that we will wait before giving up on logging + into the host. + @return: A ShellSession object. + """ + if driver == "qemu": + command = "virsh --connect %s+ssh://%s@%s/system" % (driver, username, + host) + session = aexpect.ShellSession(command, linesep=linesep, prompt=prompt) + try: + _remote_login(session, username, password, prompt, timeout) + except: + session.close() + return session + def remote_login(client, host, port, username, password, prompt, linesep="\n", log_filename=None, timeout=10): -- 1.7.0.4 _______________________________________________ Autotest mailing list [email protected] http://test.kernel.org/cgi-bin/mailman/listinfo/autotest
