]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/scripts/startstop_node.py
trailing-whitespace eradication, no functional changes
[tahoe-lafs/tahoe-lafs.git] / src / allmydata / scripts / startstop_node.py
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 def do_start(basedir, profile=False, out=sys.stdout, err=sys.stderr):
32     print >>out, "STARTING", basedir
33     if os.path.exists(os.path.join(basedir, "client.tac")):
34         tac = "client.tac"
35         type = "client"
36     elif os.path.exists(os.path.join(basedir, "tahoe-client.tac")):
37         tac = "tahoe-client.tac"
38         type = "client"
39     elif os.path.exists(os.path.join(basedir, "introducer.tac")):
40         tac = "introducer.tac"
41         type = "introducer"
42     elif os.path.exists(os.path.join(basedir, "tahoe-introducer.tac")):
43         tac = "tahoe-introducer.tac"
44         type = "introducer"
45     else:
46         print >>err, "%s does not look like a node directory" % basedir
47         if not os.path.isdir(basedir):
48             print >>err, " in fact, it doesn't look like a directory at all!"
49         return 1
50
51     cmd = find_exe.find_exe('twistd')
52     if not cmd:
53         print "Can't find twistd (it comes with Twisted).  Aborting."
54         sys.exit(1)
55
56     fileutil.make_dirs(os.path.join(basedir, "logs"))
57     cmd.extend(["-y", tac, "--logfile", os.path.join("logs", "twistd.log")])
58     if profile:
59         cmd.extend(["--profile=profiling_results.prof", "--savestats",])
60     curdir = os.getcwd()
61     try:
62         os.chdir(basedir)
63         rc = os.system(' '.join(cmd))
64     finally:
65         os.chdir(curdir)
66     if rc == 0:
67         print >>out, "%s node probably started" % type
68         return 0
69     else:
70         print >>err, "%s node probably not started" % type
71         return 1
72
73 def do_stop(basedir, out=sys.stdout, err=sys.stderr):
74     print >>out, "STOPPING", basedir
75     pidfile = os.path.join(basedir, "twistd.pid")
76     if not os.path.exists(pidfile):
77         print >>err, "%s does not look like a running node directory (no twistd.pid)" % basedir
78         return 2
79     pid = open(pidfile, "r").read()
80     pid = int(pid)
81
82     # kill it hard (SIGKILL), delete the twistd.pid file, then wait for the
83     # process itself to go away. If it hasn't gone away after 5 seconds, warn
84     # the user but keep waiting until they give up.
85     try:
86         os.kill(pid, signal.SIGKILL)
87     except OSError, oserr:
88         if oserr.errno == 3:
89             print oserr.strerror
90             # the process didn't exist, so wipe the pid file
91             os.remove(pidfile)
92             return 1
93         else:
94             raise
95     try:
96         os.remove(pidfile)
97     except EnvironmentError:
98         pass
99     start = time.time()
100     time.sleep(0.1)
101     wait = 5
102     first_time = True
103     while True:
104         # poll once per second until we see the process is no longer running
105         try:
106             os.kill(pid, 0)
107         except OSError:
108             print >>out, "process %d is dead" % pid
109             return
110         wait -= 1
111         if wait < 0:
112             if first_time:
113                 print >>err, ("It looks like pid %d is still running "
114                               "after %d seconds" % (pid,
115                                                     (time.time() - start)))
116                 print >>err, "I will keep watching it until you interrupt me."
117                 wait = 10
118                 first_time = False
119             else:
120                 print >>err, "pid %d still running after %d seconds" % \
121                       (pid, (time.time() - start))
122                 wait = 10
123         time.sleep(1)
124     return 1
125
126 def start(config, stdout, stderr):
127     rc = 0
128     for basedir in config['basedirs']:
129         rc = do_start(basedir, config['profile'], stdout, stderr) or rc
130     return rc
131
132 def stop(config, stdout, stderr):
133     rc = 0
134     for basedir in config['basedirs']:
135         rc = do_stop(basedir, stdout, stderr) or rc
136     return rc
137
138 def restart(config, stdout, stderr):
139     rc = 0
140     for basedir in config['basedirs']:
141         rc = do_stop(basedir, stdout, stderr) or rc
142     if rc == 2 and config['force']:
143         print >>stderr, "ignoring couldn't-stop"
144         rc = 0
145     if rc:
146         print >>stderr, "not restarting"
147         return rc
148     for basedir in config['basedirs']:
149         rc = do_start(basedir, config['profile'], stdout, stderr) or rc
150     return rc
151
152
153 subCommands = [
154     ["start", None, StartOptions, "Start a node (of any type)."],
155     ["stop", None, StopOptions, "Stop a node."],
156     ["restart", None, RestartOptions, "Restart a node."],
157 ]
158
159 dispatch = {
160     "start": start,
161     "stop": stop,
162     "restart": restart,
163     }