Skip to content

Commit 95bc6c1

Browse files
Merge pull request #863 from imjaroiswebdev/issue-709-err-removing-user
Return remediation measures for team membership deletion with EP dependencies
2 parents 48f4bed + 93f2cde commit 95bc6c1

File tree

2 files changed

+210
-90
lines changed

2 files changed

+210
-90
lines changed

pagerduty/resource_pagerduty_team_membership.go

Lines changed: 50 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"log"
66
"net/http"
7+
"net/url"
78
"strings"
89
"time"
910

@@ -201,23 +202,19 @@ func resourcePagerDutyTeamMembershipDelete(d *schema.ResourceData, meta interfac
201202
return err
202203
}
203204

204-
log.Printf("[DEBUG] Removing user: %s from team: %s", userID, teamID)
205-
206-
// Extract Escalation Policies associated to the team for which the userID is
207-
// a rule target.
208-
epsAssociatedToTeamAndUser, err := extractEPsAssociatedToTeamAndUser(client, teamID, userID)
209-
if err != nil {
210-
return err
211-
}
212-
213-
epsDissociatedFromTeam, err := dissociateEPsFromTeam(client, teamID, epsAssociatedToTeamAndUser)
214-
if err != nil {
215-
return err
216-
}
217-
218-
// Retrying to give other resources (such as escalation policies) to delete
205+
var isFoundErrRemovingUserFromTeam bool
219206
retryErr := retry.Retry(2*time.Minute, func() *retry.RetryError {
220207
if _, err := client.Teams.RemoveUser(teamID, userID); err != nil {
208+
if isErrCode(err, 400) && strings.Contains(err.Error(), "User cannot be removed as they belong to an escalation policy on this team") {
209+
if !isFoundErrRemovingUserFromTeam {
210+
// Giving some time for the escalation policies to be removed during destroy operations.
211+
time.Sleep(2 * time.Second)
212+
isFoundErrRemovingUserFromTeam = true
213+
return retry.RetryableError(err)
214+
}
215+
216+
return retry.NonRetryableError(err)
217+
}
221218
if isErrCode(err, 400) {
222219
return retry.RetryableError(err)
223220
}
@@ -226,25 +223,57 @@ func resourcePagerDutyTeamMembershipDelete(d *schema.ResourceData, meta interfac
226223
}
227224
return nil
228225
})
226+
if retryErr != nil && isFoundErrRemovingUserFromTeam {
227+
// Extract Escalation Policies associated to the team for which the userID is
228+
// a rule target.
229+
epsAssociatedToUser, err := extractEPsAssociatedToTeamAndUser(client, teamID, userID)
230+
if err != nil {
231+
return fmt.Errorf("%v; %w", retryErr, err)
232+
}
233+
234+
if len(epsAssociatedToUser) > 0 {
235+
pdURLData, err := url.Parse(epsAssociatedToUser[0])
236+
if err != nil {
237+
return fmt.Errorf("%v; %w", retryErr, err)
238+
}
239+
240+
accountSubdomain := strings.Split(pdURLData.Hostname(), ".")[0]
241+
var formatEPsList = func(eps []string) string {
242+
var formated []string
243+
for _, ep := range eps {
244+
formated = append(formated, fmt.Sprintf("\t* %s", ep))
245+
}
246+
return strings.Join(formated, "\n")
247+
}
248+
249+
return fmt.Errorf(`User %[1]q can't be removed from Team %[2]q as they belong to an Escalation Policy on this team.
250+
Please take only one of the following remediation measures in order to unblock the Team Membership removal:
251+
1. Remove the user from the following Escalation Policies:
252+
%[4]s
253+
2. Remove the Escalation Policies from the Team https://%[3]s.pagerduty.com/teams/%[2]s
254+
255+
After completing one of the above given remediation options come back to continue with the destruction of Team Membership.`,
256+
userID,
257+
teamID,
258+
accountSubdomain,
259+
formatEPsList(epsAssociatedToUser),
260+
)
261+
}
262+
}
229263
if retryErr != nil {
230264
time.Sleep(2 * time.Second)
231265
return retryErr
232266
}
233267

234268
d.SetId("")
235269

236-
err = associateEPsBackToTeam(client, teamID, epsDissociatedFromTeam)
237-
if err != nil {
238-
return err
239-
}
240-
241270
return nil
242271
}
243272

244273
func buildEPsIdsList(l []*pagerduty.EscalationPolicy) []string {
245274
eps := []string{}
246275
for _, o := range l {
247-
eps = append(eps, o.ID)
276+
eps = append(eps, o.HTMLURL)
248277
}
249278
return unique(eps)
250279
}
@@ -288,59 +317,6 @@ func extractEPsAssociatedToTeamAndUser(c *pagerduty.Client, teamID, userID strin
288317
return epsAssociatedToTeamAndUser, nil
289318
}
290319

291-
func dissociateEPsFromTeam(c *pagerduty.Client, teamID string, eps []string) ([]string, error) {
292-
epsDissociatedFromTeam := []string{}
293-
for _, ep := range eps {
294-
retryErr := retry.Retry(2*time.Minute, func() *retry.RetryError {
295-
_, err := c.Teams.RemoveEscalationPolicy(teamID, ep)
296-
if err != nil && !isErrCode(err, 404) {
297-
time.Sleep(2 * time.Second)
298-
return retry.RetryableError(err)
299-
}
300-
if err != nil && isErrCode(err, 404) {
301-
return retry.NonRetryableError(err)
302-
}
303-
return nil
304-
})
305-
if retryErr != nil {
306-
if !isErrCode(retryErr, 404) {
307-
return nil, fmt.Errorf("%w; Error while trying to dissociate Team %q from Escalation Policy %q", retryErr, teamID, ep)
308-
} else {
309-
// Skip Escaltion Policies not found. This happens when a destroy
310-
// operation is requested and Escalation Policy is destroyed first.
311-
continue
312-
}
313-
}
314-
epsDissociatedFromTeam = append(epsDissociatedFromTeam, ep)
315-
log.Printf("[DEBUG] EscalationPolicy %s removed from team %s", ep, teamID)
316-
}
317-
return epsDissociatedFromTeam, nil
318-
}
319-
320-
func associateEPsBackToTeam(c *pagerduty.Client, teamID string, eps []string) error {
321-
for _, ep := range eps {
322-
retryErr := retry.Retry(2*time.Minute, func() *retry.RetryError {
323-
_, err := c.Teams.AddEscalationPolicy(teamID, ep)
324-
if err != nil && !isErrCode(err, 404) {
325-
time.Sleep(2 * time.Second)
326-
return retry.RetryableError(err)
327-
}
328-
return nil
329-
})
330-
if retryErr != nil {
331-
if !isErrCode(retryErr, 404) {
332-
return fmt.Errorf("%w; Error while trying to associate back team %q to Escalation Policy %q. Resource succesfully deleted, but some team association couldn't be completed, so you need to run \"terraform plan -refresh-only\" and again \"terraform apply/destroy\" in order to remediate the drift", retryErr, teamID, ep)
333-
} else {
334-
// Skip Escaltion Policies not found. This happens when a destroy
335-
// operation is requested and Escalation Policy is destroyed first.
336-
continue
337-
}
338-
}
339-
log.Printf("[DEBUG] EscalationPolicy %s added to team %s", ep, teamID)
340-
}
341-
return nil
342-
}
343-
344320
func isTeamMember(user *pagerduty.User, teamID string) bool {
345321
var found bool
346322

0 commit comments

Comments
 (0)