Ironic Microversions

https://blueprints.launchpad.net/ironic/+spec/api-microversions

本规范的目的是明确 Ironic 和 python-ironicclient 之间在现在使用 microversions 时的具体行为要求,并为其他客户端提供与 Ironic 交互的指导。

问题描述

作为一个社区,我们在接口和代码的演进方面做得很好,通过增量开发不断改进。我们在一次性的大规模代码更新方面做得不太好。Ironic API 正在积极开发中,我们希望确保 Ironic API 的使用者能够利用新功能,同时也要确保它们不会因不兼容性而崩溃。

讽刺的是,Ironic 并不是唯一一个实现 microversions 的 OpenStack 项目。Nova[0] 也在并行地为 ‘Kilo’ 版本实现 microversions。

Ironic 中 microversions 的实现目前正在进行中,基于 Nova 的规范。Ironic 中的实现已经完成[1],并且目前正在为 Ironic 的主要客户端 python-ironicclient[2] 实现中。

Microversions 通过添加一个新的 HTTP header 实现,具体来说就是 ‘X-OpenStack-Ironic-API-Version’。Ironic 接受此 header,以便客户端可以指示它希望使用的 API 版本进行通信,同样地,Ironic 也可以指示它正在使用的版本进行通信。

对于 Ironic,如果没有提供 HTTP header,则使用 v1.0 (稳定/juno) 的 API。如果在 HTTP header 中指定了无效的版本,则返回 HTTP 406 Not Acceptable,并指示支持的版本范围[4]。如果指定了特殊的 ‘latest’ 版本,Ironic 将使用其最新版本。

在对 python-ironicclient[2] 进行更改以支持 Ironic 的 microversions 时,发现缺少 Ironic 和客户端在不同 microversion 不匹配或未知/未指定的 microversion 情况下交互的正式规范。

在 IRC[3] 中讨论了对本规范的需求,以专门解决 Ironic 和客户端(无论是 python-ironicclient 还是任何其他客户端)之间的交互。

提议的变更

为了解决 Ironic 和 python-ironicclient 之间的具体行为,列出了以下用例来指定预期的功能。有关这些用例的更多上下文,请参阅 IRC 日志[3][5] 和此代码审查[2]。

为了便于定义,我们将使用术语“旧 Ironic”来指代一个在 microversions 之前存在的,并且不了解它们的 Ironic 版本。同样,我们将使用术语“新 Ironic”来指代一个包含对 microversions 支持的 Ironic 版本。

类似地,我们将对“旧客户端”和“新客户端”分别应用这样的标签。

新客户端默认 Microversion

python-ironicclient 提供了指定与 Ironic 通信尝试使用的 microversion 的选项。如果指定了此选项,则应使用请求的 microversion(除非客户端不支持该版本)。这包括 ‘latest’,它指示 Ironic 使用 ironic 了解的最新 microversion。

但是,如果未向客户端指定 microversion,它应使用客户端支持的最新 microversion。

作为与 Ironic 的初始通信的一部分,由于 Ironic 只支持旧的 microversions,它可能需要降级到较低的 microversion(如用例 7 所述)。

此要求的目的是使 python-ironicclient / Ironic 通信对用户来说“即刻可用”,并且尽可能使用最新的 REST API 版本,以便用户能够利用最新的功能。

用例 1:旧客户端与旧 Ironic 通信

这与 microversions 引入之前的行为完全相同 - 客户端和服务器都不需要更改此情况。

  • 客户端建立与 Ironic 的连接,未指定 HTTP header X-OpenStack-Ironic-API-Version

  • Ironic 不会检查 X-OpenStackIronic-API-Version header,并简单地将所有通信处理为 v1.0 (稳定/juno)

用例 2:旧客户端与新 Ironic 通信

这是 Ironic 更新到支持 microversions 的新版本,但使用旧客户端与其通信的情况。

  • 客户端建立与 Ironic 的连接,未指定 HTTP header X-OpenStack-Ironic-API-Version

  • Ironic 未看到 X-OpenStack-Ironic-API-Version HTTP header

  • Ironic 使用 v1.0 (稳定/juno) 的 REST API 进行通信,所有与客户端的通信都使用该版本的接口。

用例 3A:新客户端与旧 Ironic 通信(未用户指定)

这是用户未请求特定 microversion 的新客户端支持 microversions 并尝试与旧 Ironic 通信的情况。新客户端使用的版本是它支持的最高 microversion。

  • 用户未在与客户端的通信中指定 microversion。因此,客户端尝试使用客户端了解的最新 microversion。

  • 客户端建立与旧 Ironic 的连接,提供带有 X-OpenStack-Ironic-API-Version HTTP header

  • Ironic 不查找或解析 HTTP header。它使用它所知道的唯一 API 代码路径进行通信,即 v1.0

  • 客户端未在响应中收到 X-OpenStack-Ironic-API-Version header,并且由此能够假设它正在与之通信的 Ironic 版本不支持 microversions。也就是说,它正在使用早于 v1.0 (稳定/juno) 的 REST API 版本。

  • 客户端现在应该透明地继续,因为它知道它正在与只能支持 v1.0 REST API 的 Ironic 进行通信。

用例 3B:新客户端与旧 Ironic 通信(用户指定)

这是用户请求特定 microversion 的新客户端支持 microversions 并尝试与旧 Ironic 通信的情况。

  • 用户指定对客户端有效的 microversion。

  • 客户端建立与旧 Ironic 的连接,提供带有 X-OpenStack-Ironic-API-Version HTTP header

  • Ironic 不查找或解析 HTTP header。它使用它所知道的唯一 API 代码路径进行通信,即 v1.0

  • 客户端未在响应中收到 X-OpenStack-Ironic-API-Version header,并且由此能够假设它正在与之通信的 Ironic 版本不支持 microversions。也就是说,它正在使用早于 v1.0 的 REST API 版本。

  • 客户端通知用户它无法使用该 microversion 与 Ironic 通信并退出。

用例 4:新客户端,用户指定无效版本号

这是用户向新客户端输入无效 microversion 标识符的情况,例如 ‘spam’、‘l33t’ 或 ‘1.2.3.4.5’。

  • 用户指定对客户端无效的 microversion。客户端应向用户返回错误,即客户端应提供对提供的 microversion 标识符进行验证。

用例 5:新客户端/新 Ironic:不支持的 Ironic 版本

这是新客户端请求的新 Ironic 无法处理的版本的情况。例如,客户端支持 microversions 1.1 到 1.6,而 Ironic 支持版本 1.8 到 1.15。

  • 客户端建立与 Ironic 的连接,提供 1.6 作为请求的 microversion。

  • Ironic 使用 406 Not Acceptable 回应,并附带它可以支持的 -Min- 和 -Max- header(在本例中为 1.8 和 1.15)

  • 由于客户端不支持 Ironic 支持的版本,它无法继续并向用户报告此情况。

  • (另一种方法是客户端尝试使用 Ironic 可接受的版本继续。请注意,在这种情况下,客户端应该能够继续,因为任何会破坏基本兼容性的更改可能需要将主要版本升级到 v2)

用例 6:新客户端/新 Ironic:不支持的客户端版本

这是新客户端请求的新 Ironic 无法处理的版本的情况。例如,客户端支持 microversions 1.10 到 1.15,而 Ironic 支持版本 1.1 到 1.5。

  • 客户端建立与 Ironic 的连接,提供 1.10 作为请求的 microversion。

  • Ironic 使用 406 Not Acceptable 回应,并附带它可以支持的 -Min- 和 -Max- header(在本例中为 1.1 和 1.5)

  • 客户端向用户报告此错误

  • (另一种方法是客户端尝试使用 Ironic 可接受的版本继续。请注意,在这种情况下,客户端应该能够继续,因为任何会破坏基本兼容性的更改可能需要将主要版本升级到 v2)

注意:在实践中不应发生这种情况,因为客户端应始终能够与任何版本的 Ironic 通信。

用例 7A:新客户端/新 Ironic:协商版本(未用户指定)

这是新客户端请求的新 Ironic 无法处理的版本的情况,但支持 Ironic 支持的版本。例如,客户端支持 microversions 1.8 到 1.15,而 Ironic 支持版本 1.1 到 1.10。

  • 用户未向客户端指定版本

  • 客户端建立与 Ironic 的连接,提供 1.15 作为 microversion,因为这是客户端支持的最新 microversion。

  • Ironic 使用 406 Not Acceptable 回应,并附带它可以支持的 -Min- 和 -Max- header(在本例中为 1.1 和 1.10)

  • 客户端应透明地继续,协商客户端和服务器都将使用 v1.10。客户端还应缓存此 microversion,以便后续尝试无需重新协商 microversions。

用例 7B:新客户端/新 Ironic:协商版本(用户指定)

这是用例 7A 的一个变体,用户指定使用与 Ironic 通信的特定版本。

  • 用户指定特定的 microversion(例如 1.15)供客户端使用

  • 客户端建立与 Ironic 的连接,提供 1.15 作为 microversion

  • Ironic 使用 406 Not Acceptable 回应,并附带它可以支持的 -Min- 和 -Max- header(在本例中为 1.1 和 1.10)

  • 客户端向用户报告此情况并退出

用例 8:新客户端/新 Ironic:兼容版本

这是新客户端请求的新 Ironic 支持的版本的情况。例如,客户端支持 microversions 1.8 到 1.10,而 Ironic 支持版本 1.1 到 1.12。

  • 客户端建立与 Ironic 的连接,提供 1.10 作为请求的 microversion。

  • 由于 Ironic 可以支持此 microversion,因此它通过在 X-OpenStack-Ironic-API-Version HTTP header 中发送 1.10 的响应来响应。

用例 9:新客户端/新 Ironic:版本请求为 ‘latest’

这是新客户端从新 Ironic 请求版本为 ‘latest’ 的情况。

  • 客户端建立与 Ironic 的连接,在 X-OpenStack-Ironic-API-Version HTTP header 中提供 ‘latest’ 作为版本

  • Ironic 通过使用它支持的最新 API 版本来响应,并在 X-OpenStack-Ironic-API-Version header 中包含此版本,以及 -Min- 和 -Max- header。

注意:Ironic 可能会提供客户端无法正确解释的响应。这是不可避免的,但是它使早于已部署 Ironic 版本的客户端有可能访问该 Ironic 版本中提供的所有功能。在这种情况下,客户端可以选择向用户报告 Ironic 在响应中包含的版本,以及客户端已知能够支持的最小和最大 microversions。客户端未编程为处理的 Ironic 响应的任何部分都将被丢弃。

备选方案

Microversions 的一种替代方案是不使用它们。这将导致一组大型更改同时发生,导致未配对的服务器/客户端版本完全不兼容。它还会导致不太频繁但更大的 API 更改。没有人想要那样。

数据模型影响

无。此更改仅限于 API 代码。

REST API 影响

如上所述,将接受并由 Ironic 返回一个新的 HTTP header。

如果客户端选择使用该 header 请求特定版本,Ironic 将响应,要么接受请求的版本以供将来通信,要么拒绝该版本请求,认为该版本不受支持。

如果客户端选择不使用该 header,Ironic 将假定要使用的 REST API 将是 v1.0(即 ‘Juno’ 版本[6] 中存在的 API)。REST API 今天的工作方式就是如此。

RPC API 影响

驱动程序 API 影响

Nova 驱动程序影响

python-ironicclient 的当前行为(不传递版本头)导致 Nova 驱动程序使用我们 API 的 v1.0 版本。对 python-ironicclient 的提议更改将导致 Nova 驱动程序使用客户端支持的最新微版本。这将使 Nova 能够使用我们在标记新客户端发布时添加到 Ironic 的任何新功能。

未来的增强功能将是修改 Nova Ironic 驱动程序,以便在与 Ironic 通信时指定要使用的特定微版本。这将提供对要使用的 REST API 版本的确切控制。

这种行为应记录在 Nova 和 Ironic 的门控测试方式中。

如果请求了不正确的版本,这里存在破坏 nova 驱动程序的可能性。因此,管理 Nova 驱动程序、Ironic 和 python-ironicclient 的版本更改非常重要。

安全影响

其他最终用户影响

希望使用自 ‘Juno’ 发布以来通过 REST API 添加的新功能的客户端需要开始使用此 HTTP 头。 只有在新版本中才会添加新功能的事实将鼓励他们这样做。

可扩展性影响

性能影响

其他部署者影响

开发人员影响

Ironic 的 REST API 的任何未来更改(无论是在请求或任何响应中)必须导致微版本更新,并在代码中进行适当的保护。

升级和向后兼容性

如上所述。

实现

负责人

主要负责人

lintan - Tan Lin <tan.lin.good@gmail.com>

次要分配人

devananda - Devananda van der Veen <devananda.vdv@gmail.com>
rloo - Ruby Loo <rloo@yahoo-inc.com>
mrda - Michael Davies <michael@the-davies.net>
plus many others

工作项

在...之前完成 python-ironicclient 微版本实现
  1. 添加 python-ironicclient 可以支持的最高的 Ironic 微版本。

  2. 如果用户没有传递版本,客户端应自动尝试其支持的最高版本。也就是说,使用支持的最高的 Ironic 微版本的 X-OpenStack-Ironic-API-Version HTTP 头。

  3. python-ironicclient 应支持 X.Y 和 ‘latest’ 作为有效的 API 版本。

依赖项

测试

对于 tempest 来说,测试微版本支持的 API 的所有可能组合是不可行的。 我们必须选择代表已实现内容的特定版本。 现有的 tempest 测试将作为未来 API 版本测试的基线。

应测试以下组合

  • 旧客户端(例如,juno 时代客户端发布版)与 Ironic 的当前主分支

  • 最新客户端(例如,对主分支的提议更改)与 Ironic 的当前主分支

  • 最新客户端(例如,对主分支的提议更改)与 Ironic 的 stable/juno

我们应该继续进行这种正向和反向测试,只要我们声称支持给定的发布版本。

文档影响

未识别到任何未涵盖在现有 API 变更流程中的特定文档影响。

参考资料