From 0c0450b3471da2f2bda7423bdd74d2f693188bde Mon Sep 17 00:00:00 2001 From: alenapan <47909261+alenapan@users.noreply.github.com> Date: Fri, 14 Jun 2024 07:41:51 -0700 Subject: [PATCH 1/7] [ORCA-4811] Add support for `dynamic_route_to` action to `pagerduty_event_orchestration_router` (#1) * temporarily replace go-client with a feature branch * ORCA-4811 - add support for action * fix import tests * Revert "fix import tests" This reverts commit e42694d1ad4bc43be28016213ac4a1ebbcfe0c9f. --- go.mod | 2 + go.sum | 4 +- ...gerduty_event_orchestration_path_router.go | 58 +++++++++++- ...ty_event_orchestration_path_router_test.go | 94 +++++++++++++++++++ .../pagerduty/event_orchestration_path.go | 7 ++ vendor/modules.txt | 3 +- 6 files changed, 162 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 98a5fd37d..7724ef2aa 100644 --- a/go.mod +++ b/go.mod @@ -76,3 +76,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/alexzakabluk/go-pagerduty v0.0.0-20240607142119-ac9a64bba6da diff --git a/go.sum b/go.sum index c7794d9a7..746f28393 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c h1:kMFnB0vCcX github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= +github.com/alexzakabluk/go-pagerduty v0.0.0-20240607142119-ac9a64bba6da h1:O2mVKSglj/gEz+Z7GX+L4Y1zGRIiDxPHdfp6Ri7klww= +github.com/alexzakabluk/go-pagerduty v0.0.0-20240607142119-ac9a64bba6da/go.mod h1:r59w5iyN01Qvi734yA5hZldbSeJJmsJzee/1kQ/MK7s= github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= @@ -95,8 +97,6 @@ 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-20240503143637-3459408ac715 h1:DbdS2LIPkhsqgRcQzOAux0RpTJSH8VYOrN4rZZgznak= -github.com/heimweh/go-pagerduty v0.0.0-20240503143637-3459408ac715/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= diff --git a/pagerduty/resource_pagerduty_event_orchestration_path_router.go b/pagerduty/resource_pagerduty_event_orchestration_path_router.go index 5a1a0e8b0..873864b42 100644 --- a/pagerduty/resource_pagerduty_event_orchestration_path_router.go +++ b/pagerduty/resource_pagerduty_event_orchestration_path_router.go @@ -63,9 +63,29 @@ func resourcePagerDutyEventOrchestrationPathRouter() *schema.Resource { MaxItems: 1, // there can only be one action for router Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "dynamic_route_to": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "lookup_by": { + Type: schema.TypeString, + Required: true, + }, + "regex": { + Type: schema.TypeString, + Required: true, + }, + "source": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, "route_to": { Type: schema.TypeString, - Required: true, + Optional: true, ValidateFunc: func(v interface{}, key string) (warns []string, errs []error) { value := v.(string) if value == "unrouted" { @@ -294,7 +314,12 @@ func expandRouterActions(v interface{}) *pagerduty.EventOrchestrationPathRuleAct actions := new(pagerduty.EventOrchestrationPathRuleActions) for _, ai := range v.([]interface{}) { am := ai.(map[string]interface{}) - actions.RouteTo = am["route_to"].(string) + dra := am["dynamic_route_to"] + if !isNilFunc(dra) && len(dra.([]interface{})) > 0 { + actions.DynamicRouteTo = expandRouterDynamicRouteToAction(dra) + } else { + actions.RouteTo = am["route_to"].(string) + } } return actions @@ -311,6 +336,17 @@ func expandCatchAll(v interface{}) *pagerduty.EventOrchestrationPathCatchAll { return catchAll } +func expandRouterDynamicRouteToAction(v interface{}) *pagerduty.EventOrchestrationPathDynamicRouteTo { + dr := new(pagerduty.EventOrchestrationPathDynamicRouteTo) + for _, i := range v.([]interface{}) { + dra := i.(map[string]interface{}) + dr.LookupBy = dra["lookup_by"].(string) + dr.Regex = dra["regex"].(string) + dr.Source = dra["source"].(string) + } + return dr +} + func flattenSets(orchPathSets []*pagerduty.EventOrchestrationPathSet) []interface{} { var flattenedSets []interface{} for _, set := range orchPathSets { @@ -344,7 +380,11 @@ func flattenRouterActions(actions *pagerduty.EventOrchestrationPathRuleActions) var actionsMap []map[string]interface{} am := make(map[string]interface{}) - am["route_to"] = actions.RouteTo + if actions.DynamicRouteTo != nil { + am["dynamic_route_to"] = flattenRouterDynamicRouteToAction(actions.DynamicRouteTo) + } else { + am["route_to"] = actions.RouteTo + } actionsMap = append(actionsMap, am) return actionsMap } @@ -360,6 +400,18 @@ func flattenCatchAll(catchAll *pagerduty.EventOrchestrationPathCatchAll) []map[s return caMap } +func flattenRouterDynamicRouteToAction(dra *pagerduty.EventOrchestrationPathDynamicRouteTo) []map[string]interface{} { + var dr []map[string]interface{} + + dr = append(dr, map[string]interface{}{ + "lookup_by": dra.LookupBy, + "regex": dra.Regex, + "source": dra.Source, + }) + + return dr +} + func resourcePagerDutyEventOrchestrationPathRouterImport(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { client, err := meta.(*Config).Client() if err != nil { diff --git a/pagerduty/resource_pagerduty_event_orchestration_path_router_test.go b/pagerduty/resource_pagerduty_event_orchestration_path_router_test.go index 246c349d5..c2885623e 100644 --- a/pagerduty/resource_pagerduty_event_orchestration_path_router_test.go +++ b/pagerduty/resource_pagerduty_event_orchestration_path_router_test.go @@ -8,6 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/heimweh/go-pagerduty/pagerduty" ) func init() { @@ -23,6 +24,17 @@ func TestAccPagerDutyEventOrchestrationPathRouter_Basic(t *testing.T) { service := fmt.Sprintf("tf-%s", acctest.RandString(5)) orchestration := fmt.Sprintf("tf-orchestration-%s", acctest.RandString(5)) + dynamicRouteToByNameInput := &pagerduty.EventOrchestrationPathDynamicRouteTo{ + LookupBy: "service_name", + Regex: ".*", + Source: "event.custom_details.pd_service_name", + } + dynamicRouteToByIDInput := &pagerduty.EventOrchestrationPathDynamicRouteTo{ + LookupBy: "service_id", + Regex: "ID:(.*)", + Source: "event.custom_details.pd_service_id", + } + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, @@ -48,6 +60,27 @@ func TestAccPagerDutyEventOrchestrationPathRouter_Basic(t *testing.T) { "pagerduty_event_orchestration_router.router", "unrouted", true), //test for catch_all route_to prop, by default it should be unrouted ), }, + // Configure a Dynamic Routing rule: + { + Config: testAccCheckPagerDutyEventOrchestrationRouterDynamicRouteToConfig(team, escalationPolicy, service, orchestration, dynamicRouteToByNameInput), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationRouterExists("pagerduty_event_orchestration_router.router"), + testAccCheckPagerDutyEventOrchestrationRouterPathDynamicRouteToMatch("pagerduty_event_orchestration_router.router", dynamicRouteToByNameInput), + testAccCheckPagerDutyEventOrchestrationRouterPathRouteToMatch( + "pagerduty_event_orchestration_router.router", "unrouted", true), + ), + }, + // Update the Dynamic Routing rule added in the previous test case: + { + Config: testAccCheckPagerDutyEventOrchestrationRouterDynamicRouteToConfig(team, escalationPolicy, service, orchestration, dynamicRouteToByIDInput), + Check: resource.ComposeTestCheckFunc( + testAccCheckPagerDutyEventOrchestrationRouterExists("pagerduty_event_orchestration_router.router"), + testAccCheckPagerDutyEventOrchestrationRouterPathDynamicRouteToMatch("pagerduty_event_orchestration_router.router", dynamicRouteToByIDInput), + testAccCheckPagerDutyEventOrchestrationRouterPathRouteToMatch( + "pagerduty_event_orchestration_router.router", "unrouted", true), + ), + }, + // Delete the Dynamic Routing rule added in the previous test cases: { Config: testAccCheckPagerDutyEventOrchestrationRouterConfigWithConditions(team, escalationPolicy, service, orchestration), Check: resource.ComposeTestCheckFunc( @@ -279,6 +312,42 @@ func testAccCheckPagerDutyEventOrchestrationRouterConfig(t, ep, s, o string) str `) } +func testAccCheckPagerDutyEventOrchestrationRouterDynamicRouteToConfig(t, ep, s, o string, dynamicRouteToByNameInput *pagerduty.EventOrchestrationPathDynamicRouteTo) string { + routerConfig := fmt.Sprintf( + `resource "pagerduty_event_orchestration_router" "router" { + event_orchestration = pagerduty_event_orchestration.orch.id + + catch_all { + actions { + route_to = "unrouted" + } + } + set { + id = "start" + rule { + disabled = false + label = "dynamic routing rule" + actions { + dynamic_route_to { + lookup_by = "%s" + regex = "%s" + source = "%s" + } + } + } + rule { + label = "static routing rule" + actions { + route_to = pagerduty_service.bar.id + } + } + } + } + `, dynamicRouteToByNameInput.LookupBy, dynamicRouteToByNameInput.Regex, dynamicRouteToByNameInput.Source) + + return fmt.Sprintf("%s%s", createBaseConfig(t, ep, s, o), routerConfig) +} + func testAccCheckPagerDutyEventOrchestrationRouterConfigWithConditions(t, ep, s, o string) string { return fmt.Sprintf("%s%s", createBaseConfig(t, ep, s, o), `resource "pagerduty_event_orchestration_router" "router" { @@ -510,3 +579,28 @@ func testAccCheckPagerDutyEventOrchestrationRouterPathRouteToMatch(router, servi return nil } } + +func testAccCheckPagerDutyEventOrchestrationRouterPathDynamicRouteToMatch(router string, expectedDynamicRouteTo *pagerduty.EventOrchestrationPathDynamicRouteTo) resource.TestCheckFunc { + return func(s *terraform.State) error { + r, rOk := s.RootModule().Resources[router] + if !rOk { + return fmt.Errorf("Not found: %s", router) + } + + rLookupBy := r.Primary.Attributes["set.0.rule.0.actions.0.dynamic_route_to.0.lookup_by"] + rRegex := r.Primary.Attributes["set.0.rule.0.actions.0.dynamic_route_to.0.regex"] + rSource := r.Primary.Attributes["set.0.rule.0.actions.0.dynamic_route_to.0.source"] + + if rLookupBy != expectedDynamicRouteTo.LookupBy { + return fmt.Errorf("Event Orchestration Router `dynamic_route_to.lookup_by` (%v) does not match expected value: %v", rLookupBy, expectedDynamicRouteTo.LookupBy) + } + if rRegex != expectedDynamicRouteTo.Regex { + return fmt.Errorf("Event Orchestration Router `dynamic_route_to.regex` (%v) does not match expected value: %v", rRegex, expectedDynamicRouteTo.Regex) + } + if rSource != expectedDynamicRouteTo.Source { + return fmt.Errorf("Event Orchestration Router `dynamic_route_to.source` (%v) does not match expected value: %v", rSource, expectedDynamicRouteTo.Source) + } + + return nil + } +} diff --git a/vendor/github.com/heimweh/go-pagerduty/pagerduty/event_orchestration_path.go b/vendor/github.com/heimweh/go-pagerduty/pagerduty/event_orchestration_path.go index 72b60e0f4..9760a6702 100644 --- a/vendor/github.com/heimweh/go-pagerduty/pagerduty/event_orchestration_path.go +++ b/vendor/github.com/heimweh/go-pagerduty/pagerduty/event_orchestration_path.go @@ -53,6 +53,7 @@ type EventOrchestrationPathRuleCondition struct { type EventOrchestrationPathRuleActions struct { DropEvent bool `json:"drop_event"` RouteTo string `json:"route_to"` + DynamicRouteTo *EventOrchestrationPathDynamicRouteTo `json:"dynamic_route_to"` Suppress bool `json:"suppress"` Suspend *int `json:"suspend"` Priority string `json:"priority"` @@ -66,6 +67,12 @@ type EventOrchestrationPathRuleActions struct { Extractions []*EventOrchestrationPathActionExtractions `json:"extractions"` } +type EventOrchestrationPathDynamicRouteTo struct { + Source string `json:"source,omitempty"` + Regex string `json:"regex,omitempty"` + LookupBy string `json:"lookup_by,omitempty"` +} + type EventOrchestrationPathIncidentCustomFieldUpdate struct { ID string `json:"id,omitempty"` Value string `json:"value,omitempty"` diff --git a/vendor/modules.txt b/vendor/modules.txt index 26f324e00..2f1765710 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -258,7 +258,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-20240503143637-3459408ac715 +# github.com/heimweh/go-pagerduty v0.0.0-20240503143637-3459408ac715 => github.com/alexzakabluk/go-pagerduty v0.0.0-20240607142119-ac9a64bba6da ## explicit; go 1.17 github.com/heimweh/go-pagerduty/pagerduty github.com/heimweh/go-pagerduty/persistentconfig @@ -559,3 +559,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/alexzakabluk/go-pagerduty v0.0.0-20240607142119-ac9a64bba6da From 71f2a22cd33390d9e0aa5e53a5594fe986aa5617 Mon Sep 17 00:00:00 2001 From: alenapan <47909261+alenapan@users.noreply.github.com> Date: Thu, 20 Jun 2024 12:30:49 -0700 Subject: [PATCH 2/7] ORCA-4813 - Add validation for Dynamic Routing rule (#2) --- pagerduty/event_orchestration_path_util.go | 4 + ...gerduty_event_orchestration_path_router.go | 52 ++++++- ...ty_event_orchestration_path_router_test.go | 133 +++++++++++++++++- 3 files changed, 186 insertions(+), 3 deletions(-) diff --git a/pagerduty/event_orchestration_path_util.go b/pagerduty/event_orchestration_path_util.go index 92f7b41de..f69d12656 100644 --- a/pagerduty/event_orchestration_path_util.go +++ b/pagerduty/event_orchestration_path_util.go @@ -427,3 +427,7 @@ func emptyOrchestrationPathStructBuilder(pathType string) *pagerduty.EventOrches return commonEmptyOrchestrationPath() } + +func isNonEmptyList(arg interface{}) bool { + return !isNilFunc(arg) && len(arg.([]interface{})) > 0 +} diff --git a/pagerduty/resource_pagerduty_event_orchestration_path_router.go b/pagerduty/resource_pagerduty_event_orchestration_path_router.go index 873864b42..9be29d6f0 100644 --- a/pagerduty/resource_pagerduty_event_orchestration_path_router.go +++ b/pagerduty/resource_pagerduty_event_orchestration_path_router.go @@ -5,6 +5,7 @@ import ( "fmt" "log" "net/http" + "strings" "time" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -22,6 +23,7 @@ func resourcePagerDutyEventOrchestrationPathRouter() *schema.Resource { Importer: &schema.ResourceImporter{ StateContext: resourcePagerDutyEventOrchestrationPathRouterImport, }, + CustomizeDiff: checkDynamicRoutingRule, Schema: map[string]*schema.Schema{ "event_orchestration": { Type: schema.TypeString, @@ -133,6 +135,54 @@ func resourcePagerDutyEventOrchestrationPathRouter() *schema.Resource { } } +func checkDynamicRoutingRule(context context.Context, diff *schema.ResourceDiff, i interface{}) error { + rNum := diff.Get("set.0.rule.#").(int) + draIdxs := []int{} + errorMsgs := []string{} + + for ri := 0; ri < rNum; ri++ { + dra := diff.Get(fmt.Sprintf("set.0.rule.%d.actions.0.dynamic_route_to", ri)) + hasDra := isNonEmptyList(dra) + if !hasDra { + continue + } + draIdxs = append(draIdxs, ri) + } + // 1. Only the first rule of the first ("start") set can have the Dynamic Routing action: + if len(draIdxs) > 1 { + idxs := []string{} + for _, idx := range draIdxs { + idxs = append(idxs, fmt.Sprintf("%d", idx)) + } + errorMsgs = append(errorMsgs, fmt.Sprintf("A Router can have at most one Dynamic Routing rule; Rules with the dynamic_route_to action found at indexes: %s", strings.Join(idxs, ", "))) + } + // 2. The Dynamic Routing action can only be used in the first rule of the first set: + if len(draIdxs) > 0 && draIdxs[0] != 0 { + errorMsgs = append(errorMsgs, fmt.Sprintf("The Dynamic Routing rule must be the first rule in a Router")) + } + // 3. If the Dynamic Routing rule is the first rule of the first set, + // validate its configuration. It cannot have any conditions or the `route_to` action: + if len(draIdxs) == 1 && draIdxs[0] == 0 { + condNum := diff.Get("set.0.rule.0.condition.#").(int) + // diff.NewValueKnown(str) will return false if the value is based on interpolation that was unavailable at diff time, + // which may be the case for the `route_to` action when it references a pagerduty_service resource. + // Source: https://pkg.go.dev/github.com/hashicorp/terraform-plugin-sdk/helper/schema#ResourceDiff.NewValueKnown + routeToValueKnown := diff.NewValueKnown("set.0.rule.0.actions.0.route_to") + routeTo := diff.Get("set.0.rule.0.actions.0.route_to").(string) + if condNum > 0 { + errorMsgs = append(errorMsgs, fmt.Sprintf("Dynamic Routing rules cannot have conditions")) + } + if !routeToValueKnown || routeToValueKnown && routeTo != "" { + errorMsgs = append(errorMsgs, fmt.Sprintf("Dynamic Routing rules cannot have the `route_to` action")) + } + } + + if len(errorMsgs) > 0 { + return fmt.Errorf("Invalid Dynamic Routing rule configuration:\n- %s", strings.Join(errorMsgs, "\n- ")) + } + return nil +} + func resourcePagerDutyEventOrchestrationPathRouterRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics @@ -315,7 +365,7 @@ func expandRouterActions(v interface{}) *pagerduty.EventOrchestrationPathRuleAct for _, ai := range v.([]interface{}) { am := ai.(map[string]interface{}) dra := am["dynamic_route_to"] - if !isNilFunc(dra) && len(dra.([]interface{})) > 0 { + if isNonEmptyList(dra) { actions.DynamicRouteTo = expandRouterDynamicRouteToAction(dra) } else { actions.RouteTo = am["route_to"].(string) diff --git a/pagerduty/resource_pagerduty_event_orchestration_path_router_test.go b/pagerduty/resource_pagerduty_event_orchestration_path_router_test.go index c2885623e..fcf81f2c1 100644 --- a/pagerduty/resource_pagerduty_event_orchestration_path_router_test.go +++ b/pagerduty/resource_pagerduty_event_orchestration_path_router_test.go @@ -3,6 +3,7 @@ package pagerduty import ( "context" "fmt" + "regexp" "testing" "github.com/hashicorp/terraform-plugin-testing/helper/acctest" @@ -34,12 +35,32 @@ func TestAccPagerDutyEventOrchestrationPathRouter_Basic(t *testing.T) { Regex: "ID:(.*)", Source: "event.custom_details.pd_service_id", } + invalidDynamicRouteToPlacementMessage := "Invalid Dynamic Routing rule configuration:\n- A Router can have at most one Dynamic Routing rule; Rules with the dynamic_route_to action found at indexes: 1, 2\n- The Dynamic Routing rule must be the first rule in a Router" + invalidDynamicRouteToConfigMessage := "Invalid Dynamic Routing rule configuration:\n- Dynamic Routing rules cannot have conditions\n- Dynamic Routing rules cannot have the `route_to` action" resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckPagerDutyEventOrchestrationRouterDestroy, Steps: []resource.TestStep{ + // Invalid Dynamic Routing rule config for a new resource: multiple Dynamic Routing rules, Dynamic Routing rule not the first rule in the Router: + { + Config: testAccCheckPagerDutyEventOrchestrationRouterInvalidDynamicRoutingRulePlacement(team, escalationPolicy, service, orchestration), + PlanOnly: true, + ExpectError: regexp.MustCompile(invalidDynamicRouteToPlacementMessage), + }, + // Invalid Dynamic Routing rule config for a new resource: Dynamic Routing rule with conditions and the interpolated route_to action: + { + Config: testAccCheckPagerDutyEventOrchestrationRouterInvalidDynamicRoutingRuleConfig(team, escalationPolicy, service, orchestration, "pagerduty_service.bar.id"), + PlanOnly: true, + ExpectError: regexp.MustCompile(invalidDynamicRouteToConfigMessage), + }, + // Invalid Dynamic Routing rule config for a new resource: Dynamic Routing rule with conditions and the hard-coded route_to action: + { + Config: testAccCheckPagerDutyEventOrchestrationRouterInvalidDynamicRoutingRuleConfig(team, escalationPolicy, service, orchestration, "\"PARASOL\""), + PlanOnly: true, + ExpectError: regexp.MustCompile(invalidDynamicRouteToConfigMessage), + }, { Config: testAccCheckPagerDutyEventOrchestrationRouterConfigNoRules(team, escalationPolicy, service, orchestration), Check: resource.ComposeTestCheckFunc( @@ -70,7 +91,25 @@ func TestAccPagerDutyEventOrchestrationPathRouter_Basic(t *testing.T) { "pagerduty_event_orchestration_router.router", "unrouted", true), ), }, - // Update the Dynamic Routing rule added in the previous test case: + // Invalid Dynamic Routing rule config for an existing resource: multiple Dynamic Routing rules, Dynamic Routing rule not the first rule in the Router: + { + Config: testAccCheckPagerDutyEventOrchestrationRouterInvalidDynamicRoutingRulePlacement(team, escalationPolicy, service, orchestration), + PlanOnly: true, + ExpectError: regexp.MustCompile(invalidDynamicRouteToPlacementMessage), + }, + // Invalid Dynamic Routing rule config for an existing resource: Dynamic Routing rule with conditions and the interpolated route_to action: + { + Config: testAccCheckPagerDutyEventOrchestrationRouterInvalidDynamicRoutingRuleConfig(team, escalationPolicy, service, orchestration, "pagerduty_service.bar.id"), + PlanOnly: true, + ExpectError: regexp.MustCompile(invalidDynamicRouteToConfigMessage), + }, + // Invalid Dynamic Routing rule config for an existing resource: Dynamic Routing rule with conditions and the hard-coded route_to action: + { + Config: testAccCheckPagerDutyEventOrchestrationRouterInvalidDynamicRoutingRuleConfig(team, escalationPolicy, service, orchestration, "\"PARASOL\""), + PlanOnly: true, + ExpectError: regexp.MustCompile(invalidDynamicRouteToConfigMessage), + }, + // Update the Dynamic Routing rule: { Config: testAccCheckPagerDutyEventOrchestrationRouterDynamicRouteToConfig(team, escalationPolicy, service, orchestration, dynamicRouteToByIDInput), Check: resource.ComposeTestCheckFunc( @@ -80,7 +119,7 @@ func TestAccPagerDutyEventOrchestrationPathRouter_Basic(t *testing.T) { "pagerduty_event_orchestration_router.router", "unrouted", true), ), }, - // Delete the Dynamic Routing rule added in the previous test cases: + // Delete the Dynamic Routing rule: { Config: testAccCheckPagerDutyEventOrchestrationRouterConfigWithConditions(team, escalationPolicy, service, orchestration), Check: resource.ComposeTestCheckFunc( @@ -271,6 +310,96 @@ func createBaseConfig(t, ep, s, o string) string { `, t, ep, s, o) } +func testAccCheckPagerDutyEventOrchestrationRouterInvalidDynamicRoutingRulePlacement(t, ep, s, o string) string { + return fmt.Sprintf("%s%s", createBaseConfig(t, ep, s, o), + `resource "pagerduty_event_orchestration_router" "router" { + event_orchestration = pagerduty_event_orchestration.orch.id + + catch_all { + actions { + route_to = "unrouted" + } + } + set { + id = "start" + rule { + label = "static routing rule 1" + actions { + route_to = pagerduty_service.bar.id + } + } + rule { + disabled = false + label = "dynamic routing rule 1" + actions { + dynamic_route_to { + lookup_by = "service_id" + regex = ".*" + source = "event.custom_details.pd_service_id" + } + } + } + rule { + label = "dynamic routing rule 2" + actions { + dynamic_route_to { + lookup_by = "service_name" + regex = ".*" + source = "event.custom_details.pd_service_name" + } + } + } + rule { + label = "static routing rule 2" + actions { + route_to = "P1B2C23" + } + } + + } + } + `) +} + +func testAccCheckPagerDutyEventOrchestrationRouterInvalidDynamicRoutingRuleConfig(t, ep, s, o, routeTo string) string { + routerConfig := fmt.Sprintf( + `resource "pagerduty_event_orchestration_router" "router" { + event_orchestration = pagerduty_event_orchestration.orch.id + + catch_all { + actions { + route_to = "unrouted" + } + } + set { + id = "start" + rule { + label = "dynamic routing rule 1" + condition { + expression = "event.summary matches part 'production'" + } + actions { + dynamic_route_to { + lookup_by = "service_id" + regex = ".*" + source = "event.custom_details.pd_service_id" + } + route_to = %s + } + } + rule { + label = "static routing rule 1" + actions { + route_to = "P1B2C23" + } + } + + } + } + `, routeTo) + return fmt.Sprintf("%s%s", createBaseConfig(t, ep, s, o), routerConfig) +} + func testAccCheckPagerDutyEventOrchestrationRouterConfigNoRules(t, ep, s, o string) string { return fmt.Sprintf("%s%s", createBaseConfig(t, ep, s, o), `resource "pagerduty_event_orchestration_router" "router" { From 00b4f2a5055a19d01af92859207225c68ebdeaf2 Mon Sep 17 00:00:00 2001 From: Marcos Wright-Kuhns Date: Tue, 25 Jun 2024 09:50:19 -0700 Subject: [PATCH 3/7] ORCA-4812: Document The `dynamic_route_to` action (#3) * Update the router example to use the pagerduty_service data source * Add a dynamic router rule example * Document the dynamic vs static router actions --- .../event_orchestration_router.html.markdown | 42 ++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/website/docs/r/event_orchestration_router.html.markdown b/website/docs/r/event_orchestration_router.html.markdown index 821289d4a..c232ea8b4 100644 --- a/website/docs/r/event_orchestration_router.html.markdown +++ b/website/docs/r/event_orchestration_router.html.markdown @@ -12,15 +12,31 @@ An Orchestration Router allows users to create a set of Event Rules. The Router ## Example of configuring Router rules for an Orchestration -In this example the user has defined the Router with two rules, each routing to a different service. - -This example assumes services used in the `route_to` configuration already exists. So it does not show creation of service resource. +In this example the user has defined the Router with three rules. The first rule configures a dynamic route: any event containing a value in its `pd_service_id` custom detail will be routed to the Service with the ID specified by that value. The other rules route events matching a condition to specific services. ```hcl +data "pagerduty_service" "database" { + name = "Primary Data Store" +} + +data "pagerduty_service" "www" { + name = "Web Server App" +} + resource "pagerduty_event_orchestration_router" "router" { event_orchestration = pagerduty_event_orchestration.my_monitor.id set { id = "start" + rule { + label = "Dynamically route events related to specific PagerDuty services" + actions { + dynamic_route_to = { + lookup_by = "service_id" + source = "event.custom_details.pd_service_id" + regexp = "(.*)" + } + } + } rule { label = "Events relating to our relational database" condition { @@ -30,7 +46,7 @@ resource "pagerduty_event_orchestration_router" "router" { expression = "event.source matches regex 'db[0-9]+-server'" } actions { - route_to = pagerduty_service.database.id + route_to = data.pagerduty_service.database.id } } rule { @@ -38,7 +54,7 @@ resource "pagerduty_event_orchestration_router" "router" { expression = "event.summary matches part 'www'" } actions { - route_to = pagerduty_service.www.id + route_to = data.pagerduty_service.www.id } } } @@ -72,6 +88,22 @@ The following arguments are supported: * `expression`- (Required) A [PCL condition](https://developer.pagerduty.com/docs/ZG9jOjM1NTE0MDc0-pcl-overview) string. ### Actions (`actions`) supports the following: + +#### Dynamic Routing + +Use the contents of an event payload to dynamically route an event to the target service. Note these setting can only be used once in the Router, and only in the first rule. The dynamic routing rule cannot have `conditions` nor a `route_to` action defined. + +* `dynamic_route_to` - (Required) supports the following: + * `source` - (Required) The path to a field in an event. + * `regex` - (Required) The regular expression, used to extract a value from the source field. Must use valid [RE2 regular expression](https://github.com/google/re2/wiki/Syntax) syntax. + * `lookup_by` - (Required) Indicates whether the extracted value from the source is a service's name or ID. Allowed values are: `service_name`, `service_id` + +If an event has a value at the specified `source`, and if the `regex` successfully matches the value, and if the matching portion is valid Service ID or Name, then the event will be routed to that service. Otherwise the event will be checked against any subsequent router rules. + +#### Service Route + +If an event matches this rule's conditions, then route it to the specified Service. + * `route_to` - (Required) The ID of the target Service for the resulting alert. ### Catch All (`catch_all`) supports the following: From 6e29bb4de8477de253a19d85255cc30eea6d6353 Mon Sep 17 00:00:00 2001 From: alenapan <47909261+alenapan@users.noreply.github.com> Date: Tue, 9 Jul 2024 09:51:12 -0700 Subject: [PATCH 4/7] ORCA-4807 - document the escalation_policy action (#4) --- .../r/event_orchestration_global.html.markdown | 16 +++++++++++++++- .../r/event_orchestration_service.html.markdown | 16 +++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/website/docs/r/event_orchestration_global.html.markdown b/website/docs/r/event_orchestration_global.html.markdown index d59a62809..c57c6b39d 100644 --- a/website/docs/r/event_orchestration_global.html.markdown +++ b/website/docs/r/event_orchestration_global.html.markdown @@ -14,7 +14,7 @@ A [Global Orchestration](https://support.pagerduty.com/docs/event-orchestration# This example shows creating `Team`, and `Event Orchestration` resources followed by creating a Global Orchestration to handle Events sent to that Event Orchestration. -This example also shows using `priority` [data source](https://registry.terraform.io/providers/PagerDuty/pagerduty/latest/docs/data-sources/priority) to configure `priority` action for a rule. If the Event matches the third rule in set "step-two" the resulting incident will have the Priority `P1`. +This example also shows using the [pagerduty_priority](https://registry.terraform.io/providers/PagerDuty/pagerduty/latest/docs/data-sources/priority) and [pagerduty_escalation_policy](https://registry.terraform.io/providers/PagerDuty/pagerduty/latest/docs/data-sources/escalation_policy) data sources to configure `priority` and `escalation_policy` actions for a rule. This example shows a Global Orchestration that has nested sets: a rule in the "start" set has a `route_to` action pointing at the "step-two" set. @@ -35,6 +35,10 @@ data "pagerduty_priority" "p1" { name = "P1" } +data "pagerduty_escalation_policy" "sre_esc_policy" { + name = "SRE Escalation Policy" +} + resource "pagerduty_event_orchestration_global" "global" { event_orchestration = pagerduty_event_orchestration.event_orchestration.id set { @@ -59,6 +63,15 @@ resource "pagerduty_event_orchestration_global" "global" { drop_event = true } } + rule { + label = "If the DB host is running out of space, then page the SRE team" + condition { + expression = "event.summary matches part 'running out of space'" + } + actions { + escalation_policy = data.pagerduty_escalation_policy.sre_esc_policy.id + } + } rule { label = "If there's something wrong on the replica, then mark the alert as a warning" condition { @@ -112,6 +125,7 @@ The following arguments are supported: * `suppress` - (Optional) Set whether the resulting alert is suppressed. Suppressed alerts will not trigger an incident. * `suspend` - (Optional) The number of seconds to suspend the resulting alert before triggering. This effectively pauses incident notifications. If a `resolve` event arrives before the alert triggers then PagerDuty won't create an incident for this alert. * `priority` - (Optional) The ID of the priority you want to set on resulting incident. Consider using the [`pagerduty_priority`](https://registry.terraform.io/providers/PagerDuty/pagerduty/latest/docs/data-sources/priority) data source. +* `escalation_policy` - (Optional) The ID of the Escalation Policy you want to assign incidents to. Event rules with this action will override the Escalation Policy already set on a Service's settings, with what is configured by this action. * `annotate` - (Optional) Add this text as a note on the resulting incident. * `incident_custom_field_update` - (Optional) Assign a custom field to the resulting incident. * `id` - (Required) The custom field id diff --git a/website/docs/r/event_orchestration_service.html.markdown b/website/docs/r/event_orchestration_service.html.markdown index 17f7d8fb3..74b25f7e3 100644 --- a/website/docs/r/event_orchestration_service.html.markdown +++ b/website/docs/r/event_orchestration_service.html.markdown @@ -16,7 +16,7 @@ A [Service Orchestration](https://support.pagerduty.com/docs/event-orchestration This example shows creating `Team`, `User`, `Escalation Policy`, and `Service` resources followed by creating a Service Orchestration to handle Events sent to that Service. -This example also shows using `priority` [data source](https://registry.terraform.io/providers/PagerDuty/pagerduty/latest/docs/data-sources/priority) to configure `priority` action for a rule. If the Event matches the first rule in set "step-two" the resulting incident will have the Priority `P1`. +This example also shows using the [pagerduty_priority](https://registry.terraform.io/providers/PagerDuty/pagerduty/latest/docs/data-sources/priority) and [pagerduty_escalation_policy](https://registry.terraform.io/providers/PagerDuty/pagerduty/latest/docs/data-sources/escalation_policy) data sources to configure `priority` and `escalation_policy` actions for a rule. This example shows a Service Orchestration that has nested sets: a rule in the "start" set has a `route_to` action pointing at the "step-two" set. @@ -70,6 +70,10 @@ data "pagerduty_priority" "p1" { name = "P1" } +data "pagerduty_escalation_policy" "sre_esc_policy" { + name = "SRE Escalation Policy" +} + resource "pagerduty_event_orchestration_service" "www" { service = pagerduty_service.example.id enable_event_orchestration_for_service = true @@ -116,6 +120,15 @@ resource "pagerduty_event_orchestration_service" "www" { } } } + rule { + label = "If any of the API apps are unavailable, page the SRE team" + condition { + expression = "event.custom_details.service_name matches part '-api' and event.custom_details.status_code matches '502'" + } + actions { + escalation_policy = data.pagerduty_escalation_policy.sre_esc_policy.id + } + } rule { label = "If there's something wrong on the canary let the team know about it in our deployments Slack channel" condition { @@ -184,6 +197,7 @@ The following arguments are supported: * `suppress` - (Optional) Set whether the resulting alert is suppressed. Suppressed alerts will not trigger an incident. * `suspend` - (Optional) The number of seconds to suspend the resulting alert before triggering. This effectively pauses incident notifications. If a `resolve` event arrives before the alert triggers then PagerDuty won't create an incident for this alert. * `priority` - (Optional) The ID of the priority you want to set on resulting incident. Consider using the [`pagerduty_priority`](https://registry.terraform.io/providers/PagerDuty/pagerduty/latest/docs/data-sources/priority) data source. +* `escalation_policy` - (Optional) The ID of the Escalation Policy you want to assign incidents to. Event rules with this action will override the Escalation Policy already set on a Service's settings, with what is configured by this action. * `annotate` - (Optional) Add this text as a note on the resulting incident. * `incident_custom_field_update` - (Optional) Assign a custom field to the resulting incident. * `id` - (Required) The custom field id From c68d79a010cc2cb665680e54e277b48475d3c14d Mon Sep 17 00:00:00 2001 From: Alison Warner <108023093+alisonwarner-pd@users.noreply.github.com> Date: Fri, 12 Jul 2024 13:58:07 -0700 Subject: [PATCH 5/7] [ORCA-4806] Add support for the Escalation Policy action to Global and Service Event Orchestration resources (#5) * WIP * Add tests for global and service orchs * Changes from review * Formatting changes, renamed methods to be clearer * Syntax errors :facepalm: * Missed re-adding the expand line :o * * Catch-all supports EP, ensure it fits there * Add test cases to test tf resource * Add delete config * Do not add empty string for policy * Global and service path flattening * WIP Test for EP with terraformed ID * WIP * Temporary, running pagerduty-go from fork * Fixup tests, validate that *string escalation_policy is accepted * reformat test config * reimport go-pagerduty --------- Co-authored-by: Alena Pantuzenko --- go.mod | 2 +- go.sum | 4 ++-- ...gerduty_event_orchestration_path_global.go | 22 ++++++++++++------- ...ty_event_orchestration_path_global_test.go | 8 +++++++ ...erduty_event_orchestration_path_service.go | 20 +++++++++++------ ...y_event_orchestration_path_service_test.go | 7 ++++++ .../pagerduty/event_orchestration_path.go | 1 + vendor/modules.txt | 4 ++-- 8 files changed, 48 insertions(+), 20 deletions(-) diff --git a/go.mod b/go.mod index 7724ef2aa..24a8a2983 100644 --- a/go.mod +++ b/go.mod @@ -77,4 +77,4 @@ require ( gopkg.in/ini.v1 v1.67.0 // indirect ) -replace github.com/heimweh/go-pagerduty => github.com/alexzakabluk/go-pagerduty v0.0.0-20240607142119-ac9a64bba6da +replace github.com/heimweh/go-pagerduty => github.com/alexzakabluk/go-pagerduty v0.0.0-20240712180401-2eb91c030980 diff --git a/go.sum b/go.sum index 746f28393..7dfe0fc04 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,8 @@ github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c h1:kMFnB0vCcX github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= -github.com/alexzakabluk/go-pagerduty v0.0.0-20240607142119-ac9a64bba6da h1:O2mVKSglj/gEz+Z7GX+L4Y1zGRIiDxPHdfp6Ri7klww= -github.com/alexzakabluk/go-pagerduty v0.0.0-20240607142119-ac9a64bba6da/go.mod h1:r59w5iyN01Qvi734yA5hZldbSeJJmsJzee/1kQ/MK7s= +github.com/alexzakabluk/go-pagerduty v0.0.0-20240712180401-2eb91c030980 h1:ovY3d2mRCubr/5uuk0xcAZq2zJIR7t0kqGc/n/OWOYc= +github.com/alexzakabluk/go-pagerduty v0.0.0-20240712180401-2eb91c030980/go.mod h1:r59w5iyN01Qvi734yA5hZldbSeJJmsJzee/1kQ/MK7s= github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= diff --git a/pagerduty/resource_pagerduty_event_orchestration_path_global.go b/pagerduty/resource_pagerduty_event_orchestration_path_global.go index 1f989d5fe..3de411fe5 100644 --- a/pagerduty/resource_pagerduty_event_orchestration_path_global.go +++ b/pagerduty/resource_pagerduty_event_orchestration_path_global.go @@ -72,6 +72,10 @@ var eventOrchestrationPathGlobalCatchAllActionsSchema = map[string]*schema.Schem Schema: eventOrchestrationIncidentCustomFieldsObjectSchema, }, }, + "escalation_policy": { + Type: schema.TypeString, + Optional: true, + }, } var eventOrchestrationPathGlobalRuleActionsSchema = buildEventOrchestrationPathGlobalRuleActionsSchema() @@ -374,6 +378,7 @@ func expandGlobalPathActions(v interface{}) *pagerduty.EventOrchestrationPathRul actions.Suppress = a["suppress"].(bool) actions.Suspend = intTypeToIntPtr(a["suspend"].(int)) actions.Priority = a["priority"].(string) + actions.EscalationPolicy = stringTypeToStringPtr(a["escalation_policy"].(string)) actions.Annotate = a["annotate"].(string) actions.Severity = a["severity"].(string) actions.EventAction = a["event_action"].(string) @@ -439,14 +444,15 @@ func flattenGlobalPathActions(actions *pagerduty.EventOrchestrationPathRuleActio var actionsMap []map[string]interface{} flattenedAction := map[string]interface{}{ - "drop_event": actions.DropEvent, - "route_to": actions.RouteTo, - "severity": actions.Severity, - "event_action": actions.EventAction, - "suppress": actions.Suppress, - "suspend": actions.Suspend, - "priority": actions.Priority, - "annotate": actions.Annotate, + "drop_event": actions.DropEvent, + "route_to": actions.RouteTo, + "severity": actions.Severity, + "event_action": actions.EventAction, + "suppress": actions.Suppress, + "suspend": actions.Suspend, + "priority": actions.Priority, + "annotate": actions.Annotate, + "escalation_policy": stringPtrToStringType(actions.EscalationPolicy), } if actions.Variables != nil { diff --git a/pagerduty/resource_pagerduty_event_orchestration_path_global_test.go b/pagerduty/resource_pagerduty_event_orchestration_path_global_test.go index bdc6fded0..c5e1818e3 100644 --- a/pagerduty/resource_pagerduty_event_orchestration_path_global_test.go +++ b/pagerduty/resource_pagerduty_event_orchestration_path_global_test.go @@ -135,6 +135,9 @@ func TestAccPagerDutyEventOrchestrationPathGlobal_Basic(t *testing.T) { resource.TestCheckResourceAttrSet(res, "set.0.rule.1.id"), resource.TestCheckResourceAttrSet(res, "set.1.rule.0.id"), resource.TestCheckResourceAttrSet(res, "set.1.rule.1.id"), + resource.TestCheckResourceAttr( + res, "set.0.rule.0.actions.0.escalation_policy", "POLICY3", + ), }..., )..., ), @@ -481,6 +484,7 @@ func testAccCheckPagerDutyEventOrchestrationPathGlobalAllActionsConfig(t, ep, s, actions { route_to = "set-1" priority = "P0IN2KQ" + escalation_policy = pagerduty_escalation_policy.foo.id annotate = "Routed through an event orchestration" severity = "critical" event_action = "trigger" @@ -544,6 +548,7 @@ func testAccCheckPagerDutyEventOrchestrationPathGlobalAllActionsConfig(t, ep, s, actions { drop_event = true priority = "P0IN2KW" + escalation_policy = pagerduty_escalation_policy.foo.id annotate = "Routed through an event orchestration - catch-all rule" severity = "warning" event_action = "trigger" @@ -589,6 +594,7 @@ func testAccCheckPagerDutyEventOrchestrationPathGlobalAllActionsUpdateConfig(t, actions { route_to = "set-2" priority = "P0IN2KR" + escalation_policy = "POLICY3" annotate = "Routed through a service orchestration!" severity = "warning" event_action = "resolve" @@ -629,6 +635,7 @@ func testAccCheckPagerDutyEventOrchestrationPathGlobalAllActionsUpdateConfig(t, label = "set-2 rule 1" actions { suspend = 15 + escalation_policy = pagerduty_escalation_policy.foo.id } } rule { @@ -666,6 +673,7 @@ func testAccCheckPagerDutyEventOrchestrationPathGlobalAllActionsUpdateConfig(t, actions { drop_event = false priority = "P0IN2KX" + escalation_policy = "POLICY4" annotate = "[UPD] Routed through an event orchestration - catch-all rule" severity = "info" event_action = "resolve" diff --git a/pagerduty/resource_pagerduty_event_orchestration_path_service.go b/pagerduty/resource_pagerduty_event_orchestration_path_service.go index c6b85c6d9..1fcdf81ed 100644 --- a/pagerduty/resource_pagerduty_event_orchestration_path_service.go +++ b/pagerduty/resource_pagerduty_event_orchestration_path_service.go @@ -82,6 +82,10 @@ var eventOrchestrationPathServiceCatchAllActionsSchema = map[string]*schema.Sche Schema: eventOrchestrationIncidentCustomFieldsObjectSchema, }, }, + "escalation_policy": { + Type: schema.TypeString, + Optional: true, + }, } var eventOrchestrationPathServiceRuleActionsSchema = buildEventOrchestrationPathServiceRuleActionsSchema() @@ -484,6 +488,7 @@ func expandServicePathActions(v interface{}) *pagerduty.EventOrchestrationPathRu actions.Suppress = a["suppress"].(bool) actions.Suspend = intTypeToIntPtr(a["suspend"].(int)) actions.Priority = a["priority"].(string) + actions.EscalationPolicy = stringTypeToStringPtr(a["escalation_policy"].(string)) actions.Annotate = a["annotate"].(string) actions.Severity = a["severity"].(string) actions.EventAction = a["event_action"].(string) @@ -565,13 +570,14 @@ func flattenServicePathActions(actions *pagerduty.EventOrchestrationPathRuleActi var actionsMap []map[string]interface{} flattenedAction := map[string]interface{}{ - "route_to": actions.RouteTo, - "severity": actions.Severity, - "event_action": actions.EventAction, - "suppress": actions.Suppress, - "suspend": actions.Suspend, - "priority": actions.Priority, - "annotate": actions.Annotate, + "route_to": actions.RouteTo, + "severity": actions.Severity, + "event_action": actions.EventAction, + "suppress": actions.Suppress, + "suspend": actions.Suspend, + "priority": actions.Priority, + "annotate": actions.Annotate, + "escalation_policy": stringPtrToStringType(actions.EscalationPolicy), } if actions.Variables != nil { diff --git a/pagerduty/resource_pagerduty_event_orchestration_path_service_test.go b/pagerduty/resource_pagerduty_event_orchestration_path_service_test.go index ff91dcbd0..d1e8d9d43 100644 --- a/pagerduty/resource_pagerduty_event_orchestration_path_service_test.go +++ b/pagerduty/resource_pagerduty_event_orchestration_path_service_test.go @@ -135,6 +135,9 @@ func TestAccPagerDutyEventOrchestrationPathService_Basic(t *testing.T) { resource.TestCheckResourceAttrSet(resourceName, "set.0.rule.0.id"), resource.TestCheckResourceAttrSet(resourceName, "set.1.rule.0.id"), resource.TestCheckResourceAttrSet(resourceName, "set.1.rule.1.id"), + resource.TestCheckResourceAttr( + resourceName, "set.0.rule.0.actions.0.escalation_policy", "POLICY3", + ), }..., )..., ), @@ -547,6 +550,7 @@ func testAccCheckPagerDutyEventOrchestrationPathServiceAllActionsConfig(ep, s st actions { route_to = "set-1" priority = "P0IN2KQ" + escalation_policy = pagerduty_escalation_policy.foo.id annotate = "Routed through an event orchestration" pagerduty_automation_action { action_id = "01CSB5SMOKCKVRI5GN0LJG7SMB" @@ -604,6 +608,7 @@ func testAccCheckPagerDutyEventOrchestrationPathServiceAllActionsConfig(ep, s st actions { suspend = 120 priority = "P0IN2KW" + escalation_policy = pagerduty_escalation_policy.foo.id annotate = "Routed through an event orchestration - catch-all rule" pagerduty_automation_action { action_id = "01CSB5SMOKCKVRI5GN0LJG7SMC" @@ -652,6 +657,7 @@ func testAccCheckPagerDutyEventOrchestrationPathServiceAllActionsUpdateConfig(ep actions { route_to = "set-2" priority = "P0IN2KR" + escalation_policy = "POLICY3" annotate = "Routed through a service orchestration!" pagerduty_automation_action { action_id = "01CSB5SMOKCKVRI5GN0LJG7SMBUPDATED" @@ -723,6 +729,7 @@ func testAccCheckPagerDutyEventOrchestrationPathServiceAllActionsUpdateConfig(ep actions { suspend = 360 priority = "P0IN2KX" + escalation_policy = "POLICY4" annotate = "[UPD] Routed through an event orchestration - catch-all rule" pagerduty_automation_action { action_id = "01CSB5SMOKCKVRI5GN0LJG7SMD" diff --git a/vendor/github.com/heimweh/go-pagerduty/pagerduty/event_orchestration_path.go b/vendor/github.com/heimweh/go-pagerduty/pagerduty/event_orchestration_path.go index 9760a6702..f4a3b5919 100644 --- a/vendor/github.com/heimweh/go-pagerduty/pagerduty/event_orchestration_path.go +++ b/vendor/github.com/heimweh/go-pagerduty/pagerduty/event_orchestration_path.go @@ -65,6 +65,7 @@ type EventOrchestrationPathRuleActions struct { EventAction string `json:"event_action"` Variables []*EventOrchestrationPathActionVariables `json:"variables"` Extractions []*EventOrchestrationPathActionExtractions `json:"extractions"` + EscalationPolicy *string `json:"escalation_policy"` } type EventOrchestrationPathDynamicRouteTo struct { diff --git a/vendor/modules.txt b/vendor/modules.txt index 2f1765710..8fadd10fa 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -258,7 +258,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-20240503143637-3459408ac715 => github.com/alexzakabluk/go-pagerduty v0.0.0-20240607142119-ac9a64bba6da +# github.com/heimweh/go-pagerduty v0.0.0-20240503143637-3459408ac715 => github.com/alexzakabluk/go-pagerduty v0.0.0-20240712180401-2eb91c030980 ## explicit; go 1.17 github.com/heimweh/go-pagerduty/pagerduty github.com/heimweh/go-pagerduty/persistentconfig @@ -559,4 +559,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/alexzakabluk/go-pagerduty v0.0.0-20240607142119-ac9a64bba6da +# github.com/heimweh/go-pagerduty => github.com/alexzakabluk/go-pagerduty v0.0.0-20240712180401-2eb91c030980 From 208e54de0c4b4e75c9b755f716b51bd43e083498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Antonio=20Reyes?= Date: Fri, 19 Jul 2024 11:15:32 -0400 Subject: [PATCH 6/7] add acc test `EventOrchestrationPathRouterDynamicRouteTo_import` --- ...ty_event_orchestration_path_router_test.go | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/pagerduty/import_pagerduty_event_orchestration_path_router_test.go b/pagerduty/import_pagerduty_event_orchestration_path_router_test.go index 0fa46d893..9c7374ffe 100644 --- a/pagerduty/import_pagerduty_event_orchestration_path_router_test.go +++ b/pagerduty/import_pagerduty_event_orchestration_path_router_test.go @@ -7,6 +7,7 @@ import ( "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/heimweh/go-pagerduty/pagerduty" ) func TestAccPagerDutyEventOrchestrationPathRouter_import(t *testing.T) { @@ -37,6 +38,39 @@ func TestAccPagerDutyEventOrchestrationPathRouter_import(t *testing.T) { }) } +func TestAccPagerDutyEventOrchestrationPathRouterDynamicRouteTo_import(t *testing.T) { + team := fmt.Sprintf("tf-name-%s", acctest.RandString(5)) + escalationPolicy := fmt.Sprintf("tf-%s", acctest.RandString(5)) + service := fmt.Sprintf("tf-%s", acctest.RandString(5)) + orchestration := fmt.Sprintf("tf-orchestration-%s", acctest.RandString(5)) + dynamicRouteToByNameInput := &pagerduty.EventOrchestrationPathDynamicRouteTo{ + LookupBy: "service_name", + Regex: ".*", + Source: "event.custom_details.pd_service_name", + } + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckPagerDutyEventOrchestrationRouterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckPagerDutyEventOrchestrationRouterDynamicRouteToConfig(team, escalationPolicy, service, orchestration, dynamicRouteToByNameInput), + }, + { + ResourceName: "pagerduty_event_orchestration_router.router", + ImportStateIdFunc: testAccCheckPagerDutyEventOrchestrationPathRouterID, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "set.0.rule.0.id", + "set.0.rule.1.id", + }, + }, + }, + }) +} + func testAccCheckPagerDutyEventOrchestrationPathRouterID(s *terraform.State) (string, error) { return s.RootModule().Resources["pagerduty_event_orchestration.orch"].Primary.ID, nil } From 9539e474f1873181b150d7454f0a320ef26ac7f2 Mon Sep 17 00:00:00 2001 From: Ka Ieong Chan Date: Mon, 22 Jul 2024 11:46:42 -0400 Subject: [PATCH 7/7] Point api client to master --- go.mod | 4 +--- go.sum | 4 ++-- vendor/modules.txt | 3 +-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 24a8a2983..75262afcb 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/hashicorp/terraform-plugin-mux v0.13.0 github.com/hashicorp/terraform-plugin-sdk/v2 v2.31.0 github.com/hashicorp/terraform-plugin-testing v1.6.0 - github.com/heimweh/go-pagerduty v0.0.0-20240503143637-3459408ac715 + github.com/heimweh/go-pagerduty v0.0.0-20240722154207-95f2261a009a ) require ( @@ -76,5 +76,3 @@ 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/alexzakabluk/go-pagerduty v0.0.0-20240712180401-2eb91c030980 diff --git a/go.sum b/go.sum index 7dfe0fc04..f4c7be3ec 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,6 @@ github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c h1:kMFnB0vCcX github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= -github.com/alexzakabluk/go-pagerduty v0.0.0-20240712180401-2eb91c030980 h1:ovY3d2mRCubr/5uuk0xcAZq2zJIR7t0kqGc/n/OWOYc= -github.com/alexzakabluk/go-pagerduty v0.0.0-20240712180401-2eb91c030980/go.mod h1:r59w5iyN01Qvi734yA5hZldbSeJJmsJzee/1kQ/MK7s= github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= @@ -97,6 +95,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-20240722154207-95f2261a009a h1:s7Z3DLwXMmfoeLEpgF8tfIxXGs8o734zcEVICTvAkAQ= +github.com/heimweh/go-pagerduty v0.0.0-20240722154207-95f2261a009a/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= diff --git a/vendor/modules.txt b/vendor/modules.txt index 8fadd10fa..be368b146 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -258,7 +258,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-20240503143637-3459408ac715 => github.com/alexzakabluk/go-pagerduty v0.0.0-20240712180401-2eb91c030980 +# github.com/heimweh/go-pagerduty v0.0.0-20240722154207-95f2261a009a ## explicit; go 1.17 github.com/heimweh/go-pagerduty/pagerduty github.com/heimweh/go-pagerduty/persistentconfig @@ -559,4 +559,3 @@ 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/alexzakabluk/go-pagerduty v0.0.0-20240712180401-2eb91c030980