在所需的Terraform变量中具有可选的子变量



我已经创建了一个与Azure防火墙网络规则集合相对应的模块。模块如下所示:

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)
})
}

我知道可以使CCD_ 2变量";可选的";通过将其默认值设置为CCD_ 3。我想更深入一步,使子变量*可选/必需。例如,在资源文档中,必须指定*_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"
}
}
}

实验;可选的";如果选择进入,对象类型当前可用。

将以下内容添加到您的模块中:

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(),您还可以为属性添加另一个默认值。

如果存在非null默认值,或者默认值是用其他属性构建的,那么使用局部变量填充默认值可能会更干净(类似于当前optional()提案所需的内容(。

例如:

locals {
rule = merge(
{
description       = var.rule.name
destination_fqdns = ["foo.example.com]
source_addresses  = null
# ...
},
var.rule
)
}

然后,您可以始终只使用点表示法来引用属性。

最新更新