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
41 """An asyncore dispatcher for inotify events.
42
43 """
44
45 - def __init__(self, watch_manager, default_proc_fun=None, map=None):
46 """Initializes this class.
47
48 This is a a special asyncore file_dispatcher that actually wraps a
49 pyinotify Notifier, making it asyncronous.
50
51 """
52 if default_proc_fun is None:
53 default_proc_fun = pyinotify.ProcessEvent()
54
55 self.notifier = pyinotify.Notifier(watch_manager, default_proc_fun)
56
57
58
59
60
61 self.fd = self.notifier._fd
62 asyncore.file_dispatcher.__init__(self, self.fd, map)
63
65 self.notifier.read_events()
66 self.notifier.process_events()
67
68
71 """An asyncnotifier that can survive errors in the callbacks.
72
73 We define this as a separate class, since we don't want to make AsyncNotifier
74 diverge from what we contributed upstream.
75
76 """
77
78
80 """Base class for file event handlers.
81
82 @ivar watch_manager: Inotify watch manager
83
84 """
86 """Initializes this class.
87
88 @type watch_manager: pyinotify.WatchManager
89 @param watch_manager: inotify watch manager
90
91 """
92
93
94 self.watch_manager = watch_manager
95
97 logging.error("Received unhandled inotify event: %s", event)
98
100 """Adds a file watch.
101
102 @param filename: Path to file
103 @param mask: Inotify event mask
104 @return: Result
105
106 """
107 result = self.watch_manager.add_watch(filename, mask)
108
109 ret = result.get(filename, -1)
110 if ret <= 0:
111 raise errors.InotifyError("Could not add inotify watcher (%s)" % ret)
112
113 return result[filename]
114
116 """Removes a handle from the watcher.
117
118 @param handle: Inotify handle
119 @return: Whether removal was successful
120
121 """
122 result = self.watch_manager.rm_watch(handle)
123
124 return result[handle]
125
126
128 """Handle modify events for a single file.
129
130 """
131 - def __init__(self, watch_manager, callback, filename):
132 """Constructor for SingleFileEventHandler
133
134 @type watch_manager: pyinotify.WatchManager
135 @param watch_manager: inotify watch manager
136 @type callback: function accepting a boolean
137 @param callback: function to call when an inotify event happens
138 @type filename: string
139 @param filename: config file to watch
140
141 """
142 FileEventHandlerBase.__init__(self, watch_manager)
143
144 self._callback = callback
145 self._filename = filename
146
147 self._watch_handle = None
148
150 """Watch the given file.
151
152 """
153 if self._watch_handle is not None:
154 return
155
156
157
158 mask = (pyinotify.EventsCodes.ALL_FLAGS["IN_MODIFY"] |
159 pyinotify.EventsCodes.ALL_FLAGS["IN_IGNORED"])
160
161 self._watch_handle = self.AddWatch(self._filename, mask)
162
164 """Stop watching the given file.
165
166 """
167 if self._watch_handle is not None and self.RemoveWatch(self._watch_handle):
168 self._watch_handle = None
169
170
171
173
174
175
176
177
178
179
180 logging.debug("Received 'ignored' inotify event for %s", event.path)
181 self._watch_handle = None
182 self._callback(False)
183
184
185
187
188
189
190
191 logging.debug("Received 'modify' inotify event for %s", event.path)
192 self._callback(True)
193