Python SDK 指南

Red Hat Virtualization 4.4

使用 Red Hat Virtualization Python SDK

摘要

本指南描述了如何安装和使用 Red Hat Virtualization Python 软件开发工具包的版本 4。

第 1 章 概述

Python 软件开发套件的版本 4 是一组类,允许您在基于 Python 的项目中与 Red Hat Virtualization Manager 进行交互。通过下载这些课程并将其添加到项目中,您可以访问一系列功能,以实现高层次的管理任务自动化。

注意

SDK 的版本 3 不再被支持。如需更多信息,请参阅本指南的 RHV 4.3 版本

Python 3.7 和 async

在 Python 3.7 及更新的版本中 ,async 是一个保留关键字。您无法在之前支持它的服务方法中使用 async 参数,如下例所示,因为 async=True 将导致错误:

dc = dc_service.update(
    types.DataCenter(
        description='Updated description',
    ),
    async=True,
)

解决方法是在 参数中添加下划线(async_)

dc = dc_service.update(
    types.DataCenter(
        description='Updated description',
    ),
    async_=True,
)
注意

这个限制只适用于 Python 3.7 及之后的版本。Python 的早期版本不需要进行这个修改。

1.1. 先决条件

要安装 Python 软件开发套件,您必须有:

  • 安装 Red Hat Enterprise Linux 8 的系统。支持 Server 和 Workstation 变体。
  • Red Hat Virtualization 权利订阅。
重要

软件开发套件是 Red Hat Virtualization REST API 的接口。使用与 Red Hat Virtualization 环境版本对应的软件开发套件的版本。例如,如果您使用 Red Hat Virtualization 4.3,请使用 V4 Python 软件开发工具包。

1.2. 安装 Python 软件开发套件

安装 Python 软件开发工具包:

  1. 启用适合您的硬件平台的存储库。例如,对于 x86-64 硬件,启用:

    # subscription-manager repos \
        --enable=rhel-8-for-x86_64-baseos-rpms \
        --enable=rhel-8-for-x86_64-appstream-rpms \
        --enable=rhv-4.4-manager-for-rhel-8-x86_64-rpms
  2. 安装所需的软件包:

    # dnf install python3-ovirt-engine-sdk4

Python 软件开发工具包被安装到 Python 3 site-packages 目录中,随附的文档和示例安装到 /usr/share/doc/python3-ovirt-engine-sdk4

第 2 章 使用软件开发套件

这部分论述了如何将软件开发套件用于版本 4。

2.1. 软件包

以下模块最常被 Python SDK 使用:

ovirtsdk4

这是顶级模块。最重要的元素是 Connection 类,这是连接到服务器并获取对服务树根目录的引用的机制。

Error 类是基本的异常类,当需要报告错误时 SDK 将引发这个类。

对于某些类型的错误,有特定的错误类,它们扩展基本错误类:

  • AuthError - 身份验证或授权失败时原始化。
  • ConnectionError - 当服务器名称无法解析或服务器无法访问时,进行拍摄。
  • NotFoundError - 当请求的对象不存在时Red。
  • TimeoutError - 操作超时时原始。
ovirtsdk4.types

此模块包含实施 API 中使用的类型的类。例如,ovirt sdk4.types.Vm 类是虚拟机类型的实现。这些类是数据容器,不包含任何逻辑。

这些类的实例用作服务方法的参数和返回值。到底层表示的转换或从底层表示的转换由 SDK 透明地处理。

ovirtsdk4.services

此模块包含实施 API 所支持服务的类。例如,ovirtsdk4.services.VmsService 类是管理系统虚拟机集合的服务实施。

当服务位于时,SDK 会自动创建这些类的实例。例如,在执行以下操作时,SDK 会自动创建 VmsService 类的新实例:

vms_service = connection.system_service().vms_service()

最好避免手动创建这些类的实例,因为构造器的参数,一般而言,服务定位器和服务方法以外的所有方法将来可能会发生变化。

还有其它模块,如 ovirtsdk4.http、ovirtsdk4.readersovirtsdk4.writers。它们用于实施 HTTP 通信,以及用于 XML 解析和渲染。避免使用它们,因为它们是内部实施细节,将来可能会改变;无法保证向后兼容性。

2.2. 连接到服务器

要连接到服务器,请导入包含 Connection 类的 ovirtsdk4 模块。这是 SDK 的入口点,提供对 API 服务树根的访问:

import ovirtsdk4 as sdk

connection = sdk.Connection(
    url='https://engine.example.com/ovirt-engine/api',
    username='admin@internal',
    password='password',
    ca_file='ca.pem',
)

连接包含关键资源,包括与服务器的 HTTP 连接池和身份验证令牌。在这些资源不再使用时释放这些资源非常重要:

connection.close()

连接关闭后,就无法重复使用。

当连接到使用 TLS 保护的服务器时,需要 ca.pem 文件。在常规安装中,它位于 Manager 计算机上的 /etc/pki/ovirt-engine/ 中。如果没有指定 ca_file,将使用系统范围的 CA 证书存储。有关获取 ca.pem 文件的更多信息,请参阅 REST API 指南

如果连接不成功,SDK 将引发包含详细信息的 ovirtsdk4.Error 异常。

2.3. 使用类型

ovirtsdk4.types 模块中的类是纯数据容器。它们没有任何逻辑或操作。可以随意创建和修改类型实例。

创建或修改实例不会影响服务器端,除非通过调用来明确传递给下面描述的其中一种服务方法。服务器端的更改不会自动反映到内存中已存在的实例中。

这些类的结构器具有多个可选参数,每个参数对应一个类型的属性。这是为了简化对多个构造器使用嵌套调用的对象创建过程。本例创建一个虚拟机实例,以字节为单位指定其集群名称、模板和内存:

from ovirtsdk4 import types

vm = types.Vm(
    name='vm1',
    cluster=types.Cluster(
        name='Default'
    ),
    template=types.Template(
        name='mytemplate'
    ),
    memory=1073741824
)

建议以这种方式使用构造器,但不强制使用。您还可以在调用构造器时不使用任何参数创建实例,并使用集合器逐步填充对象,或者同时使用这两种方法:

vm = types.Vm()
vm.name = 'vm1'
vm.cluster = types.Cluster(name='Default')
vm.template = types.Template(name='mytemplate')
vm.memory=1073741824

在 API 规格中定义为对象列表的属性作为 Python 列表实施。例如,Vm 类型的 custom_properties 属性定义为 CustomProperty 类型的对象列表。当 SDK 中使用这些属性时,它们是 Python 列表:

vm = types.Vm(
    name='vm1',
    custom_properties=[
        types.CustomProperty(...),
        types.CustomProperty(...),
        ...
    ]
)

在 API 中定义为枚举值的属性在 Python 中以 举形式实施,使用对 Python 3 中的 enums 的原生支持和 Python 2.7 中的 enum34 软件包的原生支持。在本例中,Vm 类型的 status 属性使用 Vm Status enum 来定义:

if vm.status == types.VmStatus.DOWN:
    ...
elif vm.status == types.VmStatus.IMAGE_LOCKED:
    ....
注意

在 API 规格中,enum 类型的值以小写形式出现,因为这是用于 XML 和 JSON 的内容。但是,Python 约定是利用 枚举 值。

使用对应的属性读取类型实例的属性:

print("vm.name: %s" % vm.name)
print("vm.memory: %s" % vm.memory)
for custom_property in vm.custom_properties:
    ...

2.5. 查找服务

API 提供一组服务,各自与服务器 URL 空间内的路径关联。例如,管理系统虚拟机集合的服务位于 /vms 中,而管理标识符为 123 的虚拟机的服务 位于 /vms/123 中。

在 SDK 中,服务树的根由系统服务实施。它通过调用连接的 system_service 方法获得:

system_service = connection.system_service()

当您引用此系统服务时,您可以使用它获取对其他服务的引用,调用上一服务的 *_service 方法,称为服务定位器。例如,要获得对管理系统虚拟机集合的服务引用,您可以使用 vms_service 服务定位器:

vms_service = system_service.vms_service()

要获得对标识符为 123 的管理虚拟机的服务的引用 您可以使用管理虚拟机集合的服务 vm_service 服务定位器。它使用虚拟机的标识符作为参数:

vm_service = vms_service.vm_service('123')
重要

调用服务定位器不会向服务器发送请求。他们返回的 Python 对象是纯服务,不包含任何数据。例如,本例中调用的 vm_service Python 对象不是虚拟机的表示形式。它是用于检索、更新、删除、启动和停止该虚拟机的服务。

2.6. 使用服务

找到服务后,您可以调用其服务方法,它将请求发送到服务器并执行实际工作。

管理单个对象的服务通常支持 getupdateremove 方法。

管理对象集合的服务通常支持 列表添加 方法。

这两种服务(特别是管理单个对象的服务)都支持额外的操作方法。

2.6.1. 使用 get Methods

这些服务方法用于检索单个对象的表示法。以下示例使用标识符 123 检索虚拟机的表示形式:

# Find the service that manages the virtual machine:
vms_service = system_service.vms_service()
vm_service = vms_service.vm_service('123')

# Retrieve the representation of the virtual machine:
vm = vm_service.get()

响应是对应类型的实例,在本例中是一个 Python 类 ovirtsdk4.types.Vm 的实例。

某些服务的 get 方法支持额外的参数,这些参数控制如何检索对象表示法,或者如果存在多个表示,则检索哪些表示。例如,您可能希望在下次启动时检索虚拟机的当前状态或其状态,因为它们可能有所不同。管理虚拟机的服务的 get 方法支持 next_run 布尔值参数:

# Retrieve the representation of the virtual machine, not the
# current one, but the one that will be used after the next
# boot:
vm = vm_service.get(next_run=True)

详情请查看 SDK 的参考文档

如果因为某种原因无法检索对象,SDK 会引发 ovirtsdk4.Error 异常,其中包含失败的详情。这包括对象实际不存在的情况。请注意,调用 get service 方法时会出现异常。对服务定位器方法的调用永远不会失败,即使对象不存在,因为该调用不会向服务器发送请求。例如:

# Call the service that manages a non-existent virtual machine.
# This call will succeed.
vm_service = vms_service.vm_service('junk')

# Retrieve the virtual machine. This call will raise an exception.
vm = vm_service.get()

2.6.2. 使用 列表 方法

这些服务方法检索集合对象的表示法。本示例检索系统虚拟机的完整集合:

# Find the service that manages the collection of virtual
# machines:
vms_service = system_service.vms_service()

# List the virtual machines in the collection
vms = vms_service.list()

结果将是包含对应类型实例的 Python 列表。例如,在这种情况下,结果将是 ovirtsdk4.types.Vm 类的实例列表。

某些服务 的列表 方法支持附加参数。例如,几乎所有顶级集合都支持 搜索 参数来过滤结果或 max 参数,以限制服务器返回的结果数。本示例检索以 开头的虚拟机名称,上限为 10:

vms = vms_service.list(search='name=my*', max=10)
注意

并非所有 列表 方法都支持这些参数。某些 列表 方法支持其他参数。详情请查看 SDK 的参考文档

如果返回的结果列表因任何原因为空,返回的值将是一个空列表。它永远不会 是无

如果尝试检索结果时出错,SDK 将引发 ovirtsdk4.Error 异常,其中包含失败的详情。

2.6.3. 使用 添加 方法

这些服务方法为集合添加新元素。它们接收描述要添加的对象的相关类型实例,发送添加的请求,并返回描述添加对象类型的实例。

本例添加了一个名为 vm1 的新虚拟机:

from ovirtsdk4 import types

# Add the virtual machine:
vm = vms_service.add(
    vm=types.Vm(
        name='vm1',
        cluster=types.Cluster(
            name='Default'
        ),
        template=types.Template(
            name='mytemplate'
        )
    )
)

如果因为某种原因无法创建对象,SDK 将引发包含故障详情的 ovirtsdk4.Error 异常。它永远不会返回 None

重要

添加 方法返回的 Python 对象是相关类型的实例。这不是服务,而是数据容器。在这个特定示例中,返回的对象是 ovirtsdk4.types.Vm 类的实例。如果创建虚拟机后,您需要执行诸如检索或启动它等操作,首先需要找到管理虚拟机的服务,并调用相应的服务定位器:

# Add the virtual machine:
vm = vms_service.add(
  ...
)

# Find the service that manages the virtual machine:
vm_service = vms_service.vm_service(vm.id)

# Start the virtual machine
vm_service.start()

对象是异步创建的。创建新虚拟机时,添加 方法将返回响应,然后虚拟机完全创建并可供使用。最好轮询对象的状态,以确保对象已完全创建。对于虚拟机,您应该检查其状态,直到其状态为 DOWN:

# Add the virtual machine:
vm = vms_service.add(
  ...
)

# Find the service that manages the virtual machine:
vm_service = vms_service.vm_service(vm.id)

# Wait until the virtual machine is down, indicating that it is
# completely created:
while True:
    time.sleep(5)
    vm = vm_service.get()
    if vm.status == types.VmStatus.DOWN:
        break

使用循环通过 get 方法检索对象状态,确保 status 属性已更新。

2.6.4. 使用 更新 方法

这些服务方法更新现有的对象。它们接收描述要执行的更新的相关类型实例,发送更新请求以更新它,并返回描述更新的对象类型的实例。

本例将虚拟机的名称从 vm1 更新为 newvm

from ovirtsdk4 import types

# Find the virtual machine, and then the service that
# manages it:
vm = vms_service.list(search='name=vm1')[0]
vm_service = vm_service.vm_service(vm.id)

# Update the name:
updated_vm = vm_service.update(
    vm=types.Vm(
        name='newvm'
    )
)

执行更新时,避免发送对象的完整表示法。仅发送您要更新的属性。不要这样做:

# Retrieve the complete representation:
vm = vm_service.get()

# Update the representation, in memory, without sending a request
# to the server:
vm.name = 'newvm'

# Send the update. Do *not* do this.
vms_service.update(vm)

发送完整的表示会导致两个问题:

  • 您发送的信息比服务器需求多得多,从而浪费资源。
  • 服务器将尝试更新对象的所有属性,即使您不希望更改的那些属性。这可能会导致服务器端的错误。

某些服务 的更新 方法支持额外的参数,这些参数控制要更新的方式或内容。例如,您可能想要更新虚拟机的当前状态或下次启动虚拟机时要使用的状态。管理虚拟机的服务 更新 方法支持 next_run 布尔值参数:

# Update the memory of the virtual machine to 1 GiB,
# not during the current run, but after next boot:
vm = vm_service.update(
    vm=types.Vm(
        memory=1073741824
    ),
    next_run=True
)

如果因为任何原因而无法执行更新,SDK 将引发 ovirtsdk4.Error 异常,其中包含失败的详情。它永远不会返回 None

此更新方法返回的 Python 对象是相关类型的实例。这不是服务,而是用于数据的容器。在这个特定示例中,返回的对象将是 ovirtsdk4.types.Vm 类的实例。

2.6.5. 使用 删除 方法

这些服务方法移除现有的对象。它们通常不采用参数,因为它们是管理单一对象的服务方法。因此,服务已经知道要删除的对象。

本例使用标识符 123 删除虚拟机:

# Find the virtual machine by name:
vm = vms_service.list(search='name=123')[0]

# Find the service that manages the virtual machine using the ID:
vm_service = vms_service.vm_service(vm.id)

# Remove the virtual machine:
vm_service.remove()

删除某些服务 的方法支持额外的参数,这些参数控制要删除的方式或内容。例如,可以使用 detach_only 布尔值参数在保留磁盘的同时删除虚拟机:

# Remove the virtual machine while preserving the disks:
vm_service.remove(detach_only=True)

如果对象被成功移除,则 remove 方法会返回 None。它不会返回移除的对象。如果因为某种原因无法删除对象,SDK 会引发包含故障详情的 ovirtsdk4.Error 异常。

2.6.6. 使用其他操作方法

还有其他的服务方法可以执行其他操作,如停止和启动虚拟机:

# Start the virtual machine:
vm_service.start()

其中很多方法都包含用于修改操作的参数。例如,如果您想要使用 cloud- init 启动虚拟机,则启动虚拟机的方法支持 use_cloud_ init 参数:

# Start the virtual machine:
vm_service.start(cloud_init=True)

大多数操作方法在成功后返回 None,并在失败时引发 ovirtsdk4.Error。些操作方法返回值。例如,管理存储域的服务具有 is_attached 操作 方法,用于检查存储域是否已附加到数据中心并返回一个布尔值:

# Check if the storage domain is attached to a data center:
sds_service = system_service.storage_domains_service()
sd_service = sds_service.storage_domain_service('123')
if sd_service.is_attached():
    ...

检查 SDK 的参考文档,以查看各个服务支持的操作方法、它们采用的参数以及返回的值。

2.7. 其它资源

详情和示例请查看以下资源:

生成模块

您可以使用 pydoc 为以下模块生成文档:

  • ovirtsdk.api
  • ovirtsdk.infrastructure.brokers
  • ovirtsdk.infrastructure.errors

文档由 ovirt-engine-sdk-python 软件包提供。在 Manager 机器中运行以下命令查看这些文档的最新版本:

$ pydoc [MODULE]

第 3 章 Python 示例

3.1. 概述

本节演示了使用 Python SDK 在基本红帽虚拟化环境中创建虚拟机的步骤。

这些示例使用 ovirt- engine-sdk -python 软件包提供的 ovirtsdk Python 库。此软件包可用于 红帽订阅管理器中附加到红帽虚拟化 订阅池的系统。有关订阅您的系统以下载软件的更多信息,请参阅 第 1.2 节 “安装 Python 软件开发套件”

您还需要:

  • Red Hat Virtualization Manager 网络安装。
  • 网络和配置红帽虚拟化主机.
  • 包含用于在虚拟机上安装的操作系统的 ISO 镜像文件。
  • 工作理解构成红帽虚拟化环境的逻辑和物理对象。
  • 熟悉 Python 编程语言.

示例包括身份验证信息的占位符(用户名为admin@internal密码为 password)。将占位符替换为您环境的身份验证要求。

红帽虚拟化管理器 为每个 资源生成一个全局唯一标识符(GUID)。这些示例中的标识符代码与您 Red Hat Virtualization 环境中的标识符代码不同。

示例仅包含基本异常和错误处理逻辑。有关 SDK 特定异常的更多信息,请参阅 ovirtsdk.infrastructure.errors 模块的 pydoc:

$ pydoc ovirtsdk.infrastructure.errors

3.2. 连接到版本 4 中的 Red Hat Virtualization Manager

要连接到 Red Hat Virtualization Manager,您必须在脚本开始时导入类,从 ovirtsdk4.sdk 模块创建一个 Connection 类实例:

import ovirtsdk4 as sdk

Connection 类的构造器采用多个参数:支持的参数有:

url
包含 Manager 基本 URL 的字符串,如 https://server.example.com/ovirt-engine/api
username
指定要连接的用户名,如 admin@internal。此参数是必需的。
password
指定 username 参数提供的用户名的密码。此参数是必需的。
令牌
用于访问 API 的可选令牌,而不是用户名和密码。如果没有指定 令牌 参数,SDK 将自动创建一个。
insecure
指明是否应该检查服务器的 TLS 证书和主机名的布尔值标志。
ca_file
包含可信 CA 证书的 PEM 文件。服务器提供的证书将使用这些 CA 证书进行验证。如果没有设置 ca_file 参数,则会使用系统范围的 CA 证书存储。
debug

指示是否应生成调试输出的布尔值标志。如果值为 True,并且 log 参数不是 None,则发送至服务器的数据将写入日志中。

注意

用户名和密码写入调试日志,因此请谨慎处理。

压缩在 debug 模式中被禁用,这意味着调试消息以纯文本形式发送。

log
将在其中写入日志消息的日志记录器。
kerberos
指明是否应使用 Kerberos 身份验证而非默认基本身份验证的布尔值标志。
timeout
等待响应的最长时间(以秒为单位)。0 (默认)值表示永久等待。如果在收到响应前超时过期,则会引发异常。
compress
指明 SDK 是否应该要求服务器发送压缩的响应的布尔值标志。默认值为 True。这是服务器的提示,即使此参数设为 True,也会返回未压缩的数据。压缩在 debug 模式中被禁用,这意味着调试消息以纯文本形式发送。
sso_url
包含服务器基础 SSO URL 的字符串。如果提供 no sso_ url ,则默认 SSO URL 将从 URL 计算。
sso_revoke_url
包含 SSO 基础 URL 的字符串撤销服务。这只需要在使用外部身份验证服务时指定。默认情况下,从 url 参数的值自动计算此 URL,以便撤销 SSO 令牌将通过作为 Manager 一部分的 SSO 服务来执行。
sso_token_name
从 SSO 服务器返回的 JSON SSO 响应中的令牌名称。默认值为 access_token
标头
包含标头的字典,应随每个请求一起发送。
连接
对主机打开的最大连接数。如果值为 0 (默认),连接数将无限制。
pipeline
在不等待响应的情况下将请求放入 HTTP 管道的最大请求数。如果值为 0 (默认值),则禁用 pipelining。
import ovirtsdk4 as sdk

# Create a connection to the server:
connection = sdk.Connection(
    url='https://engine.example.com/ovirt-engine/api',
    username='admin@internal',
    password='password',
    ca_file='ca.pem',
)

connection.test()

print("Connected successfully!")

connection.close()

要获得支持的方法的完整列表,您可以在 Manager 机器上生成 ovirtsdk.api 模块的文档:

$ pydoc ovirtsdk.api

3.3. 列出数据中心

datacenters 集合包含环境中的所有数据中心。

例 3.1. 列出数据中心

本例列出了 数据中心 集合中的数据中心,并输出集合中每个数据中心的一些基本信息。

V4

import ovirtsdk4 as sdk
import ovirtsdk4.types as types

connection = sdk.Connection(
    url='https://engine.example.com/ovirt-engine/api',
    username='admin@internal',
    password='password',
    ca_file='ca.pem',
)

dcs_service = connection.system_service().dcs_service()

dcs = dcs_service.list()

for dc in dcs:
    print("%s (%s)" % (dc.name, dc.id))

connection.close()

在一个只存在 Default 数据中心且未激活的环境中,示例会输出文本:

Default (00000000-0000-0000-0000-000000000000)

3.4. 列出集群

集群 集合包含环境中的所有集群。

例 3.2. 列出集群

本例列出了集群集合中 的集群,并输出集合中有关每个集群的一些基本信息。

V4

import ovirtsdk4 as sdk
import ovirtsdk4.types as types

connection = sdk.Connection(
    url='https://engine.example.com/ovirt-engine/api',
    username='admin@internal',
    password='password',
    ca_file='ca.pem',
)

cls_service = connection.system_service().clusters_service()

cls = cls_service.list()

for cl in cls:
    print("%s (%s)" % (cl.name, cl.id))

connection.close()

在只有 Default 集群存在的环境中,示例输出文本:

Default (00000000-0000-0000-0000-000000000000)

3.5. 列出主机

主机集合 包含环境中的所有主机。

例 3.3. 列出主机

本例列出了 hosts 集合中的主机 及其 ID。

V4

import ovirtsdk4 as sdk
import ovirtsdk4.types as types

connection = sdk.Connection(
    url='https://engine.example.com/ovirt-engine/api',
    username='admin@internal',
    password='password',
    ca_file='ca.pem',
)

host_service = connection.system_service().hosts_service()

hosts = host_service.list()

for host in hosts:
    print("%s (%s)" % (host.name, host.id))

connection.close()

在一个只附加了一台主机 MyHost 的环境中,示例会输出以下文本:

MyHost (00000000-0000-0000-0000-000000000000)

3.6. 列出逻辑网络

网络 集合包含环境中的所有逻辑网络。

例 3.4. 列出逻辑网络

本示例列出了网络集合中的逻辑网络 ,并 输出集合中各个网络的一些基本信息。

V4

import ovirtsdk4 as sdk
import ovirtsdk4.types as types

connection = sdk.Connection(
    url='https://engine.example.com/ovirt-engine/api',
    username='admin@internal',
    password='password',
    ca_file='ca.pem',
)

nws_service = connection.system_service().networks_service()

nws = nws_service.list()

for nw in nws:
    print("%s (%s)" % (nw.name, nw.id))

connection.close()

在仅存在默认管理网络的环境中,示例输出文本:

ovirtmgmt (00000000-0000-0000-0000-000000000000)

3.7. 列出虚拟机和总磁盘大小

vms 集合包含一个 磁盘 集合,描述附加到虚拟机的每个磁盘的详细信息。

例 3.5. 列出虚拟机和磁盘总大小

本例以字节为单位输出虚拟机列表及其总磁盘大小:

V4

import ovirtsdk4 as sdk
import ovirtsdk4.types as types

connection = sdk.Connection(
    url='https://engine.example.com/ovirt-engine/api',
    username='admin@internal',
    password='password',
    ca_file='ca.pem',
)

vms_service = connection.system_service().vms_service()

virtual_machines = vms_service.list()

if len(virtual_machines) > 0:

    print("%-30s  %s" % ("Name", "Disk Size"))
    print("==================================================")

    for virtual_machine in virtual_machines:
        vm_service = vms_service.vm_service(virtual_machine.id)
        disk_attachments = vm_service.disk_attachments_service().list()
        disk_size = 0
        for disk_attachment in disk_attachments:
            disk = connection.follow_link(disk_attachment.disk)
            disk_size += disk.provisioned_size

            print("%-30s: %d" % (virtual_machine.name, disk_size))

输出虚拟机名称及其磁盘大小的示例:

Name                          Disk Size
==================================================
vm1                           50000000000

3.8. 创建 NFS 数据存储

首次创建红帽虚拟化环境时,需要至少定义一个数据存储域和 ISO 存储域。数据存储域存储虚拟磁盘,而 ISO 存储域存储虚拟客户机操作系统的安装媒体。

storagedomains 集合包含环境中的所有存储域,并可用于添加和删除存储域。

注意

本例中提供的代码假定远程 NFS 共享已预先配置为与 Red Hat Virtualization 搭配使用。有关准备 NFS 共享的更多信息,请参阅管理指南

例 3.6. 创建 NFS 数据存储

这个示例在 storagedomains 集合中添加了一个 NFS 数据域。

V4

对于 V4,添加 方法用于添加新存储域,类型 类用于传递以下参数:

  • 存储域的名称。
  • 从数据中心 集合 检索的数据中心对象。
  • 从主机集合检索 的主机 对象。
  • 正在添加的存储域的类型(数据iso导出)。
  • 要使用的存储格式(v1v2v3)。
import ovirtsdk4 as sdk
import ovirtsdk4.types as types

# Create the connection to the server:
connection = sdk.Connection(
    url='https://engine.example.com/ovirt-engine/api',
    username='admin@internal',
    password='password',
    ca_file='ca.pem',
)

# Get the reference to the storage domains service:
sds_service = connection.system_service().storage_domains_service()

# Create a new NFS storage domain:
sd = sds_service.add(
    types.StorageDomain(
        name='mydata',
        description='My data',
        type=types.StorageDomainType.DATA,
        host=types.Host(
            name='myhost',
        ),
        storage=types.HostStorage(
            type=types.StorageType.NFS,
            address='_FQDN_',
            path='/nfs/ovirt/path/to/mydata',
        ),
    ),
)

# Wait until the storage domain is unattached:
sd_service = sds_service.storage_domain_service(sd.id)
while True:
    time.sleep(5)
    sd = sd_service.get()
    if sd.status == types.StorageDomainStatus.UNATTACHED:
        break

print("Storage Domain '%s' added (%s)." % (sd.name(), sd.id()))

connection.close()

如果 add 方法调用成功,示例会输出文本:

Storage Domain 'mydata' added (00000000-0000-0000-0000-000000000000).

3.9. 创建 NFS ISO 存储

要创建虚拟机,您需要客户机操作系统的安装介质。安装介质存储在 ISO 存储域中。

注意

本例中提供的代码假定远程 NFS 共享已预先配置为与 Red Hat Virtualization 搭配使用。有关准备 NFS 共享的更多信息,请参阅管理指南

例 3.7. 创建 NFS ISO 存储

这个示例在 storagedomains 集合中添加了一个 NFS ISO 域。

V4

对于 V4,添加 方法用于添加新存储域,类型 类用于传递以下参数:

  • 存储域的名称。
  • 从数据中心 集合 检索的数据中心对象。
  • 从主机集合检索 的主机 对象。
  • 正在添加的存储域的类型(数据iso导出)。
  • 要使用的存储格式(v1v2v3)。
import ovirtsdk4 as sdk
import ovirtsdk4.types as types

connection = sdk.Connection(
    url='https://engine.example.com/ovirt-engine/api',
    username='admin@internal',
    password='password',
    ca_file='ca.pem',
)

# Get the reference to the storage domains service:
sds_service = connection.system_service().storage_domains_service()

# Use the "add" method to create a new NFS storage domain:
sd = sds_service.add(
    types.StorageDomain(
        name='myiso',
        description='My ISO',
        type=types.StorageDomainType.ISO,
        host=types.Host(
            name='myhost',
        ),
        storage=types.HostStorage(
            type=types.StorageType.NFS,
            address='FQDN',
            path='/nfs/ovirt/path/to/myiso',
        ),
    ),
)

# Wait until the storage domain is unattached:
sd_service = sds_service.storage_domain_service(sd.id)
while True:
    time.sleep(5)
    sd = sd_service.get()
    if sd.status == types.StorageDomainStatus.UNATTACHED:
        break

print("Storage Domain '%s' added (%s)." % (sd.name(), sd.id()))

# Close the connection to the server:
connection.close()

如果 add 方法调用成功,示例会输出文本:

Storage Domain 'myiso' added (00000000-0000-0000-0000-000000000000).

3.10. 将存储域附加到数据中心

向红帽虚拟化中添加存储域后,您必须将其附加到数据中心并将其激活,然后才能使用。

例 3.8. 将存储域附加到数据中心

这个示例将现有 NFS 存储域 mydata 附加到现有数据中心 Default。通过数据中心的 storagedomains 集合的 add 方法,可简化附加操作。这些示例可用于连接数据和 ISO 存储域。

V4

import ovirtsdk4 as sdk
import ovirtsdk4.types as types

# Create the connection to the server:
connection = sdk.Connection(
    url='https://engine.example.com/ovirt-engine/api',
    username='admin@internal',
    password='password',
    ca_file='ca.pem',
)

# Locate the service that manages the storage domains and use it to
# search for the storage domain:
sds_service = connection.system_service().storage_domains_service()
sd = sds_service.list(search='name=mydata')[0]

# Locate the service that manages the data centers and use it to
# search for the data center:
dcs_service = connection.system_service().data_centers_service()
dc = dcs_service.list(search='name=Default')[0]

# Locate the service that manages the data center where we want to
# attach the storage domain:
dc_service = dcs_service.data_center_service(dc.id)

# Locate the service that manages the storage domains that are attached
# to the data centers:
attached_sds_service = dc_service.storage_domains_service()

# Use the "add" method of service that manages the attached storage
# domains to attach it:
attached_sds_service.add(
    types.StorageDomain(
        id=sd.id,
    ),
)

# Wait until the storage domain is active:
attached_sd_service = attached_sds_service.storage_domain_service(sd.id)
while True:
    time.sleep(5)
    sd = attached_sd_service.get()
    if sd.status == types.StorageDomainStatus.ACTIVE:
        break

print("Attached data storage domain '%s' to data center '%s' (Status: %s)." %
  (sd.name(), dc.name(), sd.status.state()))

# Close the connection to the server:
connection.close()

如果对 add 方法的调用成功,示例会输出以下文本:

Attached data storage domain 'data1' to data center 'Default' (Status: maintenance).

状态:维护 表示仍然需要激活存储域。

3.11. 激活存储域

将存储域添加到红帽虚拟化并将其附加到数据中心后,您必须先将其激活,然后才能使用。

例 3.9. 激活存储域

这个示例激活了附加到数据中心 Default 的 NFS 存储域 mydata。通过 激活 存储域的方法可以简化 激活 操作。

V4

import ovirtsdk4 as sdk

connection = sdk.Connection
    url='https://engine.example.com/ovirt-engine/api',
    username='admin@internal',
    password='password',
    ca_file='ca.pem',
)

# Locate the service that manages the storage domains and use it to
# search for the storage domain:
sds_service = connection.system_service().storage_domains_service()
sd = sds_service.list(search='name=mydata')[0]

# Locate the service that manages the data centers and use it to
# search for the data center:
dcs_service = connection.system_service().data_centers_service()
dc = dcs_service.list(search='name=Default')[0]

# Locate the service that manages the data center where we want to
# attach the storage domain:
dc_service = dcs_service.data_center_service(dc.id)

# Locate the service that manages the storage domains that are attached
# to the data centers:
attached_sds_service = dc_service.storage_domains_service()

# Activate storage domain:
attached_sd_service = attached_sds_service.storage_domain_service(sd.id)
attached_sd_service.activate()

# Wait until the storage domain is active:
while True:
    time.sleep(5)
    sd = attached_sd_service.get()
    if sd.status == types.StorageDomainStatus.ACTIVE:
        break

print("Attached data storage domain '%s' to data center '%s' (Status: %s)." %
  (sd.name(), dc.name(), sd.status.state()))

# Close the connection to the server:
connection.close()

如果 激活 请求成功,示例会输出文本:

Activated storage domain 'mydata' in data center 'Default' (Status: active).

status:active 表示存储域已经激活。

3.12. 列出 ISO 存储域中的文件

storagedomains 集合包含一个 文件 集合,用于描述存储域中的文件。

例 3.10. 列出 ISO 存储域中的文件

这个示例输出每个 ISO 存储域中的 ISO 文件列表:

V4

import ovirtsdk4 as sdk
import ovirtsdk4.types as types

connection = sdk.Connection(
    url='https://engine.example.com/ovirt-engine/api',
    username='admin@internal',
    password='password',
    ca_file='ca.pem',
)

storage_domains_service = connection.system_service().storage_domains_service()

storage_domains = storage_domains_service.list()

for storage_domain in storage_domains:
    if(storage_domain.type == types.StorageDomainType.ISO):
        print(storage_domain.name + ":\n")
        files = storage_domain.files_service().list()

        for file in files:
            print("%s" % file.name + "\n")

connection.close()

示例输出文本:

ISO_storage_domain:
file1
file2

3.13. 创建虚拟机

在几个步骤中执行虚拟机创建。这里涵盖的第一步是创建虚拟机对象本身。

例 3.11. 创建虚拟机

本例创建了虚拟机 vm1,其要求如下:

  • 512 MB 内存,以字节为单位表示.
  • 附加到 Default 集群,因此附加 Default 数据中心。
  • 基于默认的 空白 模板。
  • 从虚拟硬盘引导.

V4

在 V4 中,这些选项使用 add 方法添加类型

import ovirtsdk4 as sdk
import ovirtsdk4.types as types

connection = sdk.Connection(
    url='https://engine.example.com/ovirt-engine/api',
    username='admin@internal',
    password='password',
    ca_file='ca.pem',
)

# Get the reference to the "vms" service:
vms_service = connection.system_service().vms_service()

# Use the "add" method to create a new virtual machine:
vms_service.add(
    types.Vm(
        name='vm1',
        memory = 512*1024*1024
        cluster=types.Cluster(
            name='Default',
        ),
        template=types.Template(
            name='Blank',
        ),
        os=types.OperatingSystem(boot=types.Boot(devices=[types.BootDevice.HD)]
    ),
)

print("Virtual machine '%s' added." % vm.name)

# Close the connection to the server:
connection.close()

如果 添加 请求成功,示例会输出文本:

Virtual machine 'vm1' added.

3.14. 创建虚拟 NIC

为确保新创建的虚拟机具有网络访问权限,您必须创建并附加虚拟 NIC。

例 3.12. 创建虚拟 NIC

本例创建一个 NIC nic1,并将它附加到虚拟机 vm1。本例中的 NIC 是 virtio 网络设备,并附加到 ovirtmgmt 管理网络。

V4

import ovirtsdk4 as sdk
import ovirtsdk4.types as types

connection = sdk.Connection(
    url='https://engine.example.com/ovirt-engine/api',
    username='admin@internal',
    password='password',
    ca_file='ca.pem',
)

# Locate the virtual machines service and use it to find the virtual
# machine:
vms_service = connection.system_service().vms_service()
vm = vms_service.list(search='name=vm1')[0]

# Locate the service that manages the network interface cards of the
# virtual machine:
nics_service = vms_service.vm_service(vm.id).nics_service()

# Locate the vnic profiles service and use it to find the ovirmgmt
# network's profile id:
profiles_service = connection.system_service().vnic_profiles_service()
profile_id = None
for profile in profiles_service.list():
    if profile.name == 'ovirtmgmt':
        profile_id = profile.id
        break

# Use the "add" method of the network interface cards service to add the
# new network interface card:

nic = nics_service.add(
    types.Nic(
        name='nic1',
        interface=types.NicInterface.VIRTIO,
        vnic_profile=types.VnicProfile(id=profile_id),
    ),
)

print("Network interface '%s' added to '%s'." % (nic.name, vm.name))

connection.close()

如果 添加 请求成功,示例会输出文本:

Network interface 'nic1' added to 'vm1'.

3.15. 创建虚拟机磁盘

为确保新创建的虚拟机有权访问持久性存储,您必须创建并附加磁盘。

例 3.13. 创建虚拟机磁盘

本例创建了一个 8 GB virtio 磁盘,并将它附加到虚拟机 vm1。磁盘有以下要求:

  • 存储在名为 data1 的存储域中.
  • 8 GB 大小.
  • 系统 类型磁盘(与 数据相反)。
  • VirtIO 存储设备.
  • COW 格式.
  • 标记为可用引导设备.

V4

import ovirtsdk4 as sdk
import ovirtsdk4.types as types

connection = sdk.Connection(
    url='https://engine.example.com/ovirt-engine/api',
    username='admin@internal',
    password='password',
    ca_file='ca.pem',
)

# Locate the virtual machines service and use it to find the virtual
# machine:
vms_service = connection.system_service().vms_service()
vm = vms_service.list(search='name=vm1')[0]

# Locate the service that manages the disk attachments of the virtual
# machine:
disk_attachments_service = vms_service.vm_service(vm.id).disk_attachments_service()

# Use the "add" method of the disk attachments service to add the disk.
# Note that the size of the disk, the `provisioned_size` attribute, is
# specified in bytes, so to create a disk of 10 GiB the value should
# be 10 * 2^30.
disk_attachment = disk_attachments_service.add(
    types.DiskAttachment(
        disk=types.Disk(
            format=types.DiskFormat.COW,
            provisioned_size=8*1024*1024,
            storage_domains=[
                types.StorageDomain(
                    name='data1',
                ),
            ],
        ),
        interface=types.DiskInterface.VIRTIO,
        bootable=True,
        active=True,
    ),
)

# Wait until the disk status is OK:
disks_service = connection.system_service().disks_service()
disk_service = disks_service.disk_service(disk_attachment.disk.id)
while True:
    time.sleep(5)
    disk = disk_service.get()
    if disk.status == types.DiskStatus.OK:
        break

print("Disk '%s' added to '%s'." % (disk.name(), vm.name()))

# Close the connection to the server:
connection.close()

如果 添加 请求成功,示例会输出文本:

Disk 'vm1_Disk1' added to 'vm1'.

3.16. 将 ISO 镜像附加到虚拟机

要在新创建的虚拟机上安装客户机操作系统,您必须附加包含操作系统安装介质的 ISO 文件。要找到 ISO 文件,请查看 第 3.12 节 “列出 ISO 存储域中的文件”

例 3.14. 将 ISO 镜像附加到虚拟机

本例使用虚拟机的 cdroms 集合的 add 方法将 my_iso_file.iso 附加到 vm1 虚拟机。

V4

import ovirtsdk4 as sdk
import ovirtsdk4.types as types

connection = sdk.Connection(
    url='https://engine.example.com/ovirt-engine/api',
    username='admin@internal',
    password='password',
    ca_file='ca.pem',
)

# Get the reference to the "vms" service:
vms_service = connection.system_service().vms_service()

# Find the virtual machine:
vm = vms_service.list(search='name=vm1')[0]

# Locate the service that manages the virtual machine:
vm_service = vms_service.vm_service(vm.id)

# Locate the service that manages the CDROM devices of the virtual machine:
cdroms_service = vm_service.cdroms_service()

# Get the first CDROM:
cdrom = cdroms_service.list()[0]

# Locate the service that manages the CDROM device found in previous step:
cdrom_service = cdroms_service.cdrom_service(cdrom.id)

# Change the CD of the VM to 'my_iso_file.iso'. By default the
# operation permanently changes the disk that is visible to the
# virtual machine after the next boot, but has no effect
# on the currently running virtual machine. If you want to change the
# disk that is visible to the current running virtual machine, change
# the `current` parameter's value to `True`.
cdrom_service.update(
    cdrom=types.Cdrom(
        file=types.File(
            id='my_iso_file.iso'
        ),
    ),
    current=False,
)

print("Attached CD to '%s'." % vm.name())

# Close the connection to the server:
connection.close()

如果 添加 请求成功,示例会输出文本:

Attached CD to 'vm1'.

例 3.15. 从虚拟机弹出 CDROM

本例从虚拟机的 cdrom 集合中弹出 ISO 镜像。

V4

import ovirtsdk4 as sdk
import ovirtsdk4.types as types

connection = sdk.Connection(
    url='https://engine.example.com/ovirt-engine/api',
    username='admin@internal',
    password='password',
    ca_file='ca.pem',
)

# Get the reference to the "vms" service:
vms_service = connection.system_service().vms_service()

# Find the virtual machine:
vm = vms_service.list(search='name=vm1')[0]

# Locate the service that manages the virtual machine:
vm_service = vms_service.vm_service(vm.id)

# Locate the service that manages the CDROM devices of the VM:
cdroms_service = vm_service.cdroms_service()

# Get the first found CDROM:
cdrom = cdroms_service.list()[0]

# Locate the service that manages the CDROM device found in previous step
# of the VM:
cdrom_service = cdroms_service.cdrom_service(cdrom.id)

cdrom_service.remove()

print("Removed CD from '%s'." % vm.name())

connection.close()

如果 删除 或删除 请求成功,示例会输出文本:

Removed CD from 'vm1'.

3.17. 分离磁盘

您可以从虚拟机分离磁盘。

分离磁盘

V4

import ovirtsdk4 as sdk
import ovirtsdk4.types as types

connection = sdk.Connection(
    url='https://engine.example.com/ovirt-engine/api',
    username='admin@internal',
    password='password',
    ca_file='ca.pem',
)

# Get the reference to the "vms" service:
vms_service = connection.system_service().vms_service()

# Find the virtual machine:
vm = vms_service.list(search='name=vm1')[0]

# Locate the service that manages the virtual machine:
vm_service = vms_service.vm_service(vm.id)

attachments_service = vm_service.disk_attachments_service()
attachment = next(
    (a for a in disk_attachments if a.disk.id == disk.id), None
)

# Remove the attachment. The default behavior is that the disk is detached
# from the virtual machine, but not deleted from the system. If you wish to
# delete the disk, change the detach_only parameter to "False".
attachment.remove(detach_only=True)

print("Detached disk %s successfully!" % attachment)

# Close the connection to the server:
connection.close()

如果 删除 或删除 请求成功,示例会输出文本:

Detached disk vm1_disk1 successfully!

3.18. 启动虚拟机

您可以启动虚拟机。

例 3.16. 启动虚拟机

本例使用 start 方法启动虚拟机。

V4

import time
import ovirtsdk4 as sdk
import ovirtsdk4.types as types

connection = sdk.Connection(
    url='https://engine.example.com/ovirt-engine/api',
    username='admin@internal',
    password='password',
    ca_file='ca.pem',
)

# Get the reference to the "vms" service:
vms_service = connection.system_service().vms_service()

# Find the virtual machine:
vm = vms_service.list(search='name=vm1')[0]

# Locate the service that manages the virtual machine, as that is where
# the action methods are defined:
vm_service = vms_service.vm_service(vm.id)

# Call the "start" method of the service to start it:
vm_service.start()

# Wait until the virtual machine is up:
while True:
    time.sleep(5)
    vm = vm_service.get()
    if vm.status == types.VmStatus.UP:
        break

print("Started '%s'." % vm.name())

# Close the connection to the server:
connection.close()

如果 启动 请求成功,示例会输出文本:

Started 'vm1'.

UP 状态表示虚拟机正在运行。

3.19. 使用覆盖参数启动虚拟机

您可以启动虚拟机,覆盖其默认参数。

例 3.17. 使用覆盖参数启动虚拟机

本例使用 Windows ISO 启动虚拟机,并附加包含 Windows 驱动程序 的 virtio-win_x86.vfd 软盘。此操作等同于使用管理门户中的 Run Once 窗口来启动虚拟机。

V4

import time
import ovirtsdk4 as sdk
import ovirtsdk4.types as types

connection = sdk.Connection(
    url='https://engine.example.com/ovirt-engine/api',
    username='admin@internal',
    password='password',
    ca_file='ca.pem',
)

# Get the reference to the "vms" service:
vms_service = connection.system_service().vms_service()

# Find the virtual machine:
vm = vms_service.list(search='name=vm1')[0]

# Locate the service that manages the virtual machine:
vm_service = vms_service.vm_service(vm.id)

# Locate the service that manages the CDROM devices of the virtual machine:
cdroms_service = vm_service.cdroms_service()

# Get the first CDROM:
cdrom = cdroms_service.list()[0]

# Locate the service that manages the CDROM device found in previous step:
cdrom_service = cdroms_service.cdrom_service(cdrom.id)

# Change the CD of the VM to 'windows_example.iso':
cdrom_service.update(
    cdrom=types.Cdrom(
        file=types.File(
            id='windows_example.iso'
        ),
    ),
    current=False,
)

# Call the "start" method of the service to start it:
vm_service.start(
    vm=types.Vm(
        os=types.OperatingSystem(
            boot=types.Boot(
                devices=[
                    types.BootDevice.CDROM,
                ]
            )
        ),
    )
)

# Wait until the virtual machine's status is "UP":
while True:
    time.sleep(5)
    vm = vm_service.get()
    if vm.status == types.VmStatus.UP:
        break

print("Started '%s'." % vm.name())

# Close the connection to the server:
connection.close()
注意

CD 映像和软盘文件必须可供虚拟机使用。详情请参阅将镜像上传到数据存储域

3.20. 使用 Cloud-Init 启动虚拟机

您可以使用 Cloud-Init 工具启动具有特定配置的虚拟机。

例 3.18. 使用 Cloud-Init 启动虚拟机

本例演示了如何使用 Cloud-Init 工具启动虚拟机,以设置 eth0 接口的主机名和静态 IP。

V4

import ovirtsdk4 as sdk
import ovirtsdk4.types as types

connection = sdk.Connection(
    url='https://engine.example.com/ovirt-engine/api',
    username='admin@internal',
    password='password',
    ca_file='ca.pem',
)

# Find the virtual machine:
vms_service = connection.system_service().vms_service()
vm = vms_service.list(search = 'name=vm1')[0]

# Find the service that manages the virtual machine:
vm_service = vms_service.vm_service(vm.id)

# Start the virtual machine enabling cloud-init and providing the
# password for the `root` user and the network configuration:
vm_service.start(
    use_cloud_init=True,
    vm=types.Vm(
        initialization=types.Initialization(
        user_name='root',
        root_password='password',
        host_name='MyHost.example.com',
        nic_configurations=[
            types.NicConfiguration(
                name='eth0',
                on_boot=True,
                boot_protocol=types.BootProtocol.STATIC,
                ip=types.Ip(
                    version=types.IpVersion.V4,
                    address='10.10.10.1',
                    netmask='255.255.255.0',
                    gateway='10.10.10.1'
                )
            )
        )
    )
)

# Close the connection to the server:
connection.close()

3.21. 检查系统事件

Red Hat Virtualization Manager 记录并记录多个系统事件。这些事件日志可通过用户界面、系统日志文件和 API 访问。ovirtsdk 库使用 events 集合公开事件。

例 3.19. 检查系统事件

本例中列出了 事件 集合。

list 方法 的查询 参数用于确保返回所有可用的结果页面。默认情况下,list 方法 仅返回第一页结果,即长度为 100 条记录。

返回的列表按相反的时间顺序排序,按照事件发生的顺序显示。

V4

import ovirtsdk4 as sdk
import ovirtsdk4.types as types

connection = sdk.Connection(
    url='https://engine.example.com/ovirt-engine/api',
    username='admin@internal',
    password='password',
    ca_file='ca.pem',
)

# Find the service that manages the collection of events:
events_service = connection.system_service().events_service()

page_number = 1
events = events_service.list(search='page %s' % page_number)
while events:
    for event in events:
        print(
            "%s %s CODE %s - %s" % (
                event.time,
                event.severity,
                event.code,
                event.description,
            )
        )
    page_number = page_number + 1
    events = events_service.list(search='page %s' % page_number)

# Close the connection to the server:
connection.close()

这些输出事件示例如下:

YYYY-MM-DD_T_HH:MM:SS NORMAL CODE 30 - User admin@internal logged in.
YYYY-MM-DD_T_HH:MM:SS NORMAL CODE 153 - VM vm1 was started by admin@internal (Host: MyHost).
YYYY-MM-DD_T_HH:MM:SS NORMAL CODE 30 - User admin@internal logged in.