Ticket #1159: notac.diff

File notac.diff, 10.6 KB (added by warner, at 2012-05-23T07:20:11Z)

stop using contents of .tac files

  • src/allmydata/scripts/startstop_node.py

    diff --git a/src/allmydata/scripts/startstop_node.py b/src/allmydata/scripts/startstop_node.py
    index 5045bd6..ecf67ae 100644
    a b  
    11
    22import os, sys, signal, time
     3from twisted.scripts import twistd
     4from twisted.python import usage
    35from allmydata.scripts.common import BasedirMixin, BaseOptions
    46from allmydata.util import fileutil
    5 from allmydata.util.assertutil import precondition
    67from allmydata.util.encodingutil import listdir_unicode, quote_output
    78
    89
    910class StartOptions(BasedirMixin, BaseOptions):
    10     optFlags = [
    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."],
    13         ]
     11    def parseArgs(self, basedir=None, *twistd_args):
     12        # this can't handle e.g. 'tahoe start --nodaemon', since then
     13        # --nodaemon looks like a basedir. So you can either use 'tahoe
     14        # start' or 'tahoe start BASEDIR --TWISTD-OPTIONS'.
     15        BasedirMixin.parseArgs(self, basedir)
     16        if not os.path.isdir(self['basedir']):
     17            raise usage.UsageError("--basedir '%s' doesn't exist" %
     18                                   quote_output(self['basedir']))
     19        self.twistd_args = twistd_args
    1420
    1521    def getSynopsis(self):
    1622        return "Usage:  %s start [options] [NODEDIR]" % (self.command_name,)
    class StopOptions(BasedirMixin, BaseOptions): 
    2127        return "Usage:  %s stop [options] [NODEDIR]" % (self.command_name,)
    2228
    2329
    24 class RestartOptions(BasedirMixin, BaseOptions):
    25     optFlags = [
    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."],
    28         ]
    29 
     30class RestartOptions(StartOptions):
    3031    def getSynopsis(self):
    3132        return "Usage:  %s restart [options] [NODEDIR]" % (self.command_name,)
    3233
    33 
    34 class RunOptions(BasedirMixin, BaseOptions):
    35     default_nodedir = u"."
    36 
    37     optParameters = [
    38         ["node-directory", "d", None, "Specify the directory of the node to be run. [default, for 'tahoe run' only: current directory]"],
    39     ]
    40 
     34class RunOptions(StartOptions):
    4135    def getSynopsis(self):
    4236        return "Usage:  %s run [options] [NODEDIR]" % (self.command_name,)
    4337
    4438
    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)
    50         return 1
     39class MyTwistdConfig(twistd.ServerOptions):
     40    subCommands = [("XYZ", None, usage.Options, "node")]
     41
     42class NodeStartingPlugin:
     43    tapname = "xyznode"
     44    def __init__(self, nodetype, basedir):
     45        self.nodetype = nodetype
     46        self.basedir = basedir
     47    def makeService(self, so):
     48        # delay this import as late as possible, to allow twistd's code to
     49        # accept --reactor= selection. N.B.: this can't actually work until
     50        # this file, and all the __init__.py files above it, also respect the
     51        # prohibition on importing anything that transitively imports
     52        # twisted.internet.reactor . That will take a lot of work.
     53        if self.nodetype == "client":
     54            from allmydata.client import Client
     55            return Client(self.basedir)
     56        if self.nodetype == "introducer":
     57            from allmydata.introducer.server import IntroducerNode
     58            return IntroducerNode(self.basedir)
     59        if self.nodetype == "key-generator":
     60            from allmydata.key_generator import KeyGeneratorService
     61            return KeyGeneratorService(default_key_size=2048)
     62        if self.nodetype == "stats-gatherer":
     63            from allmydata.stats import StatsGathererService
     64            return StatsGathererService(verbose=True)
     65        raise ValueError("unknown nodetype %s" % self.nodetype)
     66
     67def identify_node_type(basedir):
    5168    for fn in listdir_unicode(basedir):
    5269        if fn.endswith(u".tac"):
    5370            tac = str(fn)
    5471            break
    5572    else:
    56         print >>err, "%s does not look like a node directory (no .tac file)" % quote_output(basedir)
    57         return 1
     73        return None
    5874    if "client" in tac:
    59         nodetype = "client"
     75        return "client"
    6076    elif "introducer" in tac:
    61         nodetype = "introducer"
     77        return "introducer"
     78    elif "key-generator" in tac:
     79        return "key-generator"
     80    elif "stats-gatherer" in tac:
     81        return "stats-gatherer"
    6282    else:
    63         nodetype = "unknown (%s)" % tac
     83        return None
    6484
    65     args = ["twistd", "-y", tac]
    66     if opts["syslog"]:
    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")])
    71     if opts["profile"]:
    72         args.extend(["--profile=profiling_results.prof", "--savestats",])
    73     # now we're committed
     85def start(config, out=sys.stdout, err=sys.stderr):
     86    basedir = config['basedir']
     87    print >>out, "STARTING", quote_output(basedir)
     88    if not os.path.isdir(basedir):
     89        print >>err, "%s does not look like a directory at all" % quote_output(basedir)
     90        return 1
     91    nodetype = identify_node_type(basedir)
     92    if not nodetype:
     93        print >>err, "%s is not a recognizable node directory" % quote_output(basedir)
     94        return 1
     95    # Now prepare to turn into a twistd process. This os.chdir is the point
     96    # of no return.
    7497    os.chdir(basedir)
    75     from twisted.scripts import twistd
    76     sys.argv = args
    77     twistd.run()
    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.
     98    twistd_args = []
     99    if (nodetype in ("client", "introducer")
     100        and "--nodaemon" not in config.twistd_args
     101        and "--syslog" not in config.twistd_args
     102        and "--logfile" not in config.twistd_args):
     103        fileutil.make_dirs(os.path.join(basedir, "logs"))
     104        twistd_args.extend(["--logfile", os.path.join("logs", "twistd.log")])
     105    twistd_args.extend(config.twistd_args)
     106    twistd_args.append("XYZ") # point at our NodeStartingPlugin
     107
     108    twistd_config = MyTwistdConfig()
     109    try:
     110        twistd_config.parseOptions(twistd_args)
     111    except usage.error, ue:
     112        # these arguments were unsuitable for 'twistd'
     113        print >>err, twistd_config
     114        print >>err, "tahoe start: %s" % (config.subCommand, ue)
     115        return 1
     116    twistd_config.loadedPlugins = {"XYZ": NodeStartingPlugin(nodetype, basedir)}
     117
     118    # Unless --nodaemon was provided, the twistd.runApp() below spawns off a
     119    # child process, and the parent calls os._exit(0), so there's no way for
     120    # us to get control afterwards, even with 'except SystemExit'. If
     121    # application setup fails (e.g. ImportError), runApp() will raise an
     122    # exception.
     123    #
     124    # So if we wanted to do anything with the running child, we'd have two
     125    # options:
     126    #
     127    #  * fork first, and have our child wait for the runApp() child to get
     128    #    running. (note: just fork(). This is easier than fork+exec, since we
     129    #    don't have to get PATH and PYTHONPATH set up, since we're not
     130    #    starting a *different* process, just cloning a new instance of the
     131    #    current process)
     132    #  * or have the user run a separate command some time after this one
     133    #    exits.
     134    #
     135    # For Tahoe, we don't need to do anything with the child, so we can just
     136    # let it exit.
     137
     138    verb = "starting"
     139    if "--nodaemon" in twistd_args:
     140        verb = "running"
     141    print >>out, "%s node in %s" % (verb, basedir)
     142    twistd.runApp(twistd_config)
     143    # we should only reach here if --nodaemon was used
     144    return 0
    81145
    82146def stop(config, out=sys.stdout, err=sys.stderr):
    83147    basedir = config['basedir']
    def restart(config, stdout, stderr): 
    147211    return start(config, stdout, stderr)
    148212
    149213def run(config, stdout, stderr):
    150     from twisted.internet import reactor
    151     from twisted.python import log, logfile
    152     from allmydata import client
    153 
    154     basedir = config['basedir']
    155     precondition(isinstance(basedir, unicode), basedir)
    156 
    157     if not os.path.isdir(basedir):
    158         print >>stderr, "%s does not look like a directory at all" % quote_output(basedir)
    159         return 1
    160     for fn in listdir_unicode(basedir):
    161         if fn.endswith(u".tac"):
    162             tac = str(fn)
    163             break
    164     else:
    165         print >>stderr, "%s does not look like a node directory (no .tac file)" % quote_output(basedir)
    166         return 1
    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))
    171         return 1
    172 
    173     os.chdir(basedir)
    174 
    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):
    178         os.makedirs(logdir)
    179     lf = logfile.LogFile('tahoesvc.log', logdir)
    180     log.startLogging(lf)
    181 
    182     # run the node itself
    183     c = client.Client(basedir)
    184     reactor.callLater(0, c.startService) # after reactor startup
    185     reactor.run()
    186 
    187     return 0
     214    config.twistd_args = config.twistd_args + ("--nodaemon",)
     215    # also ("--logfile", "tahoesvc.log")
     216    return start(config, stdout, stderr)
    188217
    189218
    190219subCommands = [
  • src/allmydata/test/test_runner.py

    diff --git a/src/allmydata/test/test_runner.py b/src/allmydata/test/test_runner.py
    index 4e9f683..53f8850 100644
    a b class RunNode(common_util.SignalMixin, unittest.TestCase, pollmixin.PollMixin, 
    664664        def _cb(res):
    665665            out, err, rc_or_sig = res
    666666            self.failUnlessEqual(rc_or_sig, 1)
    667             self.failUnless("does not look like a node directory" in err, err)
     667            self.failUnless("is not a recognizable node directory" in err, err)
    668668        d.addCallback(_cb)
    669669
    670670        def _then_stop_it(res):
    class RunNode(common_util.SignalMixin, unittest.TestCase, pollmixin.PollMixin, 
    685685        def _cb3(res):
    686686            out, err, rc_or_sig = res
    687687            self.failUnlessEqual(rc_or_sig, 1)
    688             self.failUnless("does not look like a directory at all" in err, err)
     688            self.failUnless("--basedir" in out, out)
     689            self.failUnless("doesn't exist" in out, out)
    689690        d.addCallback(_cb3)
    690691        return d
    691692