跳转到: 导航, 搜索

XMLTemplates


XMLTemplates

起草人: Vek

起草人邮箱: <<MailTo(kevin DOT mitchell AT rackspace DOT com)>>

状态: 待 POC 完成

目前,请求扩展需要反序列化数据,操作它,然后重新序列化它。这发生在每个扩展上。对于 JSON 数据来说,这通常不是什么问题,但 XML 的反序列化和重新序列化代价很高,并且目前不可能在不直接编辑序列化器或编写独立的序列化器的情况下扩展 XML。

本提案是建立一个新的中间件来执行 XML 序列化,并建立创建 XML 模板的机制,可以通过附加从属模板来描述扩展可能希望包含的额外数据。

这部分代码的大部分已经编写完成,并且 nova-api 的许多元素已经转换为使用基于模板的序列化器,而不是目前使用的手工编码的序列化器。本页旨在记录已经完成的工作。

延迟序列化

规范的第一部分也是最简单的一部分是延迟序列化。基本上,这涉及到创建 LazySerializationMiddleware,并将其添加到 openstackapi 管道中,以及对 nova.api.openstack.wsgi 进行一些修改——具体来说,Response 被修改为跟踪一个 lazy_serialization 属性(默认为 True),并且 ResponseSerializer 的 serialize_body() 方法被修改为将实际的序列化器和操作(如果可用,则包括模板)存储到请求中,如果 lazy_serialization 为 True。数据本身被序列化为 JSON 对象,以便通过 webob 管道传递(webob 被设计为传递文本响应体,并且扩展它以允许在组件之间传递原始对象将是困难的)。

扩展

请求扩展也略有修改;循环调用特定请求的所有处理程序会反序列化主体,并将其作为第三个参数传递给所有处理程序。处理程序可以就地修改主体,并且还可以修改 WSGI 环境中的模板(如果存在;对于请求编码为 JSON 格式的数据,WSGI 环境中将不存在模板)。

XML 模板

该提案最复杂的部分是引入 XML 模板。XML 模板可以使用 lxml 的 ElementTree 接口构建 XML 树的方式构建;存在一个 TemplateElement 类和一个 SubTemplateElement() 辅助函数,它们以类似于 ElementTree 的方式运行。关键的区别在于使用选择器;当对象针对 XML 模板进行序列化时,对象会被传入,并且使用选择器(基本上是一个简单的可调用对象)来选择要操作的数据。每个元素都关联一个选择器,并且选择器也可以作为属性值和作为元素的文本内容附加;这些选择器进一步细化元素的选择器。子元素也会收到其父元素选择的对象,并有机会进一步细化自己的选择。

一旦构建了元素树,就可以将其包装在 Template 子类中。有两个可用的子类——MasterTemplate 和 SlaveTemplate。两者都可以直接针对模板序列化对象,但 MasterTemplate 实例可以附加 SlaveTemplate 实例,从而进一步扩展序列化;效果就像 SlaveTemplate 实例中的元素与 MasterTemplate 中的元素合并一样。此外,MasterTemplate 实例具有版本号,并自动排除不适用于该 MasterTemplate 版本的 SlaveTemplate 实例(SlaveTemplate 实例具有最低版本和可选的最大版本,用于此选择标准)。这使得扩展能够轻松修改序列化器以包含其扩展数据。

现有代码还包括一个 TemplateBuilder 类,可用于确保给定模板只需要构建一次;以及一个 XMLTemplateSerializer,类似于现有的 XMLDictSerializer。

WSGI 环境

延迟序列化可能会向 WSGI 环境添加 3 个新变量。(请注意“可能”——对于 JSON 序列化,这些变量都不会添加。)nova.serializer 变量包含对要使用的主体序列化器的引用(通常是 XMLDictSerializer 的子类,或者最好是 XMLTemplateSerializer 的子类),而 nova.action 变量包含要传递给序列化器的 serialize() 方法的操作。如果序列化器具有 get_template() 方法,则该方法的返回值将被分配给 nova.template 变量;扩展可以将它们的从属模板附加到此主模板,如果需要的话。


蓝图: https://blueprints.launchpad.net/nova/+spec/xml-templates