diff options
| author | Barry Warsaw | 2010-02-16 17:17:38 -0500 |
|---|---|---|
| committer | Barry Warsaw | 2010-02-16 17:17:38 -0500 |
| commit | cf6e714bc3c68a8b9d788370fbdee4df6764e936 (patch) | |
| tree | 47321a735879e40e50a228db254f6efbc3018a4b | |
| parent | 5d12a07fccf0278293e222ca5a5c4a7653d4f0af (diff) | |
| download | mailman-cf6e714bc3c68a8b9d788370fbdee4df6764e936.tar.gz mailman-cf6e714bc3c68a8b9d788370fbdee4df6764e936.tar.zst mailman-cf6e714bc3c68a8b9d788370fbdee4df6764e936.zip | |
| -rw-r--r-- | src/mailman/core/initialize.py | 19 | ||||
| -rw-r--r-- | src/mailman/rest/configuration.py | 21 | ||||
| -rw-r--r-- | src/mailman/rest/configure.zcml | 14 | ||||
| -rw-r--r-- | src/mailman/rest/publication.py | 4 | ||||
| -rw-r--r-- | src/mailman/rest/urls.py | 8 | ||||
| -rw-r--r-- | src/mailman/rest/webservice.py | 82 |
6 files changed, 100 insertions, 48 deletions
diff --git a/src/mailman/core/initialize.py b/src/mailman/core/initialize.py index 7c03a61db..e55e97ee5 100644 --- a/src/mailman/core/initialize.py +++ b/src/mailman/core/initialize.py @@ -87,19 +87,15 @@ def search_for_configuration_file(): # initialization, but before database initialization. Generally all other # code will just call initialize(). -def initialize_1(config_path=None, propagate_logs=None): +def initialize_1(config_path=None): """First initialization step. * Zope component architecture * The configuration system * Run-time directories - * The logging subsystem - * Internationalization :param config_path: The path to the configuration file. :type config_path: string - :param propagate_logs: Should the log output propagate to stderr? - :type propagate_logs: boolean or None """ zcml = resource_string('mailman.config', 'configure.zcml') xmlconfig.string(zcml) @@ -119,13 +115,12 @@ def initialize_1(config_path=None, propagate_logs=None): # For the test suite, force this back to not using a config file. config_path = None mailman.config.config.load(config_path) - # Create the queue and log directories if they don't already exist. - mailman.core.logging.initialize(propagate_logs) -def initialize_2(debug=False): +def initialize_2(debug=False, propagate_logs=None): """Second initialization step. + * Logging * Pre-hook * Rules * Chains @@ -134,7 +129,11 @@ def initialize_2(debug=False): :param debug: Should the database layer be put in debug mode? :type debug: boolean + :param propagate_logs: Should the log output propagate to stderr? + :type propagate_logs: boolean or None """ + # Create the queue and log directories if they don't already exist. + mailman.core.logging.initialize(propagate_logs) # Run the pre-hook if there is one. config = mailman.config.config if config.mailman.pre_hook: @@ -172,6 +171,6 @@ def initialize_3(): def initialize(config_path=None, propagate_logs=None): - initialize_1(config_path, propagate_logs) - initialize_2() + initialize_1(config_path) + initialize_2(propagate_logs=propagate_logs) initialize_3() diff --git a/src/mailman/rest/configuration.py b/src/mailman/rest/configuration.py index df756d76a..30e2607cb 100644 --- a/src/mailman/rest/configuration.py +++ b/src/mailman/rest/configuration.py @@ -55,18 +55,33 @@ class AdminWebServiceConfiguration(BaseWSGIWebServiceConfiguration): """See `IWebServiceConfiguration`.""" return as_boolean(config.webservice.use_https) - # This should match the major.minor Mailman version. - service_version_uri_prefix = '{0.MAJOR_REV}.{0.MINOR_REV}'.format(version) + # We currently have only one active version; the first entry in this list + # should match the major.minor Mailman version. The second entry is just + # an alias for the 'floating' development version. + active_versions = [ + '{0.MAJOR_REV}.{0.MINOR_REV}'.format(version), + 'dev', + ] code_revision = version.VERSION @property def show_tracebacks(self): """See `IWebServiceConfiguration`.""" return config.webservice.show_tracebacks - + default_batch_size = 50 max_batch_size = 300 def get_request_user(self): """See `IWebServiceConfiguration`.""" return None + + @property + def hostname(self): + """See `IWebServiceConfiguration`.""" + return config.webservice.hostname + + @property + def port(self): + """See `IWebServiceConfiguration`.""" + return int(config.webservice.port) diff --git a/src/mailman/rest/configure.zcml b/src/mailman/rest/configure.zcml index fff1b5bac..7fecf4608 100644 --- a/src/mailman/rest/configure.zcml +++ b/src/mailman/rest/configure.zcml @@ -5,8 +5,7 @@ <include package="zope.component" file="meta.zcml"/> <include package="zope.security" file="meta.zcml"/> - <include package="lazr.restful" file="meta.zcml"/> - <include package="lazr.restful" file="configure.zcml"/> + <include package="lazr.restful.example.wsgi" file="site.zcml"/> <webservice:register module="mailman.interfaces.domain" /> <webservice:register module="mailman.interfaces.listmanager" /> @@ -36,6 +35,12 @@ /> <adapter + for="mailman.interfaces.system.ISystem + lazr.restful.simple.Request" + provides="zope.traversing.browser.interfaces.IAbsoluteURL" + factory="mailman.rest.urls.FallbackURLMapper" + /> + <adapter for="mailman.interfaces.mailinglist.IMailingList lazr.restful.simple.Request" provides="zope.traversing.browser.interfaces.IAbsoluteURL" @@ -83,6 +88,11 @@ <!-- Utilities --> <utility + factory="mailman.rest.webservice.AdminWebServiceRootResource" + provides="lazr.restful.interfaces.IServiceRootResource" + /> + + <utility factory="mailman.rest.configuration.AdminWebServiceConfiguration" provides="lazr.restful.interfaces.IWebServiceConfiguration" /> diff --git a/src/mailman/rest/publication.py b/src/mailman/rest/publication.py index 13866861f..becca8fa6 100644 --- a/src/mailman/rest/publication.py +++ b/src/mailman/rest/publication.py @@ -25,12 +25,16 @@ __all__ = [ ] +import logging + from lazr.restful.simple import Publication from zope.publisher.interfaces import NotFound from mailman.config import config from mailman.interfaces.rest import IResolvePathNames +log = logging.getLogger('mailman.http') + class AdminWebServicePublication(Publication): diff --git a/src/mailman/rest/urls.py b/src/mailman/rest/urls.py index ec8e40557..1d7adc0dd 100644 --- a/src/mailman/rest/urls.py +++ b/src/mailman/rest/urls.py @@ -22,7 +22,9 @@ from __future__ import absolute_import, unicode_literals __metaclass__ = type __all__ = [ 'DomainURLMapper', + 'FallbackURLMapper', 'MailingListURLMapper', + 'MemberURLMapper', ] @@ -53,10 +55,10 @@ class BasicURLMapper: self.context = context self.request = request self.webservice_config = AdminWebServiceConfiguration() - self.version = self.webservice_config.service_version_uri_prefix + self.version = self.webservice_config.active_versions[0] self.schema = ('https' if self.webservice_config.use_https else 'http') - self.hostname = config.webservice.hostname - self.port = int(config.webservice.port) + self.hostname = self.webservice_config.hostname + self.port = self.webservice_config.port diff --git a/src/mailman/rest/webservice.py b/src/mailman/rest/webservice.py index 7f7cd898a..e30ac856d 100644 --- a/src/mailman/rest/webservice.py +++ b/src/mailman/rest/webservice.py @@ -34,15 +34,21 @@ import logging # proper Mailman logger instead of stderr, as is the default. from wsgiref.simple_server import WSGIServer, WSGIRequestHandler -from lazr.restful.simple import Request +from lazr.restful import register_versioned_request_utility +from lazr.restful.interfaces import ( + IServiceRootResource, IWebServiceClientRequest) +from lazr.restful.simple import Request, RootResource +from lazr.restful.wsgi import WSGIApplication from zope.component import getUtility from zope.interface import implements from zope.publisher.publish import publish from mailman.config import config from mailman.core.system import system -from mailman.interfaces.domain import IDomainCollection, IDomainManager +from mailman.interfaces.domain import IDomain, IDomainCollection from mailman.interfaces.listmanager import IListManager +from mailman.interfaces.mailinglist import IMailingList +from mailman.interfaces.member import IMember from mailman.interfaces.membership import ISubscriptionService from mailman.interfaces.rest import IResolvePathNames from mailman.rest.publication import AdminWebServicePublication @@ -51,46 +57,59 @@ log = logging.getLogger('mailman.http') -class AdminWebServiceApplication: - """A WSGI application for the admin REST interface.""" +# Marker interfaces for multiversion lazr.restful. +class I30Version(IWebServiceClientRequest): + pass + + +class IDevVersion(IWebServiceClientRequest): + pass + + + +class AdminWebServiceRootResource(RootResource): + """The lazr.restful non-versioned root resource.""" implements(IResolvePathNames) - def __init__(self, environ, start_response): - self.environ = environ - self.start_response = start_response + def __init__(self): + # We can't build these mappings at construction time. + self._collections = None + self._entry_links = None + self._top_names = None - def __iter__(self): - environ = self.environ - # Create the request based on the HTTP method used. - method = environ.get('REQUEST_METHOD', 'GET').upper() - request = Request(environ['wsgi.input'], environ) - request.setPublication(AdminWebServicePublication(self)) - # Support post-mortem debugging. - handle_errors = environ.get('wsgi.handleErrors', True) - # The request returned by the publisher may in fact be different than - # the one passed in. - request = publish(request, handle_errors=handle_errors) - # Start the WSGI server response. - response = request.response - self.start_response(response.getStatusString(), response.getHeaders()) - # Return the result body iterable. - return iter(response.consumeBodyIter()) + def _build_top_level_objects(self): + """See `RootResource`.""" + self._collections = dict( + domains=(IDomain, getUtility(IDomainCollection)), + lists=(IMailingList, getUtility(IListManager)), + members=(IMember, getUtility(ISubscriptionService)), + ) + self._entry_links = dict( + system=system, + ) + self._top_names = self._collection.copy() + self._top_names.update(self._entry_links) + return (self._collections, self._entry_links) def get(self, name): - """Maps root names to resources.""" - top_level = dict( - system=system, + """See `IResolvePathNames`.""" + top_names = dict( domains=getUtility(IDomainCollection), lists=getUtility(IListManager), members=getUtility(ISubscriptionService), + system=system, ) - next_step = top_level.get(name) - log.debug('Top level name: %s -> %s', name, next_step) - return next_step + return top_names.get(name) + + +class AdminWebServiceApplication(WSGIApplication): + """A WSGI application for the admin REST interface.""" + + # The only thing we need to override is the publication class. + publication_class = AdminWebServicePublication - class AdminWebServiceWSGIRequestHandler(WSGIRequestHandler): """Handler class which just logs output to the right place.""" @@ -99,8 +118,11 @@ class AdminWebServiceWSGIRequestHandler(WSGIRequestHandler): log.info('%s - - %s', self.address_string(), format % args) + def make_server(): """Create the WSGI admin REST server.""" + register_versioned_request_utility(I30Version, '3.0') + register_versioned_request_utility(IDevVersion, 'dev') host = config.webservice.hostname port = int(config.webservice.port) server = WSGIServer((host, port), AdminWebServiceWSGIRequestHandler) |
