【问题标题】:Have optional sub-variables in required Terraform variable在所需的 Terraform 变量中有可选的子变量
【发布时间】:2022-01-20 04:43:54
【问题描述】:

我创建了一个与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)
  })
}

我知道可以将rule 变量设置为“可选”,方法是将其默认值设置为null。我想更深入一步,使子变量*可选/必需。例如,在资源文档中写道,必须指定 either *_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 terraform-provider-azure hcl


    【解决方案1】:

    如果有人选择加入,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))
      })
    }
    

    希望此功能能够成为下一个版本中完全受支持的部分。

    【讨论】:

      【解决方案2】:

      如果没有实验性的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
        )
      }
      

      那么你总是可以只用点符号来引用属性。

      【讨论】:

        猜你喜欢
        • 2019-11-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多