Split control and log to two separate tubs, remove control knobs.

This also removes the tahoe.cfg keys that would have configured the
control-port. And it deletes the logport.furl file before asking the Tub
to re-create it, because we're now using an ephemeral Tub (so we're not
persisting the private key, so the tubid will change each time).

closes ticket:2794
This commit is contained in:
Brian Warner 2016-07-06 19:47:00 -07:00
parent e5ffbdbcdf
commit 7d692d0afd
2 changed files with 51 additions and 46 deletions

View File

@ -85,6 +85,7 @@ class Node(service.MultiService):
self.init_tempdir() self.init_tempdir()
self.create_tub() self.create_tub()
self.create_control_tub() self.create_control_tub()
self.create_log_tub()
self.logSource="Node" self.logSource="Node"
self.setup_logging() self.setup_logging()
@ -167,16 +168,6 @@ class Node(service.MultiService):
return "tcp:%d" % int(s) return "tcp:%d" % int(s)
return s return s
def get_control_tub_port(self):
# return a descriptor string
cfg_tubport = self.get_config("node", "control_tub.port", "")
if cfg_tubport:
return self._convert_tub_port(cfg_tubport)
# XXX should really be: tcp:interface=127.0.0.1:1234
tubport = "tcp:%d" % iputil.allocate_tcp_port()
return tubport
def get_tub_port(self): def get_tub_port(self):
# return a descriptor string # return a descriptor string
cfg_tubport = self.get_config("node", "tub.port", "") cfg_tubport = self.get_config("node", "tub.port", "")
@ -191,16 +182,6 @@ class Node(service.MultiService):
fileutil.write_atomically(self._portnumfile, tubport + "\n", mode="") fileutil.write_atomically(self._portnumfile, tubport + "\n", mode="")
return tubport return tubport
def get_control_tub_location(self, tubport):
location = self.get_config("node", "control_tub.location", "127.0.0.1")
# Replace the location "AUTO", if present, with the detected local
# addresses. Don't probe for local addresses unless necessary.
split_location = location.split(",")
new_locations = []
for loc in split_location:
new_locations.append(loc)
return ",".join(new_locations)
def get_tub_location(self, tubport): def get_tub_location(self, tubport):
location = self.get_config("node", "tub.location", "AUTO") location = self.get_config("node", "tub.location", "AUTO")
# Replace the location "AUTO", if present, with the detected local # Replace the location "AUTO", if present, with the detected local
@ -219,32 +200,13 @@ class Node(service.MultiService):
new_locations.append(loc) new_locations.append(loc)
return ",".join(new_locations) return ",".join(new_locations)
def create_control_tub(self):
certfile = os.path.join(self.basedir, "private", self.CERTFILE)
self.control_tub = Tub(certFile=certfile)
self.control_tub_options = {
"logLocalFailures": True,
"logRemoteFailures": True,
"expose-remote-exception-types": False,
}
for (name, value) in self.control_tub_options.items():
self.control_tub.setOption(name, value)
tubport = self.get_control_tub_port()
if tubport in ("0", "tcp:0"):
raise ValueError("tub.port cannot be 0: you must choose")
self.control_tub.listenOn(tubport)
location = self.get_control_tub_location(tubport)
self.control_tub.setLocation(location)
self.log("Control/logging Tub location set to %s" % (location,))
# the Tub is now ready for tub.registerReference()
self.control_tub.setServiceParent(self)
def create_tub(self): def create_tub(self):
certfile = os.path.join(self.basedir, "private", self.CERTFILE) certfile = os.path.join(self.basedir, "private", self.CERTFILE)
self.tub = Tub(certFile=certfile) self.tub = Tub(certFile=certfile)
self.tub_options = { self.tub_options = {
"logLocalFailures": True,
"logRemoteFailures": True,
"expose-remote-exception-types": False,
} }
# see #521 for a discussion of how to pick these timeout values. # see #521 for a discussion of how to pick these timeout values.
@ -273,6 +235,33 @@ class Node(service.MultiService):
# the Tub is now ready for tub.registerReference() # the Tub is now ready for tub.registerReference()
self.tub.setServiceParent(self) self.tub.setServiceParent(self)
def create_control_tub(self):
# the control port uses a localhost-only ephemeral Tub, with no
# control over the listening port or location
self.control_tub = Tub()
portnum = iputil.allocate_tcp_port()
port = "tcp:%d:interface=127.0.0.1" % portnum
location = "tcp:127.0.0.1:%d" % portnum
self.control_tub.listenOn(port)
self.control_tub.setLocation(location)
self.log("Control Tub location set to %s" % (location,))
self.control_tub.setServiceParent(self)
def create_log_tub(self):
# The logport uses a localhost-only ephemeral Tub, with no control
# over the listening port or location. This might change if we
# discover a compelling reason for it in the future (e.g. being able
# to use "flogtool tail" against a remote server), but for now I
# think we can live without it.
self.log_tub = Tub()
portnum = iputil.allocate_tcp_port()
port = "tcp:%d:interface=127.0.0.1" % portnum
location = "tcp:127.0.0.1:%d" % portnum
self.log_tub.listenOn(port)
self.log_tub.setLocation(location)
self.log("Log Tub location set to %s" % (location,))
self.log_tub.setServiceParent(self)
def get_app_versions(self): def get_app_versions(self):
# TODO: merge this with allmydata.get_package_versions # TODO: merge this with allmydata.get_package_versions
return dict(app_versions.versions) return dict(app_versions.versions)
@ -392,13 +381,15 @@ class Node(service.MultiService):
# TODO: twisted >2.5.0 offers maxRotatedFiles=50 # TODO: twisted >2.5.0 offers maxRotatedFiles=50
lgfurl_file = os.path.join(self.basedir, "private", "logport.furl").encode(get_filesystem_encoding()) lgfurl_file = os.path.join(self.basedir, "private", "logport.furl").encode(get_filesystem_encoding())
self.control_tub.setOption("logport-furlfile", lgfurl_file) if os.path.exists(lgfurl_file):
os.remove(lgfurl_file)
self.log_tub.setOption("logport-furlfile", lgfurl_file)
lgfurl = self.get_config("node", "log_gatherer.furl", "") lgfurl = self.get_config("node", "log_gatherer.furl", "")
if lgfurl: if lgfurl:
# this is in addition to the contents of log-gatherer-furlfile # this is in addition to the contents of log-gatherer-furlfile
self.control_tub.setOption("log-gatherer-furl", lgfurl) self.log_tub.setOption("log-gatherer-furl", lgfurl)
self.control_tub.setOption("log-gatherer-furlfile", self.log_tub.setOption("log-gatherer-furlfile",
os.path.join(self.basedir, "log_gatherer.furl")) os.path.join(self.basedir, "log_gatherer.furl"))
incident_dir = os.path.join(self.basedir, "logs", "incidents") incident_dir = os.path.join(self.basedir, "logs", "incidents")
foolscap.logging.log.setLogDir(incident_dir.encode(get_filesystem_encoding())) foolscap.logging.log.setLogDir(incident_dir.encode(get_filesystem_encoding()))

14
topfiles/2794.change Normal file
View File

@ -0,0 +1,14 @@
The little-used "control port" now uses a separate (ephemeral) Tub. This
means the FURL changes each time the node is restarted, and it only listens
on the loopback (127.0.0.1) interface, on a random port. As the control port
is only used by some automated tests (check_memory, check_speed), this
shouldn't affect anyone.
The slightly-more-used "log port" now also uses a separate (ephemeral) Tub,
with the same consequences. The lack of a stable (and externally-reachable)
logport.furl means it is no longer possible to use `flogtool tail FURL`
against a distant Tahoe server, however `flogtool tail
.../nodedir/private/logport.furl` still works just fine (and is the more
common use case anyways). We might bring back the ability to configure the
port and location of the logport in the future, if there is sufficient
demand, but for now it seems better to avoid the complexity.