ZStack Logo

ZStack AIOS

XML Hook编写方法

完整平台用户手册,包含基础云平台能力与 AIOS 相关章节。

本章介绍如何编写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>