自动化运维

脚本库

概述

脚本库:脚本库集中存储和管理自动化脚本文件。对云主机执行脚本,可以完成复杂的运维操作和自动化任务。

图 1所示:
图 1. 脚本库


功能优势

ZStack Cloud脚本库功能具有以下优势:
  • 简单易用
    • 支持以可视化方式快速创建脚本,并通过自定义参数实现脚本灵活配置。
    • 脚本内可以包含复杂命令,为云主机一键执行脚本,即可完成复杂的运维操作,例如:应用健康检查、平台电源负载均衡 (节能) 与调度、应用程序批量更新、灰度发布等,提高管理便利性,降低人工运维成本。
  • 便捷运维
    • 提供专门的脚本库页面,对脚本进行集中生命周期管理。用户可以在脚本库中灵活地创建、修改或删除脚本。
    • 创建好的脚本可以长期保存,重复使用;一个脚本可以同时在多台云主机执行、互不影响,有效提升大规模场景运维效率。
    • 提供丰富、详细的脚本执行记录,包括运行过该脚本的云主机、运行时间、结束时间、运行时配置和结果返回,便于操作回溯和问题定位。
  • 类型丰富:支持多种命令类型,包括:Shell、Python、Perl、Bat、Powershell,用户可根据实际需求,灵活选用。

创建脚本

ZStack Cloud主菜单,点击平台运维 > 自动化运维 > 脚本运维 > 脚本库。在脚本库界面,点击创建脚本,弹出创建脚本界面。

可参考以下示例输入相应内容:
  • 名称:输入脚本名称。命名规则:命名规则:长度限制1~128字符,输入内容只能包含中文汉字、英文字母、数字、空格和以下7种英文字符 - _ . ( ) : + 且不支持以空格开头或结尾
  • 简介:可选项,可留空不填
  • 平台类型:选择脚本适用的操作系统平台类型,目前支持两种类型:Linux、Windows。脚本只能在使用对应类型操作系统的云主机执行
  • 脚本类型:选择脚本命令类型
    • Linux支持以下命令类型:Shell、Python、Perl
    • Windows支持以下命令类型:Bat、Powershell
  • 脚本内容:输入脚本内容。如需传递自定义参数,请遵循Jinja2模板语法
    Note: ZStack Cloud将对脚本内容进行Base64编码,确保数据存储和传输安全。
  • 超时时间:设置脚本执行超时时间,默认为60秒,单位:秒、分钟、小时
  • 自定义参数:可选项,为脚本添加自定义参数,一个脚本最多可添加20个自定义参数,如需添加,请点击添加自定义参数,并设置以下内容:
    • 参数名:填写参数名,长度限制1~64字符
    • 参数值:填写参数值,长度限制1~64字符
    • 简介:填写参数简介
图 1所示:
图 1. 创建脚本


管理脚本

ZStack Cloud主菜单,点击平台运维 > 自动化运维 > 脚本运维 > 脚本库,进入脚本库界面。

脚本支持以下操作:
操作 描述
创建脚本 创建一个新的脚本。
编辑名称简介 修改脚本的名称、简介信息。
修改脚本 修改脚本内容、超时时间和自定义参数。
执行脚本 在指定云主机执行脚本。
Note:
  • 需确保云主机处于运行中状态、已安装最新版性能优化工具,且云主机操作系统与脚本平台类型相符。
  • 执行前,请确认脚本内容,并建议进行云主机备份,以防不当的脚本命令造成云主机故障或业务中断。
  • 如云主机已开启SELinux,请确认SELinux策略是否对本脚本中的命令产生影响,如是否限制脚本中的命令执行,或影响命令返回输出。
删除脚本 将脚本删除。

脚本详情

ZStack Cloud支持两个入口查看脚本执行记录:
  • 查看平台内所有脚本执行记录:在ZStack Cloud主菜单,点击平台运维 > 自动化运维 > 脚本运维 > 脚本库。在脚本库界面,点击执行记录标签,即可查看平台内所有脚本执行记录。
  • 查看单个脚本执行记录:在脚本库界面,点击需要查看的脚本名称,进入该脚本详情页。在脚本详情页,点击执行记录标签,即可查看该脚本的所有执行记录。
    Note: 如脚本已被删除,用户仍然可以在平台内所有脚本执行记录中查看其相关的执行记录。
图 1图 2所示:
图 1. 查看平台内所有脚本执行记录


图 2. 查看单个脚本执行记录


执行记录中的执行名称由系统根据脚本名称和执行时间自动生成。点击执行名称,可进入该条执行记录详情页,查看更多详细信息。每条执行记录详情页包含两个标签页:总览脚本信息
  • 总览包含执行记录的基本信息,包括:执行状态、执行记录UUID、脚本名称、操作员、开始时间、结束时间、云主机执行明细。
    • 如查看记录时,对应的脚本已被删除,则脚本名称栏将显示该脚本UUID。
    • ZStack Cloud支持同时在多台云主机上执行同一个脚本,如本次执行记录发生时,用户选择多台云主机同时执行脚本,则开始时间以第一台云主机开始执行脚本的时间为准、结束时间以最后一台云主机执行脚本结束时间为准。
    • 执行状态分为执行中、成功、失败、异常四种:
      • 执行中:本次执行记录中的全部或部分云主机正在执行脚本。
      • 成功:本次执行记录中的所有云主机均执行脚本成功。
      • 失败:本次执行记录中的所有云主机均执行脚本失败。
      • 异常:本次执行记录中的部分云主机执行脚本成功、部分云主机执行脚本失败。
    • 云主机执行明细列明本次执行该脚本的全部云主机信息,用户可点击查看详情,以云主机为粒度了解脚本执行情况,包括该云主机的脚本执行状态、执行开始时间、结束时间,和执行结果。
    图 3所示:
    图 3. 执行记录详情-总览


  • 脚本信息展示执行记录生成时,该脚本的详细配置信息,包括脚本内容、自定义参数和其他基本配置,便于用户进行操作回溯。
    Note: 执行记录中的脚本信息为执行时的脚本配置记录,可能和脚本最新配置不一致,仅供回溯参考。
    图 4所示:
    图 4. 执行记录详情-脚本信息


脚本执行记录

ZStack Cloud支持两个入口查看脚本执行记录:
  • 查看平台内所有脚本执行记录:在ZStack Cloud主菜单,点击平台运维 > 自动化运维 > 脚本运维 > 脚本库。在脚本库界面,点击执行记录标签,即可查看平台内所有脚本执行记录。
  • 查看单个脚本执行记录:在脚本库界面,点击需要查看的脚本名称,进入该脚本详情页。在脚本详情页,点击执行记录标签,即可查看该脚本的所有执行记录。
    Note: 如脚本已被删除,用户仍然可以在平台内所有脚本执行记录中查看其相关的执行记录。
图 1图 2所示:
图 1. 查看平台内所有脚本执行记录


图 2. 查看单个脚本执行记录


执行记录中的执行名称由系统根据脚本名称和执行时间自动生成。点击执行名称,可进入该条执行记录详情页,查看更多详细信息。每条执行记录详情页包含两个标签页:总览脚本信息
  • 总览包含执行记录的基本信息,包括:执行状态、执行记录UUID、脚本名称、操作员、开始时间、结束时间、云主机执行明细。
    • 如查看记录时,对应的脚本已被删除,则脚本名称栏将显示该脚本UUID。
    • ZStack Cloud支持同时在多台云主机上执行同一个脚本,如本次执行记录发生时,用户选择多台云主机同时执行脚本,则开始时间以第一台云主机开始执行脚本的时间为准、结束时间以最后一台云主机执行脚本结束时间为准。
    • 执行状态分为执行中、成功、失败、异常四种:
      • 执行中:本次执行记录中的全部或部分云主机正在执行脚本。
      • 成功:本次执行记录中的所有云主机均执行脚本成功。
      • 失败:本次执行记录中的所有云主机均执行脚本失败。
      • 异常:本次执行记录中的部分云主机执行脚本成功、部分云主机执行脚本失败。
    • 云主机执行明细列明本次执行该脚本的全部云主机信息,用户可点击查看详情,以云主机为粒度了解脚本执行情况,包括该云主机的脚本执行状态、执行开始时间、结束时间,和执行结果。
    图 3所示:
    图 3. 执行记录详情-总览


  • 脚本信息展示执行记录生成时,该脚本的详细配置信息,包括脚本内容、自定义参数和其他基本配置,便于用户进行操作回溯。
    Note: 执行记录中的脚本信息为执行时的脚本配置记录,可能和脚本最新配置不一致,仅供回溯参考。
    图 4所示:
    图 4. 执行记录详情-脚本信息


XML Hook

概述

XML Hook:一种脚本程序,用于在云主机XML文件中灵活插入或修改参数,从而实现定制化配置并扩展云主机功能。

图 1所示:
图 1. XML Hook


功能优势

ZStack Cloud XML Hook功能具有以下优势:
  • 灵活性
    • XML Hook以单独的脚本文件形式管理和维护,将临时或个性化配置需求与程序核心逻辑代码分离,云主机绑定/解绑XML Hook,即可实现配置动态调整和灵活扩展,无需手动修改代码。
    • XML Hook可长期保存、重复使用,一个XML Hook可同时绑定到多台云主机,有效提高大规模场景运维效率。
  • 可扩展性

    通过定义并使用XML Hook,用户可按实际需求灵活修改云主机XML参数,实现部分无法通过界面操作直接完成的配置,有效扩展云主机能力,满足个性化场景需求,例如:修改QEMU自定义参数、关闭vNIC TSO等。XML Hook为用户现场、第三方软硬件测试与应用提供了更便捷的适配途径。

注意事项

  • 使用XML Hook需熟悉云主机配置和XML编写规则,如XML Hook中包含语法错误或导致云主机配置错误,云主机将无法启动。
  • 如需对已绑定XML Hook的云主机需进行QEMU/Libvirt升级,请提前确认预期QEMU/Libvirt是否兼容该XML Hook,避免升级后因不兼容导致云主机启动/重启失败。

创建XML Hook

ZStack Cloud主菜单,点击平台运维 > 自动化运维 > 脚本运维 > XML Hook,进入XML Hook界面。点击创建XML Hook,弹出创建 XML Hook界面。

可参考以下示例输入相应内容:
  • 名称:设置XML Hook名称。命名规则:长度限制1~128字符,输入内容只能包含中文汉字、英文字母、数字、空格和以下7种英文字符 - _ . ( ) : + 且不支持以空格开头或结尾
  • 简介:可选项,可留空不填
  • 脚本内容:填写XML Hook内容,为确保脚本内容安全、合规,填写前可点击查看示例,详细编写方法可查看XML Hook编写方法
图 1所示:
图 1. 创建XML Hook


管理XML Hook

ZStack Cloud主菜单,点击平台运维 > 自动化运维 > 脚本运维 > XML Hook,进入XML Hook界面。

XML Hook支持以下操作:
操作 描述
创建XML Hook 创建一个新的XML Hook。
编辑名称简介 修改XML Hook的名称、简介信息。
修改XML Hook 修改XML Hook内容。
Note:
  • 如XML Hook已绑定云主机,请确保修改后的XML Hook内容安全、合规,避免因修改不当导致云主机操作系统不可用。
  • 如XML Hook已绑定云主机,修改后需重新启动云主机使修改生效。
绑定云主机 将XML Hook绑定到云主机,在云主机XML文件中插入或修改参数,实现定制化配置。
Note:
  • 仅支持为运行中或已停止状态的云主机绑定XML Hook。
  • 一台云主机仅支持绑定一个XML Hook,已绑定XML Hook的云主机不支持绑定其他XML Hook。
  • 绑定后,需重新启动云主机使XML Hook生效。
解绑云主机 将XML Hook从云主机解绑。
Note:
  • 仅支持为运行中、已停止或已删除状态的云主机解绑XML Hook。
  • 解绑XML Hook将导致云主机配置变化,相关配置将恢复绑定XML Hook前状态。
  • 解绑后,需重新启动云主机使设置生效。已删除的云主机无需重启。
删除XML Hook 将XML Hook删除。
Note: 已绑定云主机的XML Hook不支持删除。如需删除,请先从所有云主机解绑。

XML Hook编写方法

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

示例五:配置云主机CPU拓扑

  • 修改前XML
    <domain>
    	<cpu mode='custom' match='exact' check='full'>
    		<topology sockets='32' dies='1' cores='4' threads='1'/>
    	</cpu>
    </domain>
  • XML Hook
    def config_cpu_topology(root, sockets, dies, cores, threads, hook):
    
        for cpu in root.findall("cpu"):
            for topology in cpu.findall("topology"):
                hook.modify_value_of_attribute(topology, "sockets", str(sockets))
                hook.modify_value_of_attribute(topology, "dies", str(dies))
                hook.modify_value_of_attribute(topology, "cores", str(cores))
                hook.modify_value_of_attribute(topology, "threads", str(threads))
                
    config_cpu_topology(root, sockets=2, dies=1, cores=64, threads=1, hook=hook)
  • 通过XML Hook修改后的XML
    <domain>
    	<cpu mode='custom' match='exact' check='full'>
    		<topology sockets='2' dies='1' cores='64' threads='1'/>
    	</cpu>
    </domain>

示例六:修改云主机CPU特性

  • 修改前XML
    <domain>
        <cpu mode='custom' match='exact' check='full'>
        <feature policy='require' name='x2apic'/>
        <feature policy='require' name='hypervisor'/>
        <feature policy='require' name='lahf_lm'/>
        </cpu>
    </domain>
  • XML Hook
    def config_cpu_feature(root, hook):
        for cpu in root.findall("cpu"):
            feature = hook.create_element("feature")
            hook.add_attribute(feature, "policy", "disable")
            hook.add_attribute(feature, "name", "svm")
            hook.add_element_to_parent(feature, cpu)
    
    config_cpu_feature(root, hook)
  • 通过XML Hook修改后的XML
    <domain>
        <cpu mode='custom' match='exact' check='full'>
        <feature policy='require' name='x2apic'/>
        <feature policy='require' name='hypervisor'/>
        <feature policy='require' name='lahf_lm'/>
        <feature policy='disable' name='svm'/>
        </cpu>
    </domain>

示例七:配置云主机QEMU参数

  • 修改前XML
    <domain>
        <cpu mode='host-passthrough' check='none'>
          <topology sockets='2' cores='2' threads='1'/>
        </cpu>
        <qemu:commandline>
          <qemu:arg value='-qmp'/>
          <qemu:arg value='unix:/var/lib/libvirt/qemu/zstack/af45d04006114268a7ed0801fc46e961.sock,server,nowait'/>
        </qemu:commandline>
    </domain>
  • XML Hook
    def hide_cpu_emulator(root, hook):
        for cpu in root.findall("cpu"):
            for child in list(cpu):
                cpu.remove(child)
            cpu.set("mode", "host-passthrough")
            cpu.set("check", "none")
            feature = hook.create_element("feature")
            hook.add_attribute(feature, "policy", "disable")
            hook.add_attribute(feature, "name", "hypervisor")
            hook.add_element_to_parent(feature, cpu)
     
    def config_namespace(root, hook):
        import xml.etree.ElementTree as etree
        etree.register_namespace("zs", "http://zstack.org")
        etree.register_namespace("qemu", "http://libvirt.org/schemas/domain/qemu/1.0")
     
    def hide_hardware_vendor(root, hook):
        qemu_namespace = {'qemu': 'http://libvirt.org/schemas/domain/qemu/1.0'}
        for cmd in root.findall('qemu:commandline', qemu_namespace):
            # for CPU
            if not cmd.find("qemu:arg[@value='-cpu']", qemu_namespace):
                cpu_cfg = hook.create_element("qemu:arg")
                hook.add_attribute(cpu_cfg, "value", "-cpu")
                hook.add_element_to_parent(cpu_cfg, cmd)
    
            # for HOST KVM
            if not cmd.find("qemu:arg[@value='host,kvm=off']", qemu_namespace):
                host_kvm_cfg = hook.create_element("qemu:arg")
                hook.add_attribute(host_kvm_cfg, "value", "host,kvm=off")
                hook.add_element_to_parent(host_kvm_cfg, cmd)
    
            # for BIOS-VENDOR
            if not cmd.find("qemu:arg[@value='-smbios']", qemu_namespace):
                bios_cfg = hook.create_element("qemu:arg")
                hook.add_attribute(bios_cfg, "value", "-smbios")
                hook.add_element_to_parent(bios_cfg, cmd)
    
            # for VENDOR
            type0_value = "type=0,vendor=LENOVO,version=FBKTB4AUS,date=07/01/2015,release=1.180"
            xpath_type0 = "qemu:arg[@value='{}']".format(type0_value)
            if not cmd.find(xpath_type0, qemu_namespace):
                vendor_cfg = hook.create_element("qemu:arg")
                hook.add_attribute(vendor_cfg, "value", type0_value)
                hook.add_element_to_parent(vendor_cfg, cmd)
    
            # for BIOS-FACTORY
            smbios_args = cmd.findall("qemu:arg[@value='-smbios']", qemu_namespace)
            if len(smbios_args) < 2:
                bios_cfg_2 = hook.create_element("qemu:arg")
                hook.add_attribute(bios_cfg_2, "value", "-smbios")
                hook.add_element_to_parent(bios_cfg_2, cmd)
    
            # for FACTORY
            type1_value = "type=1,manufacturer=LENOVO,product=30AH001GPB,version=ThinkStation P300,serial=S4M88119,uuid=cecf333d-6603-e511-97d5-6c0b843f98ba,sku=LENOVO_MT_30AH,family=P3"
            xpath_type1 = "qemu:arg[@value='{}']".format(type1_value)
            if not cmd.find(xpath_type1, qemu_namespace):
                factory_cfg = hook.create_element("qemu:arg")
                hook.add_attribute(factory_cfg, "value", type1_value)
                hook.add_element_to_parent(factory_cfg, cmd)
    
    config_namespace(root, hook)
    hide_cpu_emulator(root, hook)
    hide_hardware_vendor(root, hook)
  • 通过XML Hook修改后的XML
    <domain>
        <cpu mode='host-passthrough' check='none'>
            <topology sockets='2' cores='2' threads='1'/>
            <feature name="hypervisor" policy="disable"/>
        </cpu>
        <qemu:commandline>
            <qemu:arg value="-qmp"/>
            <qemu:arg value="unix:/var/lib/libvirt/qemu/zstack/af45d04006114268a7ed0801fc46e961.sock,server,nowait"/>
            <qemu:arg value="-cpu"/>
            <qemu:arg value="host,kvm=off"/>
            <qemu:arg value="-smbios"/>
            <qemu:arg value="type=0,vendor=LENOVO,version=FBKTB4AUS,date=07/01/2015,release=1.180"/>
            <qemu:arg value='-smbios'/>
            <qemu:arg value="type=1,manufacturer=LENOVO,product=30AH001GPB,version=ThinkStation P300,serial=S4M88119,uuid=cecf333d-6603-e511-97d5-6c0b843f98ba,sku=LENOVO_MT_30AH,family=P3"/>
        </qemu:commandline>
    </domain>

定时任务

概述

ZStack Cloud提供两种定时运维服务:定时任务和定时器。定时器和定时任务完全解耦,用户可按需创建不同规则的定时器、以及不同的定时任务,并将定时任务灵活加载到定时器或从定时器上卸载。

定时运维相关定义

  • 定时任务:一种预设任务,在指定时间执行指定行为。与定时器配合使用。
    • 加载到定时器上的任务条目。
    • 支持选择性停用/启用/加载/卸载,可灵活处理生产环境中的特殊情况。
    • 删除定时器后,该定时器上的定时任务将被卸载,定时任务可重新加载到其它定时器上。
    • 定时任务的操作支持完整计入审计服务中。
  • 定时器:承载定时任务的容器,尤其适用于长时间运行的操作。
    • 承载定时任务的容器。
    • 非常适用于长时间运行的操作,例如,为某个云主机定时创建快照。
    • 删除定时器后,该定时器上的定时任务将被卸载,定时任务可重新加载到其它定时器上。
    • 定时器的操作支持完整计入审计服务中。

注意事项

在生产环境中,建议单块磁盘的快照数量尽量控制在5以内,快照过多会影响云主机/云盘的IO性能、数据安全以及主存储容量,不建议进行高频的定时快照备份。如需长期备份,请选择灾备相关功能。

创建定时任务

ZStack Cloud主菜单,点击平台运维 > 自动化运维 > 定时运维 > 定时任务,进入定时任务界面。点击创建定时任务,弹出创建定时任务界面。

可参考以下示例输入相应内容:
  • 名称:设置定时任务名称
  • 简介:可选项,可留空不填
  • 任务:选择任务类型。目前支持任务类型包括:启动云主机、停止云主机、重启云主机、创建云主机快照、创建云盘快照
    Note: 如创建停止云主机定时任务,请注意,云主机因为定时任务关机后,即使启用高可用功能,也不会自动重启。
  • 快照类型:选择任务类型为创建云主机快照时,需选择快照类型。支持创建单盘快照或快照组。单盘快照仅对云主机根云盘创建快照,快照组则对云主机根云盘及加载的数据云盘创建快照
    Note:
    • 定时任务创建的快照组不包含云主机内存快照
    • 创建快照组需确保云主机根云盘和数据云盘均在Ceph主存储上。定时任务创建完成后,如迁移云主机/数据云盘至非Ceph主存储,或为云主机加载非Ceph主存储上的数据云盘,定时任务将执行失败。
    • 不支持为加载共享云盘的云主机创建快照组。如在创建定时快照组任务后为云主机加载共享云盘,定时任务将执行失败。
  • 云主机/云盘:选择执行任务的云主机/云盘,可多选
    Note: 如选择的任务类型是创建云主机快照创建云盘快照,请注意:
    • 此处不支持选择已绑定CDP任务的云主机/云盘。
    • 此处不支持选择已有定时快照任务的云主机/云盘。
    • 如快照类型为快照组,且云主机加载的数据云盘已有定时快照任务,则此处不支持选择该云主机。
  • 保留快照数量:设置快照允许保留的最大数量
    Note:
    • 仅当云主机系统盘在Ceph主存储时支持设置,且保留数量不包括云主机系统盘手动快照。
    • 保留快照数量范围:1~32。
  • 定时器:可选项,加载合适的定时器到定时任务
图 1所示:
图 1. 创建定时任务


管理定时任务

ZStack Cloud主菜单,点击平台运维 > 自动化运维 > 定时运维 > 定时任务,进入定时任务界面。

定时任务支持以下操作:

操作 描述
创建定时任务 创建一个新的定时任务。
编辑定时任务 编辑定时任务的名称、简介信息。
启用定时任务 启用处于停用状态的定时任务。
Note: 启用定时任务,启动后该定时任务生效。
停用定时任务 停止选中的定时任务。
Note: 停用定时任务,停用后该定时任务不生效。
加载定时器 将定时任务加载到运行的定时器上。
卸载定时器 将定时任务从定时器上卸载。
删除定时任务 删除选中的定时任务。
Note: 删除该定时任务,不可恢复,请谨慎操作。

定时器

了解定时器

创建定时器

ZStack Cloud主菜单,点击 平台运维 > 自动化运维 > 定时运维 > 定时器。点击 创建定时器按钮,弹出创建定时器界面。

可参考以下示例设置相应内容:
  • 名称:设置定时器名称
  • 简介:可选项,可留空不填
  • 设置定时器执行方式有以下两种方式:
    • 执行方式:选择按周期执行
      • 执行策略:设置定时器执行周期
        Note: 需输入整数。时间单位:分钟/小时/天。
      • 开始时间:可按需更改,开始时间不能小于当前时间
    • 执行方式:选择按次执行
      Note: 对于周期内有限次执行的定时器,当定时任务执行完后,定时器状态将显示为已完成
      • 执行策略:设置定时器执行次数和时间
        Note: 需输入整数。时间单位:分钟/小时/天。
      • 开始时间:可按需更改,开始时间不能小于当前时间
图 1所示:
图 1. 创建定时器:按周期周期/按次执行




管理定时器

ZStack Cloud主菜单,点击平台运维 > 自动化运维 > 定时运维 > 定时器,进入定时器界面。

定时器支持以下操作:

操作 描述
创建定时器 创建一个新的定时器。
编辑定时器 编辑定时器的名称、简介信息。
修改定时器配置 修改定时器的执行方式、开始时间、执行策略。
删除定时器 删除选中的定时器。
Note: 删除定时器后,定时器上的定时任务将被卸载,定时任务可重新加载到其它运行的定时器上。