refactor where plugins are loaded; use this to error early for users

This commit is contained in:
meejah 2023-08-09 22:27:55 -06:00
parent 295e816d4e
commit cf4fe0061c
4 changed files with 69 additions and 19 deletions

View File

@ -483,6 +483,11 @@ def create_storage_farm_broker(config: _Config, default_connection_handlers, foo
storage_client_config = storage_client.StorageClientConfig.from_node_config(
config,
)
# ensure that we can at least load all plugins that the
# configuration mentions; doing this early (i.e. before creating
# storage-clients themselves) allows us to exit in case of a
# problem.
storage_client_config.get_configured_storage_plugins()
def tub_creator(handler_overrides=None, **kwargs):
return node.create_tub(

View File

@ -30,10 +30,12 @@ from twisted.python.filepath import (
from twisted.python import log as twlog
from twisted.application import service
from twisted.python.failure import Failure
from twisted.plugin import getPlugins
from foolscap.api import Tub
import foolscap.logging.log
from allmydata.interfaces import IFoolscapStoragePlugin
from allmydata.util import log
from allmydata.util import fileutil, iputil
from allmydata.util.fileutil import abspath_expanduser_unicode

View File

@ -42,6 +42,9 @@ from allmydata.util.pid import (
from allmydata.storage.crawler import (
MigratePickleFileError,
)
from allmydata.storage_client import (
MissingPlugin,
)
from allmydata.node import (
PortAssignmentRequired,
PrivacyError,
@ -197,6 +200,17 @@ class DaemonizeTheRealService(Service, HookMixin):
self.basedir,
)
)
elif reason.check(MissingPlugin):
self.stderr.write(
"Missing Plugin\n"
"The configuration requests a plugin:\n"
"\n {}\n\n"
"...which cannot be found.\n"
"This typically means that some software hasn't been installed or the plugin couldn't be instantiated.\n\n"
.format(
reason.value.plugin_name,
)
)
else:
self.stderr.write("\nUnknown error, here's the traceback:\n")
reason.printTraceback(self.stderr)

View File

@ -187,6 +187,30 @@ class StorageClientConfig(object):
grid_manager_keys,
)
def get_configured_storage_plugins(self):
"""
:returns Dict[str, IFoolscapStoragePlugin]: a dict mapping names
to instances for all available plugins
:raises MissingPlugin: if the configuration asks for a plugin
for which there is no corresponding instance (e.g. it is
not installed).
"""
plugins = {
plugin.name: plugin
for plugin
in getPlugins(IFoolscapStoragePlugin)
}
configured = dict()
for plugin_name in self.storage_plugins:
try:
plugin = plugins[plugin_name]
except KeyError:
raise MissingPlugin(plugin_name)
configured[plugin_name] = plugin
return configured
@implementer(IStorageBroker)
class StorageFarmBroker(service.MultiService):
@ -765,10 +789,9 @@ class MissingPlugin(Exception):
"""
plugin_name = attr.ib()
nickname = attr.ib()
def __str__(self):
return "Missing plugin '{}' for server '{}'".format(self.plugin_name, self.nickname)
return "Missing plugin '{}'".format(self.plugin_name)
def _storage_from_foolscap_plugin(node_config, config, announcement, get_rref):
@ -782,26 +805,32 @@ def _storage_from_foolscap_plugin(node_config, config, announcement, get_rref):
:param dict announcement: The storage announcement for the storage
server we should build
"""
plugins = {
plugin.name: plugin
for plugin
in getPlugins(IFoolscapStoragePlugin)
}
storage_options = announcement.get(u"storage-options", [])
for plugin_name, plugin_config in list(config.storage_plugins.items()):
plugins = config.get_configured_storage_plugins()
# for every storage-option that we have enabled locally (in order
# of preference), see if the announcement asks for such a thing.
# if it does, great: we return that storage-client
# otherwise we've run out of options...
for options in storage_options:
try:
plugin = plugins[plugin_name]
plugin = plugins[options[u"name"]]
except KeyError:
raise MissingPlugin(plugin_name, announcement.get(u"nickname", "<unknown>"))
for option in storage_options:
if plugin_name == option[u"name"]:
furl = option[u"storage-server-FURL"]
return furl, plugin.get_storage_client(
node_config,
option,
get_rref,
)
plugin_names = ", ".join(sorted(list(config.storage_plugins.keys())))
# we didn't configure this kind of plugin locally, so
# consider the next announced option
continue
furl = options[u"storage-server-FURL"]
return furl, plugin.get_storage_client(
node_config,
options,
get_rref,
)
# none of the storage options in the announcement are configured
# locally; we can't make a storage-client.
plugin_names = ", ".join(sorted(plugins))
raise AnnouncementNotMatched(plugin_names)