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 (error code %s);"
113 " increasing fs.inotify.max_user_watches sysctl"
114 " might be necessary" % ret)
115
116 return result[filename]
117
119 """Removes a handle from the watcher.
120
121 @param handle: Inotify handle
122 @return: Whether removal was successful
123
124 """
125 result = self.watch_manager.rm_watch(handle)
126
127 return result[handle]
128
129
131 """Handle modify events for a single file.
132
133 """
134 - def __init__(self, watch_manager, callback, filename):
135 """Constructor for SingleFileEventHandler
136
137 @type watch_manager: pyinotify.WatchManager
138 @param watch_manager: inotify watch manager
139 @type callback: function accepting a boolean
140 @param callback: function to call when an inotify event happens
141 @type filename: string
142 @param filename: config file to watch
143
144 """
145 FileEventHandlerBase.__init__(self, watch_manager)
146
147 self._callback = callback
148 self._filename = filename
149
150 self._watch_handle = None
151
153 """Watch the given file.
154
155 """
156 if self._watch_handle is not None:
157 return
158
159
160
161 mask = (pyinotify.EventsCodes.ALL_FLAGS["IN_MODIFY"] |
162 pyinotify.EventsCodes.ALL_FLAGS["IN_IGNORED"])
163
164 self._watch_handle = self.AddWatch(self._filename, mask)
165
167 """Stop watching the given file.
168
169 """
170 if self._watch_handle is not None and self.RemoveWatch(self._watch_handle):
171 self._watch_handle = None
172
173
174
176
177
178
179
180
181
182
183 logging.debug("Received 'ignored' inotify event for %s", event.path)
184 self._watch_handle = None
185 self._callback(False)
186
187
188
190
191
192
193
194 logging.debug("Received 'modify' inotify event for %s", event.path)
195 self._callback(True)
196