本章介绍如何编写XML Hook内容并提供XML Hook示例。
XmlHook类方法释义
class XmlHook:
def get_value_of_element(self, xmlbranch):
""" 获取XML元素的文本内容 """
# Params:
xmlbranch: Element,表示XML元素对象
# Return: 字符串,表示元素的文本内容
return
def get_value_of_attribute(self, xmlbranch, attribute):
""" 获取XML元素的指定属性的值 """
# Params:
xmlbranch: Element,表示XML元素对象
attribute: 字符串,表示属性名称
# Return: 字符串,表示属性的值
return
def get_value_of_attribute_from_parent(self, parent_xmlbranch, element, attribute):
""" 从父元素中获取指定子元素的指定属性的值 """
# Params:
parent_xmlbranch: Element,表示父XML元素对象
element: 字符串,表示子元素标签名
attribute: 字符串,表示属性名称
# Return: 字符串,表示属性的值
return
def found_attribute(self, xmlbranch, attribute):
""" 检查XML元素是否包含指定的属性 """
# Params:
xmlbranch: Element,表示XML元素对象
attribute: 字符串,表示属性名称
# Return: 布尔值,表示属性是否存在
return
def modify_value_of_element(self, xmlbranch, value):
""" 修改XML元素的文本内容 """
# Params:
xmlbranch: Element,表示XML元素对象
value: 字符串,表示新的文本内容
# Return: 无
return
def add_value_of_element(self, xmlbranch, value):
""" 添加或修改XML元素的文本内容 """
# Params:
xmlbranch: Element,表示XML元素对象
value: 字符串,表示新的文本内容
# Return: 无
return
def set_value_of_attribute(self, xmlbranch, attribute, attribute_value):
""" 设置XML元素的指定属性的值(如不存在则创建)"""
# Params:
xmlbranch: Element,表示XML元素对象
attribute: 字符串,表示属性的名称
attribute_value: 字符串,表示属性的值
# Return: 无
return
def modify_value_of_attribute(self, xmlbranch, attribute, attribute_value):
""" 修改XML元素的指定属性的值(如不存在则不修改)"""
# Params:
xmlbranch: Element,表示XML元素对象
attribute: 字符串,表示属性名称
attribute_value: 字符串,表示属性的值
# Return: 无
def add_attribute(self, xmlbranch, attribute, attribute_value):
""" 添加XML元素的指定属性 """
# Params:
xmlbranch: Element,表示XML元素对象
attribute: 字符串,表示属性名称
attribute_value: 字符串,表示属性的值
# Return: 无
return
def delete_attribute(self, xmlbranch, attribute):
""" 删除XML元素的指定属性 """
# Params:
xmlbranch: Element,表示XML元素对象
attribute: 字符串,表示属性名称
# Return: 无
return
def get_index_of_element(self, root, element_key):
""" 获取指定元素在父元素中的索引 """
# Params:
root: Element,表示父元素对象
element_key: 字符串,表示元素的标签名
# Return: 整数,表示元素的索引,如果不存在则返回 - 1
return
def found_element(self, root, element_key):
"""检查父元素中是否包含指定标签名的子元素 """
# Params:
root: Element,表示父元素对象
element_key: 字符串,表示元素的标签名
# Return: 布尔值,表示元素是否存在
return
def delete_element_from_parent(self, child_xmlbranch, parent_xmlbranch):
""" 从父元素中删除指定的子元素 """
# Params:
child_xmlbranch: Element,表示子元素对象
parent_xmlbranch: Element, 表示父元素对象
# Return: 无
return
def add_element_to_parent(self, child_xmlbranch, parent_xmlbranch, index=-1):
""" 将子元素添加到父元素中(可选指定索引位置)"""
# Params:
child_xmlbranch: Element,表示子元素对象
parent_xmlbranch: Element,表示父元素对象
index: 整数,表示插入的索引位置,默认为 - 1(追加到末尾)
# Return: 根元素对象
return
def get_changed_xmlstr(self, root_xmlbranch):
""" 获取修改后的XML字符串,并格式化输出 """
# Params:
root_xmlbranch: Element,表示根元素对象
# Return: 字符串,表示格式化后的XML字符串
return
def create_element(self, element_name):
""" 创建一个新的XML元素 """
# Params:
element_name: 字符串,表示元素的标签名
# Return: 新的XML元素对象
return
XML Hook示例
用户可根据需求编写对应的方法,并定义正确的函数参数。其中,每个函数必填root、hook参数:
- root:Element类型,表示根XML对象,一般指云主机的完整XML。
- hook:表示XmlHook类型对象。
以下示例将展示XML Hook内容以及云主机绑定XML Hook前后的XML配置变化。
示例一:配置GPU透传
- 修改前XML
<domain> <devices> <hostdev mode='subsystem' type='pci' managed='no'> <source> <address domain='0x0000' bus='0x00' slot='0x0a' function='0x0'/> </source> </hostdev> </devices> </domain> - XML
Hook
def config_gpu_passthrough(root, hook, gpu_uuid): for devices in root.findall("devices"): for hostdev in devices.findall("hostdev"): hostdev_type = hook.get_value_of_attribute(hostdev, "type") if hostdev_type == "pci": hook.modify_value_of_attribute(hostdev, "type", "mdev") hook.add_attribute(hostdev, "model", "vfio-pci") hook.add_attribute(hostdev, "display", "on") for source in hostdev.findall("source"): for address in source.findall("address"): hook.delete_element_from_parent(address, source) source_address = hook.create_element("address") hook.add_attribute(source_address, "uuid", gpu_uuid) hook.add_element_to_parent(source_address, source) config_gpu_passthrough(root, hook, "4162a71b-f41e-4b06-b9ee-c503114dff29") - 通过XML
Hook修改后的XML
<domain> <devices> <hostdev display="on" managed="no" mode="subsystem" model="vfio-pci" type="mdev"> <source> <address uuid="4162a71b-f41e-4b06-b9ee-c503114dff29"/> </source> </hostdev> </devices> </domain>
示例二:配置云主机CPU模式
- 修改前XML
<domain> <cpu mode='custom' match='exact' check='full'> <topology sockets='1' cores='1' threads='1'/> <feature policy='require' name='hypervisor'/> </cpu> </domain> - XML
Hook
def config_cpu_mode(root, cpu_mode, hook): for cpu in root.findall("cpu"): hook.modify_value_of_attribute(cpu, "mode", cpu_mode) config_cpu_mode(root, "host-model", hook) - 通过XML
Hook修改后的XML
<domain> <cpu mode='host-model' match='exact' check='full'> <topology sockets='1' cores='1' threads='1'/> <feature policy='require' name='hypervisor'/> </cpu> </domain>
示例三:为所有VirtIO类型的磁盘设置磁盘多队列
- 修改前XML
<domain> <devices> <disk type="file" device="disk"> <driver name='qemu' type='qcow2'/> <target bus="virtio" dev="vda"/> </disk> <disk type="file" device="cdrom"> <target bus="ide" dev="hdc"/> <driver name='qemu' type='raw'/> </disk> <disk type="file" device="disk"> <driver name='qemu' type='qcow2'/> <target bus="ide" dev="vdb"/> </disk> <disk type="file" device="disk"> <driver name='qemu' type='qcow2'/> <target bus="virtio" dev="vdc"/> </disk> </devices> </domain> - XML
Hook
def config_virtio_disk_queue_number(root, queue_number, hook): def config_disk_queue_number(disk): for driver in disk.findall("driver"): hook.set_value_of_attribute(driver, "queues", str(queue_number)) # find virtio_disks from all_disks for devices in root.findall("devices"): for disks in devices.findall("disk"): for target in disks.findall("target"): bus = hook.get_value_of_attribute(target, "bus") if bus == "virtio": config_disk_queue_number(disks) config_virtio_disk_queue_number(root, 4, hook) - 通过XML
Hook修改后的XML
<domain> <devices> <disk type="file" device="disk"> <driver name='qemu' type='qcow2' queues="4"/> <target bus="virtio" dev="vda"/> </disk> <disk type="file" device="cdrom"> <target bus="ide" dev="hdc"/> <driver name='qemu' type='raw'/> </disk> <disk type="file" device="disk"> <driver name='qemu' type='qcow2'/> <target bus="ide" dev="vdb"/> </disk> <disk type="file" device="disk"> <driver name='qemu' type='qcow2' queues="4"/> <target bus="virtio" dev="vdc"/> </disk> </devices> </domain>
示例四:根据MTU值配置MAC地址
- 修改前XML
<domain> <devices> <interface type='default'> <mac address='fa:af:36:ba:c2:00'/> <mtu size='1500'/> </interface> <interface type='bridge'> <mac address='fa:88:98:8e:73:01'/> <mtu size='8888'/> </interface> </devices> </domain> - XML
Hook
def config_mac_address_by_mtu(root, hook, mac_address, expect_mtu_number): def config_mac_address(interface): for mac in interface.findall("mac"): hook.modify_value_of_attribute(mac, "address", mac_address) # find network (interface) card with specific mtu for devices in root.findall("devices"): for interface in devices.findall("interface"): for mtu in interface.findall("mtu"): mtu_number = hook.get_value_of_attribute(mtu, "size") if mtu_number == str(expect_mtu_number): config_mac_address(interface) config_mac_address_by_mtu(root, hook, "23:1a:d0:4e:3b:1e", 8888) - 通过XML
Hook修改后的XML
<domain> <devices> <interface type='default'> <mac address='fa:af:36:ba:c2:00'/> <mtu size='1500'/> </interface> <interface type='bridge'> <mac address='23:1a:d0:4e:3b:1e'/> <mtu size='8888'/> </interface> </devices> </domain>