Neutron Core 和 Vendor 代码分解

https://blueprints.launchpad.net/neutron/+spec/core-vendor-decomposition

在 Neutron 中贡献和审查现有的和/或新的 Vendor 代码,由于许多原因而非常困难。我们正在提出对项目现有结构的更改,以解决这些痛点。更具体地说,我们正在推动以下领域的变革

  • 代码结构;

  • 贡献流程:这扩展到以下领域

    • 设计和开发;

    • 测试和持续集成;

    • 缺陷管理;

    • 文档。

问题描述

Vendor 和社区的关注点争夺着稀缺的资源,因为我们目前的流程是“一刀切”。早期将插件/驱动程序放在核心附近,是为了建立社区,但 Neutron 作为项目已经成熟。我们有机会发展插件/驱动程序维护者与核心之间的关系,以确保作为一个社区,我们可以在不产生目前面临的瓶颈和问题的情况下不断壮大。

目前,我们有 20 多个插件和 12 多个 ML2 机制驱动程序。还有许多新的插件/驱动程序正在开发中,它们的规范和代码贡献需要通过贡献流程,其中

  • 开发者向 neutron-specs 仓库提交蓝图规范;

  • 开发者向 neutron 仓库提交代码补丁;

  • 至少需要核心团队的两个成员(迭代地)审查规范;

  • 至少需要驱动程序团队的一个成员批准规范;

  • 至少需要两个核心审查者(迭代地)审查/批准补丁;

这种模式显然无法扩展,因为每个核心成员只能有限地了解代码库的某些部分,并且 Neutron 作为项目迄今为止看到的 vendor 特定的贡献数量巨大,这意味着没有一个核心审查者可以了解所有内容。这种模式还存在以下问题

  • 需要核心团队的强制性监督,因为核心审查者没有能力完全理解和判断 vendor 特定源代码的质量,有时以数千行代码的相互关联补丁的形式出现;当然,良好的静态代码审查可以帮助解决诸如样式、数据结构、算法、模块化等问题,但如果没有完全理解所有活动部件的能力,有时很难评估可能的故障模式、潜在的瓶颈,甚至为什么事后需要某些修复;

  • 核心审查有时可能需要使用补丁,由于缺乏访问专有和/或外部系统的权限,这使得操作变得困难,甚至不可能;

  • 防止核心审查者资源专注于 Neutron 作为管理服务的核心问题;

  • 防止 Vendor 对其自身代码的开发和发布拥有更多控制权;

  • 防止 Vendor 与 Neutron 社区的不同层级的互动:现有的模式施加了很高的接受门槛。Vendor 开发者被邀请积极参与项目的日常管理,维护他们的代码等,即使他们有时未能这样做。如果代码贡献量很大,那么这些开发者参与跨领域问题(例如,门控失败、oslo 库刷新、样式指南更改等)是理所当然的;换句话说,当前流程要求 Vendor 通过为非 Vendor 发起的项目做出贡献来建立良好关系,以便核心团队能够及时审查或解决 Vendor 的非核心贡献。在理想情况下,这将促进社区发展,但它预设了所有 Vendor 都有类似资源投入 Neutron,并且核心团队可以非线性地扩展(这两种情况在今天都不是事实);

  • 不促进清晰的关注点分离,因为代码都在一个大桶里;

  • 整个代码库的维护成本在 Neutron 团队中分布不均;

  • 重构工作受到处理开发者不熟悉的代码的困难的阻碍;

  • 对单元测试反馈运行时间产生负面影响,因为为了特定的更改,需要一次运行更多的测试;

所有这些问题最终都会影响项目演进的速度。

值得注意的是,这个问题以及潜在的解决方案,可能会以不同的方式影响 OpenStack 社区中的不同人员。例如

  • OpenStack Infra:团队需要提供哪些工具来帮助项目?他们是否会因为项目组织方式的改变而定期受到影响?

  • Vendor 开发者:开发者如何更快地合并他们的更改,并以最小的开销?编写更好的代码并更多地参与核心审查肯定有帮助,但这并不是每个贡献者都能或愿意为自己设定的标准;

  • Vendor 营销人员:营销人员如何声称他们的 Vendor 插件是 OpenStack 友好的?在这方面,Vendor 插件作为“兼容”OpenStack 交付的事实,与代码的来源在很大程度上是独立的。认为 openstack.org trunk 中的内容是“好的”的看法实际上是一种误解,因此,营销团队需要纠正这种看法。

  • Distros:Distro 如何通过捕获必要的代码、它们的外部依赖项以及提供允许轻松使用解决方案的配置工具来打包 Neutron?

  • Neutron 开发者:开发者如何支持(非)Vendor 代码贡献而不精疲力竭?

  • Operators:只要他们能够访问稳定、可升级且文档完善的产品,他们是否关心?

  • OpenStack 技术委员会:只要 OpenStack 的理想(开放性、透明性、通用性、集成性和质量)仍然得到执行,TC 成员是否会推广这项工作?就开放性而言,任何新的项目安排都必须保证四个开放性仍然存在(开源、开放设计、开放开发、开放社区 [17]);TC 成员也代表着积极的技术贡献者,因此对他们来说,减轻对 OpenStack 的贡献的痛苦至关重要;

  • OpenStack 基金会:只要不因试图使项目更好地运作而阻碍 OpenStack 云操作系统开发、分发和采用的工作,他们应该欢迎这项工作。基金会还具有职责,通过 openstack.org 上的市场,来推广驱动程序兼容性,并且很快也会有 RefStack [14];

话虽如此,所提出的更改主要解决 Neutron 社区今天面临的开发挑战,将社会或营销认知和相关问题留待 OpenStack 基金会指导解决。

提议的变更

这里提出的建议是一个初步步骤,并且可以在一个发布周期内实现。它绝不是最终目标,而是一个良好的平衡,让我们可以在迭代中找到黄金分割点 [5]。值得注意的是,这项工作是关于核心插件,而不是负载均衡器、VPN 和防火墙等高级服务。将这些服务拆分将通过另一个蓝图 [8] 进行跟踪。

高级代码库结构

我们建议

  • 单体插件ML2 机制驱动程序L3 服务插件 成为与树外代码集成的唯一入口(下面章节中提供更多详细信息);同样适用于任何 Vendor 特定的代理:将保留在树中的唯一部分是代理“main”(一个小型的 Python 文件,它从 Vendor 库导入代理代码并启动它)。L3 作为 Neutron 核心的组成部分,将经历与核心插件和 ML2 驱动程序相同的过程。 “树外”可以是 Vendor 舒适的任何东西:例如,StackForge 仓库、tarball、pypi 包等。重要的是,这个 Vendor 库必须是公开可访问的,原因有很多

    • 潜在的许可冲突,可能只能通过访问 Vendor 库来解决,但更重要的是,在任何情况下,像 Neutron 这样的关键 OpenStack 项目都不应鼓励关键组件(例如插件或机制驱动程序)的闭源开发;

    • Distros 的打包支持;即使在大多数情况下,Distros 会与他们想要打包和验证的 Vendor 建立关系,但仍然可能存在纯开源玩家,如果底层技术本身是开源的,他们可能会有兴趣使用它。

    插件/驱动程序维护者团队自我管理,以促进共享、重用、创新和“树外”主干的发布。不需要核心团队的任何成员参与此过程,尽管 Neutron 团队的核心成员可以在必要时以任何容量参与树外开发。

开发策略

  • 建议以下元素保留在树中,用于所有插件和驱动程序(以下称为 Vendor 集成) - 至少在本次努力的第一次迭代中

    • 数据模型;

    • 扩展定义;

    • 配置文件;

    • 针对 Vendor 代码的目标需求文件;

  • 不保留在树中的内容(以下称为 Vendor 库)

    • Vendor 特定的逻辑;

    • 相关的单元测试;

这里的想法是保留树中的插件/驱动程序代码,以实现 API,但将其委托给树外的代码进行后端特定的交互;Vendor 集成通常涉及参数的次要传递/解析、DB 对象的次要处理以及响应处理,而 Vendor 库将完成繁重的工作并实现 Vendor 特定的逻辑。在树内层和树外层之间的边界应由维护者定义,同时提出以下类型的问题

  • 如果我的后端发生更改,我是否需要大幅更改集成层?显然,影响越小,实现的分离就越好;

  • 如果我公开 Vendor 详细信息(例如,协议、身份验证等),是否可以轻松地交换和替换(例如,用更新的版本提供的硬件)而不会过多地影响集成?显然,集成的可重用性越高,分离就越好。

此外,我们可以观察到

  • 关于 db 模型,我们希望在目前保持向后兼容性(对于已经部署的系统)。在完全将 db 模型移出树之前,有许多技术点需要解决,例如,FK、连接查询、现有部署的 db 迁移等,因为目前 alembic 需要额外的工作才能支持单个数据库上的多个 db 迁移路径 [16]。一旦完成此建议的主要部分,就可以在适当的时候处理这个技术挑战;

  • 可以将配置文件移到其他地方(甚至依赖于配置自动生成功能)作为下一步进行探索。我们一直在使用 DocImpact 标志来跟踪配置更改,以确保 OpenStack 手册保持同步,我们不应该破坏这种模式;

  • Vendor 代码必须通过 pypi 或与 pip 需求兼容的公共源代码仓库公开可用;此需求文件不应与列出所有通用依赖项的 Neutron 需求文件混淆;相反,它是一个位于 neutron/plugins/pluginXXX/ 中的文件“requirements.txt”,其内容类似于“my_plugin_xxx_library>=X.Y.Z”。Vendor 应负责确保他们的库没有依赖于与全局需求冲突的库,但可以包含全局需求中未包含的库。如果 Vendor 库依赖于全局需求中未捕获的 python 包,这与今天发生的情况没有区别,我们不打算在本范围内解决这个问题。

  • 可以使用版本控制来固定 Vendor 代码;

  • 对于参考实现:它们仍然会遵循相同的模型,但实现将保留在树中,因为存在门控要求;原因是,在没有向后兼容接口的情况下,无法将参考实现外部化。协调在核心 neutron 仓库中着陆的破坏性更改以及参考实现仓库中的修复,以避免破坏 openstack 集成作业将是一个非常棘手的问题。本文档中提出的建议旨在鼓励插件/驱动程序将其自身分离为与 Neutron 集成的一部分以及与后端集成的部分。考虑到大多数破坏将发生在与 Neutron 的集成中(仍然在树中) - 并且只有在可以合理地预期在周期结束前修复这些破坏时(例如,在 milestone2 之前),对于非门控插件/驱动程序来说,风险应该大大降低。Trunk 将始终有效:对于可以检测到的破坏性更改,我们可以确保插件驱动程序的树内部分得到修复。插件/驱动程序特定的破坏需要由该插件/驱动程序的维护者修复,但作为一个社区,我们应该分别解决这种破坏的可能性。

  • 不需要 DevStack 更改:Devstack 已经具有正确的钩子 [6,7,10];此外,Vendor 完全控制第三方 CI 环境;他们可以在 CI 设置环境并堆叠之前,通过其他方式安装所需的依赖项。他们中的一些人已经做了各种各样的事情。

例如,一个厂商集成模块可以简单到只包含以下内容

  • 注册配置选项;

  • 注册插件类;

  • 注册模型;

  • 注册扩展。

例如

>    class DummyPlugin(db_base_plugin_v2.NeutronDbPluginV2,
>                      your_mixin_here):
>
>    supported_extension_aliases = ["the_extension_you_implement"]
>
>    __native_bulk_support = True
>    __native_pagination_support = True
>    __native_sorting_support = True
>
>    def __init__(self):
>        super(DummyPlugin, self).__init__()
>        config.register_config_opts()
>        self.vendor_plugin_init()
>
>    db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(...)

Nuage 插件 [2, 3] 遵循一种类似的方法。由于单元测试必须纯粹测试构成厂商库的单元,因此它们不再有意义作为 Neutron 代码库的一部分。话虽如此,厂商集成应该通过功能测试进行测试。VMware 插件也正朝着这个方向发展 [4],插件定义变得纯粹是声明性的。

测试策略

测试流程将如下变化

  • 树中将不会对插件和驱动程序进行单元测试,除了参考实现。期望是厂商将在他们自己的外部库中运行单元测试(例如,在 stackforge 中,Jenkins 设置是免费的);对于验证厂商库的单元测试,厂商有责任选择他们认为合适的 CI 系统来运行它们;如果他们不想使用,则不需要或要求使用 OpenStack CI 资源;最终,这些测试可以作为第 3 方 CI 系统 [9] 的一部分运行,如果需要,可以根据特定过滤器进行运行。值得注意的是,这项工作可能会揭示核心代码中测试不足的区域。我们应该努力识别这些区域,并提高其覆盖率,以便这些改进也能使各种厂商集成受益,因为添加/修改的测试将行使共享框架;

  • 第 3 方 CI 将继续通过 Tempest(例如,功能测试)验证厂商与 Neutron 的集成。第 3 方 CI 是一种通信机制。该机制的目标是三方面的

    • 它向插件/驱动程序维护者传达,有人贡献了一个可能破坏性的更改。然后,由给定的维护者确定故障是瞬时的还是真实的,并在是真实的情况下解决问题;

    • 它向补丁作者传达,他们可能会破坏一个插件/驱动程序。如果他们有时间/精力/与插件/驱动程序的维护者之间的关系,那么他们可以(根据自己的判断)努力解决破坏;

    • 它向整个社区传达,给定的插件/驱动程序是否正在积极维护。

    在第 3 方 CI 上进行门控一个糟糕的主意。它给合并过程引入了太多的不确定性,而且我们已经面临着比我们能够处理的更多的混乱。所提出的方案试图通过将插件/驱动程序接口保留在树中来减少一些破坏。我们可以添加接口集成的简单单元测试,但似乎集成失败应该在功能和集成级别而不是单元级别上更有效地捕获。话虽如此,此处概述的任何内容都不会阻止随着时间的推移调整测试覆盖率。

审查和缺陷管理策略

我们建议

  • 相同的缺陷管理流程适用:影响厂商代码的缺陷可以针对 Neutron 集成进行报告,如果集成代码有错;否则,代码维护者可以决定在没有监督的情况下修复一个缺陷,并在厂商库被固定时,针对相关代码中的要求文件发布一个新版本固定;对于给定的插件/驱动程序,在合并到任何分支(即 master 和 stable 分支)之前,需要通过第 3 方 CI,这很有意义;

  • 相同的审查流程适用:厂商特定代码遵循与树中任何其他代码相同的审查指南,但是,正在审查的代码严格适用于集成代码或要求版本更新;至于厂商库,它变成了一个外部仓库;厂商可以选择任何人来批准/合并此仓库中的更改;

  • 相同的发布流程适用:这不会改变;

  • 相同的安全漏洞流程适用:这不会改变。但是,由于厂商库的攻击面更大得多,因此漏洞很可能在那里被发现,维护者需要根据他们自己的程序发布修复;如果在厂商集成中发现漏洞,则漏洞修复需要遵循 OpenStack 定义的相同程序。厂商可以决定在 LP 或任何其他跟踪系统中发布漏洞:完全由他们决定。

蓝图规范提交策略

我们建议

  • 如果厂商遵守提案中概述的有限开发足迹,则他们不应被要求遵循仅影响其厂商集成和库的更改的规范流程。

  • 新的厂商插件和驱动程序的提案不再应遵循 Neutron 任何其他贡献的规范提交流程,只要厂商插件/驱动程序采用本提案中概述的指南即可。新的贡献可以直接提交代码审查,前提是提交代码时提供了足够的文档和第 3 方 CI。为了跟踪目的,审查本身可以标记为 Launchpad 错误报告,标记为愿望清单;设计文档仍然可以以 RST 文档的形式提供,在同一个厂商库仓库中,用于文档目的;

  • 针对 Neutron 当前发布周期的新厂商插件/驱动程序的蓝图规范将因此被评估为假设本提案通过,并因此标记为放弃。可以继续进行代码提交,并根据本提案中概述的指南进行评估。代码包含很可能在周期第三个里程碑时被考虑,以便为核心团队有足够的时间来充分实践本提案。

文档策略

有参考文档 [15] 中的文档的配套提案。未来的意图是文档团队将完全记录参考插件/驱动程序,并添加简短的部分来记录厂商插件和驱动程序,这与本提案(关于代码分解)所倡导的精神相同。现有的插件和驱动程序将不得不添加对其他文档的引用,就像新的插件和驱动程序在他们的厂商集成合并到 Neutron 仓库中一样。

采用和弃用策略

我们建议

  • 从 Kilo 开始,所有新的(核心或 L3)插件和驱动程序都遵循此模型;

  • 强烈建议现有的插件和驱动程序在 Kilo 周期中采用此模型,并根据上述指南构建代码;

  • 不能向现有的插件和驱动程序添加树中的功能:这意味着现有插件/驱动程序代码在主 Neutron 树中的功能将在 Kilo 版本中冻结。有些人可能会认为冻结可能不是必要的,我们仍然可以依赖一些审查的尽力而为。但是,重要的是要认识到,严格的纪律是确保本提案顺利进行所必需的;

  • 仅允许对现有的插件和驱动程序进行关键的错误修复;ML2 至少目前需要排除在外,因为我们依赖于 ML2+OVS,这排除了在引入向后兼容的接口之前拆分其任何部分。尽管如此,我们建议重构 OVS ML2 驱动程序,以便驱动程序本身包含为所有驱动程序提出的相同最小足迹,并且它们与后端实现清晰分离。

  • 在 Kilo 结束时仍然“原样”(即不符合本提案)的插件和驱动程序将被评估是否弃用和删除;维护者需要在 Kilo 时间范围内积极努力开始此过程;流程已经进行中,但在 Lxxx 完成仍然可以接受。但是,至关重要的是,维护者优先考虑他们的资源,以便重写过程不会推迟到 Lxxx,并减轻在 Mxxx 及时弃用和删除的潜在危险。

话虽如此,需要在 Kilo 的各个里程碑评估弃用目标和冻结,以确定本提案的完成程度,以及每个厂商维护者在完成“工作项目”部分中概述的任务方面的进展程度。如果本提案获得批准,那么将设置时钟并跟踪每个插件、ML2 驱动程序以及正在取得的进展(例如,设置仓库、解决相关代码的补丁等)。

注意:需要跟踪感兴趣各方的任何行动或缺乏参与,以确保弃用被视为最后的手段。

总结

此处提出的方法解决了 Neutron 开发人员厌倦的所有问题(如上所述);它通过将一些控制权委托给厂商来做到这一点,同时保留对 Neutron 项目一部分的可见性。

常见问题解答

在此处添加您的问题,我们将尽力回答

  • 问:如果核心团队追求 ML2 插件重构。对相同更改会影响 Neutron 树中现有大量厂商机械驱动程序的接口和行为。那么,厂商机械驱动程序是否继续保留在核心树中。

  • 答:该提案不是将驱动程序移出树。相反,意图是鼓励关注点分离,以便插件和驱动程序尽可能轻量级,并主要用于与树外部的库集成,这些库提供后端特定的实现。这将具有以下优势:允许厂商更好地控制其后端特定代码,并提供更改插件/驱动程序的可能性,而无需进行重量级的流程(无需规范流程和更快的合并)。

  • 问:是否将三个代码工件(模型、扩展和配置文件)也放在厂商仓库中?通过将上述三个保留在树中,该提案仍然给 Neutron 核心带来了审查厂商代码工件的重大负担。

  • 答:简短的答案是“否”,因为(希望)这些工件相对较小且易于理解。长答案是:完全分离所需的努力是巨大的。建议的方法将允许插件/驱动程序维护者更快地控制他们的工作,并降低风险。让每个人适应新模型可能需要整个周期,这不需要任何额外的工作,例如新的钩子、不同的 DB 时间线等,而只需要“机械”翻译。一旦清除,我们就可以专注于完善模型并进一步将代码委托给厂商。我们还需要考虑迁移路径:在拆分 db 模型时,我们需要考虑 db 迁移路径和与 Neutron 核心模型(网络、端口等)的 FK 关系。在提案之前提出如何处理此问题的具体计划被认为是一种值得推迟的风险。

  • 问:每个厂商的 DB 模型将保留在主仓库中。这可能避免了迁移的 alembic 挑战,但当涉及到同步模型和版本化插件库时,这让我有点困惑。换句话说,如果您发布一个需要数据模型更改的库版本,那么您必须等到数据模型更改合并后才能将 Neutron 固定到该库版本。这个过程应该是什么?

  • 答:理想情况下,模型更改是向后兼容的,但如果不是,那么,如概述,该过程仍然非常简单。

  • 问:什么是 distro 打包策略?例如,我们是否需要为厂商插件模块定义版本策略?例如,Kilo 的厂商插件模块应该有一个版本 2015.1.N?

  • 答:我们不需要为其他 python 依赖项定义 openstack 特定的版本,也不应该为插件/驱动程序依赖项库定义版本。我们可以依赖给定 Neutron 版本的插件/驱动程序中的要求文件,以权威地确定给定插件/驱动程序所需的库版本,并且可以根据需要更新稳定分支上的版本。

  • 问:似乎插件库维护者预计会为合适的 distro 提供打包。这是真的吗?

  • A: 就像今天分发版负责确定如何打包插件/驱动依赖项一样,在本次提案下它们将继续这样做。通过添加一个插件/驱动需求文件,可以更容易地确定当前需要手动发现的插件/驱动依赖项,从而简化它们的工作。这里的期望是插件业务逻辑将拥有自己的生命周期,位于 OpenStack 之外的库中。Neutron 与供应商库之间的关系将与 Neutron 与 sqlalchemy 之间的关系相同。因此,供应商库的版本控制可以按照任何方式进行。然而,插件本身仍然保留在主 neutron 仓库中,但会尽可能地最小化,使其仅成为一个桩。我们将继续为 openstack 2015.1 提供 Neutron “供应商 X” 插件。

  • Q: 我们如何处理 Oslo 集成?

  • A: 当发生 oslo 集成时,第三方 CI(以及插件/驱动维护者的内部测试)应该检测到插件/驱动外部依赖项中的任何破坏。我们可能希望在预计发生这些更改时进行通知,以便插件/驱动维护者能够及时响应并最大限度地减少作业失败的时间。只有当插件/驱动维护者对 Neutron 树中的破坏性更改完全没有响应时,这些更改才有可能一路推送到生产环境。如果维护者如此不响应,那么他们的插件包含在树中的可能性可能会受到质疑。这里的目标是减轻核心团队在解决这些类型问题时的一些维护负担。

  • Q: 我们如何确保 API 不会被更改和版本化?例如,如果 mixin 的内部方法被更新,那么覆盖或使用此方法的供应商可能会错过此更新。换句话说,我们没有稳定的 API,因此在当前模型中,可以通过一次性修复所有类型的补丁来防止破坏性更改。在这种情况下,我们如何处理这类问题?

  • A: 提案是在 Neutron 和供应商关注点之间保持尽可能严格的分离,并继续开发我们的测试套件以捕获(API 或其他)破坏性更改。只要插件/驱动维护者勤奋地跟进破坏性更改,本次提案的唯一变化将是修复破坏性更改的速度(一次性补丁与 Neutron 的一次性补丁 + 每个外部插件依赖项的一次性补丁)。破坏性更改的成本增加实际上可能是一件好事,如果它可以鼓励社区更加谨慎地提供更清晰的关注点分离(通过 API 或其他方式)。今天,集成的 gate 和非 gate 插件都会不时地出现故障;只要对问题做出迅速反应,我们认为该模型不会加剧这个问题。事实上,CI 正在变得更好,团队也越来越擅长发现并迅速修复这些问题;我们所需要的只是参与!

  • Q: 您能否详细说明一下新仓库的治理?至少需要 1 名维护者。最少需要多少成员?如果只有 1 名成员,他/她将提交、审查和合并自己的代码?

  • A: 本提案不强制执行任何类型的治理(甚至不通过仓库分发)给定的插件/驱动依赖库。我们将继续要求每个插件/驱动都有一个树内维护者/联系人,就像今天一样,该维护者将负责与树外开发协调。

  • Q: 以前,如果存在任何影响插件/驱动的更改,则会在所有受影响的代码路径中进行更改,以确保不会出现故障。但是,在拆分仓库的情况下,如何使第三方 CI 通过更改破坏供应商代码并需要在两个或多个仓库中进行更改?看起来我们需要在 Neutron 或供应商插件/驱动仓库中覆盖第三方 CI 投票?如果绝对需要覆盖,应该在哪里进行?

  • A: 第三方 CI 投票但不 gate,本次提案不会改变这一点。当破坏性更改降落在 Neutron 树中时,插件/驱动维护者将负责在自己的时间范围内解决破坏性更改。从短期来看,我们将通过外部化后端特定代码来引入协调开销,但从长远来看,这应该鼓励减少耦合,从而最大限度地降低这些成本。

  • Q: 我们如何定义某个供应商插件是 OpenStack 发布的一部分?我们来定义吗?由第三方测试集成定义吗?这在某种程度上与分发版打包策略有关。

  • A: 插件是否是给定发布的一部分的答案是:‘插件/驱动是否存在于 Neutron 树中?’。我们需要回答的问题是:‘在什么条件下允许插件/驱动位于树中?’。我们将不得不依靠关系管理(PTL <-> 插件/驱动维护者)和第三方 CI 来回答这个问题,本次提案不需要回答这个问题。一些插件已经依赖于所提出的模型的变体,并且似乎没有分发问题。

  • Q: 第三方 CI 结果是否应该发布到 Neutron 核心更改?我们需要定义第三方测试要求吗?

  • A: 如果他们认为更改可能会破坏他们的支持,他们可以选择这样做,但这今天已经发生了;无论本次提案如何,都需要澄清第三方 CI 要求。

  • Q: 本提案是否会使 ML2 Agent 不可行?

  • A: 不,努力开发 ML2 Agent 不是社区资源的最佳用途。由于历史原因,Neutron 已发展成为不仅是一个网络编排项目,还是一个类似于某些人所说的 SDN 控制器的参考实现。我们需要摆脱这种模式,因此,追求 ML2 Agent 不再可行。

  • Q: Linux Bridge 呢?

  • A: Linux Bridge 目前不是我们选择关注开发和测试的选项;维持其与 OVS 相当的水平的任何努力都需要识别和量化的资源。缺乏这些资源,Linux Bridge 已经落后,除非有人愿意赞助它,否则不会在重构工作中考虑它。

  • Q: 我们如何处理供应商库中 Neutron 特定的导入(例如,实用程序函数、常量、基本工件等)?

  • A: 实施插件/驱动后端特定交互的外部库预计会显式依赖 Neutron,以便它们可以引用诸如数据库模型、实用程序函数和常量之类的东西。由于 Neutron 对外部库的依赖关系不是显式的(插件/驱动需求文件不会被 pip 考虑),因此不会导致循环依赖。该模型将松散地遵循任何 OpenStack 项目在引用 Oslo 时所做的事情。在固定核心代码库的特定“快照”时,可以使用 git 哈希。该模型最终需要发展到核心和供应商特定内容之间进行更好的划分,从而使依赖性不太可能成为一个潜在的问题。

  • Q: 如果供应商库使用核心中定义的 API 呢?

  • A: 外部库可以通过依赖注入重用一些插件方法,这是一种花哨的说法,意思是“将插件的引用传递给需要调用其方法的代码”。

  • Q: 采用这种方法,打包者是否会忽略树中的某些插件,因为他们没有为其库制作软件包?

  • A: 在拆分之前,所有插件都被分发版“神奇地”打包,至少是它们的源代码。然后,打包者需要显式地添加“控制”规则,才能将各个部分与操作系统和/或配置管理工具集成,以反映各自配置文件中的配置选择。这并不一定认可平台上的供应商解决方案的有效性,但打包者别无选择,只能遵循此路线,以避免打包和分发悬空代码。使用这种方法,消耗实际源代码变得可选,供应商可以决定继续保留现有的打包模型,从各个来源提取。换句话说,这引发了一个问题,即所有分发版是否都应该考虑为明确与供应商建立关系协议的插件进行打包是否值得。每个分发版都有不同的内部流程来跟踪软件包和发布,因此分发版采取适当的措施以确保其销售和支持的 Neutron 解决方案的整体质量是合理的。我们应该强调,根据本次提案,从长远来看,一些插件可能会失去打包和商业版分发版的发行,但与此同时,开源倡议仍然可以不受影响地继续进行。

  • Q: 许多供应商特定的插件/驱动当前都在树中,这给人留下了供应商的新插件/驱动没有进入树中就“失败”的印象——“失败”有各种可能的含义,包括“不能保证与 OpenStack 协同工作,并且随着 OpenStack 的发展继续协同工作”,以及“未能证明与 OpenStack 社区的充分参与”。本次提案是否有助于解决代码贡献方面的这个问题?

  • A: 当然!首先,让我们明确一点:树内并不等同于成功,树外也不等同于失败。这是人们随着时间的推移而建立的一种看法,因为过去的事件导致了质量可疑的代码被删除或由于缺乏测试(最著名的是 Nova 中的 Hyper-V)。今天,现实完全不同,OpenStack 已经发展,第三方 CI 在建立基于 OpenStack 的云中所有组件的健全性方面发挥着基本作用。此外,通过本次提案,未能将新的供应商支持纳入树中的失败得到缓解,因为核心团队更容易完成检查清单中的步骤,以考虑供应商与 Neutron 集成,而无需被多次审查周期以将插件/驱动纳入树中的需要所困扰。

数据模型影响

N/A

REST API 影响

N/A

安全影响

N/A

通知影响

N/A

其他最终用户影响

从最终用户角度来看(与 Neutron API 交互的租户或管理员);这种方法对他们没有影响。

性能影响

N/A

IPv6 影响

N/A

其他部署者影响

A: 最小。根据 Neutron 的使用方式,部署者需要拉取一个额外的依赖项,即所选插件的供应商库。可以通过各种方式拉取此依赖项,无论是否获得部署者使用的操作系统/分发版的实际支持。

A: 值得一提的是,这种方法使分发版(尤其是打包者)能够更有效地集中资源。这意味着他们现在可以选择仅针对特定供应商解决方案进行打包。虽然这听起来可能是一步倒退,但自动打包的好处只是在整体 Neutron 解决方案没有支持性问题或供应商或分发版隐式验证的情况下给予了虚假的保证。任何客户都应该在采用 Neutron+后端组合时进行适当的尽职调查,如果他们选择通过两个不同的渠道访问整体 Neutron 解决方案,则应该这样做。本次提案不会阻碍此过程。

开发人员影响

A: 如本次提案中所述。

社区影响

A: 非常小,或者几乎没有从我们今天运营方式的重大偏差。事实上,我们认为这将对社区产生积极影响

  • A: 核心能够更快地迭代核心;

  • A: 更好的职责分离;

  • A: 供应商能够更快地迭代他们的插件;

备选方案

A: 可以探索替代方案,有或没有工具辅助

  • A: 增加 Neutron 核心数量 (1)

    A: 我们可以允许每个供应商拥有核心审查者,以便他们只能批准自己的代码(即子树委托)。这提出了一系列有趣的挑战

    • A: 我们如何处理新贡献者?

    • A: 核心开发人员到底是什么意思?

    • A: 我们如何确保代码审查的一致标准?

  • A: Neutron 核心的橡皮图章 (2)

    A: Neutron 核心可能会成为文书工作者,并盲目批准仅与特定供应商相关的更改。这提出了一系列有趣的挑战

    • A: 我们如何确保不会忽视跨领域问题?

    • A: 我们如何确保供应商维护者仍然要对其负责?

  • A: 采用源代码树的不同分解

    A: 现有的源代码树可以分解为单独的仓库

    • A: 一个仓库托管核心元素(DB、API、RPC 等)和当前 gate 的完全开源 L2/L3 API 实现;

    • A: 一个仓库用于每个贡献了一个或多个(单体)插件的供应商;

    • A: 一个仓库用于所有 ML2 机制驱动程序;贡献了单体插件和 ML2 驱动程序的供应商应决定 ML2 驱动程序需要属于哪个仓库;

    A: 理想情况下,这是最有意义的分解,如果不是受到我们所受到的政治和社会规则的约束的话。换句话说,从纯软件开发角度来看,这种分解最有意义,可以通过技术解决方案克服对这种方法的任何反对意见。也就是说,在单个发布周期内追求这种方法可能太难了。在代码库经过此初始转换和其他努力(例如,高级服务分离、API 重构等)完成后,可以在一个发布周期后重新评估这种方法。

  • A: 使用 git 子模块来分解源代码树

    OpenStack Infra 强烈不建议这样做,因为管理 git 子模块会带来复杂性:这不仅会给 CI 工具增加潜在的复杂性,而且几乎与使用单独的仓库没有区别,因此也无法解决使用单独仓库时提出的任何问题。

  • 使用特性分支

    可以通过使用长期分支来实现(类似于 Linux 内核模型,其中子团队维护者拥有自己的分支)。 短期分支不太适合表示插件/驱动程序的生命周期。 尽管特性分支的一个优点是可以拥有不同的 ACL,从而让不同的人群获得 +2/+W 权限,但这种方法的缺点是它不利于系统各个部分之间的清晰分离和责任划分。 换句话说,如果我们有这些实体之间的稳定接口,使用特性分支就不会比将这些实体放在不同的仓库中提供任何好处。

评论

虽然方法 1 和 2 可能有助于解决变更速度,但最终可能会导致代码库的不稳定性增加,它们不利于创建更清晰的接口,并且会给需要处理更大、更大的代码库的 Neutron 团队增加负担。 换句话说,虽然这些方法在短期内可能看起来合理,但它们可能会在长期内严重影响项目。

实现

负责人

对于参考实现重构,代码和测试重组

  • Armando Migliaccio

  • Maru Newby

有关此提案在实践中如何发展示例

  • Kevin Benton (Big Switch)

  • Doug Wiegley (A10)

  • Kyle Mestery (OpenDayLight ML2 Mech Driver)

  • Yamamoto Takashi (ofagent)

  • Gary Kotton (VMware)

  • <在此处添加您的姓名>

对于希望率先采用此模型的新的插件/驱动程序

  • Sandhya Dasu (Cisco UCS Manager ML2 mech driver)

  • Vivekanandan Narasimhan (OVSvApp [12, 13])

  • <在此处添加您的姓名>

工作项

  • 宣布新的策略和现有插件/驱动程序的弃用时间表;

  • 以类似的方式分离参考实现,但将代码保留在树中(ML2 OVS mech driver + L3 服务 pluign 与 l3-agent,这是它目前被限制的原因);这至关重要,以便完善任何剩余的技术细节,并为供应商代码维护者在自己的代码中效仿铺平道路。

    • 插件成为与 neutron/reference_code 中大量代码集成的切入点。

  • 每个供应商建议的工作项

    • 设置一个仓库来托管供应商库(stackforge 有用,因为它提供 jenkins 集成);stackforge 不强制对供应商进行命名约定,但是,如果选择 stackforge 路线,供应商应避免使用明确引用 Neutron 的仓库名称:这可以保护供应商,以防出现新的命名问题(有人还记得 Quantum 命名的混乱吗?),并且允许供应商可以自由地将相同的 Python 绑定定位到潜在的不同 CMS;

    • 设置新仓库中的代码:值得注意的是,如果代码是从 neutron core 复制到这些驱动程序中,git subtree 工具可以在此操作中保留历史记录。 OpenStack infra 正在对 puppet 模块执行类似的操作 [11];

    • 设置单元测试;

    • 将代码发布到 pypi;

    • 更改 neutron 驱动程序/插件以导入 pypi 模块并删除所有供应商内部逻辑;

依赖项

N/A

测试

有关更多详细信息,请参阅测试策略部分。

Tempest 测试

N/A

功能测试

N/A

API 测试

N/A

文档影响

有关更多详细信息,请参阅文档策略部分。

用户文档

在采用此提案后,Neutron 系统的整体功能不会发生变化。 从用户角度来看,一旦系统部署、配置并启动运行,就无法察觉任何差异。 但是,已经记录了另一个相关的提案 [15]。 运营商预计将遵循文档和/或由 Upstream OpenStack 文档提供的外部引用指针,以了解如何安装和配置系统以使用特定的插件和驱动程序。

开发人员文档

这里没有提出任何 API 更改,因此提供插件/驱动程序贡献指南就足够了。 此提案已经广泛概述了其中涉及的一些工作,并将用作树内开发人员文档的基础。

参考资料