Search code examples
terraformterraform-provider-azurehashicorpterraform-modules

terraform lookup function is not returning null by default


I am trying to decide the Azure Web application stack based on the input using lookup function, however I am getting below error saying to have only one stack in the application_stack block. However the expectation is java_version line should return null. When I try null for java_version it works fine. There is something wrong in my lookup function syntax ?

terraform plan
╷
│ Error: Invalid combination of arguments
│
│   with azurerm_windows_function_app.example,
│   on functionapp.tf line 67, in resource "azurerm_windows_function_app" "example":
│   67:     application_stack {
│
│ "site_config.0.application_stack.0.powershell_core_version": only one of
│ `site_config.0.application_stack.0.dotnet_version,site_config.0.application_stack.0.java_version,site_config.0.application_stack.0.node_version,site_config.0.application_stack.0.powershell_core_version,site_config.0.application_stack.0.use_custom_runtime`
│ can be specified, but `site_config.0.application_stack.0.java_version,site_config.0.application_stack.0.node_version` were specified.

I want to create a web app with node stack version. Below is the terraform code

variable "applicationstack" {
  type = string
  default = "node"  
}

variable "stack_version" {
  type = map
  default ={
    node = "~14"
    java = "8"
  }
}

resource "azurerm_resource_group" "example" {
  name     = "eus-s-test-rg-01"
  location = "eastus"
}

resource "azurerm_storage_account" "example" {
  name                     = "eusperftestjs01"
  resource_group_name      = azurerm_resource_group.example.name
  location                 = azurerm_resource_group.example.location
  account_tier             = "Standard"
  account_replication_type = "LRS"
}


resource "azurerm_service_plan" "example" {
  name                = "example-app-service-plan"
  resource_group_name = azurerm_resource_group.example.name
  location            = azurerm_resource_group.example.location
  os_type             = "Windows"
  sku_name            = "Y1"
}

resource "azurerm_windows_function_app" "example" {
  name                = "eus-perf-test-js-01"
  resource_group_name = azurerm_resource_group.example.name
  location            = azurerm_resource_group.example.location
  storage_account_name       = azurerm_storage_account.example.name
  storage_account_access_key = azurerm_storage_account.example.primary_access_key
  service_plan_id            = azurerm_service_plan.example.id
  site_config {
    application_stack {
      node_version = lookup(var.stack_version,var.applicationstack,null)
      java_version = lookup(var.stack_version,var.applicationstack,null)
    }
  }
}

Solution

  • To expand my answer a bit: in both node_version and java_version arguments you are using the same lookup:

    lookup(var.stack_version,var.applicationstack,null)
    

    From the terraform docs for lookup built-in function:

    lookup retrieves the value of a single element from a map, given its key.

    In other words, you are effectively doing this:

    lookup({node="~14", java="8"}, "node", null)
    

    Since the key node is there in both situations, it will always return a non-null value or "~14" in your case.

    You could try using the ternary operator in terraform for this [1]. The code would have to be changed slightly:

        application_stack {
          node_version = var.applicationstack == "node" ? var.stack_version.node : null
          java_version = var.applicationstack == "node" ? null : var.stack_version.java
        }
    

    The other way to fix it, knowing that the two only possible values for keys are node and java, you could do something like:

        application_stack {
          node_version = lookup(var.stack_version, "node", null)
          java_version = lookup(var.stack_version, "java", null)
        }
    

    However, if you were to use this approach, you would have to assign a different value to the stack_version variable since the default value has both of the keys. For example, in a terraform.tfvars file:

    stack_version = {
      node = "~14"
    }
    

    or if you want to deploy a Java-based app:

    stack_version = {
      java = "8"
    }
    

    [1] https://developer.hashicorp.com/terraform/language/expressions/conditionals