如何在OpenStack Nova v2.1 API 中增加或变更一个API接口

本人接触OpenStack有小半年时间,有幸加入了国内最好的OpenStack社区开发团队之一,为了能跟上团队内各位大牛的步伐,也为了给自己学习过程中留下一些记录,方便日后查看,结合自己在工作和学习中的体会,准备在此写一写技术博客。水平有限,能力一般,请各位尽情拍砖,共勉。

本人目前主要贡献Nova项目,因此目前会以Nova为主。

Nova 的API已经正式切换到了V2.1版本。V2.1版本和之前的V2版本的不同点主要是:
1. 采用了JSON schema对输入参数的合法性和完整性进行校验;
2. 引入了Microversion的概念,即在每次对API做出对接口有影响的修改后,都要更新相应的Microversion版本。

目前,若想对API做出修改,首先需要提交对于想要修改的功能的完整说明文档(spec)。其中主要首先需要包括对于当前接口行为的描述,以及当前行为为什么不能满足使用要求,并给出相应的需求应用场景。接下来要详细描述所提出的修改方案的具体细节,除了要包括详细的逻辑实现外,最重要的就是对于当前API的影响了,其中就主要包括了要进行microversion的升级,以及添加相应的JSON schema。在这里需要完整的给出修改后的输入,输出的实例,以及相应的JSON schema检查的结构以及作用等。最后还需要指明需要修改或添加的测试用例都有哪些。

本文主要介绍与Microversion相关的内容,JSON schema在下次进行介绍。

Microversion:
Microversion 是Nova在Liberty版本引入的一个概念,其他模块也有效仿的意愿。
在当前版本中,修改或者新增一个API时,则需要指明其所对应的Microversion版本,在调用REST API的时候,通过在头中加入新的字段‘X-Openstack-Nova-API-Version’指定相应的Microversion 版本来访问特定的版本的API。

Microversion 格式采用 X.Y 的格式,其中 X 只有在发生大的导致API不能向前兼容的变动时才会变更,而 Y 则是这里所提到的 Microversion 当前已经更新到了2.13版本。
在使用 Microversion 的同时,还需要在 nova/api/openstack/api_version_request.py 中指定 min_version 以及 max_version,即当前所支持的最低版本以及最高版本,一般最低版本就是V2.1而最高版本就是刚刚修改过的版本,只有当发生了很大的改动导致不能向前兼容的时候才需要修改最低版本。

OpenStack对整个microversion所使用的新增加的头(Head)指定了命名规则,如果需要引入mircoversion,名称都采用如下格式:
X-OpenStack-[SERVICE_TYPE]-API-Version: 2.114
比如,keystone采用mircoversion后会加入如下的头:
X-OpenStack-Identity-API-Version: 2.114

由于Nova是OpenStack中一贯的先行者,其在标准出台前就已经发布了带有mircoversion的API版本,采用的头是X-Openstack-Nova-API-Version,为了保证前向兼容性,仍然会保持这样的命名方式。Ironic也是类似的情况。

在实际的使用过程中,当不包含此头的时候,API会默认指向最低版本。当此头存在且指定了某一个版本时,API会响应相对应的版本,当指定的版本不存在时,会返回HTTP 406错误并且返回当前所支持的最高和最低Microversion版本范围。当包含此头且使用关键字"latest"作为版本号时,则会指向当前的最大版本号。

同时,当使用了Microversion头时,返回值内容中也会相应的增加:
X-OpenStack-[SERVICE_TYPE]-API-Version: version_number - 表示当前执行了的microversion版本号;
X-Openstack-[SERVICE_TYPE]-API-Minimum-Version: min_version_number - 表示当前所能支持的最小版本号
X-Openstack-[SERVICE_TYPE]-API-Maximum-Version: max_version_number - 表示当前所能支持的最大版本号。

在spec被approve了之后,就进入到具体编码的环节了,在编码过程中除了对功能高质量的实现外,最重要的就是进行microversion的相关操作了,官方有相应的指导文档[1]。这里根据笔者实际的操作做一个最简单的总结:
首先当需要增加一个全新的方法时,最好采用装饰器的方法,如:
@wsgi.Controller.api_version("2.4")
def my_api_method(self, req, id):
    ....

这表示从2.4开始才会调用此方法, @wsgi.Controller.api_version("2.4") 装饰器就是对req对象中的api_version_request对象(传入的X-Openstack-Nova-API-Version)进行识别,从而区分不同的代码逻辑。

如果是对现有的代码逻辑做出一定的更改,则一般会采用如下的方法:
@wsgi.Controller.api_version("2.1", "2.3")
def my_api_method(self, req, id):
    .... method_1 ...

@wsgi.Controller.api_version("2.4")  # noqa
def my_api_method(self, req, id):
    .... method_2 ...

显而易见,当Microversion号在2.1到2.3之间时会调用method 1 而当版本号大于等于2.4时则会调用method 2。需要注意的是采用这种方法时需要在靠后的方法定义后面添加#noqa关键字,避免pep8错误。

当改动较小时,则可以只将相应的逻辑提出来做版本处理:
@api_version("2.1", "2.4")
def _version_specific_func(self, req, arg1):
    pass

@api_version(min_version="2.5")  # noqa
def _version_specific_func(self, req, arg1):
    pass

def show(self, req, id):
    .... common stuff ....
    self._version_specific_func(req, "foo")
    .... common stuff ....

当改动只有一到两行时,则建议采用直接在原逻辑中增加判断逻辑的方法:
def index(self, req):
    <common code>

    req_version = req.api_version_request
    if req_version.matches("2.1", "2.5"):
        ....stuff....
    elif req_version.matches("2.6", "2.10"):
        ....other stuff....
    elif req_version > api_version_request.APIVersionRequest("2.10"):
        ....more stuff.....

    <common code>

在实现完功能后,需要添加合适的测试用例,才能算是patch完成。由于我们修改的是API接口,会对functional test造成一定的影响,因此除了修改UT也要记得修改functional test。一般,对functional test 的修改是为新增加的版本增加相应的API输入输出示例文件,并将其放入相应的位置。
对于UT,则主要是在测试时,基于原有的测试类派生出一个新的测试类,并指出相对应的API版本,如wsgi_api_version = '2.12';在测试更改前后有影响的用例时,在这个新类中进行相应的复写。其余测试则直接调用父类中的测试即可。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值