通用资源池

https://blueprints.launchpad.net/nova/+spec/generic-resource-pools

此蓝图旨在通过引入管理特定数量某种资源的通用资源池的概念,来解决资源使用量报告不正确的问题。

注意

在实现此规范的过程中,开发人员意识到使用两个术语,资源提供者资源池,是冗余的。资源提供者 涵盖所有情况,现在是首选术语。 在本文档中,原始的“资源池”术语仍然使用。

问题描述

在云部署中,用户可能会消耗许多资源。 一些资源类型由计算节点提供; 这些类型的资源包括 CPU、内存、PCI 设备和本地临时磁盘。 然而,其他类型的资源不是由计算节点提供的,而是由一些外部资源池提供的。 例如,此类资源可以是 Ceph 或 NFS 共享提供的共享存储池。

不幸的是,由于遗留原因,Nova 认为资源仅由计算节点提供。 资源的跟踪假定资源由计算节点提供,因此在报告某些资源的用法时,Nova 会通过简单地汇总数据库中所有计算节点上的数量来天真地计算资源使用量和可用性。 这最终会导致许多问题 [1],导致使用量和容量信息不正确。

用例

作为选择使用共享存储解决方案来存储实例临时磁盘的部署者,我希望 Nova 和 Horizon 报告磁盘资源的正确使用量和容量信息。

作为高级 Neutron 用户,我希望使用新的路由网络功能,并能够让 Nova 理解特定的预创建 Neutron 端口与特定的子网池段相关联,并确保我的实例启动在与该段匹配的计算节点上。

作为高级 Cinder 用户,如果我在 nova boot 命令中指定 Cinder volume-id,我希望 Nova 能够知道哪些计算节点连接到包含请求卷的 Cinder 存储池。

提议的变更

我们建议一个新的 RESTful 放置 API,允许查询和管理资源提供者、它们的库存和分配记录,以及它们与聚合的关联。

资源提供者向多个资源消费者公开一种或多种资源类型的数量。 资源提供者不特定于共享存储,尽管它们的设计目的是解决 Nova 中的共享存储会计问题。

建议使用 RESTful API(如下所示),允许管理员(或服务)用户创建资源提供者,更新这些提供者的容量和使用信息,并通过将池与一个或多个聚合关联来指示哪些计算节点可以使用提供者的资源。

场景 1:用于 VM 磁盘镜像的共享磁盘存储

在此场景中,我们试图让 Nova 意识到环境中一组计算节点使用共享存储来存储 VM 磁盘镜像。 共享存储是具有 100 TB 总磁盘空间的 NFS 共享。 大约 1 TB 的共享空间已经被无关的事物消耗了。

第 1 行、机架 6 到 10 中的所有计算节点都连接到此共享。

  1. 云部署者创建代表第 1 行、机架 6 到 10 中所有计算节点的聚合

    AGG_UUID=`openstack aggregate create r1rck0610`
    # for all compute nodes in the system that are in racks 6-10 in row 1...
    openstack aggregate add host $AGG_UUID $HOSTNAME
    
  2. 云部署者创建代表 NFS 共享的资源池

    RP_UUID=`openstack resource-provider create "/mnt/nfs/row1racks0610/" \
        --aggregate-uuid=$AGG_UUID`
    

    在底层,此命令行执行两个 REST API 请求。 一个用于创建资源提供者,另一个用于关联聚合。

  3. 云部署者更新共享磁盘的资源池容量

    openstack resource-provider set inventory $RP_UUID \
        --resource-class=DISK_GB \
        --total=100000 --reserved=1000 \
        --min-unit=50 --max-unit=10000 --step-size=10 \
        --allocation-ratio=1.0
    

注意

–reserved 字段指示已被非核算消费者消耗的 NFS 共享的部分。 当 Nova 计算资源池是否有能力满足对某种数量资源的请求时,它使用以下公式进行检查:((TOTAL - RESERVED) * ALLOCATION_RATIO) - USED >= REQUESTED_AMOUNT

场景 2a:使用 Neutron 路由网络功能

在此(未来)场景中,我们假设 Neutron 路由网络功能在我们的部署中可用。 有一组路由网络,每个网络包含一组 IP 地址,代表数据中心中的物理网络拓扑。 假设标识符为 rnA 的路由网络代表数据中心第 3 行第 1 个机架中所有计算节点的子网 IP 池。 此子网的 CIDR 为 192.168.10.1/24。 此外,假设未管理的设备消耗了子网底部的 5 个 IP 地址。

  1. 网络管理员创建网络和路由网络段,代表第 1 个机架第 3 行的广播域

    NET_UUID=`openstack network create "routed network"`
    SEG_UUID=`openstack subnet pool create $NET_UUID`
    SUBNET_UUID=`openstack subnet create $SEG_UUID --cidr=192.168.10.1/24`
    
  2. 云部署者创建代表第 3 行、机架 1 到 5 中所有计算节点的聚合

    AGG_UUID=`openstack aggregate create "row 3, rack 1"`
    # for all compute nodes in the system that are in racks 1 in row 3...
    openstack aggregate add host $AGG_UUID $HOSTNAME
    
  3. 云部署者创建代表路由网络的 IP 池的资源池

    openstack resource-provider create "routed network rack 1 row 3" \
        --uuid=$SUBNET_UUID \
        --aggregate-uuid=$AGG_UUID
    

注意

请注意,上述 openstack resource-provider create 调用中的 –uuid 字段是 openstack resource-provider create 的可选参数。 您可能已经注意到,在第一个用例中,我们没有在创建资源提供者时提供 UUID。

–uuid 参数允许传入 UUID 标识符,以便外部系统可以提供资源池的已知外部全局标识符。 如果在调用 openstack resource-provider create 中未提供 –uuid 参数,则将自动分配一个新的 UUID 并显示给用户。

在上述情况下,我们假设调用 neutron subnet create 返回一个包含子网 IP 分配池(段)的 UUID 的值。

  1. 云部署者更新 IPv4 地址的资源池容量

    openstack resource-provider set inventory $RP_UUID \
        --resource-class=IPV4_ADDRESS \
        --total=254 --reserved=5 \
        --min-unit=1 --max-unit=1 --step-size=1 \
        --allocation-ratio=1.0
    

注意

与其让云部署者手动更新资源池的库存,更有可能的是,脚本会调用 neutron subnet-XXX 命令来确定容量和保留数量。

  1. 云用户在 Neutron 中创建端口,要求从特定子网获取 IP

    PORT_UUID=`openstack port create --network-id=$NET_UUID --fixed-ip \
        subnet=$SUBNET_UUID`
    
  2. 云用户启动实例,指定在步骤 5 中创建的端口的 ID

    openstack server create --nic port_id=$PORT_UUID --image XXX --flavor AAA
    
  3. 在(或之前)调度过程中,Nova 将希望回答这个问题:“如果此端口 ID 是包含 IPV4_ADDRESS 资源的资源池的成员,哪些计算节点是与该 IPv4 子网关联的可能的目标目的地?”

    Nova 调度器(或导体)可以通过查看与该子网关联的聚合来确定用于放置决策的计算节点集,进而允许它识别与这些聚合关联的计算节点。

这为云用户提供了调度期间的基本网络亲和性,云用户只需要指定端口 ID。

场景 2b:在场景 2a 中启动的实例的实时迁移

假设在场景 2a 的步骤 #6 中启动的虚拟机需要进行实时迁移——也许是因为计算主机正在发生故障或正在升级。 实时迁移在保持工作负载的网络设置不变的情况下,将工作负载从源主机移动到目标主机。 在实例使用与特定资源池关联的端口启动的情况下,该资源池包含路由网络的 IP 地址集,我们需要确保目标主机与源主机位于同一聚合中(因为路由网络仅跨特定聚合中的计算主机)。

借助通用的资源池信息,我们可以让调度器(或导体)通过检查与实例 UUID 作为消费者匹配的 IPV4_ADDRESS 资源类的资源提供者来限制用于确定实时迁移的目标主机的一组计算节点。 从此列表中,我们可以识别与资源提供者关联的聚合,并从聚合列表中确定可以作为迁移目标主机的计算主机。

备选方案

一种替代方法是在 Nova 系统中拥有一个实体来表示这些资源池,就是让 Nova 某种方式检查配置标志,以确定计算节点上的磁盘资源是使用共享存储还是本地可用。 这种方法存在一些问题

  • 此方法不是通用的,并且假定唯一的共享资源是磁盘空间

  • 此信息实际上不是配置数据,而是系统库存数据,因此它属于数据库,而不是配置文件

数据模型影响

将在 API 数据库中创建一个多对多映射表,以启用聚合与一个或多个资源池的关联

CREATE TABLE resource_provider_aggregates (
    resource_provider_id INT NOT NULL,
    aggregate_id INT NOT NULL,
    PRIMARY KEY (aggregate_id, resource_provider_id),
    FOREIGN KEY fk_aggregates (aggregate_id)
        REFERENCES aggregates (id),
    FOREIGN KEY fk_resource_providers (resource_provider_id),
        REFERENCES resource_providers (id)
);

将引入一个新的 Nova 对象模型来表示资源提供者。 此对象模型将允许查询与资源提供者关联的聚合以及池的库存和分配记录。

REST API 影响

所有以下 API 调用仅供云管理员和/或服务用户使用。

注意:所有以下 API 调用都应在 /nova/api/openstack/placement/ 中实现,而不是/nova/api/openstack/compute/ 中实现,因为这些调用将是拆分 REST API 的一部分。 应该有一个完全独立的放置 API 端点,在与 Nova API 不同的端口上启动,并由不同的服务提供。

从一开始就将添加微版本支持到新的放置 API。

API 更改将向以下位置添加资源端点

  • GET 资源提供者列表

  • POST 新资源提供者

  • GET 带有指向其子资源的链接的单个资源提供者

  • PUT 单个资源提供者以更改其名称

  • DELETE 单个资源提供者及其关联的库存(如果没有分配存在)和聚合(删除了关联,而不是聚合本身)

  • GET 与单个资源提供者关联的库存列表

  • POST 特定资源类的新库存

  • GET 给定资源类的单个库存

  • PUT 更新单个库存

  • PUT 要在单个资源提供者上设置所有库存的库存列表

  • DELETE 库存(如果没有分配存在)

  • PUT 要与此资源提供者关联的聚合列表

  • GET 该聚合列表

  • GET 按资源类列出用法

  • PUT 为一个消费者和一个或多个资源提供者设置分配记录

  • DELETE 消费者的分配记录集

  • GET 按消费者列出分配

  • GET 按资源提供者列出分配

这提供了对重要资源的粒度访问,同时提供了对使用信息的直接访问。

详情如下。

将添加以下新的 REST API 调用

GET /resource_providers

返回此 Nova 部署中的所有资源提供者列表。

示例

200 OK
Content-Type: application/json

{
  "resource_providers": [
    {
      "uuid": "b6b065cc-fcd9-4342-a7b0-2aed2d146518",
      "name": "RBD volume group",
      "generation": 12,
      "links": [
         {
           "rel": "self",
           "href": "/resource_providers/b6b065cc-fcd9-4342-a7b0-2aed2d146518"
         },
         {
           "rel": "inventories",
           "href": "/resource_providers/b6b065cc-fcd9-4342-a7b0-2aed2d146518/inventories"
         },
         {
           "rel": "aggregates",
           "href": "/resource_providers/b6b065cc-fcd9-4342-a7b0-2aed2d146518/aggregates"
         },
         {
           "rel": "usages",
           "href": "/resource_providers/b6b065cc-fcd9-4342-a7b0-2aed2d146518/usages"
         }
      ]
    },
    {
      "uuid": "eaaf1c04-ced2-40e4-89a2-87edded06d64",
      "name": "Global NFS share",
      "generation": 4,
      "links": [
         {
           "rel": "self",
           "href": "/resource_providers/eaaf1c04-ced2-40e4-89a2-87edded06d64"
         },
         {
           "rel": "inventories",
           "href": "/resource_providers/eaaf1c04-ced2-40e4-89a2-87edded06d64/inventories"
         },
         {
           "rel": "aggregates",
           "href": "/resource_providers/eaaf1c04-ced2-40e4-89a2-87edded06d64/aggregates"
         },
         {
           "rel": "usages",
           "href": "/resource_providers/eaaf1c04-ced2-40e4-89a2-87edded06d64/usages"
         }
      ]
    }
  ]
}

注意

上述输出中的 generation 字段是一致的视图标记。 我们需要在该字段中包含该字段,以便库存和分配信息的更新者可以指示资源提供者在最初读取其信息时的状态。

POST /resource_providers

创建一个新的资源提供者。

一个示例 POST 请求

Content-type: application/json

{
    "name": "Global NFS share",
    "uuid": "eaaf1c04-ced2-40e4-89a2-87edded06d64"
}

请求体必须符合以下 JSONSchema 文档

{
    "type": "object",
    "properties": {
        "name": {
            "type": "string"
        },
        "uuid": {
            "type": "string",
            "format": "uuid"
        }
    },
    "required": [
        "name"
    ]
    "additionalProperties": False
}

响应体为空。 标头包括指向创建的资源提供者的位置标头

201 Created
Location: /resource_providers/eaaf1c04-ced2-40e4-89a2-87edded06d64

如果提供了提供的名称,将返回 409 Conflict 响应代码,因为存在另一个资源提供者。

GET /resource_providers/{uuid}

检索由 {uuid} 标识的资源提供者的表示形式。

示例

GET /resource_providers/eaaf1c04-ced2-40e4-89a2-87edded06d64

200 OK
Content-Type: application/json

{
  "uuid": "eaaf1c04-ced2-40e4-89a2-87edded06d64",
  "name": "Global NFS share",
  "generation": 4,
  "links": [
     {
       "rel": "self",
       "href": "/resource_providers/eaaf1c04-ced2-40e4-89a2-87edded06d64"
     },
     {
       "rel": "inventories",
       "href": "/resource_providers/eaaf1c04-ced2-40e4-89a2-87edded06d64/inventories"
     },
     {
       "rel": "aggregates",
       "href": "/resource_providers/eaaf1c04-ced2-40e4-89a2-87edded06d64/aggregates"
     },
     {
       "rel": "usages",
       "href": "/resource_providers/eaaf1c04-ced2-40e4-89a2-87edded06d64/usages"
     }
  ]
}

如果资源提供者不存在,则必须返回 404 Not Found

PUT /resource_providers/{uuid}

更新由 {uuid} 标识的资源提供者的名称。

示例

PUT /resource_providers/eaaf1c04-ced2-40e4-89a2-87edded06d64

Content-type: application/json

{
    "name": "Global NFS share"
}

成功后,将返回 200 OK 响应,其中包含与相同 URI 上的 GET 响应相同形式的 application/json 正文。

如果发生错误,HTTP 响应代码将是以下之一

  • 400 Bad Request,用于错误的或无效的语法。

  • 404 Not Found,如果具有 {uuid} 的资源池不存在。

  • 409 Conflict,如果存在具有提供的名称的另一个资源池。

DELETE /resource_providers/{uuid}

删除由 {uuid} 标识的资源提供者。

这将同时取消关联聚合并删除库存。

请求体和响应为空。

返回的 HTTP 响应代码将是以下之一

  • 204 No Content,如果请求成功并且删除了资源池。

  • 404 Not Found,如果未找到由 {uuid} 标识的资源提供者。

  • 409 冲突 如果移除资源提供者会导致删除任何库存的分配记录。

GET /resource_providers/{uuid}/inventories

检索与由 {uuid} 标识的资源提供者关联的库存列表。

示例

GET /resource_providers/eaaf1c04-ced2-40e4-89a2-87edded06d64/inventories

200 OK
Content-Type: application/json

{
  "resource_provider_generation": 4,
  "inventories": {
    "DISK_GB": {
      "total": 2048,
      "reserved": 512,
      "min_unit": 10,
      "max_unit": 1024,
      "step_size": 10,
      "allocation_ratio": 1.0
    },
    "IPV4_ADDRESS": {
      "total": 256,
      "reserved": 2,
      "min_unit": 1,
      "max_unit": 1,
      "step_size": 1,
      "allocation_ratio": 1.0
    }
  ]
}

注意

输出中的 resource_provider_generation 字段为调用者提供了一致的视图标记。如果调用者希望更新库存,则将此生成字段值返回到 PUT /resource_providers/{uuid}/inventories/{resource_class} 的调用中,服务器将确保如果在初始读取生成值和更新库存之间,另一个进程已更新资源提供者的库存或分配的状态,则返回 409 冲突,从而允许调用者重试操作。

返回的 HTTP 响应代码将是以下之一

  • 200 OK 如果资源池存在。

  • 404 Not Found 如果未找到由 {uuid} 标识的资源提供者。如果资源提供者存在但没有库存,则请求将成功,但 inventories 键的值将是一个空字典。

POST /resource_providers/{uuid}/inventories

为由 {uuid} 标识的资源提供者创建一个新的库存。

示例

POST /resource_providers/eaaf1c04-ced2-40e4-89a2-87edded06d64/inventories
Content-Type: application/json

{
  "resource_class": "DISK_GB",
  "total": 2048,
  "reserved": 512,
  "min_unit": 10,
  "max_unit": 1024,
  "step_size": 10,
  "allocation_ratio": 1.0
}

请求体必须符合以下 JSONSchema 文档

{
    "type": "object",
    "properties": {
        "resource_class": {
            "type": "string",
            "pattern": "^[A-Z_]+"
        },
        "total": {
            "type": "integer"
        },
        "reserved": {
            "type": "integer"
        },
        "min_unit": {
            "type": "integer"
        },
        "max_unit": {
            "type": "integer"
        },
        "step_size": {
            "type": "integer"
        },
        "allocation_ratio": {
            "type": "number"
        },
    },
    "required": [
        "resource_class",
        "total"
    ],
    "additionalProperties": False
}

响应主体是 application/json 格式的库存表示,与 GET /resource_providers/{uuid}/inventories/{resource_class} 请求返回的相同。标头包括一个指向创建的库存的位置标头

201 Created
Location: /resource_providers/eaaf1c04-ced2-40e4-89a2-87edded06d64/inventories/DISK_GB

注意

如果提供者中的一些非 Nova 资源消耗了一定数量的资源,则应使用“reserved”字段来调整库存的总容量。

返回的 HTTP 响应代码将是以下之一

  • 201 Created 如果库存成功创建

  • 404 Not Found 如果未找到由 {uuid} 标识的资源提供者

  • 400 Bad Request 对于错误的或无效的语法(例如,无效的资源类)

  • 409 Conflict 如果针对建议的资源类已经存在库存

PUT /resource_providers/{uuid}/inventories

设置由 {uuid} 标识的资源提供者的所有库存。

示例

PUT /resource_providers/eaaf1c04-ced2-40e4-89a2-87edded06d64/inventories
Content-Type: application/json

{
  "resource_provider_generation": 1
  "inventories": {
    "DISK_GB": {
        "total": 2048,
    },
    "IPV4_ADDRESS": {
        "total": 255,
        "reserved": 2
    }
  }
}

请求主体必须符合以下缩写的 JSONSchema 文档

{
  "type": "object",
  "properties": {
  "resource_provider_generation": {
    "type": "integer"
  },
  "inventories": {
    "type": "object",
    "patternProperties": {
      "^[A-Z0-9_]+$": {
        "type": "object",
        # the scheme for POST of one inventory above except for the
        # resource_class element, which is represented as the
        # patternProperty key.
    }
  },
  "required": [
    "resource_provider_generation",
    "inventories"
  ],
  "additionalProperties": False
}

响应主体是 application/json 格式的资源提供者的所有库存表示,形式与 GET /resource_providers/{uuid}/inventories 相同。

返回的 HTTP 响应代码将是以下之一

  • 200 OK 如果库存成功设置

  • 404 Not Found 如果未找到由 {uuid} 标识的资源提供者

  • 400 Bad Request 对于错误的或无效的语法(例如,无效的资源类)

  • 409 Conflict 如果任何现有库存中 totalreservedallocation_ratio 的更改将导致现有分配与建议的容量冲突

  • 409 Conflict 如果在返回 resource_provider_generation 视图标记后,另一个进程更新了任何现有的库存记录。

GET /resource_providers/{uuid}/inventories/{resource_class}

检索与由 {uuid} 标识的资源提供者关联的类为 {resource_class} 的单个库存。

示例

GET /resource_providers/eaaf1c04-ced2-40e4-89a2-87edded06d64/inventories/DISK_GB
200 OK
{
  "resource_provider_generation": 4,
  "total": 2048,
  "reserved": 512,
  "min_unit": 10,
  "max_unit": 1024,
  "step_size": 10,
  "allocation_ratio": 1.0
}

返回的 HTTP 响应代码将是以下之一

  • 200 OK 如果库存存在

  • 404 Not Found 如果未找到由 {uuid} 标识的资源提供者,或者类为 {resource_class} 的库存未与资源提供者关联

PUT /resource_providers/{uuid}/inventories/{resource_class}

更新现有的库存。

示例

PUT /resource_providers/eaaf1c04-ced2-40e4-89a2-87edded06d64/inventories/DISK_GB
{
  "resource_provider_generation": 4,
  "total": 1024,
  "reserved": 512,
  "min_unit": 10,
  "max_unit": 1024,
  "step_size": 10,
  "allocation_ratio": 1.0
}

请求主体必须符合上述库存 POST 中描述的 JSONSchema 文档,除了 resource_class 不是必需的,如果存在则会被忽略。

如果请求成功,响应主体将与 GET /resource_providers/{uuid}/inventories/{resource_class} 相同。

返回的 HTTP 响应代码将是以下之一

  • 200 OK 如果库存成功创建

  • 404 Not Found 如果未找到由 {uuid} 标识的资源提供者

  • 400 Bad Request 对于错误的或无效的语法

  • 409 Conflict 如果 totalreservedallocation_ratio 的更改将导致现有分配与建议的容量冲突

  • 409 Conflict 如果在返回 resource_provider_generation 视图标记后,另一个进程更新了相同的库存记录。

DELETE /resource_providers/{uuid}/inventories/{resource_class}

删除现有的库存。

示例

DELETE /resource_providers/eaaf1c04-ced2-40e4-89a2-87edded06d64/inventories/DISK_GB

主体为空。

返回的 HTTP 响应代码将是以下之一

  • 204 No Content 如果库存成功删除

  • 404 Not Found 如果未找到由 {uuid} 标识的资源提供者,或者没有与 {resource_class} 关联的库存

  • 400 Bad Request 对于错误的或无效的语法

  • 409 Conflict 如果此库存存在现有分配

GET /resource_providers/{uuid}/aggregates

注意

聚合支持是在微版本 1.1 中实现的。

获取与此资源提供者关联的聚合列表。

示例

GET /resource_providers/eaaf1c04-ced2-40e4-89a2-87edded06d64/aggregates

{
  "aggregates":
  [
    "21d7c4aa-d0b6-41b1-8513-12a1eac17c0c",
    "7a2e7fd2-d1ec-4989-b530-5508c3582025"
  ]
}

注意

使用名称 aggregates 列表可以保留以后向对象添加其他键的选项。这是 api-wg 集合资源的标准形式。

返回的 HTTP 响应代码将是以下之一

  • 200 OK 如果资源提供者存在

  • 404 Not Found 如果未找到由 {uuid} 标识的资源提供者

PUT /resource_providers/{uuid}/aggregates

注意

聚合支持是在微版本 1.1 中实现的。

将聚合列表与此资源提供者关联。

示例

PUT /resource_providers/eaaf1c04-ced2-40e4-89a2-87edded06d64/aggregates

[
    "21d7c4aa-d0b6-41b1-8513-12a1eac17c0c",
    "b455ae1f-5f4e-4b19-9384-4989aff5fee9"
]

成功后,响应主体将是与 GET /resource_providers/{uuid}/aggregates 上面的相同形式的关联聚合的 application/json 表示。

返回的 HTTP 响应代码将是以下之一

  • 200 OK 如果聚合成功更新

  • 404 Not Found 如果资源提供者不存在

  • 400 Bad Request,用于错误的或无效的语法。

GET /resource_providers/{uuid}/usages

检索与由 {uuid} 标识的资源提供者关联的资源的用法报告。该值是资源类与该资源提供者的该资源类的分配总和配对的字典。

示例

GET /resource_providers/eaaf1c04-ced2-40e4-89a2-87edded06d64/usages

{
  "resource_provider_generation": 4,
  "usages": {
    "DISK_GB": 480,
    "IPV4_ADDRESS": 2
  }
}

返回的 HTTP 响应代码将是以下之一

  • 200 OK 如果资源提供者存在。如果没有关联的库存,则 usages 字典应为空。

  • 404 Not Found 如果资源提供者不存在。

注意

用法是只读的。它们表示从资源提供者分配的资源类数量的总和。

PUT /allocations/{consumer_uuid}

创建一个或多个分配记录,表示指定使用者从一个或多个资源提供者消耗一类或多类资源。

示例

PUT /allocations/9a82ff67-26e2-4d0a-a7e1-746788a85646
{
  "allocations": [
    {
      "resource_provider": {
        "uuid": "fa84d9e3-ab3b-4240-8eee-e8f1138b3423"
      },
      "resources": {
        "DISK_GB": 10
      },
    },
    {
      "resource_provider": {
        "uuid": "7dd1cd8a-4058-4f58-a24a-e38a5f4d563e"
      },
      "resources": {
        "VCPU": 2,
        "MEMORY_MB": 1024
      }
    }
  }
}

注意

为了允许在一个事务中服务请求,一个使用者的分配是在一个请求中针对多个资源提供者设置的。

请求体必须符合以下 JSONSchema 文档

{
  "type": "object",
  "properties": {
    "allocations": {
      "type": "array",
      "items": {
          "type": "object",
          "properties": {
            "resource_provider": {
              "type": "object",
              "properties": {
                "uuid": {
                  "type": "string",
                  "format": "uuid"
                }
              },
              "additionalProperties": false,
              "required": ["uuid"]
            },
            "resources": {
              "type": "object",
              "patternProperties": {
                  "type": "object",
                  "patternProperties": {
                    "^[A-Z_]+$": {"type": "integer"}
                  }
              },
              "additionalProperties": false
            }
          },
          "additionalProperties": false,
          "required": [
            "resource_providers",
            "resources"
          ]
      }
    }
  },
  "required": ["allocations"],
  "additionalProperties": false
}

返回的 HTTP 响应代码将是以下之一

  • 204 No Content 如果分配记录成功创建

  • 400 Bad Request 对于错误的或无效的语法

  • 409 Conflict 如果任何资源提供者中没有指定资源类的可用库存

DELETE /allocations/{consumer_uuid}

删除使用者在所有其正在消耗的资源提供者上的所有分配记录。

示例

DELETE /allocations/9a82ff67-26e2-4d0a-a7e1-746788a85646

主体为空。

返回的 HTTP 响应代码将是以下之一

  • 204 No Content 如果分配记录成功删除

  • 404 Not Found 如果没有与

    {consumer_uuid}

GET /allocations/{consumer_uuid}

列出单个使用者在所有其正在消耗的资源提供者上的所有分配记录。

示例

GET /allocations/9a82ff67-26e2-4d0a-a7e1-746788a85646

{
  "allocations": {
    "63d56264-1f3f-4495-a8b7-0efa5e6c9670": {
        "generation": 2,
        "resources": {
            "DISK_GB": 4,
            "VCPU": 2
        }
    },
    "5af2c770-6878-4dc6-b739-1164cf990fc5" {
        "generation": 99,
        "resources": {
            "DISK_GB": 6,
            "VCPU": 3
        }
    }
  }
}

如果对于提供的使用者标识符没有分配,则将返回一个空的 allocations 字典。

注意

目前没有对使用者标识符进行验证,因此不可能出现 404 响应。

GET /resource_providers/{uuid}/allocations

列出针对由 uuid 标识的资源提供者的所有分配。

示例

GET /resource_providers/5af2c770-6878-4dc6-b739-1164cf990fc5/allocations

{
  "resource_provider_generation": 99,
  "allocations": {
    "9a82ff67-26e2-4d0a-a7e1-746788a85646": {
        "resources": {
            "DISK_GB": 6,
            "VCPU": 3
        }
    },
    "aeaf9aa1-8d4a-46e6-8dec-cf2c704b5976": {
        "resource": {
            "DISK_GB": 2,
            "VCPU": 1
        }
    }
  }
}

如果资源提供者存在,则响应将为 200 OK。如果没有分配,则 allocations 对象将为空。

如果资源提供者不存在,则响应将为 404 Not Found

安全影响

无。

通知影响

当资源提供者被创建、销毁、更新、与聚合关联以及从聚合中分离时,应该创建新的通知消息,以及库存和分配记录被创建和销毁时。

其他最终用户影响

应该为相应的功能创建新的 openstackclient CLI 命令

  • openstack resource-provider list

  • openstack resource-provider show $UUID

  • openstack resource-provider create “Global NFS share” –aggregate-uuid=$AGG_UUID [–uuid=$UUID]

  • openstack resource-provider delete $UUID

  • openstack resource-provider update $UUID –name=”New name”

  • openstack resource-provider list inventory $UUID

  • openstack resource-provider set inventory $UUID –resource-class=DISK_GB –total=1024 –reserved=450 –min-unit=1 –max-unit=1 –step-size=1 –allocation-ratio=1.0

  • openstack resource-provider delete inventory $UUID –resource-class=DISK_GB

  • openstack resource-provider add aggregate $UUID $AGG_UUID

  • openstack resource-provider delete aggregate $UUID $AGG_UUID

性能影响

无。

其他部署者影响

使用共享存储的部署者需要为他们的共享磁盘存储创建一个资源池,为可能需要为使用该共享存储的任何计算节点创建的任何主机聚合创建任何主机聚合,将资源池与这些聚合关联,并安排(cronjob 或类似)一些脚本来定期运行 openstack resource-provider set inventory $UUID –resource-class=DISK_GB –total=X –reserved=Y

我们应该在文档中包含一个示例脚本。

开发人员影响

无。

实现

负责人

主要负责人

cdent

其他贡献者

jaypipes

工作项

  • 创建新的 resource_provider_aggregates 表的数据库模型和迁移。

  • ResourceProvider 创建 nova.objects 模型

  • 创建用于资源提供者查询和处理的 REST API 控制器

  • 修改资源跟踪器以提取计算节点关联的聚合信息以及这些聚合可用的资源提供者信息。如果实例请求一定数量的 DISK_GB 资源,并且计算节点与包含可用 DISK_GB 库存的资源提供者关联,则资源跟踪器应针对该资源提供者(而不是计算节点本身)声明资源(写入分配记录)。

  • 修改调度器以查看与计算节点关联的聚合的资源提供者信息,以确定请求是否可以由这些关联的资源提供者满足

    对于此步骤,对现有的过滤器调度器的更改应该很小。现在,主机管理器在每次调用 select_destinations() 时都会查询部署中所有聚合的列表。对 nova.objects.AggregateList.get_all() 的调用返回一组聚合对象,然后将这些对象与每个聚合中的主机关联。在某些过滤器 host_passes() 检查期间,可以查询聚合的额外规格以确定是否满足某些功能请求。我们希望返回分配给每个聚合的每个资源池的库存和使用信息,以便像 DiskFilter 这样的过滤器不仅可以查询主机的 local_gb 值,还可以查询聚合的库存信息以获取共享磁盘存储。

  • 用于更新共享磁盘资源池的容量和使用信息的文档和示例 cronjob 脚本

  • 在具有共享存储的多节点 devstack 环境中的功能集成测试

依赖项

  • policy-in-code 蓝图必须先完成,因为我们希望在新放置 API 模块中使用新的策略框架

  • resource-classes 蓝图必须先完成

  • resource-providers 蓝图必须先完成,以确保 resource-providersinventoriesallocations 表存在。

  • compute-node-inventory-newton 蓝图必须完成,以便所有计算节点都具有 UUID 列和 resource_providers 表中的记录。这对于确定哪些资源提供者是资源池而不是计算节点是必要的。

  • resource-providers-allocations 蓝图的涉及将 inventoriesallocationsaggregatesresource_providers 表迁移到顶级 API 数据库的部分必须先完成

测试

必须添加完整的单元和功能集成测试,以演示用通用资源池表示的共享存储的正确资源核算。

文档影响

应该添加开发人员文档,详细说明新的资源提供者功能,以及外部脚本如何保持提供共享资源池的资源提供者的容量和使用信息更新。

参考资料

[1] 与资源使用报告和计算相关的错误

历史

修订版

发布名称

描述

Newton

引入