注意:新版本已经移除在主流程之前插入自定义扩展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代码居然还保存在他的博客服务器上,肯定是真爱粉)。
下面的源码部分是根据同事的实现截取的其中一部分,实现原理分析也是参考她整理的。
实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
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 [] |
1 2 3 4 5 6 7 8 9 10 11 |
[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。