默认卷类型覆盖

https://blueprints.launchpad.net/cinder/+spec/multiple-default-volume-types

Cinder 当前的默认卷类型选项有限,对于大型和/或复杂的部署而言不足。

本规范建议添加每个项目的卷类型。

问题描述

在大型和/或复杂的 OpenStack 部署中,我们可能拥有多个可用区 (AZ) 和许多项目,从而增加了正确构建和管理资源复杂性。

当拥有多个 AZ 时遇到的问题之一是,我们通常希望我们的项目拥有位于同一 AZ 内的卷和实例,但我们只能定义一个默认卷类型,迫使我们的用户始终记住使用具有 AZ 定义的卷类型创建卷(如果存在),或者显式传递 AZ。

这种做法容易出错,用户忘记它会导致不希望的跨 AZ 附加,从而导致性能问题和网络吞吐量成本。

目前,用户正在采用 2 种解决方法来缓解这种情况

  • 禁用 Nova 中的跨 AZ 附加:对于不想执行跨 AZ 实例实时迁移的部署,他们可以在 Nova 中禁用跨 AZ 附加,以便附加到实例失败,从而防止运行的 VM 上出现性能问题。此解决方案通常迫使用户在正确的 AZ 中重新创建卷。

  • 不可用的默认卷类型:设置一个具有明确名称的默认卷类型,例如 *Need_To_Select_Volume_Type*,并以一种导致调度失败并将卷置于错误状态的方式进行设置。这种方法浪费较少,但仍然不是一个好的用户体验。

本规范解决了这个问题。

用例

  1. 在一个跨多个数据中心展开的全国范围内的 OpenStack 部署中,每个数据中心都有自己的存储阵列和 OpenStack 项目,管理员希望确保卷默认在自己的数据中心中创建。为此,管理员定义了一个具有适当额外规格的每个项目的默认卷类型。

  2. 在具有 3 种不同卷类型(高性能、复制、压缩)的 OpenStack 部署中,不同的部门(每个部门都有一个不同的项目)有不同的要求,因此系统管理员希望将不同的 OpenStack 卷类型分配给每个部门。

提议的变更

该建议是添加在项目基础上覆盖现有的 Cinder 默认卷类型,以便更轻松地管理复杂的部署。

随着此新的默认卷类型配置的引入,现在我们将拥有 2 种不同的默认卷类型。从更具体到更通用,它们是

  • 每个项目

  • 在 cinder.conf 中定义(默认为 *__DEFAULT__* 类型)

因此,当用户创建没有定义卷类型(显式或在源中)的新卷时,Cinder 将首先通过检查特定项目是否定义了数据库中的一个来查找适当的默认值,并使用它。如果未定义,它将像今天一样继续使用 cinder.conf 中的默认类型。

管理员和用户在创建卷时仍然需要小心 Cinder 的正常行为,因为 Cinder 仅在用户未在请求中选择一个或源中没有卷类型时才会使用默认卷类型。这意味着如果我们在

  • 提供卷类型创建卷

  • 从快照创建卷

  • 克隆卷

  • 从具有 cinder_img_volume_type 定义在元数据中的镜像创建卷

默认情况下,限制访问设置、取消设置、获取或列出所有项目默认卷类型的策略将设置为仅限系统管理员。

备选方案

另一种选择是在每个用户和每个项目的基础上以及全局范围内允许设置默认卷类型覆盖。

这种替代方案已被放弃,鉴于实施所需的额外复杂性和工作量,提供的收益非常有限,因为可配置的每个用户和全局默认卷类型似乎不是用户的必要条件。

数据模型影响

我们将添加一个名为 default_volume_type 的新表,该表将具有 3 个字段

  • id 主整数键。

  • volume_type_id 长度为 36 的外键字符串。

  • project_id 字符串。

我们不会重用现有的 volume_type_projects 表并添加一个 is_default 字段,因为当我们更新或删除它们时,私有/公共卷类型和默认值的组合会变得复杂。

在数据库迁移方面,我们只需要创建表。

REST API 影响

我们需要一组新的 REST API 调用来提供 CRUD 操作

  • 为特定项目设置默认卷类型(创建或更新)。

    除了确保卷类型存在并且项目可以访问它之外,此方法还将调用 keystone 以验证项目是否存在。

    • PUT /v3/default-types/{project_id}

      • 用于设置项目默认类型(按名称或 ID)的 JSON 正文

        {
          "volume_type": "lvm"
        }
        
      • 响应代码
        • 成功 - 200(带有正文)

          {
            "project_id": "248592b4-a6da-4c4c-abe0-9d8dbe0b74b4",
            "type_id": "f8a82360-0b1a-4649-8615-114341dd06e0"
          }
          
        • 错误 - 400(未找到卷类型),404(未找到项目 ID)

  • 取消设置默认卷类型。如果给定项目没有默认卷类型或项目不再存在于 keystone 中,则会失败。

    • DELETE /v3/default-types/{project_id}

      • 响应代码:- 成功 - 204 - 错误 - 404(未找到项目 ID)

  • 获取卷类型

    • 显示项目的默认类型 GET /v3/default-types/{project_id}

      • 带有 project_id 的请求将返回一个 JSON 对象,其中包含指定项目的 project_id 和 type_id。如果数据库中不存在该条目,则无论项目是否存在于 keystone 中,都将返回 404 错误代码。

        {
          "project_id": "248592b4-a6da-4c4c-abe0-9d8dbe0b74b4",
          "type_id": "f8a82360-0b1a-4649-8615-114341dd06e0"
        }
        
      • 响应代码:- 成功 - 200(带有正文)- 错误 - 404(未找到项目 ID 或没有默认类型)

    • 列出所有默认类型 GET /v3/default-types

      • 没有 project_id 的请求将返回所有定义的卷类型默认值。示例响应如下

        [
            {
              "project_id": "248592b4-a6da-4c4c-abe0-9d8dbe0b74b4",
              "type_id": "f8a82360-0b1a-4649-8615-114341dd06e0"
            },
            {
              "project_id": "1234567-4c4c-abcd-abe0-1a2b3c4d5e6ff",
              "type_id": "5c4df055-571e-4430-9823-416b82f337b2"
            }
        ]
        
      • 响应代码:- 成功 - 200(带有正文)

        请注意,我们仅列出覆盖,我们不会返回 default_volume_type 的值。

用户可以使用现有的 cinder type-default 命令获取其有效的默认类型:GET /v3/{project_id}/types/default

安全影响

Active/Active HA 影响

通知影响

其他最终用户影响

将在 python-cinderclient 中添加一组新的命令来匹配新的 REST API 端点

  • 设置默认值:cinder default-type-set <type-name> <project-id>

  • 取消设置默认值:cinder default-type-unset <project-id>

  • 列出默认值:cinder default-type-list [--project <project-id>]

性能影响

创建不定义默认卷类型(显式或通过源)的卷操作将产生很小的性能影响,因为我们将添加一个数据库查询来获取默认值。

其他部署者影响

开发人员影响

我们不应在整个代码中直接引用 default_volume_type 配置选项,而应使用 cinder.volume.volume_types 中的 get_default_volume_type 方法。

实现

负责人

主要负责人

<whoami-rajat>

工作项

  • Cinder 服务

    • 检查调用者是否有权执行操作:首先,我们将检查常规策略以查看它是否是系统管理员等,然后我们将不得不检查项目,并且仅当调用者的上下文具有系统范围时,我们才会授权该操作。

      为此,我们引入了一个新的策略来检查调用者是否是系统管理员,然后利用 cinder.quota_utils 中的 get_project_hierarchy 方法来验证项目是否实际存在(因为该方法执行项目的 get)。

    • 添加 DB 字段和 DB 迁移。

    • 添加 3 个 DB 层方法

      • 设置默认卷类型:给定卷类型 ID 和项目 ID,此方法设置其默认卷类型。

        它将尝试更新 volume_type_id 用于 project_id,如果由于该行不存在而失败,则将创建 DB 行。

      • 取消设置默认卷类型:这将设置 deleteddeleted_at 字段用于 project_id。如果由于它不存在而失败,则不会传播该失败,并将其视为成功。

      • 获取项目默认卷类型:返回受 project_id 限制的项目和卷类型 ID 列表(如果提供)。

    • 更新 get_default_volume_type 以返回当前项目的有效卷类型。基本上调用 DB 方法 *get project default type*,如果它返回 None,我们将继续使用当前的代码来使用配置中的那个。

    • 更新卷类型方法以确保我们不会尝试删除用作默认值的卷类型,并确保我们不会将项目用作默认值的卷类型设置为私有,以及此类操作。

    • 确保 purge_deleted_rowscinder.db.sqlalchemy.api 正常工作。

    • 添加一个新的 API 微版本并实现 4 个 REST API 方法。

    • 编写 DB 方法、REST API 方法的适当单元测试,并更新现有测试以进行我们引入的更改。

  • Cinder 客户端:添加 其他最终用户影响 部分中提到的 3 个命令。

  • Tempest 测试:添加 Tempest 测试,如 测试 部分所述。

  • 文档,如 文档影响 部分所述。

依赖项

测试

除了编写 DB 方法、REST API 方法的适当单元测试,并更新现有测试以进行我们引入的更改之外,我们还需要一系列 Tempest 测试来测试现有功能。

  • 确认默认类型的优先级被观察到

    • 管理员创建一个自定义卷类型并将其设置为项目的默认值

    • 使用普通用户创建一个空卷,并检查卷类型是我们创建的那个,然后删除它。

    • 使用管理员用户创建另一个卷,并查看它是否以相同的方式工作。

    • 使用替代项目管理员用户创建一个空卷,并确认它不使用我们的自定义卷类型。

    • 取消设置我们在步骤 1 中设置的自定义卷类型。

    • 创建一个空卷并检查卷类型不是自定义类型。

  • 确认 cinder type-default 正常工作

    • 管理员确认对于项目和替代项目没有默认覆盖。

    • 获取使用 type-default 的当前默认值。

    • 创建 2 个自定义卷类型:#1 和 #2

    • 将默认卷类型 #1 设置为项目,将 #2 设置为替代项目。

    • 请求两种项目的类型默认值,并确认我们获得刚刚设置的类型。

    • 取消设置自定义卷类型。

    • 获取使用 type-default 的当前默认值,并确认它与步骤 2 相同。

  • 确认列出/显示默认类型覆盖正常工作

    • 管理员确认对于项目没有默认覆盖,首先列出 default-types,然后通过显示项目的默认类型(我们将获得 404),对于普通项目和替代项目。

    • 创建 2 个自定义卷类型:#1 和 #2

    • 将默认卷类型 #1 设置为项目,将 #2 设置为替代项目。

    • 管理员列出所有默认卷类型并验证它们。

    • 管理员获取项目的默认卷类型并确认它仅获取该类型。

    • 对替代项目重复前两个步骤。

    • 取消设置默认类型。

    • 确认默认类型列表返回空列表。

    • 确认显示项目 ID 的默认值返回 404。

    • 显示假的 project ID 并确认我们获得 404 错误代码。

文档影响

将在管理部分添加默认卷类型覆盖行为的描述,例如在路径 doc/source/admin/default-volume-types.rst 上。

此文件将链接到 doc/source/admin/index.rstdoc/source/configuration/index.rst,因为它既是配置的一部分,也是一项管理任务。

将在 doc/source/cli/cli-manage-volumes.rst 中列出并解释新的 CLI 命令,并提供新 CLI 命令的示例。

此外,还需要在 api-ref/source/v3/default-volume-types.inc 中记录新的 REST API 调用,并在 api-ref/source/v3/samples 中添加样本。

并且需要在 cinder/api/openstack/rest_api_version_history.rst 中更新微版本历史记录。

参考资料