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 微版本实现
添加 python-ironicclient 可以支持的最高的 Ironic 微版本。
如果用户没有传递版本,客户端应自动尝试其支持的最高版本。也就是说,使用支持的最高的 Ironic 微版本的 X-OpenStack-Ironic-API-Version HTTP 头。
python-ironicclient 应支持 X.Y 和 ‘latest’ 作为有效的 API 版本。
依赖项¶
无
测试¶
对于 tempest 来说,测试微版本支持的 API 的所有可能组合是不可行的。 我们必须选择代表已实现内容的特定版本。 现有的 tempest 测试将作为未来 API 版本测试的基线。
应测试以下组合
旧客户端(例如,juno 时代客户端发布版)与 Ironic 的当前主分支
最新客户端(例如,对主分支的提议更改)与 Ironic 的当前主分支
最新客户端(例如,对主分支的提议更改)与 Ironic 的 stable/juno
我们应该继续进行这种正向和反向测试,只要我们声称支持给定的发布版本。
文档影响¶
未识别到任何未涵盖在现有 API 变更流程中的特定文档影响。
参考资料¶
[0] https://specs.openstack.org/openstack/nova-specs/specs/kilo/implemented/api-microversions.html 了解 Nova 的微版本信息。 请注意,本文档大量借鉴了该规范。(感谢 cyeoh!)
[1] https://review.openstack.org/#/c/150821/ 和 https://review.openstack.org/#/c/158601/
[6] 虽然总体上是正确的,但至少有一项更改 - 添加 ‘maintenance_reason’ 字段 - 是在 Ironic 的 ‘Juno’ 发布之后进行的