ComputeDriver.update_provider_tree

本文档详细介绍了开发人员在自己的虚拟驱动程序中实现此方法时,ComputeDriver 抽象方法 update_provider_tree 的细节。

背景

在转向使用 placement 进行调度和资源管理的过程中,虚拟驱动程序方法 get_available_resource 最初被 get_inventory 取代(现在已移除),从而驱动程序可以以 placement 能够理解的术语指定其库存。在 Queens 版本中,添加了一个 get_traits 驱动程序方法。但是 get_inventory 仅限于表达库存(不包括特性或聚合)。并且这两种方法都仅限于与计算节点对应的资源提供程序。

嵌套资源提供程序等发展需要虚拟驱动程序能够更深入地控制资源跟踪器代表计算节点在 placement 中配置的内容。这种需求由虚拟驱动程序方法 update_provider_tree 及其资源跟踪器使用来满足,从而可以完全控制计算节点及其相关提供程序的 placement 表示形式。

该方法

update_provider_tree 接受以下参数

  • 一个 nova.compute.provider_tree.ProviderTree 对象,代表与计算节点关联的树中的所有提供程序,以及任何共享提供程序(那些具有 MISC_SHARES_VIA_AGGREGATE 特性的提供程序)通过聚合与这些提供程序中的任何一个关联(但不包括它们的树或聚合关联的提供程序),如 placement 当前所知。此对象完全由 update_provider_tree 方法拥有,因此可以在无需锁定/并发考虑的情况下对其进行修改。换句话说,参数是按引用传递的,并且期望虚拟驱动程序修改该对象。但是,请注意,它可能包含不由计算主机直接拥有/控制的提供程序。必须小心不要意外删除或修改此类提供程序。此外,提供程序可能与外部代理维护的特性和/或聚合相关联。update_provider_tree 方法因此也必须小心仅添加/删除它明确控制的特性/聚合。

  • 字符串,表示计算节点(即 ComputeNode.hypervisor_hostname)的名称,调用者正在请求更新的提供程序信息。驱动程序可以使用此信息来帮助识别 ProviderTree 中的计算节点提供程序。管理多个节点的驱动程序(例如 ironic)也可以将其用作指示调用者正在处理哪个节点的线索。

  • 字典,包含 allocations 数据,格式如下

    { $CONSUMER_UUID: {
          # The shape of each "allocations" dict below is identical
          # to the return from GET /allocations/{consumer_uuid}
          "allocations": {
              $RP_UUID: {
                  "generation": $RP_GEN,
                  "resources": {
                      $RESOURCE_CLASS: $AMOUNT,
                      ...
                  },
              },
              ...
          },
          "project_id": $PROJ_ID,
          "user_id": $USER_ID,
          "consumer_generation": $CONSUMER_GEN,
      },
      ...
    }
    

    如果 None,并且该方法确定需要移动任何库存(从一个提供程序到另一个提供程序和/或到不同的资源类),则必须引发 ReshapeNeeded 异常。否则,必须就地编辑此字典以指示分配的期望最终状态。驱动程序应编辑受重塑操作影响的提供程序的分配记录。有关重塑操作的更多信息,请参阅 规范

预期虚拟驱动程序使用当前资源提供程序和库存信息更新 ProviderTree 对象。当该方法返回时,ProviderTree 应代表与此计算节点关联的嵌套资源提供程序的正确层次结构,以及与这些资源提供程序关联的库存、聚合和特性。

注意

尽管名称如此,ProviderTree 实例实际上可能包含多个树。就此规范而言,传递给 update_provider_tree 的 ProviderTree 将包含

  • 与计算节点关联的整个树;以及

  • 任何共享提供程序(那些具有 MISC_SHARES_VIA_AGGREGATE 特性的提供程序),这些提供程序通过聚合与计算节点树中的任何提供程序关联。共享提供程序将作为 ProviderTree 中的独立根呈现,即使它们恰好是某个树的一部分。

考虑下面的例子。SSP 是一个共享存储提供程序,BW1BW2 是共享带宽提供程序;所有三个都具有 MISC_SHARES_VIA_AGGREGATE 特性

         CN1                 SHR_ROOT               CN2
        /   \       agg1    /   /\     agg1        /   \
   NUMA1     NUMA2--------SSP--/--\-----------NUMA1     NUMA2
  /     \   /    \            /    \         /     \   /    \
PF1    PF2 PF3   PF4--------BW1   BW2------PF1    PF2 PF3   PF4
                     agg2             agg3

当为 CN1 调用 update_provider_tree 时,传递给它的是一个包含

         CN1 (root)
        /   \       agg1
   NUMA1     NUMA2-------SSP (root)
  /     \   /    \
PF1    PF2 PF3   PF4------BW1 (root)
                     agg2

update_provider_tree 进行驱动程序实现预计将使用公共 ProviderTree 方法来对传递的提供程序树进行更改。可能有用的一些方法如下

  • new_root:将新的根提供程序添加到树中。

  • new_child:在现有提供程序下添加新的子项。

  • data:访问树中提供程序的信息(名称、UUID、父项、库存、特性、聚合)。

  • remove:从树中删除提供程序及其后代。在多所有权场景中使用时要小心。

  • update_inventory:设置提供程序的库存。

  • add_traitsremove_traits:设置/取消设置提供程序的虚拟拥有的特性。

  • add_aggregatesremove_aggregates:设置/取消设置提供程序的虚拟拥有的聚合关联。

注意

没有受支持的机制来让 update_provider_tree 影响分配。这是故意的:在 Nova 中,分配完全由虚拟之外的管理。 (通常由调度器管理;有时 - 例如对于迁移 - 由 conductor 管理。)

从 get_inventory 移植

希望从 get_inventory 迁移到 update_provider_tree 的虚拟驱动程序开发人员应使用 ProviderTree.update_inventory 方法,将计算节点指定为提供程序,并指定与 get_inventory 返回的库存相同。例如

def get_inventory(self, nodename):
    inv_data = {
        'VCPU': { ... },
        'MEMORY_MB': { ... },
        'DISK_GB': { ... },
    }
    return inv_data

将变为

def update_provider_tree(self, provider_tree, nodename, allocations=None):
    inv_data = {
        'VCPU': { ... },
        'MEMORY_MB': { ... },
        'DISK_GB': { ... },
    }
    provider_tree.update_inventory(nodename, inv_data)

在报告标准资源类 VCPUMEMORY_MBDISK_GB 的库存时,update_provider_tree 的实现者可能需要在 inv_data 字典中设置 allocation_ratioreserved 值,基于配置以反映计算上的更改,将分配比例和保留资源量传回 placement 服务。

从 get_traits 移植

要替换 get_traits,开发人员应使用 ProviderTree.add_traits 方法,将计算节点指定为提供程序,并指定与 get_traits 返回的特性相同。例如

def get_traits(self, nodename):
    traits = ['HW_CPU_X86_AVX', 'HW_CPU_X86_AVX2', 'CUSTOM_GOLD']
    return traits

将变为

def update_provider_tree(self, provider_tree, nodename, allocations=None):
    provider_tree.add_traits(
        nodename, 'HW_CPU_X86_AVX', 'HW_CPU_X86_AVX2', 'CUSTOM_GOLD')

特性和能力分类

有各种类型的特性

  • 有些是标准的(在 os-traits 中注册的);其他是自定义的。

  • 有些由计算服务拥有;其他可以由运营商管理。

  • 有些来自驱动程序支持的能力,通过一种 引入 的机制将它们转换为计算节点资源提供程序上的标准特性。此机制在 配置指南 中有 文档说明

此图表可能会进一步阐明这些特性如何相互关联以及如何管理它们。

Venn diagram showing taxonomy of traits and capabilities