oslo_config中的DuplicateOptError坑

前言:

最近在重写公司的Cinder Driver,我们driver是按照OpenStack的要求,依赖一个叫oslo_config的一个包。这个包的作用就是让driver申明所依赖的选项(可以来自文件,也可以来自命令行),oslo_config负责读取文件,并加载。

具体的使用可以参考:

http://www.giantflyingsaucer.com/blog/?p=4822

或者:

http://docs.openstack.org/developer/oslo.config/cfg.html

安装oslo_config:

sudo pip install oslo_config

问题:

重写是把新的代码放到与原来代码的文件和目录里面,所以在一段时间内是,两份代码都会在Cinder的目录里面。新的driver所有option是不变的,于是我把原来的代码拷贝过来,然后小改了下,注意这里的小改,后面会debug我一天的时间!!!

首先,重构前的代码是这样的:

 cfg.StrOpt('storage_vnx_pool_names',
deprecated_name='storage_vnx_pool_name',
help='Comma-separated list of storage pool names to be used.'),

改动的地方是把“to be used”去掉,其实保持不变,因为我觉得比较冗余...

改成了

 cfg.StrOpt('storage_vnx_pool_names',
deprecated_name='storage_vnx_pool_name',
help='Comma-separated list of storage pool names.'),

然后我的悲剧就开始了:

跑UT的时候 一直报:

oslo_config.cfg.DuplicateOptError: duplicate option: storage_vnx_pool_names

问题分析:

经过不断的分析,发现oslo_config是重写了 __eq__和__ne__来判断两个选项是否一样,如下:

# oslo_config/cfg.py

def _is_opt_registered(opts, opt):
"""Check whether an opt with the same name is already registered. The same opt may be registered multiple times, with only the first
registration having any effect. However, it is an error to attempt
to register a different opt with the same name. :param opts: the set of opts already registered
:param opt: the opt to be registered
:returns: True if the opt was previously registered, False otherwise
:raises: DuplicateOptError if a naming conflict is detected
"""
if opt.dest in opts:
if opts[opt.dest]['opt'] != opt:
raise DuplicateOptError(opt.name)
return True
else:
return False

红色就是抛出这个ERROR的地方

# oslo_config/cfg.py

class Opt(object):
...
  def __ne__(self, another):
return vars(self) != vars(another)
  def __eq__(self, another):
    return vars(self) == vars(another)

我写了一个测试(代码在github 上)vars是如何进行比较的,dump下的数据如下:

(Pdb) print vars(self)
{'deprecated_for_removal': False, 'short': None, 'name': 'enable', 'dest': 'enable', 'required': False, '_logged_deprecation': False, 'sample_default': None, 'deprecated_opts': [], 'positional': False, 'default': False, 'secret': False, 'deprecated_reason': None, 'mutable': False, 'type': Boolean, 'metavar': None, 'help': 'True enables, False disables'}
(Pdb) print vars(another)
{'deprecated_for_removal': False, 'short': None, 'name': 'enable', 'dest': 'enable', 'required': False, '_logged_deprecation': False, 'sample_default': None, 'deprecated_opts': [], 'positional': False, 'default': False, 'secret': False, 'deprecated_reason': None, 'mutable': False, 'type': Boolean, 'metavar': None, 'help': 'True enables, False disables.'}

注意红色的东西,下面的少了一个句号,于是会返回不相等. 我就是因为改了help里面的东西,所以oslo_config直接认为我在两个不同的option使用了同一个名字.

现在抛出这个错误的原因也很明确了,把两个地方的cfg.StrOpt改成完全一样的就可以了。

参考资料:

http://docs.openstack.org/developer/oslo.config/cfg.html

http://www.giantflyingsaucer.com/blog/?p=4822

上一篇:WITH RECOMPILE 和 OPTION(RECOMPILE) 使用上的区别


下一篇:记一次Java的内存泄露分析