zoukankan      html  css  js  c++  java
  • openstack Rocky系列之keystone:(二)keystone中API注册

    主要说一下initialize_application中的application_factory

    1     def loadapp():
    2         app = application.application_factory(name)
    3         return app

    源码如下

     1 @fail_gracefully
     2 def application_factory(name='public'):
     3     if name not in ('admin', 'public'):
     4         raise RuntimeError('Application name (for base_url lookup) must be '
     5                            'either `admin` or `public`.')
     6 
     7     # NOTE(morgan): The Flask App actually dispatches nothing until we migrate
     8     # some routers to Flask-Blueprints, it is simply a placeholder.
     9     app = flask.Flask(name)
    10     app.after_request(_add_vary_x_auth_token_header)
    11 
    12     # NOTE(morgan): Configure the Flask Environment for our needs.
    13     app.config.update(
    14         # We want to bubble up Flask Exceptions (for now)
    15         PROPAGATE_EXCEPTIONS=True)
    16 
    17     # TODO(morgan): Convert Subsystems over to Flask-Native, for now, we simply
    18     # dispatch to another "application" [e.g "keystone"]
    19     # NOTE(morgan): as each router is converted to flask-native blueprint,
    20     # remove from this list. WARNING ORDER MATTERS; ordered dict used to
    21     # ensure sane ordering of the routers in the legacy-dispatch model.
    22     dispatch_map = collections.OrderedDict()
    23 
    24     # Load in Healthcheck and map it to /healthcheck
    25     hc_app = healthcheck.Healthcheck.app_factory(
    26         {}, oslo_config_project='keystone')
    27     dispatch_map['/healthcheck'] = hc_app
    28 
    29     # More legacy code to instantiate all the magic for the dispatchers.
    30     # The move to blueprints (FLASK) will allow this to be eliminated.
    31     _routers = []
    32     sub_routers = []
    33     mapper = routes.Mapper()
    34     for api_routers in ALL_API_ROUTERS:
    35         moved_found = [pfx for
    36                        pfx in getattr(api_routers, '_path_prefixes', [])
    37                        if pfx in _MOVED_API_PREFIXES]
    38         if moved_found:
    39             raise RuntimeError('An API Router is trying to register path '
    40                                'prefix(s) `%(pfx)s` that is handled by the '
    41                                'native Flask app. Keystone cannot '
    42                                'start.' %
    43                                {'pfx': ', '.join([p for p in moved_found])})
    44 
    45         routers_instance = api_routers.Routers()
    46         _routers.append(routers_instance)
    47         routers_instance.append_v3_routers(mapper, sub_routers)
    48     # TODO(morgan): Remove "API version registration". For now this is kept
    49     # for ease of conversion (minimal changes)
    50     keystone.api.discovery.register_version('v3')
    51 
    52     # NOTE(morgan): We add in all the keystone.api blueprints here, this
    53     # replaces (as they are implemented) the legacy dispatcher work.
    54     for api in keystone.api.__apis__:
    55         for api_bp in api.APIs:
    56             api_bp.instantiate_and_register_to_app(app)
    57 
    58     # Build and construct the dispatching for the Legacy dispatching model
    59     sub_routers.append(_ComposibleRouterStub(_routers))
    60     legacy_dispatcher = keystone_wsgi.ComposingRouter(mapper, sub_routers)
    61 
    62     for pfx in itertools.chain(*[rtr.Routers._path_prefixes for
    63                                  rtr in ALL_API_ROUTERS]):
    64         import pdb;pdb.set_trace()
    65         dispatch_map['/v3/%s' % pfx] = legacy_dispatcher
    66     app.wsgi_app = KeystoneDispatcherMiddleware(
    67         app.wsgi_app,
    68         dispatch_map)
    69     return app
    fail_gracefully是个装饰器,主要是为了防止函数报错,抓一下exception,并记录报错信息,其中又使用了一个functools.wraps的装饰器,防止fail_gracefully对被装饰的函数造成影响
    主要看27行dispatch_map = collections.OrderedDict(),这里创建了一个dispatch_map的变量,这个变量用于记录所有的路由分发

    33行创建了一个router.Mapper()的对象mapper
     1     for api_routers in ALL_API_ROUTERS:
     2         moved_found = [pfx for
     3                        pfx in getattr(api_routers, '_path_prefixes', [])
     4                        if pfx in _MOVED_API_PREFIXES]
     5         if moved_found:
     6             raise RuntimeError('An API Router is trying to register path '
     7                                'prefix(s) `%(pfx)s` that is handled by the '
     8                                'native Flask app. Keystone cannot '
     9                                'start.' %
    10                                {'pfx': ', '.join([p for p in moved_found])})
    11 
    12         routers_instance = api_routers.Routers()
    13         _routers.append(routers_instance)
    14         routers_instance.append_v3_routers(mapper, sub_routers)

    ALL_API_ROUTER是一个包含所有处理路由的类的列表,这个循环中主要是过滤掉所有的被移除的API,api_routes.Routers()继承wsgi.RoutersBase,并通过append_v3_routers将自己的路由信息记录到mapper中,其中sub_routers是记录顶层路由下的路由

    sub_routers.append(_ComposibleRouterStub(_routers))这行代码将_router整合到sub_routers中
    legacy_dispatcher = keystone_wsgi.ComposingRouter(mapper, sub_routers)这行代码最终调用的源代码如下
     1 class Router(wsgi.ComposableRouter):
     2     def __init__(self, controller, collection_key, key,
     3                  resource_descriptions=None,
     4                  is_entity_implemented=True,
     5                  method_template=None):
     6         self.controller = controller
     7         self.key = key
     8         self.collection_key = collection_key
     9         self._resource_descriptions = resource_descriptions
    10         self._is_entity_implemented = is_entity_implemented
    11         self.method_template = method_template or '%s'
    12 
    13     def add_routes(self, mapper):
    14         collection_path = '/%(collection_key)s' % {
    15             'collection_key': self.collection_key}
    16         entity_path = '/%(collection_key)s/{%(key)s_id}' % {
    17             'collection_key': self.collection_key,
    18             'key': self.key}
    19 
    20         mapper.connect(
    21             collection_path,
    22             controller=self.controller,
    23             action=self.method_template % 'create_%s' % self.key,
    24             conditions=dict(method=['POST']))
    25         mapper.connect(
    26             collection_path,
    27             controller=self.controller,
    28             action=self.method_template % 'list_%s' % self.collection_key,
    29             conditions=dict(method=['GET', 'HEAD']))
    30         mapper.connect(
    31             entity_path,
    32             controller=self.controller,
    33             action=self.method_template % 'get_%s' % self.key,
    34             conditions=dict(method=['GET', 'HEAD']))
    35         mapper.connect(
    36             entity_path,
    37             controller=self.controller,
    38             action=self.method_template % 'update_%s' % self.key,
    39             conditions=dict(method=['PATCH']))
    40         mapper.connect(
    41             entity_path,
    42             controller=self.controller,
    43             action=self.method_template % 'delete_%s' % self.key,
    44             conditions=dict(method=['DELETE']))
    45 
    46         # Add the collection resource and entity resource to the resource
    47         # descriptions.
    48 
    49         collection_rel = json_home.build_v3_resource_relation(
    50             self.collection_key)
    51         rel_data = {'href': collection_path, }
    52         self._resource_descriptions.append((collection_rel, rel_data))
    53         json_home.JsonHomeResources.append_resource(collection_rel, rel_data)
    54 
    55         if self._is_entity_implemented:
    56             entity_rel = json_home.build_v3_resource_relation(self.key)
    57             id_str = '%s_id' % self.key
    58             id_param_rel = json_home.build_v3_parameter_relation(id_str)
    59             entity_rel_data = {
    60                 'href-template': entity_path,
    61                 'href-vars': {
    62                     id_str: id_param_rel,
    63                 },
    64             }
    65             self._resource_descriptions.append((entity_rel, entity_rel_data))
    66             json_home.JsonHomeResources.append_resource(
    67                 entity_rel, entity_rel_data)

    通过add_router为route添加mapper

    1     for pfx in itertools.chain(*[rtr.Routers._path_prefixes for
    2                                  rtr in ALL_API_ROUTERS]):
    3         dispatch_map['/v3/%s' % pfx] = legacy_dispatcher

    这里主要添加dispatch_map中的前缀和处理代码的映射关系,涉及到itertools.chain()用法的小技巧

    最后一行的KeystoneDispatcherMiddleware类负责API的分发,同样是通过__call__()这个魔法函数

  • 相关阅读:
    使用VisualStudio进行单元测试之二
    使用VisualStudio进行单元测试之一
    ExtJS监听键盘事件:回车键实现登录功能
    PPTP无法连网
    Android深度探索.
    Android深度探索
    Android驱动开发
    window.open()的具体使用方法
    js控制的几种页面跳转和传值(转载)
    Hatching shader
  • 原文地址:https://www.cnblogs.com/sumoning/p/11224666.html
Copyright © 2011-2022 走看看