~ubuntu-branches/ubuntu/saucy/heat/saucy-updates

« back to all changes in this revision

Viewing changes to heat/common/wsgi.py

  • Committer: Package Import Robot
  • Author(s): James Page, Chuck Short, James Page
  • Date: 2013-08-08 15:23:59 UTC
  • mfrom: (1.1.3)
  • Revision ID: package-import@ubuntu.com-20130808152359-9jgqjp23kssvc3x9
Tags: 2013.2~b2.a186.g2b4b248-0ubuntu1
[ Chuck Short ]
* debian/patches/rename-quantumclient.patch: Dropped no longer needed. 
* debian/control: Add python-oslo.sphinx

[ James Page ]
* New upstream snapshot.
* d/watch: Updated to track releases on launchpad.
* d/control: Drop BD in pep8, no longer required.
* d/control,rules: Drop use of openstack-pkg-tools, revert use of xz
  compression for debs.
* d/control,*.config,*.templates,po: Drop use of debconf/dbconfig-common
  to configure heat.
* d/*.upstart: Add upstart configurations for Ubuntu.
* d/p/default-kombu.patch: Switch default messaging from qpid to
  kombu.
* d/p/default-sqlite.patch: Use sqlite as default database option.
* d/control: Add python-ceilometerclient to BD's.
* d/rules: Fail package build for unit test failures.
* d/*.install: Directly install configuration files to /etc/heat.
* d/control: Update VCS locations to ubuntu-server-dev branches.
* d/heat-common.{install,manpages}: Include new binaries and associated
  manpages.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 
3
3
# Copyright 2010 United States Government as represented by the
4
4
# Administrator of the National Aeronautics and Space Administration.
 
5
# Copyright 2013 IBM Corp.
5
6
# All Rights Reserved.
6
7
#
7
8
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
43
44
import webob.exc
44
45
 
45
46
from heat.common import exception
 
47
from heat.openstack.common import gettextutils
 
48
from heat.openstack.common.gettextutils import _
46
49
from heat.openstack.common import importutils
47
 
from heat.openstack.common.gettextutils import _
48
50
 
49
51
 
50
52
URL_LENGTH_LIMIT = 50000
51
53
 
52
 
# TODO(shadower) remove this once eventlet 0.9.17 is in distros Heat
53
 
# supports (notably Fedora 17 and Ubuntu 12.04 and newer)
54
 
eventlet.wsgi.MAX_REQUEST_LINE = URL_LENGTH_LIMIT
55
 
 
56
54
bind_opts = [
57
 
    cfg.StrOpt('bind_host', default='0.0.0.0'),
58
 
    cfg.IntOpt('bind_port'),
 
55
    cfg.StrOpt('bind_host', default='0.0.0.0',
 
56
               help=_('Address to bind the server.  Useful when '
 
57
                      'selecting a particular network interface.')),
 
58
    cfg.IntOpt('bind_port',
 
59
               help=_('The port on which the server will listen.'))
59
60
]
60
61
 
 
62
cfg.CONF.register_opts(bind_opts)
 
63
 
61
64
socket_opts = [
62
 
    cfg.IntOpt('backlog', default=4096),
63
 
    cfg.StrOpt('cert_file'),
64
 
    cfg.StrOpt('key_file'),
 
65
    cfg.IntOpt('backlog', default=4096,
 
66
               help=_("Number of backlog requests "
 
67
                      "to configure the socket with")),
 
68
    cfg.StrOpt('cert_file', default=None,
 
69
               help=_("Location of the SSL Certificate File "
 
70
                      "to use for SSL mode")),
 
71
    cfg.StrOpt('key_file', default=None,
 
72
               help=_("Location of the SSL Key File to use "
 
73
                      "for enabling SSL mode")),
65
74
]
66
75
 
67
 
workers_opt = cfg.IntOpt('workers', default=0)
 
76
cfg.CONF.register_opts(socket_opts)
 
77
 
 
78
workers_opts = cfg.IntOpt('workers', default=0,
 
79
                          help=_("Number of workers for Heat service"))
 
80
 
 
81
cfg.CONF.register_opt(workers_opts)
68
82
 
69
83
 
70
84
class WritableLogger(object):
178
192
 
179
193
        self.application = application
180
194
        self.sock = get_socket(conf, default_port)
181
 
        conf.register_opt(workers_opt)
182
195
 
183
196
        self.logger = logging.getLogger('eventlet.wsgi.server')
184
197
 
206
219
                if err.errno not in (errno.EINTR, errno.ECHILD):
207
220
                    raise
208
221
            except KeyboardInterrupt:
209
 
                sys.exit(1)
210
222
                self.logger.info(_('Caught keyboard interrupt. Exiting.'))
211
223
                break
212
224
        eventlet.greenio.shutdown_safe(self.sock)
242
254
        eventlet.patcher.monkey_patch(all=False, socket=True)
243
255
        self.pool = eventlet.GreenPool(size=self.threads)
244
256
        try:
245
 
            eventlet_wsgi_server(self.sock,
 
257
            eventlet.wsgi.server(self.sock,
246
258
                                 self.application,
247
259
                                 custom_pool=self.pool,
248
260
                                 url_length_limit=URL_LENGTH_LIMIT,
255
267
    def _single_run(self, application, sock):
256
268
        """Start a WSGI server in a new green thread."""
257
269
        self.logger.info(_("Starting single process server"))
258
 
        eventlet_wsgi_server(sock, application,
 
270
        eventlet.wsgi.server(sock, application,
259
271
                             custom_pool=self.pool,
260
272
                             url_length_limit=URL_LENGTH_LIMIT,
261
273
                             log=WritableLogger(self.logger))
262
274
 
263
275
 
264
 
def eventlet_wsgi_server(sock, application, **kwargs):
265
 
    '''
266
 
    Return a new instance of the eventlet wsgi server with the proper url limit
267
 
    in a way that's compatible with eventlet 0.9.16 and 0.9.17.
268
 
    '''
269
 
    try:
270
 
        return eventlet.wsgi.server(sock, application, **kwargs)
271
 
    # TODO(shadower) remove this when we don't support eventlet 0.9.16 anymore
272
 
    except TypeError:
273
 
        kwargs.pop('url_length_limit', None)
274
 
        return eventlet.wsgi.server(sock, application, **kwargs)
275
 
 
276
 
 
277
276
class Middleware(object):
278
277
    """
279
278
    Base WSGI middleware wrapper. These classes require an application to be
317
316
 
318
317
    @webob.dec.wsgify
319
318
    def __call__(self, req):
320
 
        print ("*" * 40) + " REQUEST ENVIRON"
 
319
        print(("*" * 40) + " REQUEST ENVIRON")
321
320
        for key, value in req.environ.items():
322
321
            print(key, "=", value)
323
322
        print
324
323
        resp = req.get_response(self.application)
325
324
 
326
 
        print ("*" * 40) + " RESPONSE HEADERS"
 
325
        print(("*" * 40) + " RESPONSE HEADERS")
327
326
        for (key, value) in resp.headers.iteritems():
328
327
            print(key, "=", value)
329
328
        print
338
337
        Iterator that prints the contents of a wrapper string iterator
339
338
        when iterated.
340
339
        """
341
 
        print ("*" * 40) + " BODY"
 
340
        print(("*" * 40) + " BODY")
342
341
        for part in app_iter:
343
342
            sys.stdout.write(part)
344
343
            sys.stdout.flush()
427
426
        else:
428
427
            return content_type
429
428
 
 
429
    def best_match_language(self):
 
430
        """Determine language for returned response."""
 
431
        all_languages = gettextutils.get_available_languages('heat')
 
432
        return self.accept_language.best_match(all_languages,
 
433
                                               default_match='en_US')
 
434
 
430
435
 
431
436
def is_json_content_type(request):
432
437
    if request.method == 'GET':
585
590
                                          request, **action_args)
586
591
        except TypeError as err:
587
592
            logging.error(_('Exception handling resource: %s') % str(err))
588
 
            raise webob.exc.HTTPBadRequest()
 
593
            msg = _('The server could not comply with the request since\r\n'
 
594
                    'it is either malformed or otherwise incorrect.\r\n')
 
595
            err = webob.exc.HTTPBadRequest(msg)
 
596
            raise translate_exception(err, request.best_match_language())
 
597
        except webob.exc.HTTPException as err:
 
598
            logging.error(_("Returning %(code)s to user: %(explanation)s"),
 
599
                          {'code': err.code, 'explanation': err.explanation})
 
600
            raise translate_exception(err, request.best_match_language())
 
601
        except Exception as err:
 
602
            logging.error(_("Unexpected error occurred serving API: %s") % err)
 
603
            raise translate_exception(err, request.best_match_language())
589
604
 
590
605
        # Here we support either passing in a serializer or detecting it
591
606
        # based on the content type.
649
664
        return args
650
665
 
651
666
 
 
667
def translate_exception(exc, locale):
 
668
    """Translates all translatable elements of the given exception."""
 
669
    exc.message = gettextutils.get_localized_message(exc.message, locale)
 
670
    if isinstance(exc, webob.exc.HTTPError):
 
671
        # If the explanation is not a Message, that means that the
 
672
        # explanation is the default, generic and not translatable explanation
 
673
        # from webop.exc. Since the explanation is the error shown when the
 
674
        # exception is converted to a response, let's actually swap it with
 
675
        # message, since message is what gets passed in at construction time
 
676
        # in the API
 
677
        if not isinstance(exc.explanation, gettextutils.Message):
 
678
            exc.explanation = exc.message
 
679
            exc.detail = ''
 
680
        else:
 
681
            exc.explanation = \
 
682
                gettextutils.get_localized_message(exc.explanation, locale)
 
683
            exc.detail = gettextutils.get_localized_message(exc.detail, locale)
 
684
    return exc
 
685
 
 
686
 
652
687
class BasePasteFactory(object):
653
688
 
654
689
    """A base class for paste app and filter factories.