"Fossies" - the Fresh Open Source Software Archive

Member "zaqar-10.0.0/zaqar/transport/wsgi/driver.py" (13 May 2020, 7426 Bytes) of package /linux/misc/openstack/zaqar-10.0.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "driver.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 9.0.0_vs_10.0.0.

    1 # Copyright (c) 2013 Rackspace, Inc.
    2 #
    3 # Licensed under the Apache License, Version 2.0 (the "License");
    4 # you may not use this file except in compliance with the License.
    5 # You may obtain a copy of the License at
    6 #
    7 #    http://www.apache.org/licenses/LICENSE-2.0
    8 #
    9 # Unless required by applicable law or agreed to in writing, software
   10 # distributed under the License is distributed on an "AS IS" BASIS,
   11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
   12 # implied.
   13 # See the License for the specific language governing permissions and
   14 # limitations under the License.
   15 
   16 from distutils import version as d_version
   17 import falcon
   18 import six
   19 import socket
   20 from wsgiref import simple_server
   21 
   22 from oslo_log import log as logging
   23 from oslo_utils import netutils
   24 
   25 from zaqar.common import decorators
   26 from zaqar.common.transport.wsgi import helpers
   27 from zaqar.conf import drivers_transport_wsgi
   28 from zaqar.i18n import _
   29 from zaqar import transport
   30 from zaqar.transport import acl
   31 from zaqar.transport.middleware import auth
   32 from zaqar.transport.middleware import cors
   33 from zaqar.transport.middleware import profile
   34 from zaqar.transport import validation
   35 from zaqar.transport.wsgi import v1_0
   36 from zaqar.transport.wsgi import v1_1
   37 from zaqar.transport.wsgi import v2_0
   38 from zaqar.transport.wsgi import version
   39 
   40 
   41 LOG = logging.getLogger(__name__)
   42 
   43 
   44 class FuncMiddleware(object):
   45 
   46     def __init__(self, func):
   47         self.func = func
   48 
   49     def process_resource(self, req, resp, resource, params):
   50         return self.func(req, resp, params)
   51 
   52 
   53 class Driver(transport.DriverBase):
   54 
   55     def __init__(self, conf, storage, cache, control):
   56         super(Driver, self).__init__(conf, storage, cache, control)
   57 
   58         self._conf.register_opts(drivers_transport_wsgi.ALL_OPTS,
   59                                  group=drivers_transport_wsgi.GROUP_NAME)
   60         self._wsgi_conf = self._conf[drivers_transport_wsgi.GROUP_NAME]
   61         self._validate = validation.Validator(self._conf)
   62 
   63         self.app = None
   64         self._init_routes()
   65         self._init_middleware()
   66 
   67     def _verify_pre_signed_url(self, req, resp, params):
   68         return helpers.verify_pre_signed_url(self._conf.signed_url.secret_key,
   69                                              req, resp, params)
   70 
   71     def _validate_queue_identification(self, req, resp, params):
   72         return helpers.validate_queue_identification(
   73             self._validate.queue_identification, req, resp, params)
   74 
   75     def _validate_topic_identification(self, req, resp, params):
   76         return helpers.validate_topic_identification(
   77             self._validate.topic_identification, req, resp, params)
   78 
   79     def _require_client_id(self, req, resp, params):
   80         return helpers.require_client_id(
   81             self._validate.client_id_uuid_safe, req, resp, params)
   82 
   83     @decorators.lazy_property(write=False)
   84     def before_hooks(self):
   85         """Exposed to facilitate unit testing."""
   86         return [
   87             self._verify_pre_signed_url,
   88             helpers.require_content_type_be_non_urlencoded,
   89             helpers.require_accepts_json,
   90             self._require_client_id,
   91             helpers.extract_project_id,
   92 
   93             # NOTE(jeffrey4l): Depends on the project_id and client_id being
   94             # extracted above
   95             helpers.inject_context,
   96 
   97             # NOTE(kgriffs): Depends on project_id being extracted, above
   98             self._validate_queue_identification,
   99 
  100             # NOTE(kgriffs): Depends on project_id being extracted, above
  101             self._validate_topic_identification
  102         ]
  103 
  104     def _init_routes(self):
  105         """Initialize hooks and URI routes to resources."""
  106 
  107         catalog = [
  108             ('/v1', v1_0.public_endpoints(self, self._conf)),
  109             ('/v1.1', v1_1.public_endpoints(self, self._conf)),
  110             ('/v2', v2_0.public_endpoints(self, self._conf)),
  111             ('/', [('', version.Resource())])
  112         ]
  113 
  114         if self._conf.admin_mode:
  115             catalog.extend([
  116                 ('/v1', v1_0.private_endpoints(self, self._conf)),
  117                 ('/v1.1', v1_1.private_endpoints(self, self._conf)),
  118                 ('/v2', v2_0.private_endpoints(self, self._conf)),
  119             ])
  120 
  121         # NOTE(wanghao): Since hook feature has removed after 1.0.0, using
  122         # middleware instead of it, but for the compatibility with old version,
  123         # we support them both now. Hook way can be removed after falcon
  124         # version must be bigger than 1.0.0 in requirements.
  125         if (d_version.LooseVersion(falcon.__version__) >=
  126                 d_version.LooseVersion("1.0.0")):
  127             middleware = [FuncMiddleware(hook) for hook in self.before_hooks]
  128             self.app = falcon.API(middleware=middleware)
  129         else:
  130             self.app = falcon.API(before=self.before_hooks)
  131 
  132         # Set options to keep behavior compatible to pre-2.0.0 falcon
  133         self.app.req_options.auto_parse_qs_csv = True
  134         self.app.req_options.keep_blank_qs_values = False
  135 
  136         self.app.add_error_handler(Exception, self._error_handler)
  137 
  138         for version_path, endpoints in catalog:
  139             if endpoints:
  140                 for route, resource in endpoints:
  141                     self.app.add_route(version_path + route, resource)
  142 
  143     def _init_middleware(self):
  144         """Initialize WSGI middlewarez."""
  145 
  146         # NOTE(zhiyan): Install Profiler
  147         if (self._conf.profiler.enabled and
  148                 self._conf.profiler.trace_wsgi_transport):
  149             self.app = profile.install_wsgi_tracer(self.app, self._conf)
  150 
  151         auth_app = self.app
  152         # NOTE(flaper87): Install Auth
  153         if self._conf.auth_strategy:
  154             strategy = auth.strategy(self._conf.auth_strategy)
  155             auth_app = strategy.install(self.app, self._conf)
  156 
  157         self.app = auth.SignedHeadersAuth(self.app, auth_app)
  158 
  159         # NOTE(wangxiyuan): Install CORS, this middleware should be called
  160         # before Keystone auth.
  161         self.app = cors.install_cors(self.app, auth_app, self._conf)
  162 
  163         acl.setup_policy(self._conf)
  164 
  165     def _error_handler(self, exc, request, response, params):
  166         if isinstance(exc, falcon.HTTPError):
  167             raise
  168         LOG.exception('Internal server error')
  169         raise falcon.HTTPInternalServerError('Internal server error',
  170                                              six.text_type(exc))
  171 
  172     def _get_server_cls(self, host):
  173         """Return an appropriate WSGI server class base on provided host
  174 
  175         :param host: The listen host for the zaqar API server.
  176         """
  177         server_cls = simple_server.WSGIServer
  178         if netutils.is_valid_ipv6(host):
  179             if getattr(server_cls, 'address_family') == socket.AF_INET:
  180                 class server_cls(server_cls):
  181                     address_family = socket.AF_INET6
  182         return server_cls
  183 
  184     def listen(self):
  185         """Self-host using 'bind' and 'port' from the WSGI config group."""
  186 
  187         msgtmpl = _(u'Serving on host %(bind)s:%(port)s')
  188         LOG.info(msgtmpl,
  189                  {'bind': self._wsgi_conf.bind, 'port': self._wsgi_conf.port})
  190         server_cls = self._get_server_cls(self._wsgi_conf.bind)
  191         httpd = simple_server.make_server(self._wsgi_conf.bind,
  192                                           self._wsgi_conf.port,
  193                                           self.app,
  194                                           server_cls)
  195         httpd.serve_forever()