2 import os, sys, signal, time
3 from allmydata.scripts.common import BasedirMixin, BaseOptions
4 from allmydata.util import fileutil
5 from allmydata.util.assertutil import precondition
6 from allmydata.util.encodingutil import listdir_unicode, quote_output
9 class StartOptions(BasedirMixin, BaseOptions):
11 ["profile", "p", "Run under the Python profiler, putting results in 'profiling_results.prof'."],
12 ["syslog", None, "Tell the node to log to syslog, not a file."],
15 def getSynopsis(self):
16 return "Usage: %s start [options] [NODEDIR]" % (self.command_name,)
19 class StopOptions(BasedirMixin, BaseOptions):
20 def getSynopsis(self):
21 return "Usage: %s stop [options] [NODEDIR]" % (self.command_name,)
24 class RestartOptions(BasedirMixin, BaseOptions):
26 ["profile", "p", "Run under the Python profiler, putting results in 'profiling_results.prof'."],
27 ["syslog", None, "Tell the node to log to syslog, not a file."],
30 def getSynopsis(self):
31 return "Usage: %s restart [options] [NODEDIR]" % (self.command_name,)
34 class RunOptions(BasedirMixin, BaseOptions):
35 default_nodedir = u"."
38 ["node-directory", "d", None, "Specify the directory of the node to be run. [default, for 'tahoe run' only: current directory]"],
41 def getSynopsis(self):
42 return "Usage: %s run [options] [NODEDIR]" % (self.command_name,)
45 def start(opts, out=sys.stdout, err=sys.stderr):
46 basedir = opts['basedir']
47 print >>out, "STARTING", quote_output(basedir)
48 if not os.path.isdir(basedir):
49 print >>err, "%s does not look like a directory at all" % quote_output(basedir)
51 for fn in listdir_unicode(basedir):
52 if fn.endswith(u".tac"):
56 print >>err, "%s does not look like a node directory (no .tac file)" % quote_output(basedir)
60 elif "introducer" in tac:
61 nodetype = "introducer"
63 nodetype = "unknown (%s)" % tac
65 args = ["twistd", "-y", tac]
67 args.append("--syslog")
68 elif nodetype in ("client", "introducer"):
69 fileutil.make_dirs(os.path.join(basedir, "logs"))
70 args.extend(["--logfile", os.path.join("logs", "twistd.log")])
72 args.extend(["--profile=profiling_results.prof", "--savestats",])
75 from twisted.scripts import twistd
78 # run() doesn't return: the parent does os._exit(0) in daemonize(), so
79 # we'll never get here. If application setup fails (e.g. ImportError),
80 # run() will raise an exception.
82 def stop(config, out=sys.stdout, err=sys.stderr):
83 basedir = config['basedir']
84 print >>out, "STOPPING", quote_output(basedir)
85 pidfile = os.path.join(basedir, "twistd.pid")
86 if not os.path.exists(pidfile):
87 print >>err, "%s does not look like a running node directory (no twistd.pid)" % quote_output(basedir)
88 # we define rc=2 to mean "nothing is running, but it wasn't me who
91 pid = open(pidfile, "r").read()
94 # kill it hard (SIGKILL), delete the twistd.pid file, then wait for the
95 # process itself to go away. If it hasn't gone away after 20 seconds, warn
96 # the user but keep waiting until they give up.
98 os.kill(pid, signal.SIGKILL)
99 except OSError, oserr:
102 # the process didn't exist, so wipe the pid file
109 except EnvironmentError:
116 # poll once per second until we see the process is no longer running
120 print >>out, "process %d is dead" % pid
125 print >>err, ("It looks like pid %d is still running "
126 "after %d seconds" % (pid,
127 (time.time() - start)))
128 print >>err, "I will keep watching it until you interrupt me."
132 print >>err, "pid %d still running after %d seconds" % \
133 (pid, (time.time() - start))
136 # we define rc=1 to mean "I think something is still running, sorry"
139 def restart(config, stdout, stderr):
140 rc = stop(config, stdout, stderr)
142 print >>stderr, "ignoring couldn't-stop"
145 print >>stderr, "not restarting"
147 return start(config, stdout, stderr)
149 def run(config, stdout, stderr):
150 from twisted.internet import reactor
151 from twisted.python import log, logfile
152 from allmydata import client
154 basedir = config['basedir']
155 precondition(isinstance(basedir, unicode), basedir)
157 if not os.path.isdir(basedir):
158 print >>stderr, "%s does not look like a directory at all" % quote_output(basedir)
160 for fn in listdir_unicode(basedir):
161 if fn.endswith(u".tac"):
165 print >>stderr, "%s does not look like a node directory (no .tac file)" % quote_output(basedir)
167 if "client" not in tac:
168 print >>stderr, ("%s looks like it contains a non-client node (%s).\n"
169 "Use 'tahoe start' instead of 'tahoe run'."
170 % (quote_output(basedir), tac))
175 # set up twisted logging. this will become part of the node rsn.
176 logdir = os.path.join(basedir, 'logs')
177 if not os.path.exists(logdir):
179 lf = logfile.LogFile('tahoesvc.log', logdir)
182 # run the node itself
183 c = client.Client(basedir)
184 reactor.callLater(0, c.startService) # after reactor startup
191 ["start", None, StartOptions, "Start a node (of any type)."],
192 ["stop", None, StopOptions, "Stop a node."],
193 ["restart", None, RestartOptions, "Restart a node."],
194 ["run", None, RunOptions, "Run a node synchronously."],