implement the feature

improve the test slightly, too, to verify the configuration supplied to the
plugin is as expected.
This commit is contained in:
Jean-Paul Calderone 2019-07-24 15:37:24 -04:00
parent 326e5829b0
commit d69de15664
7 changed files with 101 additions and 4 deletions

View File

@ -889,6 +889,16 @@ class _Client(node.Node, pollmixin.PollMixin):
ic.publish("storage", announcement, self._node_private_key)
def get_client_storage_plugin_web_resources(self):
"""
Get all of the client-side ``IResource`` implementations provided by
enabled storage plugins.
:return dict[bytes, IResource provider]: The implementations.
"""
return self.storage_broker.get_client_storage_plugin_web_resources()
def _enable_storage_servers(self, announceable_storage_servers):
"""
Register and announce the given storage servers.

View File

@ -3117,6 +3117,17 @@ class IFoolscapStoragePlugin(IPlugin):
:rtype: ``Deferred`` firing with ``IStorageServer``
"""
def get_client_resource(configuration):
"""
Get an ``IResource`` that can be published in the Tahoe-LAFS web interface
to expose information related to this plugin.
:param dict configuration: Any configuration given in the section for
this plugin in the node's configuration file.
:rtype: ``IResource``
"""
class IAnnounceableStorageServer(Interface):
announcement = Attribute(

View File

@ -197,6 +197,24 @@ class StorageFarmBroker(service.MultiService):
storage_server.setServiceParent(self)
storage_server.start_connecting(self._trigger_connections)
def get_client_storage_plugin_web_resources(self):
"""
Get all of the client-side ``IResource`` implementations provided by
enabled storage plugins.
"""
plugins = {
plugin.name: plugin
for plugin
in getPlugins(IFoolscapStoragePlugin)
}
return {
name: plugins[name].get_client_resource(config)
for (name, config)
in self.storage_client_config.storage_plugins.items()
}
@log_call(
action_type=u"storage-client:broker:make-storage-server",
include_args=["server_id"],

View File

@ -3,6 +3,10 @@ A storage server plugin the test suite can use to validate the
functionality.
"""
from json import (
dumps,
)
import attr
from zope.interface import (
@ -12,7 +16,9 @@ from zope.interface import (
from twisted.internet.defer import (
succeed,
)
from twisted.web.static import (
Data,
)
from foolscap.api import (
RemoteInterface,
)
@ -60,6 +66,14 @@ class DummyStorage(object):
return DummyStorageClient(get_rref, configuration, announcement)
def get_client_resource(self, configuration):
"""
:return: A static data resource that produces the given configuration when
rendered, as an aid to testing.
"""
return Data(dumps(configuration), b"text/json")
@implementer(RIDummy)
@attr.s(cmp=True, hash=True)

View File

@ -1,6 +1,8 @@
import hashlib
from mock import Mock
from json import (
dumps,
)
from fixtures import (
TempDir,
)
@ -430,8 +432,10 @@ class StoragePluginWebPresence(AsyncTestCase):
self.node = yield self.node_fixture.create_node()
self.webish = self.node.getServiceNamed(WebishServer.name)
self.node.startService()
self.addCleanup(self.node.stopService)
self.port = self.webish.getPortnum()
@inlineCallbacks
def test_plugin_resource_path(self):
"""
@ -441,8 +445,8 @@ class StoragePluginWebPresence(AsyncTestCase):
port=self.port,
plugin_name=self.storage_plugin,
)
# As long as it doesn't raise an exception, the test is a success.
yield do_http(b"get", url)
result = yield do_http(b"get", url)
self.assertThat(result, Equals(dumps({b"web": b"1"})))

View File

@ -0,0 +1,34 @@
"""
This module implements a resource which has as children the web resources
of all enabled storage client plugins.
"""
from twisted.web.resource import (
Resource,
NoResource,
)
class StoragePlugins(Resource):
"""
The parent resource of all enabled storage client plugins' web resources.
"""
def __init__(self, client):
"""
:param _Client client: The Tahoe-LAFS client node object which will be
used to find the storage plugin web resources.
"""
Resource.__init__(self)
self._client = client
def getChild(self, segment, request):
"""
Get an ``IResource`` from the loaded, enabled plugin with a name that
equals ``segment``.
:see: ``twisted.web.iweb.IResource.getChild``
"""
resources = self._client.get_client_storage_plugin_web_resources()
try:
return resources[segment]
except KeyError:
return NoResource()

View File

@ -12,6 +12,10 @@ from allmydata.util import log, fileutil
from allmydata.web import introweb, root
from allmydata.web.common import IOpHandleTable, MyExceptionHandler
from .web.storage_plugins import (
StoragePlugins,
)
# we must override twisted.web.http.Request.requestReceived with a version
# that doesn't use cgi.parse_multipart() . Since we actually use Nevow, we
# override the nevow-specific subclass, nevow.appserver.NevowRequest . This
@ -168,6 +172,8 @@ class WebishServer(service.MultiService):
self.site.remember(self.root.child_operations, IOpHandleTable)
self.root.child_operations.setServiceParent(self)
self.root.putChild("storage-plugins", StoragePlugins(client))
def buildServer(self, webport, nodeurl_path, staticdir):
self.webport = webport
self.site = site = appserver.NevowSite(self.root)