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
>From 09bf45216bc703e1bdd7d300e17321cfc9a26497 Mon Sep 17 00:00:00 2001 From: Richard W.M. Jones <[email protected]> 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
_______________________________________________ virt-tools-list mailing list [email protected] https://www.redhat.com/mailman/listinfo/virt-tools-list
