39
logging.getLogger("routes.middleware").addHandler(logging.StreamHandler())
37
from paste import deploy
39
from nova import flags
40
from nova import log as logging
41
from nova import utils
47
class WritableLogger(object):
48
"""A thin wrapper that responds to `write` and logs."""
50
def __init__(self, logger, level=logging.DEBUG):
55
self.logger.log(self.level, msg)
42
58
class Server(object):
43
59
"""Server class to manage multiple WSGI sockets and applications."""
45
61
def __init__(self, threads=1000):
46
63
self.pool = eventlet.GreenPool(threads)
48
65
def start(self, application, port, host='0.0.0.0', backlog=128):
49
66
"""Run a WSGI server with the given application."""
67
logging.audit(_("Starting %s on %s:%s"), sys.argv[0], host, port)
50
68
socket = eventlet.listen((host, port), backlog=backlog)
51
69
self.pool.spawn_n(self._run, application, socket)
60
78
def _run(self, application, socket):
61
79
"""Start a WSGI server in a new green thread."""
62
eventlet.wsgi.server(socket, application, custom_pool=self.pool)
80
logger = logging.getLogger('eventlet.wsgi.server')
81
eventlet.wsgi.server(socket, application, custom_pool=self.pool,
82
log=WritableLogger(logger))
65
85
class Application(object):
66
# TODO(gundlach): I think we should toss this class, now that it has no
68
86
"""Base WSGI application wrapper. Subclasses need to implement __call__."""
89
def factory(cls, global_config, **local_config):
90
"""Used for paste app factories in paste.deploy config fles.
92
Any local configuration (that is, values under the [app:APPNAME]
93
section of the paste config) will be passed into the `__init__` method
96
A hypothetical configuration would look like:
100
paste.app_factory = nova.api.fancy_api:Wadl.factory
102
which would result in a call to the `Wadl` class as
104
import nova.api.fancy_api
105
fancy_api.Wadl(latest_version='1.3')
107
You could of course re-implement the `factory` method in subclasses,
108
but using the kwarg passing it shouldn't be necessary.
111
return cls(**local_config)
70
113
def __call__(self, environ, start_response):
71
114
r"""Subclasses will probably want to implement __call__ like this:
100
143
See the end of http://pythonpaste.org/webob/modules/dec.html
103
raise NotImplementedError("You must implement __call__")
146
raise NotImplementedError(_("You must implement __call__"))
106
149
class Middleware(Application):
108
Base WSGI middleware wrapper. These classes require an application to be
150
"""Base WSGI middleware.
152
These classes require an application to be
109
153
initialized that will be called next. By default the middleware will
110
154
simply call its wrapped app, or you can override __call__ to customize its
114
def __init__(self, application): # pylint: disable-msg=W0231
159
def factory(cls, global_config, **local_config):
160
"""Used for paste app factories in paste.deploy config fles.
162
Any local configuration (that is, values under the [filter:APPNAME]
163
section of the paste config) will be passed into the `__init__` method
166
A hypothetical configuration would look like:
169
redis_host = 127.0.0.1
170
paste.filter_factory = nova.api.analytics:Analytics.factory
172
which would result in a call to the `Analytics` class as
174
import nova.api.analytics
175
analytics.Analytics(app_from_paste, redis_host='127.0.0.1')
177
You could of course re-implement the `factory` method in subclasses,
178
but using the kwarg passing it shouldn't be necessary.
182
return cls(app, **local_config)
185
def __init__(self, application):
115
186
self.application = application
188
def process_request(self, req):
189
"""Called on each request.
191
If this returns None, the next application down the stack will be
192
executed. If it returns a response then that response will be returned
193
and execution will stop here.
198
def process_response(self, response):
199
"""Do whatever you'd like to the response."""
117
202
@webob.dec.wsgify
118
def __call__(self, req): # pylint: disable-msg=W0221
119
"""Override to implement middleware behavior."""
120
return self.application
203
def __call__(self, req):
204
response = self.process_request(req)
207
response = req.get_response(self.application)
208
return self.process_response(response)
123
211
class Debug(Middleware):
270
358
needed to serialize a dictionary to that type.
272
360
self.metadata = metadata or {}
273
req = webob.Request(environ)
361
req = webob.Request.blank('', environ)
274
362
suffix = req.path_info.split('.')[-1].lower()
275
363
if suffix == 'json':
276
364
self.handler = self._to_json
372
460
node = doc.createTextNode(str(data))
373
461
result.appendChild(node)
465
def paste_config_file(basename):
466
"""Find the best location in the system for a paste config file.
471
The search for a paste config file honors `FLAGS.state_path`, which in a
472
version checked out from bzr will be the `nova` directory in the top level
473
of the checkout, and in an installation for a package for your distribution
474
will likely point to someplace like /etc/nova.
476
This method tries to load places likely to be used in development or
477
experimentation before falling back to the system-wide configuration
480
* Current working directory
481
* the `etc` directory under state_path, because when working on a checkout
482
from bzr this will point to the default
483
* top level of FLAGS.state_path, for distributions
484
* /etc/nova, which may not be diffrerent from state_path on your distro
488
configfiles = [basename,
489
os.path.join(FLAGS.state_path, 'etc', basename),
490
os.path.join(FLAGS.state_path, basename),
491
'/etc/nova/%s' % basename]
492
for configfile in configfiles:
493
if os.path.exists(configfile):
497
def load_paste_configuration(filename, appname):
498
"""Returns a paste configuration dict, or None."""
499
filename = os.path.abspath(filename)
502
config = deploy.appconfig("config:%s" % filename, name=appname)
508
def load_paste_app(filename, appname):
509
"""Builds a wsgi app from a paste config, None if app not configured."""
510
filename = os.path.abspath(filename)
513
app = deploy.loadapp("config:%s" % filename, name=appname)
519
def paste_config_to_flags(config, mixins):
520
for k, v in mixins.iteritems():
521
value = config.get(k, v)
522
converted_value = FLAGS[k].parser.Parse(value)
523
setattr(FLAGS, k, converted_value)