PagerDuty / terraform-provider-pagerduty

Terraform PagerDuty provider
https://www.terraform.io/docs/providers/pagerduty/
Mozilla Public License 2.0
204 stars 208 forks source link

pagerduty_team_membership should accept a list of teams #452

Open nwsparks opened 2 years ago

nwsparks commented 2 years ago

pagerduty_user shows teams as being deprecated. this field accepts a list.

It is recommended to use pagerduty_team_membership, however this does not accept a list.

This makes it quite difficult to apply team memberships efficiently, such as this when looping over a map:

locals {
  users = [
    { email = "email@gmail.com", name = "person", role = "admin", teams = ["role1","role2"]}
  ]
}

If you're going to deprecate and remove teams from users, I think that pagerduty_team_membership should provide the same original functionality as what is being deprecated.

imjaroiswebdev commented 2 years ago

Hi there @nwsparks at this time the new API for team_membership doesn't accept an array of team ID to be assign as you pointed out, but if you since Terraform 0.12.6, the new HCL syntax supports the use of for_each meta-argument to loop through maps and sets of strings. So I managed to recreate the previous resource configuration using HCL to assign the teams to the array of users.

The solution consist in converting your array of users to a map with unique keys where each value contains every team that needs to be assigned to the user, and its own information to configure the resource. I know this may be cumbersome, but you can solve it with this for the time being. ✌🏽

You can verify the solution with HCL snippet below, which implements the solution...

locals {
  testLabel = toset(["lt_1", "lt_2", "lt_3", "lt_4"])
}
resource "pagerduty_user" "tf_user" {
  for_each = local.testLabel
  name     = "local_user_${each.value}"
  email    = "local.user.${each.value}.testing@foo.test"
}
resource "pagerduty_team" "tf_team_tm" {
  for_each    = local.testLabel
  name        = "TF Team for Local Testing ${each.value}"
  description = "A new team created with Terraform for local testing"
}

# This is the same structure that you mentioned.
locals {
  users = [
    { email = "local.user.lt_1.testing@foo.test", name = "local_user_lt_1", role = "responder", teams = [pagerduty_team.tf_team_tm["lt_2"].id, pagerduty_team.tf_team_tm["lt_3"].id] },
    { email = "local.user.lt_2.testing@foo.test", name = "local_user_lt_2", role = "observer", teams = [pagerduty_team.tf_team_tm["lt_1"].id, pagerduty_team.tf_team_tm["lt_4"].id] },
    { email = "local.user.lt_3.testing@foo.test", name = "local_user_lt_3", role = "responder", teams = [pagerduty_team.tf_team_tm["lt_1"].id] },
    { email = "local.user.lt_4.testing@foo.test", name = "local_user_lt_4", role = "observer", teams = [pagerduty_team.tf_team_tm["lt_1"].id, pagerduty_team.tf_team_tm["lt_2"].id, pagerduty_team.tf_team_tm["lt_3"].id] },
  ]
}

data "pagerduty_user" "users" {
  depends_on = [
    pagerduty_user.tf_user,
  ]
  for_each = toset([for u in local.users : u.email])
  email    = each.value
}

locals {
  # Conversion to map of unique keys for looping throut it in regards of using the `for_each` meta-argument.
  userTeamPairs = flatten([for u in local.users : [
    for t in u.teams : {
      user_id : data.pagerduty_user.users[u.email].id
      user : u
      team : t
    }
  ]])
}

output "userTeamPairs" {
  value = local.userTeamPairs
}

resource "pagerduty_team_membership" "foo_tm" {
  depends_on = [
    pagerduty_user.tf_user,
    pagerduty_team.tf_team_tm,
  ]

  # Here you are looping through the user's data and teams to create every needed `team_membership` block
  for_each = {
    for utpair in local.userTeamPairs : "${utpair.user.email}.${utpair.team}" => utpair
  }
  user_id = each.value.user_id
  team_id = each.value.team
  role    = each.value.user.role
}

output "foo_tm" {
  depends_on = [
    pagerduty_team_membership.foo_tm
  ]
  value = pagerduty_team_membership.foo_tm
}

State resulting for the team_memberships resource blocks would be...

foo_tm = {
  "local.user.lt_1.testing@foo.test.P680208" = {
    "id" = "PDKB540:P680208"
    "role" = "responder"
    "team_id" = "P680208"
    "user_id" = "PDKB540"
  }
  "local.user.lt_1.testing@foo.test.P9HO2CY" = {
    "id" = "PDKB540:P9HO2CY"
    "role" = "manager"
    "team_id" = "P9HO2CY"
    "user_id" = "PDKB540"
  }
  "local.user.lt_2.testing@foo.test.P2YC1NI" = {
    "id" = "PHWM5GQ:P2YC1NI"
    "role" = "observer"
    "team_id" = "P2YC1NI"
    "user_id" = "PHWM5GQ"
  }
  "local.user.lt_2.testing@foo.test.PQTZ3RL" = {
    "id" = "PHWM5GQ:PQTZ3RL"
    "role" = "observer"
    "team_id" = "PQTZ3RL"
    "user_id" = "PHWM5GQ"
  }
  "local.user.lt_3.testing@foo.test.PQTZ3RL" = {
    "id" = "PAOQ4RA:PQTZ3RL"
    "role" = "responder"
    "team_id" = "PQTZ3RL"
    "user_id" = "PAOQ4RA"
  }
  "local.user.lt_4.testing@foo.test.P680208" = {
    "id" = "PT2E2MK:P680208"
    "role" = "manager"
    "team_id" = "P680208"
    "user_id" = "PT2E2MK"
  }
  "local.user.lt_4.testing@foo.test.P9HO2CY" = {
    "id" = "PT2E2MK:P9HO2CY"
    "role" = "observer"
    "team_id" = "P9HO2CY"
    "user_id" = "PT2E2MK"
  }
  "local.user.lt_4.testing@foo.test.PQTZ3RL" = {
    "id" = "PT2E2MK:PQTZ3RL"
    "role" = "observer"
    "team_id" = "PQTZ3RL"
    "user_id" = "PT2E2MK"
  }
}

In the console you would be able to see the users assigned to their corresponding teams

Screen Shot 2022-06-06 at 19 58 38