terraformterraform-provider-azure

How to handle empty list for dynamic block


This is regarding an Azure resource, app_service, but I think it’s a more general HCL question…

You can specify IP restrictions to an app_service using a dynamic block e.g.

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

However, to remove the restrictions you need to explicit assign ip_restriction to the empty list, i.e.

resource "azurerm_app_service" "example" {
  ...

  ip_restriction = []
}

What I don’t see is how to do this conditionally - if I make two resources and have those conditional my app_service will be created/destroyed whereas I need it updated in place.


Solution

  • I'm afraid that the dynamic block does not support an empty list when using a conditional expression. Read more reference here.

    After my validation, the conditional expression like for_each = var.some_variable == "" ? [] : [1] does not work when var.some_variable set to null but this could work seperately when for_each = var.some_variable and var.some_variable set to null.

    So, in this case, as the answer from @rkm, you can use the for loop like this working sample for me.

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