Search code examples
azureterraformterraform-provider-azureazure-container-apps

Pass list of objects into Terraform module as a parameter


I am using this main.tf module in my Terraform script to create an Azure Container App. I need to pass in a complex object with all the values needed to create a Container App.

In the main.tf file of this module, the complex object is iterated over and populates the secrets dynamic block. Notice that it will loop over the secrets list and populate each name/value pair.

resource "azurerm_container_app" "container_app" {
  for_each                     = {for app in var.container_apps: app.name => app}

  name                         = each.key
  ...
  template {
    dynamic "container" {
      ...
      }
    }
    ...
  }

  ...

  dynamic "secret" {
    for_each                     = each.value.secrets != null ? [each.value.secrets] : []
    content {
      name                       = secret.value.name
      value                      = secret.value.value
    }
  }
...

In the variables.tf file for the container_app module, the format of these parameters is specified. Notice that it wants a list of objects (with attributes name and value).

variable "container_apps" {
  description = "Specifies the container apps in the managed environment."
  type = list(object({
    name                           = string
    ...
    secrets                        = optional(list(object({
      name                         = string
      value                        = string
    })))
    ...
    template                       = object({
      containers                   = list(object({
        ...

I want to specify the list of secrets to pass. Here is how I am calling the module.

module "container_app" {
  source         = "./modules/container_app"
  location       = var.location
  ...
  container_apps = [ 
    {
      name = "api"
      ...
      configuration = {
        ...
      }
      secrets = [
        {
          name = "azure-openai-api-key",
          value = module.cognitive_services.azure_cognitive_services_key
        },
        {
          name = "container-registry-admin-secret",
          value = module.container_registry.container_registry_admin_password
        }
      ]
      ...
      template = {
        containers = [
          ...

My complex object includes variables, references to other module's output, etc. Notice that the secrets object is a list of objects (with attributes name and value)

However, this results in an error when I try to apply the Terraform.

  ╷
  │ Error: Unsupported attribute
  │
  │   on modules\container_app\main.tf line 88, in resource "azurerm_container_app" 
  "container_app":
  │   88:       name                       = secret.value.name
  │     ├────────────────
  │     │ secret.value is list of object with 2 elements
  │
  │ Can't access attributes on a list of objects. Did you mean to access attribute "name" 
  for a specific element of the list, or across all elements of the list?
  ╵
  ╷
  │ Error: Unsupported attribute
  │
  │   on modules\container_app\main.tf line 89, in resource "azurerm_container_app" 
  "container_app":
  │   89:       value                      = secret.value.value
  │     ├────────────────
  │     │ secret.value is list of object with 2 elements
  │
  │ Can't access attributes on a list of objects. Did you mean to access attribute "value" 
  for a specific element of the list, or across all elements of the list?
  ╵ 

I don't know how to pass in the correct list of object such that this module can then add those values as secrets in the Container App specification.


Solution

  • You don't need square brackets around [each.value.secrets] as you create a list of lists. It should be:

    for_each                     = each.value.secrets != null ? each.value.secrets : []