[PATCH V2] [Kimchi] Add support to Libvirt Events.

From: Paulo Vital <pvital@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@linux.vnet.ibm.com> --- i18n.py | 4 +++ model/libvirtevents.py | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++ model/model.py | 6 +++- 3 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 model/libvirtevents.py diff --git a/i18n.py b/i18n.py index 6214687..3939aba 100644 --- a/i18n.py +++ b/i18n.py @@ -326,4 +326,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..2775476 --- /dev/null +++ b/model/libvirtevents.py @@ -0,0 +1,97 @@ +# +# Project Kimchi +# +# 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_generic_cb(self, conn, dom, event, detail, *args): + """ + Generic callback to handle Domain (VMs) events. + """ + 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 register_common_domain_events(self, conn): + """ + Register the most common Libvirt domain events to be handled. + """ + conn = conn.get() + for ev in (libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE, + libvirt.VIR_DOMAIN_EVENT_ID_REBOOT, + libvirt.VIR_DOMAIN_EVENT_ID_RTC_CHANGE, + libvirt.VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON, + libvirt.VIR_DOMAIN_EVENT_ID_GRAPHICS, + libvirt.VIR_DOMAIN_EVENT_ID_BLOCK_JOB, + libvirt.VIR_DOMAIN_EVENT_ID_WATCHDOG): + conn.domainEventRegisterAny(None, ev, self.domain_event_generic_cb, + ev) 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 -- 2.5.5

Reviewed-By: Lucio Correia <luciojhc@linux.vnet.ibm.com> On 31-03-2016 18:01, pvital@linux.vnet.ibm.com wrote:
From: Paulo Vital <pvital@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@linux.vnet.ibm.com> --- i18n.py | 4 +++ model/libvirtevents.py | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++ model/model.py | 6 +++- 3 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 model/libvirtevents.py
diff --git a/i18n.py b/i18n.py index 6214687..3939aba 100644 --- a/i18n.py +++ b/i18n.py @@ -326,4 +326,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..2775476 --- /dev/null +++ b/model/libvirtevents.py @@ -0,0 +1,97 @@ +# +# Project Kimchi +# +# 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_generic_cb(self, conn, dom, event, detail, *args): + """ + Generic callback to handle Domain (VMs) events. + """ + 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 register_common_domain_events(self, conn): + """ + Register the most common Libvirt domain events to be handled. + """ + conn = conn.get() + for ev in (libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE, + libvirt.VIR_DOMAIN_EVENT_ID_REBOOT, + libvirt.VIR_DOMAIN_EVENT_ID_RTC_CHANGE, + libvirt.VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON, + libvirt.VIR_DOMAIN_EVENT_ID_GRAPHICS, + libvirt.VIR_DOMAIN_EVENT_ID_BLOCK_JOB, + libvirt.VIR_DOMAIN_EVENT_ID_WATCHDOG): + conn.domainEventRegisterAny(None, ev, self.domain_event_generic_cb, + ev) 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 -- 2.5.5
_______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel
-- Lucio Correia Software Engineer IBM LTC Brazil

On Apr 06 11:15AM, Lucio Correia wrote:
Reviewed-By: Lucio Correia <luciojhc@linux.vnet.ibm.com>
Lucio, thanks by your review, but I found a little error when logging some events. I'll send a fix ASAP.
On 31-03-2016 18:01, pvital@linux.vnet.ibm.com wrote:
From: Paulo Vital <pvital@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@linux.vnet.ibm.com> --- i18n.py | 4 +++ model/libvirtevents.py | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++ model/model.py | 6 +++- 3 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 model/libvirtevents.py
diff --git a/i18n.py b/i18n.py index 6214687..3939aba 100644 --- a/i18n.py +++ b/i18n.py @@ -326,4 +326,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..2775476 --- /dev/null +++ b/model/libvirtevents.py @@ -0,0 +1,97 @@ +# +# Project Kimchi +# +# 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_generic_cb(self, conn, dom, event, detail, *args): + """ + Generic callback to handle Domain (VMs) events. + """ + 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 register_common_domain_events(self, conn): + """ + Register the most common Libvirt domain events to be handled. + """ + conn = conn.get() + for ev in (libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE, + libvirt.VIR_DOMAIN_EVENT_ID_REBOOT, + libvirt.VIR_DOMAIN_EVENT_ID_RTC_CHANGE, + libvirt.VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON, + libvirt.VIR_DOMAIN_EVENT_ID_GRAPHICS, + libvirt.VIR_DOMAIN_EVENT_ID_BLOCK_JOB, + libvirt.VIR_DOMAIN_EVENT_ID_WATCHDOG): + conn.domainEventRegisterAny(None, ev, self.domain_event_generic_cb, + ev) 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 -- 2.5.5
_______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel
-- Lucio Correia Software Engineer IBM LTC Brazil
_______________________________________________ Kimchi-devel mailing list Kimchi-devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/kimchi-devel
-- Paulo Ricardo Paz Vital Linux Technology Center, IBM Systems http://www.ibm.com/linux/ltc/
participants (3)
-
Lucio Correia
-
Paulo Ricardo Paz Vital
-
pvital@linux.vnet.ibm.com