diff --git a/pagerduty/resource_pagerduty_team_membership.go b/pagerduty/resource_pagerduty_team_membership.go index 70456cd4e..2213b7f18 100644 --- a/pagerduty/resource_pagerduty_team_membership.go +++ b/pagerduty/resource_pagerduty_team_membership.go @@ -190,6 +190,44 @@ func resourcePagerDutyTeamMembershipUpdate(d *schema.ResourceData, meta interfac return fetchPagerDutyTeamMembershipWithRetries(d, meta, genError, 0, d.Get("role").(string)) } +func getAllEPsForTeam(client *pagerduty.Client, teamID string) ([]string, error) { + const maxLimit = 100 + var escalationPolicyIDs []string + opts := &pagerduty.ListEscalationPoliciesOptions{ + TeamIDs: []string{teamID}, + Limit: maxLimit, + Offset: 0, + } + + for { + listResp, _, err := client.EscalationPolicies.List(opts) + if err != nil { + return nil, err + } + + for _, ep := range listResp.EscalationPolicies { + escalationPolicyIDs = append(escalationPolicyIDs, ep.ID) + } + + if !listResp.More { + break + } + opts.Offset += opts.Limit + } + return escalationPolicyIDs, nil +} + +func filterEPsAssociatedToTeam(client *pagerduty.Client, teamID string, epsAssociatedToUser []string) ([]string, error) { + // take epsAssociatedToUser and return EP IDs asscociated with teamID + epIdsAssociatedWithTeam, err := getAllEPsForTeam(client, teamID) + if err != nil { + return nil, err + } + + epsInBoth := intersect(epIdsAssociatedWithTeam, epsAssociatedToUser) + return epsInBoth, nil +} + func resourcePagerDutyTeamMembershipDelete(d *schema.ResourceData, meta interface{}) error { client, err := meta.(*Config).Client() if err != nil { @@ -209,7 +247,12 @@ func resourcePagerDutyTeamMembershipDelete(d *schema.ResourceData, meta interfac return err } - epsDissociatedFromTeam, err := dissociateEPsFromTeam(client, teamID, epsAssociatedToUser) + epsAssociatedWithUserAndTeam, err := filterEPsAssociatedToTeam(client, teamID, epsAssociatedToUser) + if err != nil { + return err + } + + epsDissociatedFromTeam, err := dissociateEPsFromTeam(client, teamID, epsAssociatedWithUserAndTeam) if err != nil { return err } @@ -336,3 +379,17 @@ func isTeamMember(user *pagerduty.User, teamID string) bool { return found } + +func intersect(slice1, slice2 []string) []string { + m := make(map[string]struct{}) + for _, item := range slice1 { + m[item] = struct{}{} + } + var intersection []string + for _, item := range slice2 { + if _, found := m[item]; found { + intersection = append(intersection, item) + } + } + return intersection +} diff --git a/pagerduty/resource_pagerduty_team_membership_test.go b/pagerduty/resource_pagerduty_team_membership_test.go index cc6b26d27..1c3c3f2c2 100644 --- a/pagerduty/resource_pagerduty_team_membership_test.go +++ b/pagerduty/resource_pagerduty_team_membership_test.go @@ -297,3 +297,183 @@ resource "pagerduty_escalation_policy" "foo" { } `, user, team, role, escalationPolicy) } + +func TestAccPagerDutyTeamMembership_basic(t *testing.T) { + user := fmt.Sprintf("tf-%s", acctest.RandString(5)) + team1 := fmt.Sprintf("tf-%s", acctest.RandString(5)) + team2 := fmt.Sprintf("tf-%s", acctest.RandString(5)) + role := "manager" + escalationPolicy1 := fmt.Sprintf("tf-%s", acctest.RandString(5)) + escalationPolicy2 := fmt.Sprintf("tf-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPagerDutyTeamMembershipDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutyTeamMembershipDestroyWithEscalationPolicyDependant_UnrelatedEPs(user, team1, team2, role, escalationPolicy1, escalationPolicy2), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyTeamMembershipExists("pagerduty_team_membership.foo"), + testAccCheckPagerDutyTeamMembershipExists("pagerduty_team_membership.bar"), + resource.TestCheckResourceAttr("pagerduty_team_membership.bar", "role", "manager"), + ), + }, + { + Config: testAccCheckPagerDutyTeamMembershipDestroyWithEscalationPolicyDependant_UnrelatedEPsUpdated(user, team1, team2, role, escalationPolicy1, escalationPolicy2), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyTeamMembershipNoExists("pagerduty_team_membership.foo"), + testAccCheckPagerDutyTeamExists("pagerduty_team.foo"), + testAccCheckPagerDutyTeamExists("pagerduty_team.bar"), + testAccCheckPagerDutyEscalationPolicyExists("pagerduty_escalation_policy.foo"), + testAccCheckPagerDutyEscalationPolicyExists("pagerduty_escalation_policy.bar"), + testAccCheckPagerDutyEscalationPolicyTeamsFieldMatches("pagerduty_escalation_policy.foo", "pagerduty_team.foo"), + testAccCheckPagerDutyEscalationPolicyTeamsFieldMatches("pagerduty_escalation_policy.bar", "pagerduty_team.bar"), + ), + }, + }, + }) +} + +func testAccCheckPagerDutyEscalationPolicyTeamsFieldMatches(n, expectedTeam string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + client, _ := testAccProvider.Meta().(*Config).Client() + expectedTeamID, err := getTeamID(s, expectedTeam) + if err != nil { + return err + } + + // get the object from remote state -- tests for prescence + remoteResource, _, err := client.EscalationPolicies.Get(rs.Primary.ID, &pagerduty.GetEscalationPolicyOptions{}) + if err != nil { + return fmt.Errorf("%s\n", err) + } + + if attachedTeam := remoteResource.Teams[0].ID; attachedTeam != expectedTeamID { + return fmt.Errorf("Mismatch detected. Expected %s, and got %s\n", expectedTeamID, attachedTeam) + } + return nil + } +} + +func testAccCheckPagerDutyTeamMembershipDestroyWithEscalationPolicyDependant_UnrelatedEPs(user, team1, team2, role, escalationPolicy1, escalationPolicy2 string) string { + return fmt.Sprintf(` +resource "pagerduty_user" "foo" { + name = "%[1]v" + email = "%[1]v@foo.test" +} + +resource "pagerduty_team" "foo" { + name = "%[2]v" + description = "foo" +} + +resource "pagerduty_team" "bar" { + name = "%[5]v" + description = "bar" +} + +resource "pagerduty_team_membership" "foo" { + user_id = pagerduty_user.foo.id + team_id = pagerduty_team.foo.id + role = "%[3]v" +} + +resource "pagerduty_team_membership" "bar" { + user_id = pagerduty_user.foo.id + team_id = pagerduty_team.bar.id + role = "%[3]v" +} + +resource "pagerduty_escalation_policy" "foo" { + name = "%[4]v" + num_loops = 2 + teams = [pagerduty_team.foo.id] + rule { + escalation_delay_in_minutes = 10 + target { + type = "user_reference" + id = pagerduty_user.foo.id + } + } +} + +resource "pagerduty_escalation_policy" "bar" { + name = "%[6]v" + num_loops = 2 + teams = [pagerduty_team.bar.id] + rule { + escalation_delay_in_minutes = 10 + target { + type = "user_reference" + id = pagerduty_user.foo.id + } + } +} + +`, user, team1, role, escalationPolicy1, team2, escalationPolicy2) +} + +func testAccCheckPagerDutyTeamMembershipDestroyWithEscalationPolicyDependant_UnrelatedEPsUpdated(user, team1, team2, role, escalationPolicy1, escalationPolicy2 string) string { + return fmt.Sprintf(` +resource "pagerduty_user" "foo" { + name = "%[1]v" + email = "%[1]v@foo.test" +} + +resource "pagerduty_team" "foo" { + name = "%[2]v" + description = "foo" +} + +resource "pagerduty_team" "bar" { + name = "%[5]v" + description = "bar" +} +resource "pagerduty_team_membership" "bar" { + user_id = pagerduty_user.foo.id + team_id = pagerduty_team.bar.id + role = "%[3]v" +} + +resource "pagerduty_escalation_policy" "foo" { + name = "%[4]v" + num_loops = 2 + teams = [pagerduty_team.foo.id] + rule { + escalation_delay_in_minutes = 10 + target { + type = "user_reference" + id = pagerduty_user.foo.id + } + } +} + +resource "pagerduty_escalation_policy" "bar" { + name = "%[6]v" + num_loops = 2 + teams = [pagerduty_team.bar.id] + rule { + escalation_delay_in_minutes = 10 + target { + type = "user_reference" + id = pagerduty_user.foo.id + } + } +} +`, user, team1, role, escalationPolicy1, team2, escalationPolicy2) +} + +func getTeamID(s *terraform.State, teamName string) (string, error) { + for name, r := range s.RootModule().Resources { + if name == teamName { + return r.Primary.ID, nil + } + } + return "", fmt.Errorf("Could not find team %s\n", teamName) +} diff --git a/pagerdutyplugin/resource_pagerduty_team_test.go b/pagerdutyplugin/resource_pagerduty_team_test.go index fd35cdfb1..7f76812db 100644 --- a/pagerdutyplugin/resource_pagerduty_team_test.go +++ b/pagerdutyplugin/resource_pagerduty_team_test.go @@ -176,12 +176,14 @@ func testAccCheckPagerDutyTeamDestroy(s *terraform.State) error { return nil } -func testAccCheckPagerDutyTeamExists(_ string) resource.TestCheckFunc { +func testAccCheckPagerDutyTeamExists(n string) resource.TestCheckFunc { return func(s *terraform.State) error { - for _, r := range s.RootModule().Resources { - ctx := context.Background() - if _, err := testAccProvider.client.GetTeamWithContext(ctx, r.Primary.ID); err != nil { - return fmt.Errorf("Received an error retrieving team %s ID: %s", err, r.Primary.ID) + client, _ := testAccProvider.Meta().(*Config).Client() + for name, r := range s.RootModule().Resources { + if name == n { + if _, _, err := client.Teams.Get(r.Primary.ID); err != nil { + return fmt.Errorf("Received an error retrieving team %s ID: %s", err, r.Primary.ID) + } } } return nil