-
Notifications
You must be signed in to change notification settings - Fork 210
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
Event Orchestration: add support for Dynamic Routing and Dynamic Escalation Policy Assignment #885
Changes from all commits
0c0450b
71f2a22
00b4f2a
6e29bb4
c68d79a
208e54d
9539e47
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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, | ||
|
@@ -63,9 +65,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" { | ||
|
@@ -113,6 +135,54 @@ func resourcePagerDutyEventOrchestrationPathRouter() *schema.Resource { | |
} | ||
} | ||
|
||
func checkDynamicRoutingRule(context context.Context, diff *schema.ResourceDiff, i interface{}) error { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Annotation: This function performs the following checks and returns a plan error if any of the checks are violated:
|
||
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 | ||
|
||
|
@@ -294,7 +364,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 isNonEmptyList(dra) { | ||
actions.DynamicRouteTo = expandRouterDynamicRouteToAction(dra) | ||
} else { | ||
actions.RouteTo = am["route_to"].(string) | ||
} | ||
Comment on lines
+367
to
+372
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Annotation: Because |
||
} | ||
|
||
return actions | ||
|
@@ -311,6 +386,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 +430,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 +450,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 { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Annotation: The
EscalationPolicy
property is a string pointer (*string
) and not a string because we need to be able to sendnull
to the API in order to reset the action.