On 04/14/2016 06:36 PM, pvital(a)linux.vnet.ibm.com wrote:
From: Paulo Vital <pvital(a)linux.vnet.ibm.com>
This patch adds support to handle in Kimchi any Libvirt Event, just by adding
a callback to process the event and register the event with the callback.
A method called register_common_events() is responsible to register the common
domain events to use a generic callback that logs into error log, the event
happened and it's details.
This patch is part of the solution for Kimchi Issue #817
Signed-off-by: Paulo Vital <pvital(a)linux.vnet.ibm.com>
---
i18n.py | 4 ++
model/libvirtevents.py | 124 +++++++++++++++++++++++++++++++++++++++++++++++++
model/model.py | 6 ++-
3 files changed, 133 insertions(+), 1 deletion(-)
create mode 100644 model/libvirtevents.py
diff --git a/i18n.py b/i18n.py
index 7cce796..8fa233f 100644
--- a/i18n.py
+++ b/i18n.py
@@ -324,4 +324,8 @@ messages = {
"KCHLVMS0001E": _("Invalid volume group name parameter:
%(name)s."),
+ "KCHEVENT0001E": _("Failed to register the default event
implementation."),
+ "KCHEVENT0002E": _("Failed to register timeout event."),
+ "KCHEVENT0003E": _("Failed to Run the default event
implementation."),
+
}
diff --git a/model/libvirtevents.py b/model/libvirtevents.py
new file mode 100644
index 0000000..86e012a
--- /dev/null
+++ b/model/libvirtevents.py
@@ -0,0 +1,124 @@
+#
+# Project Kimchi
+#
+# Copyright IBM, Corp. 2016
+# Copyright IBM Corp, 2016
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+import cherrypy
+import libvirt
+import time
+
+from wok.exception import OperationFailed
+from wok.utils import wok_log
+
+
+class LibvirtEvents(object):
+ def __init__(self):
+ # Register default implementation of event handlers
+ if libvirt.virEventRegisterDefaultImpl() < 0:
+ raise OperationFailed('KCHEVENT0001E')
+
+ # Run a background thread with the event loop. Using cherrypy
+ # BackgroundTask class due to issues when using threading module with
+ # cherrypy.
+ self.event_loop_thread = cherrypy.process.plugins.BackgroundTask(
+ 2,
+ self._event_loop_run
+ )
+ self.event_loop_thread.setName('KimchiLibvirtEventLoop')
+ self.event_loop_thread.setDaemon(True)
+ self.event_loop_thread.start()
+
+ # Set an event timeout to control the self._event_loop_run
+ if libvirt.virEventAddTimeout(0, self._kimchi_EventTimeout, None) < 0:
+ raise OperationFailed('KCHEVENT0002E')
+
+ # Event loop method to be executed in background as thread
+ def _event_loop_run(self):
+ while True:
+ if libvirt.virEventRunDefaultImpl() < 0:
+ raise OperationFailed('KCHEVENT0003E')
+
+ def is_event_loop_alive(self):
+ return self.event_loop_thread.isAlive()
+
+ # Event loop handler used to limit length of waiting for any other event.
+ def _kimchi_EventTimeout(self, timer, opaque):
+ time.sleep(1)
+
+ def domain_event_lifecycle_cb(self, conn, dom, event, detail, *args):
+ """
+ Callback to handle Domain (VMs) events - VM Livecycle.
+ """
+ evStrings = ("Defined", "Undefined", "Started",
"Suspended", "Resumed",
+ "Stopped", "Shutdown", "PMSuspended",
"Crashed")
+ evDetails = (("Added", "Updated"),
+ ("Removed", ),
+ ("Booted", "Migrated", "Restored",
"Snapshot", "Wakeup"),
+ ("Paused", "Migrated", "IOError",
"Watchdog", "Restored",
+ "Snapshot", "API error"),
+ ("Unpaused", "Migrated",
"Snapshot"),
+ ("Shutdown", "Destroyed", "Crashed",
"Migrated", "Saved",
+ "Failed", "Snapshot"),
+ ("Finished", ),
+ ("Memory", "Disk"),
+ ("Panicked"))
+ msg = "Libvirt Event: Domain %s %s %s" % (dom.name(),
evStrings[event],
+ evDetails[event][detail])
+ wok_log.error(msg)
+
+ def domain_event_reboot_cb(self, conn, dom, *args):
+ """
+ Callback to handle Domain (VMs) events - VM Reboot.
+ """
+ msg = "Libvirt Event: Domain %s rebooted" % dom.name()
+ wok_log.error(msg)
+
+ def domain_event_pmwakeup_cb(self, conn, dom, reason, *args):
+ """
+ Callback to handle Domain (VMs) events - VM PM WakeUp.
+ """
+ msg = "Libvirt Event: Domain %s system pmwakeup" % dom.name()
+ wok_log.error(msg)
+
+ def domain_event_pmsuspend_cb(self, conn, dom, reason, *args):
+ """
+ Callback to handle Domain (VMs) events - VM PM Suspend.
+ """
+ msg = "Libvirt Event: Domain %s system pmsuspend" % dom.name()
+ wok_log.error(msg)
+
+ def register_common_domain_events(self, conn):
+ """
+ Register the most common Libvirt domain events to be handled.
+ """
+ conn = conn.get()
+ event_map = [(libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE,
+ self.domain_event_lifecycle_cb),
+ (libvirt.VIR_DOMAIN_EVENT_ID_REBOOT,
+ self.domain_event_reboot_cb),
+ (libvirt.VIR_DOMAIN_EVENT_ID_PMWAKEUP,
+ self.domain_event_pmwakeup_cb),
+ (libvirt.VIR_DOMAIN_EVENT_ID_PMSUSPEND,
+ self.domain_event_pmsuspend_cb)]
+
+ for event, event_cb in event_map:
+ try:
+ conn.domainEventRegisterAny(None, event, event_cb, None)
+ except libvirt.libvirtError as e:
+ # It's not a big deal if an event could not be registered.
+ wok_log.error("Could not register event %s. Details: %s" %
+ (event, e))
diff --git a/model/model.py b/model/model.py
index e44f804..aeb8b7d 100644
--- a/model/model.py
+++ b/model/model.py
@@ -26,6 +26,7 @@ from wok.plugins.kimchi import config
from wok.utils import import_module, listPathModules
from wok.plugins.kimchi.model.libvirtconnection import LibvirtConnection
+from wok.plugins.kimchi.model.libvirtevents import LibvirtEvents
class Model(BaseModel):
@@ -43,8 +44,11 @@ class Model(BaseModel):
return instances
self.objstore = ObjectStore(objstore_loc or config.get_object_store())
+ self.events = LibvirtEvents()
self.conn = LibvirtConnection(libvirt_uri)
- kargs = {'objstore': self.objstore, 'conn': self.conn}
+ self.events.register_common_domain_events(self.conn)
+ kargs = {'objstore': self.objstore, 'conn': self.conn,
+ 'eventsloop': self.events}
models = []
# Import task model from Wok