OpenStack开发基础-oslo.config

The cfg Module

cfg Module来自于OpenStack中的重要的基础组件oslo.config,通过cfg Module可以用来通过命令行或者是配置文件来配置一些options,对于每一个选项使用Opt类或者其子类来定义。首先我们来看一个定义option的例子:

example1:
#!/usr/bin/env python
# encoding: utf-8

from oslo_config import cfg
from oslo_config import types

# 定义了一个类型和范围
PortType = types.Integer(1,65535)

# 定义一组选项
common_opts = [
    #定义了一个Str类型的选项,名字是bind_host,默认值是0.0.0.0,还有帮助信息
    #用的是Opt的子类来定义的,所以无需指定类类型,因为类型已经定下来了就是Str类型
    cfg.StrOpt('bind_host',default='0.0.0.0',
               help='IP address to listen on.'),
    #使用Opt类来定义一个选项,因为用的是基类,类型可以是任意的,所以需要使用type字段明确其类型
    #使用这种方式的好处我觉得就是可以定制类型的值范围
    cfg.Opt('bind_port',
            type=PortType,
            default=9292,
            help="Port number to listen on.")
]

Opt是父类,其下有很多特定类型的子类。下面是cfg Module支持的一些类型

oslo_config.types.String    
oslo_config.types.Boolean
oslo_config.types.Integer
oslo_config.types.Float
oslo_config.types.List
oslo_config.types.Dict
oslo_config.types.IPAddress

这些类型可以用于在传递给Opt类,定义选型的类型信息,cfg也给我们提供了一系列的特定类型的选项类,可以直接使用这些类来定义对应类型的选项

oslo_config.cfg.StrOpt
oslo_config.cfg.BoolOpt
oslo_config.cfg.IntOpt
oslo_config.cfg.PortOpt
oslo_config.cfg.FloatOpt
oslo_config.cfg.ListOpt
oslo_config.cfg.DictOpt
oslo_config.cfg.IPOpt

我相信一眼就可以看出猫腻,所以这里就不解释了。
cfg Module同样也支持具有多个值的选项,使用oslo_config.cfg.MultiOpt来定义,和oslo_config.cfg.Opt是相对的,前者是支持多个值的选项,后者是支持单个值的在使用MultiOpt类的时候通过设置item_type参数来设置选项的类型,为了方面MultiOpt同样也又许多可以创建特定类型的子类,请看下面这个例子:

example2:
#!/usr/bin/env python
# encoding: utf-8

from oslo_config import cfg
from oslo_config import types

DEFAULT_EXTENSIONS = [
    'nova.api.openstack.compute.contrib.standard_extensions'
]

# cfg.MultiOpt的子类用来定义一个多值的选项,值的类型是str
osapi_compute_extension_opt = cfg.MultiStrOpt('osapi_compute_extension',default=DEFAULT_EXTENSIONS)

个人感觉这个和oslo_config.cfg.ListOpt功能差不多。具体细节咱就不多说了,继续往下看吧。

Registering Options

上文中定义了很多的选项,但是离真正使用还差一步,那就是注册,下面的例子演示了如何去注册选项和使用选项

example3:
#!/usr/bin/env python
# encoding: utf-8

from oslo_config import cfg
from oslo_config import types

PortType = types.Integer(1, 65535)
#定义一组选项
common_opts = [
    cfg.StrOpt('bind_host',
               default='0.0.0.0',
               help='IP address to listen on.'),
    cfg.Opt('bind_port',
            type=PortType,
            default=9292,
            help='Port number to listen on.')
]
#注册选项
def add_common_opts(conf):
        conf.register_opts(common_opts)
#使用选项
def get_bind_host(conf):
        return conf.bind_host

def get_bind_port(conf):
        return conf.bind_port

#创建配置类
cf = cfg.CONF
#开始注册
add_common_opts(cf)
print(get_bind_host(cf))

就是这么简单,看起来不错把,也没有想象中的那么复杂,毕竟只是一个配置类,搞的太复杂谁还用啊,功能再强大我也不会用的。

基于命令行配置选项

上面说了那么多,通过Opt类平配置了选项,设置选项的类型,默认值,然后通过CONF类来注册选项,最后通过CONF类使用注册的选项,读者有没有觉得很鸡肋这不就是定义一个变量,赋值然后使用嘛,这哪是配置选项啊,文章的开头说了,cfg Module是可以通过命令行来传递配置选项的值,还可以通过配置文件了来传递配置选项的值的,好吧我承认,上面说了那么多其实都是在讲基础,真正的还没开始呢,首先还是来分析下cfg Module如何通过命令行来配置选项。看下面这个例子:

example4:
#!/usr/bin/env python
# encoding: utf-8

import sys
from oslo_config import cfg
from oslo_config import types
cli_opts = [
    cfg.BoolOpt('verbose',
                short='v',
                default=False,
                help='Print more verbose output.'),
    cfg.BoolOpt('debug',
                short='d',
                default=False,
                help='Print debugging output.'),
]

def add_common_opts(conf):
        conf.register_cli_opts(cli_opts)

cf = cfg.CONF
add_common_opts(cf);
cf(sys.argv[1:])  #将命令行参数传递给CONF类,argv[0]是程序名,所以从1开始

if cf.debug:
    print("开启调试")
else:
    print("关闭调试")

完了,这个版本终于不是鸡肋了,可以通过命令行参数来改变verbos和debug两个选项的值,使用一下把,先help一把,输出如下:

usage: example4.py [-h] [--config-dir DIR] [--config-file PATH] [--debug]
                 [--nodebug] [--noverbose] [--verbose] [--version]

optional arguments:
  -h, --help show this help message and exit
  --config-dir DIR Path to a config directory to pull *.conf files from.
                      This file set is sorted, so as to provide a predictable parse order if individual options are over-ridden. The set is parsed after the file(s) specified via previous --config-file, arguments hence over-ridden options in the directory take precedence. --config-file PATH Path to a config file to use. Multiple config files can be specified, with values in later files taking precedence. The default files used are: None. --debug, -d Print debugging output. --nodebug The inverse of --debug --noverbose The inverse of --verbose --verbose, -v Print more verbose output. --version show program's version number and exit 

尼玛好多东西啊,其实只有倒数几行是我们定义的选项,这里不解释了,cfg Module帮我们做了很多设置,比如提供了–nodebug接下来看看怎么设置选项的值把,因为我这里是bool类型,所以直接使用选项–debug就是debug=True,–nodebug就是debug=False,如果什么参数也没有就是debug=False,简单吧。

基于配置文件配置选项

其实也很简单了,代码不变,依然example4部分的代码,相信有的读者已经猜到了,因为上面在执行–help的时候出现了–config-file和–config-dir两个命令行参数这两个的功能就是用来从配置文件载入配置选项的,前者指定一个配置文件,后者则指定一个目录下的所有配置文件。这里提供一个配置文件,通过配置文件来运行一下example4中代码:

example4.conf
[DEFAULT]
debug=True
verbose=False
通过下面的命令类载入配置
python example4.py --config-file=example4.conf

简单吧,但是我觉得还是有必要解释一下,DEFAULT是一个默认组,默认情况下Opt定义的选项都是属于这个组的,cfg Module给配置选项提供了组的概念,不同的组配置选项是可以重复的。那么让我们看看如何使用配置组吧。

Option Groups

先来一段代码,看看如何使用配置组

#!/usr/bin/env python
# encoding: utf-8
#定义了一个名为rabbit的组,记住组的名字也很重要,后面会用到
rabbit_group = cfg.OptGroup(name='rabbit',
                            title='RabbitMQ options')

#定义了两个选项,和上文中说到的定义选项没有任何区别
rabbit_host_opt = cfg.StrOpt('host',
                             default='localhost',
                             help='IP/hostname to listen on.'),
rabbit_port_opt = cfg.PortOpt('port',
                              default=5672,
                              help='Port number to listen on.')
def register_rabbit_opts(conf):
    #通过CONF类来注册了一个组,(CONF类啥都要先注册后使用,注册其实就是在CONF类内部做解析呢)
    conf.register_group(rabbit_group)
    # options can be registered under a group in either of these ways:
    #注册选项的时候通过指定组来把选项添加到特定的组中,指定组可以有如下两种方式,一种就是直接使用OptGroup实例的方式
    #另外一种就是使用配置组的名字这里是rabbit
    conf.register_opt(rabbit_host_opt, group=rabbit_group)
    conf.register_opt(rabbit_port_opt, group='rabbit')
#没提供group就是默认组DEFAULT

之前只有默认组的时候,在命令行使用–debug就会自动去DEFAULT组去找,那么现在添加了一个rabbit组,如果要找rabbit组中的host该怎么通过命令行来指定呢这也是很方便的直接通过前缀来判断例如–rabbit-host指的就是rabbit组中的host选项。配置文件句不多说了,定义一个[rabbit]就可以了,如何在代码中访问呢,也很简单,直接使用conf.rabbit.host就可以了。

Special Handling Instructions

说了这么多,是不是感觉cfg Module有点强大,我也这么觉得的,这个部分介绍下cfg Module关于选项提供的一些处理指令吧.

  • 设置必须要输入的选项值,如果用户没有提供就会抛出一个错误的异常
    通过在Opt类或者子类中添加required=True这个参数就可以实现了。

  • 设置选型值不计入日志文件中
    cfg Module提供了一个LOG类,可以用户输入的配置选项的值记录到日志文件中,但是对于一些敏感的配置选项值还是不要记录到日志中把。可以通过在Opt类或者子类中添加secret=True这个参数就可以实现了。

小结

cfg Module还有很多细节在本篇文章还未涉及到,但是本文的初衷只是因为作者我在分析OpenStack代码的时候因为对很多基础库不熟悉,导致分析的时候遇到了很多困难因此有了本文,希望本文带您入门,至少可以看懂OpenStack中惯关于配置选项的大部分代码,那么我觉得本文的目的就达到了。如要想知道更多关于oslo.config的知识请参考下面的链接。
oslo-config doc

你可能感兴趣的:(python,openstack,oslo-confi)