允许验证和检查嵌套资源¶
https://blueprints.launchpad.net/heat/+spec/nested-validation
目前,除了进行堆栈创建并等待其失败外,没有办法递归地验证所有嵌套模板。此外,没有办法检查嵌套模板暴露的接口,例如通过 parameter_defaults 可访问的接口。添加更全面的预创建验证支持(例如 heat template-validate)将允许解决这两个问题。
问题描述¶
heat template-validate 接受一个可选的环境参数,但它不会解析文件并包含一个“files”映射,就像 create/update 所使用的那样。
因此,即使在环境中指定了它们,我们也会显式忽略对任何嵌套堆栈的验证。这意味着在创建之前,很难验证嵌套模板,除非单独验证每个模板(这部分可能可以被认为是一个错误)。
然而,当嵌套模板暴露我们希望通过环境中的 parameter_defaults 交互的接口时,情况也会变得棘手,例如,不通过父模板的 properties/parameters 指定。我们需要的是一种验证整个树的方法,并返回整个树的模式,而不仅仅是顶级模板暴露的参数。
例如,考虑以下工作流程
选择父模板。
选择一组其他模板和环境(或者通过程序化方式生成,例如从一个或多个已知位置/路径中提取模板)
检查该组以确定资源类型级别的功能/选项。这些是用户将要做的主要选择,以确定每个类型的嵌套堆栈实现。
用户为每个具有多个选择的嵌套堆栈选择一个选项(请注意 https://review.openstack.org/#/c/196656/ 讨论了通过 (3) 中所做的选择以编程方式进行此选择的方法)
在这些主要选项的基础上重新检查,以获取完整的参数集,以便可以提示用户提供强制性和可选参数,包括那些未由顶级父模板暴露的参数。
用户输入所有参数的值,然后创建堆栈。
本规范的主题是上述步骤 5,我们希望构建整个树的参数模式。
为了更具体的例子,考虑这种模式(在 TripleO 中常用) - 父模板创建一个服务器,然后将 ID 传递给一些嵌套模板,然后执行一些配置步骤,这些步骤旨在是可插拔的,并且接口在编写父模板时是未知的
resource_registry:
OS::TripleO::ControllerExtraConfigPre: extraconfig/some_extra.yaml
parameter_defaults:
SomeExtraParam: "extra foo"
在这里,任何模板都可以通过 ControllerExtraConfigPre 挂钩,并且父模板不需要知道任何暴露的参数,除了可以传递服务器 ID 之外,任何额外的参数都在定义 ControllerExtraConfigPre 时通过 parameter_defaults 连接。
heat_template_version: 2015-04-30
description: Configure some extra config on your server
parameters:
server:
description: ID of the server to apply config to
type: string
# Config specific parameters, to be provided via parameter_defaults
SomeExtraParam:
type: string
default: "bar"
resources:
ExtraServerConfig:
type: OS::Heat::StructuredConfig
properties:
group: os-apply-config
config: <some config>
ExtraServerDeployment:
type: OS::Heat::StructuredDeployment
properties:
config: {get_resource: ExtraServerConfig}
server: {get_param: server}
input_values:
ImplementationSpecificStuff: {get_param: SomeExtraParam}
在这里我们可以看到嵌套模板同时使用父模板提供的参数(服务器)和环境提供的参数(SomeExtraParam)。
目前,除了了解模板(或通过非 heat 工具进行检查/解析)之外,没有办法知道在选择 extraconfig/some_extra.yaml 时 SomeExtraParam 是一个必需的附加参数。
提议的变更¶
首先,我们需要修复基本的语法/结构验证部分,这意味着将一个可选的“files”映射传递给 validate API(与 create 和 update 相同),然后我们不再跳过 TemplateResource 验证(在 service.py validate_template() 中),我们可以递归到子模板并进行验证(类似于预创建发生的情况,除了我们将容忍缺少参数)。
然后,我们需要暴露额外的参数信息,而不仅仅是当前暴露的信息(仅父模板参数),可以通过一个新的 –show-nested (-n) 选项来完成
heat template-validate -f parent.yaml -e env.yaml --show-nested
以下是在一组具有以下属性的模板上运行时示例输出
父模板包含一个名为
level-1-resource的单个资源,类型为demo::Level1参数
parent-p1由父模板定义模板
demo::Level1包含一个必须由父模板指定的一个参数,以及一个具有默认值的参数。后者旨在表示作为parameter_default指定的值的类型。资源
level-1-resource包含一个名为level-2-resource的资源,类型为demo::Level2。类似地,模板
demo::Level2定义了一个必须由父模板指定的非默认参数,以及一个可以通过parameter_defaults可选覆盖的参数。
{
"Description": "parent template",
"Parameters": {
"parent-p1": {
"Type": "String",
"NoEcho": "false",
"Description": "parent first parameter",
"Label": "parent-p1"
}
},
"NestedParameters": {
"level-1-resource": {
"Type": "demo::Level1",
"Description": "level 1 nested template",
"Parameters": {
"level-1-p1": {
"Type": "String",
"NoEcho": "false",
"Description": "set by parent; should have a Value field",
"Value": "parent-set-value-1",
"Label": "level-1-p1"
},
"level-1-p2-optional": {
"Default": "",
"Type": "String",
"NoEcho": "false",
"Description": "not set by parent",
"Label": "level-1-p2-optional"
}
},
"NestedParameters": {
"level-2-resource": {
"Type": "demo::Level2",
"Description": "level 2 nested template",
"Parameters": {
"level-2-p2-optional": {
"Default": "",
"Type": "String",
"NoEcho": "false",
"Description": "not set by parent",
"Label": "level-2-p2-optional"
},
"level-2-p1": {
"Type": "String",
"NoEcho": "false",
"Description": "set by parent; should have a Value field",
"Value": "level-1-set-value",
"Label": "level-2-p1"
}
}
}
}
}
}
}
在这里我们将返回一个新的“NestedParameters”部分(可能到多个嵌套级别),反映在通过子模板递归的每个步骤中进行的参数验证(或者更准确地说,是每个子模板的资源实例化,这些资源可以在不同的参数下使用多次)。
如果嵌套模板定义了参数默认值(像往常一样),或者通过 parameter_defaults 设置了默认值,则将包含“Default”键。如果父模板提供了值,则将包含“Value”键。请注意,由于在 template-validate 调用期间参数是可选的,因此这可能是 None,例如 Value 为 None 表示父模板提供了一个值,但它未作为 template-validate 调用的一部分提供。
这意味着可以从返回的数据构建一个模式,例如,可以识别缺少“Default”和“Value”的任何参数,因为这些参数需要操作员输入才能提供参数。
下一类参数将是“默认但可配置”,其中存在 Default,但没有 Value - 您可能希望要求操作员提供与模板默认值不同的值,并且如果指定了约束,它们将在这里公开(如现有 Parameters 部分中的 choices 一样)。
请注意,返回的数据结构中的键名与现有的 Parameters 部分对齐 - 当我们达到 v2 API 时,最好将两者都重构为使用更 native_api_style_names。
以下是在将上面的示例模板修改为使用资源组时示例输出。唯一的更改是父资源 level-1-resource 已被一个名为 level-1-groups 的资源组替换。组内的定义与前面的示例相同。
为了简洁起见,已删除大部分输出。相关点是,组中的每个节点将按索引列出
{
"Description": "parent template",
"Parameters": {
"parent-p1": {
"Default": "foo",
"Type": "String",
"NoEcho": "false",
"Description": "parent first parameter",
"Label": "parent-p1"
}
},
"NestedParameters": {
"level-1-groups": {
"Type": "OS::Heat::ResourceGroup",
"Description": "No description",
"Parameters": {},
"NestedParameters": {
"0": {
"Type": "demo::Level1",
"Description": "level 1 nested template",
"Parameters": {
"level-1-p1": {},
"level-1-p2-optional": {}
},
"NestedParameters": {
"level-2-resource": {
"Type": "demo::Level2",
"Description": "level 2 nested template"
}
}
}
}
}
}
}
备选方案¶
我们在 TripleO 社区中使用一段时间的替代方案是维护一个单独的服务,该服务位于 heat 之外,包含与模板实现耦合的逻辑,并知道如何连接适当的参数,并维护嵌套模板实现到提供程序资源类型的映射。
这可行,但最终会得到一个单一用途的服务,该服务与模板实现高度耦合,这对于可维护性来说是一个挑战,并且无助于更广泛的 heat 社区构建其组合和接口需求。
实现¶
实现将分为两个阶段,首先将 files 映射传递给 heat,并通过 template-validate 实现基本的嵌套堆栈验证。
然后将添加上述额外数据通过 NestedParameters 键,最后将添加 heatclient 接口以使用它。
可能可以向 heatclient 添加额外的可用性功能,例如构建包含与验证输出相关的 parameter_defaults 的 stub 环境文件(这在 ML 上讨论过),但由于这里的要求尚未完全定义,我不会在本规范中考虑它。
负责人¶
- 主要负责人
shardy
里程碑¶
- 完成目标里程碑
liberty-2
工作项¶
API 更改
添加对通过 validate 调用传递“files”映射的支持
引擎更改
修改 template-validate 路径,以便不再跳过 TemplateResources,而是递归验证,类似于预创建步骤。
更新 template-validate 代码以构建 NestedParameter 输出
heatclient 更改
向 template-validate 添加 –show-nested 选项,该选项收集并填充可选的 files 映射,并将其传递给 API
文档变更
更新 API 文档以反映可选的“files”参数
依赖项¶
无