[virt-tools-list] [PATCH 1/3 version 2] Add inspection thread.

Richard W.M. Jones rjones at redhat.com
Tue Apr 19 13:58:02 UTC 2011


On Tue, Apr 19, 2011 at 12:01:41PM +0100, Richard W.M. Jones wrote:
> +        for disk in vm.get_disk_devices():
> +            path = disk.path
> +            driver_type = disk.driver_type
> +            g.add_drive_opts(path, readonly=1, format=driver_type)

Oops - turns out that if the VM has any disks without <source/>
elements (eg. CD-ROMs), then path == None here.  The updated patch
attached fixed this.

Rich.

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
libguestfs lets you edit virtual machines.  Supports shell scripting,
bindings from many languages.  http://libguestfs.org
-------------- next part --------------
>From 09bf45216bc703e1bdd7d300e17321cfc9a26497 Mon Sep 17 00:00:00 2001
From: Richard W.M. Jones <rjones at redhat.com>
Date: Tue, 19 Apr 2011 10:42:55 +0100
Subject: [PATCH] Add inspection thread.

This commit adds an inspection daemon thread which performs libguestfs
inspection on domains when they first appear in the manager UI.

python-guestfs is not required.
---
 src/virtManager/config.py     |   25 +++++++++
 src/virtManager/engine.py     |   15 +++++
 src/virtManager/inspection.py |  121 +++++++++++++++++++++++++++++++++++++++++
 src/virtManager/manager.py    |    3 +
 4 files changed, 164 insertions(+), 0 deletions(-)
 create mode 100644 src/virtManager/inspection.py

diff --git a/src/virtManager/config.py b/src/virtManager/config.py
index f2dfd2d..7f3f85c 100644
--- a/src/virtManager/config.py
+++ b/src/virtManager/config.py
@@ -105,6 +105,31 @@ class vmmConfig(object):
         self._objects = []
 
         self.support_threading = virtinst.support.support_threading()
+
+        # Check that we have the guestfs module with the non-broken
+        # support for Python threads.  Also libvirt must be
+        # thread-safe too.
+        self.support_inspection = False
+        if self.support_threading:
+            try:
+                from guestfs import GuestFS
+                g = GuestFS()
+                version = g.version()
+                if version["major"] == 1: # major must be 1
+                    if version["minor"] == 8:
+                        if version["release"] >= 6: # >= 1.8.6
+                            self.support_inspection = True
+                    elif version["minor"] == 10:
+                        if version["release"] >= 1: # >= 1.10.1
+                            self.support_inspection = True
+                    elif version["minor"] == 11:
+                        if version["release"] >= 2: # >= 1.11.2
+                            self.support_inspection = True
+                    elif version["minor"] >= 12:    # >= 1.12.x
+                        self.support_inspection = True
+            except:
+                pass
+
         self._spice_error = None
 
         self.status_icons = {
diff --git a/src/virtManager/engine.py b/src/virtManager/engine.py
index 39a37cd..2484656 100644
--- a/src/virtManager/engine.py
+++ b/src/virtManager/engine.py
@@ -239,6 +239,9 @@ class vmmEngine(vmmGObject):
         if not self.config.support_threading:
             logging.debug("Libvirt doesn't support threading, skipping.")
 
+        self.inspection_thread = None
+        self._create_inspection_thread()
+
         # Counter keeping track of how many manager and details windows
         # are open. When it is decremented to 0, close the app or
         # keep running in system tray if enabled
@@ -533,6 +536,18 @@ class vmmEngine(vmmGObject):
         logging.debug("Exiting app normally.")
         gtk.main_quit()
 
+    def _create_inspection_thread(self):
+        if not self.config.support_inspection:
+            logging.debug("No inspection thread because "
+                          "libguestfs is too old, not available, "
+                          "or libvirt is not thread safe.")
+            return
+        from virtManager.inspection import vmmInspection
+        self.inspection_thread = vmmInspection()
+        self.inspection_thread.daemon = True
+        self.inspection_thread.start()
+        return
+
     def add_connection(self, uri, readOnly=None, autoconnect=False):
         conn = self._check_connection(uri)
         if conn:
diff --git a/src/virtManager/inspection.py b/src/virtManager/inspection.py
new file mode 100644
index 0000000..d5788f4
--- /dev/null
+++ b/src/virtManager/inspection.py
@@ -0,0 +1,121 @@
+#
+# Copyright (C) 2011 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+# MA 02110-1301 USA.
+#
+
+import sys
+import time
+import traceback
+from Queue import Queue
+from threading import Thread
+
+from guestfs import GuestFS
+
+import logging
+import util
+
+class vmmInspection(Thread):
+    _name = "inspection thread"
+    _wait = 15 # seconds
+
+    def __init__(self):
+        Thread.__init__(self, name=self._name)
+        self._q = Queue()
+        self._vmseen = dict()
+
+    # Called by the main thread whenever a VM is added to vmlist.
+    def vm_added(self, connection, vmuuid):
+        obj = (connection, vmuuid)
+        self._q.put(obj)
+
+    def run(self):
+        # Wait a few seconds before we do anything.  This prevents
+        # inspection from being a burden for initial virt-manager
+        # interactivity (although it shouldn't affect interactivity at
+        # all).
+        logging.debug("%s: waiting" % self._name)
+        time.sleep(self._wait)
+
+        logging.debug("%s: ready" % self._name)
+
+        while True:
+            obj = self._q.get(True)
+            (connection, vmuuid) = obj
+
+            logging.debug("%s: processing started on '%s'" %
+                          (self._name, vmuuid))
+            try:
+                self._process(connection, vmuuid)
+            except:
+                logging.debug("%s: exception while processing '%s':\n%s" %
+                              (self._name, vmuuid, traceback.format_exc()))
+
+            self._q.task_done()
+            logging.debug("%s: processing done on '%s'" %
+                          (self._name, vmuuid))
+
+    def _process(self, connection, vmuuid):
+        if not connection or connection.is_remote():
+            logging.debug("%s: %s: no connection object or "
+                          "connection is remote" % (self._name, vmuuid))
+            return
+        vm = connection.get_vm(vmuuid)
+
+        # If we've already inspected this VM, don't do it again.  Note
+        # that we must filter here (not before adding to the queue in
+        # the main thread) because of the case where the VM has
+        # already been enqueued but the results are not yet in the
+        # cache.
+        if vmuuid in self._vmseen: return
+
+        xml = vm.get_xml()
+
+        # Add the disks.  Note they *must* be added with readonly flag set.
+        g = GuestFS()
+        for disk in vm.get_disk_devices():
+            path = disk.path
+            driver_type = disk.driver_type
+            if path != None:
+                g.add_drive_opts(path, readonly=1, format=driver_type)
+
+        g.launch()
+
+        # Inspect the operating system.
+        roots = g.inspect_os()
+        if len(roots) == 0:
+            logging.debug("%s: %s: no operating systems found" %
+                          (self._name, vmuuid))
+            return
+
+        # Arbitrarily pick the first root device.
+        root = roots[0]
+
+        # Inspection results.
+        typ = g.inspect_get_type(root) # eg. "linux"
+        distro = g.inspect_get_distro(root) # eg. "fedora"
+        major_version = g.inspect_get_major_version(root) # eg. 14
+        minor_version = g.inspect_get_minor_version(root) # eg. 0
+        product_variant = g.inspect_get_product_variant(root) # string
+        hostname = g.inspect_get_hostname(root) # string
+        product_name = g.inspect_get_product_name(root) # string
+
+        # Force the libguestfs handle to close right now.
+        del g
+
+        self._vmseen[vmuuid] = True
+
+        pass
diff --git a/src/virtManager/manager.py b/src/virtManager/manager.py
index 02ebabc..2abca04 100644
--- a/src/virtManager/manager.py
+++ b/src/virtManager/manager.py
@@ -742,6 +742,9 @@ class vmmManager(vmmGObjectUI):
 
         self._append_vm(model, vm, connection)
 
+        if self.engine.inspection_thread:
+            self.engine.inspection_thread.vm_added(connection, vmuuid)
+
     def vm_removed(self, connection, uri_ignore, vmuuid):
         vmlist = self.window.get_widget("vm-list")
         model = vmlist.get_model()
-- 
1.7.4.4



More information about the virt-tools-list mailing list