Hello Chris, 
     Please find the improved patch for adding to libvirt - support 
for running tests with multiple VMs without interfering with
other VM resources. Please let me know if there are any issues- 
my security patches are based on this - 

>From 5cff67ca3f004381ddcbe862ce20ae6894bb742e Mon Sep 17 00:00:00 2001
From: Onkar N Mahajan <onkar.n.maha...@linux.vnet.ibm.com>
Date: Tue, 26 Jun 2012 22:31:11 +0530
Subject: [PATCH] Libvirt-Autotest: Support for running multiple guest
 (Improved) Signed-off-by: Onkar N Mahajan
 <onkar.n.maha...@linux.vnet.ibm.com>

---
 client/tests/libvirt/tests-shared.cfg.sample |   12 +-
 client/virt/libvirt_vm.py                    |  159 +++++++++++++++++++++++++-
 client/virt/virt_utils.py                    |   38 +++++--
 client/virt/virt_vm.py                       |   54 +++++++++-
 4 files changed, 246 insertions(+), 17 deletions(-)

diff --git a/client/tests/libvirt/tests-shared.cfg.sample 
b/client/tests/libvirt/tests-shared.cfg.sample
index 1fe0894..64cf516 100644
--- a/client/tests/libvirt/tests-shared.cfg.sample
+++ b/client/tests/libvirt/tests-shared.cfg.sample
@@ -28,13 +28,13 @@ include virtio-win.cfg
 # * The parameters cdrom_unattended, floppy, kernel and initrd are generated
 #   by LIBVIRT autotest, so remember to put them under a writable location
 #   (for example, the cdrom share can be read only)
-image_name(_.*)? ?<= /tmp/libvirt_autotest_root/images/
-cdrom(_.*)? ?<= /tmp/libvirt_autotest_root/
-floppy ?<= /tmp/libvirt_autotest_root/
-image_dir = /tmp/libvirt_autotest_root/
+image_name(_.*)? ?<= /tmp/libvirt_autotest_root/$main_vm/
+cdrom(_.*)? ?<= /tmp/libvirt_autotest_root/$main_vm/
+floppy ?<= /tmp/libvirt_autotest_root/$main_vm/
+image_dir = /tmp/libvirt_autotest_root/$main_vm/
 Linux..unattended_install:
-    kernel ?<= /tmp/libvirt_autotest_root/
-    initrd ?<= /tmp/libvirt_autotest_root/
+    kernel ?<= /tmp/libvirt_autotest_root/$main_vm/
+    initrd ?<= /tmp/libvirt_autotest_root/$main_vm/
 
 # Uncomment the following lines to enable abort-on-error mode:
 #abort_on_error = yes
diff --git a/client/virt/libvirt_vm.py b/client/virt/libvirt_vm.py
index d97ac0c..df9fd9b 100644
--- a/client/virt/libvirt_vm.py
+++ b/client/virt/libvirt_vm.py
@@ -461,6 +461,156 @@ def virsh_detach_device(name, xml_file, extra="", uri=""):
         logging.error("Detaching device from VM %s failed." % name)
         return False
 
+def virsh_vncdisplay(name, uri=""):
+    """
+    Returns the VNC display information for the domain
+    Returns : [ <IP>, <port> ]
+    """
+
+    cmd = "vncdisplay %s" % name
+    try:
+        cmdresult = virsh_cmd(cmd, uri).stdout.strip()
+        # Match IP|'':<port>
+        m = re.search('^((?:25[0-]|2[0-4][0-9]|[01]?[0-9][0-9]?\.){3}'
+                      '(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))?\:(\d+)',
+                       cmdresult)
+        ip = m.group(1)
+        if ip == None:
+            ip = "0.0.0.0"
+        vncinfo = [ ip, m.group(2)]
+        return vncinfo
+    except error.CmdError, details:
+        out = str(details)
+        if out.strip() == "":
+            domxml = virsh_dumpxml(self.name, self.connect_uri)
+            dom = minidom.parseString(domxml)
+            if dom.getElementsByTagName('graphics'):
+                display = node.childNodes[0]
+                ap = display.attributes["autoport"]
+                if ap.value =="yes":
+                    # VNC display configured with autoport='yes'
+                    return ["0.0.0.0", -1]
+                else:
+                    raise virt_vm.UnsupportedDisplayError(self.name, "vnc")
+        raise virt_vm.LibvirtVirshCmdError(name, cmd, uri, details)
+
+
+def virsh_list(option="--all", uri = ""):
+    """
+    - list domains -
+    @param option: Can take various values see 'virsh help list'
+                   for more details.
+    @param uri   : connect uri
+
+    Returns a list :
+    Returns dictionary with each entry
+    as : <'dom-name'>: [ <dom-id> , <dom-status> ]
+
+    """
+    cmd = "list %s" % option
+    try:
+        cmd_res = virsh_cmd(cmd, uri).stdout.strip()
+        d = {}
+        for line in cmd_res.split("\n"):
+            l = []
+            m = re.search('^\s([0-9]*\-?)\s+([0-9a-zA-Z\.-_]+)\s+(.*)', line)
+            if m:
+                l.append(m.group(1))
+                l.append(m.group(3))
+                d[m.group(2)] = l
+        return d
+    except error.CmdError, details:
+        raise virt_vm.LibvirtVirshCmdError(virsh_cmd=cmd, connuri=uri,
+        details=details)
+
+
+def list_all_domains(uri, option="--all"):
+    """
+    Returns list of domains for the uri
+    """
+    try:
+        val = virsh_list(option, uri)
+        return val
+    except virt_vm.LibvirtVirshCmdError:
+        raise virt_vm.LibvirtFailedGettingInfoError(connuri=uri)
+
+
+def get_graphics_info(name, uri, displaytype):
+    """
+    Returns Graphics display Information configured for a given
+    domain.
+    ** Currently supports only VNC display **
+    """
+    if displaytype == "vnc":
+        try:
+            """
+            Add virsh functions to get graphics information
+            here.
+            """
+            vncinfo = virsh_vncdisplay(name, uri)
+            if vncinfo:
+                ip = vncinfo[0]
+                port = vncinfo[1]
+                return [ip, port]
+        except virt_vm.UnsupportedDisplayError:
+            raise NotImplementedError("Only VMs with VNC"
+                                          "displays are supported")
+        except virt_vm.LibvirtVirshCmdError:
+           raise virt_vm.LibvirtFailedGettingInfoError(name, uri)
+
+
+def get_free_port(name, uri, type, startport, endport):
+    """
+    Get first free port available for a given application.
+    ** Currently supports only VNC **
+    Returns : port (>0) : success
+              -1        : Failure
+    """
+    if type == "vnc":
+        val={}
+        assigned_ports=[]
+        maxport = 0
+        port = 0
+        try:
+            val = list_all_domains(uri)
+        except virt_vm.LibvirtFailedGettingInfoError:
+            logging.error("Failed to get domains information for "
+                          "%s" % (self.connect_uri))
+            return -1
+        for key in val.keys():
+            try:
+                vncinfo = get_graphics_info(key, uri, type)
+                p = int(vncinfo[1])
+                if p >= startport:
+                    p = p-int(startport)
+                if p >= maxport:
+                    maxport = p
+                assigned_ports.append(p)
+            except (virt_vm.LibvirtFailedGettingInfoError,
+                    NotImplementedError):
+                logging.error("Failed to get information for VM %s "
+                              "at URI %s" % (name, uri))
+                return -1
+        cmd = "vncserver -list | grep ^:[0-9]* | cut -c1-4"
+        cmd_result = str(utils.run(cmd))
+        for line in cmd_result.split("\n"):
+            m = re.search('^:(\d)\s*$', line)
+            if m:
+                vncsp = m.group(1)
+                vncserverport =  int(vncsp)
+                if vncserverport >= maxport:
+                    maxport = vncserverport
+                assigned_ports.append(vncserverport)
+        for p in range(0,endport-startport):
+            if not p in assigned_ports:
+                port = p
+                if virt_utils.find_free_port(port,port+1):
+                    break
+                else:
+                    continue
+        port += startport
+        return port
+
 
 class VM(virt_vm.BaseVM):
     """
@@ -485,6 +635,7 @@ class VM(virt_vm.BaseVM):
             self.process = None
             self.serial_console = None
             self.redirs = {}
+            self.displaytype= None
             self.vnc_port = 5900
             self.vnclisten = "0.0.0.0"
             self.pci_assignable = None
@@ -934,6 +1085,7 @@ class VM(virt_vm.BaseVM):
             virt_install_cmd += add_location(help, location)
 
         if params.get("display") == "vnc":
+            self.displaytype = "vnc"
             if params.get("vnc_port"):
                 vm.vnc_port = int(params.get("vnc_port"))
             virt_install_cmd += add_vnc(help, vm.vnc_port)
@@ -941,8 +1093,10 @@ class VM(virt_vm.BaseVM):
                 vm.vnclisten = params.get("vnclisten")
             virt_install_cmd += add_vnclisten(help, vm.vnclisten)
         elif params.get("display") == "sdl":
+            self.displaytype = "sdl"
             virt_install_cmd += add_sdl(help)
         elif params.get("display") == "nographic":
+            self.displaytype = "nographic"
             virt_install_cmd += add_nographic(help)
 
         video_device = params.get("video_device")
@@ -1188,7 +1342,10 @@ class VM(virt_vm.BaseVM):
 
             # Find available VNC port, if needed
             if params.get("display") == "vnc":
-                self.vnc_port = virt_utils.find_free_port(5900, 6100)
+                self.displaytype = "vnc"
+                port = get_free_port(self.name, self.connect_uri, 
self.displaytype,
+                                  5900, 6100)
+                self.vnc_port = port
 
             # Find available spice port, if needed
             if params.get("spice"):
diff --git a/client/virt/virt_utils.py b/client/virt/virt_utils.py
index 1c4d90d..5079cbb 100644
--- a/client/virt/virt_utils.py
+++ b/client/virt/virt_utils.py
@@ -3889,14 +3889,36 @@ def virt_test_assistant(test_name, test_dir, base_dir, 
default_userspace_paths,
     logging.info("%d - Verifying directories (check if the directory structure 
"
                  "expected by the default test config is there)", step)
     sub_dir_list = ["images", "isos", "steps_data"]
-    for sub_dir in sub_dir_list:
-        sub_dir_path = os.path.join(base_dir, sub_dir)
-        if not os.path.isdir(sub_dir_path):
-            logging.debug("Creating %s", sub_dir_path)
-            os.makedirs(sub_dir_path)
-        else:
-            logging.debug("Dir %s exists, not creating" %
-                          sub_dir_path)
+
+    if test_name == 'libvirt':
+        base_fl = "%s/%s" % (test_dir, "base.cfg")
+        if not os.path.isfile(base_fl):
+            base_fl = "%s/%s" % (common_dir, "base.cfg.sample")
+        cmd = "cat %s | grep \"^main_vm\s=\s.*\" | cut -d \"=\" -f 2|sed 
's/[^\w]//'" % base_fl
+        try:
+            vmdir = utils.run("%s" % cmd).stdout
+        except error.CmdError, detail:
+            logging.error("Failed to fetch 'main_vm' parameter from base.cfg 
:%s", detail)
+            sys.exit(1)
+        base_dir = "%s/%s" % (base_dir, vmdir.strip())
+        for sub_dir in sub_dir_list:
+            sub_dir_path = os.path.join(base_dir, sub_dir)
+            if not os.path.isdir(sub_dir_path):
+                logging.debug("Creating %s", sub_dir_path)
+                os.makedirs(sub_dir_path)
+            else:
+                logging.debug("Dir %s exists, not creating" %
+                              sub_dir_path)
+    else:
+        for sub_dir in sub_dir_list:
+            sub_dir_path = os.path.join(base_dir, sub_dir)
+            if not os.path.isdir(sub_dir_path):
+                logging.debug("Creating %s", sub_dir_path)
+                os.makedirs(sub_dir_path)
+            else:
+                logging.debug("Dir %s exists, not creating" %
+                              sub_dir_path)
+
     logging.info("")
     step += 1
     logging.info("%d - Creating config files from samples (copy the default "
diff --git a/client/virt/virt_vm.py b/client/virt/virt_vm.py
index 534f8e3..201992d 100644
--- a/client/virt/virt_vm.py
+++ b/client/virt/virt_vm.py
@@ -1,8 +1,8 @@
-import logging, time, glob, re
+import os, logging, time, glob, re, shutil, string
 from autotest.client.shared import error
+from autotest.client import utils
 import virt_utils, virt_remote
 
-
 class VMError(Exception):
     pass
 
@@ -312,6 +312,56 @@ class VMUSBControllerPortFullError(VMUSBControllerError):
     def __str__(self):
         return ("No available USB Controller port left for VM %s." % self.name)
 
+class VMDisplayError(VMError):
+    pass
+
+class UnsupportedDisplayError(VMDisplayError):
+    def __init__(self, name, display):
+        VMDisplayError.__init__(self, name, displaytype)
+        self.name = name
+        self.display = displaytype
+   
+    def __str__(self):
+        return ("%s display not supported for this VM '%s' on this host." %
+              (string.upper(self.display), self.name))
+
+"""
+Libvirt error handling starts below.
+"""
+
+class LibvirtError(Exception):
+    pass
+
+class LibvirtFailedGettingInfoError(LibvirtError):
+    def __init__(self, name, connuri):
+        LibvirtError.__init__(self, name, connuri)
+        self.name = name
+        self.uri = connuri
+
+    def __str__(self, name=None, uri =""):
+       if self.name:
+           return ("Libvirt failed to get information for VM '%s' at"
+                   " connection URI '%s'" % (self.name, self.uri))
+       else:
+           return ("Libvirt failed to get information for "
+                   "connection '%s' : %s" % (self.uri))
+
+class LibvirtVirshCmdError(LibvirtError):
+    def __init__(self, name, virsh_cmd, connuri, details=""):
+        LibvirtError.__init__(self, name, virsh_cmd, connuri, details)
+        self.virshcmd = virsh_cmd
+        self.name = name
+        self.uri = connuri
+        self.details = details
+
+    def __str__(self):
+        if self.name :
+            return ("Error executing command '%s' for VM '%s' at"
+                    " connection URI '%s' : "
+                    "%s" % (self.virshcmd, self.name, self.uri, self.details))
+        else:
+            return ("Error in executing commmand '%s' for connect URI"
+                    " %s : %s" % (self.virshcmd, self.uri, self.details))
 
 class BaseVM(object):
     """
-- 
1.7.4.4


On Mon, 2012-06-11 at 11:10 -0400, Chris Evich wrote: 
> On 06/11/2012 09:30 AM, Pradeep Kumar Surisetty wrote:
> > * Chris Evich<cev...@redhat.com>  [2012-06-08 10:45:29]:
> >
> >> On 06/08/2012 02:06 AM, Onkar N Mahajan wrote:
> >>> On Thu, 2012-06-07 at 10:52 -0400, Chris Evich wrote:
> >>>> On 06/07/2012 04:46 AM, Onkar N Mahajan wrote:
> >>> See, I have tried making nxt_free_vnc_port() available for general usage
> >>> (vnc/spice/etc) as you mentioned , but this requires virsh to have
> >>> vncdisplay counterparts to spice/etc - which AFAIK are currently not
> >>> available.
> >>
> >> Annoyingly, it must be extracted from the xml :(  However, you're right
> >> in that virsh only has a vncdisplay command.  Along those lines, how
> >> about adding a lower-level and more generic virsh_vncdisplay() function
> >> that returns the port and ip address?
> >>
> >> I'd like the the vm class methods to support a wider usage, even if all
> >> the capabilities aren't there immediately.  When possible, methods
> >> should not be tied closely to underlying implementation details.
> >>
> >> For example with graphics, I'd prefer a vm.graphics_info() (or similar
> >> name) method provides details independent of the underlying graphics
> >> device type.  But it's perfectly acceptable if support for other types
> >> gets added at a later date, and it just throws exceptions for the stubs.
> >>
> >> With this deign, we can easily extend the tests (later) by adding
> >> support for additional graphics.  It also allows for extending the
> >> underlying support w/o disturbing the callers.  Make sense?
> 
> Code example of the above:
> 
> virsh_vncdisplay(name, uri=""):
>      ...
>      if cmdresult.exit_status:
>          ... # other checks
>          raise virt_vm.UnsupportedDisplayError("VM %s doesn't use vnc"
>                                                "graphics" % name)
> 
> class VM(virt_vm.BaseVM):
>      ...
>      def graphics_info(self):
>          d={}
>          # only VNC graphics supported for now
>          try:
>              vncinfo=virsh_vncdisplay(...)
>              d["ip"] = vncinfo[0]
>              d["port"] = vncinfo[1]
>          except virt_vm.UnsupportedDisplayError:
>              raise virt_vm.NotImplementedError("Only VMs with VNC
>                                                displays are supported")
>          return d
> 
> In this way, we can easily add spice or whatever support to 
> vm.graphics_info (or whatever name) later w/o affecting callers.  If a 
> test needs to specifically only deal with VM's using VNC, they can just 
> call virst_vncdisplay directly.  It also supports error testing in a 
> generic way by calling vm.graphics_info() and checking making sure it 
> does NOT raise UnsupportedDisplayError or NotImplementedError (presuming 
> bad guest XML raises a different exception).
> 

-- 
Onkar N Mahajan
System Software Engineer,
IBM Linux Technology Center,
Bangalore,India

_______________________________________________
Autotest mailing list
Autotest@test.kernel.org
http://test.kernel.org/cgi-bin/mailman/listinfo/autotest

Reply via email to