0

I Want to add the users to the team and assigned them roles as per the yaml but the error is value does not have any attributes. i will have multiple users in single team with different roles

this is variables.tf

variable "admin_role_id" {
  description = "The id to give access admin role to the user"
  type        = string
  default     = "1111111111111"
}


variable "user_role_id" {
  description = "The id to give access user role to the user"
  type        = string
  default     = "22222222222222222"
}

this is my yaml file

TEAM1:
  - users: 
     - joe@gmail.com
     - pa@gmail.com
    roles:
    -  ${user_role}
    - ${admin_role}
  - users:
    - test@gmail.com
    roles:
     - ${user_role}
TEAM2:
  - users: 
     -  joe@gmail.com
    roles:
    - ${test_user_role}

This is TERRAFORM CODE i am using local variable and i flatten the values there

locals {
  render_membership = templatefile("${path.module}/teammembers.yaml",
    {
      admin_role    = var.admin_role_id
      user_role     = var.user_role_id
    }
  )

  membership_nested = yamldecode(local.render_membership)



  membership_flat = flatten(
    [
      for team_key, team in local.membership_nested : [
        for user in team.users : {
          team_name = team_key
          user_name = user
          roles     = team.roles
        }
      ]
    ]
  )
}

resource "squadcast_team_member" "membership" {
  for_each = { for i, v in local.membership_flat : i => v }
  team_id  = data.squadcast_team.teams[each.value.team_name].id
  user_id  = data.squadcast_user.users[each.value.user_name].id
  role_ids = each.value.roles
}

data "squadcast_team" "teams" {
  for_each = { for i, v in local.membership_flat : i => v }
  name     = each.value.team_name
}

data "squadcast_user" "users" {
  for_each = { for i, v in local.membership_flat : i => v }
  email    = each.value.user_name
}

output "rendered_yaml" {
  value = local.membership_nested
}

Error:

│ Error: Unsupported attribute
│ 
│   on teammembers.tf line 112, in locals:
│  112:         for user in team.users : {
│ 
│ This value does not have any attributes.
Dhaval Shah
  • 144
  • 1
  • 8
  • This question looks similar to [this one](https://stackoverflow.com/questions/74746192/if-loop-to-ignore-null-value-for-conditional-checks/74788038#74788038), same logic can be applied. – Leo Jan 04 '23 at 11:41
  • can you help with that @Leo – Dhaval Shah Jan 04 '23 at 12:58

1 Answers1

0

Decoding the YAML document you showed would produce the following Terraform value:

{
  TEAM1 = [
    {
      users = [
        "joe@gmail.com",
        "pa@gmail.com",
      ]
      roles = [
        "...",
        "...",
      ]
    },
  ]
  TEAM2 = [
    {
      users = [
        "joe@gmail.com",
      ]
      roles = [
        "...",
      ],
    },
  ]
}

Notice that the values assigned to TEAM1 and TEAM2 are lists -- or more accurately: tuples -- that each contain one object.

That means that in your membership_flat expression the value of team in the first for expression is not an object, and so it's not valid to write team.users: the . operator for accessing an attribute is only valid for object types or map types.


If the structure of this YAML is fixed and you need to change the Terraform configuration to work with it then one way would be to access the first element of the tuple and then take the users attribute of that object:

for user in team[0].users : {

This solution will only work if your team values are always single-element sequences. If you had a team with more than one object assigned to it then the above expression would ignore the other elements, and if you had a team with zero objects assigned to it then it would fail because there would be no index zero.


If you are able to change the YAML structure instead, then I would suggest removing the YAML sequences so that each "team" is represented by only a single mapping, which Terraform will then decode as a single object:

TEAM1:
  users: 
    - joe@gmail.com
    - pa@gmail.com
  roles:
    -  ${user_role}
    - ${admin_role}
TEAM2:
  users: 
    - joe@gmail.com
  roles:
    - ${test_user_role}

Terraform's yamldecode would decode the above to the following value instead:

{
  TEAM1 = {
    users = [
      "joe@gmail.com",
      "pa@gmail.com",
    ]
    roles = [
      "...",
      "...",
    ]
  }
  TEAM2 = {
    users = [
      "joe@gmail.com",
    ]
    roles = [
      "...",
    ],
  }
}

Notice that now each team is just a single object rather than a tuple of objects, and so team.users would now be a valid way to access the users attribute of each single object.

Martin Atkins
  • 62,420
  • 8
  • 120
  • 138