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
32
33
34
35 """
36 ClusterShell worker interface.
37
38 A worker is a generic object which provides "grouped" work in a specific task.
39 """
40
41 from ClusterShell.Worker.EngineClient import EngineClient
42 from ClusterShell.NodeSet import NodeSet
43
44
46 """Generic worker exception."""
47
49 """Generic worker error."""
50
52 """Bad argument in worker error."""
53
55 """
56 Base class Worker.
57 """
58
60 """
61 Initializer. Should be called from derived classes.
62 """
63 self.eh = handler
64 self.task = None
65
67 """
68 Bind worker to task. Called by task.schedule()
69 """
70 if self.task is not None:
71
72 raise WorkerError("worker has already been scheduled")
73 self.task = task
74
76 if not self.task:
77 raise WorkerError("worker is not task bound")
78
80 """
81 Return a list of underlying engine clients.
82 """
83 raise NotImplementedError("Derived classes must implement.")
84
86 """
87 Invoke user EventHandler method if needed.
88 """
89 if self.eh:
90 self.eh._invoke(ev_type, self)
91
93 """
94 Get last read message from event handler.
95 """
96 raise NotImplementedError("Derived classes must implement.")
97
99 """
100 Get last error message from event handler.
101 """
102 raise NotImplementedError("Derived classes must implement.")
103
110
111
113 """
114 Base class DistantWorker, which provides a useful set of setters/getters
115 to use with distant workers like ssh or pdsh.
116 """
117
119 Worker.__init__(self, handler)
120
121 self._last_node = None
122 self._last_msg = None
123 self._last_rc = 0
124 self.started = False
125
127 """
128 Starting
129 """
130 if not self.started:
131 self.started = True
132 self._invoke("ev_start")
133
135 """
136 Message received from node, update last* stuffs.
137 """
138 self._last_node = node
139 self._last_msg = msg
140
141 self.task._msg_add((self, node), msg)
142
143 self._invoke("ev_read")
144
146 """
147 Error message received from node, update last* stuffs.
148 """
149 self._last_node = node
150 self._last_errmsg = msg
151
152 self.task._errmsg_add((self, node), msg)
153
154 self._invoke("ev_error")
155
157 """
158 Return code received from a node, update last* stuffs.
159 """
160 self._last_node = node
161 self._last_rc = rc
162
163 self.task._rc_set((self, node), rc)
164
165 self._invoke("ev_hup")
166
168 """
169 Update on node timeout.
170 """
171
172 self._last_node = node
173
174 self.task._timeout_add((self, node))
175
177 """
178 Get last node, useful to get the node in an EventHandler
179 callback like ev_timeout().
180 """
181 return self._last_node
182
184 """
185 Get last (node, buffer), useful in an EventHandler.ev_read()
186 """
187 return self._last_node, self._last_msg
188
190 """
191 Get last (node, error_buffer), useful in an EventHandler.ev_error()
192 """
193 return self._last_node, self._last_errmsg
194
196 """
197 Get last (node, rc), useful in an EventHandler.ev_hup()
198 """
199 return self._last_node, self._last_rc
200
207
214
221
223 """
224 Returns an iterator over available buffers and associated
225 NodeSet. If the optional parameter match_keys is defined, only
226 keys found in match_keys are returned.
227 """
228 self._task_bound_check()
229 for msg, keys in self.task._call_tree_matcher( \
230 self.task._msgtree.walk, match_keys, self):
231 yield msg, NodeSet.fromlist(keys)
232
234 """
235 Returns an iterator over available error buffers and associated
236 NodeSet. If the optional parameter match_keys is defined, only
237 keys found in match_keys are returned.
238 """
239 self._task_bound_check()
240 for msg, keys in self.task._call_tree_matcher( \
241 self.task._errtree.walk, match_keys, self):
242 yield msg, NodeSet.fromlist(keys)
243
251
253 """
254 Returns an iterator over each node and associated error buffer.
255 """
256 self._task_bound_check()
257 return self.task._call_tree_matcher(self.task._errtree.items,
258 match_keys, self)
259
261 """
262 Returns an iterator over return codes and associated NodeSet.
263 If the optional parameter match_keys is defined, only keys
264 found in match_keys are returned.
265 """
266 self._task_bound_check()
267 for rc, keys in self.task._rc_iter_by_worker(self, match_keys):
268 yield rc, NodeSet.fromlist(keys)
269
276
283
290
291
293 """
294 Implements a simple Worker being itself an EngineClient.
295 """
296
297 - def __init__(self, file_reader, file_writer, file_error, key, handler,
298 stderr=False, timeout=-1, autoclose=False):
299 """
300 Initialize worker.
301 """
302 Worker.__init__(self, handler)
303 EngineClient.__init__(self, self, stderr, timeout, autoclose)
304
305 self.last_msg = None
306 if key is None:
307 self.key = self
308 else:
309 self.key = key
310 self.file_reader = file_reader
311 self.file_writer = file_writer
312 self.file_error = file_error
313
315 """
316 Return a list of underlying engine clients.
317 """
318 return [self]
319
321 """
322 Source key for this worker is free for use. Use this method to
323 set the custom source key for this worker.
324 """
325 self.key = key
326
328 """
329 Start worker.
330 """
331 self._invoke("ev_start")
332
333 return self
334
336 """
337 Returns the standard error reader file descriptor as an integer.
338 """
339 if self.file_error and not self.file_error.closed:
340 return self.file_error.fileno()
341
342 return None
343
345 """
346 Returns the reader file descriptor as an integer.
347 """
348 if self.file_reader and not self.file_reader.closed:
349 return self.file_reader.fileno()
350
351 return None
352
354 """
355 Returns the writer file descriptor as an integer.
356 """
357 if self.file_writer and not self.file_writer.closed:
358 return self.file_writer.fileno()
359
360 return None
361
362 - def _read(self, size=4096):
363 """
364 Read data from process.
365 """
366 return EngineClient._read(self, size)
367
373
374 - def _close(self, force, timeout):
375 """
376 Close worker. Called by engine after worker has been
377 unregistered. This method should handle all termination types
378 (normal, forced or on timeout).
379 """
380 if not force and self._rbuf:
381
382
383 self.worker._on_msgline(self._rbuf)
384
385 if self.file_reader != None:
386 self.file_reader.close()
387 if self.file_writer != None:
388 self.file_writer.close()
389 if self.file_error != None:
390 self.file_error.close()
391
392 if timeout:
393 self._on_timeout()
394
395 self._invoke("ev_close")
396
398 """
399 Engine is telling us there is data available for reading.
400 """
401 debug = self.task.info("debug", False)
402 if debug:
403 print_debug = self.task.info("print_debug")
404
405 for msg in self._readlines():
406 if debug:
407 print_debug(self.task, "LINE %s" % msg)
408 self._on_msgline(msg)
409
411 """
412 Engine is telling us there is error available for reading.
413 """
414 debug = self.task.info("debug", False)
415 if debug:
416 print_debug = self.task.info("print_debug")
417
418 for msg in self._readerrlines():
419 if debug:
420 print_debug(self.task, "LINE@STDERR %s" % msg)
421 self._on_errmsgline(msg)
422
424 """
425 Read last msg, useful in an EventHandler.
426 """
427 return self.last_msg
428
430 """
431 Get last error message from event handler.
432 """
433 return self.last_errmsg
434
436 """
437 Add a message.
438 """
439
440 self.last_msg = msg
441
442
443 self.task._msg_add((self, self.key), msg)
444
445 self._invoke("ev_read")
446
448 """
449 Add a message.
450 """
451
452 self.last_errmsg = msg
453
454
455 self.task._errmsg_add((self, self.key), msg)
456
457 self._invoke("ev_error")
458
460 """
461 Update on timeout.
462 """
463 self.task._timeout_add((self, self.key))
464
465
466 self._invoke("ev_timeout")
467
477
487
489 """
490 Write to worker.
491 """
492 self._write(buf)
493
495 """
496 Tell worker to close its writer file descriptor once flushed. Do not
497 perform writes after this call.
498 """
499 self._set_write_eof()
500