在生命周期管理上添加多租户策略

https://blueprints.launchpad.net/tacker/+spec/multi-tenant-policy

本文档展示了在多租户情况下生命周期管理存在的问题,并提出了相应的变更方案来解决这些问题。本规范的目标是使用租户来隔离基于 ETSI NFV-SOL 的 VNF 管理相关的资源。目标资源如下。

  • 虚拟化基础设施管理器 (VIMs)

    • /v1.0/vims

  • 虚拟化网络功能包 (VNF packages)

    • /vnfpkgm/v1/vnf_packages

  • 虚拟化网络功能生命周期管理接口 (VNF LCM)

    • /vnflcm/v1/vnf_instances

    • /vnflcm/v1/vnf_lcm_op_occs

    • /vnflcm/v1/subscriptions

问题描述

在当前的 Tacker 实现中,使用租户进行资源隔离无法正常工作。VNF LCM 及其操作中使用到的资源应该按租户进行隔离。在多租户情况下存在两个问题。

1) 不支持不同租户的订阅和 LCM 操作发生。

订阅和 LCM 操作的发生没有按租户进行隔离。我们无法正确获取每个租户的信息。

我们还需要注意通知。订阅 API 只能设置为回调 URL。在这种情况下,可以发送通知来显示在不同租户中发生的生命周期管理操作的状态。

2) 不限制将不同租户的 VIM 和 VNF 关联起来。

目前 Tacker 可以将 VIM 与 VNF 关联起来,即使它们都属于不同的租户。

例如,管理员用户可以使用属于与 VNF 不同的租户的 VIM 来实例化 VNF。非管理员用户无法终止 VNF,因为该非管理员用户不属于 VIM 的租户。

  1. 非管理员用户创建一个 VNF。

  2. 管理员用户通过指定非管理员用户不属于的 VIM 来实例化 VNF。

  3. 非管理员用户无法终止 VNF。

管理员用户可以获取 VNF 的资源信息或操作 VNF LCM 并不存在问题。问题在于管理员用户可以对属于与 VNF 租户不同的租户的 VIM 进行 LCM 操作。

提议的变更

为了解决这些问题,我们提出以下变更。

1) 在 VnfLcmSubscriptions 和 VnfLcmOpOccs 中添加 tenant_id:

我们在数据库表 vnf_lcm_subscriptionsvnf_lcm_op_occs 以及对象 VnfLcmSubscriptionsVnfLcmOpOccs 中添加 tenant_id 字段。

用户只能在其自己的租户中获取上述信息。

2) 在发送通知时指定租户:

通知被修改为检查在订阅序列期间分配的租户,然后将事件通知给指定的租户。

../../_images/0141.png

3) 禁止在不同租户中创建的 VIM 和 VNF 关联:

Tacker 仅允许将属于与 VIM 相同租户的 VNF 与 VIM 关联起来。

../../_images/0225.png

如何设计功能测试

为了解决这三个提出的变更,我们需要确认解决方案在多租户环境中是否有效。但是,现有的功能测试仅用于单租户验证,无法从多租户的角度进行验证。因此,我们需要添加一个新的测试用例来查看多租户情况。

为了查看多租户工作情况,我们需要至少两个不同的租户。本规范为每个租户配置用户、VIM 和 VNF,在每个租户上操作 VNF 包和 VNF LCM,并验证操作结果的通知仅到达属于其租户的订阅通知服务器。

多租户功能测试目录

将此规范的测试添加到现有的功能测试中会产生很大的影响并使测试视角复杂化。因此,我们将添加一个新的多租户测试用例。

tacker/tacker/tests/functional/
    legacy/
    sol/
    sol_kuberenates/
    sol_separatednfvo/
    sol_v2/
    sol_multi_tenant/   <--- new add test case

针对提出的变更 (1) 和 (2) 的测试视角

为了验证本规范中提出的变更 (1) 和 (2) 的操作,添加了以下测试用例。

  • 注册、显示、列出订阅
    • 用户 A 属于项目 A 注册订阅 A(通知服务器 A)

    • 用户 B 属于项目 B 注册订阅 B(通知服务器 B)

    • 用户 A 属于项目 A 获取订阅列表并确认仅打印订阅 A

    • 用户 B 属于项目 B 获取订阅列表并确认仅打印订阅 B

    • 用户 A 属于项目 A 获取订阅 A 的信息,并输出订阅 A 的信息。

    • 用户 A 属于项目 A 无法获取订阅 B 的信息,并且不应该获取订阅 B 的信息。

    • 用户 B 属于项目 B 获取订阅 B 的信息,并输出订阅 B 的信息。

    • 用户 B 属于项目 B 无法获取订阅 A 的信息,并且不应该获取订阅 A 的信息。

../../_images/0314.png
  • 创建、上传、显示、列出 VNF 包
    • 用户 A 属于项目 A 创建 VNF 包 A

    • 用户 A 属于项目 A 上传 VNF 包 A

    • 用户 B 属于项目 B 创建 VNF 包 B

    • 用户 B 属于项目 B 上传 VNF 包 B

    • 用户 A 属于项目 A 获取 VNF 包列表并确认仅输出 VNF 包 A

    • 用户 B 属于项目 B 获取 VNF 包列表并确认仅输出 VNF 包 B

    • 用户 A 属于项目 A 显示 VNF 包 A

    • 用户 B 属于项目 B 显示 VNF 包 B

    • 用户 A 属于项目 A 显示 VNF 包 B,应该失败

    • 用户 B 属于项目 B 显示 VNF 包 A,应该失败

../../_images/0410.png
  • 创建 VNF
    • 用户 A 属于项目 A 使用 VNF 包 B 创建 VNF 实例 B,应该失败

    • 用户 B 属于项目 B 使用 VNF 包 A 创建 VNF 实例 A,应该失败

    • 用户 A 属于项目 A 使用 VNF 包 A 创建 VNF 实例 A

    • 用户 B 属于项目 B 使用 VNF 包 B 创建 VNF 实例 B

    • 验证通知服务器 A 能够获取 VNF 实例 A 的创建信息

    • 验证通知服务器 B 无法获取 VNF 实例 A 的创建信息

    • 验证通知服务器 B 能够获取 VNF 实例 B 的创建信息

    • 验证通知服务器 A 无法获取 VNF 实例 B 的创建信息

../../_images/057.png
  • 实例化 VNF
    • 用户 A 属于项目 A 实例化 VNF 实例 B,应该失败

    • 用户 B 属于项目 B 实例化 VNF 实例 A,应该失败

    • 用户 A 属于项目 A 实例化 VNF 实例 A

    • 用户 B 属于项目 B 实例化 VNF 实例 B

    • 用户 A 属于项目 A 获取 LcmOpOccs 列表,应该仅获取 VNF 实例 A 的 LcmOpOccs

    • 用户 B 属于项目 B 获取 LcmOpOccs 列表,应该仅获取 VNF 实例 B 的 LcmOpOccs

    • 用户 A 属于项目 A 显示 VNF 实例 A 的 LcmOpOccs

    • 用户 A 属于项目 A 显示 VNF 实例 B 的 LcmOpOccs,不应该获取 VNF 实例 B 的 LcmOpOccs 信息

    • 用户 B 属于项目 B 显示 VNF 实例 B 的 LcmOpOccs

    • 用户 B 属于项目 B 显示 VNF 实例 A 的 LcmOpOccs,不应该获取 VNF 实例 A 的 LcmOpOccs 信息

    • 验证通知服务器 A 能够获取 VNF 实例 A 的实例化信息

    • 验证通知服务器 B 无法获取 VNF 实例 A 的实例化信息

    • 验证通知服务器 B 能够获取 VNF 实例 B 的实例化信息

    • 验证通知服务器 A 无法获取 VNF 实例 B 的实例化信息

../../_images/064.png
  • 终止 VNF
    • 用户 A 属于项目 A 终止 VNF 实例 B,应该失败

    • 用户 B 属于项目 B 终止 VNF 实例 A,应该失败

    • 用户 A 属于项目 A 终止 VNF 实例 A

    • 用户 B 属于项目 B 终止 VNF 实例 B

    • 用户 A 属于项目 A 获取 LcmOpOcc 列表,应该仅获取 VNF 实例 A 的 LcmOpOcc

    • 用户 B 属于项目 B 获取 LcmOpOcc 列表,应该仅获取 VNF 实例 B 的 LcmOpOcc

    • 用户 A 属于项目 A 显示 VNF 实例 A 的 LcmOpOcc

    • 用户 A 属于项目 A 显示 VNF 实例 B 的 LcmOpOcc,不应该获取 VNF 实例 B 的 LcmOpOcc 信息

    • 用户 B 属于项目 B 显示 VNF 实例 B 的 LcmOpOcc

    • 用户 B 属于项目 B 显示 VNF 实例 A 的 LcmOpOcc,不应该获取 VNF 实例 A 的 LcmOpOcc 信息

    • 验证通知服务器 A 能够获取 VNF 实例 A 的终止信息

    • 验证通知服务器 B 无法获取 VNF 实例 A 的终止信息

    • 验证通知服务器 B 能够获取 VNF 实例 B 的终止信息

    • 验证通知服务器 A 无法获取 VNF 实例 B 的终止信息

../../_images/072.png
  • 删除 VNF
    • 用户 A 属于项目 A 删除 VNF 实例 B,应该失败

    • 用户 B 属于项目 B 删除 VNF 实例 A,应该失败

    • 用户 A 属于项目 A 删除 VNF 实例 A

    • 用户 B 属于项目 B 删除 VNF 实例 B

    • 验证通知服务器 A 能够检索 VNF 实例 A 的删除信息

    • 验证通知服务器 B 无法获取 VNF 实例 A 的删除信息

../../_images/082.png
  • 删除 VNF 包
    • 用户 A 属于项目 A 删除 VNF 包 B,应该失败

    • 用户 B 属于项目 B 删除 VNF 包 A,应该失败

    • 用户 A 属于项目 A 删除 VNF 包 A

    • 用户 B 属于项目 B 删除 VNF 包 B

../../_images/091.png
  • 删除订阅
    • 用户 A 属于项目 A 删除订阅 B,应该失败

    • 用户 B 属于项目 B 删除订阅 A,应该失败

    • 用户 A 属于项目 A 删除订阅 A

    • 用户 B 属于项目 B 删除订阅 B

../../_images/101.png

针对提出的变更 (3) 的测试视角

为了验证本规范中提出的变更 (3) 的操作,添加了以下测试用例。

  • 无法使用不同的 VIM 实例化
    • 用户 A 属于项目 A 注册 VIM A 作为默认 VIM。

    • 用户 B 属于项目 B 注册 VIM B 作为默认 VIM。

    • 用户 A 属于项目 A 创建 VNF 包 A

    • 用户 A 属于项目 A 上传 VNF 包 A

    • 用户 B 属于项目 B 创建 VNF 包 B

    • 用户 B 属于项目 B 上传 VNF 包 B

    • 用户 A 属于项目 A 使用 VNF 包 A 创建 VNF 实例 A

    • 用户 B 属于项目 B 使用 VNF 包 B 创建 VNF 实例 B

    • 用户 A 属于项目 A 使用 VIM B 实例化 VNF 实例 A,应该失败

    • 用户 B 属于项目 B 使用 VIM A 实例化 VNF 实例 B,应该失败

    • 用户 A 属于项目 A 使用 VIM A 实例化 VNF 实例 A

    • 用户 B 属于项目 B 使用 VIM B 实例化 VNF 实例 B

    • 用户 A 属于项目 A 终止 VNF 实例 A

    • 用户 B 属于项目 B 终止 VNF 实例 B

    • 用户 A 属于项目 A 删除 VNF 实例 A

    • 用户 B 属于项目 B 删除 VNF 实例 B

../../_images/11.png

备选方案

数据模型影响

添加到 Tacker 数据库表如下。

vnf_lcm_subscriptions

tenant_id varchar(64)

vnf_lcm_op_occs

tenant_id varchar(64)

REST API 影响

安全影响

通知影响

其他最终用户影响

性能影响

其他部署者影响

开发人员影响

升级影响

实现

负责人

主要负责人

Koichi Edagawa <edagawa.kc@nec.com>

工作项

  • 修改租户策略,禁止将属于与 VIM 不同的租户的 VIM 与 VNF 关联起来。

  • 修改通知流程,以指定在订阅序列期间分配的租户。

  • 更改通知事件,以便仅将通知发送给指定的租户。

依赖项

测试

添加一个多租户功能测试用例。有关如何设计功能测试的详细信息,请参阅“如何设计功能测试”。

文档影响

参考资料

历史