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便啟動了~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM