tahoe-lafs/src/allmydata/scripts/startstop_node.py

230 lines
7.5 KiB
Python
Raw Normal View History

2007-07-11 02:05:18 +00:00
import os, sys, signal, time
2007-07-11 02:05:18 +00:00
from twisted.python import usage
from allmydata.scripts.common import BasedirMixin
from allmydata.util import fileutil, find_exe
2007-07-11 02:05:18 +00:00
class StartOptions(BasedirMixin, usage.Options):
optParameters = [
["basedir", "C", None, "which directory to start the node in"],
]
2007-09-21 22:03:47 +00:00
optFlags = [
["profile", "p", "whether to 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
class StopOptions(BasedirMixin, usage.Options):
optParameters = [
["basedir", "C", None, "which directory to stop the node in"],
]
class RestartOptions(BasedirMixin, usage.Options):
optParameters = [
["basedir", "C", None, "which directory to restart the node in"],
]
optFlags = [
["profile", "p", "whether to run under the Python profiler, putting results in \"profiling_results.prof\""],
["syslog", None, "tell the node to log to syslog, not a file"],
]
2007-07-11 02:05:18 +00:00
class RunOptions(usage.Options):
optParameters = [
["basedir", "C", None, "which directory to run the node in, CWD by default"],
]
def do_start(basedir, opts, out=sys.stdout, err=sys.stderr):
2007-07-11 02:05:18 +00:00
print >>out, "STARTING", basedir
if not os.path.isdir(basedir):
print >>err, "%s does not look like a directory at all" % basedir
return 1
for fn in os.listdir(basedir):
if fn.endswith(".tac"):
tac = fn
break
2007-07-11 02:05:18 +00:00
else:
print >>err, "%s does not look like a node directory (no .tac file)" % basedir
return 1
if "client" in tac:
nodetype = "client"
elif "introducer" in tac:
nodetype = "introducer"
else:
nodetype = "unknown (%s)" % tac
cmd = find_exe.find_exe('twistd')
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
# BASEDIR/support/$BINDIR/twistd
up = os.path.dirname
TAHOEDIR = up(up(up(up(os.path.abspath(__file__)))))
if sys.platform == "win32":
bin_dir = "Scripts"
else:
bin_dir = "bin"
bindir = os.path.join(TAHOEDIR, "support", bin_dir)
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'
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'
if not cmd:
print "Can't find twistd (it comes with Twisted). Aborting."
sys.exit(1)
cmd.extend(["-y", tac])
if opts["syslog"]:
cmd.append("--syslog")
elif nodetype in ("client", "introducer"):
fileutil.make_dirs(os.path.join(basedir, "logs"))
cmd.extend(["--logfile", os.path.join("logs", "twistd.log")])
if opts["profile"]:
2007-09-21 22:03:47 +00:00
cmd.extend(["--profile=profiling_results.prof", "--savestats",])
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:
print >>out, "%s node probably started" % nodetype
2007-07-11 02:05:18 +00:00
return 0
else:
print >>err, "%s node probably not started" % nodetype
2007-07-11 02:05:18 +00:00
return 1
def do_stop(basedir, out=sys.stdout, err=sys.stderr):
2007-07-11 02:05:18 +00:00
print >>out, "STOPPING", basedir
pidfile = os.path.join(basedir, "twistd.pid")
if not os.path.exists(pidfile):
print >>err, "%s does not look like a running node directory (no twistd.pid)" % basedir
# 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)
# kill it hard (SIGKILL), delete the twistd.pid file, then wait for the
# process itself to go away. If it hasn't gone away after 20 seconds, warn
# the user but keep waiting until they give up.
try:
os.kill(pid, signal.SIGKILL)
except OSError, oserr:
if oserr.errno == 3:
print oserr.strerror
# the process didn't exist, so wipe the pid file
os.remove(pidfile)
return 2
else:
raise
try:
os.remove(pidfile)
except EnvironmentError:
pass
start = time.time()
2007-07-11 02:05:18 +00:00
time.sleep(0.1)
wait = 40
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
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)
# 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']:
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']:
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']:
rc = do_stop(basedir, stdout, stderr) or rc
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']:
rc = do_start(basedir, config, stdout, stderr) or rc
2007-07-11 02:05:18 +00:00
return rc
def run(config, stdout, stderr):
from twisted.internet import reactor
from twisted.python import log, logfile
from allmydata import client
basedir = config['basedir']
if basedir is None:
basedir = '.'
else:
os.chdir(basedir)
# 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
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."],
["run", None, RunOptions, "Run a node synchronously."],
2007-07-11 02:05:18 +00:00
]
dispatch = {
"start": start,
"stop": stop,
"restart": restart,
"run": run,
2007-07-11 02:05:18 +00:00
}