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