terraform

terraform: how to allow variable (missing) attributes using jsondecode


How can I flatten the below json where sometimes permissions are there and sometimes not, assuming I cant control the json and just add a permissions:[] where it's not provided

{
"AVS": { "type": "host" },
"SQL1": {
    "type": "host",
    "permissions": [
        {
            "ad_account": "peter",
            "role": "admin",
            "is_group": false
        }
    ]
},
"SQL2": {
    "type": "host",
    "permissions": [
        {
            "ad_account": "peter",
            "role": "user",
            "is_group": false
        },
        {
            "ad_account": "peter2",
            "role": "admin",
            "is_group": false
        }
    ]
}
}

which I am parsing like this:

locals {
  # Load the default folders from a JSON file.
  default_folders = jsondecode(file("${path.module}/folders.json"))
 
  # flatten ensures that this local value is a flat list of objects, rather
  # than a list of lists of objects, including the additional_folders from the
  # datacenter configuration.
  folders = flatten([
    for datacenter_key, datacenter in var.datacenters : [
      for folder_key, folder in local.default_folders : {
        datacenter_key  = datacenter_key
        datacenter_moid = datacenter.datacenter_moid
        name            = folder_key
        type            = folder.type
      # permissions     = try(folder.permissions, tolist([]))
      # permissions     = folder.permissions == null ? tolist([]) : folder.permissions
      # permissions     = can(folder.permissions) ? folder.permissions : tolist([])
      # permissions     = folder.permissions
      }
    ]
  ])
}
resource "vsphere_folder" "folder" {
  # local.folders is a list, so we must now project it into a map
  # where each key is unique. We'll combine the datacenter and folder keys to
  # produce a single unique key per instance.
  for_each = tomap({
    for folder in local.folders : "${folder.datacenter_moid}.${folder.name}" => folder
  })

  datacenter_id = each.value.datacenter_moid
  path          = each.value.name
  type          = each.value.type
}

I cant figure out how to parse permissions such that it can be a missing attribute and if it is just assign an empty list

Here is the error:

│ Error: Invalid function argument
│ 
│   on ../modules/vcenter/folders.tf line 27, in resource "vsphere_folder" "folder":
│   27:   for_each = tomap({
│   28:     for folder in local.folders : "${folder.datacenter_moid}.${folder.name}" => folder
│   29:   })
│     ├────────────────
│     │ while calling tomap(v)
│     │ local.folders is tuple with 73 elements
│ 
│ Invalid value for "v" parameter: cannot convert object to map of any single type.

Solution

  • The try function and an empty list constructor [] can assist with assigning an empty permissions value during data transformation when the key permissions is absent from the JSON string:

    permissions = try(folder.permissions, [])
    

    This will result in the permissions value when the key is present after decoding, or an empty list when the key is absent after decoding.