在必需的 Terraform 变量中有可选的子变量
Have optional sub-variables in required Terraform variable
我已经创建了一个对应于Azure Firewall Network Rule Collection的模块。该模块如下所示:
resource "azurerm_firewall_network_rule_collection" "fwnrc" {
name = "fwnrc-${var.name}"
resource_group_name = var.resource_group_name
azure_firewall_name = var.azure_firewall_name
priority = var.priority
action = var.action
dynamic "rule" {
for_each = var.rule != null ? [true] : []
content {
name = var.rule.name
description = var.rule.description
source_addresses = var.rule.source_addresses
source_ip_groups = var.rule.source_ip_groups
destination_addresses = var.rule.destination_addresses
destination_ip_groups = var.rule.destination_ip_groups
destination_fqdns = var.rule.destination_fqdns
destination_ports = var.rule.destination_ports
protocols = var.rule.protocols
}
}
}
现在感兴趣的部分是 dynamic "rule"
,它有一个相应的变量定义如下:
variable "rule" {
type = object({
name = string
description = string
source_addresses = list(string)
source_ip_groups = list(string)
destination_addresses = list(string)
destination_ip_groups = list(string)
destination_fqdns = list(string)
destination_ports = list(string)
protocols = list(string)
})
}
我知道可以通过将其默认值设置为 null
来使 rule
变量成为“可选”。我想更深入一步,使子变量* optional/required。例如,在资源文档中写道,必须指定 *_addresses
或 *_ip_groups
。文档还说 destination_fqdns
是可选的。
* 这些有实际名称吗?
由于我的模块需要 rule
变量,如果我没有为所有子变量提供明确的值,我会收到错误消息。我现在的解决方案是执行以下操作:
module "firewall_network_rule_collection" {
source = "/path/to/module"
name = "fwrc"
azure_firewall_name = "afw"
resource_group_name = "rg"
priority = 110
action = "Allow"
rule = {
description = "rule"
name = "rule"
source_addresses = ["*"]
source_ip_groups = null
destination_ports = ["*"]
destination_addresses = [
"AzureContainerRegistry",
"MicrosoftContainerRegistry",
"AzureActiveDirectory"
]
destination_fqdns = null
destination_ip_groups = null
protocols = ["Any"]
}
}
记下 null
值。我能以某种方式摆脱这些吗?
--
我正在使用以下提供商设置:
terraform {
required_version = ">=1.0.11"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = ">=2.90.0"
}
}
}
如果有人选择加入,experimental "optional" object type 目前可用。
将以下内容添加到您的模块中:
terraform {
experiments = [module_variable_optional_attrs]
}
这允许以下内容:
variable "rule" {
type = object({
name = string
description = optional(string)
source_addresses = optional(list(string))
source_ip_groups = optional(list(string))
destination_addresses = optional(list(string))
destination_ip_groups = optional(list(string))
destination_fqdns = optional(list(string))
destination_ports = optional(list(string))
protocols = optional(list(string))
})
}
希望此功能成为下一个版本的完全支持部分。
如果没有实验性的 optional()
,您可以删除 type
约束并告知模块用户预期具有指定属性的 map
。
然后在代码中您必须检查是否设置了属性。
简化示例:
variable "rule" {
# Type can't be specified, as even `map(any)` would enforce all entries to same type
type = any
# Some validation might be added for required attributes,
# or just let the error flow though from code
}
# ...
content {
# Fails if `name` is not specified
name = var.rule.name
# Default to `null`
description = lookup(var.rule, "description", null)
# ...
}
使用 lookup()
您还可以为属性添加另一个默认值。
如果有非空默认值或默认值是用其他属性构造的,使用局部变量填充默认值可能更清晰(类似于当前 optional()
提议)。
例如:
locals {
rule = merge(
{
description = var.rule.name
destination_fqdns = ["foo.example.com]
source_addresses = null
# ...
},
var.rule
)
}
那么您始终可以仅使用点符号来引用属性。
我已经创建了一个对应于Azure Firewall Network Rule Collection的模块。该模块如下所示:
resource "azurerm_firewall_network_rule_collection" "fwnrc" {
name = "fwnrc-${var.name}"
resource_group_name = var.resource_group_name
azure_firewall_name = var.azure_firewall_name
priority = var.priority
action = var.action
dynamic "rule" {
for_each = var.rule != null ? [true] : []
content {
name = var.rule.name
description = var.rule.description
source_addresses = var.rule.source_addresses
source_ip_groups = var.rule.source_ip_groups
destination_addresses = var.rule.destination_addresses
destination_ip_groups = var.rule.destination_ip_groups
destination_fqdns = var.rule.destination_fqdns
destination_ports = var.rule.destination_ports
protocols = var.rule.protocols
}
}
}
现在感兴趣的部分是 dynamic "rule"
,它有一个相应的变量定义如下:
variable "rule" {
type = object({
name = string
description = string
source_addresses = list(string)
source_ip_groups = list(string)
destination_addresses = list(string)
destination_ip_groups = list(string)
destination_fqdns = list(string)
destination_ports = list(string)
protocols = list(string)
})
}
我知道可以通过将其默认值设置为 null
来使 rule
变量成为“可选”。我想更深入一步,使子变量* optional/required。例如,在资源文档中写道,必须指定 *_addresses
或 *_ip_groups
。文档还说 destination_fqdns
是可选的。
* 这些有实际名称吗?
由于我的模块需要 rule
变量,如果我没有为所有子变量提供明确的值,我会收到错误消息。我现在的解决方案是执行以下操作:
module "firewall_network_rule_collection" {
source = "/path/to/module"
name = "fwrc"
azure_firewall_name = "afw"
resource_group_name = "rg"
priority = 110
action = "Allow"
rule = {
description = "rule"
name = "rule"
source_addresses = ["*"]
source_ip_groups = null
destination_ports = ["*"]
destination_addresses = [
"AzureContainerRegistry",
"MicrosoftContainerRegistry",
"AzureActiveDirectory"
]
destination_fqdns = null
destination_ip_groups = null
protocols = ["Any"]
}
}
记下 null
值。我能以某种方式摆脱这些吗?
--
我正在使用以下提供商设置:
terraform {
required_version = ">=1.0.11"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = ">=2.90.0"
}
}
}
如果有人选择加入,experimental "optional" object type 目前可用。
将以下内容添加到您的模块中:
terraform {
experiments = [module_variable_optional_attrs]
}
这允许以下内容:
variable "rule" {
type = object({
name = string
description = optional(string)
source_addresses = optional(list(string))
source_ip_groups = optional(list(string))
destination_addresses = optional(list(string))
destination_ip_groups = optional(list(string))
destination_fqdns = optional(list(string))
destination_ports = optional(list(string))
protocols = optional(list(string))
})
}
希望此功能成为下一个版本的完全支持部分。
如果没有实验性的 optional()
,您可以删除 type
约束并告知模块用户预期具有指定属性的 map
。
然后在代码中您必须检查是否设置了属性。 简化示例:
variable "rule" {
# Type can't be specified, as even `map(any)` would enforce all entries to same type
type = any
# Some validation might be added for required attributes,
# or just let the error flow though from code
}
# ...
content {
# Fails if `name` is not specified
name = var.rule.name
# Default to `null`
description = lookup(var.rule, "description", null)
# ...
}
使用 lookup()
您还可以为属性添加另一个默认值。
如果有非空默认值或默认值是用其他属性构造的,使用局部变量填充默认值可能更清晰(类似于当前 optional()
提议)。
例如:
locals {
rule = merge(
{
description = var.rule.name
destination_fqdns = ["foo.example.com]
source_addresses = null
# ...
},
var.rule
)
}
那么您始终可以仅使用点符号来引用属性。