mirror of
https://github.com/tahoe-lafs/tahoe-lafs.git
synced 2024-12-20 21:43:09 +00:00
Merge branch '1159-notac-4'
This commit is contained in:
commit
a5daf73361
@ -39,7 +39,7 @@ class BasedirOptions(BaseOptions):
|
||||
default_nodedir = _default_nodedir
|
||||
|
||||
optParameters = [
|
||||
["basedir", "C", None, "Same as --node-directory (default %s)."
|
||||
["basedir", "C", None, "Specify which Tahoe base directory should be used. [default: %s]"
|
||||
% get_default_nodedir()],
|
||||
]
|
||||
|
||||
@ -67,6 +67,21 @@ class BasedirOptions(BaseOptions):
|
||||
if not self['basedir']:
|
||||
raise usage.UsageError("A base directory for the node must be provided.")
|
||||
|
||||
class NoDefaultBasedirOptions(BasedirOptions):
|
||||
default_nodedir = None
|
||||
|
||||
optParameters = [
|
||||
["basedir", "C", None, "Specify which Tahoe base directory should be used."],
|
||||
]
|
||||
|
||||
# This is overridden in order to ensure we get a "Wrong number of arguments."
|
||||
# error when more than one argument is given.
|
||||
def parseArgs(self, basedir=None):
|
||||
BasedirOptions.parseArgs(self, basedir)
|
||||
|
||||
def getSynopsis(self):
|
||||
return "Usage: %s [global-opts] %s [options] NODEDIR" % (self.command_name, self.subcommand_name)
|
||||
|
||||
|
||||
DEFAULT_ALIAS = u"tahoe"
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
|
||||
import os, sys
|
||||
from allmydata.scripts.common import BasedirOptions
|
||||
from allmydata.scripts.common import BasedirOptions, NoDefaultBasedirOptions
|
||||
from allmydata.util.assertutil import precondition
|
||||
from allmydata.util.encodingutil import listdir_unicode, argv_to_unicode, quote_output
|
||||
import allmydata
|
||||
@ -19,6 +19,11 @@ class CreateClientOptions(BasedirOptions):
|
||||
def getSynopsis(self):
|
||||
return "Usage: %s [global-opts] create-client [options] [NODEDIR]" % (self.command_name,)
|
||||
|
||||
# This is overridden in order to ensure we get a "Wrong number of arguments."
|
||||
# error when more than one argument is given.
|
||||
def parseArgs(self, basedir=None):
|
||||
BasedirOptions.parseArgs(self, basedir)
|
||||
|
||||
|
||||
class CreateNodeOptions(CreateClientOptions):
|
||||
optFlags = [
|
||||
@ -29,11 +34,8 @@ class CreateNodeOptions(CreateClientOptions):
|
||||
return "Usage: %s [global-opts] create-node [options] [NODEDIR]" % (self.command_name,)
|
||||
|
||||
|
||||
class CreateIntroducerOptions(BasedirOptions):
|
||||
default_nodedir = None
|
||||
|
||||
def getSynopsis(self):
|
||||
return "Usage: %s [global-opts] create-introducer [options] NODEDIR" % (self.command_name,)
|
||||
class CreateIntroducerOptions(NoDefaultBasedirOptions):
|
||||
subcommand_name = "create-introducer"
|
||||
|
||||
|
||||
client_tac = """
|
||||
|
@ -1,14 +1,12 @@
|
||||
|
||||
import os, sys
|
||||
from allmydata.scripts.common import BasedirOptions
|
||||
from allmydata.scripts.common import NoDefaultBasedirOptions
|
||||
from allmydata.util.assertutil import precondition
|
||||
from allmydata.util.encodingutil import listdir_unicode, quote_output
|
||||
|
||||
class CreateKeyGeneratorOptions(BasedirOptions):
|
||||
default_nodedir = None
|
||||
|
||||
def getSynopsis(self):
|
||||
return "Usage: %s [global-opts] create-key-generator [options] NODEDIR" % (self.command_name,)
|
||||
class CreateKeyGeneratorOptions(NoDefaultBasedirOptions):
|
||||
subcommand_name = "create-key-generator"
|
||||
|
||||
|
||||
keygen_tac = """
|
||||
|
@ -1,79 +1,163 @@
|
||||
|
||||
import os, sys, signal, time
|
||||
from allmydata.scripts.common import BasedirOptions
|
||||
from twisted.scripts import twistd
|
||||
from twisted.python import usage
|
||||
from allmydata.util import fileutil
|
||||
from allmydata.util.assertutil import precondition
|
||||
from allmydata.util.encodingutil import listdir_unicode, quote_output
|
||||
|
||||
|
||||
class StartOptions(BasedirOptions):
|
||||
optFlags = [
|
||||
["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."],
|
||||
]
|
||||
subcommand_name = "start"
|
||||
|
||||
def parseArgs(self, basedir=None, *twistd_args):
|
||||
# This can't handle e.g. 'tahoe start --nodaemon', since '--nodaemon'
|
||||
# looks like an option to the tahoe subcommand, not to twistd.
|
||||
# So you can either use 'tahoe start' or 'tahoe start NODEDIR --TWISTD-OPTIONS'.
|
||||
# Note that 'tahoe --node-directory=NODEDIR start --TWISTD-OPTIONS' also
|
||||
# isn't allowed, unfortunately.
|
||||
|
||||
BasedirOptions.parseArgs(self, basedir)
|
||||
self.twistd_args = twistd_args
|
||||
|
||||
def getSynopsis(self):
|
||||
return "Usage: %s [global-opts] start [options] [NODEDIR]" % (self.command_name,)
|
||||
return "Usage: %s [global-opts] %s [options] [NODEDIR [twistd-options]]" % (self.command_name, self.subcommand_name)
|
||||
|
||||
def getUsage(self, width=None):
|
||||
t = BasedirOptions.getUsage(self, width) + "\n"
|
||||
twistd_options = str(MyTwistdConfig()).partition("\n")[2].partition("\n\n")[0]
|
||||
t += twistd_options.replace("Options:", "twistd-options:", 1)
|
||||
t += """
|
||||
|
||||
Note that if any twistd-options are used, NODEDIR must be specified explicitly
|
||||
(not by default or using -C/--basedir or -d/--node-directory), and followed by
|
||||
the twistd-options.
|
||||
"""
|
||||
return t
|
||||
|
||||
class StopOptions(BasedirOptions):
|
||||
def parseArgs(self, basedir=None):
|
||||
BasedirOptions.parseArgs(self, basedir)
|
||||
|
||||
def getSynopsis(self):
|
||||
return "Usage: %s [global-opts] stop [options] [NODEDIR]" % (self.command_name,)
|
||||
|
||||
class RestartOptions(StartOptions):
|
||||
subcommand_name = "restart"
|
||||
|
||||
class RestartOptions(BasedirOptions):
|
||||
optFlags = [
|
||||
["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."],
|
||||
]
|
||||
|
||||
def getSynopsis(self):
|
||||
return "Usage: %s [global-opts] restart [options] [NODEDIR]" % (self.command_name,)
|
||||
class RunOptions(StartOptions):
|
||||
subcommand_name = "run"
|
||||
|
||||
|
||||
class RunOptions(BasedirOptions):
|
||||
default_nodedir = u"."
|
||||
class MyTwistdConfig(twistd.ServerOptions):
|
||||
subCommands = [("StartTahoeNode", None, usage.Options, "node")]
|
||||
|
||||
def getSynopsis(self):
|
||||
return "Usage: %s [global-opts] run [options] [NODEDIR]" % (self.command_name,)
|
||||
class StartTahoeNodePlugin:
|
||||
tapname = "tahoenode"
|
||||
def __init__(self, nodetype, basedir):
|
||||
self.nodetype = nodetype
|
||||
self.basedir = basedir
|
||||
def makeService(self, so):
|
||||
# delay this import as late as possible, to allow twistd's code to
|
||||
# accept --reactor= selection. N.B.: this can't actually work until
|
||||
# this file, and all the __init__.py files above it, also respect the
|
||||
# prohibition on importing anything that transitively imports
|
||||
# twisted.internet.reactor . That will take a lot of work.
|
||||
if self.nodetype == "client":
|
||||
from allmydata.client import Client
|
||||
return Client(self.basedir)
|
||||
if self.nodetype == "introducer":
|
||||
from allmydata.introducer.server import IntroducerNode
|
||||
return IntroducerNode(self.basedir)
|
||||
if self.nodetype == "key-generator":
|
||||
from allmydata.key_generator import KeyGeneratorService
|
||||
return KeyGeneratorService(default_key_size=2048)
|
||||
if self.nodetype == "stats-gatherer":
|
||||
from allmydata.stats import StatsGathererService
|
||||
return StatsGathererService(verbose=True)
|
||||
raise ValueError("unknown nodetype %s" % self.nodetype)
|
||||
|
||||
|
||||
def start(opts, out=sys.stdout, err=sys.stderr):
|
||||
basedir = opts['basedir']
|
||||
print >>out, "STARTING", quote_output(basedir)
|
||||
if not os.path.isdir(basedir):
|
||||
print >>err, "%s does not look like a directory at all" % quote_output(basedir)
|
||||
return 1
|
||||
def identify_node_type(basedir):
|
||||
for fn in listdir_unicode(basedir):
|
||||
if fn.endswith(u".tac"):
|
||||
tac = str(fn)
|
||||
break
|
||||
else:
|
||||
print >>err, "%s does not look like a node directory (no .tac file)" % quote_output(basedir)
|
||||
return 1
|
||||
if "client" in tac:
|
||||
nodetype = "client"
|
||||
elif "introducer" in tac:
|
||||
nodetype = "introducer"
|
||||
else:
|
||||
nodetype = "unknown (%s)" % tac
|
||||
return None
|
||||
|
||||
args = ["twistd", "-y", tac]
|
||||
if opts["syslog"]:
|
||||
args.append("--syslog")
|
||||
elif nodetype in ("client", "introducer"):
|
||||
fileutil.make_dirs(os.path.join(basedir, "logs"))
|
||||
args.extend(["--logfile", os.path.join("logs", "twistd.log")])
|
||||
if opts["profile"]:
|
||||
args.extend(["--profile=profiling_results.prof", "--savestats",])
|
||||
# now we're committed
|
||||
for t in ("client", "introducer", "key-generator", "stats-gatherer"):
|
||||
if t in tac:
|
||||
return t
|
||||
return None
|
||||
|
||||
def start(config, out=sys.stdout, err=sys.stderr):
|
||||
basedir = config['basedir']
|
||||
print >>out, "STARTING", quote_output(basedir)
|
||||
if not os.path.isdir(basedir):
|
||||
print >>err, "%s does not look like a directory at all" % quote_output(basedir)
|
||||
return 1
|
||||
nodetype = identify_node_type(basedir)
|
||||
if not nodetype:
|
||||
print >>err, "%s is not a recognizable node directory" % quote_output(basedir)
|
||||
return 1
|
||||
# Now prepare to turn into a twistd process. This os.chdir is the point
|
||||
# of no return.
|
||||
os.chdir(basedir)
|
||||
from twisted.scripts import twistd
|
||||
sys.argv = args
|
||||
twistd.run()
|
||||
# run() doesn't return: the parent does os._exit(0) in daemonize(), so
|
||||
# we'll never get here. If application setup fails (e.g. ImportError),
|
||||
# run() will raise an exception.
|
||||
twistd_args = []
|
||||
if (nodetype in ("client", "introducer")
|
||||
and "--nodaemon" not in config.twistd_args
|
||||
and "--syslog" not in config.twistd_args
|
||||
and "--logfile" not in config.twistd_args):
|
||||
fileutil.make_dirs(os.path.join(basedir, "logs"))
|
||||
twistd_args.extend(["--logfile", os.path.join("logs", "twistd.log")])
|
||||
twistd_args.extend(config.twistd_args)
|
||||
twistd_args.append("StartTahoeNode") # point at our StartTahoeNodePlugin
|
||||
|
||||
twistd_config = MyTwistdConfig()
|
||||
try:
|
||||
twistd_config.parseOptions(twistd_args)
|
||||
except usage.error, ue:
|
||||
# these arguments were unsuitable for 'twistd'
|
||||
print >>err, config
|
||||
print >>err, "tahoe %s: usage error from twistd: %s\n" % (config.subcommand_name, ue)
|
||||
return 1
|
||||
twistd_config.loadedPlugins = {"StartTahoeNode": StartTahoeNodePlugin(nodetype, basedir)}
|
||||
|
||||
# On Unix-like platforms:
|
||||
# Unless --nodaemon was provided, the twistd.runApp() below spawns off a
|
||||
# child process, and the parent calls os._exit(0), so there's no way for
|
||||
# us to get control afterwards, even with 'except SystemExit'. If
|
||||
# application setup fails (e.g. ImportError), runApp() will raise an
|
||||
# exception.
|
||||
#
|
||||
# So if we wanted to do anything with the running child, we'd have two
|
||||
# options:
|
||||
#
|
||||
# * fork first, and have our child wait for the runApp() child to get
|
||||
# running. (note: just fork(). This is easier than fork+exec, since we
|
||||
# don't have to get PATH and PYTHONPATH set up, since we're not
|
||||
# starting a *different* process, just cloning a new instance of the
|
||||
# current process)
|
||||
# * or have the user run a separate command some time after this one
|
||||
# exits.
|
||||
#
|
||||
# For Tahoe, we don't need to do anything with the child, so we can just
|
||||
# let it exit.
|
||||
#
|
||||
# On Windows:
|
||||
# twistd does not fork; it just runs in the current process whether or not
|
||||
# --nodaemon is specified. (As on Unix, --nodaemon does have the side effect
|
||||
# of causing us to log to stdout/stderr.)
|
||||
|
||||
if "--nodaemon" in twistd_args or sys.platform == "win32":
|
||||
verb = "running"
|
||||
else:
|
||||
verb = "starting"
|
||||
|
||||
print >>out, "%s node in %s" % (verb, basedir)
|
||||
twistd.runApp(twistd_config)
|
||||
# we should only reach here if --nodaemon or equivalent was used
|
||||
return 0
|
||||
|
||||
def stop(config, out=sys.stdout, err=sys.stderr):
|
||||
basedir = config['basedir']
|
||||
@ -143,44 +227,12 @@ def restart(config, stdout, stderr):
|
||||
return start(config, stdout, stderr)
|
||||
|
||||
def run(config, stdout, stderr):
|
||||
from twisted.internet import reactor
|
||||
from twisted.python import log, logfile
|
||||
from allmydata import client
|
||||
config.twistd_args = config.twistd_args + ("--nodaemon",)
|
||||
# Previously we would do the equivalent of adding ("--logfile", "tahoesvc.log"),
|
||||
# but that redirects stdout/stderr which is often unhelpful, and the user can
|
||||
# add that option explicitly if they want.
|
||||
|
||||
basedir = config['basedir']
|
||||
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
|
||||
else:
|
||||
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)
|
||||
|
||||
# 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)
|
||||
reactor.callLater(0, c.startService) # after reactor startup
|
||||
reactor.run()
|
||||
|
||||
return 0
|
||||
return start(config, stdout, stderr)
|
||||
|
||||
|
||||
subCommands = [
|
||||
|
@ -1,14 +1,12 @@
|
||||
|
||||
import os, sys
|
||||
from allmydata.scripts.common import BasedirOptions
|
||||
from allmydata.scripts.common import NoDefaultBasedirOptions
|
||||
from allmydata.util.assertutil import precondition
|
||||
from allmydata.util.encodingutil import listdir_unicode, quote_output
|
||||
|
||||
class CreateStatsGathererOptions(BasedirOptions):
|
||||
default_nodedir = None
|
||||
|
||||
def getSynopsis(self):
|
||||
return "Usage: %s [global-opts] create-stats-gatherer [options] NODEDIR" % (self.command_name,)
|
||||
class CreateStatsGathererOptions(NoDefaultBasedirOptions):
|
||||
subcommand_name = "create-stats-gatherer"
|
||||
|
||||
|
||||
stats_gatherer_tac = """
|
||||
|
@ -646,7 +646,7 @@ class Help(unittest.TestCase):
|
||||
|
||||
def test_start(self):
|
||||
help = str(startstop_node.StartOptions())
|
||||
self.failUnlessIn(" [global-opts] start [options] [NODEDIR]", help)
|
||||
self.failUnlessIn(" [global-opts] start [options] [NODEDIR [twistd-options]]", help)
|
||||
|
||||
def test_stop(self):
|
||||
help = str(startstop_node.StopOptions())
|
||||
@ -654,11 +654,11 @@ class Help(unittest.TestCase):
|
||||
|
||||
def test_restart(self):
|
||||
help = str(startstop_node.RestartOptions())
|
||||
self.failUnlessIn(" [global-opts] restart [options] [NODEDIR]", help)
|
||||
self.failUnlessIn(" [global-opts] restart [options] [NODEDIR [twistd-options]]", help)
|
||||
|
||||
def test_run(self):
|
||||
help = str(startstop_node.RunOptions())
|
||||
self.failUnlessIn(" [global-opts] run [options] [NODEDIR]", help)
|
||||
self.failUnlessIn(" [global-opts] run [options] [NODEDIR [twistd-options]]", help)
|
||||
|
||||
def test_create_client(self):
|
||||
help = str(create_node.CreateClientOptions())
|
||||
@ -3869,6 +3869,9 @@ class Options(unittest.TestCase):
|
||||
o = self.parse(["--node-directory", "there", "start"])
|
||||
self.failUnlessEqual(o["basedir"], os.path.abspath("there"))
|
||||
|
||||
o = self.parse(["start", "here", "--nodaemon"])
|
||||
self.failUnlessEqual(o["basedir"], os.path.abspath("here"))
|
||||
|
||||
self.failUnlessRaises(usage.UsageError, self.parse,
|
||||
["--basedir", "there", "start"])
|
||||
self.failUnlessRaises(usage.UsageError, self.parse,
|
||||
@ -3886,3 +3889,7 @@ class Options(unittest.TestCase):
|
||||
["--node-directory=there",
|
||||
"start", "--basedir=here", "anywhere"])
|
||||
|
||||
self.failUnlessRaises(usage.UsageError, self.parse,
|
||||
["--node-directory=there", "start", "--nodaemon"])
|
||||
self.failUnlessRaises(usage.UsageError, self.parse,
|
||||
["start", "--basedir=here", "--nodaemon"])
|
||||
|
@ -668,7 +668,7 @@ class RunNode(common_util.SignalMixin, unittest.TestCase, pollmixin.PollMixin,
|
||||
def _cb(res):
|
||||
out, err, rc_or_sig = res
|
||||
self.failUnlessEqual(rc_or_sig, 1)
|
||||
self.failUnless("does not look like a node directory" in err, err)
|
||||
self.failUnless("is not a recognizable node directory" in err, err)
|
||||
d.addCallback(_cb)
|
||||
|
||||
def _then_stop_it(res):
|
||||
@ -689,7 +689,7 @@ class RunNode(common_util.SignalMixin, unittest.TestCase, pollmixin.PollMixin,
|
||||
def _cb3(res):
|
||||
out, err, rc_or_sig = res
|
||||
self.failUnlessEqual(rc_or_sig, 1)
|
||||
self.failUnless("does not look like a directory at all" in err, err)
|
||||
self.failUnlessIn("does not look like a directory at all", err)
|
||||
d.addCallback(_cb3)
|
||||
return d
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user