source file: /home/buildslave/tahoe/edgy/build/src/allmydata/scripts/startstop_node.py
file stats: 133 lines, 88 executed: 66.2% covered
1.
2. import os, sys, signal, time
3. from twisted.python import usage
4. from allmydata.scripts.common import BasedirMixin
5. from allmydata.util import fileutil, find_exe
6.
7. class StartOptions(BasedirMixin, usage.Options):
8. optParameters = [
9. ["basedir", "C", None, "which directory to start the node in"],
10. ]
11. optFlags = [
12. ["profile", "p", "whether to run under the Python profiler, putting results in \"profiling_results.prof\""],
13. ]
14.
15. class StopOptions(BasedirMixin, usage.Options):
16. optParameters = [
17. ["basedir", "C", None, "which directory to stop the node in"],
18. ]
19.
20. class RestartOptions(BasedirMixin, usage.Options):
21. optParameters = [
22. ["basedir", "C", None, "which directory to restart the node in"],
23. ]
24. optFlags = [
25. ["force", "f", "if the node is not already running, start it "
26. "instead of complaining that you should have used 'start' instead "
27. "of 'restart'"],
28. ["profile", "p", "whether to run under the Python profiler, putting results in \"profiling_results.prof\""],
29. ]
30.
31. class RunOptions(usage.Options):
32. optParameters = [
33. ["basedir", "C", None, "which directory to run the node in, CWD by default"],
34. ]
35.
36. def do_start(basedir, profile=False, out=sys.stdout, err=sys.stderr):
37. print >>out, "STARTING", basedir
38. if not os.path.isdir(basedir):
39. print >>err, "%s does not look like a directory at all" % basedir
40. return 1
41. for fn in os.listdir(basedir):
42. if fn.endswith(".tac"):
43. tac = fn
44. break
45. else:
46. print >>err, "%s does not look like a node directory (no .tac file)" % basedir
47. return 1
48. if "client" in tac:
49. nodetype = "client"
50. elif "introducer" in tac:
51. nodetype = "introducer"
52. else:
53. nodetype = "unknown (%s)" % tac
54.
55. cmd = find_exe.find_exe('twistd')
56. if not cmd:
57. print "Can't find twistd (it comes with Twisted). Aborting."
58. sys.exit(1)
59.
60. cmd.extend(["-y", tac])
61. if nodetype in ("client", "introducer"):
62. fileutil.make_dirs(os.path.join(basedir, "logs"))
63. cmd.extend(["--logfile", os.path.join("logs", "twistd.log")])
64. if profile:
65. cmd.extend(["--profile=profiling_results.prof", "--savestats",])
66. curdir = os.getcwd()
67. try:
68. os.chdir(basedir)
69. rc = os.system(' '.join(cmd))
70. finally:
71. os.chdir(curdir)
72. if rc == 0:
73. print >>out, "%s node probably started" % nodetype
74. return 0
75. else:
76. print >>err, "%s node probably not started" % nodetype
77. return 1
78.
79. def do_stop(basedir, out=sys.stdout, err=sys.stderr):
80. print >>out, "STOPPING", basedir
81. pidfile = os.path.join(basedir, "twistd.pid")
82. if not os.path.exists(pidfile):
83. print >>err, "%s does not look like a running node directory (no twistd.pid)" % basedir
84. return 2
85. pid = open(pidfile, "r").read()
86. pid = int(pid)
87.
88. # kill it hard (SIGKILL), delete the twistd.pid file, then wait for the
89. # process itself to go away. If it hasn't gone away after 5 seconds, warn
90. # the user but keep waiting until they give up.
91. try:
92. os.kill(pid, signal.SIGKILL)
93. except OSError, oserr:
94. if oserr.errno == 3:
95. print oserr.strerror
96. # the process didn't exist, so wipe the pid file
97. os.remove(pidfile)
98. return 1
99. else:
100. raise
101. try:
102. os.remove(pidfile)
103. except EnvironmentError:
104. pass
105. start = time.time()
106. time.sleep(0.1)
107. wait = 5
108. first_time = True
109. while True:
110. # poll once per second until we see the process is no longer running
111. try:
112. os.kill(pid, 0)
113. except OSError:
114. print >>out, "process %d is dead" % pid
115. return
116. wait -= 1
117. if wait < 0:
118. if first_time:
119. print >>err, ("It looks like pid %d is still running "
120. "after %d seconds" % (pid,
121. (time.time() - start)))
122. print >>err, "I will keep watching it until you interrupt me."
123. wait = 10
124. first_time = False
125. else:
126. print >>err, "pid %d still running after %d seconds" % \
127. (pid, (time.time() - start))
128. wait = 10
129. time.sleep(1)
130. return 1
131.
132. def start(config, stdout, stderr):
133. rc = 0
134. for basedir in config['basedirs']:
135. rc = do_start(basedir, config['profile'], stdout, stderr) or rc
136. return rc
137.
138. def stop(config, stdout, stderr):
139. rc = 0
140. for basedir in config['basedirs']:
141. rc = do_stop(basedir, stdout, stderr) or rc
142. return rc
143.
144. def restart(config, stdout, stderr):
145. rc = 0
146. for basedir in config['basedirs']:
147. rc = do_stop(basedir, stdout, stderr) or rc
148. if rc == 2 and config['force']:
149. print >>stderr, "ignoring couldn't-stop"
150. rc = 0
151. if rc:
152. print >>stderr, "not restarting"
153. return rc
154. for basedir in config['basedirs']:
155. rc = do_start(basedir, config['profile'], stdout, stderr) or rc
156. return rc
157.
158. def run(config, stdout, stderr):
159. from twisted.internet import reactor
160. from twisted.python import log, logfile
161. from allmydata import client
162.
163. basedir = config['basedir']
164. if basedir is None:
165. basedir = '.'
166. else:
167. os.chdir(basedir)
168.
169. # set up twisted logging. this will become part of the node rsn.
170. logdir = os.path.join(basedir, 'logs')
171. if not os.path.exists(logdir):
172. os.makedirs(logdir)
173. lf = logfile.LogFile('tahoesvc.log', logdir)
174. log.startLogging(lf)
175.
176. # run the node itself
177. c = client.Client(basedir)
178. reactor.callLater(0, c.startService) # after reactor startup
179. reactor.run()
180.
181. return 0
182.
183.
184. subCommands = [
185. ["start", None, StartOptions, "Start a node (of any type)."],
186. ["stop", None, StopOptions, "Stop a node."],
187. ["restart", None, RestartOptions, "Restart a node."],
188. ["run", None, RunOptions, "Run a node synchronously."],
189. ]
190.
191. dispatch = {
192. "start": start,
193. "stop": stop,
194. "restart": restart,
195. "run": run,
196. }