python: Added a simple module for daemon management.
[ashd.git] / python / ashd / pdm.py
CommitLineData
6983e036
FT
1"""Management for daemon processes
2
3This module contains a utility to listen for management commands on a
4socket, lending itself to managing daemon processes.
5"""
6
7import os, sys, socket, threading, grp, select
8import types, pprint, traceback
9
10class repl(object):
11 def __init__(self, cl):
12 self.cl = cl
13 self.mod = types.ModuleType("repl")
14 self.mod.echo = self.echo
15 self.printer = pprint.PrettyPrinter(indent = 4, depth = 6)
16 cl.sk.send("+REPL\n")
17
18 def echo(self, ob):
19 self.cl.sk.send(self.printer.pformat(ob) + "\n")
20
21 def command(self, cmd):
22 try:
23 try:
24 ccode = compile(cmd, "PDM Input", "eval")
25 except SyntaxError:
26 ccode = compile(cmd, "PDM Input", "exec")
27 exec ccode in self.mod.__dict__
28 self.cl.sk.send("+OK\n")
29 else:
30 self.echo(eval(ccode, self.mod.__dict__))
31 self.cl.sk.send("+OK\n")
32 except:
33 for line in traceback.format_exception(*sys.exc_info()):
34 self.cl.sk.send(line)
35 self.cl.sk.send("+EXC\n")
36
37 def handle(self, buf):
38 p = buf.find("\n\n")
39 if p < 0:
40 return buf
41 cmd = buf[:p + 1]
42 self.command(cmd)
43 return buf[p + 2:]
44
45class client(threading.Thread):
46 def __init__(self, sk):
47 super(client, self).__init__(name = "Management client")
48 self.setDaemon(True)
49 self.sk = sk
50 self.handler = self
51
52 def choose(self, proto):
53 if proto == "repl":
54 self.handler = repl(self)
55 else:
56 self.sk.send("-ERR Unknown protocol: %s\n" % proto)
57 raise Exception()
58
59 def handle(self, buf):
60 p = buf.find("\n")
61 if p >= 0:
62 proto = buf[:p]
63 buf = buf[p + 1:]
64 self.choose(proto)
65 return buf
66
67 def run(self):
68 try:
69 buf = ""
70 self.sk.send("+PDM1\n")
71 while True:
72 ret = self.sk.recv(1024)
73 if ret == "":
74 return
75 buf += ret
76 while True:
77 try:
78 nbuf = self.handler.handle(buf)
79 except:
80 return
81 if nbuf == buf:
82 break
83 buf = nbuf
84 finally:
85 self.sk.close()
86
87class listener(threading.Thread):
88 def __init__(self):
89 super(listener, self).__init__(name = "Management listener")
90 self.setDaemon(True)
91
92 def listen(self, sk):
93 self.running = True
94 while self.running:
95 rfd, wfd, efd = select.select([sk], [], [sk], 1)
96 for fd in rfd:
97 if fd == sk:
98 nsk, addr = sk.accept()
99 self.accept(nsk, addr)
100
101 def stop(self):
102 self.running = False
103 self.join()
104
105 def accept(self, sk, addr):
106 cl = client(sk)
107 cl.start()
108
109class unixlistener(listener):
110 def __init__(self, name, mode = 0600, group = None):
111 super(unixlistener, self).__init__()
112 self.name = name
113 self.mode = mode
114 self.group = group
115
116 def run(self):
117 sk = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
118 ul = False
119 try:
120 if os.path.exists(self.name) and os.path.stat.S_ISSOCK(os.stat(self.name).st_mode):
121 os.unlink(self.name)
122 sk.bind(self.name)
123 ul = True
124 os.chmod(self.name, self.mode)
125 if self.group is not None:
126 os.chown(self.name, os.getuid(), grp.getgrnam(self.group).gr_gid)
127 sk.listen(16)
128 self.listen(sk)
129 finally:
130 sk.close()
131 if ul:
132 os.unlink(self.name)
133
134class tcplistener(listener):
135 def __init__(self, port, bindaddr = "127.0.0.1"):
136 super(tcplistener, self).__init__()
137 self.port = port
138 self.bindaddr = bindaddr
139
140 def run(self):
141 sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
142 try:
143 sk.bind((self.bindaddr, self.port))
144 sk.listen(16)
145 self.listen(sk)
146 finally:
147 sk.close()