在分析Neutron源碼的過程中,會遇到很多阻礙,oslo.config就是其中之一。啟動Neutron的标準方式是systemctl start neutron-server.service。那麼該指令具體做了哪些事情,neutron-server的配置參數又是怎麼被加載的呢?
下面讓我們具體分析。
-
neutron-server.service的具體内容
檔案路徑在/usr/lib/systemd/system/neutron-server.service。如果不清楚怎麼确定systemd配置檔案,可以檢視我的另外一篇專門講解systemd的博文。
[Unit]
Description=OpenStack Neutron Server
After=syslog.target network.target
[Service]
Type=notify
User=neutron
ExecStart=/usr/bin/neutron-server --config-file /usr/share/neutron/neutron-dist.conf --config-dir /usr/share/neutron/server --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugin.ini --config-dir /etc/neutron/conf.d/common --config-dir /etc/neutron/conf.d/neutron-server --log-file /var/log/neutron/server.log
PrivateTmp=true
NotifyAccess=all
KillMode=process
Restart=on-failure
TimeoutStartSec=0
[Install]
WantedBy=multi-user.target
從上可知,neutron-server的配置檔案有neutron-dist.conf,neutron.conf, plugin.ini和server.log四個檔案。
下面根據檔案之間的引用關系,按順序依次找到并展示如下:
- /usr/bin/neutron-server
#!/usr/bin/python2
# PBR Generated from u'console_scripts'
import sys
from neutron.cmd.eventlet.server import main
if __name__ == "__main__":
sys.exit(main())
- neutron.cmd.eventlet.server.main
from neutron import server
from neutron.server import rpc_eventlet
from neutron.server import wsgi_eventlet
def main():
server.boot_server(wsgi_eventlet.eventlet_wsgi_server)
- neutron.server.boot_server
def boot_server(server_func):
_init_configuration()
try:
server_func()
except KeyboardInterrupt:
pass
except RuntimeError as e:
sys.exit(_("ERROR: %s") % e)
- boot_server回調了_init_configuration函數
def _init_configuration():
# the configuration will be read into the cfg.CONF global data structure
config.init(sys.argv[1:])
config.setup_logging()
config.set_config_defaults()
if not cfg.CONF.config_file:
sys.exit(_("ERROR: Unable to find configuration file via the default"
" search paths (~/.neutron/, ~/, /etc/neutron/, /etc/) and"
" the '--config-file' option!"))
至此,我們終于找到neutron-server服務加載配置檔案的函數。它又調用了neutron.common.config的init方法。
- neutron.common.config.init
def init(args, **kwargs):
cfg.CONF(args=args, project='neutron',
version='%%(prog)s %s' % version.version_info.release_string(),
**kwargs)
# FIXME(ihrachys): if import is put in global, circular import
# failure occurs
from neutron.common import rpc as n_rpc
n_rpc.init(cfg.CONF)
# Validate that the base_mac is of the correct format
msg = validators.validate_regex(cfg.CONF.base_mac, validators.MAC_PATTERN)
if msg:
msg = _("Base MAC: %s") % msg
raise Exception(msg)
我們知道args的實際值是:
--config-file /usr/share/neutron/neutron-dist.conf --config-dir /usr/share/neutron/server --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugin.ini --config-dir /etc/neutron/conf.d/common --config-dir /etc/neutron/conf.d/neutron-server --log-file /var/log/neutron/server.log
讓我們在互動指令視窗模拟neutron-server的cfg.CONF對象初始化過程:
>>> from oslo_config import cfg
>>> cfg.CONF.register_opt(cfg.StrOpt('transport_url'))
True
>>> cfg.CONF(args=['--config-file', '/usr/share/neutron/neutron-dist.conf', '--config-dir', '/usr/share/neutron/server', '--config-file', '/etc/neutron/neutron.conf', '--config-file', '/etc/neutron/plugin.ini', '--config-dir', '/etc/neutron/conf.d/common', '--config-dir', '/etc/neutron/conf.d/neutron-server'])
>>> cfg.CONF.items()
[('transport_url', 'rabbit://guest:[email protected]'), ('config_dir', ['/etc/neutron/conf.d/neutron-server']), ('config_file', ['/usr/share/neutron/neutron-dist.conf', '/etc/neutron/neutron.conf', '/etc/neutron/plugin.ini'])]
>>> cfg.CONF.transport_url
'rabbit://guest:[email protected]'
從上可知,在加載配置檔案之前,需要先注冊配置項的鍵。neutron-server鍵值注冊有部分是在neutron.conf.common中處理的,相關方法如下:
register_core_common_config_opts
register_nova_opts
register_placement_opts
neutron-server配置加載流程就介紹到這裡,如果想繼續深入,可直接閱讀源碼。
oslo.config子產品使用介紹
上面我們已經對neutron-server通過oslo.config加載配置檔案的流程進行了詳細分析,接下來對oslo.config子產品的用法進行簡單介紹,以幫助大家快速上手oslo.config,并且能夠應用到生産實踐中。
衆所周知,oslo.config是一個OpenStack通用庫,用于解析并加載來自于CLI或者配置檔案中提供的參數項或者配置項。
- 定義配置項
default_opts = [
cfg.StrOpt('host',default='0.0.0.0',help='default ip'),
cfg.IntOpt('port',default='443',help='listen port'),
]
- 注冊配置項
from oslo_config import cfg
cfg.CONF.register_opts(default_opts)
register_opts用于注冊option對象數組,如果僅注冊單項可使用register_opt方法。
- 定義配置組并注冊
group = cfg.OptGroup(name='rabbit',title='group')
cfg.CONF.register_group(group)
cfg.CONF.register_opts(default_opts,group)
- 從指令行讀取配置
cfg.CONF(default_config_files=['/etc/api.ini'])
在互動指令視窗進行驗證:
>>> from oslo_config import cfg
>>> default_opts = [
... cfg.StrOpt('host',default='0.0.0.0',help='default ip'),
... cfg.IntOpt('port',default='443',help='listen port'),
... ]
>>> cfg.CONF.register_opts(default_opts)
>>> cfg.CONF.items()
[('host', '0.0.0.0'), ('port', 443)]
>>> cfg.CONF.host
'0.0.0.0'
>>> cfg.CONF.port
443
>>> group = cfg.OptGroup(name='rabbit',title='group')
>>> cfg.CONF.register_group(group)
>>> cfg.CONF.register_opts(default_opts,group)
>>> cfg.CONF.items()
[('host', '0.0.0.0'), ('port', 443), ('rabbit', <oslo_config.cfg.GroupAttr object at 0x7fb42693ca50>)]
>>> cfg.CONF.rabbit.host
'0.0.0.0'
>>> cfg.CONF.rabbit.port
443
>>> cfg.CONF(default_config_files=['/etc/api.ini'])
>>> cfg.CONF.items()
[('config_dir', []), ('host', '0.0.0.0'), ('config_file', ['/etc/api.ini']), ('port', 443), ('rabbit', <oslo_config.cfg.GroupAttr object at 0x7fb419c8cf10>)]
>>> cfg.CONF.rabbit.host
'192.168.90.26'
>>> cfg.CONF.rabbit.port
9527
其中,/etc/api.ini内容如下:
[rabbit]
host=192.168.90.26
port=9527
最後,一個需要注意的地方是各種配置方式的優先級:CLI參數項>配置檔案項>自定義的配置項預設值。推薦使用配置檔案對項目變量進行配置。另外,cfg.CONF對象采用了單例模式,整個neutron-server項目中的cfg.CONF執行個體僅有一個。
小結
oslo.config子產品被廣泛應用于OpenStack各個子產品,是以學會使用oslo.config,對快速分析OpenStack項目特别重要。其次,在進行Python項目開發時,使用oslo.config子產品解析項目配置也是一個不錯的選擇。
如果對雲計算感興趣,可以關注我的微信公衆号: