Search code examples
for-loopnestedterraform

obtaining a list of objects from a complex nested object in terraform


I am trying to create a local variable "secret_list" in terraform based on a variable "secrets" that is defined in a tfvars.json file.

The "secrets" variable looks like this:

{
"secrets" : {
        "datacore": {
            "secrets" : [
                {"secret_scope": "datacore", "secret_key": "serviceaccount-databricks-deploy", "secret_value": "dummy"},
                {"secret_scope": "datacore", "secret_key": "serviceaccount-datacore", "secret_value": "dummy"}
            ],
            "acls" : [
                {"secret_scope": "datacore", "principal": "admins", "permission": "MANAGE"},
                {"secret_scope": "datacore", "principal": "Datacore Power Users", "permission": "READ"}
            ]
        },
        "ai" : {
            "secrets" : [
                {"secret_scope": "ai", "secret_key": "serviceaccount-ai", "secret_value": "dummy"},
                {"secret_scope": "ai", "secret_key": "serviceaccount-ai-private-key", "secret_value": "dummy"}
            ],
            "acls" : [
                {"secret_scope": "ai", "principal": "admins", "permission": "MANAGE"},
                {"secret_scope": "ai", "principal": "AI Power Users", "permission": "READ"}
            ]
        }
   }
}

its structure is described as:

variable "secrets" {
    type = map(object({
            secrets = list(
                object({
                    secret_scope = string,
                    secret_key = string,
                    secret_value =string
                })),
            acls = list(
                object({
                    secret_scope = string,
                    principal = string,
                    permission = string
            }))}))
}

I want to create a new local variable "secret_list" which outputs this:

secret_list =  [
{"secret_scope": "datacore", "secret_key": "serviceaccount-databricks-deploy", "secret_value": "dummy"},
{"secret_scope": "datacore", "secret_key": "serviceaccount-databricks-deploy", "secret_value": "dummy"},
{"secret_scope": "ai", "secret_key": "serviceaccount-ai", "secret_value": "dummy"},
{"secret_scope": "ai", "secret_key": "serviceaccount-ai-private-key", "secret_value": "dummy"}
]

This is a list of objects that contains all the secrets that are inside the "secrets" variable.

I have tried to create a local variable "secret_list" using a for loop like this:

locals {
    secret_list = {
        value = flatten([
            for secrets in var.secrets : [
                for secret_attributes in secrets.secrets : secret_attributes
            ]
        ])
    }
}

and created a new output object to view the result in the console:

output "secret_list" {
  value = local.secret_list
}

I cannot seem to get the desired output. In the console it looks like:

 secret_list              = {
      + value = [
          + {
              + secret_key   = "serviceaccount-databricks-deploy"
              + secret_scope = "datacore"
              + secret_value = "dummy"
            },
          + {
              + secret_key   = "serviceaccount-datacore"
              + secret_scope = "datacore"
              + secret_value = "dummy"
            },
          + {
              + secret_key   = "serviceaccount-ai"
              + secret_scope = "ai"
              + secret_value = "dummy"
            },
          + {
              + secret_key   = "serviceaccount-ai-private-key"
              + secret_scope = "ai"
              + secret_value = "dummy"
            }
       ]
}

How can I get to:

secret_list =  [
{"secret_scope": "datacore", "secret_key": "serviceaccount-databricks-deploy", "secret_value": "dummy"},
{"secret_scope": "datacore", "secret_key": "serviceaccount-databricks-deploy", "secret_value": "dummy"},
{"secret_scope": "ai", "secret_key": "serviceaccount-ai", "secret_value": "dummy"},
{"secret_scope": "ai", "secret_key": "serviceaccount-ai-private-key", "secret_value": "dummy"}
]

Solution

  • To remove the delta between the observed and desired structures, your locals block with the for expressions:

    locals {
      secret_list = {
        value = flatten([
          for secrets in var.secrets : [
            for secret_attributes in secrets.secrets : secret_attributes
          ]
        ])
      }
    }
    

    needs to not specify an outer map constructor with a key of value. The value of that map should be the entire structure:

    locals {
      secret_list = flatten([
        for secrets in var.secrets : [
          for secret_attributes in secrets.secrets : secret_attributes
        ]
      ])
    }