向 API 添加策略引擎类

此蓝图使得可以通过 API 访问策略引擎(除了领域无关的策略引擎)。

问题描述

目前,无法通过 API 访问除当前领域无关策略引擎之外的其他策略引擎。现在我们正在添加其他策略引擎,我们需要为用户提供一种与它们交互的方式。

除了对领域特定策略引擎有用之外,启用多个策略引擎应该可以更轻松地处理领域无关策略引擎的升级:在旧引擎旁边启动新引擎,然后原子地用新引擎替换旧引擎。

提议的变更

在这里,我们讨论两个方案。我们将在下一节中列出权衡。

方案 1:基于类型

在这里,我们只是添加一个顶级的“policy-engines”API 端点,从而得到…

/v1/policy-engines/<engine-id>/… /v1/data-sources/<datasource-id>/… /v1/system/…

例如:/data-sources/nova/… /data-sources/neutron/… /policy-engines/agnostic/…

数据源将支持:* schema:可用表 * actions:可用操作 * status:状态

策略引擎将支持

  • schema:可用表(例如 classification:connected_to_internet)

  • actions:可用操作(例如内置于策略引擎中的脚本,用于执行某些任务)

  • status:状态

  • policies:可用策略

也就是说,策略引擎和数据源之间的唯一区别在于数据源不支持“policies”。如果我们将“policies”视为“modules”,那么我们可以想象一个数据源驱动程序暴露分层表,就像策略引擎一样。在这种情况下,数据源将拥有类似于策略引擎“policies”的东西。

方案 2:基于服务

在这里,我们放弃了策略引擎和数据源的类型,并赋予客户端从同一端点访问策略引擎和数据源的能力。这是可能的,因为你不能为策略引擎和数据源赋予相同的名称(为了确保策略中对其他服务的引用是明确的,这种限制是存在的)。

/v1/services/<service-id>/… /v1/system/…

例如:/v1/services/nova/… /v1/services/neutron/… /v1/services/agnostic/…

所有服务将支持

  • schema:可用表(例如 classification:connected_to_internet)

  • actions:可用操作(例如内置于策略引擎中的脚本,用于执行某些任务)

  • status:状态

  • policies:可用策略

简而言之,此方案将所有内容视为策略引擎。数据源策略引擎禁止用户直接进行更改(即使他们进行了更改,也只会接受非常受限制的策略语句形式:基本事实)。

这种方法也可以向后兼容。我们仍然可以支持

/v1/datasources/<datasource-id>/…

它会被路由到

/v1/services/<datasource-id>。

并且我们可以支持

/v1/policies /v1/actions /v1/tables /v1/status

作为语法糖,用于

/v1/services/<default-service>/policies /v1/services/<default-service>/actions /v1/services/<default-service>/tables /v1/services/<default-service>/status

这将使用户能够选择一个管理数据中心中策略的单一入口点,同时使他们能够直接访问数据中心中的所有服务。(唯一的担忧是)

要设置 <default-service>,我们需要一个用户可以动态设置的参数(以帮助升级)。现在我们将它设置为 /services/agnostic。也许我们还可以为服务设置任意别名,以便我们可以在不更改策略的情况下升级任何服务。

提供 /v1/policies 等端点的一个担忧是,它可能会掩盖 Congress 的整体状态、策略、操作和表。也就是说,人们可能会期望这些端点聚合所有潜在的策略、操作、表和状态。但如果将来需要这种功能,我们可以将这些端点附加到 /v1/services,从而得到以下端点。

/services/policies /services/actions /services/tables /services/status

这是一个例子,如果我们有 Nova、GBP 和我们的策略引擎,那么入口点是什么样的。服务的名称是 DSE 期望的任何名称。

/policies /actions /tables /services/policies /services/actions /services/tables

/services/nova/policies -> empty /services/nova/actions -> createVM, deleteVM, migrateVM, etc. /services/nova/tables -> servers, hosts, etc. /services/gbp/policies /services/gbp/actions /services/gbp/tables /services/engine/policies /services/engine/actions /services/engine/tables

/system/drivers/

/system/engine-drivers/nova-uber-driver /system/datasource-drivers/nova-uber-driver /system/action-drivers/nova-uber-driver

/users /stats

通过 Congress API 启用人们修改领域特定策略引擎的一个好处是,我们为管理数据中心中运行的所有策略引擎提供了一种单一的策略语言。对于委托,我们已经需要将 Datalog 转换为每个策略引擎的本机语言的适配器,因此我们也将此功能直接暴露给用户。

备选方案

N/A

权衡

基于类型的方案的优点:* 易于用户理解 * 简单地扩展了当前的 API

基于类型的方案的缺点

  • 数据源和策略引擎实现几乎完全相同的接口并具有单独的命名空间,但作为 API 中的不同类,这很奇怪。

  • 使我们能够构建具有与策略引擎显著不同的程序接口的数据源。如果在 API 层,这两类对象几乎无法区分,这将导致底层实现中更好的抽象和接口。

基于服务的方案的优点

  • DSE 上运行的所有服务都通过 API 以相同的方式访问。这是这些服务的性质的更自然的反映。

基于服务的方案的缺点

  • 更大的变化

  • 可能一开始对用户来说更难理解。

  • 最终,策略引擎类将包含数据源类不具备的功能。在数据源上执行该功能将导致 404,并且我们无法仅根据 URL 预测会发生什么。

  • 执行诸如列出所有数据源的操作将需要像 /v1/services?action=list&type=datasource 这样的 API,而不是更明显的 /v1/data-sources/。

总的来说,在这两个方案中都存在类型(数据源与策略引擎),但它们在基于服务的方案中会强调得更少。基于服务的方案更接近 Python,因为系统无法查看你编写的代码(URL)并检查你请求的方法是否存在。基于类型的方案更接近 C/Java,因为系统仅通过查看代码(URL)就能告诉你方法是否存在。

通常,策略系统本质上是相当动态的(你可以在运行时更改策略/代码),因此它们更接近于 Python 等动态编程语言,而不是 C/Java 等静态语言。因此,我们通常会倾向于将决策偏向于动态性,在这种情况下意味着基于服务的方案。

策略

N/A

策略动作

N/A

数据源

N/A

数据模型影响

N/A

REST API 影响

见上文。API 结果没有变化——只是调用它们的路径。

安全影响

N/A

通知影响

N/A

其他最终用户影响

N/A

性能影响

N/A

其他部署者影响

见上文。

开发者影响

N/A

实现

负责人

主要负责人

<launchpad-id 或 None>

其他贡献者

<launchpad-id 或 None>

工作项

一旦我们决定了方案,我们将确定必要的工作项。但这是一个粗略的概述。

  • 基于类型的方案:添加路由,创建 congress/api/engine_model.py,修改 congress/api/*_model 以启用引擎的 tables/actions/policies/etc。

  • 基于服务的方案:添加路由,创建 congress/api/service_model.py(包括列出不同类型对象的 API),修改 congress/api/*_model 以消除数据源和策略之间的区别

依赖项

假设我们已经添加了“actions”的 API 调用,尽管这项工作可以在没有它的情况下完成:add-action-listing。

测试

  • 更改 congress/tests/test_congress.py 中的单元测试

  • 更改 congress_pythonclient(它将处理 tempest 测试)

文档影响

许多 URL 可能会更改。

参考资料

N/A