如何处理动态块的空列表

How to handle empty list for dynamic block

这是关于 Azure 资源的,app_service,但我认为这是一个更一般的 HCL 问题……

您可以使用动态块将 IP 限制指定给 app_service,例如

locals {
  ip_addresses = [ "192.168.250.1" ]
}

resource "azurerm_resource_group" "example" {
  name     = "example-resources"
  location = "West Europe"
}

resource "azurerm_app_service_plan" "example" {
  name                = "example-appserviceplan"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name

  sku {
    tier = "Standard"
    size = "S1"
  }
}

resource "azurerm_app_service" "example" {
  name                = "example-app-service"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name
  app_service_plan_id = azurerm_app_service_plan.example.id

  site_config {
    dotnet_framework_version = "v4.0"
    scm_type                 = "LocalGit"
  }

  app_settings = {
    "SOME_KEY" = "some-value"
  }

  connection_string {
    name  = "Database"
    type  = "SQLServer"
    value = "Server=some-server.mydomain.com;Integrated Security=SSPI"
  }

  dynamic "ip_restriction" {
    for_each = toset(local.ip_addresses)
    content {
      ip_address = each.value
    }
  }  
}

但是,要删除限制,您需要将 ip_restriction 显式分配给空列表,即

resource "azurerm_app_service" "example" {
  ...

  ip_restriction = []
}

我看不到如何有条件地执行此操作 - 如果我制作两个资源并有条件地使用这些资源,我的 app_service 将是 created/destroyed,而我需要就地更新它。

这是一种特殊的 terraform 语法,称为 Attributes as Blocks. Resource arguments defined using nested block syntax implicitly define a fixed collection of objects,因此为了指定零个对象,我们应该明确设置空列表。而且这两种形式不能混用。

话虽如此,terraform 也支持参数语法(尽管他们建议在简单情况下使用块语法以提高可读性):

example = [
  for name in var.names: {
    foo = name
  }
]

恐怕动态块在使用条件表达式时不支持空列表。阅读更多参考 here.

经过我的验证,当 var.some_variable 设置为 null 时,像 for_each = var.some_variable == "" ? [] : [1] 这样的条件表达式不起作用,但是当 for_each = var.some_variablevar.some_variable 设置为 null.

因此,在这种情况下,作为@rkm 的回答,您可以使用 for 循环,就像我的这个工作示例一样。

variable "ip_restrictions" {

default = [
    #   {
    #   ip_address = "1.1.1.1/32"
    #   virtual_network_subnet_id = null
    #   subnet_id = null
    #   name = "aaa"
    #   priority = 110
    #   action = "Allow"
    # },

    # {
    #   ip_address = "2.2.2.2/32"
    #   virtual_network_subnet_id = null
    #   subnet_id = null
    #   name = "bbb"
    #   priority = 112
    #   action = "Allow"
    # },

]

}


resource "azurerm_app_service" "example" {
  name                = "nn-example-app-service"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name
  app_service_plan_id = azurerm_app_service_plan.example.id

  site_config {

  ip_restriction =  [

   for s in var.ip_restrictions :

   {

      ip_address = s.ip_address
      virtual_network_subnet_id = s.virtual_network_subnet_id
      subnet_id = s.subnet_id
      name = s.name
      priority = s.priority
      action = s.action

   }
  ]
}
}