summaryrefslogtreecommitdiffstats
path: root/openstack/common
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2012-04-04 15:50:16 +0000
committerGerrit Code Review <review@openstack.org>2012-04-04 15:50:16 +0000
commit3b6b2c5e8e6d67446127c9f99d7a5104843cb472 (patch)
tree84f7142439dc0b7fc1aea128a55fa8450565ca55 /openstack/common
parentdcd50714c4f1a207ff53b20475b620de39c0ed4a (diff)
parentbea9d49615563f73fe8be6ef5e71f96cc8fc1be3 (diff)
downloadoslo-3b6b2c5e8e6d67446127c9f99d7a5104843cb472.tar.gz
oslo-3b6b2c5e8e6d67446127c9f99d7a5104843cb472.tar.xz
oslo-3b6b2c5e8e6d67446127c9f99d7a5104843cb472.zip
Merge "Add generic PasteDeploy app and filter factories"
Diffstat (limited to 'openstack/common')
-rw-r--r--openstack/common/pastedeploy.py164
1 files changed, 164 insertions, 0 deletions
diff --git a/openstack/common/pastedeploy.py b/openstack/common/pastedeploy.py
new file mode 100644
index 0000000..2f29356
--- /dev/null
+++ b/openstack/common/pastedeploy.py
@@ -0,0 +1,164 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+import sys
+
+from paste import deploy
+
+from openstack.common import local
+
+
+class BasePasteFactory(object):
+
+ """A base class for paste app and filter factories.
+
+ Sub-classes must override the KEY class attribute and provide
+ a __call__ method.
+ """
+
+ KEY = None
+
+ def __init__(self, data):
+ self.data = data
+
+ def _import_factory(self, local_conf):
+ """Import an app/filter class.
+
+ Lookup the KEY from the PasteDeploy local conf and import the
+ class named there. This class can then be used as an app or
+ filter factory.
+
+ Note we support the <module>:<class> format.
+
+ Note also that if you do e.g.
+
+ key =
+ value
+
+ then ConfigParser returns a value with a leading newline, so
+ we strip() the value before using it.
+ """
+ mod_str, _sep, class_str = local_conf[self.KEY].strip().rpartition(':')
+ del local_conf[self.KEY]
+
+ __import__(mod_str)
+ return getattr(sys.modules[mod_str], class_str)
+
+
+class AppFactory(BasePasteFactory):
+
+ """A Generic paste.deploy app factory.
+
+ This requires openstack.app_factory to be set to a callable which returns a
+ WSGI app when invoked. The format of the name is <module>:<callable> e.g.
+
+ [app:myfooapp]
+ paste.app_factory = openstack.common.pastedeploy:app_factory
+ openstack.app_factory = myapp:Foo
+
+ The WSGI app constructor must accept a data object and a local config
+ dict as its two arguments.
+ """
+
+ KEY = 'openstack.app_factory'
+
+ def __call__(self, global_conf, **local_conf):
+ """The actual paste.app_factory protocol method."""
+ factory = self._import_factory(local_conf)
+ return factory(self.data, **local_conf)
+
+
+class FilterFactory(AppFactory):
+
+ """A Generic paste.deploy filter factory.
+
+ This requires openstack.filter_factory to be set to a callable which
+ returns a WSGI filter when invoked. The format is <module>:<callable> e.g.
+
+ [filter:myfoofilter]
+ paste.filter_factory = openstack.common.pastedeploy:filter_factory
+ openstack.filter_factory = myfilter:Foo
+
+ The WSGI filter constructor must accept a WSGI app, a data object and
+ a local config dict as its three arguments.
+ """
+
+ KEY = 'openstack.filter_factory'
+
+ def __call__(self, global_conf, **local_conf):
+ """The actual paste.filter_factory protocol method."""
+ factory = self._import_factory(local_conf)
+
+ def filter(app):
+ return factory(app, self.data, **local_conf)
+
+ return filter
+
+
+def app_factory(global_conf, **local_conf):
+ """A paste app factory used with paste_deploy_app()."""
+ return local.store.app_factory(global_conf, **local_conf)
+
+
+def filter_factory(global_conf, **local_conf):
+ """A paste filter factory used with paste_deploy_app()."""
+ return local.store.filter_factory(global_conf, **local_conf)
+
+
+def paste_deploy_app(paste_config_file, app_name, data):
+ """Load a WSGI app from a PasteDeploy configuration.
+
+ Use deploy.loadapp() to load the app from the PasteDeploy configuration,
+ ensuring that the supplied data object is passed to the app and filter
+ factories defined in this module.
+
+ To use these factories and the data object, the configuration should look
+ like this:
+
+ [app:myapp]
+ paste.app_factory = openstack.common.pastedeploy:app_factory
+ openstack.app_factory = myapp:App
+ ...
+ [filter:myfilter]
+ paste.filter_factory = openstack.common.pastedeploy:filter_factory
+ openstack.filter_factory = myapp:Filter
+
+ and then:
+
+ myapp.py:
+
+ class App(object):
+ def __init__(self, data):
+ ...
+
+ class Filter(object):
+ def __init__(self, app, data):
+ ...
+
+ :param paste_config_file: a PasteDeploy config file
+ :param app_name: the name of the app/pipeline to load from the file
+ :param data: a data object to supply to the app and its filters
+ :returns: the WSGI app
+ """
+ (af, ff) = (AppFactory(data), FilterFactory(data))
+
+ local.store.app_factory = af
+ local.store.filter_factory = ff
+ try:
+ return deploy.loadapp("config:%s" % paste_config_file, name=app_name)
+ finally:
+ del local.store.app_factory
+ del local.store.filter_factory