terraform tomap() requires some care when using it

Terraform tomap function requires the object to have the same schema otherwise it will give you the following error 

│   on main.tf line 14, in resource "null_resource" "from_yaml_files":

│   14:   for_each = tomap(local.yaml_data)

│     ├────────────────

│     │ while calling tomap(v)

│     │ local.yaml_data is object with 3 attributes

│ Invalid value for "v" parameter: cannot convert object to map of any single type.


Let's see what that looks like in yaml - if you're loading 3 files and all of them have the following - that's great! happy days. But if you have somehing that looks different 

---
name: DisabledApp
version: 0.5
enabled: false
environment: development

items:
  - id: 1
    type: test
    name: test-service
    port: 7000

different like this

---
name: DisabledApp
version: 0.5
enabled: false
environment: development

items:
  - id: 1
    type: test
    name: test-service
    port: 7000

newites: # Extra schemas here - tomap unhappy
  - id: 1
    type: test
    name: test-service
    port: 7000


You can test it with the following -


locals {
 
  # fileset enumerates a set of regular file names given a path and pattern
  yaml_files = fileset("${path.module}/config", "*.yaml")
 
  yaml_data = {
    for file in local.yaml_files :
    file => yamldecode(file("./${path.module}/config/${file}"))
  }
}


resource "null_resource" "from_yaml_files" {
  for_each = tomap(local.yaml_data)

  triggers = {
    filename = each.key
    content  = jsonencode(each.value)
  }
}

of course the solution is just to remove the tomap() and provides default variable in case the list is null (as in there's no files in the config folder.

tomap() forces all your schema to be the same. And we can easily fix it by using the code below (removing to map)

locals {
 
  # fileset enumerates a set of regular file names given a path and pattern
  yaml_files = fileset("${path.module}/config", "*.yaml")
 
  yaml_data = {
    for file in local.yaml_files :
    file => yamldecode(file("./${path.module}/config/${file}"))
  }
}

resource "null_resource" "from_yaml_files" {
  for_each = local.yaml_data

  triggers = {
    filename = each.key
    content  = jsonencode(each.value)
  }
}

The solution will be depends on your use-case or context for example some files we can do some simple checking while other greatly different from one another and potentially has null value. 

source code

https://github.com/kepungnzai/terraform-to-map-example










Comments

Popular posts from this blog

Windows SSH: Permissions for 'private-key' are too open

NodeJS: Error: spawn EINVAL in window for node version 20.20 and 18.20