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