Difference using modules with count and for_each

Hello

I faced with problem using modules with for_each instead count. I’m trying use modules like described below, and get error:

    Error: Unsupported attribute

      on cloud_configure.tf line 192, in module "user":
     192:   user_group_id = [for x in module.ug[*].ug: x.id if x.label == each.value.user_group_label][0]

    This object does not have an attribute named "label".

    Error: Unsupported attribute

      on cloud_configure.tf line 193, in module "user":
     193:   bucket_id     = [for x in module.bucket[*].bucket: x.id if x.label == each.value.bucket_label][0]

    This object does not have an attribute named "label".

When previously I use count and local.cloud_config was declared as arrays of object I didn’t have this error on terraform plan stage

module "user" {
  count         = length(local.cloud_config["user"])
  source        = "../terraform-modules/user"
  email         = local.cloud_config["user"][count.index].email
  login         = local.cloud_config["user"][count.index].login

  user_group_id = [for x in module.ug[*].ug: x.id if x.label == local.cloud_config["user"][count.index].user_group_label][0]
  bucket_id     = [for x in module.bucket[*].bucket: x.id if x.label == local.cloud_config["user"][count.index].bucket_label][0]
}

So where I wrong?

    locals {
      cloud_config = {
        "user_group" = {
          "tf_ug" = {
            bucket_labels = [
              "tf_bucket"
            ]
          }
        }

        "bucket" = {
          "tf_bucket" = {
            currency_code = "USD"
            monthly_price = 10
          }
        },

        "user" = {
          "user1" = {
            role_labels      = [
              "tf_role1",
              "tf_role3"
            ]
            user_group_label = "tf_ug"
            bucket_label     = "tf_bucket"
          }
        }
      }
    }

    module "bucket" {
      for_each      = local.cloud_config["bucket"]
      source        = "../terraform-modules/bucket"
      currency_code = each.value.currency_code
      label         = each.key
      monthly_price = each.value.monthly_price
    }

    module "ug" {
      for_each   = local.cloud_config["user_group"]
      source     = "../terraform-modules/user_group"
      label      = each.key
    }

    module "user" {
      for_each      = local.cloud_config["user"]
      source        = "../terraform-modules/user"

      role_ids      = flatten([for i in each.value.role_labels : [for r in module.role[*].role : r.id if r.label == i ] ])

      user_group_id = [for x in module.ug[*].ug: x.id if x.label == each.value.user_group_label][0]
      bucket_id     = [for x in module.bucket[*].bucket: x.id if x.label == each.value.bucket_label][0]
    }

Using for_each the module references are based on keys instead of an index.

You could start using module outputs to make the module data structures “visible”.

This is my module output for user_group module.

output "ug" {
  value = user_group.ug
}

As I understand I can’t use construction like this, only should specifies some key?

module.ug[*].ug

But how I can resolve my problem if I want iterate all created user_groups?

That’s my understanding, yes.

So, you have to use a for expression.

Maybe I don’t understand but I allready use this…

user_group_id = [for x in module.ug[*].ug: x.id if x.label == each.value.user_group_label][0]

And got error like on the top of the topic…

It might be rather like (not tested):

user_group_id = [for xx in module.ug: [for x in xx.ug : x.id if x.label == each.value.user_group_label][0]]

Hey,

Nope it didn’t work…
I’m trying run some test in console and got next results, looks like I got only values, but don’t have keys… now I understand where is problem, but don’t know how to fix it…

> [ for xx in module.ug: [ for x in xx.ug: x ]]
[
  [
    {},
    0,
    [
      1,
    ],
    "2021-01-13T11:16:56.000Z",
    0,
    0,
    0,
    "5",
    "qzjkvbgvgdoxkt",
    "tf_ug",
    false,
    0,
    null,
    [],
    "2021-01-13T11:16:56.000Z",
    [],
  ],
 ]

Okay, looks like I’m finally fix this :slight_smile: should be

user_group_id = flatten([ for xx in module.ug: [ for x in xx: x.id if x.label == each.value.user_group_label ] ])[0]

That’s a good start. Depending on your data structures k,v can be access using pattern like for k,v in map : ...