Skip to content
Snippets Groups Projects
Commit e543a42f authored by Michael Hanselmann's avatar Michael Hanselmann
Browse files

Extract base class from SingleFileEventHandler


The base class can contain code useful to other inotify users.
As it is “SingleFileEventHandler” can not be used in ganeti-rapi,
therefore it'll use its own small inotify handler class based
on this base class.

Signed-off-by: default avatarMichael Hanselmann <hansmi@google.com>
Reviewed-by: default avatarIustin Pop <iustin@google.com>
parent 2287b920
No related branches found
No related tags found
No related merge requests found
...@@ -76,11 +76,58 @@ class ErrorLoggingAsyncNotifier(AsyncNotifier, ...@@ -76,11 +76,58 @@ class ErrorLoggingAsyncNotifier(AsyncNotifier,
""" """
class SingleFileEventHandler(pyinotify.ProcessEvent): class FileEventHandlerBase(pyinotify.ProcessEvent):
"""Handle modify events for a single file. """Base class for file event handlers.
@ivar watch_manager: Inotify watch manager
""" """
def __init__(self, watch_manager):
"""Initializes this class.
@type watch_manager: pyinotify.WatchManager
@param watch_manager: inotify watch manager
"""
# pylint: disable-msg=W0231
# no need to call the parent's constructor
self.watch_manager = watch_manager
def process_default(self, event):
logging.error("Received unhandled inotify event: %s", event)
def AddWatch(self, filename, mask):
"""Adds a file watch.
@param filename: Path to file
@param mask: Inotify event mask
@return: Result
"""
result = self.watch_manager.add_watch(filename, mask)
ret = result.get(filename, -1)
if ret <= 0:
raise errors.InotifyError("Could not add inotify watcher (%s)" % ret)
return result[filename]
def RemoveWatch(self, handle):
"""Removes a handle from the watcher.
@param handle: Inotify handle
@return: Whether removal was successful
"""
result = self.watch_manager.rm_watch(handle)
return result[handle]
class SingleFileEventHandler(FileEventHandlerBase):
"""Handle modify events for a single file.
"""
def __init__(self, watch_manager, callback, filename): def __init__(self, watch_manager, callback, filename):
"""Constructor for SingleFileEventHandler """Constructor for SingleFileEventHandler
...@@ -92,34 +139,32 @@ class SingleFileEventHandler(pyinotify.ProcessEvent): ...@@ -92,34 +139,32 @@ class SingleFileEventHandler(pyinotify.ProcessEvent):
@param filename: config file to watch @param filename: config file to watch
""" """
# pylint: disable-msg=W0231 FileEventHandlerBase.__init__(self, watch_manager)
# no need to call the parent's constructor
self.watch_manager = watch_manager self._callback = callback
self.callback = callback self._filename = filename
self.mask = pyinotify.EventsCodes.ALL_FLAGS["IN_IGNORED"] | \
pyinotify.EventsCodes.ALL_FLAGS["IN_MODIFY"] self._watch_handle = None
self.file = filename
self.watch_handle = None
def enable(self): def enable(self):
"""Watch the given file """Watch the given file.
""" """
if self.watch_handle is None: if self._watch_handle is not None:
result = self.watch_manager.add_watch(self.file, self.mask) return
if not self.file in result or result[self.file] <= 0:
raise errors.InotifyError("Could not add inotify watcher") # Class '...' has no 'IN_...' member, pylint: disable-msg=E1103
else: mask = (pyinotify.EventsCodes.IN_MODIFY |
self.watch_handle = result[self.file] pyinotify.EventsCodes.IN_IGNORED)
self._watch_handle = self.AddWatch(self._filename, mask)
def disable(self): def disable(self):
"""Stop watching the given file """Stop watching the given file.
""" """
if self.watch_handle is not None: if self._watch_handle is not None and self.RemoveWatch(self._watch_handle):
result = self.watch_manager.rm_watch(self.watch_handle) self._watch_handle = None
if result[self.watch_handle]:
self.watch_handle = None
# pylint: disable-msg=C0103 # pylint: disable-msg=C0103
# this overrides a method in pyinotify.ProcessEvent # this overrides a method in pyinotify.ProcessEvent
...@@ -132,8 +177,8 @@ class SingleFileEventHandler(pyinotify.ProcessEvent): ...@@ -132,8 +177,8 @@ class SingleFileEventHandler(pyinotify.ProcessEvent):
# case we'll need to create a watcher for the "new" file. This can be done # case we'll need to create a watcher for the "new" file. This can be done
# by the callback by calling "enable" again on us. # by the callback by calling "enable" again on us.
logging.debug("Received 'ignored' inotify event for %s", event.path) logging.debug("Received 'ignored' inotify event for %s", event.path)
self.watch_handle = None self._watch_handle = None
self.callback(False) self._callback(False)
# pylint: disable-msg=C0103 # pylint: disable-msg=C0103
# this overrides a method in pyinotify.ProcessEvent # this overrides a method in pyinotify.ProcessEvent
...@@ -143,7 +188,4 @@ class SingleFileEventHandler(pyinotify.ProcessEvent): ...@@ -143,7 +188,4 @@ class SingleFileEventHandler(pyinotify.ProcessEvent):
# replacing any file with a new one, at filesystem level, rather than # replacing any file with a new one, at filesystem level, rather than
# actually changing it. (see utils.WriteFile) # actually changing it. (see utils.WriteFile)
logging.debug("Received 'modify' inotify event for %s", event.path) logging.debug("Received 'modify' inotify event for %s", event.path)
self.callback(True) self._callback(True)
def process_default(self, event):
logging.error("Received unhandled inotify event: %s", event)
...@@ -24,6 +24,8 @@ ...@@ -24,6 +24,8 @@
import unittest import unittest
import signal import signal
import os import os
import tempfile
import shutil
try: try:
# pylint: disable-msg=E0611 # pylint: disable-msg=E0611
...@@ -149,5 +151,23 @@ class TestSingleFileEventHandler(testutils.GanetiTestCase): ...@@ -149,5 +151,23 @@ class TestSingleFileEventHandler(testutils.GanetiTestCase):
self.assertEquals(self.notifiers[self.NOTIFIER_TERM].error_count, 0) self.assertEquals(self.notifiers[self.NOTIFIER_TERM].error_count, 0)
class TestSingleFileEventHandlerError(unittest.TestCase):
def setUp(self):
self.tmpdir = tempfile.mkdtemp()
def tearDown(self):
shutil.rmtree(self.tmpdir)
def test(self):
wm = pyinotify.WatchManager()
handler = asyncnotifier.SingleFileEventHandler(wm, None,
utils.PathJoin(self.tmpdir,
"nonexist"))
self.assertRaises(errors.InotifyError, handler.enable)
self.assertRaises(errors.InotifyError, handler.enable)
handler.disable()
self.assertRaises(errors.InotifyError, handler.enable)
if __name__ == "__main__": if __name__ == "__main__":
testutils.GanetiTestProgram() testutils.GanetiTestProgram()
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment