Cinder Nested Quota Driver

bp cinder-nested-quota-driver

嵌套配额驱动程序将使 OpenStack 能够强制执行嵌套项目中的配额。

bp hierarchical-multitenancy

问题描述

OpenStack 正在向支持项目层级所有权发展。在这方面,Keystone 将改变 OpenStack 的组织结构,创建嵌套项目。

Cinder 中现有的 Quota Driver,名为 DbQuotaDriver,在项目和项目用户级别强制执行配额非常有用,前提是所有项目都在同一级别(即层级级别不能大于 1)。

该提案是开发一个新的 Quota Driver,名为 NestedQuotaDriver,通过扩展现有的 DbQuotaDriver,从而允许在 OpenStack 中的嵌套项目中强制执行配额。嵌套项目具有层级结构,每个项目可能包含用户和项目(可以称为子项目)。

用户可以在每个项目内拥有不同的角色:普通用户可以使用项目的资源。项目管理员,例如,可以是一个允许创建子项目、将资源配额分配给这些子项目以及将子项目管理员角色分配给子项目的各个用户的用户。根项目的资源配额只能由根项目的管理员设置。用户角色可以设置为继承,如果设置了继承,则项目的管理员会自动成为树下所有项目的管理员。

用例

参与者

  • Mike - 云管理员(即角色:cloud-admin) of ProductionIT

  • Jay - 经理(即角色:project-admin) of Project CMS

  • John - 经理(即角色:project-admin) of Project ATLAS

  • Eric - 经理(即角色:project-admin) of Project Operations

  • Xing - 经理(即角色:project-admin) of Project Services

  • Walter - 经理(即角色:project-admin) of Project Computing

  • Duncan - 经理(即角色:project-admin) of Project Visualisation

项目的嵌套结构如下。

{
   ProductionIT: {
                  CMS  : {
                            Computing,
                            Visualisation
                        },
                  ATLAS: {
                            Operations,
                            Services
                      }
               }
 }

Mike 是一个基础设施提供商,为 Jay 的 Project CMS 和 John 的 Project ATLAS 提供云服务。CMS 在其下方有两个子项目,名为 Visualisation 和 Computing,分别由 Duncan 和 Walter 管理。ATLAS 有两个子项目,名为 Services 和 Operations,分别由 Xing 和 Eric 管理。

  1. Mike 需要能够设置 CMS 和 ATLAS 的配额,并管理整个项目(包括根项目 ProductionIT)的配额。

  2. Jay 应该能够设置和更新 Visualisation 和 Computing 的配额。

  3. Jay 应该能够查看 CMS、Visualisation 和 Computing 的配额。

  4. Jay 不应该能够更新 CMS 的配额,尽管他是它的经理。只有 Mike 才能做到这一点。

  5. Jay 不应该能够查看 ATLAS 的配额。只有 John 和 Mike 才能做到这一点。

  6. Visualisation 的经理 Duncan 不应该能够查看 CMS 的配额。Duncan 应该能够查看 Visualisation 的配额,以及将在 Visualisation 下创建的任何子项目的配额。

  7. 一个项目的总资源消耗分为
    1. hard_limit - 可以消耗的最大容量。

    2. used - 项目中资源“volumes”使用的资源。

      (不包括子项目)

    3. reserved - 项目为将来保留的资源,不

      包括后代。

  8. 关于不同项目中卷数量的配额信息如下,

名称

hard_limit

used

reserved

ProductionIT

1000

100

100

CMS

300

25

15

Computing

100

50

50

Visualisation

150

25

25

ATLAS

400

25

25

Services

100

25

25

Computing

200

50

50

考虑以下用例:-

  1. 假设 Mike(根项目或云管理员的管理员)将 CMS 中卷的 hard_limit 增加到 400

  2. 假设 Mike 将 CMS 中卷的 hard_limit 增加到 500

  3. 假设 Mike 删除 CMS 的配额

  4. 假设 Mike 将 CMS 中卷的 hard_limit 减少到 350

  5. 假设 Mike 将 CMS 中卷的 hard_limit 减少到 200

  6. 假设 Jay(CMS 的经理)将 CMS 中卷的 hard_limit 增加到 400

  7. 假设 Jay 尝试查看 ATLAS 的配额

  8. 假设 Duncan 尝试将 CMS 中卷的 hard_limit 减少到 400。

  9. 假设 Mike 尝试将 ProductionIT 中卷的 hard_limit 增加到 2000。

  10. 假设 Mike 删除 Visualisation 的配额。

  11. 假设 Mike 删除项目 Visualisation。

  1. 假设公司不希望使用嵌套结构,并希望重构为只有四个项目,即 Visualisation、Computing、Services 和 Operations。

项目优先级

现有 DBQuotaDriver 中的代码已弃用,因此我们需要更新。此外,由于整个 OpenStack 社区正在向层级项目发展,这可以成为 Cinder 的一个有用的补充。

提议的变更

  1. 任何新创建的子项目的默认配额(硬限制)设置为 0。零的默认值确保在多个管理员同时创建多个项目时数据的一致性。假设每个项目允许的卷数量的默认值为 100,A 是根项目。并且管理员正在创建 B,A 的子项目,以及另一个管理员正在创建 C,同样是 A 的子项目。现在,B 和 C 的卷数量的默认值之和超过了 A 的默认值。为了避免这种情况,默认配额设置为零。

  2. 只有在将配额设置为非零值后,项目才能创建卷(因为默认值为 0)。在创建新项目后,必须通过 Cinder API 调用显式设置配额值,以确保项目中的可用配额,然后才能在该项目中声明资源。

  3. 在根项目中具有“cloud-admin”角色的用户,并且具有继承的角色被称为 Cloud-Admin,允许在整个层级结构中执行配额操作,包括顶级项目。Cloud-Admin 是唯一允许设置树中根项目配额的用户。

  4. 在项目中具有“project-admin”角色的用户允许对其子项目和层级结构中的用户执行配额操作。如果在 Keystone 中将“project-admin”角色设置为可继承,则具有此角色的用户允许从其直接子项目到项目层级下最后一个项目/用户的配额操作。注意:“cloud-admin”和“project-admin”等角色不是硬编码的。它在本蓝图中用于演示目的。

  5. 一个项目的总资源消耗分为

    1. 已用配额 - 卷在项目中使用的资源。

      (不包括子项目)

    2. 保留配额 - 项目为将来保留的资源,不

      包括后代。

    3. 包括后代。

      分配配额 - 立即子项目的配额 hard_limit 值之和

  6. 项目内可用的 free 配额计算如下

    free quota = hard_limit - (used + reserved + allocated)

    空闲配额不存储在数据库中;它是为每个项目动态计算的。

  7. 只有在父项目有足够的空闲配额可用时,才允许增加项目的配额值。如果父项目有空闲配额可用,则配额更新操作将导致项目 hard_limit 值及其父项目的 allocated 值更新。因此,应该注意的是,更新项目的配额需要令牌在父级别作用域内。

    • 项目层级为 A->B->C(A 是根项目)

      名称

      hard_limit

      used

      reserved

      allocated

      A

      100

      0

      0

      50

      B

      50

      20

      0

      10

      C

      10

      10

      0

      0

      项目的空闲配额将是

      A:Free Quota = 100 {A:hard_limit} - ( 0 {A:used} + 0 {A:reserved} +

      50 {A:Allocated to B}) = 50

      B:Free Quota = 50 {B:hard_limit} - ( 20 {B:used} + 0 {B:reserved} +

      10 {B:Allocated to C}) = 20

      C:Free Quota = 10 {C:hard_limit} - ( 10 {C:used} + 0 {C:reserved} +

      0 {C:Allocated}) = 0

      如果项目 C hard_limit 增加 10,则此更改将导致

      名称

      hard_limit

      used

      reserved

      allocated

      A

      100

      0

      0

      50

      B

      50

      20

      0

      20

      C

      20

      10

      0

      0

      如果项目 C hard_limit 需要进一步增加 20,则此操作将被中止,因为其父项目即项目 B 的可用空闲配额仅为 10。因此,A 的项目管理员应首先增加项目 B 的 hard_limit(使用作用域到项目 A 的令牌,因为在 A 级别执行操作),然后增加项目 C 的 hard_limit(同样作用域到项目 B 的令牌)。

      请考虑上述用例。各种项目的配额信息,包括分配的配额如下,

      ProductionIT : hard_limit=1000, used=100, reserved=100, allocated=700
      CMS : hard_limit=300, used=25, reserved=15, allocated=250
      Computing : hard_limit=100, used=50, reserved=50, allocated=0
      Visualisation : hard_limit=150, used=25, reserved=25, allocated=0
      ATLAS : hard_limit=400, used=25, reserved=25, allocated=300
      Services : hard_limit=100, used=25, reserved=25, allocated=0
      Computing : hard_limit=200, used=50, reserved=50, allocated=0
      • 假设 Mike 尝试将 CMS 中的卷配额增加到 400。由于 Mike 具有 ProductionIT 的管理员角色,它是 CMS 的父项目,因此他可以增加 CMS 的配额,前提是令牌作用域限定为 ProductionIT。这是必需的,因为增加 CMS 的配额限制会导致 ProductionIT 的空闲配额相应减少。

        使用上述公式,ProductionIT 的空闲配额为,free quota = hard_limit - used - reserved - allocated free quota = 1000 - 100 - 100 - (400 + 400) free quota = 0

        因此 CMS 的最大允许配额为 300 + 100 = 400

        注意:ProductionIT:allocated = CMS:hard_limit + ATLAS:hard_limit

        CMS 的最小配额为,CMS:used + CMS:reserved + CMS:allocated = 25 + 15 + 250 = 290

        注意: CMS:allocated = Visualisation:hard_limit + Computing:hard_limit

        由于 290(最小配额)<= 400(新配额)<=400(最大配额),配额操作将成功。更新后,ProductionIT 和 CMS 的配额将如下,

        ProductionIT : hard_limit=1000, used=100, reserved=100, allocated=800
        CMS : hard_limit=400, used=25, reserved=15, allocated=250
      • 假设 Mike 尝试将 CMS 中的实例配额增加到 500。那么它将不会成功,因为 CMS 的最大配额为 400。

      • 假设 Jay,CMS 的经理,将 CMS 中的卷配额增加到 400,那么它将不会成功,因为 Jay 没有 ProductionIT 的管理员或项目管理员角色,它是 CMS 的父项目。

      • 假设 Mike 尝试将 ProductionIT 的配额增加到 2000,那么它将成功。由于 ProductionIT 是根项目,因此 ProductionIT 的最大配额没有限制。而且,Mike 在 ProductionIT 中具有管理员角色。对于私有云,hard_limit 取决于云提供商内部维护的内部清单。Mike 云管理员将可以访问这些详细信息,并根据可用清单更新 hard_limit。因此,hard_limit 受私有云可用清单的限制,并且对于每个私有云而异。

  8. 只有在项目有可用空闲配额的情况下,才允许减少项目的配额值,空闲配额 > 0(零),因此配额值的最大减少限制为空闲配额值。

  • 项目层级为 A->B->C,其中 A 是根项目

    项目 A(hard_limit = 100,used = 0,reserved = 0,allocated = 50)项目 B(hard_limit = 50,used = 20,reserved = 0,allocated = 10)项目 C(hard_limit = 10,used = 10,reserved = 0,allocated = 0)

    如果项目 B hard_limit 减少 10,则此更改将导致项目 A(hard_limit = 100,used = 0,reserved = 0,allocated = 40)项目 B(hard_limit = 40,used = 20,reserved = 0,allocated = 10)项目 C(hard_limit = 10,used = 10,reserved = 0,allocated = 0)

    如果项目 B 的 hard_limit 需要进一步减少 20,则此操作将被中止,因为项目 B 的空闲配额应大于或等于(20+0+10)。

  1. 假设 Mike 尝试将 CMS 中的卷配额减少到 350,它将成功,因为 CMS 的最小配额要求为 290。

  2. 假设 Mike 尝试将 CMS 中的卷配额减少到 200,那么它将不会成功,因为它违反了最小配额标准。

  3. 删除配额等同于将配额更新为零值。如果分配的配额为零,它将成功。身份验证逻辑与更新逻辑相同。

    • 假设 Mike 尝试删除 CMS 的配额,那么它将不会成功,因为 CMS 的分配配额不为零。

    • 假设 Mike 删除配额 Visualisation,那么它将成功,因为 Visualisation 的分配配额为零。删除的 Visualisation 配额将添加到 CMS 的 free_quota。CMS 的配额将为 CMS :hard_limit=300, used=25, reserved=15, allocated=100。

    • 假设 Mike 删除项目 Visualisation,Visualisation 的配额应释放给其父项目 CMS。但是,在当前设置中,Cinder 不会知道 Keystone 中何时删除了项目。这是因为 Keystone 服务与其他服务(包括 Cinder)不同步。因此,即使项目已从 keystone 中删除,配额信息仍然存在于 cinder 数据库中。当前 OpenStack 运行模型存在此问题。一旦 Keystone 服务同步,这将自动得到处理。目前,Mike 必须在删除该项目之前删除 Visualisation 的配额。Keystone 与其他 OpenStack 服务的同步超出了此蓝图的范围。

  4. 假设 Jay,CMS 的经理,尝试查看 ATLAS 的配额,它将不会成功,因为 Jay 在 ATLAS 或 ATLAS 的父项目中没有角色。

  5. 假设 Duncan,Visualisation 的经理,尝试更新 CMS 的配额,它将不会成功,因为他没有 CMS 的父项目的管理员或项目管理员角色。

  6. 假设组织不希望使用嵌套结构,并希望只有四个项目,即 Visualisation、Computing、Services 和 Operations,那么设置将像当前设置一样,只有一个级别的项目。所有四个项目都将被视为根项目。

  7. 在并行配额消耗的情况下,即多个子项目同时消耗配额,如果请求未被满足,则应在增加父配额后过一段时间后重试该请求。 此规范需要管理员干预。 如“通知影响”部分所述,通过采用基于通知/事件的支持,我们可以克服管理员干预。 在后续工作中,我将添加关于如何序列化请求的详细信息。 这很重要,因为增加子项目的硬限制(取决于父项目的可用配额)以及在父级别更新分配的配额需要是一个原子操作。 一旦执行了原子操作,就可以服务新的传入请求。

备选方案

对于项目的配额更新和删除操作,令牌可以限定到项目本身,而不是其父项目。 但是,我们避免这样做,因为子项目的配额更改会导致父项目的可用配额发生变化。 因此,根据此 bp,对于配额更新和删除操作,令牌限定到父项目。

数据模型影响

在表 quotas 中创建一个名为 allocated 的新列,默认值为 0。 可以通过添加迁移脚本来完成此操作。

REST API 影响

安全影响

规范中使用的 hard_limit 参数需要与每个私有云中实际的库存紧密相关。 由于大多数计算都基于 hard_limit,因此需要透明地了解可用的库存来进行配额计算。 这超出了此规范的范围,但为了清晰起见,在此提出。 此外,应注意确保这不会允许任何配额逃逸漏洞。 鉴于这是一个更复杂的模型,因此值得审查人员花时间主动尝试破坏该模型(检查时与使用时,等等)。

通知影响

任何配额值的更改(不是使用量,而是限制)都将生成一个事件。 这对于一般的调试、审计,以了解谁做了什么很有用。 对于此规范,我们将限制通知范围仅用于跟踪和审计,但将来事件或通知机制可用于通知配额不足的子项目,以便在父项目有足够的可用配额时稍后重试。 此外,将来当 Keystone 删除项目时,可以向队列发送通知,然后 cinder 可以消耗此事件以主动从 cinder 数据库中释放配额。

其他最终用户影响

只有 Cloud-Admin 或直接父项目才能设置子项目的配额。 Cloud-Admin 甚至可以设置和更新他/她的自己的配额。

性能影响

其他部署者影响

开发人员影响

实现

负责人

主要负责人
  • vilobhmm

其他贡献者

工作项

  1. 对于此规范的第一个实现补丁,我们将仅修复配额计算,使其意识到子项目,而不是添加任何新的编辑功能。 此外,我们将跳过由 root 项目管理员以外的任何人更新配额。

  2. 对于此规范的第二个实现补丁,我们将添加由子项目的项目管理员编辑配额的功能。

  3. 将创建一个名为“cloud-admin”的角色,并将该角色分配给 root 项目中的用户,并使其可继承。

  4. 将创建一个名为“project-admin”的角色。 在项目中具有“project-admin”角色的用户将能够在从其直接子项目到项目下最后一个级别项目/用户中的项目执行配额操作,前提是它是可继承的。

    注意:“cloud-admin”和“project-admin”之类的角色不是硬编码的。 它在此蓝图中使用,仅用于演示目的。

  5. 将通过扩展现有的 DbQuotaDriver 来实现一个新的配额驱动程序,名为 NestedQuotaDriver,以在 OpenStack 中强制执行分层多租户中的配额。

  6. 将添加一个迁移脚本,以在表 quotas 中创建名为 allocated 的新列,默认值为 0。

依赖项

依赖于 bp hierarchical-multitenancy

测试

  • 将为所有 REST API 调用添加单元测试。

  • 添加与其它服务集成的单元测试。

文档影响

将更新文档,以提供有关配额计算的详细信息,以及在使用嵌套配额驱动程序(在具有分层支持的项目中)的项目中如何分配和管理配额。 这些部署需要是 Kilo 或更高版本,因为分层支持是从 Kilo 版本开始添加的。

参考资料