zoukankan      html  css  js  c++  java
  • openstack Rocky系列之keystone:(一)keystone的启动

    keystone在httpd的入口执行文件为/usr/bin/keystone-wsgi-public

    查看文件/usr/bin/keystone-wsgi-public,根据代码,看到主要是这几行代码对keystone的服务进行了初始化,keystone服务通过wsgiref.simple_server与httpd进行交互,初始化函数为initialize_public_application

     1 from keystone.server.wsgi import initialize_public_application
     2 
     3 if __name__ == "__main__":
     4     ......
     5     import wsgiref.simple_server as wss 
     6 
     7     ......
     8  
     9     server = wss.make_server(args.host, args.port, initialize_public_application())
    10 
    11     .......                                                     
    12     server.serve_forever()

    查看initialize_public_application

    1 from keystone.server.flask import core as flask_core
    2 def initialize_public_application():
    3     return flask_core.initialize_application(name='public', config_files=flask_core._get_config_files())
    4 initialize_admin_application = initialize_public_application

    从这里可以看到在Rocky版本的keystone中,admin和public已经合并在了一起,不再区分admin和public,flask_core.initialize_application接受三个参数,原型如下

     1 def initialize_application(name, post_log_configured_function=lambda: None,
     2                            config_files=None):
     3     possible_topdir = os.path.normpath(os.path.join(
     4                                        os.path.abspath(__file__),
     5                                        os.pardir,
     6                                        os.pardir,
     7                                        os.pardir,
     8                                        os.pardir))
     9 
    10     dev_conf = os.path.join(possible_topdir,
    11                             'etc',
    12                             'keystone.conf')
    13     if not config_files:
    14         config_files = None
    15         if os.path.exists(dev_conf):
    16             config_files = [dev_conf]
    17 
    18     keystone.server.configure(config_files=config_files)
    19 
    20     if CONF.debug:
    21         CONF.log_opt_values(log.getLogger(CONF.prog), log.DEBUG)
    22 
    23     post_log_configured_function()
    24 
    25     def loadapp():
    26         app = application.application_factory(name)
    27         return app
    28 
    29     _unused, app = keystone.server.setup_backends(
    30         startup_application_fn=loadapp)
    31 
    32     profiler.setup(name)
    33 
    34     return setup_app_middleware(app)
    name 这个不需要讲,但是name必须是public或者admin,在后面的初始化过程中有限制
    post_log_configured_function   接收一个函数,会在initialize_application这个函数中调用,但是具体是什么作用,还没有领悟出来,但是这个函数应该是可以做一些类似于初始化等等作用的
    config_files 在开发模式下可以自定义keystone.conf,如果自己定义了keyston.conf这个文件,那么就会完全的替代/etc/keystone/keystone.conf中定义的一些配置参数,关于配置参数,后续会介绍

    接着往下看这个函数
    keystone.server.configure这个函数对keystone进行了一些配置
     1 def configure(version=None, config_files=None,
     2               pre_setup_logging_fn=lambda: None):
     3     keystone.conf.configure()
     4     sql.initialize()
     5     keystone.conf.set_config_defaults()
     6 
     7     CONF(project='keystone', version=version,
     8          default_config_files=config_files)
     9 
    10     pre_setup_logging_fn()
    11     keystone.conf.setup_logging()
    12 
    13     if CONF.insecure_debug:
    14         LOG.warning(
    15             'insecure_debug is enabled so responses may include sensitive '
    16             'information.')
    keystone.conf.configure()这个函数添加了几个参数,
    standard-threads 可以自定义多少个线程
    pydev-debug-host以及pydev-debug-port是对远程debug的机器和port进行了定义,并在conf中注册了它们三个参数
     1 def configure(conf=None):
     2     if conf is None:
     3         conf = CONF
     4 
     5     conf.register_cli_opt(
     6         cfg.BoolOpt('standard-threads', default=False,
     7                     help='Do not monkey-patch threading system modules.'))
     8     conf.register_cli_opt(
     9         cfg.StrOpt('pydev-debug-host',
    10                    help='Host to connect to for remote debugger.'))
    11     conf.register_cli_opt(
    12         cfg.PortOpt('pydev-debug-port',
    13                     help='Port to connect to for remote debugger.'))
    14 
    15     for module in conf_modules:
    16         module.register_opts(conf)
    17 
    18     # register any non-default auth methods here (used by extensions, etc)
    19     auth.setup_authentication()
    20 
    21     # add oslo.cache related config options
    22     cache.configure(conf)
    auth.setup_authentication(),配置了几种认证方式,password,token等等,跟上述参数一样,先定义,后注册到conf中
    cache.configure(conf),对cache进行了定义和注册,主要涉及到各种cache的定义等等

    回到 keystone.server.configure
    sql.initialize() 这个函数主要是对数据库进行了初始化,导入配置文件中的参数
    keystone.conf.set_config_defaults()   采用默认值对keystone的设置进行初始化
    CONF(project='keystone', version=version, default_config_files=config_files) 这块比较难理解,先说第三个参数,第三个参数采用指定的config_files对默认参数进行复写

    CONF的原型是 keystone.conf.CONF, 它采用了从文件中直接导入的方式,构造了一个单例的configure配置类 CONF = ConfigOpts()

    CONF()调用了ConfigOpts.__call__()这个方法
    pre_setup_logging_fn()这个和前文的post_log_configured_function是相似的,都是完成一些自定义的动作
    keystone.conf.setup_logging()这个参数是对log进行配置

    回到initialize_application
    keystone.server.setup_backend(startup_application_fn=loadapp)
    1 def setup_backends(load_extra_backends_fn=lambda: {},
    2                    startup_application_fn=lambda: None):
    3     drivers = backends.load_backends()
    4     drivers.update(load_extra_backends_fn())
    5     res = startup_application_fn()
    6     return drivers, res
    1     def loadapp():
    2         app = application.application_factory(name)
    3         return app

    这两段代码中,setup_backends首先导入一些driver,导入方法主要是用stevedore的DriverManager类对一些方法进行导入,并将这些driver注册到provider_api中,供后续调用

    load_app采用了flask.application的工厂模式方法构造

     1 def application_factory(name='public'):
     2     if name not in ('admin', 'public'):
     3         raise RuntimeError('Application name (for base_url lookup) must be '
     4                            'either `admin` or `public`.')
     5 
     6     app = flask.Flask(name)
     7     app.after_request(_add_vary_x_auth_token_header)
     8 
     9     app.config.update(PROPAGATE_EXCEPTIONS=True)
    10 
    11     # TODO(morgan): Convert Subsystems over to Flask-Native, for now, we simply
    12     dispatch_map = collections.OrderedDict()
    13 
    14     hc_app = healthcheck.Healthcheck.app_factory(
    15         {}, oslo_config_project='keystone')
    16     dispatch_map['/healthcheck'] = hc_app
    17     _routers = []
    18     sub_routers = []
    19     mapper = routes.Mapper()
    20     for api_routers in ALL_API_ROUTERS:
    21         moved_found = [pfx for
    22                        pfx in getattr(api_routers, '_path_prefixes', [])
    23                        if pfx in _MOVED_API_PREFIXES]
    24         if moved_found:
    25             raise RuntimeError('An API Router is trying to register path '
    26                                'prefix(s) `%(pfx)s` that is handled by the '
    27                                'native Flask app. Keystone cannot '
    28                                'start.' %
    29                                {'pfx': ', '.join([p for p in moved_found])})
    30 
    31         routers_instance = api_routers.Routers()
    32         _routers.append(routers_instance)
    33         routers_instance.append_v3_routers(mapper, sub_routers)
    34 
    35     keystone.api.discovery.register_version('v3')
    36     for api in keystone.api.__apis__:
    37         for api_bp in api.APIs:
    38             api_bp.instantiate_and_register_to_app(app)
    39     sub_routers.append(_ComposibleRouterStub(_routers))
    40     legacy_dispatcher = keystone_wsgi.ComposingRouter(mapper, sub_routers)
    41 
    42     for pfx in itertools.chain(*[rtr.Routers._path_prefixes for
    43                                  rtr in ALL_API_ROUTERS]):
    44         dispatch_map['/v3/%s' % pfx] = legacy_dispatcher
    45 
    46     app.wsgi_app = KeystoneDispatcherMiddleware(
    47         app.wsgi_app,
    48         dispatch_map)
    49     return app

    这块限定了name只能是public or admin,这个函数主要是为keystone的请求添加路由的mapper以及中间件的调用,先由这个函数对请求的API的路径进行解析, 最后KeystoneDispatcherMiddleware完成对路径API的访问,同样是调用了__call__()方法

    profiler.setup(name)是对信息的采集,对性能统计有作用
    setup_app_middleware()同样是通过stevedore.DriverManager进行中间件的导入

    到此基本上整个keystone便启动了~
  • 相关阅读:
    SpringCloud之架构搭建
    3.通用权限设计——SnailAspNetCoreFramework快速开发框架之后端设计
    2.接口输入校验、输出格式、及异常处理——SnailAspNetCoreFramework快速开发框架之后端设计
    1、框架内各项目及目录的介绍和总设计思路——SnailAspNetCoreFramework快速开发框架
    SnailAspNetCoreFramework框架系列博客
    Asp.net core中间件实现原理及用法解说
    深入剖析linq的联接
    webapi框架搭建系列博客
    webapi框架搭建-依赖注入之autofac
    webapi框架搭建-创建项目(三)-webapi owin
  • 原文地址:https://www.cnblogs.com/sumoning/p/11132290.html
Copyright © 2011-2022 走看看