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

Add support for Incident Workflow triggers team restrictions #861

Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,5 @@ require (
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
)

replace github.com/heimweh/go-pagerduty => github.com/imjaroiswebdev/go-pagerduty v0.0.0-20240419180041-eace2b31e15b
imjaroiswebdev marked this conversation as resolved.
Show resolved Hide resolved
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ github.com/hashicorp/terraform-svchost v0.1.1 h1:EZZimZ1GxdqFRinZ1tpJwVxxt49xc/S
github.com/hashicorp/terraform-svchost v0.1.1/go.mod h1:mNsjQfZyf/Jhz35v6/0LWcv26+X7JPS+buii2c9/ctc=
github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE=
github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ=
github.com/heimweh/go-pagerduty v0.0.0-20240403153232-5876af2ce24a h1:upvfy2kYdl/poYpITYmq6ZqJb5mu9zHm4V0YeXlyNOM=
github.com/heimweh/go-pagerduty v0.0.0-20240403153232-5876af2ce24a/go.mod h1:r59w5iyN01Qvi734yA5hZldbSeJJmsJzee/1kQ/MK7s=
github.com/imjaroiswebdev/go-pagerduty v0.0.0-20240419180041-eace2b31e15b h1:RAXrlZOEqvzl5g27JLT2Fdsl39KGSo6TDow8TtKTR6M=
github.com/imjaroiswebdev/go-pagerduty v0.0.0-20240419180041-eace2b31e15b/go.mod h1:r59w5iyN01Qvi734yA5hZldbSeJJmsJzee/1kQ/MK7s=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
Expand Down
70 changes: 70 additions & 0 deletions pagerduty/resource_pagerduty_incident_workflow_trigger.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,25 @@ func resourcePagerDutyIncidentWorkflowTrigger() *schema.Resource {
Type: schema.TypeString,
Optional: true,
},
"permissions": {
Type: schema.TypeList,
Optional: true,
Computed: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"restricted": {
Type: schema.TypeBool,
Optional: true,
Computed: true,
},
"team_id": {
Type: schema.TypeString,
Optional: true,
},
},
},
},
},
}
}
Expand Down Expand Up @@ -138,6 +157,16 @@ func validateIncidentWorkflowTrigger(_ context.Context, d *schema.ResourceDiff,
return fmt.Errorf("when trigger type conditional is used, condition must be specified")
}

// pagerduty_incident_workflow_trigger.permissions input validation
permissionRestricted := d.Get("permissions.0.restricted").(bool)
permissionTeamID := d.Get("permissions.0.team_id").(string)
if triggerType != "manual" && permissionRestricted {
return fmt.Errorf("restricted can only be true when trigger type is manual")
}
if !permissionRestricted && permissionTeamID != "" {
return fmt.Errorf("team_id not allowed when restricted is false")
}

s, hadServices := d.GetOk("services")
all := d.Get("subscribed_to_all_services").(bool)
if all && hadServices && len(s.([]interface{})) > 0 {
Expand Down Expand Up @@ -186,6 +215,14 @@ func flattenIncidentWorkflowTrigger(d *schema.ResourceData, t *pagerduty.Inciden
if t.Condition != nil {
d.Set("condition", t.Condition)
}
if t.Permissions != nil {
d.Set("permissions", []map[string]interface{}{
{
"restricted": t.Permissions.Restricted,
"team_id": t.Permissions.TeamID,
},
})
}

return nil
}
Expand Down Expand Up @@ -219,6 +256,14 @@ func buildIncidentWorkflowTriggerStruct(d *schema.ResourceData, forUpdate bool)
iwt.Condition = &condStr
}

if permissions, ok := d.GetOk("permissions"); ok {
p, err := expandIncidentWorkflowTriggerPermissions(permissions)
if err != nil {
return nil, err
}
iwt.Permissions = p
}

return &iwt, nil
}

Expand All @@ -232,3 +277,28 @@ func buildIncidentWorkflowTriggerServices(s interface{}) []*pagerduty.ServiceRef
}
return newServices
}

func expandIncidentWorkflowTriggerPermissions(v interface{}) (*pagerduty.IncidentWorkflowTriggerPermissions, error) {
var permissions *pagerduty.IncidentWorkflowTriggerPermissions

permissionsData, ok := v.([]interface{})
if ok && len(permissionsData) > 0 {
p := permissionsData[0].(map[string]interface{})

// Unfortunately this validatation can't be made during diff checking, since
// Diff Customization doesn't support computed/"known after apply" values
// like team_id in this case. Based on
// https://developer.hashicorp.com/terraform/plugin/sdkv2/resources/customizing-differences
// because of this, it will only be returned during the apply phase.
if p["restricted"].(bool) && p["team_id"].(string) == "" {
return nil, fmt.Errorf("team_id must be specified when restricted is true")
}

permissions = &pagerduty.IncidentWorkflowTriggerPermissions{
Restricted: p["restricted"].(bool),
TeamID: p["team_id"].(string),
}
}

return permissions, nil
}
144 changes: 144 additions & 0 deletions pagerduty/resource_pagerduty_incident_workflow_trigger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,150 @@ func TestAccPagerDutyIncidentWorkflowTrigger_BasicConditionalAllServices(t *test
})
}

func TestAccPagerDutyIncidentWorkflowTrigger_ManualWithTeamPermissions(t *testing.T) {
username := fmt.Sprintf("tf-%s", acctest.RandString(5))
email := fmt.Sprintf("%s@foo.test", username)
escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5))
service := fmt.Sprintf("tf-%s", acctest.RandString(5))
workflow := fmt.Sprintf("tf-%s", acctest.RandString(5))
teamName := fmt.Sprintf("tf-%s", acctest.RandString(5))
teamIDTFRef := "pagerduty_team.foo.id"
emptyCondition := ""
dummyCondition := "event.summary matches 'foo'"

resource.Test(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
testAccPreCheckIncidentWorkflows(t)
},
ProviderFactories: testAccProviderFactories,
CheckDestroy: testAccCheckPagerDutyIncidentWorkflowTriggerDestroy,
Steps: []resource.TestStep{
{
Config: testAccCheckPagerDutyIncidentWorkflowTriggerConfigManualWithPermissions(username, email, escalationPolicy, service, teamName, workflow),
Check: resource.ComposeTestCheckFunc(
testAccCheckPagerDutyIncidentWorkflowTriggerExists("pagerduty_incident_workflow_trigger.test"),
resource.TestCheckResourceAttr(
"pagerduty_incident_workflow_trigger.test", "type", "manual"),
resource.TestCheckResourceAttr(
"pagerduty_incident_workflow_trigger.test", "permissions.0.restricted", "false"),
),
},
{
Config: testAccCheckPagerDutyIncidentWorkflowTriggerConfigManualWithPermissionsUpdated(username, email, escalationPolicy, service, teamName, workflow, "manual", emptyCondition, "true", teamIDTFRef),
Check: resource.ComposeTestCheckFunc(
testAccCheckPagerDutyIncidentWorkflowTriggerExists("pagerduty_incident_workflow_trigger.test"),
resource.TestCheckResourceAttr(
"pagerduty_incident_workflow_trigger.test", "type", "manual"),
resource.TestCheckResourceAttr(
"pagerduty_incident_workflow_trigger.test", "permissions.0.restricted", "true"),
testAccCheckPagerDutyIncidentWorkflowTriggerCheckPermissionsTeamId("pagerduty_incident_workflow_trigger.test", "pagerduty_team.foo"),
),
},
// Check input validation conditions for permissions configuration
{
Config: testAccCheckPagerDutyIncidentWorkflowTriggerConfigManualWithPermissionsUpdated(username, email, escalationPolicy, service, teamName, workflow, "conditional", dummyCondition, "true", teamIDTFRef),
Check: resource.ComposeTestCheckFunc(
testAccCheckPagerDutyIncidentWorkflowTriggerExists("pagerduty_incident_workflow_trigger.test"),
),
PlanOnly: true,
ExpectError: regexp.MustCompile("restricted can only be true when trigger type is manual"),
},
{
Config: testAccCheckPagerDutyIncidentWorkflowTriggerConfigManualWithPermissionsUpdated(username, email, escalationPolicy, service, teamName, workflow, "manual", emptyCondition, "false", teamIDTFRef),
Check: resource.ComposeTestCheckFunc(
testAccCheckPagerDutyIncidentWorkflowTriggerExists("pagerduty_incident_workflow_trigger.test"),
),
PlanOnly: true,
ExpectError: regexp.MustCompile("team_id not allowed when restricted is false"),
},
{
Config: testAccCheckPagerDutyIncidentWorkflowTriggerConfigManualWithPermissionsUpdated(username, email, escalationPolicy, service, teamName, workflow, "manual", emptyCondition, "true", `""`),
Check: resource.ComposeTestCheckFunc(
testAccCheckPagerDutyIncidentWorkflowTriggerExists("pagerduty_incident_workflow_trigger.test"),
),
ExpectError: regexp.MustCompile("team_id must be specified when restricted is true"),
},
},
})
}

func testAccCheckPagerDutyIncidentWorkflowTriggerConfigManualWithPermissions(username, email, escalationPolicy, service, workflow, team string) string {
return fmt.Sprintf(`
%s

%s

resource "pagerduty_team" "foo" {
name = %q
}

resource "pagerduty_incident_workflow_trigger" "test" {
type = "manual"
workflow = pagerduty_incident_workflow.test.id
services = [pagerduty_service.foo.id]
subscribed_to_all_services = false
}
`, testAccCheckPagerDutyServiceConfig(username, email, escalationPolicy, service), testAccCheckPagerDutyIncidentWorkflowConfig(workflow), team)
}

func testAccCheckPagerDutyIncidentWorkflowTriggerConfigManualWithPermissionsUpdated(username, email, escalationPolicy, service, workflow, team, triggerType, condition, isRestricted, teamId string) string {
return fmt.Sprintf(`
%s

%s

resource "pagerduty_team" "foo" {
name = "%s"
}

resource "pagerduty_incident_workflow_trigger" "test" {
type = "%s"
condition = "%s"
workflow = pagerduty_incident_workflow.test.id
services = [pagerduty_service.foo.id]
subscribed_to_all_services = false
permissions {
restricted = %s
team_id = %s
}
}
`, testAccCheckPagerDutyServiceConfig(username, email, escalationPolicy, service), testAccCheckPagerDutyIncidentWorkflowConfig(workflow), team, triggerType, condition, isRestricted, teamId)
}

func testAccCheckPagerDutyIncidentWorkflowTriggerCheckPermissionsTeamId(iwtName, teamName string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rsIWT, ok := s.RootModule().Resources[iwtName]
if !ok {
return fmt.Errorf("not found: %s", iwtName)
}
if rsIWT.Primary.ID == "" {
return fmt.Errorf("no incident workflow trigger ID is set")
}

rsTeam, ok := s.RootModule().Resources[teamName]
if !ok {
return fmt.Errorf("not found: %s", teamName)
}
if rsTeam.Primary.ID == "" {
return fmt.Errorf("no team ID is set")
}

client, _ := testAccProvider.Meta().(*Config).Client()

found, _, err := client.IncidentWorkflowTriggers.Get(rsIWT.Primary.ID)
if err != nil {
return err
}

if found.Permissions.TeamID != rsTeam.Primary.ID {
return fmt.Errorf("incident workflow trigger team restriction wanted %q, but got %q", rsTeam.Primary.ID, found.Permissions.TeamID)
}

return nil
}
}

func TestAccPagerDutyIncidentWorkflowTrigger_ChangeTypeCausesReplace(t *testing.T) {
workflow := fmt.Sprintf("tf-%s", acctest.RandString(5))

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion vendor/modules.txt
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ github.com/hashicorp/terraform-svchost
# github.com/hashicorp/yamux v0.1.1
## explicit; go 1.15
github.com/hashicorp/yamux
# github.com/heimweh/go-pagerduty v0.0.0-20240403153232-5876af2ce24a
# github.com/heimweh/go-pagerduty v0.0.0-20240403153232-5876af2ce24a => github.com/imjaroiswebdev/go-pagerduty v0.0.0-20240419180041-eace2b31e15b
## explicit; go 1.17
github.com/heimweh/go-pagerduty/pagerduty
github.com/heimweh/go-pagerduty/persistentconfig
Expand Down Expand Up @@ -551,3 +551,4 @@ google.golang.org/protobuf/types/known/timestamppb
# gopkg.in/ini.v1 v1.67.0
## explicit
gopkg.in/ini.v1
# github.com/heimweh/go-pagerduty => github.com/imjaroiswebdev/go-pagerduty v0.0.0-20240419180041-eace2b31e15b
3 changes: 3 additions & 0 deletions website/docs/r/incident_workflow_trigger.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ The following arguments are supported:
* `workflow` - (Required) The workflow ID for the workflow to trigger.
* `services` - (Optional) A list of service IDs. Incidents in any of the listed services are eligible to fire this trigger.
* `subscribed_to_all_services` - (Required) Set to `true` if the trigger should be eligible for firing on all services. Only allowed to be `true` if the services list is not defined or empty.
* `permissions` - (Optional) Indicates who can start this Trigger. Applicable only to `manual`-type triggers.
* `restricted` - (Optional) If `true`, indicates that the Trigger can only be started by authorized Users. If `false` (default), any user can start this Trigger. Applicable only to `manual`-type triggers.
* `team_id` - (Optional) The ID of the Team whose members can manually start this Trigger. Required and allowed only if `restricted` is `true`.
* `condition` - (Required for `conditional`-type triggers) A [PCL](https://developer.pagerduty.com/docs/ZG9jOjM1NTE0MDc0-pcl-overview) condition string which must be satisfied for the trigger to fire.

## Attributes Reference
Expand Down
Loading