This object does not have an attribute named, even so attribut is there (at least I believe so)

I have a list like this

## Create a new rancher2 Projects
locals {
  projects = {
    "demo" = {
      name                            = "Demo",
      description                     = "DEV project for Demo",
      pod_security_policy_template_id = "restricted",
      limits_cpu                      = "2001m",
      limits_memory                   = "1001Mi",
      requests_cpu                    = "11m",
      requests_memory                 = "21Mi",
      requests_storage_project        = "5001Mi",
      requests_storage_namespace      = "5001Mi"
      members = {
         "all-ro" = {
            name="ALL_ReadOnly"
            role="my-project-member-id"
         }
         "ro" = {
            name="Demo_ReadOnly"
            role="my-read-only-id"
         }
         "pm" = {
            name="Demo_ProjectMember"
            role="my-project-member-id"
         }
      }
    },
...
}

I want to dynamically create a list for the project_role_template_binding doing So

locals {
   prtbs = flatten([
      for projectname,project in local.projects: [
         for role, details in project.members : {
            "${projectname}-${role}" = {
               project_name       = "${projectname}"
               role_template_id   = "data.terraform_remote_state.local-state.outputs.${details.role}"
               group_principal_id = "activedirectory_group://CN=${details.name},OU=Groups,DC=wyssmann,DC=com"
            }
         }
      ]
   ])
}

Which generates local.prtbs which I can check in tf console

prtbs = [
    "demo-ro" = {​​​​​​​​
      "group_principal_id" = "activedirectory_group://CN=Demo_ReadOnly,OU=Groups,DC=wyssmann,DC=com"
      "project_name" = "demo"
      "role_template_id" = "data.terraform_remote_state.local-state.outputs.my-read-only-id"
    }​​​​​​​​
  }​​​​​​​​,
]

Now I would like to use the values as follows

resource "rancher2_project_role_template_binding" "prtb" {​​​​​​​​
   for_each = {​​​​​​​​
      for key, value in local.prtbs:
         key => value
   }​​​​​​​​  
  name               = "prtb-${​​​​​​​​each.key}​​​​​​​​"
  project_id         = rancher2_project.pr["${​​​​​​​​each.value.project_name}​​​​​​​​"].id
  role_template_id   = data.terraform_remote_state.nop-local-state.outputs.sc-project-member-id
  group_principal_id = each.value.group_principal_id
}​​​​​​​​

While tf plan complains

Error: Unsupported attribute
  on dyn_project_ns.tf line 21, in resource "rancher2_project_role_template_binding" "prtb":
  21:   project_id         = rancher2_project.pr["${​​​​​​​each.value.project_name}​​​​​​​"].id
    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    β”‚ each.value is object with 1 attribute "demo-ro"
This object does not have an attribute named "project_name".
Error: Unsupported attribute
  on dyn_project_ns.tf line 23, in resource "rancher2_project_role_template_binding" "prtb":
  23:   group_principal_id = each.value.group_principal_id
    β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
    β”‚ each.value is object with 1 attribute "demo-ro"
This object does not have an attribute named "group_principal_id".

I assume the error is cause the keys are quotes with " i.e. "group_principal_id" instead group_principal_id. What am I doing wrong? is it even possible to do what I want to?

Ok, looks like some things worng. First I could create a simple list

locals {
   prtbs = flatten([
      for projectname,project in local.projects : [
         for role, details in project.members: {
            role_name          = "${projectname}-${role}"
            project_name       = "${projectname}"
            role_template_id   = data.terraform_remote_state.nop-local-state.outputs."${details.role}"
            group_principal_id = "activedirectory_group://CN=${details.name},DC=wyssmann,DC=com"
         }
      ]
   ])
}

Which results in something like this

[
  {
    "group_principal_id" = "activedirectory_group://CN=XXXX"
    "project_name" = "demo"
    "role_name" = "demo-all-ro"
    "role_template_id" = "data.terraform_remote_state.nop-local-state.outputs.read-only-id"
  },
  {
    "group_principal_id" = "activedirectory_group://CN=XXXX"
    "project_name" = "demo"
    "role_name" = "demo-pm"
    "role_template_id" = "data.terraform_remote_state.nop-local-state.outputs.sproject-member-id"
  },
  {
    "group_principal_id" = "activedirectory_group://CN=XXXX"
    "project_name" = "acquiring"
    "role_name" = "demo-ro"
    "role_template_id" = "data.terraform_remote_state.nop-local-state.outputs.read-only-id"
  },
]
```

Which then I can use in a simple `for_each`-loop
```
resource "rancher2_project_role_template_binding" "prtb" {
  for_each           = { for entry in local.prtbs : "${entry.role_name}" => entry }
  name               = "prtb-${each.key}"
  project_id         = rancher2_project.pr["${each.value.project_name}"].id
  role_template_id   = each.value.role_template_id
  group_principal_id = each.value.group_principal_id
}
```

Below should fix your problem:

resource "rancher2_project_role_template_binding" "prtb" {​​​​​​​​
  for_each = {for index, role in local.prtbs: keys(role)[0] => values(role)[0] }
  name               = "prtb-${​​​​​​​​each.key}​​​​​​​​"
  project_id         = rancher2_project.pr["${​​​​​​​​each.value.project_name}​​​​​​​​"].id
  role_template_id   = data.terraform_remote_state.nop-local-state.outputs.sc-project-member-id
  group_principal_id = each.value.group_principal_id
}​​​​​​​​
1 Like