Terraform: how to iterate over key-value pairs of map input via json file

12.5k views Asked by At

This is my input json file:

{
  "inputs": [
        {
          "acct_id": "foo-bar-15",
          "display_name": "foo bar",
          "project-role-pairs": {"test-1234": "roles/logging.logWriter", "test-2345": "roles/storage.objectViewer"}
        },
        {
          "acct_id": "foo-bar-16",
          "display_name": "john doe",
          "project-role-pairs": {"test-3456": "roles/logging.logWriter", "test-4567": "roles/storage.objectViewer"}
        }
      ]
}

CODE: This is my code that create service accounts in GCP based on the input (That part works fine). It also tries to create IAM roles in 2 projects based on project-roles-pairs map in the json file above. I am unable to interate over the map. I simply don't know why. Code, as it stands right now, simply uses the first key in the map for both as if there isn't a second pair of key-values. I have looked to "flatten" and dynamic blocks and setproduct. They seems to not fit the use case OR I am not able use them effectively. Please help.

locals {
  json_data_7 = jsondecode(file("./data7.json"))
}


# Creates a Service Account for each top level in input
resource "google_service_account" "service_accounts_for_each_7" {
  for_each = {for v in local.json_data_7.inputs: v.acct_id => v.display_name}
  account_id   = each.key
  display_name = each.value
}

# 
resource "google_project_iam_member" "rolebinding" {
  for_each     = { for v in local.json_data_7.inputs: v.acct_id => v }
  project = element(keys(each.value.project-role-pairs),0)  #ONLYfirst key in MAP , not what I want, I would like this part loop through map and create a role for each KV-pair in JSON input
  role    = lookup(each.value.project-role-pairs,element(keys(each.value.project-role-pairs),0))
  member  = "serviceAccount:${google_service_account.service_accounts_for_each_7[each.key].email}"
}

The question:

How do I make my code iterate over the 2 key-value pairs input in: project-roles-pairs in the JSON file ? Thank you.

1

There are 1 answers

2
Marcin On BEST ANSWER

If I understand correctly, you need to iterate twice over inputs and over project-role-pairs. Thus, you can create a helper_list first as follows:

locals {

  helper_list = flatten([ for v in local.json_data_7.inputs: 
            [ for project, role in v.project-role-pairs:
             { "project" = project
               "role" = role
                acct_id = v.acct_id
                display_name = v.display_name}
            ]
          ])
}

The above will result in helper_list being:

[
  {
    "acct_id" = "foo-bar-15"
    "display_name" = "foo bar"
    "project" = "test-1234"
    "role" = "roles/logging.logWriter"
  },
  {
    "acct_id" = "foo-bar-15"
    "display_name" = "foo bar"
    "project" = "test-2345"
    "role" = "roles/storage.objectViewer"
  },
  {
    "acct_id" = "foo-bar-16"
    "display_name" = "john doe"
    "project" = "test-3456"
    "role" = "roles/logging.logWriter"
  },
  {
    "acct_id" = "foo-bar-16"
    "display_name" = "john doe"
    "project" = "test-4567"
    "role" = "roles/storage.objectViewer"
  },
]

Subsequently, your google_project_iam_member could be:

resource "google_project_iam_member" "rolebinding" {
  for_each     = { for idx, v in local.helper_list: idx => v }
  project = each.value.project
  role    = each.value.role
  member  = "serviceAccount:${google_service_account.service_accounts_for_each_7[each.value.acct_id].email}"
}

Note, that the above probably needs adjustments, as I'm not normally using GCP, thus I can't verify how exactly google_project_iam_member should look like.