Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resource/pagerduty_team_membership: Support team member's role #151

Merged
merged 14 commits into from
Mar 19, 2020

Conversation

dtan4
Copy link
Contributor

@dtan4 dtan4 commented Sep 4, 2019

WHAT

Add role field to pagerduty_team_membership resource to specify team member's role

resource "pagerduty_user" "foo" {
  name  = "foo"
  email = "foo@bar.com"
}

resource "pagerduty_team" "foo" {
  name        = "foo"
  description = "foo"
}

resource "pagerduty_team_membership" "foo" {
  user_id = "${pagerduty_user.foo.id}"
  team_id = "${pagerduty_team.foo.id}"
  role    = "manager"  # <<<<<<<<<<<<<
}

WHY

A few months ago, we can add users to team with "manager" role by this resource.

resource "pagerduty_team_membership" "foo" {
  user_id = "${pagerduty_user.foo.id}"
  team_id = "${pagerduty_team.foo.id}"
}

However, a new member is assigned with "observer" role recently. This behavior is unexpected for us. We'd like to give each team members permission to manage their on-call schedule by themselves, but "observer" role doesn't allow it.

PagerDuty API has a field to specify member role when we create a new membership.
https://api-reference.pagerduty.com/#!/Teams/put_teams_id_users_user_id
We'd like to specify the role at the creation time.


UPDATE 2020-03-09:
Now this API assigns manager role by default, but I think this change can still be helpful to manage memberships in detail.

See https://github.com/terraform-providers/terraform-provider-pagerduty/pull/151#issuecomment-596463829 for details.

$ GO111MODULE=on go get -u github.com/heimweh/go-pagerduty/pagerduty
$ GO111MODULE=on go mod vendor
@dtan4
Copy link
Contributor Author

dtan4 commented Sep 18, 2019

Could anybody take a look...?

Copy link
Contributor

@pdecat pdecat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @dtan4, great addition!

As requested, I reviewed this and left a few comments.
Feel free to do what you like with them, I'm just a contributor here.

Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not explicitely documented, but it is not required to recreate the team membership resource when only the role changes.
That is, invoking PUT https://api.pagerduty.com/teams/***/users/*** with AddUserWithRole on an already existing team member works:

# curl -s -X GET --header 'Accept: application/vnd.pagerduty+json;version=2' --header 'Authorization: Token token=******' 'https://api.pagerduty.com/teams/P4*****/members' | jq '.members[] | select(.user.id=="P2*****")'                                                                                                                                         
{
  "user": {
    "id": "P2*****",
    "type": "user_reference",
    "summary": "User Name",
    "self": "https://api.pagerduty.com/users/P2*****",
    "html_url": "https://claranet.pagerduty.com/users/P2*****"
  },
  "role": "manager"
}
# curl -i -X PUT --header 'Content-Type: application/json' --header 'Accept: application/vnd.pagerduty+json;version=2' --header 'Authorization: Token token=******' -d '{ 
  "role": "observer"                                                                                                                                                                     
}' 'https://api.pagerduty.com/teams/P4*****/users/P2*****' |& grep HTTP
HTTP/2 204 
# curl -s -X GET --header 'Accept: application/vnd.pagerduty+json;version=2' --header 'Authorization: Token token=******' 'https://api.pagerduty.com/teams/P4*****/members' | jq '.members[] | select(.user.id=="P2*****")'
{
  "user": {
    "id": "P2*****",
    "type": "user_reference",
    "summary": "User Name",
    "self": "https://api.pagerduty.com/users/P2*****",
    "html_url": "https://claranet.pagerduty.com/users/P2*****"
  },
  "role": "observer"
}

Not recreating the team membership avoids the user loosing the role even for a very short period.
That will require introducing a resourcePagerDutyTeamMembershipUpdate function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. I added resourcePagerDutyTeamMembershipUpdate with the same logic of resourcePagerDutyTeamMembershipCreate. (hashicorp@3a0aaca) It worked fine.

  # pagerduty_team_membership.dtan4 will be updated in-place
  ~ resource "pagerduty_team_membership" "dtan4" {
        id      = "PPPPPPP:PQQQQQQ"
      ~ role    = "manager" -> "observer"
        team_id = "PPPPPPP"
        user_id = "PQQQQQQ"
    }

@@ -30,6 +30,12 @@ func resourcePagerDutyTeamMembership() *schema.Resource {
Required: true,
ForceNew: true,
},
"role": {
Type: schema.TypeString,
Optional: true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I remember there are issues when Optional and Computed are used together, not sure if it applies here.
This probably needs more attention.

hashicorp/terraform-provider-google#3477 (comment)
hashicorp/terraform#20505 (comment)
hashicorp/terraform-provider-google#4326

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to Optional only, as developers can set value by themselves or use the default value.
hashicorp@003ba6c

@@ -11,14 +11,15 @@ import (
func TestAccPagerDutyTeamMembership_import(t *testing.T) {
user := fmt.Sprintf("tf-%s", acctest.RandString(5))
team := fmt.Sprintf("tf-%s", acctest.RandString(5))
role := "manager"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the original test should probably be left untouched to ensure no regression is introduced.

Maybe a new TestAccPagerDutyTeamMembership_importWithRole test should be introduced.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Created a new testcase for withRole.
hashicorp@6ce1d0c

@@ -13,14 +13,15 @@ import (
func TestAccPagerDutyTeamMembership_Basic(t *testing.T) {
user := fmt.Sprintf("tf-%s", acctest.RandString(5))
team := fmt.Sprintf("tf-%s", acctest.RandString(5))
role := "manager"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the original test should probably be left untouched to ensure no regression is introduced.

Maybe a new TestAccPagerDutyTeamMembership_WithRole test should be introduced.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Created a new testcase for withRole.
hashicorp@89b0e5f

@@ -30,6 +30,12 @@ func resourcePagerDutyTeamMembership() *schema.Resource {
Required: true,
ForceNew: true,
},
"role": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validation could probably be added:

The role of the user on the team.
Can be observer, responder or manager

https://api-reference.pagerduty.com/#!/Teams/put_teams_id_users_user_id

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


retryErr := resource.Retry(2*time.Minute, func() *resource.RetryError {
if _, err := client.Teams.AddUser(teamID, userID); err != nil {
if _, err := client.Teams.AddUserWithRole(teamID, userID, role); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if the role is empty? Shouldn't client.Teams.AddUser(teamID, userID) be used instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I defined a default value for role to be the same as the current API behavior, calling AddUser API without role.
hashicorp@a560e09

With validation implemented at hashicorp@8521226, this resource guarantees a valid value is set in role at every time. So I think it's okay to use AddUserWithRole at every time too.

d.Set("role", "")

if isTeamMember(user, teamID) {
resp, _, err := client.Teams.GetMembers(teamID, &pagerduty.GetMembersOptions{})
Copy link
Contributor

@pdecat pdecat Sep 18, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't client.Teams.GetMembers become the main API to query for resourcePagerDutyTeamMembershipRead instead of calling client.Users.Get?

This could probably simplify things a bit, isn't it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of using client.Users.Get, I could simplify the logic with client.Teams.GetMembers only.
hashicorp@1f71c0c

How about this?

@ghost ghost added size/L and removed size/M labels Sep 19, 2019
@dtan4
Copy link
Contributor Author

dtan4 commented Sep 24, 2019

@pdecat Thank you for reviewing! I added some more changes you pointed out. Could you take another look?

Copy link
Contributor

@pdecat pdecat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

PS: I cannot run the acceptance tests as my test Pagerduty account does not have the Teams feature.

@dtan4
Copy link
Contributor Author

dtan4 commented Nov 8, 2019

Is there any chance to merge this...? 👀

@cilindrox
Copy link

Subbed - this just hit us and we had to fall back to the legacy team_responder roles

@cilindrox
Copy link

Any updates on this? Is there any way I can help out?

@vanvlack
Copy link

@stmcallister any chance on getting this reviewed/merged for the next release?

@stmcallister
Copy link
Contributor

Sorry for the delay! What are you getting for your test results? I'm getting the following failures.

=== RUN   TestAccPagerDutyTeamMembership_import
--- FAIL: TestAccPagerDutyTeamMembership_import (5.24s)
    testing.go:569: Step 0 error: After applying this step, the plan was not empty:
        
        DIFF:
        
        UPDATE: pagerduty_team_membership.foo
          id:      "PA03194:PHWZQAX" => "PA03194:PHWZQAX"
          role:    "manager" => "observer"
          team_id: "PHWZQAX" => "PHWZQAX"
          user_id: "PA03194" => "PA03194"
        
        
        
        STATE:
        
        pagerduty_team.foo:
          ID = PHWZQAX
          provider = provider.pagerduty
          description = foo
          html_url = https://pdt-smcallister.pagerduty.com/teams/PHWZQAX
          name = tf-xyvc9
        pagerduty_team_membership.foo:
          ID = PA03194:PHWZQAX
          provider = provider.pagerduty
          role = manager
          team_id = PHWZQAX
          user_id = PA03194
        
          Dependencies:
            pagerduty_team.foo
            pagerduty_user.foo
        pagerduty_user.foo:
          ID = PA03194
          provider = provider.pagerduty
          avatar_url = https://secure.gravatar.com/avatar/fedbea5960c2dcf789279bf3ac8a6a5a.png?d=mm&r=PG
          color = dark-orchid
          description = Managed by Terraform
          email = tf-nccl6@foo.com
          html_url = https://pdt-smcallister.pagerduty.com/users/PA03194
          invitation_sent = true
          job_title = 
          name = tf-nccl6
          role = user
          time_zone = America/Los_Angeles


=== RUN   TestAccPagerDutyTeamMembership_Basic
--- FAIL: TestAccPagerDutyTeamMembership_Basic (5.75s)
    testing.go:569: Step 0 error: After applying this step, the plan was not empty:
        
        DIFF:
        
        UPDATE: pagerduty_team_membership.foo
          id:      "PV0EBSA:PT2RNH4" => "PV0EBSA:PT2RNH4"
          role:    "manager" => "observer"
          team_id: "PT2RNH4" => "PT2RNH4"
          user_id: "PV0EBSA" => "PV0EBSA"
        
        
        
        STATE:
        
        pagerduty_team.foo:
          ID = PT2RNH4
          provider = provider.pagerduty
          description = foo
          html_url = https://pdt-smcallister.pagerduty.com/teams/PT2RNH4
          name = tf-3lbig
        pagerduty_team_membership.foo:
          ID = PV0EBSA:PT2RNH4
          provider = provider.pagerduty
          role = manager
          team_id = PT2RNH4
          user_id = PV0EBSA
        
          Dependencies:
            pagerduty_team.foo
            pagerduty_user.foo
        pagerduty_user.foo:
          ID = PV0EBSA
          provider = provider.pagerduty
          avatar_url = https://secure.gravatar.com/avatar/848fb5e400214da9ef9317b36ef59346.png?d=mm&r=PG
          color = dark-orchid
          description = Managed by Terraform
          email = tf-4nlgr@foo.com
          html_url = https://pdt-smcallister.pagerduty.com/users/PV0EBSA
          invitation_sent = true
          job_title = 
          name = tf-4nlgr
          role = user
          time_zone = America/Los_Angeles



=== RUN   TestAccPagerDutyUserContactMethodPhone_Basic
--- FAIL: TestAccPagerDutyUserContactMethodPhone_Basic (8.37s)
    testing.go:569: Step 1 error: After applying this step, the plan was not empty:
        
        DIFF:
        
        UPDATE: pagerduty_user.foo
          avatar_url:      "https://secure.gravatar.com/avatar/1d02467c6b92a031c787d3ef5d81a386.png?d=mm&r=PG" => "https://secure.gravatar.com/avatar/1d02467c6b92a031c787d3ef5d81a386.png?d=mm&r=PG"
          color:           "red" => "red"
          description:     "bar" => "bar"
          email:           "tf-vxyt2@foo.com" => "tf-np4dw@foo.com"
          html_url:        "https://pdt-smcallister.pagerduty.com/users/P3WWYZ7" => "https://pdt-smcallister.pagerduty.com/users/P3WWYZ7"
          id:              "P3WWYZ7" => "P3WWYZ7"
          invitation_sent: "true" => "true"
          job_title:       "bar" => "bar"
          name:            "tf-vxyt2" => "tf-np4dw"
          role:            "user" => "user"
          teams.#:         "0" => "0"
          time_zone:       "America/Los_Angeles" => "America/Los_Angeles"
        
        
        
        STATE:
        
        pagerduty_user.foo:
          ID = P3WWYZ7
          provider = provider.pagerduty
          avatar_url = https://secure.gravatar.com/avatar/1d02467c6b92a031c787d3ef5d81a386.png?d=mm&r=PG
          color = red
          description = bar
          email = tf-vxyt2@foo.com
          html_url = https://pdt-smcallister.pagerduty.com/users/P3WWYZ7
          invitation_sent = true
          job_title = bar
          name = tf-vxyt2
          role = user
          time_zone = America/Los_Angeles
        pagerduty_user_contact_method.foo:
          ID = PJYKO2F
          provider = provider.pagerduty
          address = 8669351337
          blacklisted = false
          country_code = 1
          enabled = false
          label = tf-np4dw
          send_short_email = false
          type = phone_contact_method
          user_id = P3WWYZ7
        
          Dependencies:
            pagerduty_user.foo
            
            
            
=== RUN   TestAccPagerDutyUserWithTeams_Basic
--- FAIL: TestAccPagerDutyUserWithTeams_Basic (5.35s)
    testing.go:569: Step 0 error: After applying this step, the plan was not empty:
        
        DIFF:
        
        UPDATE: pagerduty_team_membership.foo
          id:      "PF76XUB:P57U8D1" => "PF76XUB:P57U8D1"
          role:    "manager" => "observer"
          team_id: "P57U8D1" => "P57U8D1"
          user_id: "PF76XUB" => "PF76XUB"
        
        
        
        STATE:
        
        pagerduty_team.foo:
          ID = P57U8D1
          provider = provider.pagerduty
          description = Managed by Terraform
          html_url = https://pdt-smcallister.pagerduty.com/teams/P57U8D1
          name = tf-yy2er
        pagerduty_team_membership.foo:
          ID = PF76XUB:P57U8D1
          provider = provider.pagerduty
          role = manager
          team_id = P57U8D1
          user_id = PF76XUB
        
          Dependencies:
            pagerduty_team.foo
            pagerduty_user.foo
        pagerduty_user.foo:
          ID = PF76XUB
          provider = provider.pagerduty
          avatar_url = https://secure.gravatar.com/avatar/592504d0dd3931101adb736084c1506b.png?d=mm&r=PG
          color = dark-orchid
          description = Managed by Terraform
          email = tf-fcib2@foo.com
          html_url = https://pdt-smcallister.pagerduty.com/users/PF76XUB
          invitation_sent = true
          job_title = 
          name = tf-fcib2
          role = user
          time_zone = America/Los_Angeles

@dtan4
Copy link
Contributor Author

dtan4 commented Mar 9, 2020

@stmcallister Sorry for the late reply,

When I submitted this Pull Request, this Add a user to a team API assigns observer role by default. Due to this, I chose observer as a default membership role in this provider too.

However, the behavior changed (reverted?) recently; this API assigns manager role by default. That's why the acceptance tests failed. This behavior can be reproduced with the current stable PagerDuty provider.

I modified the default membership role to manager at hashicorp@2a72eb4 and confirmed it passes all acceptance tests.

Could you review again? Thanks!

@stmcallister
Copy link
Contributor

@dtan4 looks great! thank you!

@stmcallister stmcallister merged commit 8a14d87 into PagerDuty:master Mar 19, 2020
@dtan4 dtan4 deleted the add-teammember-with-role branch March 25, 2020 07:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants