Skip to content

Commit

Permalink
feat(alerts): Expose PagerDuty autoresolve
Browse files Browse the repository at this point in the history
Adding the autoresolve setting to pagerduty channel
for alerts and views.

ref: LOG-14904
  • Loading branch information
gjanco committed Nov 29, 2023
1 parent a19164b commit 3ce7609
Show file tree
Hide file tree
Showing 11 changed files with 183 additions and 50 deletions.
16 changes: 11 additions & 5 deletions docs/resources/logdna_alert.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,14 @@ resource "logdna_alert" "my_alert" {
}
pagerduty_channel {
immediate = "true"
key = "Your PagerDuty API key goes here"
terminal = "true"
triggerinterval = "15m"
triggerlimit = 15
immediate = "true"
key = "Your PagerDuty API key goes here"
terminal = "true"
triggerinterval = "15m"
triggerlimit = 15
autoresolve = true
autoresolvelimit = 10
autoresolveinterval = "15m"
}
slack_channel {
Expand Down Expand Up @@ -135,6 +138,9 @@ The following arguments are supported by `logdna_alert`:
- `terminal`: **_string_** _(Optional; Default: `"true"`)_ Whether the Alert will trigger after the `triggerinterval` if the Alert condition is met (e.g., send an Alert after 30s). Valid options are `"true"` and `"false"` for presence Alerts and `"true"` for absence Alerts.
- `triggerinterval`: **_string_** _(Optional; Defaults: `"30"` for presence; `"15m"` for absence)_ Interval which the Alert will be looking for presence or absence of log lines. For presence Alerts, valid options are: `30`, `1m`, `5m`, `15m`, `30m`, `1h`, `6h`, `12h`, and `24h`. For absence Alerts, valid options are: `15m`, `30m`, `1h`, `6h`, `12h`, and `24h`.
- `triggerlimit`: **_integer (Required)_** Number of lines before the Alert is triggered (e.g. setting a value of `10` for an `absence` Alert would alert you if `10` lines were not seen in the `triggerinterval`).
- `autoresolve`: **_boolean_** Set to true if you want the set a condition to resolve the incident that was raised by this alert.
- `autoresolveinterval`: **_string_** _(Required if autoresolve is set to true)_ Interval of time to aggregate and check # of matched lines against the auto resolve limit. For absence Alerts, valid options are: `30`, `1m`, `5m`, `15m`, `30m`, `1h`, `6h`, `12h`, and `24h`. For presence Alerts, valid options are: `15m`, `30m`, `1h`, `6h`, `12h`, and `24h`.
- `autoresolvelimit`: **_integer_** _(Required if autoresolve is set to true)_ Specify the number of log lines that match the view's filtering and search criteria. When the number of log lines is reached, this incident will be set to resolved in PagerDuty.

### slack_channel

Expand Down
3 changes: 3 additions & 0 deletions docs/resources/logdna_view.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ _Note:_ Any of `*_channel` parameters are not allowed if a `presetid` parameter
- `terminal`: **_string_** _(Optional; Default: `"true"`)_ Whether the Alert will trigger after the `triggerinterval` if the Alert condition is met (e.g. send an Alert after 30s). Valid options are `"true"` and `"false"` for presence Alerts, and `"true"` for absence Alerts.
- `triggerinterval`: **_string_** _(Optional; Defaults: `"30"` for presence; `"15m"` for absence)_ Interval which the Alert will be looking for presence or absence of log lines. For presence Alerts, valid options are: `30`, `1m`, `5m`, `15m`, `30m`, `1h`, `6h`, `12h`, and `24h`. For absence Alerts, valid options are: `15m`, `30m`, `1h`, `6h`, `12h`, and `24h`.
- `triggerlimit`: **_integer (Required)_** Number of lines before the Alert is triggered (e.g. setting a value of `10` for an `absence` Alert would alert you if `10` lines were not seen in the `triggerinterval`).
- `autoresolve`: **_boolean_** Set to true if you want the set a condition to resolve the incident that was raised by this alert.
- `autoresolveinterval`: **_string_** _(Required if autoresolve is set to true)_ Interval of time to aggregate and check # of matched lines against the auto resolve limit. Valid values are: 30 seconds, 1 minute, 5 minutes, 15 minutes, 30 minutes, 1 hour, 6 hours, 12 hours, 24 hours.
- `autoresolvelimit`: **_integer_** _(Required if autoresolve is set to true)_ Specify the number of log lines that match the view's filtering and search criteria. When the number of log lines is reached, this incident will be set to resolved in PagerDuty.

### webhook_channel

Expand Down
11 changes: 11 additions & 0 deletions logdna/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,17 @@ var chnlDefaults = map[string]map[string]string{
"triggerlimit": `15`,
"url": `"https://yourwebhook/endpoint"`,
},
"pagerduty_channel_auto": {
"immediate": `"false"`,
"operator": `"presence"`,
"key": `"Your PagerDuty API key goes here"`,
"terminal": `"true"`,
"triggerinterval": `"15m"`,
"triggerlimit": `15`,
"autoresolve": `"true"`,
"autoresolvelimit": `"10"`,
"autoresolveinterval": `"15m"`,
},
}

func cloneDefaults(dfts map[string]string) map[string]string {
Expand Down
7 changes: 7 additions & 0 deletions logdna/data_source_alert.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ var strSchema = &schema.Schema{
Type: schema.TypeString,
Computed: true,
}
var boolSchema = &schema.Schema{
Type: schema.TypeBool,
Computed: true,
}
var alertProps = map[string]*schema.Schema{
"immediate": strSchema,
"operator": strSchema,
Expand Down Expand Up @@ -142,6 +146,9 @@ func getAlertSchema(chnl string) map[string]*schema.Schema {
schma["url"] = strSchema
case "pagerduty":
schma["key"] = strSchema
schma["autoresolve"] = boolSchema
schma["autoresolvelimit"] = intSchema
schma["autoresolveinterval"] = strSchema
case "webhook":
schma["bodytemplate"] = strSchema
schma["method"] = strSchema
Expand Down
11 changes: 7 additions & 4 deletions logdna/data_source_alert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func TestDataAlert_BulkChannels(t *testing.T) {

pdArgs := map[string]map[string]string{
"pagerduty_channel": cloneDefaults(chnlDefaults["pagerduty_channel"]),
"pagerduty1_channel": cloneDefaults(chnlDefaults["pagerduty_channel"]),
"pagerduty1_channel": cloneDefaults(chnlDefaults["pagerduty_channel_auto"]),
}
pdsCfg := fmtTestConfigResource("alert", "test", globalPcArgs, alertDefaults, pdArgs, nilLst)

Expand Down Expand Up @@ -60,8 +60,11 @@ func TestDataAlert_BulkChannels(t *testing.T) {
testDataSourceAlertExists("data.logdna_alert.remote"),
resource.TestCheckResourceAttr("data.logdna_alert.remote", "name", "test"),
resource.TestCheckResourceAttr("data.logdna_alert.remote", "pagerduty_channel.#", "2"),
resource.TestCheckResourceAttr("data.logdna_alert.remote", "pagerduty_channel.0.%", "6"),
resource.TestCheckResourceAttr("data.logdna_alert.remote", "pagerduty_channel.1.%", "6"),
resource.TestCheckResourceAttr("data.logdna_alert.remote", "pagerduty_channel.0.%", "9"),
resource.TestCheckResourceAttr("data.logdna_alert.remote", "pagerduty_channel.1.%", "9"),
resource.TestCheckResourceAttr("data.logdna_alert.remote", "pagerduty_channel.1.autoresolve", "true"),
resource.TestCheckResourceAttr("data.logdna_alert.remote", "pagerduty_channel.1.autoresolvelimit", "10"),
resource.TestCheckResourceAttr("data.logdna_alert.remote", "pagerduty_channel.1.autoresolveinterval", "15m"),
resource.TestCheckResourceAttr("data.logdna_alert.remote", "email_channel.#", "0"),
resource.TestCheckResourceAttr("data.logdna_alert.remote", "slack_channel.#", "0"),
resource.TestCheckResourceAttr("data.logdna_alert.remote", "webhook_channel.#", "0"),
Expand Down Expand Up @@ -124,7 +127,7 @@ func TestDataSourceAlert_MultipleChannels(t *testing.T) {
resource.TestCheckResourceAttr("data.logdna_alert.remote", "email_channel.0.triggerinterval", "15m"),
resource.TestCheckResourceAttr("data.logdna_alert.remote", "email_channel.0.triggerlimit", "15"),
resource.TestCheckResourceAttr("data.logdna_alert.remote", "pagerduty_channel.#", "1"),
resource.TestCheckResourceAttr("data.logdna_alert.remote", "pagerduty_channel.0.%", "6"),
resource.TestCheckResourceAttr("data.logdna_alert.remote", "pagerduty_channel.0.%", "9"),
resource.TestCheckResourceAttr("data.logdna_alert.remote", "pagerduty_channel.0.immediate", "false"),
resource.TestCheckResourceAttr("data.logdna_alert.remote", "pagerduty_channel.0.key", "Your PagerDuty API key goes here"),
resource.TestCheckResourceAttr("data.logdna_alert.remote", "pagerduty_channel.0.operator", "presence"),
Expand Down
46 changes: 26 additions & 20 deletions logdna/request_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,22 @@ type alertRequest struct {
}

type channelRequest struct {
BodyTemplate map[string]interface{} `json:"bodyTemplate,omitempty"`
Emails []string `json:"emails,omitempty"`
Headers map[string]string `json:"headers,omitempty"`
Immediate string `json:"immediate,omitempty"`
Integration string `json:"integration,omitempty"`
Key string `json:"key,omitempty"`
Method string `json:"method,omitempty"`
Operator string `json:"operator,omitempty"`
Terminal string `json:"terminal,omitempty"`
TriggerInterval string `json:"triggerinterval,omitempty"`
TriggerLimit int `json:"triggerlimit,omitempty"`
Timezone string `json:"timezone,omitempty"`
URL string `json:"url,omitempty"`
BodyTemplate map[string]interface{} `json:"bodyTemplate,omitempty"`
Emails []string `json:"emails,omitempty"`
Headers map[string]string `json:"headers,omitempty"`
Immediate string `json:"immediate,omitempty"`
Integration string `json:"integration,omitempty"`
Key string `json:"key,omitempty"`
Method string `json:"method,omitempty"`
Operator string `json:"operator,omitempty"`
Terminal string `json:"terminal,omitempty"`
TriggerInterval string `json:"triggerinterval,omitempty"`
TriggerLimit int `json:"triggerlimit,omitempty"`
AutoResolve bool `json:"autoresolve,omitempty"`
AutoResolveInterval string `json:"autoresolveinterval,omitempty"`
AutoResolveLimit int `json:"autoresolvelimit,omitempty"`
Timezone string `json:"timezone,omitempty"`
URL string `json:"url,omitempty"`
}

type categoryRequest struct {
Expand Down Expand Up @@ -359,13 +362,16 @@ func emailChannelRequest(s map[string]interface{}) channelRequest {

func pagerDutyChannelRequest(s map[string]interface{}) channelRequest {
c := channelRequest{
Immediate: s["immediate"].(string),
Integration: PAGERDUTY,
Key: s["key"].(string),
Operator: s["operator"].(string),
Terminal: s["terminal"].(string),
TriggerInterval: s["triggerinterval"].(string),
TriggerLimit: s["triggerlimit"].(int),
Immediate: s["immediate"].(string),
Integration: PAGERDUTY,
Key: s["key"].(string),
Operator: s["operator"].(string),
Terminal: s["terminal"].(string),
TriggerInterval: s["triggerinterval"].(string),
TriggerLimit: s["triggerlimit"].(int),
AutoResolve: s["autoresolve"].(bool),
AutoResolveInterval: s["autoresolveinterval"].(string),
AutoResolveLimit: s["autoresolvelimit"].(int),
}

return c
Expand Down
19 changes: 19 additions & 0 deletions logdna/resource_alert.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,25 @@ func resourceAlert() *schema.Resource {
return
},
},
"autoresolve": {
Type: schema.TypeBool,
Optional: true,
},
"autoresolveinterval": {
Type: schema.TypeString,
Optional: true,
},
"autoresolvelimit": {
Type: schema.TypeInt,
Optional: true,
ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) {
v := val.(int)
if v < 1 || v > 100000 {
errs = append(errs, fmt.Errorf("%q must be between 1 and 100,000 inclusive, got: %d", key, v))
}
return
},
},
},
},
},
Expand Down
56 changes: 53 additions & 3 deletions logdna/resource_alert_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,55 @@ func TestAlert_ErrorsPagerDutyChannel(t *testing.T) {
})
}

func TestAlert_PagerDutyAutoResolve(t *testing.T) {
chArgs := map[string]map[string]string{"pagerduty_channel": cloneDefaults(chnlDefaults["pagerduty_channel_auto"])}

iniCfg := fmtTestConfigResource("alert", "new", globalPcArgs, alertDefaults, chArgs, nilLst)

rsArgs := cloneDefaults(rsDefaults["alert"])
rsArgs["name"] = `"test2"`
updCfg := fmtTestConfigResource("alert", "new", globalPcArgs, rsArgs, chArgs, nilLst)

resource.Test(t, resource.TestCase{
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: iniCfg,
Check: resource.ComposeTestCheckFunc(
testResourceExists("alert", "new"),
resource.TestCheckResourceAttr("logdna_alert.new", "name", "test"),
resource.TestCheckResourceAttr("logdna_alert.new", "email_channel.#", "0"),
resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.#", "1"),
resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.0.%", "9"),
resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.0.immediate", "false"),
resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.0.key", "Your PagerDuty API key goes here"),
resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.0.operator", "presence"),
resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.0.terminal", "true"),
resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.0.triggerinterval", "15m"),
resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.0.triggerlimit", "15"),
resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.0.autoresolve", "true"),
resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.0.autoresolvelimit", "10"),
resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.0.autoresolveinterval", "15m"),
resource.TestCheckResourceAttr("logdna_alert.new", "slack_channel.#", "0"),
resource.TestCheckResourceAttr("logdna_alert.new", "webhook_channel.#", "0"),
),
},
{
Config: updCfg,
Check: resource.ComposeTestCheckFunc(
testResourceExists("alert", "new"),
resource.TestCheckResourceAttr("logdna_alert.new", "name", "test2"),
),
},
{
ResourceName: "logdna_alert.new",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAlert_ErrorsSlackChannel(t *testing.T) {
ulInvd := map[string]map[string]string{"slack_channel": cloneDefaults(chnlDefaults["slack_channel"])}
ulInvd["slack_channel"]["url"] = `"this is not a valid url"`
Expand Down Expand Up @@ -283,8 +332,8 @@ func TestAlert_BulkChannels(t *testing.T) {
testResourceExists("alert", "new"),
resource.TestCheckResourceAttr("logdna_alert.new", "name", "test"),
resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.#", "2"),
resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.0.%", "6"),
resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.1.%", "6"),
resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.0.%", "9"),
resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.1.%", "9"),
resource.TestCheckResourceAttr("logdna_alert.new", "email_channel.#", "0"),
resource.TestCheckResourceAttr("logdna_alert.new", "slack_channel.#", "0"),
resource.TestCheckResourceAttr("logdna_alert.new", "webhook_channel.#", "0"),
Expand Down Expand Up @@ -346,8 +395,9 @@ func TestAlert_MultipleChannels(t *testing.T) {
resource.TestCheckResourceAttr("logdna_alert.new", "email_channel.0.triggerinterval", "15m"),
resource.TestCheckResourceAttr("logdna_alert.new", "email_channel.0.triggerlimit", "15"),
resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.#", "1"),
resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.0.%", "6"),
resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.0.%", "9"),
resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.0.immediate", "false"),
resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.0.autoresolve", "false"),
resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.0.key", "Your PagerDuty API key goes here"),
resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.0.operator", "presence"),
resource.TestCheckResourceAttr("logdna_alert.new", "pagerduty_channel.0.terminal", "true"),
Expand Down
19 changes: 19 additions & 0 deletions logdna/resource_view.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,25 @@ func resourceView() *schema.Resource {
return
},
},
"autoresolve": {
Type: schema.TypeBool,
Optional: true,
},
"autoresolveinterval": {
Type: schema.TypeString,
Optional: true,
},
"autoresolvelimit": {
Type: schema.TypeInt,
Optional: true,
ValidateFunc: func(val interface{}, key string) (warns []string, errs []error) {
v := val.(int)
if v < 1 || v > 100000 {
errs = append(errs, fmt.Errorf("%q must be between 1 and 100,000 inclusive, got: %d", key, v))
}
return
},
},
},
},
},
Expand Down
11 changes: 7 additions & 4 deletions logdna/resource_view_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,8 +326,8 @@ func TestView_BulkChannels(t *testing.T) {
resource.TestCheckResourceAttr("logdna_view.new", "name", "test"),
resource.TestCheckResourceAttr("logdna_view.new", "query", "test"),
resource.TestCheckResourceAttr("logdna_view.new", "pagerduty_channel.#", "2"),
resource.TestCheckResourceAttr("logdna_view.new", "pagerduty_channel.0.%", "6"),
resource.TestCheckResourceAttr("logdna_view.new", "pagerduty_channel.1.%", "6"),
resource.TestCheckResourceAttr("logdna_view.new", "pagerduty_channel.0.%", "9"),
resource.TestCheckResourceAttr("logdna_view.new", "pagerduty_channel.1.%", "9"),
resource.TestCheckResourceAttr("logdna_view.new", "email_channel.#", "0"),
resource.TestCheckResourceAttr("logdna_view.new", "slack_channel.#", "0"),
resource.TestCheckResourceAttr("logdna_view.new", "webhook_channel.#", "0"),
Expand Down Expand Up @@ -368,7 +368,7 @@ func TestView_BulkChannels(t *testing.T) {
func TestView_MultipleChannels(t *testing.T) {
chArgs := map[string]map[string]string{
"email_channel": cloneDefaults(chnlDefaults["email_channel"]),
"pagerduty_channel": cloneDefaults(chnlDefaults["pagerduty_channel"]),
"pagerduty_channel": cloneDefaults(chnlDefaults["pagerduty_channel_auto"]),
"slack_channel": cloneDefaults(chnlDefaults["slack_channel"]),
"webhook_channel": cloneDefaults(chnlDefaults["webhook_channel"]),
}
Expand Down Expand Up @@ -446,13 +446,16 @@ func TestView_MultipleChannels(t *testing.T) {
resource.TestCheckResourceAttr("logdna_view.new", "email_channel.0.triggerinterval", "15m"),
resource.TestCheckResourceAttr("logdna_view.new", "email_channel.0.triggerlimit", "15"),
resource.TestCheckResourceAttr("logdna_view.new", "pagerduty_channel.#", "1"),
resource.TestCheckResourceAttr("logdna_view.new", "pagerduty_channel.0.%", "6"),
resource.TestCheckResourceAttr("logdna_view.new", "pagerduty_channel.0.%", "9"),
resource.TestCheckResourceAttr("logdna_view.new", "pagerduty_channel.0.immediate", "false"),
resource.TestCheckResourceAttr("logdna_view.new", "pagerduty_channel.0.key", "Your PagerDuty API key goes here"),
resource.TestCheckResourceAttr("logdna_view.new", "pagerduty_channel.0.operator", "presence"),
resource.TestCheckResourceAttr("logdna_view.new", "pagerduty_channel.0.terminal", "true"),
resource.TestCheckResourceAttr("logdna_view.new", "pagerduty_channel.0.triggerinterval", "15m"),
resource.TestCheckResourceAttr("logdna_view.new", "pagerduty_channel.0.triggerlimit", "15"),
resource.TestCheckResourceAttr("logdna_view.new", "pagerduty_channel.0.autoresolve", "true"),
resource.TestCheckResourceAttr("logdna_view.new", "pagerduty_channel.0.autoresolvelimit", "10"),
resource.TestCheckResourceAttr("logdna_view.new", "pagerduty_channel.0.autoresolveinterval", "15m"),
resource.TestCheckResourceAttr("logdna_view.new", "slack_channel.#", "1"),
resource.TestCheckResourceAttr("logdna_view.new", "slack_channel.0.%", "6"),
resource.TestCheckResourceAttr("logdna_view.new", "slack_channel.0.immediate", "false"),
Expand Down
Loading

0 comments on commit 3ce7609

Please sign in to comment.