Check for the existence of any of them and if any are found raise exception which will abort the startup of the node.
This is a backwards-incompatible change for anyone who is still using old-style configuration files.
fixes #1385
Most users will not need to set ``tub.location``.
- Note that the old ``advertised_ip_addresses`` file from earlier releases is
- no longer supported. Tahoe-LAFS v1.3.0 and later will ignore this file.
-
``log_gatherer.furl = (FURL, optional)``
If provided, this contains a single FURL string that is used to contact
a "log gatherer", which will be granted access to the logport. This can
- be used by centralized storage grids to gather operational logs in a
- single place. Note that when an old-style ``BASEDIR/log_gatherer.furl`` file
- exists (see `Backwards Compatibility Files`_, below), both are used. (For
- most other items, the separate config file overrides the entry in
- ``tahoe.cfg``.)
+ be used to gather operational logs in a single place. Note that in
+ previous releases of Tahoe-LAFS, if an old-style
+ ``BASEDIR/log_gatherer.furl`` file existed it would also be used in
+ addition to this value, allowing multiple log gatherers to be used at
+ once. As of Tahoe-LAFS v1.9.0, an old-style file is ignored and a
+ warning will be emitted if one is detected. This means that as of
+ Tahoe-LAFS v1.9.0 you can have at most one log gatherer per node. See
+ ticket `#1423`_ about lifting this restriction and letting you have
+ multiple log gatherers.
+
+ .. _`#1423`: http://tahoe-lafs.org/trac/tahoe-lafs/ticket/1423
``timeout.keepalive = (integer in seconds, optional)``
"which peers am I connected to" list), and the shortened form (the first
few characters) is recorded in various log messages.
-Backwards Compatibility Files
-=============================
-
-Tahoe-LAFS releases before v1.3.0 had no ``tahoe.cfg`` file, and used distinct
-files for each item listed below. For each configuration knob, if the distinct
-file exists, it will take precedence over the corresponding item in ``tahoe.cfg``.
-
-=============================== =================================== =================
-Config setting File Comment
-=============================== =================================== =================
-``[node]nickname`` ``BASEDIR/nickname``
-``[node]web.port`` ``BASEDIR/webport``
-``[node]tub.port`` ``BASEDIR/client.port`` (for Clients, not Introducers)
-``[node]tub.port`` ``BASEDIR/introducer.port`` (for Introducers, not Clients) (note that, unlike other keys, ``tahoe.cfg`` overrides this file)
-``[node]tub.location`` ``BASEDIR/advertised_ip_addresses``
-``[node]log_gatherer.furl`` ``BASEDIR/log_gatherer.furl`` (one per line)
-``[node]timeout.keepalive`` ``BASEDIR/keepalive_timeout``
-``[node]timeout.disconnect`` ``BASEDIR/disconnect_timeout``
-``[client]introducer.furl`` ``BASEDIR/introducer.furl``
-``[client]helper.furl`` ``BASEDIR/helper.furl``
-``[client]key_generator.furl`` ``BASEDIR/key_generator.furl``
-``[client]stats_gatherer.furl`` ``BASEDIR/stats_gatherer.furl``
-``[storage]enabled`` ``BASEDIR/no_storage`` (``False`` if ``no_storage`` exists)
-``[storage]readonly`` ``BASEDIR/readonly_storage`` (``True`` if ``readonly_storage`` exists)
-``[storage]sizelimit`` ``BASEDIR/sizelimit``
-``[storage]debug_discard`` ``BASEDIR/debug_discard_storage``
-``[helper]enabled`` ``BASEDIR/run_helper`` (``True`` if ``run_helper`` exists)
-=============================== =================================== =================
-
-Note: the functionality of ``[node]ssh.port`` and ``[node]ssh.authorized_keys_file``
-were previously combined, controlled by the presence of a
-``BASEDIR/authorized_keys.SSHPORT`` file, in which the suffix of the filename
-indicated which port the ssh server should listen on, and the contents of the
-file provided the ssh public keys to accept. Support for these files has been
-removed completely. To ``ssh`` into your Tahoe-LAFS node, add ``[node]ssh.port``
-and ``[node].ssh_authorized_keys_file`` statements to your ``tahoe.cfg``.
-
-Likewise, the functionality of ``[node]tub.location`` is a variant of the
-now-unsupported ``BASEDIR/advertised_ip_addresses`` . The old file was additive
-(the addresses specified in ``advertised_ip_addresses`` were used in addition to
-any that were automatically discovered), whereas the new ``tahoe.cfg`` directive
-is not (``tub.location`` is used verbatim).
-
Example
=======
[helper]
enabled = True
+
+
+Old Configuration Files
+=======================
+
+Tahoe-LAFS releases before v1.3.0 had no ``tahoe.cfg`` file, and used
+distinct files for each item. This is no longer supported and if you
+have configuration in the old format you must manually convert it to
+the new format for Tahoe-LAFS to detect it. See
+`<historical/configuration.rst>`_.
creates a new directory and populates it with files that will allow the
"``tahoe start``" command to use it later on. This command creates nodes that
have client functionality (upload/download files), web API services
-(controlled by the 'webport' file), and storage services (unless
-``--no-storage`` is specified).
+(controlled by the '[node]web.port' configuration), and storage services
+(unless ``--no-storage`` is specified).
NODEDIR defaults to ``~/.tahoe/`` , and newly-created nodes default to
publishing a web server on port 3456 (limited to the loopback interface, at
--- /dev/null
+=======================
+Old Configuration Files
+=======================
+
+Tahoe-LAFS releases before v1.3.0 had no ``tahoe.cfg`` file, and used
+distinct files for each item listed below. If Tahoe-LAFS v1.9.0 or above
+detects the old configuration files at start up it emits a warning and
+aborts the start up. (This was issue ticket #1385.)
+
+=============================== =================================== =================
+Config setting File Comment
+=============================== =================================== =================
+``[node]nickname`` ``BASEDIR/nickname``
+``[node]web.port`` ``BASEDIR/webport``
+``[node]tub.port`` ``BASEDIR/client.port`` (for Clients, not Introducers)
+``[node]tub.port`` ``BASEDIR/introducer.port`` (for Introducers, not Clients) (note that, unlike other keys, ``tahoe.cfg`` overrode this file from Tahoe-LAFS v1.3.0 up to and including Tahoe-LAFS v1.8.2)
+``[node]tub.location`` ``BASEDIR/advertised_ip_addresses``
+``[node]log_gatherer.furl`` ``BASEDIR/log_gatherer.furl`` (one per line)
+``[node]timeout.keepalive`` ``BASEDIR/keepalive_timeout``
+``[node]timeout.disconnect`` ``BASEDIR/disconnect_timeout``
+``[client]introducer.furl`` ``BASEDIR/introducer.furl``
+``[client]helper.furl`` ``BASEDIR/helper.furl``
+``[client]key_generator.furl`` ``BASEDIR/key_generator.furl``
+``[client]stats_gatherer.furl`` ``BASEDIR/stats_gatherer.furl``
+``[storage]enabled`` ``BASEDIR/no_storage`` (``False`` if ``no_storage`` exists)
+``[storage]readonly`` ``BASEDIR/readonly_storage`` (``True`` if ``readonly_storage`` exists)
+``[storage]sizelimit`` ``BASEDIR/sizelimit``
+``[storage]debug_discard`` ``BASEDIR/debug_discard_storage``
+``[helper]enabled`` ``BASEDIR/run_helper`` (``True`` if ``run_helper`` exists)
+=============================== =================================== =================
+
+Note: the functionality of ``[node]ssh.port`` and
+``[node]ssh.authorized_keys_file`` were previously (before Tahoe-LAFS
+v1.3.0) combined, controlled by the presence of a
+``BASEDIR/authorized_keys.SSHPORT`` file, in which the suffix of the
+filename indicated which port the ssh server should listen on, and the
+contents of the file provided the ssh public keys to accept. Support
+for these files has been removed completely. To ``ssh`` into your
+Tahoe-LAFS node, add ``[node]ssh.port`` and
+``[node].ssh_authorized_keys_file`` statements to your ``tahoe.cfg``.
+
+Likewise, the functionality of ``[node]tub.location`` is a variant of
+the now (since Tahoe-LAFS v1.3.0) unsupported
+``BASEDIR/advertised_ip_addresses`` . The old file was additive (the
+addresses specified in ``advertised_ip_addresses`` were used in
+addition to any that were automatically discovered), whereas the new
+``tahoe.cfg`` directive is not (``tub.location`` is used verbatim).
modest) storage requirements to a different host and provides access to
logfiles from multiple nodes (web-API, storage, or helper) in a single place.
-There are two kinds of gatherers. Both produce a FURL which needs to be
-placed in the ``NODEDIR/log_gatherer.furl`` file (one FURL per line) of
-each node that is to publish its logs to the gatherer. When the Tahoe node
-starts, it will connect to the configured gatherers and offer its logport:
-the gatherer will then use the logport to subscribe to hear about events.
+There are two kinds of gatherers: "log gatherer" and "stats gatherer". Each
+produces a FURL which needs to be placed in the ``NODEDIR/tahoe.cfg `` file
+of each node that is to publish to the gatherer, under the keys
+"log_gatherer.furl" and "stats_gatherer.furl" respectively. When the Tahoe
+node starts, it will connect to the configured gatherers and offer its
+logport: the gatherer will then use the logport to subscribe to hear about
+events.
The gatherer will write to files in its working directory, which can then be
examined with tools like "``flogtool dump``" as described above.
things that happened on multiple machines (such as comparing a client node
making a request with the storage servers that respond to that request).
-The Log Gatherer is created with the "``flogtool create-gatherer WORKDIR``"
-command, and started with "``tahoe start``". The ``log_gatherer.furl`` it
-creates then needs to be copied into the ``BASEDIR/log_gatherer.furl`` file
-of all nodes that should be sending it log events.
+Create the Log Gatherer with the "``flogtool create-gatherer
+WORKDIR``" command, and start it with "``tahoe start``". Then copy the
+contents of the ``log_gatherer.furl`` file it creates into the
+``BASEDIR/tahoe.cfg`` file (under the key ``log_gatherer.furl`` of the
+section ``[node]``) of all nodes that should be sending it log
+events. (See `<configuration.rst>`_.)
The "``flogtool filter``" command, described above, is useful to cut down the
-potentially-large flogfiles into more a narrowly-focussed form.
+potentially large flogfiles into a more focussed form.
Busy nodes, particularly web-API nodes which are performing recursive
deep-size/deep-stats/deep-check operations, can produce a lot of log events.
pass
class MissingConfigEntry(Exception):
- pass
+ """ A required config entry was not found. """
+
+class OldConfigError(Exception):
+ """ An obsolete config file was found. See
+ docs/historical/configuration.rst. """
class Node(service.MultiService):
# this implements common functionality of both Client nodes and Introducer
assert self.config.get(section, option) == value
def read_config(self):
+ self.warn_about_old_config_files()
self.config = ConfigParser.SafeConfigParser()
self.config.read([os.path.join(self.basedir, "tahoe.cfg")])
- self.read_old_config_files()
-
- def read_old_config_files(self):
- # backwards-compatibility: individual files will override the
- # contents of tahoe.cfg
- copy = self._copy_config_from_file
-
- copy("nickname", "node", "nickname")
- copy("webport", "node", "web.port")
-
- cfg_tubport = self.get_config("node", "tub.port", "")
- if not cfg_tubport:
- # For 'tub.port', tahoe.cfg overrides the individual file on
- # disk. So only read self._portnumfile if tahoe.cfg doesn't
- # provide a value.
- try:
- file_tubport = open(self._portnumfile, "rU").read().strip()
- self.set_config("node", "tub.port", file_tubport)
- except EnvironmentError:
- pass
-
- copy("keepalive_timeout", "node", "timeout.keepalive")
- copy("disconnect_timeout", "node", "timeout.disconnect")
-
- def _copy_config_from_file(self, config_filename, section, keyname):
- s = self.get_config_from_file(config_filename)
- if s is not None:
- self.set_config(section, keyname, s)
+
+ def warn_about_old_config_files(self):
+ """ If any old configuration files are detected, raise OldConfigError. """
+
+ oldfnames = set()
+ for name in [
+ 'nickname', 'webport', 'keepalive_timeout', 'log_gatherer.furl',
+ 'disconnect_timeout', 'advertised_ip_addresses', 'introducer.furl',
+ 'helper.furl', 'key_generator.furl', 'stats_gatherer.furl',
+ 'no_storage', 'readonly_storage', 'sizelimit',
+ 'debug_discard_storage', 'run_helper']:
+ fullfname = os.path.join(self.basedir, name)
+ if os.path.exists(fullfname):
+ log.err("Found pre-Tahoe-LAFS-v1.3 configuration file: '%s'. See docs/historical/configuration.rst." % (fullfname,))
+ oldfnames.add(fullfname)
+ if oldfnames:
+ raise OldConfigError(oldfnames)
def create_tub(self):
certfile = os.path.join(self.basedir, "private", self.CERTFILE)
# TODO: merge this with allmydata.get_package_versions
return dict(app_versions.versions)
- def get_config_from_file(self, name, required=False):
- """Get the (string) contents of a config file, or None if the file
- did not exist. If required=True, raise an exception rather than
- returning None. Any leading or trailing whitespace will be stripped
- from the data."""
- fn = os.path.join(self.basedir, name)
- try:
- return open(fn, "r").read().strip()
- except EnvironmentError:
- if not required:
- return None
- raise
-
def write_private_config(self, name, value):
"""Write the (string) contents of a private config file (which is a
config file that resides within the subdirectory named 'private'), and
use it as a default value. If not, treat it as a 0-argument callable
which is expected to return a string.
"""
- privname = os.path.join("private", name)
- value = self.get_config_from_file(privname)
- if value is None:
- if isinstance(default, (str, unicode)):
+ privname = os.path.join(self.basedir, "private", name)
+ try:
+ value = fileutil.read(privname)
+ except EnvironmentError:
+ if isinstance(default, basestring):
value = default
else:
value = default()
- fn = os.path.join(self.basedir, privname)
- try:
- open(fn, "w").write(value)
- except EnvironmentError, e:
- self.log("Unable to write config file '%s'" % fn)
- self.log(e)
- value = value.strip()
- return value
+ fileutil.write(privname, value)
+ return value.strip()
def write_config(self, name, value, mode="w"):
"""Write a string to a config file."""
return self.stopService()
def setup_logging(self):
- # we replace the formatTime() method of the log observer that twistd
- # set up for us, with a method that uses better timestamps.
+ # we replace the formatTime() method of the log observer that
+ # twistd set up for us, with a method that uses our preferred
+ # timestamp format.
for o in twlog.theLogPublisher.observers:
# o might be a FileLogObserver's .emit method
if type(o) is type(self.setup_logging): # bound method
iv_dir = self.getdir("introducer")
if not os.path.isdir(iv_dir):
fileutil.make_dirs(iv_dir)
- f = open(os.path.join(iv_dir, "webport"), "w")
- f.write("tcp:0:interface=127.0.0.1\n")
- f.close()
+ fileutil.write(os.path.join(iv_dir, 'tahoe.cfg'), \
+ "[node]\n" + \
+ "web.port = tcp:0:interface=127.0.0.1\n")
if SYSTEM_TEST_CERTS:
os.mkdir(os.path.join(iv_dir, "private"))
f = open(os.path.join(iv_dir, "private", "node.pem"), "w")
f.write(SYSTEM_TEST_CERTS[i+1])
f.close()
- def write(name, value):
- open(os.path.join(basedir, name), "w").write(value+"\n")
+ config = "[client]\n"
+ config += "introducer.furl = %s\n" % self.introducer_furl
+ if self.stats_gatherer_furl:
+ config += "stats_gatherer.furl = %s\n" % self.stats_gatherer_furl
+
if i == 0:
# clients[0] runs a webserver and a helper, no key_generator
- write("webport", "tcp:0:interface=127.0.0.1")
- write("run_helper", "yes")
- write("keepalive_timeout", "600")
+ config += "[node]\n"
+ config += "web.port = tcp:0:interface=127.0.0.1\n"
+ config += "timeout.keepalive = 600\n"
+ config += "[helper]\n"
+ config += "enabled = True\n"
if i == 3:
# clients[3] runs a webserver and uses a helper, uses
# key_generator
- write("webport", "tcp:0:interface=127.0.0.1")
- write("disconnect_timeout", "1800")
if self.key_generator_furl:
- kgf = "%s\n" % (self.key_generator_furl,)
- write("key_generator.furl", kgf)
- write("introducer.furl", self.introducer_furl)
- if self.stats_gatherer_furl:
- write("stats_gatherer.furl", self.stats_gatherer_furl)
+ config += "key_generator.furl = %s\n" % self.key_generator_furl
+ config += "[node]\n"
+ config += "web.port = tcp:0:interface=127.0.0.1\n"
+ config += "timeout.disconnect = 1800\n"
+
+ fileutil.write(os.path.join(basedir, 'tahoe.cfg'), config)
# give subclasses a chance to append lines to the node's tahoe.cfg
# files before they are launched.
f.close()
self.helper_furl = helper_furl
if self.numclients >= 4:
- f = open(os.path.join(basedirs[3],"helper.furl"), "w")
- f.write(helper_furl)
+ f = open(os.path.join(basedirs[3], 'tahoe.cfg'), 'ab+')
+ f.write(
+ "[client]\n"
+ "helper.furl = %s\n" % helper_furl)
f.close()
# this starts the rest of the clients
basedir = self.getdir("client%d" % client_num)
if not os.path.isdir(basedir):
fileutil.make_dirs(basedir)
- open(os.path.join(basedir, "introducer.furl"), "w").write(self.introducer_furl)
+ config = "[client]\n"
+ config += "introducer.furl = %s\n" % self.introducer_furl
if helper_furl:
- f = open(os.path.join(basedir, "helper.furl") ,"w")
- f.write(helper_furl+"\n")
- f.close()
+ config += "helper.furl = %s\n" % helper_furl
+ fileutil.write(os.path.join(basedir, 'tahoe.cfg'), config)
c = client.Client(basedir=basedir)
self.clients.append(c)
import os
from twisted.trial import unittest
from twisted.application import service
-from twisted.python import log
import allmydata
+from allmydata.node import OldConfigError
from allmydata import client
from allmydata.storage_client import StorageFarmBroker
from allmydata.util import base32, fileutil
from foolscap.api import flushEventualQueue
import allmydata.test.common_util as testutil
+import mock
+
BASECONFIG = ("[client]\n"
"introducer.furl = \n"
)
+BASECONFIG_I = ("[client]\n"
+ "introducer.furl = %s\n"
+ )
+
class Basic(testutil.ReallyEqualMixin, unittest.TestCase):
def test_loadable(self):
basedir = "test_client.Basic.test_loadable"
os.mkdir(basedir)
- fileutil.write(os.path.join(basedir, "introducer.furl"), "")
+ fileutil.write(os.path.join(basedir, "tahoe.cfg"), \
+ BASECONFIG)
client.Client(basedir)
- def test_loadable_old_config_bits(self):
- basedir = "test_client.Basic.test_loadable_old_config_bits"
+ @mock.patch('allmydata.util.log.err')
+ def test_warn_on_old_config_files(self, mocklogerr):
+ basedir = "test_client.Basic.test_warn_on_old_config_files"
os.mkdir(basedir)
+ fileutil.write(os.path.join(basedir, "tahoe.cfg"), \
+ BASECONFIG + \
+ "[storage]\n" + \
+ "enabled = false\n" + \
+ "reserved_space = bogus\n")
fileutil.write(os.path.join(basedir, "introducer.furl"), "")
fileutil.write(os.path.join(basedir, "no_storage"), "")
fileutil.write(os.path.join(basedir, "readonly_storage"), "")
fileutil.write(os.path.join(basedir, "debug_discard_storage"), "")
- c = client.Client(basedir)
- try:
- c.getServiceNamed("storage")
- self.fail("that was supposed to fail")
- except KeyError:
- pass
-
- def test_loadable_old_storage_config_bits(self):
- basedir = "test_client.Basic.test_loadable_old_storage_config_bits"
- os.mkdir(basedir)
- fileutil.write(os.path.join(basedir, "introducer.furl"), "")
- fileutil.write(os.path.join(basedir, "readonly_storage"), "")
- fileutil.write(os.path.join(basedir, "debug_discard_storage"), "")
- c = client.Client(basedir)
- s = c.getServiceNamed("storage")
- self.failUnless(s.no_storage)
- self.failUnless(s.readonly_storage)
+ e = self.failUnlessRaises(OldConfigError, client.Client, basedir)
+ self.failUnlessIn(os.path.abspath(os.path.join(basedir, u"introducer.furl")), e.args[0])
+ self.failUnlessIn(os.path.abspath(os.path.join(basedir, "no_storage")), e.args[0])
+ self.failUnlessIn(os.path.abspath(os.path.join(basedir, "readonly_storage")), e.args[0])
+ self.failUnlessIn(os.path.abspath(os.path.join(basedir, "debug_discard_storage")), e.args[0])
+ for oldfile in [u'introducer.furl', 'no_storage', 'readonly_storage',
+ 'debug_discard_storage']:
+ warned = [ m for m in mocklogerr.call_args_list if ("Found pre-Tahoe-LAFS-v1.3 configuration file" in m[0][0] and oldfile in m[0][0]) ]
+ self.failUnless(warned, (oldfile, mocklogerr.call_args_list))
+
+ for oldfile in [
+ 'nickname', 'webport', 'keepalive_timeout', 'log_gatherer.furl',
+ 'disconnect_timeout', 'advertised_ip_addresses', 'helper.furl',
+ 'key_generator.furl', 'stats_gatherer.furl', 'sizelimit',
+ 'run_helper']:
+ warned = [ m for m in mocklogerr.call_args_list if ("Found pre-Tahoe-LAFS-v1.3 configuration file" in m[0][0] and oldfile in m[0][0]) ]
+ self.failIf(warned, oldfile)
def test_secrets(self):
basedir = "test_client.Basic.test_secrets"
os.mkdir(basedir)
- fileutil.write(os.path.join(basedir, "introducer.furl"), "")
+ fileutil.write(os.path.join(basedir, "tahoe.cfg"), \
+ BASECONFIG)
c = client.Client(basedir)
secret_fname = os.path.join(basedir, "private", "secret")
self.failUnless(os.path.exists(secret_fname), secret_fname)
def test_versions(self):
basedir = "test_client.Basic.test_versions"
os.mkdir(basedir)
- fileutil.write(os.path.join(basedir, "introducer.furl"), "")
+ fileutil.write(os.path.join(basedir, "tahoe.cfg"), \
+ BASECONFIG + \
+ "[storage]\n" + \
+ "enabled = true\n")
c = client.Client(basedir)
ss = c.getServiceNamed("storage")
verdict = ss.remote_get_version()
"non-numeric version in '%s'" % allmydata.__version__)
all_versions = allmydata.get_package_versions_string()
self.failUnless(allmydata.__appname__ in all_versions)
- log.msg("tahoe versions: %s" % all_versions)
# also test stats
stats = c.get_stats()
self.failUnless("node.uptime" in stats)
basedir = "test_client.Run.test_loadable"
os.mkdir(basedir)
dummy = "pb://wl74cyahejagspqgy4x5ukrvfnevlknt@127.0.0.1:58889/bogus"
- fileutil.write(os.path.join(basedir, "introducer.furl"), dummy)
+ fileutil.write(os.path.join(basedir, "tahoe.cfg"), BASECONFIG_I % dummy)
fileutil.write(os.path.join(basedir, "suicide_prevention_hotline"), "")
client.Client(basedir)
basedir = "test_client.Run.test_reloadable"
os.mkdir(basedir)
dummy = "pb://wl74cyahejagspqgy4x5ukrvfnevlknt@127.0.0.1:58889/bogus"
- fileutil.write(os.path.join(basedir, "introducer.furl"), dummy)
+ fileutil.write(os.path.join(basedir, "tahoe.cfg"), BASECONFIG_I % dummy)
c1 = client.Client(basedir)
c1.setServiceParent(self.sparent)
run_by_human=False)
+BASECONFIG_I = ("[client]\n"
+ "introducer.furl = %s\n"
+ )
+
class RunNode(common_util.SignalMixin, unittest.TestCase, pollmixin.PollMixin,
RunBinTahoeMixin):
# exercise "tahoe start", for both introducer, client node, and
# that even if the 'stop' command doesn't work (and the test fails), the client should
# still terminate.
open(HOTLINE_FILE, "w").write("")
- open(os.path.join(c1, "introducer.furl"), "w").write("pb://xrndsskn2zuuian5ltnxrte7lnuqdrkz@127.0.0.1:55617/introducer\n")
+ fileutil.write(os.path.join(basedir, "tahoe.cfg"), BASECONFIG_I % "pb://xrndsskn2zuuian5ltnxrte7lnuqdrkz@127.0.0.1:55617/introducer")
# now it's safe to start the node
d.addCallback(_cb)
# that even if the 'stop' command doesn't work (and the test fails), the client should
# still terminate.
open(HOTLINE_FILE, "w").write("")
- open(os.path.join(c1, "introducer.furl"), "w").write("pb://xrndsskn2zuuian5ltnxrte7lnuqdrkz@127.0.0.1:55617/introducer\n")
+ fileutil.write(os.path.join(c1, "tahoe.cfg"), BASECONFIG_I % "pb://xrndsskn2zuuian5ltnxrte7lnuqdrkz@127.0.0.1:55617/introducer")
# now it's safe to start the node
d.addCallback(_cb)