将共享组添加到 Manila¶
蓝图:https://blueprints.launchpad.net/manila/+spec/manila-share-groups
Manila 需要一种分组结构,就像共享一样,是一种一级原子数据类型。我们使用 CG 的经验表明,添加分组能力会带来复杂性,但还有其他用例,例如迁移、复制和备份,在这些用例中,某些存储控制器只能对共享组提供这些功能。CG 还突出了高级功能的不良前景,与供应商支持的潜力相比微乎其微。并且为每个新功能添加新的分组结构在技术上不可行。以上所有问题都可以通过共享组来解决,我们认为这是对 Manila 原始架构的干净扩展。
问题描述¶
Manila 处于其发展的一个令人兴奋的时刻,所有简单的功能都可用,社区专注于添加高价值的功能,例如迁移、复制和一致性组。这些功能都有实验代码可用,但很少考虑这些复杂功能不仅要相互交互,还要与以后添加的任何其他功能进行交互的明显需求。更深入地看,很明显,这些功能中的每一个都有局限性,可以通过单个架构增强来解决。
一致性组¶
一致性组 (CG) 是 Manila 中当前唯一对共享组进行操作的结构。对于某些人来说,CG 意味着存储控制器保证有序写入,而对于其他人来说,CG 是一种在特定时间点对一组共享进行一致快照的机制。具有任一属性的组本身可能具有价值,但 CG 的实现并未区分它们。
CG 是一种高度专业化的结构,具有专用的 CLI 命令、REST API、数据库表、调度器过滤器和驱动程序 API,总共超过 9900 行。这些都不是可用于其他用途的,并且 Manila 的其余部分都没有对 CG 的任何了解。更糟糕的是,尽管 CG 功能非常复杂,但只有少数存储后端可以支持它们,因此代码价值比非常低,并且 CG 的可用性有限确保了云之间的用户体验不一致。
复制¶
复制是另一个高价值功能,Manila 的实现可以说是干净且灵活的,但目前没有核心能力来复制一组共享。迭代地实现此功能似乎是合理的,从复制单个共享开始。但是,一直以来都 tacitly 承认,某些后端可能无法复制单个共享,即使这些后端如果以某种方式构成组,则有可能复制一组共享。
建议的方法是使用组额外规格来规定组中的共享是按一致方式复制、单独复制还是都不复制。
迁移¶
就像某些后端可能只能以组的形式复制共享一样,可以推断出这些后端也可能需要以组的形式迁移共享。并且在 CG 的情况下,单独迁移 CG 成员没有意义;必须移动整个组,这需要迁移引擎了解 CG。
用例¶
考虑以下合理的用例
复制一致性组
对一致性组进行快照
对复制组进行快照
迁移复制组
重定型一致性组中的共享
重定型复制组中的共享
备份一致性组
备份复制组
在当前路径上,支持矩阵有一个专门用于功能的维度,因此每个功能都必须被编码为与每个其他功能互操作。这很快就会变成支持和测试噩梦,并且添加更多功能会变得呈指数级复杂。
从根本上说,问题在于我们在没有底层架构框架的情况下添加功能。为了摆脱矩阵,我们必须退一步并重新思考一些事情。
提议的变更¶
因此,为了找到解决方案,让我们列举一下我们所拥有的
具有受共享类型控制的支持操作的原始对象(共享),这些共享类型因后端而异
一个非常具体的组对象 (CG),后端支持有限
许多用户根本无法使用的 API(CG 等),并且似乎被移植到项目中
我们希望拥有什么
一个统一的 API 和用户体验,无论后端如何变化都尽可能少
一种干净的方式来分组共享,以便我们可以执行 CG、多对象复制、迁移等。
我们如何到达那里?
具有受后端控制的支持操作的原始对象的通用可用组
共享组¶
就像 Manila 有“共享”一样,它也应该有“共享组”。与 CG 不同,最简单的形式下,共享组不应保证任何专门的操作。相反,它应该仅仅构成一个原子 Manila 数据类型,几乎任何 Manila 操作都可以在其上使用。例如,给定一个共享组,用户应该能够在 Manila UI 中选择该组并调用诸如快照、克隆、备份、迁移、复制、重定型等功能。共享只能在共享创建步骤上成为共享组的一部分。如果共享是在没有提供“share_group_id”的情况下创建的,则该共享将无法成为任何共享组的一部分。为此,您需要使用“共享迁移”功能。如果共享是作为组的一部分创建的,则只有在迁移或删除时才能将其移出组。
在一般情况下,组操作由通用的共享驱动程序超类处理。例如,在组上调用“快照”会导致共享管理器对每个组成员单独进行快照。生成的组快照对象可用于创建新组,类似于 CG 快照的实现方式。
这种方法有很多优点。无论多么不成熟,每个驱动程序都可以利用组的可管理性优势。用户体验是统一的,因为无论存在哪些后端,组始终可用,并且几乎 Manila 上可用的所有操作都可用于组。
当然,功能丰富的后端希望添加他们的秘诀,无论是 CG、基于组的复制还是可能更容易/更便宜/更快地对共享组执行的任何其他操作。这给我们带来了一个相关的想法。
共享组类型¶
就像 Manila 有“共享类型”一样,它也应该有“共享组类型”。任何可以以优势方式执行组操作的驱动程序都可以将其报告为组功能,例如
有序写入
一致的快照
组复制
组备份
与共享类型一样,云管理员预定义共享组类型,这些类型可以包含与后端报告的组功能相对应的组规格。管理员还指定给定组类型可以包含哪些共享类型。如果管理员未指定,Manila 将使用“默认”共享类型。然后,调度器将在匹配指定共享类型和共享组类型的后端之一上创建组。
当组操作(例如“快照”)进入共享管理器时,管理器会检查其驱动程序是否提供该操作的优势实现。如果不是,则管理器将自行处理工作流程,如上所述。但是,如果是,则管理器会将工作流程路由到其驱动程序以完成。
这种方法的优点显而易见。开发和测试得到了简化,因为不需要为每个功能定义和测试一组不同的组管理 API,也不需要测试每个功能的每种组合。Manila 不再成为相互交互的 N-by-N 矩阵,而变成了 N-by-2 矩阵,这些矩阵可以在单个共享或共享组上调用操作。
共享操作 |
共享组操作 |
|---|---|
创建(共享类型) |
创建(共享类型、组类型) |
删除 |
删除(组) |
快照 |
快照(可能或可能不是“CG”快照) |
从快照创建 |
从组快照创建 |
克隆 |
克隆组(及其所有成员)(计划中) |
复制 |
复制 |
备份 |
备份(计划中) |
重定型 |
重定型(计划中) |
迁移 |
迁移 |
扩展/缩小 |
N/A |
详情¶
需要注意几点,其中一些已经在 CG 工作中解决了。
组是 Manila 中的一级对象,并且对组的操作被视为原子操作。为了尽可能地支持更多后端,Manila 仍然会为组和成员快照维护 DB 对象,就像 CG 一样。
组的功能都将是公共组规格,类似于共享类型中的 snapshot_support。用户需要知道组能做什么,工具(如 manila-ui)也需要知道。
组配额以后可以添加并使用单独的规格进行描述。它们不在此规格的范围内,因为此规格主要涉及将 CG 移植到共享组,而 CG 还没有配额实现。
需要注意的是,某些操作,例如扩展和缩小,仅固有地适用于单个共享。理论上可以将扩展应用于组,从而增加每个成员的大小,但这最初不会涵盖用例。此类操作必须始终可用于组成员,并且可以允许对组成员进行快照等操作,但迁移或复制等操作仅在组级别可用,而不是在其成员上。
组限制为单个后端。允许跨后端的组在理论上是可行的,但这需要从 API 层到异步事件总线上的多个共享管理器的操作扇出,这将导致复杂的状态管理和同步,而带来的运营收益却很少。
与 Manila CG 一样,驱动程序可以选择将组限制在池或整个后端的范围内。我们认为驱动程序需要这种灵活性,因为池是某些后端的数据移动单元(即复制或迁移)。
与 CG 一致,分组共享必须在其整个生命周期内保持在组中。在创建/删除时间之外,添加或从组中删除共享对于某些后端可能是可行的,而其他后端可能需要移动数据。迁移引擎被设想为将共享移动到或移出组的手段。
我们还考虑过将共享类型用于组。但是,共享类型包含一组可能不适合组的公共额外规格。并且通过添加组类型作为单独的对象,可以减少对其目的和用途的混淆。
调度器将多个额外规格视为 AND 操作,其中所有功能都必须可用于后端才能被选择。即使后端可以复制组或对组进行一致的快照,它可能无法在同一组上执行这两个操作。但是,这个问题已经存在于共享类型中,并且没有成为严重的问题。创建类型是仅管理员操作,并且管理员有责任了解正在使用的后端的capabilities,并相应地创建共享类型和共享组类型。
请注意,此提案明确不涉及池或后端复制,这在根本上是不同的。对共享或共享组的操作是为租户设计的,而池或后端可以包含来自多个租户的数据。因此,池或后端操作虽然可能提供有价值的用例,但本质上是仅管理员的工作流程,这些工作流程将以不同的方式设计和执行。
备选方案¶
一种可能的替代方案是直接删除 CG。优点是简化了代码库,缺点是失去了功能。
另一种替代方案是保留已实现的 CG,并根据需要添加其他组用于复制等。如上所述,缺点是复杂性增加、代码库更大以及用户体验不一致。
可以使用标签添加一个更高层次、更松散的关联结构,这将允许重叠的成员资格以及多个后端中的成员,但这将排除此功能寻求的功能,该功能仅适用于单个后端上的共享。基于标签的关联以后可以作为并行功能添加。
数据模型影响¶
组的数据模型应与 CG 几乎相同。事实上,通用的共享组取代了 CG,因此 CG 表将被共享组的表替换。
组类型的数据模型应与共享类型几乎相同,并包含允许组类型使用的共享类型列表。
REST API 影响¶
设计一个REST API,可以无缝处理共享和共享组,而无需大量重复的API。但就目前Manila的发展阶段而言,彻底重新设计API可能为时已晚。
有可能重载一些现有的API来处理共享和共享组。例如,POST /shares/{id}/action 可以接受共享或共享组的ID,并执行正确的操作。但其他API,例如GET /shares,重载不太实用,因为单个端点将返回不同类型的对象。
似乎最好只是根据需要复制一些带有组版本的API。例如
POST /shares –> POST /share-groups
POST /shares/{share_id}/action –> POST /share-groups/{group_id}/action
POST /snapshots –> POST /share-group-snapshots
共享组API
创建共享组
URL: /share-groups
方法:POST
JSON body
{ 'share_group': { 'name': 'fake_name', 'description': 'fake_description', 'availability_zone': 'fake_az', 'group_type_id': 'fake_group_type_id', 'share_network_id': 'fake_sn_id', 'source_group_snapshot_id': 'fake_snap_id', 'source_group_backup_id': 'fake_backup_id', 'source_group_clone_id': 'fake_clone_id', 'share_types': ['fake_st_id_1', 'fake_st_id_2', 'fake_st_id_n'] } }
注意:只有在Manila出现相应功能时,才会实现 ‘source_group_backup_id’ 和 ‘source_group_clone_id’ 键。
列出共享组
URL: /share-groups
方法:GET
URL 参数
all_tenants - 整数,0或1
offset - 整数,0或更大
limit - 整数,1或更大
sort_key - 字符串,要排序的键(例如 ‘created_at’ 或 ‘status’)
sort_dir - 字符串,排序方向,应该是 ‘asc’ 或 ‘desc’。
列出共享组(详细)
URL: /share-groups/detail
方法:GET
URL 参数
all_tenants - 整数,0或1
offset - 整数,0或更大
limit - 整数,1或更大
sort_key - 字符串,要排序的键(例如 ‘created_at’ 或 ‘status’)
sort_dir - 字符串,排序方向,应该是 ‘asc’ 或 ‘desc’。
显示共享组
URL: /share-groups/{share_group_id}
方法:GET
删除共享组
URL: /share-groups/{share_group_id}
方法:DELETE
注意:只有在共享组不包含任何共享时,才能删除共享组。
强制删除共享组
URL: /share-groups/{share_group_id}/action
方法:POST
JSON body
{ 'force_delete': None }
注意:这是一个仅限管理员的API。此命令与通用的 ‘delete’ 命令之间的区别在于,它忽略状态和引发的异常。
重置共享组状态
URL: /share-groups/{share_group_id}/action
方法:POST
JSON body
{ 'reset_status': '%status%' }
注意:这是一个仅限管理员的API。
更新共享组
URL: /share-groups/{share_group_id}/action
方法:POST
JSON body
{ 'share_group': { 'name': 'new_name', 'description': 'new description' } }
共享组快照API
创建共享组快照
URL: /share-group-snapshots
方法:POST
JSON body
{ 'share_group_snapshot': { 'name': 'fake_name', 'description': 'fake_description', 'share_group_id': 'fake_share_group_id' } }
显示共享组快照
URL: /share-group-snapshots/{share_group_snapshot_id}
方法:GET
列出共享组快照
URL: /share-group-snapshots
方法:GET
URL 参数
offset - 整数,0或更大
limit - 整数,1或更大
sort_key - 字符串,要排序的键(例如 ‘created_at’ 或 ‘status’)
sort_dir - 字符串,排序方向,应该是 ‘asc’ 或 ‘desc’。
列出共享组快照(详细)
URL: /share-group-snapshots/detail
方法:GET
URL 参数
offset - 整数,0或更大
limit - 整数,1或更大
sort_key - 字符串,要排序的键(例如 ‘created_at’ 或 ‘status’)
sort_dir - 字符串,排序方向,应该是 ‘asc’ 或 ‘desc’。
删除共享组快照
URL: /share-group-snapshots/{share_group_snapshot_id}
方法:DELETE
强制删除共享组快照
URL: /share-group-snapshots/{share_group_snapshot_id}/action
方法:POST
JSON body
{ 'force_delete': None }
注意:这是一个仅限管理员的API。此命令与通用的 ‘delete’ 命令之间的区别在于,它忽略状态和引发的异常。
重置共享组快照状态
URL: /share-group-snapshots/{share_group_snapshot_id}/action
方法:POST
JSON body
{ 'reset_status': '%status%' }
注意:这是一个仅限管理员的API。
更新共享组快照
URL: /share-group-snapshots/{share_group_snapshot_id}/action
方法:POST
JSON body
{ 'share_group_snapshot': { 'name': 'new_name', 'description': 'new description' } }
共享组类型API
创建共享组类型
URL: /share-group-types
方法:POST
JSON body
{ 'share_group_type': { 'name': '%name%', 'is_public': '%boolean%', 'group_specs': { 'foo_key': 'foo_value', 'bar_key': 'bar_value' }, 'share_types': [ 'fake_share_type_id_1', 'fake_share_type_id_2', '..', 'fake_share_type_id_n', ] } }
显示共享组类型
URL: /share-group-types/{share_group_type_id}
方法:GET
设置共享组类型规范
URL: /share-group-types/{share_type_id}/group-specs
方法:POST
JSON body
{ 'group_specs': { 'driver_handles_share_servers': True, 'snapshot_support': True, 'storage_protocol': 'NFS' } }
取消设置共享组类型规范
URL: /share-group-types/{share_group_type_id}/group-specs/{group_spec}
方法:DELETE
列出共享组类型规范
URL: /share-group-types/{share_group_type_id}/group-specs
方法:GET
列出共享组类型
URL: /share-group-types
方法:GET
URL 参数
is_public - 字符串,包含类似布尔值或 ‘all’。它的行为与 ‘列出共享类型’ API 中的行为相同。如果未设置或设置为 True,则管理员/用户仅看到公共共享组类型。如果设置为 False,则管理员仅看到私有共享组类型,而用户仅看到允许用户项目的那些私有共享组类型。如果设置为 ‘all’,则管理员看到所有共享组类型,而用户看到所有类型,除了允许用户项目的那些私有共享组类型。
删除共享组类型
URL: /share-group-types/{share_group_type_id}
方法:DELETE
共享组类型访问API
将项目添加到访问列表
URL: /share-group-types/{share_group_type_id}/action
方法:POST
JSON body
{ 'addProjectAccess': { 'project': '%project_id%' } }
注意:仅适用于私有组类型
从访问列表中删除项目
URL: /share-group-types/{share_group_type_id}/action
方法:POST
JSON body
{ 'removeProjectAccess': { 'project': '%project_id%' } }
注意:仅适用于私有组类型
列出允许的项目
URL: /share-group-types/{share_group_type_id}/group-type-access
方法:GET
注意:仅适用于私有组类型
对现有 ‘创建共享’ API 的更改
将添加一个新的可选 ‘share_group_id’ 参数。
对现有 ‘删除共享’ API 的更改
当共享是共享组的一部分时,URL 中将需要 ‘share_group_id’ 参数作为 GET 参数。
共享组API 最初将是实验性的。
安全影响¶
无
通知影响¶
无
其他最终用户影响¶
Manila客户端、CLI 和 GUI 最终应扩展以支持共享组,理想情况下全部在Ocata中。客户端和 CLI 将首先更新,通过删除 CG 命令并添加组命令,以启用 Tempest 覆盖。
性能影响¶
如果共享管理器必须遍历多个单独的共享,组操作可能需要更长的时间,并且驱动程序和存储后端必须能够处理这些请求。否则,性能应与现有的一致性组实现相当。
其他部署者影响¶
共享组功能是可选的,如果部署者不需要它,可以忽略它。此外,他们可以使用 policy.json 文件禁用所有组相关的API。
如果使用组,管理员必须定义组类型,并确保他们的云支持他们宣传的组/共享类型组合。
开发人员影响¶
此功能的目标之一是简化 Manila 的维护和开发。新的功能作者必须确保任何新功能都适用于组以及单个共享(可能以分阶段实施的方式)。驱动程序作者如果可能,应该考虑以优势方式支持其存储系统中的组操作,而通用实现将尝试使用现有驱动程序进行工作。
实现¶
负责人¶
主要负责人
alex-meade
其他贡献者
clintonk
dustin-schoenbrun
vponomaryov
工作项¶
在Manila中实现通用组应该是一个简单的步骤系列
实现通用组。因为我们已经做了 CG,所以我们已经知道代码库的哪些部分必须更改才能支持任何类型的组。因此,最简单的方法是修改 CG 代码将其转换为通用组功能。
通过复制和自定义共享类型代码来添加共享组类型功能。
增强调度器以根据共享组类型放置组。与 #1 类似,这已经由 CG 项目告知。
在共享管理器中实现组快照,以演示任何驱动程序中的组快照。
将组快照连接到 CG 兼容的驱动程序,以演示新框架中的 CG 功能。
更新 Tempest 以涵盖以上所有内容。
为 manila 客户端添加功能测试。
将共享组驱动程序接口的支持添加到虚拟驱动程序。
更新 Manila 客户端将 CG 更改为共享组。
增强 Manila 客户端的共享组类型。
将共享组支持添加到 manila-ui。我们从未在 UI 中构建 CG 支持,所以所有这些新工作现在具有更广泛的吸引力和适用性。它应该是可选的,但默认情况下启用,就像共享迁移和复制功能支持一样。
随着时间的推移添加额外的组操作(迁移、复制、重新类型化、克隆等)。此时,新的组功能成为易于增量添加的垂直切片。
因为我们最近将 CG 作为实验性功能实现,所以我们可以自由地替换代码而无需弃用或升级考虑。步骤 1-8 将使 Manila 与 Liberty 中添加的 CG 功能达到平价,只需要几周的人力,并能更好地为 Manila 的长期演进和可维护性做好准备。
依赖项¶
无
测试¶
因为共享组不需要显式的驱动程序支持,所以应该可以使用 Tempest 测试在网关中完全测试。由于此功能在 Ocata 中的最小可行产品与 CG 的功能相当,因此现有的 CG 测试应该可以适应共享组。Manilaclient 测试将从头开始编写,因为现在没有 CG 测试。
文档影响¶
共享组是一项主要功能,应该完全记录。至少,用户指南、管理员指南、树内 API 参考和树内开发参考必须涵盖,就像到目前为止的其他实验性功能一样。