Skip to content

Commit

Permalink
Merge pull request #686 from imjaroiswebdev/recreate-on-external-dele…
Browse files Browse the repository at this point in the history
…tion-tag-assignment-and-team

Plan recreation of tag assignments and teams on external to Terraform deletion
  • Loading branch information
imjaroiswebdev authored May 15, 2023
2 parents f38b960 + 0c25cf6 commit 4f595a6
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 4 deletions.
54 changes: 54 additions & 0 deletions pagerduty/resource_pagerduty_tag_assignment.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package pagerduty
import (
"fmt"
"log"
"net/http"
"strings"
"time"

Expand Down Expand Up @@ -106,6 +107,15 @@ func resourcePagerDutyTagAssignmentRead(d *schema.ResourceData, meta interface{}

log.Printf("[INFO] Reading PagerDuty tag assignment with tagID %s for %s entity with ID %s", assignment.TagID, assignment.EntityType, assignment.EntityID)

ok, err := isFoundTagAssignmentEntity(d.Get("entity_id").(string), d.Get("entity_type").(string), meta)
if err != nil {
return err
}
if !ok {
d.SetId("")
return nil
}

return resource.Retry(30*time.Second, func() *resource.RetryError {
if tagResponse, _, err := client.Tags.ListTagsForEntity(assignment.EntityType, assignment.EntityID); err != nil {
time.Sleep(2 * time.Second)
Expand Down Expand Up @@ -202,6 +212,50 @@ func resourcePagerDutyTagAssignmentImport(d *schema.ResourceData, meta interface
return []*schema.ResourceData{d}, err
}

func isFoundTagAssignmentEntity(entityID, entityType string, meta interface{}) (bool, error) {
var isFound bool
client, err := meta.(*Config).Client()
if err != nil {
return isFound, err
}

fetchUser := func(id string) (*pagerduty.User, *pagerduty.Response, error) {
return client.Users.Get(id, &pagerduty.GetUserOptions{})
}
fetchTeam := func(id string) (*pagerduty.Team, *pagerduty.Response, error) {
return client.Teams.Get(id)
}
fetchEscalationPolicy := func(id string) (*pagerduty.EscalationPolicy, *pagerduty.Response, error) {
return client.EscalationPolicies.Get(id, &pagerduty.GetEscalationPolicyOptions{})
}
retryErr := resource.Retry(30*time.Second, func() *resource.RetryError {
var err error
if entityType == "users" {
_, _, err = fetchUser(entityID)
}
if entityType == "teams" {
_, _, err = fetchTeam(entityID)
}
if entityType == "escalation_policies" {
_, _, err = fetchEscalationPolicy(entityID)
}

if err != nil && isErrCode(err, http.StatusNotFound) {
return nil
}
if err != nil {
return resource.RetryableError(err)
}
isFound = true

return nil
})
if retryErr != nil {
return isFound, retryErr
}
return isFound, nil
}

func createAssignmentID(entityID, tagID string) string {
return fmt.Sprintf("%v.%v", entityID, tagID)
}
97 changes: 95 additions & 2 deletions pagerduty/resource_pagerduty_tag_assignment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/heimweh/go-pagerduty/pagerduty"
)

func TestAccPagerDutyTagAssignment_User(t *testing.T) {
Expand All @@ -32,6 +33,24 @@ func TestAccPagerDutyTagAssignment_User(t *testing.T) {
"pagerduty_user.foo", "email", email),
),
},
// Validating that externally removed users with tag assigments are
// detected and tag assignment is planed for re-creation
{
Config: testAccCheckPagerDutyTagAssignmentConfig(tagLabel, username, email),
Check: resource.ComposeTestCheckFunc(
testAccExternallyDestroyTagAssignment("pagerduty_user.foo", "users"),
),
ExpectNonEmptyPlan: true,
},
{
Config: testAccCheckPagerDutyTagAssignmentConfig(tagLabel, username, email),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckNoResourceAttr(
"pagerduty_tag_assignment.foo", "id"),
),
PlanOnly: true,
ExpectNonEmptyPlan: true,
},
},
})
}
Expand All @@ -54,6 +73,24 @@ func TestAccPagerDutyTagAssignment_Team(t *testing.T) {
"pagerduty_team.foo", "name", team),
),
},
// Validating that externally removed teams with tag assigments are
// detected and tag assignment is planed for re-creation
{
Config: testAccCheckPagerDutyTagAssignmentTeamConfig(tagLabel, team),
Check: resource.ComposeTestCheckFunc(
testAccExternallyDestroyTagAssignment("pagerduty_team.foo", "teams"),
),
ExpectNonEmptyPlan: true,
},
{
Config: testAccCheckPagerDutyTagAssignmentTeamConfig(tagLabel, team),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckNoResourceAttr(
"pagerduty_tag_assignment.foo", "id"),
),
PlanOnly: true,
ExpectNonEmptyPlan: true,
},
},
})
}
Expand All @@ -71,13 +108,31 @@ func TestAccPagerDutyTagAssignment_EP(t *testing.T) {
{
Config: testAccCheckPagerDutyTagAssignmentEPConfig(tagLabel, username, email, ep),
Check: resource.ComposeTestCheckFunc(
testAccCheckPagerDutyTagAssignmentExists("pagerduty_tag_assignment.foo", "teams"),
testAccCheckPagerDutyTagAssignmentExists("pagerduty_tag_assignment.foo", "escalation_policies"),
resource.TestCheckResourceAttr(
"pagerduty_tag.foo", "label", tagLabel),
resource.TestCheckResourceAttr(
"pagerduty_escalation_policy.foo", "name", ep),
),
},
// Validating that externally removed escalation policies with tag
// assigments are detected and tag assignment is planed for re-creation
{
Config: testAccCheckPagerDutyTagAssignmentEPConfig(tagLabel, username, email, ep),
Check: resource.ComposeTestCheckFunc(
testAccExternallyDestroyTagAssignment("pagerduty_escalation_policy.foo", "escalation_policies"),
),
ExpectNonEmptyPlan: true,
},
{
Config: testAccCheckPagerDutyTagAssignmentEPConfig(tagLabel, username, email, ep),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckNoResourceAttr(
"pagerduty_tag_assignment.foo", "id"),
),
PlanOnly: true,
ExpectNonEmptyPlan: true,
},
},
})
}
Expand Down Expand Up @@ -200,9 +255,47 @@ resource "pagerduty_escalation_policy" "foo" {
}
}
resource "pagerduty_tag_assignment" "foo" {
entity_type = "teams"
entity_type = "escalation_policies"
entity_id = pagerduty_escalation_policy.foo.id
tag_id = pagerduty_tag.foo.id
}
`, tagLabel, username, email, ep)
}

func testAccExternallyDestroyTagAssignment(n, entityType string) resource.TestCheckFunc {
deleteUser := func(id string, client *pagerduty.Client) (*pagerduty.Response, error) {
return client.Users.Delete(id)
}
deleteTeam := func(id string, client *pagerduty.Client) (*pagerduty.Response, error) {
return client.Teams.Delete(id)
}
deleteEscalationPolicy := func(id string, client *pagerduty.Client) (*pagerduty.Response, error) {
return client.EscalationPolicies.Delete(id)
}
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No Tag Assignment ID is set")
}

client, _ := testAccProvider.Meta().(*Config).Client()
var err error
if entityType == "users" {
_, err = deleteUser(rs.Primary.ID, client)
}
if entityType == "teams" {
_, err = deleteTeam(rs.Primary.ID, client)
}
if entityType == "escalation_policies" {
_, err = deleteEscalationPolicy(rs.Primary.ID, client)
}
if err != nil {
return err
}

return nil
}
}
7 changes: 5 additions & 2 deletions pagerduty/resource_pagerduty_team.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,11 @@ func resourcePagerDutyTeamRead(d *schema.ResourceData, meta interface{}) error {

return resource.Retry(30*time.Second, func() *resource.RetryError {
if team, _, err := client.Teams.Get(d.Id()); err != nil {
time.Sleep(2 * time.Second)
return resource.RetryableError(err)
errResp := handleNotFoundError(err, d)
if errResp != nil {
time.Sleep(2 * time.Second)
return resource.RetryableError(errResp)
}
} else if team != nil {
d.Set("name", team.Name)
d.Set("description", team.Description)
Expand Down
38 changes: 38 additions & 0 deletions pagerduty/resource_pagerduty_team_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,24 @@ func TestAccPagerDutyTeam_Basic(t *testing.T) {
"pagerduty_team.foo", "description", "bar"),
),
},
// Validating that externally removed teams are detected and planed for
// re-creation
{
Config: testAccCheckPagerDutyTeamConfigUpdated(teamUpdated),
Check: resource.ComposeTestCheckFunc(
testAccExternallyDestroyTeam("pagerduty_team.foo"),
),
ExpectNonEmptyPlan: true,
},
{
Config: testAccCheckPagerDutyTeamConfigUpdated(teamUpdated),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckNoResourceAttr(
"pagerduty_team.foo", "id"),
),
PlanOnly: true,
ExpectNonEmptyPlan: true,
},
},
})
}
Expand Down Expand Up @@ -173,3 +191,23 @@ resource "pagerduty_team" "foo" {
parent = pagerduty_team.parent.id
}`, parent, team)
}

func testAccExternallyDestroyTeam(n string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No Team ID is set")
}

client, _ := testAccProvider.Meta().(*Config).Client()
_, err := client.Teams.Delete(rs.Primary.ID)
if err != nil {
return err
}

return nil
}
}

0 comments on commit 4f595a6

Please sign in to comment.