]> git.rkrishnan.org Git - tahoe-lafs/tahoe-lafs.git/blob - src/allmydata/scripts/startstop_node.py
'tahoe restart': re-enable --force option, which was accidentally lost
[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
6 from twisted.python.procutils import which
7
8 class StartOptions(BasedirMixin, usage.Options):
9     optParameters = [
10         ["basedir", "C", None, "which directory to start the node in"],
11         ]
12     optFlags = [
13         ["profile", "p", "whether to run under the Python profiler, putting results in \"profiling_results.prof\""],
14         ]
15
16 class StopOptions(BasedirMixin, usage.Options):
17     optParameters = [
18         ["basedir", "C", None, "which directory to stop the node in"],
19         ]
20
21 class RestartOptions(BasedirMixin, usage.Options):
22     optParameters = [
23         ["basedir", "C", None, "which directory to restart the node in"],
24         ]
25     optFlags = [
26         ["force", "f", "if the node is not already running, start it "
27          "instead of complaining that you should have used 'start' instead "
28          "of 'restart'"],
29         ["profile", "p", "whether to run under the Python profiler, putting results in \"profiling_results.prof\""],
30         ]
31
32 def do_start(basedir, profile=False, out=sys.stdout, err=sys.stderr):
33     print >>out, "STARTING", basedir
34     if os.path.exists(os.path.join(basedir, "client.tac")):
35         tac = "client.tac"
36         type = "client"
37     elif os.path.exists(os.path.join(basedir, "introducer.tac")):
38         tac = "introducer.tac"
39         type = "introducer"
40     else:
41         print >>err, "%s does not look like a node directory" % basedir
42         if not os.path.isdir(basedir):
43             print >>err, " in fact, it doesn't look like a directory at all!"
44         return 1
45     twistds = which("twistd")
46     twistd = twistds and twistds[0]
47     if not twistd:
48         twistd = os.path.join(sys.prefix, 'Scripts', 'twistd.py') 
49     if not os.path.exists(twistd):
50         print "Can't find twistd (it comes with Twisted).  Aborting."
51         sys.exit(1)
52     path, ext = os.path.splitext(twistd)
53     if ext.lower() in [".exe", ".bat",]:
54         cmd = [twistd,]
55     else:
56         cmd = [sys.executable, twistd,]
57     
58     fileutil.make_dirs(os.path.join(basedir, "logs"))
59     cmd.extend(["-y", tac, "--logfile", os.path.join("logs", "twistd.log")])
60     if profile:
61         cmd.extend(["--profile=profiling_results.prof", "--savestats",])
62     curdir = os.getcwd()
63     try:
64         os.chdir(basedir)
65         rc = os.system(' '.join(cmd))
66     finally:
67         os.chdir(curdir)
68     if rc == 0:
69         print >>out, "%s node probably started" % type
70         return 0
71     else:
72         print >>err, "%s node probably not started" % type
73         return 1
74
75 def do_stop(basedir, out=sys.stdout, err=sys.stderr):
76     print >>out, "STOPPING", basedir
77     pidfile = os.path.join(basedir, "twistd.pid")
78     if not os.path.exists(pidfile):
79         print >>err, "%s does not look like a running node directory (no twistd.pid)" % basedir
80         return 2
81     pid = open(pidfile, "r").read()
82     pid = int(pid)
83
84     timer = 0
85     try:
86         os.kill(pid, signal.SIGTERM)
87     except OSError, oserr:
88         if oserr.errno == 3:
89             print oserr.strerror
90             return 1
91         else:
92             raise
93     time.sleep(0.1)
94     while timer < 5:
95         # poll once per second until twistd.pid goes away, up to 5 seconds
96         try:
97             os.kill(pid, 0)
98         except OSError:
99             print >>out, "process %d is dead" % pid
100             return
101         timer += 1
102         time.sleep(1)
103     print >>err, "never saw process go away"
104     return 1
105
106 def start(config, stdout, stderr):
107     rc = 0
108     for basedir in config['basedirs']:
109         rc = do_start(basedir, config['profile'], stdout, stderr) or rc
110     return rc
111
112 def stop(config, stdout, stderr):
113     rc = 0
114     for basedir in config['basedirs']:
115         rc = do_stop(basedir, stdout, stderr) or rc
116     return rc
117
118 def restart(config, stdout, stderr):
119     rc = 0
120     for basedir in config['basedirs']:
121         rc = do_stop(basedir, stdout, stderr) or rc
122     if rc == 2 and config['force']:
123         print >>stderr, "ignoring couldn't-stop"
124         rc = 0
125     if rc:
126         print >>stderr, "not restarting"
127         return rc
128     for basedir in config['basedirs']:
129         rc = do_start(basedir, config['profile'], stdout, stderr) or rc
130     return rc
131
132
133 subCommands = [
134     ["start", None, StartOptions, "Start a node (of any type)."],
135     ["stop", None, StopOptions, "Stop a node."],
136     ["restart", None, RestartOptions, "Restart a node."],
137 ]
138
139 dispatch = {
140     "start": start,
141     "stop": stop,
142     "restart": restart,
143     }