commit 6f52a3bbe00121acb5f11d9ec131c90700b27419
Author: Radek Novacek <rnovacek(a)redhat.com>
Date: Tue Jul 1 10:57:58 2014 +0200
libvirtd: use event loop instead of reconnecting all the time
tests/test_libvirtd.py | 24 +++++++-----
virt/libvirtd/libvirtd.py | 86 ++++++++++++++++++++++++--------------------
2 files changed, 61 insertions(+), 49 deletions(-)
---
diff --git a/tests/test_libvirtd.py b/tests/test_libvirtd.py
index 6077702..bb3f428 100644
--- a/tests/test_libvirtd.py
+++ b/tests/test_libvirtd.py
@@ -54,24 +54,28 @@ class TestLibvirtd(unittest.TestCase):
self.assertRaises(VirtError, libvirtd.listDomains)
@patch('libvirt.openReadOnly')
- def test_monitoring(self, virt):
+ @patch('threading.Thread')
+ def test_monitoring(self, thread, virt):
event = threading.Event()
LibvirtMonitor().set_event(event)
- LibvirtMonitor()._prepare()
- LibvirtMonitor()._checkChange()
+ LibvirtMonitor().check()
+
+ thread.assert_called()
virt.assert_called_with('')
- virt.return_value.listDomainsID.assert_called()
- virt.return_value.listDefinedDomains.assert_called()
- virt.return_value.closed.assert_called()
+ virt.return_value.domainEventRegister.assert_called()
+ virt.return_value.setKeepAlive.assert_called()
self.assertFalse(event.is_set())
- virt.return_value.listDomainsID.return_value = [1]
- LibvirtMonitor()._checkChange()
+ LibvirtMonitor()._callback()
+ LibvirtMonitor().check()
self.assertTrue(event.is_set())
event.clear()
- virt.return_value.listDomainsID.return_value = []
- LibvirtMonitor()._checkChange()
+ LibvirtMonitor().check()
+ self.assertFalse(event.is_set())
+ event.clear()
+
+ LibvirtMonitor()._callback()
self.assertTrue(event.is_set())
event.clear()
diff --git a/virt/libvirtd/libvirtd.py b/virt/libvirtd/libvirtd.py
index 1e37759..2b7a3b3 100644
--- a/virt/libvirtd/libvirtd.py
+++ b/virt/libvirtd/libvirtd.py
@@ -29,65 +29,72 @@ import virt
eventLoopThread = None
-class LibvirtMonitor(threading.Thread):
+def virEventLoopNativeRun():
+ while True:
+ libvirt.virEventRunDefaultImpl()
+
+
+class LibvirtMonitor(object):
""" Singleton class that performs background event monitoring.
"""
_instance = None
def __new__(cls, *args, **kwargs):
if not cls._instance:
+ print "Creating new instance of LibvirtMonitor"
cls._instance = super(LibvirtMonitor, cls).__new__(cls, *args, **kwargs)
+ cls._instance.logger = logging.getLogger("rhsm-app")
cls._instance.event = None
+ cls._instance.eventLoopThread = None
cls._instance.terminate = threading.Event()
cls._instance.domainIds = []
cls._instance.definedDomains = []
+ cls._instance.vc = None
return cls._instance
STATUS_NOT_STARTED, STATUS_RUNNING, STATUS_DISABLED = range(3)
def _prepare(self):
- self.logger = logging.getLogger("rhsm-app")
self.running = threading.Event()
self.status = LibvirtMonitor.STATUS_NOT_STARTED
- def run(self):
- self._prepare()
- while not self.terminate.isSet():
- self._checkChange()
- time.sleep(5)
-
- def _checkChange(self):
+ def _loop_start(self):
+ libvirt.virEventRegisterDefaultImpl()
+ if self.eventLoopThread is not None and self.eventLoopThread.isAlive():
+ self.eventLoopThread.terminate()
+ self.eventLoopThread = threading.Thread(target=virEventLoopNativeRun,
name="libvirtEventLoop")
+ self.eventLoopThread.setDaemon(True)
+ self.eventLoopThread.start()
+ self._create_connection()
+
+ def _create_connection(self):
+ self.vc = libvirt.openReadOnly('')
try:
- virt = libvirt.openReadOnly('')
- except libvirt.libvirtError, e:
- # Show error only once
- if self.status != LibvirtMonitor.STATUS_DISABLED:
- self.logger.debug("Unable to connect to libvirtd, disabling event
monitoring")
- self.logger.exception(e)
- self.status = LibvirtMonitor.STATUS_DISABLED
- return
-
- domainIds = virt.listDomainsID()
- definedDomains = virt.listDefinedDomains()
-
- changed = domainIds != self.domainIds or definedDomains != self.definedDomains
-
- self.domainIds = domainIds
- self.definedDomains = definedDomains
-
- virt.close()
-
- if changed and self.event is not None and self.status !=
LibvirtMonitor.STATUS_NOT_STARTED:
- self.event.set()
-
- if self.status == LibvirtMonitor.STATUS_DISABLED:
- self.logger.debug("Event monitoring resumed")
- self.status = LibvirtMonitor.STATUS_RUNNING
+ self.vc.registerCloseCallback(self._close_callback, None, None)
+ except AttributeError:
+ self.logger.warn("Can't monitor libvirtd restarts due to bug in
libvirt-python")
+ self.vc.domainEventRegister(self._callback, None)
+ self.vc.setKeepAlive(5, 3)
+
+ def check(self):
+ if self.eventLoopThread is None or not self.eventLoopThread.isAlive():
+ self.logger.debug("Starting libvirt monitoring event loop")
+ self._loop_start()
+ if self.vc is None or not self.vc.isAlive():
+ self.logger.debug("Reconnecting to libvirtd")
+ self._create_connection()
+
+ def _callback(self, *args, **kwargs):
+ self.event.set()
+
+ def _close_callback(self, *args, **kwargs):
+ self.logger.info("Connection to libvirtd lost, reconnecting")
+ self._create_connection()
def set_event(self, event):
self.event = event
- def stop(self):
- self.terminate.set()
+ def isAlive(self):
+ return self.eventLoopThread is not None and self.eventLoopThread.isAlive()
class Libvirtd(virt.DirectVirt):
@@ -129,7 +136,9 @@ class Libvirtd(virt.DirectVirt):
domains.append(virt.Domain(self.virt, domain))
self.logger.debug("Virtual machine found: %s: %s" %
(domainName, domain.UUIDString()))
except libvirt.libvirtError, e:
+ self.virt.close()
raise virt.VirtError(str(e))
+ self.virt.close()
return domains
def canMonitor(self):
@@ -137,9 +146,8 @@ class Libvirtd(virt.DirectVirt):
def startMonitoring(self, event):
monitor = LibvirtMonitor()
- if not monitor.isAlive():
- monitor.set_event(event)
- monitor.start()
+ monitor.set_event(event)
+ monitor.check()
def eventToString(event):
Show replies by date