pull 'basedir' entirely into _Config

Put all config-related methods into _Config; change
code to ask config for paths instead of using basedir;
add some better docstrings
This commit is contained in:
meejah
2018-01-31 11:30:46 -07:00
parent e269d2427b
commit 35810a5692
14 changed files with 304 additions and 282 deletions

View File

@ -29,6 +29,7 @@ from allmydata.interfaces import IStatsProducer, SDMF_VERSION, MDMF_VERSION
from allmydata.nodemaker import NodeMaker
from allmydata.blacklist import Blacklist
from allmydata.node import OldConfigOptionError, _common_config_sections
from allmydata.node import read_config
KiB=1024
@ -156,12 +157,10 @@ class Terminator(service.Service):
#@defer.inlineCallbacks
def create_client(basedir=u"."):
from allmydata.node import read_config
config = read_config(basedir, u"client.port", _valid_config_sections=_valid_config_sections)
#defer.returnValue(
return _Client(
config,
basedir=basedir
)
#)
@ -188,8 +187,8 @@ class _Client(node.Node, pollmixin.PollMixin):
"max_segment_size": 128*KiB,
}
def __init__(self, config, basedir=u"."):
node.Node.__init__(self, config, basedir=basedir)
def __init__(self, config):
node.Node.__init__(self, config)
# All tub.registerReference must happen *after* we upcall, since
# that's what does tub.setLocation()
self._magic_folders = dict()
@ -203,13 +202,13 @@ class _Client(node.Node, pollmixin.PollMixin):
self.init_storage()
self.init_control()
self._key_generator = KeyGenerator()
key_gen_furl = self.get_config("client", "key_generator.furl", None)
key_gen_furl = config.get_config("client", "key_generator.furl", None)
if key_gen_furl:
log.msg("[client]key_generator.furl= is now ignored, see #2783")
self.init_client()
self.load_static_servers()
self.helper = None
if self.get_config("helper", "enabled", False, boolean=True):
if config.get_config("helper", "enabled", False, boolean=True):
if not self._tub_is_listening:
raise ValueError("config error: helper is enabled, but tub "
"is not listening ('tub.port=' is empty)")
@ -221,8 +220,7 @@ class _Client(node.Node, pollmixin.PollMixin):
# If the node sees an exit_trigger file, it will poll every second to see
# whether the file still exists, and what its mtime is. If the file does not
# exist or has not been modified for a given timeout, the node will exit.
exit_trigger_file = os.path.join(self.basedir,
self.EXIT_TRIGGER_FILE)
exit_trigger_file = self.config.get_config_path(self.EXIT_TRIGGER_FILE)
if os.path.exists(exit_trigger_file):
age = time.time() - os.stat(exit_trigger_file)[stat.ST_MTIME]
self.log("%s file noticed (%ds old), starting timer" % (self.EXIT_TRIGGER_FILE, age))
@ -231,17 +229,17 @@ class _Client(node.Node, pollmixin.PollMixin):
# this needs to happen last, so it can use getServiceNamed() to
# acquire references to StorageServer and other web-statusable things
webport = self.get_config("node", "web.port", None)
webport = self.config.get_config("node", "web.port", None)
if webport:
self.init_web(webport) # strports string
def _sequencer(self):
seqnum_s = self.get_config_from_file("announcement-seqnum")
seqnum_s = self.config.get_config_from_file("announcement-seqnum")
if not seqnum_s:
seqnum_s = "0"
seqnum = int(seqnum_s.strip())
seqnum += 1 # increment
self.write_config("announcement-seqnum", "%d\n" % seqnum)
self.config.write_config_file("announcement-seqnum", "%d\n" % seqnum)
nonce = _make_secret().strip()
return seqnum, nonce
@ -249,7 +247,7 @@ class _Client(node.Node, pollmixin.PollMixin):
self.introducer_clients = []
self.introducer_furls = []
introducers_yaml_filename = os.path.join(self.basedir, "private", "introducers.yaml")
introducers_yaml_filename = self.config.get_private_path("introducers.yaml")
introducers_filepath = FilePath(introducers_yaml_filename)
try:
@ -265,7 +263,7 @@ class _Client(node.Node, pollmixin.PollMixin):
raise ValueError("'default' introducer furl cannot be specified in introducers.yaml; please fix impossible configuration.")
# read furl from tahoe.cfg
tahoe_cfg_introducer_furl = self.get_config("client", "introducer.furl", None)
tahoe_cfg_introducer_furl = self.config.get_config("client", "introducer.furl", None)
if tahoe_cfg_introducer_furl == "None":
raise ValueError("tahoe.cfg has invalid 'introducer.furl = None':"
" to disable it, use 'introducer.furl ='"
@ -274,19 +272,19 @@ class _Client(node.Node, pollmixin.PollMixin):
introducers[u'default'] = {'furl':tahoe_cfg_introducer_furl}
for petname, introducer in introducers.items():
introducer_cache_filepath = FilePath(os.path.join(self.basedir, "private", "introducer_{}_cache.yaml".format(petname)))
introducer_cache_filepath = FilePath(self.config.get_private_path("introducer_{}_cache.yaml".format(petname)))
ic = IntroducerClient(self.tub, introducer['furl'].encode("ascii"),
self.nickname,
str(allmydata.__full_version__),
str(self.OLDEST_SUPPORTED_VERSION),
self.get_app_versions(), self._sequencer,
self.config.get_app_versions(), self._sequencer,
introducer_cache_filepath)
self.introducer_clients.append(ic)
self.introducer_furls.append(introducer['furl'])
ic.setServiceParent(self)
def init_stats_provider(self):
gatherer_furl = self.get_config("client", "stats_gatherer.furl", None)
gatherer_furl = self.config.get_config("client", "stats_gatherer.furl", None)
self.stats_provider = StatsProvider(self, gatherer_furl)
self.add_service(self.stats_provider)
self.stats_provider.register_producer(self)
@ -295,10 +293,10 @@ class _Client(node.Node, pollmixin.PollMixin):
return { 'node.uptime': time.time() - self.started_timestamp }
def init_secrets(self):
lease_s = self.get_or_create_private_config("secret", _make_secret)
lease_s = self.config.get_or_create_private_config("secret", _make_secret)
lease_secret = base32.a2b(lease_s)
convergence_s = self.get_or_create_private_config('convergence',
_make_secret)
convergence_s = self.config.get_or_create_private_config('convergence',
_make_secret)
self.convergence = base32.a2b(convergence_s)
self._secret_holder = SecretHolder(lease_secret, self.convergence)
@ -308,9 +306,9 @@ class _Client(node.Node, pollmixin.PollMixin):
def _make_key():
sk_vs,vk_vs = keyutil.make_keypair()
return sk_vs+"\n"
sk_vs = self.get_or_create_private_config("node.privkey", _make_key)
sk_vs = self.config.get_or_create_private_config("node.privkey", _make_key)
sk,vk_vs = keyutil.parse_privkey(sk_vs.strip())
self.write_config("node.pubkey", vk_vs+"\n")
self.config.write_config_file("node.pubkey", vk_vs+"\n")
self._node_key = sk
def get_long_nodeid(self):
@ -322,7 +320,7 @@ class _Client(node.Node, pollmixin.PollMixin):
return idlib.nodeid_b2a(self.nodeid)
def _init_permutation_seed(self, ss):
seed = self.get_config_from_file("permutation-seed")
seed = self.config.get_config_from_file("permutation-seed")
if not seed:
have_shares = ss.have_shares()
if have_shares:
@ -339,24 +337,24 @@ class _Client(node.Node, pollmixin.PollMixin):
# pubkey-based serverid
vk_bytes = self._node_key.get_verifying_key_bytes()
seed = base32.b2a(vk_bytes)
self.write_config("permutation-seed", seed+"\n")
self.config.write_config_file("permutation-seed", seed+"\n")
return seed.strip()
def init_storage(self):
# should we run a storage server (and publish it for others to use)?
if not self.get_config("storage", "enabled", True, boolean=True):
if not self.config.get_config("storage", "enabled", True, boolean=True):
return
if not self._tub_is_listening:
raise ValueError("config error: storage is enabled, but tub "
"is not listening ('tub.port=' is empty)")
readonly = self.get_config("storage", "readonly", False, boolean=True)
readonly = self.config.get_config("storage", "readonly", False, boolean=True)
config_storedir = self.get_config(
"storage", "storage_dir", self.STOREDIR,
).decode('utf-8')
storedir = os.path.join(self.basedir, config_storedir)
storedir = self.config.get_config_path(config_storedir)
data = self.get_config("storage", "reserved_space", None)
data = self.config.get_config("storage", "reserved_space", None)
try:
reserved = parse_abbreviated_size(data)
except ValueError:
@ -365,28 +363,28 @@ class _Client(node.Node, pollmixin.PollMixin):
raise
if reserved is None:
reserved = 0
discard = self.get_config("storage", "debug_discard", False,
boolean=True)
discard = self.config.get_config("storage", "debug_discard", False,
boolean=True)
expire = self.get_config("storage", "expire.enabled", False, boolean=True)
expire = self.config.get_config("storage", "expire.enabled", False, boolean=True)
if expire:
mode = self.get_config("storage", "expire.mode") # require a mode
mode = self.config.get_config("storage", "expire.mode") # require a mode
else:
mode = self.get_config("storage", "expire.mode", "age")
mode = self.config.get_config("storage", "expire.mode", "age")
o_l_d = self.get_config("storage", "expire.override_lease_duration", None)
o_l_d = self.config.get_config("storage", "expire.override_lease_duration", None)
if o_l_d is not None:
o_l_d = parse_duration(o_l_d)
cutoff_date = None
if mode == "cutoff-date":
cutoff_date = self.get_config("storage", "expire.cutoff_date")
cutoff_date = self.config.get_config("storage", "expire.cutoff_date")
cutoff_date = parse_date(cutoff_date)
sharetypes = []
if self.get_config("storage", "expire.immutable", True, boolean=True):
if self.config.get_config("storage", "expire.immutable", True, boolean=True):
sharetypes.append("immutable")
if self.get_config("storage", "expire.mutable", True, boolean=True):
if self.config.get_config("storage", "expire.mutable", True, boolean=True):
sharetypes.append("mutable")
expiration_sharetypes = tuple(sharetypes)
@ -402,7 +400,7 @@ class _Client(node.Node, pollmixin.PollMixin):
expiration_sharetypes=expiration_sharetypes)
self.add_service(ss)
furl_file = os.path.join(self.basedir, "private", "storage.furl").encode(get_filesystem_encoding())
furl_file = self.config.get_private_path("storage.furl").encode(get_filesystem_encoding())
furl = self.tub.registerReference(ss, furlFile=furl_file)
ann = {"anonymous-storage-FURL": furl,
"permutation-seed-base32": self._init_permutation_seed(ss),
@ -411,14 +409,14 @@ class _Client(node.Node, pollmixin.PollMixin):
ic.publish("storage", ann, self._node_key)
def init_client(self):
helper_furl = self.get_config("client", "helper.furl", None)
helper_furl = self.config.get_config("client", "helper.furl", None)
if helper_furl in ("None", ""):
helper_furl = None
DEP = self.encoding_params
DEP["k"] = int(self.get_config("client", "shares.needed", DEP["k"]))
DEP["n"] = int(self.get_config("client", "shares.total", DEP["n"]))
DEP["happy"] = int(self.get_config("client", "shares.happy", DEP["happy"]))
DEP["k"] = int(self.config.get_config("client", "shares.needed", DEP["k"]))
DEP["n"] = int(self.config.get_config("client", "shares.total", DEP["n"]))
DEP["happy"] = int(self.config.get_config("client", "shares.happy", DEP["happy"]))
# for the CLI to authenticate to local JSON endpoints
self._create_auth_token()
@ -441,7 +439,7 @@ class _Client(node.Node, pollmixin.PollMixin):
Currently only the URI '/magic' for magic-folder status; other
endpoints are invited to include this as well, as appropriate.
"""
return self.get_private_config('api_auth_token')
return self.config.get_private_config('api_auth_token')
def _create_auth_token(self):
"""
@ -449,7 +447,7 @@ class _Client(node.Node, pollmixin.PollMixin):
This is intentionally re-created every time the node starts.
"""
self.write_private_config(
self.config.write_private_config(
'api_auth_token',
urlsafe_b64encode(os.urandom(32)) + '\n',
)
@ -457,7 +455,7 @@ class _Client(node.Node, pollmixin.PollMixin):
def init_client_storage_broker(self):
# create a StorageFarmBroker object, for use by Uploader/Downloader
# (and everybody else who wants to use storage servers)
ps = self.get_config("client", "peers.preferred", "").split(",")
ps = self.config.get_config("client", "peers.preferred", "").split(",")
preferred_peers = tuple([p.strip() for p in ps if p != ""])
sb = storage_client.StorageFarmBroker(permute_peers=True,
tub_maker=self._create_tub,
@ -476,7 +474,7 @@ class _Client(node.Node, pollmixin.PollMixin):
Load the servers.yaml file if it exists, and provide the static
server data to the StorageFarmBroker.
"""
fn = os.path.join(self.basedir, "private", "servers.yaml")
fn = self.config.get_private_path("servers.yaml")
servers_filepath = FilePath(fn)
try:
with servers_filepath.open() as f:
@ -489,11 +487,11 @@ class _Client(node.Node, pollmixin.PollMixin):
pass
def init_blacklist(self):
fn = os.path.join(self.basedir, "access.blacklist")
fn = self.config.get_config_path("access.blacklist")
self.blacklist = Blacklist(fn)
def init_nodemaker(self):
default = self.get_config("client", "mutable.format", default="SDMF")
default = self.config.get_config("client", "mutable.format", default="SDMF")
if default.upper() == "MDMF":
self.mutable_file_default = MDMF_VERSION
else:
@ -515,10 +513,10 @@ class _Client(node.Node, pollmixin.PollMixin):
c = ControlServer()
c.setServiceParent(self)
control_url = self.control_tub.registerReference(c)
self.write_private_config("control.furl", control_url + "\n")
self.config.write_private_config("control.furl", control_url + "\n")
def init_helper(self):
self.helper = Helper(os.path.join(self.basedir, "helper"),
self.helper = Helper(self.config.get_config_path("helper"),
self.storage_broker, self._secret_holder,
self.stats_provider, self.history)
# TODO: this is confusing. BASEDIR/private/helper.furl is created by
@ -526,8 +524,7 @@ class _Client(node.Node, pollmixin.PollMixin):
# to use the helper. I like having the filename be the same, since
# that makes 'cp' work smoothly, but the difference between config
# inputs and generated outputs is hard to see.
helper_furlfile = os.path.join(self.basedir,
"private", "helper.furl").encode(get_filesystem_encoding())
helper_furlfile = self.config.get_private_path("helper.furl").encode(get_filesystem_encoding())
self.tub.registerReference(self.helper, furlFile=helper_furlfile)
def set_default_mutable_keysize(self, keysize):
@ -537,35 +534,35 @@ class _Client(node.Node, pollmixin.PollMixin):
self.log("init_web(webport=%s)", args=(webport,))
from allmydata.webish import WebishServer
nodeurl_path = os.path.join(self.basedir, "node.url")
staticdir_config = self.get_config("node", "web.static", "public_html").decode("utf-8")
staticdir = abspath_expanduser_unicode(staticdir_config, base=self.basedir)
nodeurl_path = self.config.get_config_path("node.url")
staticdir_config = self.config.get_config("node", "web.static", "public_html").decode("utf-8")
staticdir = self.config.get_config_path(staticdir_config)
ws = WebishServer(self, webport, nodeurl_path, staticdir)
self.add_service(ws)
def init_ftp_server(self):
if self.get_config("ftpd", "enabled", False, boolean=True):
if self.config.get_config("ftpd", "enabled", False, boolean=True):
accountfile = from_utf8_or_none(
self.get_config("ftpd", "accounts.file", None))
self.config.get_config("ftpd", "accounts.file", None))
if accountfile:
accountfile = abspath_expanduser_unicode(accountfile, base=self.basedir)
accounturl = self.get_config("ftpd", "accounts.url", None)
ftp_portstr = self.get_config("ftpd", "port", "8021")
accountfile = self.config.get_config_path(accountfile)
accounturl = self.config.get_config("ftpd", "accounts.url", None)
ftp_portstr = self.config.get_config("ftpd", "port", "8021")
from allmydata.frontends import ftpd
s = ftpd.FTPServer(self, accountfile, accounturl, ftp_portstr)
s.setServiceParent(self)
def init_sftp_server(self):
if self.get_config("sftpd", "enabled", False, boolean=True):
if self.config.get_config("sftpd", "enabled", False, boolean=True):
accountfile = from_utf8_or_none(
self.get_config("sftpd", "accounts.file", None))
self.config.get_config("sftpd", "accounts.file", None))
if accountfile:
accountfile = abspath_expanduser_unicode(accountfile, base=self.basedir)
accounturl = self.get_config("sftpd", "accounts.url", None)
sftp_portstr = self.get_config("sftpd", "port", "8022")
pubkey_file = from_utf8_or_none(self.get_config("sftpd", "host_pubkey_file"))
privkey_file = from_utf8_or_none(self.get_config("sftpd", "host_privkey_file"))
accountfile = self.config.get_config_path(accountfile)
accounturl = self.config.get_config("sftpd", "accounts.url", None)
sftp_portstr = self.config.get_config("sftpd", "port", "8022")
pubkey_file = from_utf8_or_none(self.config.get_config("sftpd", "host_pubkey_file"))
privkey_file = from_utf8_or_none(self.config.get_config("sftpd", "host_privkey_file"))
from allmydata.frontends import sftpd
s = sftpd.SFTPServer(self, accountfile, accounturl,
@ -574,15 +571,15 @@ class _Client(node.Node, pollmixin.PollMixin):
def init_magic_folder(self):
#print "init_magic_folder"
if self.get_config("drop_upload", "enabled", False, boolean=True):
if self.config.get_config("drop_upload", "enabled", False, boolean=True):
raise OldConfigOptionError("The [drop_upload] section must be renamed to [magic_folder].\n"
"See docs/frontends/magic-folder.rst for more information.")
if self.get_config("magic_folder", "enabled", False, boolean=True):
if self.config.get_config("magic_folder", "enabled", False, boolean=True):
from allmydata.frontends import magic_folder
try:
magic_folders = magic_folder.load_magic_folders(self.basedir)
magic_folders = magic_folder.load_magic_folders(self.config._basedir)
except Exception as e:
log.msg("Error loading magic-folder config: {}".format(e))
raise