nova extension api原理与实现




注意:新版本已经移除在主流程之前插入自定义扩展api的功能,但在主流程之后加扩展继续保留,参考:https://review.openstack.org/#/c/332436/(remove support for legacy v2 generator extensions),去掉的原因在nova.api.openstack.wsgi.Resource#pre_process_extensions方法上面的注释里有写,说是nova里面已经没有api在用这个功能了,但我还要用啊:<。后面要升级版本的话,在主流程之前做操作只能采用在源码上添加装饰器的方式了,虽然恶心了点,但至少不用在主流程里面插入代码。下面是正题:


这几天要重构一个功能,系统盘的配额管理,之前是在web后端实现的,没有写在nova里,主要是为了减少对社区代码的侵入,对OpenStack原版无代码侵入是我当前实现产品功能的首要条件,目前看来基本算是实现了的,当前我们VisionStack产品开发的这么多功能,只有在线扩容云主机的代码还在nova里面,这个后续也考虑移出来(除了设置maxcpu和maxmemory这两个xml参数的代码目前没想到好办法移出来,其他操作代码都考虑移走)。

这次的系统盘配额功能,需要改到nova代码里,否则用命令行创建、删除云主机,配额就不准了。

即使是要加代码到nova,也要尽量做到不改动主流程,做到插件化。幸好nova支持扩展api,nova show接口返回keypairs等额外信息就是通过这种方式实现的,而我们要做到在API主流程之前执行配额检查流程(只检查不保存usage,usage直接统计instances表,符合官方新版本的配额管理逻辑,配额管理功能介绍可参考之前的这篇文章,还有这篇)。

老版本的扩展api很好实现,新版本更简单,并且改动也很小,只不过之前一直没搞清楚实现的原理,这次同事在开发的时候,顺便让她研究了下原理,当然还是靠田田专家指点的入口在哪(虽然田田专家已经跳出云计算OpenStack的坑了,但H版本的OpenStack代码居然还保存在他的博客服务器上,肯定是真爱粉)。

下面的源码部分是根据同事的实现截取的其中一部分,实现原理分析也是参考她整理的。

实现

class ExtendedDiskQuotaController(wsgi.Controller):
    @wsgi.extends
    def create(self, req, body):
        context = req.environ['nova.context']
        if authorize(context):
            ## 在nova主流程之前干你想干的事情
        yield

    @wsgi.extends(action='resize')
    def _action_resize(self, req, id, body):
        context = req.environ['nova.context']
        if authorize(context):
            ### 在nova主流程之后干你想干的事情


class ExtendedDiskQuota(extensions.V21APIExtensionBase):
    """Extended System Disk Quota support for vscloud."""

    name = "ExtendedDiskQuota"
    alias = ALIAS
    version = 1

    def get_controller_extensions(self):
        controller = ExtendedDiskQuotaController()
        extension = extensions.ControllerExtension(self, 'servers', controller)
        return [extension]

    def get_resources(self):
        return []
[entry_points]
nova.api.v21.extensions =
    access_ips = nova.api.openstack.compute.access_ips:AccessIPs
    admin_actions = nova.api.openstack.compute.admin_actions:AdminActions
    ......
    extended_disk_quota = nova.api.openstack.compute.vscloud.extended_disk_quota:ExtendedDiskQuota

nova.api.v21.extensions.server.create =
    access_ips = nova.api.openstack.compute.access_ips:AccessIPs
    ......
    extended_disk_quota = nova.api.openstack.compute.vscloud.extended_disk_quota:ExtendedDiskQuota

 

原理

大概介绍下,反正已经被删掉了,代码位置在nova.api.openstack.wsgi.Resource#_process_stack,里面调用了nova.api.openstack.wsgi.Resource#pre_process_extensions,这个方法里会遍历所有包含generator的extension,并执行,之后才执行到主流程nova.api.openstack.wsgi.Resource#dispatch,最后执行nova.api.openstack.wsgi.Resource#post_process_extensions,主流程之后的extension。