2007-07-11 02:05:18 +00:00
|
|
|
|
2007-09-20 19:37:50 +00:00
|
|
|
import os, sys, signal, time
|
2010-08-02 04:30:04 +00:00
|
|
|
from allmydata.scripts.common import BasedirMixin, BaseOptions
|
2007-10-15 17:25:15 +00:00
|
|
|
from allmydata.util import fileutil, find_exe
|
2010-08-03 08:54:16 +00:00
|
|
|
from allmydata.util.assertutil import precondition
|
|
|
|
from allmydata.util.encodingutil import listdir_unicode, quote_output
|
2007-07-11 02:05:18 +00:00
|
|
|
|
2010-08-02 04:30:04 +00:00
|
|
|
class StartOptions(BasedirMixin, BaseOptions):
|
2007-09-21 22:03:47 +00:00
|
|
|
optFlags = [
|
2010-08-03 08:48:01 +00:00
|
|
|
["profile", "p", "Run under the Python profiler, putting results in 'profiling_results.prof'."],
|
|
|
|
["syslog", None, "Tell the node to log to syslog, not a file."],
|
2007-09-21 22:03:47 +00:00
|
|
|
]
|
2007-07-11 02:05:18 +00:00
|
|
|
|
2010-08-02 04:30:04 +00:00
|
|
|
class StopOptions(BasedirMixin, BaseOptions):
|
2010-08-03 08:54:16 +00:00
|
|
|
pass
|
2007-07-11 02:05:18 +00:00
|
|
|
|
2010-08-02 04:30:04 +00:00
|
|
|
class RestartOptions(BasedirMixin, BaseOptions):
|
2007-07-11 02:05:18 +00:00
|
|
|
optFlags = [
|
2010-08-03 08:48:01 +00:00
|
|
|
["profile", "p", "Run under the Python profiler, putting results in 'profiling_results.prof'."],
|
|
|
|
["syslog", None, "Tell the node to log to syslog, not a file."],
|
2007-09-21 22:48:15 +00:00
|
|
|
]
|
2007-07-11 02:05:18 +00:00
|
|
|
|
2010-08-02 04:30:04 +00:00
|
|
|
class RunOptions(BasedirMixin, BaseOptions):
|
|
|
|
default_nodedir = u"."
|
2010-08-03 08:54:16 +00:00
|
|
|
allow_multiple = False
|
2010-08-02 04:30:04 +00:00
|
|
|
|
2008-01-10 02:54:12 +00:00
|
|
|
optParameters = [
|
2010-08-03 08:54:16 +00:00
|
|
|
["node-directory", "d", None, "Specify the directory of the node to be run. [default, for 'tahoe run' only: current directory]"],
|
|
|
|
["multiple", "m", None, "['tahoe run' cannot accept multiple node directories]"],
|
|
|
|
]
|
2008-01-10 02:54:12 +00:00
|
|
|
|
2008-09-25 01:03:02 +00:00
|
|
|
def do_start(basedir, opts, out=sys.stdout, err=sys.stderr):
|
2010-08-03 08:54:16 +00:00
|
|
|
print >>out, "STARTING", quote_output(basedir)
|
2008-02-18 07:28:17 +00:00
|
|
|
if not os.path.isdir(basedir):
|
2010-08-03 08:54:16 +00:00
|
|
|
print >>err, "%s does not look like a directory at all" % quote_output(basedir)
|
2008-02-18 07:28:17 +00:00
|
|
|
return 1
|
2010-08-03 08:54:16 +00:00
|
|
|
for fn in listdir_unicode(basedir):
|
|
|
|
if fn.endswith(u".tac"):
|
|
|
|
tac = str(fn)
|
2008-02-18 07:28:17 +00:00
|
|
|
break
|
2007-07-11 02:05:18 +00:00
|
|
|
else:
|
2010-08-03 08:54:16 +00:00
|
|
|
print >>err, "%s does not look like a node directory (no .tac file)" % quote_output(basedir)
|
2007-09-19 08:50:27 +00:00
|
|
|
return 1
|
2008-02-18 07:28:17 +00:00
|
|
|
if "client" in tac:
|
|
|
|
nodetype = "client"
|
|
|
|
elif "introducer" in tac:
|
|
|
|
nodetype = "introducer"
|
|
|
|
else:
|
|
|
|
nodetype = "unknown (%s)" % tac
|
2007-11-01 22:28:50 +00:00
|
|
|
|
2007-10-15 17:25:15 +00:00
|
|
|
cmd = find_exe.find_exe('twistd')
|
2008-09-12 02:51:38 +00:00
|
|
|
if not cmd:
|
|
|
|
# If 'twistd' wasn't on $PATH, maybe we're running from source and
|
|
|
|
# Twisted was built as one of our dependencies. If so, we're at
|
|
|
|
# BASEDIR/src/allmydata/scripts/startstop_node.py, and it's at
|
2009-02-05 01:06:20 +00:00
|
|
|
# BASEDIR/support/$BINDIR/twistd
|
2008-09-12 02:51:38 +00:00
|
|
|
up = os.path.dirname
|
|
|
|
TAHOEDIR = up(up(up(up(os.path.abspath(__file__)))))
|
2009-02-05 01:06:20 +00:00
|
|
|
if sys.platform == "win32":
|
|
|
|
bin_dir = "Scripts"
|
|
|
|
else:
|
|
|
|
bin_dir = "bin"
|
|
|
|
bindir = os.path.join(TAHOEDIR, "support", bin_dir)
|
|
|
|
|
2008-09-12 02:51:38 +00:00
|
|
|
maybe = os.path.join(bindir, "twistd")
|
|
|
|
if os.path.exists(maybe):
|
|
|
|
cmd = [maybe]
|
|
|
|
oldpath = os.environ.get("PATH", "").split(os.pathsep)
|
|
|
|
os.environ["PATH"] = os.pathsep.join(oldpath + [bindir])
|
|
|
|
# sys.path and $PYTHONPATH are taken care of by the extra code in
|
|
|
|
# 'setup.py trial'
|
2009-02-05 01:06:20 +00:00
|
|
|
else:
|
|
|
|
maybe = maybe+'.py'
|
|
|
|
if os.path.exists(maybe):
|
|
|
|
cmd = [sys.executable, maybe]
|
|
|
|
oldpath = os.environ.get("PATH", "").split(os.pathsep)
|
|
|
|
os.environ["PATH"] = os.pathsep.join(oldpath + [bindir])
|
|
|
|
# sys.path and $PYTHONPATH are taken care of by the extra code in
|
|
|
|
# 'setup.py trial'
|
|
|
|
|
2007-10-15 17:25:15 +00:00
|
|
|
if not cmd:
|
2007-09-20 19:37:50 +00:00
|
|
|
print "Can't find twistd (it comes with Twisted). Aborting."
|
|
|
|
sys.exit(1)
|
2007-10-15 17:25:15 +00:00
|
|
|
|
2008-02-18 07:28:17 +00:00
|
|
|
cmd.extend(["-y", tac])
|
2008-09-25 01:03:02 +00:00
|
|
|
if opts["syslog"]:
|
|
|
|
cmd.append("--syslog")
|
|
|
|
elif nodetype in ("client", "introducer"):
|
2008-02-18 07:31:28 +00:00
|
|
|
fileutil.make_dirs(os.path.join(basedir, "logs"))
|
2008-02-18 07:28:17 +00:00
|
|
|
cmd.extend(["--logfile", os.path.join("logs", "twistd.log")])
|
2008-09-25 01:03:02 +00:00
|
|
|
if opts["profile"]:
|
2007-09-21 22:03:47 +00:00
|
|
|
cmd.extend(["--profile=profiling_results.prof", "--savestats",])
|
2007-09-20 19:37:50 +00:00
|
|
|
curdir = os.getcwd()
|
|
|
|
try:
|
|
|
|
os.chdir(basedir)
|
|
|
|
rc = os.system(' '.join(cmd))
|
|
|
|
finally:
|
|
|
|
os.chdir(curdir)
|
2007-07-11 02:05:18 +00:00
|
|
|
if rc == 0:
|
2008-02-18 07:28:17 +00:00
|
|
|
print >>out, "%s node probably started" % nodetype
|
2007-07-11 02:05:18 +00:00
|
|
|
return 0
|
|
|
|
else:
|
2008-02-18 07:28:17 +00:00
|
|
|
print >>err, "%s node probably not started" % nodetype
|
2007-07-11 02:05:18 +00:00
|
|
|
return 1
|
|
|
|
|
2007-09-21 22:03:15 +00:00
|
|
|
def do_stop(basedir, out=sys.stdout, err=sys.stderr):
|
2010-08-03 08:54:16 +00:00
|
|
|
print >>out, "STOPPING", quote_output(basedir)
|
2007-07-11 02:05:18 +00:00
|
|
|
pidfile = os.path.join(basedir, "twistd.pid")
|
|
|
|
if not os.path.exists(pidfile):
|
2010-08-03 08:54:16 +00:00
|
|
|
print >>err, "%s does not look like a running node directory (no twistd.pid)" % quote_output(basedir)
|
2009-02-26 02:52:45 +00:00
|
|
|
# we define rc=2 to mean "nothing is running, but it wasn't me who
|
|
|
|
# stopped it"
|
2007-07-11 02:05:18 +00:00
|
|
|
return 2
|
|
|
|
pid = open(pidfile, "r").read()
|
|
|
|
pid = int(pid)
|
|
|
|
|
2007-10-29 18:43:35 +00:00
|
|
|
# kill it hard (SIGKILL), delete the twistd.pid file, then wait for the
|
2008-12-30 08:20:22 +00:00
|
|
|
# process itself to go away. If it hasn't gone away after 20 seconds, warn
|
2007-10-29 18:43:35 +00:00
|
|
|
# the user but keep waiting until they give up.
|
2007-08-09 15:57:45 +00:00
|
|
|
try:
|
2007-10-29 18:43:35 +00:00
|
|
|
os.kill(pid, signal.SIGKILL)
|
2007-08-09 15:57:45 +00:00
|
|
|
except OSError, oserr:
|
|
|
|
if oserr.errno == 3:
|
|
|
|
print oserr.strerror
|
2007-10-29 18:43:35 +00:00
|
|
|
# the process didn't exist, so wipe the pid file
|
|
|
|
os.remove(pidfile)
|
2009-02-26 02:52:45 +00:00
|
|
|
return 2
|
2007-08-09 15:57:45 +00:00
|
|
|
else:
|
|
|
|
raise
|
2007-10-29 18:43:35 +00:00
|
|
|
try:
|
|
|
|
os.remove(pidfile)
|
|
|
|
except EnvironmentError:
|
|
|
|
pass
|
|
|
|
start = time.time()
|
2007-07-11 02:05:18 +00:00
|
|
|
time.sleep(0.1)
|
2009-01-06 14:51:06 +00:00
|
|
|
wait = 40
|
2007-10-29 18:43:35 +00:00
|
|
|
first_time = True
|
|
|
|
while True:
|
|
|
|
# poll once per second until we see the process is no longer running
|
2007-07-11 02:05:18 +00:00
|
|
|
try:
|
|
|
|
os.kill(pid, 0)
|
|
|
|
except OSError:
|
|
|
|
print >>out, "process %d is dead" % pid
|
|
|
|
return
|
2007-10-29 18:43:35 +00:00
|
|
|
wait -= 1
|
|
|
|
if wait < 0:
|
|
|
|
if first_time:
|
|
|
|
print >>err, ("It looks like pid %d is still running "
|
|
|
|
"after %d seconds" % (pid,
|
|
|
|
(time.time() - start)))
|
|
|
|
print >>err, "I will keep watching it until you interrupt me."
|
|
|
|
wait = 10
|
|
|
|
first_time = False
|
|
|
|
else:
|
|
|
|
print >>err, "pid %d still running after %d seconds" % \
|
|
|
|
(pid, (time.time() - start))
|
|
|
|
wait = 10
|
2007-07-11 02:05:18 +00:00
|
|
|
time.sleep(1)
|
2009-02-26 02:52:45 +00:00
|
|
|
# we define rc=1 to mean "I think something is still running, sorry"
|
2007-07-11 02:05:18 +00:00
|
|
|
return 1
|
|
|
|
|
|
|
|
def start(config, stdout, stderr):
|
|
|
|
rc = 0
|
|
|
|
for basedir in config['basedirs']:
|
2008-09-25 01:03:02 +00:00
|
|
|
rc = do_start(basedir, config, stdout, stderr) or rc
|
2007-07-11 02:05:18 +00:00
|
|
|
return rc
|
|
|
|
|
|
|
|
def stop(config, stdout, stderr):
|
|
|
|
rc = 0
|
|
|
|
for basedir in config['basedirs']:
|
2007-09-21 22:03:15 +00:00
|
|
|
rc = do_stop(basedir, stdout, stderr) or rc
|
2007-07-11 02:05:18 +00:00
|
|
|
return rc
|
|
|
|
|
|
|
|
def restart(config, stdout, stderr):
|
|
|
|
rc = 0
|
|
|
|
for basedir in config['basedirs']:
|
2007-09-21 22:03:15 +00:00
|
|
|
rc = do_stop(basedir, stdout, stderr) or rc
|
2009-02-25 04:42:13 +00:00
|
|
|
if rc == 2:
|
2007-07-11 02:05:18 +00:00
|
|
|
print >>stderr, "ignoring couldn't-stop"
|
|
|
|
rc = 0
|
|
|
|
if rc:
|
|
|
|
print >>stderr, "not restarting"
|
|
|
|
return rc
|
|
|
|
for basedir in config['basedirs']:
|
2008-09-25 01:03:02 +00:00
|
|
|
rc = do_start(basedir, config, stdout, stderr) or rc
|
2007-07-11 02:05:18 +00:00
|
|
|
return rc
|
|
|
|
|
2008-01-10 02:54:12 +00:00
|
|
|
def run(config, stdout, stderr):
|
|
|
|
from twisted.internet import reactor
|
|
|
|
from twisted.python import log, logfile
|
|
|
|
from allmydata import client
|
|
|
|
|
2010-08-03 08:54:16 +00:00
|
|
|
basedir = config['basedirs'][0]
|
|
|
|
precondition(isinstance(basedir, unicode), basedir)
|
|
|
|
|
|
|
|
if not os.path.isdir(basedir):
|
|
|
|
print >>stderr, "%s does not look like a directory at all" % quote_output(basedir)
|
|
|
|
return 1
|
|
|
|
for fn in listdir_unicode(basedir):
|
|
|
|
if fn.endswith(u".tac"):
|
|
|
|
tac = str(fn)
|
|
|
|
break
|
2008-01-10 02:54:12 +00:00
|
|
|
else:
|
2010-08-03 08:54:16 +00:00
|
|
|
print >>stderr, "%s does not look like a node directory (no .tac file)" % quote_output(basedir)
|
|
|
|
return 1
|
|
|
|
if "client" not in tac:
|
|
|
|
print >>stderr, ("%s looks like it contains a non-client node (%s).\n"
|
|
|
|
"Use 'tahoe start' instead of 'tahoe run'."
|
|
|
|
% (quote_output(basedir), tac))
|
|
|
|
return 1
|
|
|
|
|
|
|
|
os.chdir(basedir)
|
2008-01-10 02:54:12 +00:00
|
|
|
|
|
|
|
# set up twisted logging. this will become part of the node rsn.
|
|
|
|
logdir = os.path.join(basedir, 'logs')
|
|
|
|
if not os.path.exists(logdir):
|
|
|
|
os.makedirs(logdir)
|
|
|
|
lf = logfile.LogFile('tahoesvc.log', logdir)
|
|
|
|
log.startLogging(lf)
|
|
|
|
|
|
|
|
# run the node itself
|
|
|
|
c = client.Client(basedir)
|
2008-01-11 03:14:00 +00:00
|
|
|
reactor.callLater(0, c.startService) # after reactor startup
|
2008-01-10 02:54:12 +00:00
|
|
|
reactor.run()
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
2007-07-11 02:05:18 +00:00
|
|
|
|
|
|
|
subCommands = [
|
|
|
|
["start", None, StartOptions, "Start a node (of any type)."],
|
|
|
|
["stop", None, StopOptions, "Stop a node."],
|
|
|
|
["restart", None, RestartOptions, "Restart a node."],
|
2008-01-10 02:54:12 +00:00
|
|
|
["run", None, RunOptions, "Run a node synchronously."],
|
2007-07-11 02:05:18 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
dispatch = {
|
|
|
|
"start": start,
|
|
|
|
"stop": stop,
|
|
|
|
"restart": restart,
|
2008-01-10 02:54:12 +00:00
|
|
|
"run": run,
|
2007-07-11 02:05:18 +00:00
|
|
|
}
|