Allocation API¶
https://storyboard.openstack.org/#!/story/2004341
此规范提出创建用于部署节点分配的 API。
问题描述¶
独立 ironic 用户没有现成的手段来找到适合部署的节点。 metalsmith 项目是为了短期内填补这一空白而创建的,但它不适合不是用 Python 编写的消费者代码。一个潜在的消费者是用于独立 ironic 的 K8S 提供者。
API 用户故事如下
给定一个资源类,以及可选的所需特性列表,返回一个可用的裸机节点,并设置其
instance_uuid以将其标记为已保留。
提议的变更¶
概述¶
此 RFE 提出一个新的 ReST API 端点 /v1/allocations,该端点最初将允许创建和删除 Allocation 资源。
计划了两种分配流程的实现方式
通过数据库,类似于 metalsmith 目前的操作方式。
通过 Placement 服务,类似于 nova 目前的操作方式。
此规范侧重于 API 设计和第一个(独立)用例。
分配流程¶
分配过程如下
API 客户端发送一个
POST /v1/allocations请求,指定一个资源类,以及可选的特性和节点 UUID。分配请求路由到一个随机可用的 conductor。
conductor 在数据库中创建一个 Allocation 对象,其
state=allocating和conductor_affinity=<host name>。为剩余的分配过程生成一个线程,并将分配对象返回给调用者。
分配:数据库后端¶
以下操作由处理分配的 conductor 执行,当使用数据库作为后端时(此规范中的唯一选项)
从数据库中获取节点列表,条件为
provision_state=availablemaintenance=Falsepower_state!=None注意
这与旧的 API 版本兼容,这些版本允许直接在
available状态下创建节点。instance_uuid=Noneresource_class=<请求的 资源 类>uuid在候选节点列表中(如果提供)。请求的特性是节点特性的超集。
如果列表为空,则将分配的
state设置为error,并将last_error设置为解释说明。打乱列表,以便多个进程不会尝试以相同的顺序保留节点。
获取第一个节点的锁。如果锁定成功,则检查关于此节点的假设是否仍然有效,并通过设置其
instance_uuid为分配的uuid来保留它。在同一个数据库事务中将分配的
node_id设置为节点的 ID,将分配的
state设置为active,将节点的
allocation_id设置为分配的 ID,将匹配的特性添加到节点的
instance_info。
注意
由于 conductor 可能没有所选节点的硬件类型,我们将更新 TaskManager 以避免构造
driver对象。如果在上一步中发生故障,则继续到下一个节点。如果没有剩余节点,则将分配的
state设置为error,并将last_error设置为解释说明。
反分配:数据库后端¶
反分配过程将在一个事务中
取消设置节点的
instance_uuid,取消设置节点的
allocation_id,删除分配。
反分配是通过 API 显式触发的,或者当节点被拆除时(同时清除节点的 instance_uuid 和 instance_info 时)。
注意
将来我们可能会考虑支持持久分配,这些分配在节点拆除后仍然存在。这超出此规范的范围。
使用 instance_uuid 和使用分配 API 之间存在一个重要区别:instance_uuid 可以为 active 节点设置和取消设置,而对于分配则禁止这样做。原因是,使用未来的 Placement 后端,删除分配将在 Placement 中将节点标记为可用。
HA 和接管¶
当 conductor 重新启动时,它会获取具有以下条件的分配
conductor_affinity=<host name>state=allocating
并为每个分配启动分配过程。
如果处理分配的 conductor 在没有替换的情况下停止,则保留将变为孤立。所有 conductor 定期获取属于死 conductor 的分配列表,并尝试恢复它们。
首先,它会尝试通过执行类似以下操作来更新
conductor_affinityUPDATE allocations SET conductor_affinity=<new host name> WHERE id=<allocation ID> AND conductor_affinity=<dead host name>
如果查询更新了 1 行,我们知道新的 conductor 现在管理分配。否则,我们知道另一个 conductor 已经接管了它。
为了避免这种接管过程中的罕见竞争,正常的更新也将如下所示
UPDATE allocations SET <new values> WHERE id=<allocation ID> AND conductor_affinity=<current host name>
备选方案¶
让每个消费者发明自己的分配过程或使用 metalsmith。
编写一个新的服务来管理保留(可能基于 metalsmith 代码库)。
使 API 阻塞并避免为分配设置状态。这种方法将导致更简单的 API 和实现,但当使用外部系统(例如 Placement)作为后端时,可能会出现问题,因为对它的请求会阻塞 RPC 线程。
此外,异步设计将使将来引入批量分配 API 更加容易,如果我们决定这样做的话。
数据模型影响¶
引入一个新的数据库/RPC 对象 Allocation,具有以下字段
id内部整数 ID,未暴露给用户。uuid分配的唯一 UUID。name分配的唯一名称,遵循与节点名称相同的格式。注意
此字段对于使用主机名的系统(例如 metalsmith)很有用。
node_id保留的节点 ID(可以为null)- 外键到nodes表。updated_at/created_at标准更新/创建日期时间字段。resource_class必需的请求资源类。candidate_nodes可供选择的节点 UUID 列表(可以为null)。注意
这允许调用者通过任意标准预先过滤节点。
state分配状态,请参阅 状态机影响。last_error上次错误消息。conductor_affinity内部字段,指定当前处理此分配的 conductor。
引入一个辅助表 allocation_traits,用于映射分配到其请求的特性(与 node_traits 类似)。
使用新的外键 allocation_id 更新 nodes 表。它将被设置为相应的分配的 ID。与 instance_uuid 不同,它仅在创建分配时设置。如果 allocation_id 不为空,instance_uuid 将包含相应分配的 UUID(反之不一定为真)。
状态机影响¶
对节点状态机没有影响。
此 RFE 为 Allocation 对象引入了一个简单的状态机,包含三个状态
allocating分配正在进行中(初始状态)。active分配处于活动状态。error分配失败。
在初始版本中,只有以下路径是可能的
从
allocating到active成功时。从
allocating到error失败时。
将来我们可能会允许从 error 返回到 allocating 以重试分配。
REST API 影响¶
POST /v1/allocations创建分配。API 接受一个 JSON 对象。以下字段是必需的
resource_class请求的节点资源类。
以下字段是可以接受的
uuid创建具有特定 UUID 的分配。candidate_nodes将查询限制为这些节点之一。注意
此值在内部从名称转换为 UUID。
traits请求的特性列表。name分配名称。
正常响应是 HTTP CREATED,响应体是创建的分配表示形式。分配在
allocating状态下创建。错误代码
400 Bad Request 如果
任何来自
candidate_nodes的节点都无法找到(按名称或 UUID)。resource_class值无效。traits已提供且不是有效的特性字符串列表。name不是可接受的名称。
406 Conflict 如果
提供的
uuid不唯一或与任何节点的instance_uuid匹配。提供的
name不唯一。
GET /v1/allocations列出分配。参数
fields为每个分配检索的字段列表。state按状态过滤分配。resource_class按资源类过滤分配。node按节点 UUID 或名称过滤分配。
错误代码
400 Bad Request 如果
state无效。resource_class无效。node不存在。请求的任何字段无效。
GET /v1/allocations/<uuid 或 name>获取分配。参数
fields要检索的字段列表。
错误代码
400 Bad Request 如果请求的任何字段无效。
404 Not Found 如果未找到分配。
DELETE /v1/allocations/<uuid 或 name>删除分配并释放节点。没有请求或响应体。响应代码是 HTTP 204 No Content。
错误代码
404 Not Found 如果未找到分配。
409 Conflict 如果相应的节点是
active或处于不允许更新的状态。
注意
此请求仅对真实的分配有效。将无法使用此 API 删除通过直接
PATCH到节点创建的instance_uuid。GET /v1/nodes/<node UUID 或 name>/allocation获取与节点关联的分配。参数
fields要检索的字段列表。
响应体是 Allocation 对象表示形式。
错误代码
404 Not Found 如果
找不到节点。
节点没有分配。
400 Bad Request 如果
节点具有与任何分配不对应的
instance_uuid。请求的任何字段无效。
更新
GET /v1/nodes、GET /v1/nodes/detail和GET /v1/nodes/<node UUID 或 name暴露新的
allocation_uuid字段(从节点的allocation_id转换而来)。更新
PATCH /v1/nodes/<node UUID 或 name>如果
instance_uuid未设置,并且当前值对应于一个分配如果节点是
active状态或处于不允许更新的状态,并且maintenance模式关闭,则返回 HTTP 409 Conflict,否则删除分配。
如果
instance_uuid已设置,则不要创建分配,保持之前的行为。注意
这是为了避免影响 nova virt 驱动程序。此决定可能在未来的 API 版本中重新评估。
allocation_uuid字段是只读的,尝试直接更改它将导致 HTTP 400(错误请求)。更新
DELETE /v1/nodes/<node UUID 或 name>如果节点在维护模式下被删除并具有分配,则分配也会被删除。
客户端 (CLI) 影响¶
“ironic” CLI¶
无。
“openstack baremetal” CLI¶
将创建匹配的命令
openstack baremetal allocation create --resource-class <class> \
[--trait <trait>] [--trait <trait>] [--uuid <uuid>] [--name <name>]
openstack baremetal allocation list [--state <state>] [--fields <fields>]
[--resource-class <class>] [--node <UUID or name>]
openstack baremetal allocation get <uuid or name> [--fields <fields>]
openstack baremetal allocation delete <uuid or name>
allocation_uuid 字段将被暴露。
RPC API 影响¶
引入了两个新的 RPC 调用
创建分配
def create_allocation(self, context, allocation): """Create an allocation. Creates the provided allocation in the database, then starts a thread to process it. :param context: context :param allocation: allocation object. """
删除分配
def destroy_allocation(self, context, allocation): """Destroy an allocation. Removes the allocation from the database and releases the node. :param context: context :param allocation: allocation object. """
metalsmith 影响¶
metalsmith 项目在客户端实现了所提议功能的超集。引入此 API 后,metalsmith 将以以下方式切换 reserve_node 调用来使用它
如果请求包含
resource_class,以及可选的traits和候选节点,则将使用新的 API。如果请求包含新 API 不支持的内容,metalsmith 将继续进行客户端节点过滤,并使用合适的节点列表创建分配。
驱动程序 API 影响¶
无
Nova 驱动程序影响¶
无
未来我们可能会在 nova 驱动程序中使用分配 API,但目前没有计划。当前通过分配 API 将导致在 Placement 中进行双重分配,如果 Placement 被用作分配后端。
Ramdisk 影响¶
无
安全影响¶
无
其他最终用户影响¶
无
可扩展性影响¶
无
性能影响¶
每个 conductor 将运行一个新的周期性任务,以定期检查属于死 conductor 的停滞分配。默认周期将为 60 秒。可以禁用它,在这种情况下,如果分配的 conductor 死亡,分配可能会永远卡住。
其他部署者影响¶
无
开发人员影响¶
无
实现¶
负责人¶
- 主要负责人
dtantsur
工作项¶
添加新的表和 Allocation RPC 对象。
添加用于分配/取消分配的 RPC。
添加用于创建和删除分配的 API,以及 API 参考。
更新 conductor 启动过程,以检查未完成的分配。
添加一个周期性任务来检查孤立的未完成分配。
依赖项¶
无
测试¶
将提供单元测试和 Tempest API。
将更新独立的集成测试以使用新的 API。
我们可以将对新 API 的支持添加到 bifrost(例如通过 metalsmith),并在 bifrost CI 作业中对其进行测试。
升级和向后兼容性¶
此更改完全向后兼容。使用 instance_uuid 进行分配的代码不受影响。
文档影响¶
将提供 API 参考。