1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 """Asynchronous pyinotify implementation"""
23
24
25 import asyncore
26 import logging
27
28 try:
29
30 from pyinotify import pyinotify
31 except ImportError:
32 import pyinotify
33
34 from ganeti import daemon
35 from ganeti import errors
36
37
38
39
40
42 """An asyncore dispatcher for inotify events.
43
44 """
45
46 - def __init__(self, watch_manager, default_proc_fun=None, map=None):
47 """Initializes this class.
48
49 This is a a special asyncore file_dispatcher that actually wraps a
50 pyinotify Notifier, making it asyncronous.
51
52 """
53 if default_proc_fun is None:
54 default_proc_fun = pyinotify.ProcessEvent()
55
56 self.notifier = pyinotify.Notifier(watch_manager, default_proc_fun)
57
58
59
60
61
62 self.fd = self.notifier._fd
63 asyncore.file_dispatcher.__init__(self, self.fd, map)
64
66 self.notifier.read_events()
67 self.notifier.process_events()
68
69
72 """An asyncnotifier that can survive errors in the callbacks.
73
74 We define this as a separate class, since we don't want to make AsyncNotifier
75 diverge from what we contributed upstream.
76
77 """
78
79
81 """Base class for file event handlers.
82
83 @ivar watch_manager: Inotify watch manager
84
85 """
87 """Initializes this class.
88
89 @type watch_manager: pyinotify.WatchManager
90 @param watch_manager: inotify watch manager
91
92 """
93
94
95 self.watch_manager = watch_manager
96
98 logging.error("Received unhandled inotify event: %s", event)
99
101 """Adds a file watch.
102
103 @param filename: Path to file
104 @param mask: Inotify event mask
105 @return: Result
106
107 """
108 result = self.watch_manager.add_watch(filename, mask)
109
110 ret = result.get(filename, -1)
111 if ret <= 0:
112 raise errors.InotifyError("Could not add inotify watcher (%s)" % ret)
113
114 return result[filename]
115
117 """Removes a handle from the watcher.
118
119 @param handle: Inotify handle
120 @return: Whether removal was successful
121
122 """
123 result = self.watch_manager.rm_watch(handle)
124
125 return result[handle]
126
127
129 """Handle modify events for a single file.
130
131 """
132 - def __init__(self, watch_manager, callback, filename):
133 """Constructor for SingleFileEventHandler
134
135 @type watch_manager: pyinotify.WatchManager
136 @param watch_manager: inotify watch manager
137 @type callback: function accepting a boolean
138 @param callback: function to call when an inotify event happens
139 @type filename: string
140 @param filename: config file to watch
141
142 """
143 FileEventHandlerBase.__init__(self, watch_manager)
144
145 self._callback = callback
146 self._filename = filename
147
148 self._watch_handle = None
149
151 """Watch the given file.
152
153 """
154 if self._watch_handle is not None:
155 return
156
157
158
159 mask = (pyinotify.EventsCodes.ALL_FLAGS["IN_MODIFY"] |
160 pyinotify.EventsCodes.ALL_FLAGS["IN_IGNORED"])
161
162 self._watch_handle = self.AddWatch(self._filename, mask)
163
165 """Stop watching the given file.
166
167 """
168 if self._watch_handle is not None and self.RemoveWatch(self._watch_handle):
169 self._watch_handle = None
170
171
172
174
175
176
177
178
179
180
181 logging.debug("Received 'ignored' inotify event for %s", event.path)
182 self._watch_handle = None
183 self._callback(False)
184
185
186
188
189
190
191
192 logging.debug("Received 'modify' inotify event for %s", event.path)
193 self._callback(True)
194