From 7a461011a356e3ebd3118f2a7719689ea92bb82d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Antonio=20Reyes?= Date: Fri, 15 Jul 2022 18:08:04 -0400 Subject: [PATCH 1/3] add `pagerduty_users` data source --- pagerduty/data_source_pagerduty_users.go | 93 +++++++++++++++++++ pagerduty/data_source_pagerduty_users_test.go | 85 +++++++++++++++++ pagerduty/provider.go | 1 + website/docs/d/users.html.markdown | 58 ++++++++++++ 4 files changed, 237 insertions(+) create mode 100644 pagerduty/data_source_pagerduty_users.go create mode 100644 pagerduty/data_source_pagerduty_users_test.go create mode 100644 website/docs/d/users.html.markdown diff --git a/pagerduty/data_source_pagerduty_users.go b/pagerduty/data_source_pagerduty_users.go new file mode 100644 index 000000000..2bb9cf703 --- /dev/null +++ b/pagerduty/data_source_pagerduty_users.go @@ -0,0 +1,93 @@ +package pagerduty + +import ( + "log" + "strconv" + "time" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/heimweh/go-pagerduty/pagerduty" +) + +func dataSourcePagerDutyUsers() *schema.Resource { + return &schema.Resource{ + Read: dataSourcePagerDutyUsersRead, + + Schema: map[string]*schema.Schema{ + "team_ids": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "users": { + Type: schema.TypeList, + Computed: true, + Description: "List of users who are members of the team", + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "email": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataSourcePagerDutyUsersRead(d *schema.ResourceData, meta interface{}) error { + client, err := meta.(*Config).Client() + if err != nil { + return err + } + + log.Printf("[INFO] Reading PagerDuty users") + + pre := d.Get("team_ids").([]interface{}) + var teamIds []string + for _, ti := range pre { + teamIds = append(teamIds, ti.(string)) + } + + o := &pagerduty.ListUsersOptions{ + TeamIDs: teamIds, + } + + return resource.Retry(5*time.Minute, func() *resource.RetryError { + resp, err := client.Users.ListAll(o) + if err != nil { + // Delaying retry by 30s as recommended by PagerDuty + // https://developer.pagerduty.com/docs/rest-api-v2/rate-limiting/#what-are-possible-workarounds-to-the-events-api-rate-limit + time.Sleep(30 * time.Second) + return resource.RetryableError(err) + } + + var users []map[string]interface{} + for _, user := range resp { + users = append(users, map[string]interface{}{ + "id": user.ID, + "name": user.Name, + "email": user.Email, + }) + } + + // Since this data doesn't have an unique ID, this force this data to be + // refreshed in every Terraform apply + d.SetId(strconv.FormatInt(time.Now().Unix(), 10)) + d.Set("users", users) + + return nil + }) +} diff --git a/pagerduty/data_source_pagerduty_users_test.go b/pagerduty/data_source_pagerduty_users_test.go new file mode 100644 index 000000000..d79bb469a --- /dev/null +++ b/pagerduty/data_source_pagerduty_users_test.go @@ -0,0 +1,85 @@ +package pagerduty + +import ( + "fmt" + "testing" + + "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" +) + +func TestAccDataSourcePagerDutyUsers_Basic(t *testing.T) { + teamname := fmt.Sprintf("tf-team-%s", acctest.RandString(5)) + username1 := fmt.Sprintf("tf-user-%s", acctest.RandString(5)) + email1 := fmt.Sprintf("%s@foo.test", username1) + username2 := fmt.Sprintf("tf-user-%s", acctest.RandString(5)) + email2 := fmt.Sprintf("%s@foo.test", username2) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourcePagerDutyUsersConfig(teamname, username1, email1, username2, email2), + Check: resource.ComposeTestCheckFunc( + testAccDataSourcePagerDutyUsersExists("data.pagerduty_users.test_all_users"), + testAccDataSourcePagerDutyUsersExists("data.pagerduty_users.test_by_team"), + resource.TestCheckResourceAttrSet( + "data.pagerduty_users.test_all_users", "users.#"), + resource.TestCheckResourceAttr( + "data.pagerduty_users.test_by_team", "users.#", "1"), + resource.TestCheckResourceAttrSet( + "data.pagerduty_users.test_by_team", "users.0.id"), + resource.TestCheckResourceAttr( + "data.pagerduty_users.test_by_team", "users.0.name", username2), + resource.TestCheckResourceAttr( + "data.pagerduty_users.test_by_team", "users.0.email", email2), + ), + }, + }, + }) +} + +func testAccDataSourcePagerDutyUsersExists(n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + + r := s.RootModule().Resources[n] + a := r.Primary.Attributes + + if a["id"] == "" { + return fmt.Errorf("Expected to get a user ID from PagerDuty") + } + + return nil + } +} + +func testAccDataSourcePagerDutyUsersConfig(teamname, username1, email1, username2, email2 string) string { + return fmt.Sprintf(` + resource "pagerduty_team" "test" { + name = "%s" + } + resource "pagerduty_user" "test_wo_team" { + name = "%s" + email = "%s" + } + resource "pagerduty_user" "test_w_team" { + name = "%s" + email = "%s" + } + resource "pagerduty_team_membership" "test" { + team_id = pagerduty_team.test.id + user_id = pagerduty_user.test_w_team.id + } + + data "pagerduty_users" "test_all_users" { + depends_on = [pagerduty_user.test_w_team, pagerduty_user.test_wo_team] + } + + data "pagerduty_users" "test_by_team" { + depends_on = [pagerduty_team_membership.test] + team_ids = [pagerduty_team.test.id] + } +`, teamname, username1, email1, username2, email2) +} diff --git a/pagerduty/provider.go b/pagerduty/provider.go index 92e478397..12737ca7e 100644 --- a/pagerduty/provider.go +++ b/pagerduty/provider.go @@ -49,6 +49,7 @@ func Provider() *schema.Provider { "pagerduty_escalation_policy": dataSourcePagerDutyEscalationPolicy(), "pagerduty_schedule": dataSourcePagerDutySchedule(), "pagerduty_user": dataSourcePagerDutyUser(), + "pagerduty_users": dataSourcePagerDutyUsers(), "pagerduty_user_contact_method": dataSourcePagerDutyUserContactMethod(), "pagerduty_team": dataSourcePagerDutyTeam(), "pagerduty_vendor": dataSourcePagerDutyVendor(), diff --git a/website/docs/d/users.html.markdown b/website/docs/d/users.html.markdown new file mode 100644 index 000000000..158332cea --- /dev/null +++ b/website/docs/d/users.html.markdown @@ -0,0 +1,58 @@ +--- +layout: "pagerduty" +page_title: "PagerDuty: pagerduty_user" +sidebar_current: "docs-pagerduty-datasource-user" +description: |- + Get information about users of your PagerDuty account as a list, optionally filtered by team ids that you can use for a service integration (e.g Amazon Cloudwatch, Splunk, Datadog). +--- + +# pagerduty\_users + +Use this data source to get information about [list of users][1] that you can use for other PagerDuty resources, optionally filtering by team ids. + +## Example Usage + +```hcl +data "pagerduty_team" "devops" { + name = "devops" +} + +data "pagerduty_user" "me" { + email = "me@example.com" +} + +resource "pagerduty_user" "example_w_team" { + name = "user-with-team" + email = "user-with-team@example.com" +} + +resource "pagerduty_team_membership" "example" { + team_id = pagerduty_team.devops.id + user_id = pagerduty_user.example_w_team.id +} + +data "pagerduty_users" "all_users" {} + +data "pagerduty_users" "from_devops_team" { + depends_on = [pagerduty_team_membership.example] + team_ids = [pagerduty_team.devops.id] +} +``` + +## Argument Reference + +The following arguments are supported: + +* `team_ids` - (Optional) List of team IDs. Only results related to these teams will be returned. Account must have the `teams` ability to use this parameter. + +## Attributes Reference +* `id` - The ID of queried list of users. +* `users` - List of users queried. + +### Users (`users`) supports the following: + +* `id` - The ID of the found user. +* `name` - The short name of the found user. +* `email` - The email to use to find a user in the PagerDuty API. + +[1]: https://developer.pagerduty.com/api-reference/b3A6Mjc0ODIzMw-list-users From 468969f97eebe3ded84d3ed2633d86c64e320bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Antonio=20Reyes?= Date: Mon, 18 Jul 2022 13:14:53 -0400 Subject: [PATCH 2/3] add test case for querying with more than one team --- pagerduty/data_source_pagerduty_users_test.go | 70 ++++++++++++++----- 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/pagerduty/data_source_pagerduty_users_test.go b/pagerduty/data_source_pagerduty_users_test.go index d79bb469a..55f6ec9df 100644 --- a/pagerduty/data_source_pagerduty_users_test.go +++ b/pagerduty/data_source_pagerduty_users_test.go @@ -10,31 +10,47 @@ import ( ) func TestAccDataSourcePagerDutyUsers_Basic(t *testing.T) { - teamname := fmt.Sprintf("tf-team-%s", acctest.RandString(5)) + teamname1 := fmt.Sprintf("tf-team-%s", acctest.RandString(5)) + teamname2 := fmt.Sprintf("tf-team-%s", acctest.RandString(5)) username1 := fmt.Sprintf("tf-user-%s", acctest.RandString(5)) email1 := fmt.Sprintf("%s@foo.test", username1) username2 := fmt.Sprintf("tf-user-%s", acctest.RandString(5)) email2 := fmt.Sprintf("%s@foo.test", username2) + username3 := fmt.Sprintf("tf-user-%s", acctest.RandString(5)) + email3 := fmt.Sprintf("%s@foo.test", username3) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: testAccDataSourcePagerDutyUsersConfig(teamname, username1, email1, username2, email2), + Config: testAccDataSourcePagerDutyUsersConfig(teamname1, teamname2, username1, email1, username2, email2, username3, email3), Check: resource.ComposeTestCheckFunc( testAccDataSourcePagerDutyUsersExists("data.pagerduty_users.test_all_users"), - testAccDataSourcePagerDutyUsersExists("data.pagerduty_users.test_by_team"), + testAccDataSourcePagerDutyUsersExists("data.pagerduty_users.test_by_1_team"), + testAccDataSourcePagerDutyUsersExists("data.pagerduty_users.test_by_2_team"), resource.TestCheckResourceAttrSet( "data.pagerduty_users.test_all_users", "users.#"), resource.TestCheckResourceAttr( - "data.pagerduty_users.test_by_team", "users.#", "1"), + "data.pagerduty_users.test_by_1_team", "users.#", "1"), resource.TestCheckResourceAttrSet( - "data.pagerduty_users.test_by_team", "users.0.id"), + "data.pagerduty_users.test_by_1_team", "users.0.id"), resource.TestCheckResourceAttr( - "data.pagerduty_users.test_by_team", "users.0.name", username2), + "data.pagerduty_users.test_by_1_team", "users.0.name", username2), resource.TestCheckResourceAttr( - "data.pagerduty_users.test_by_team", "users.0.email", email2), + "data.pagerduty_users.test_by_1_team", "users.0.email", email2), + resource.TestCheckResourceAttr( + "data.pagerduty_users.test_by_2_team", "users.#", "2"), + resource.TestCheckResourceAttrSet( + "data.pagerduty_users.test_by_2_team", "users.0.id"), + resource.TestCheckResourceAttr( + "data.pagerduty_users.test_by_2_team", "users.0.name", username2), + resource.TestCheckResourceAttr( + "data.pagerduty_users.test_by_2_team", "users.0.email", email2), + resource.TestCheckResourceAttr( + "data.pagerduty_users.test_by_2_team", "users.1.name", username3), + resource.TestCheckResourceAttr( + "data.pagerduty_users.test_by_2_team", "users.1.email", email3), ), }, }, @@ -55,31 +71,49 @@ func testAccDataSourcePagerDutyUsersExists(n string) resource.TestCheckFunc { } } -func testAccDataSourcePagerDutyUsersConfig(teamname, username1, email1, username2, email2 string) string { +func testAccDataSourcePagerDutyUsersConfig(teamname1, teamname2, username1, email1, username2, email2, username3, email3 string) string { return fmt.Sprintf(` - resource "pagerduty_team" "test" { + resource "pagerduty_team" "test1" { + name = "%s" + } + resource "pagerduty_team" "test2" { name = "%s" } + resource "pagerduty_user" "test_wo_team" { name = "%s" email = "%s" } - resource "pagerduty_user" "test_w_team" { + resource "pagerduty_user" "test_w_team1" { name = "%s" email = "%s" } - resource "pagerduty_team_membership" "test" { - team_id = pagerduty_team.test.id - user_id = pagerduty_user.test_w_team.id + resource "pagerduty_user" "test_w_team2" { + name = "%s" + email = "%s" + } + + resource "pagerduty_team_membership" "test1" { + team_id = pagerduty_team.test1.id + user_id = pagerduty_user.test_w_team1.id + } + resource "pagerduty_team_membership" "test2" { + depends_on = [pagerduty_team_membership.test1] + team_id = pagerduty_team.test2.id + user_id = pagerduty_user.test_w_team2.id } data "pagerduty_users" "test_all_users" { - depends_on = [pagerduty_user.test_w_team, pagerduty_user.test_wo_team] + depends_on = [pagerduty_user.test_w_team1, pagerduty_user.test_wo_team] } - data "pagerduty_users" "test_by_team" { - depends_on = [pagerduty_team_membership.test] - team_ids = [pagerduty_team.test.id] + data "pagerduty_users" "test_by_1_team" { + depends_on = [pagerduty_team_membership.test1] + team_ids = [pagerduty_team.test1.id] + } + data "pagerduty_users" "test_by_2_team" { + depends_on = [pagerduty_team_membership.test2] + team_ids = [pagerduty_team.test1.id, pagerduty_team.test2.id] } -`, teamname, username1, email1, username2, email2) +`, teamname1, teamname2, username1, email1, username2, email2, username3, email3) } From a41b13dc2e3a30b34277037d612a9360f3de9607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Antonio=20Reyes?= Date: Wed, 20 Jul 2022 18:18:49 -0400 Subject: [PATCH 3/3] update test cases for `data.pagerduty_users` --- pagerduty/data_source_pagerduty_users_test.go | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/pagerduty/data_source_pagerduty_users_test.go b/pagerduty/data_source_pagerduty_users_test.go index 55f6ec9df..78e50a61c 100644 --- a/pagerduty/data_source_pagerduty_users_test.go +++ b/pagerduty/data_source_pagerduty_users_test.go @@ -12,11 +12,11 @@ import ( func TestAccDataSourcePagerDutyUsers_Basic(t *testing.T) { teamname1 := fmt.Sprintf("tf-team-%s", acctest.RandString(5)) teamname2 := fmt.Sprintf("tf-team-%s", acctest.RandString(5)) - username1 := fmt.Sprintf("tf-user-%s", acctest.RandString(5)) + username1 := fmt.Sprintf("tf-user1-%s", acctest.RandString(5)) email1 := fmt.Sprintf("%s@foo.test", username1) - username2 := fmt.Sprintf("tf-user-%s", acctest.RandString(5)) + username2 := fmt.Sprintf("tf-user2-%s", acctest.RandString(5)) email2 := fmt.Sprintf("%s@foo.test", username2) - username3 := fmt.Sprintf("tf-user-%s", acctest.RandString(5)) + username3 := fmt.Sprintf("tf-user3-%s", acctest.RandString(5)) email3 := fmt.Sprintf("%s@foo.test", username3) resource.Test(t, resource.TestCase{ @@ -31,6 +31,24 @@ func TestAccDataSourcePagerDutyUsers_Basic(t *testing.T) { testAccDataSourcePagerDutyUsersExists("data.pagerduty_users.test_by_2_team"), resource.TestCheckResourceAttrSet( "data.pagerduty_users.test_all_users", "users.#"), + resource.TestCheckTypeSetElemNestedAttrs( + "data.pagerduty_users.test_all_users", + "users.*", + map[string]string{ + "name": username1, + }), + resource.TestCheckTypeSetElemNestedAttrs( + "data.pagerduty_users.test_all_users", + "users.*", + map[string]string{ + "name": username2, + }), + resource.TestCheckTypeSetElemNestedAttrs( + "data.pagerduty_users.test_all_users", + "users.*", + map[string]string{ + "name": username3, + }), resource.TestCheckResourceAttr( "data.pagerduty_users.test_by_1_team", "users.#", "1"), resource.TestCheckResourceAttrSet(