How to expand a set from a local value while preserving the index

I am able to create a data source based on below local:

    "aws_group_owner_ids": {
      "value": {
        "AWAS-EXC-Subnet-post-release": [
          "4844f8a3-d715-4e76-8919-d7513cff3d35",
          "c1e26350-5837-42cb-9e43-82ecfadf4047"
        ],
        "AWAS-EXC-Hybrid-Subnet-testing": [
          "4844f8a3-d715-4e76-8919-d7513c7f3d35",
          "c1e26350-5837-42cb-9e43-82ecfad4ff047"
        ]
}

Using this data source expression:

  data "azuread_user" "sec_champs" {
    for_each = {for k,v in local.aws_group_owner_ids: k => v }
    object_id = each.value[0]
   }

This produces for brevities sake below data source values:

    "azuread_user": {
      "value": {
        "AWAS-EXC-Hybrid-Subnet-testing": {
           "mail": "john@myorg.com",
            "user_type": "Member"
        }
}

In my azuread_user data source, I would like to expand on each.value instead of just grabbing the first index (each.value[0] so that I can process all UIDs. I have been banging my head trying to do this with nested for expressions and have the requirement to preserve the index key, i.e. AWAS-EXC-Hybrid-Subnet-testing for later lookups

I managed to figure this out, perhaps in not the most DRY way but thought to share in case it helps someone or if someone can suggest another way. I think it is down to how deep these for expressions can go within a resource/data source. Locals seem to offer more flexibility, even though it is suggested to use them sparingly.

So here goes:

First a flattened set of aws_group_owner_ids to feed the datasource:

 flat_aws_group_owner_ids = toset(flatten([
    for k, v in local.aws_group_owner_ids : [
      for l in local.aws_group_owner_ids[k] : l
    ]
  ]))

very simple datasource lookup:

data "azuread_user" "aws_owners" {
  for_each  = local.flat_aws_group_owner_ids
  object_id = each.value
}

Then I grab the owner emails from the data source by the index key and preserve the key by declaring another local:

owner_emails = [for k, v in local.aws_group_owner_ids : {
    for o in local.aws_group_owner_ids[k] : k => data.azuread_user.aws_owners[o].mail...
}

Lastly I figured out to cast using tomap and use merge to collapse the tuple, in order to have a single map for further referencing in for expressions :

aws_owner_emails = tomap(merge([for k, v in local.aws_group_owner_ids : {
  for o in local.aws_group_owner_ids[k] : k => data.azuread_user.aws_owners[o].mail...
  }
]...))

Wishing someday for HCL debugging support, would be helpful to step into code to see what’s going on :slight_smile:

I’m glad you got to something that worked for you.

Bear in mind that a number of your expressions were a bit more complicated than they needed to be - here are some suggestions:

This expression can be simplified to just:

    for_each = local.aws_group_owner_ids

can be simplified to just:

  for_each = toset(flatten(values(local.aws_group_owner_ids)))

can be simplified to:

  aws_owner_emails = {
    for k, v in local.aws_group_owner_ids :
    k => [for o in v: data.azuread_user.aws_owners[o].mail]
  }
1 Like

Nice, this is much more elegant thank you. One thing I wanted to understand is that when we build the below expression, the way you do it:
k => [for o in v: data.azuread_user.aws_owners[o].mail]

What are we telling the compiler to do when expression for the desired index key is in brackets?

I’m having trouble figuring out what you mean by “desired index key”.

The outer square brackets:

[for o in v: data.azuread_user.aws_owners[o].mail]

are part of the syntax of a for expression (For Expressions - Configuration Language | Terraform | HashiCorp Developer) that is producing a tuple.

The inner square brackets:

data.azuread_user.aws_owners[o]

are the syntax for referencing any data source that uses for_each.