Skip to content

Commit 7802f4c

Browse files
adcoelhotobio
andauthored
Add support for thefrequency field in the Create Rule API (#753)
* Initial commit * make docs-generate * Add Frequency. * changelog * fix test * Updated docs. * Addressing PR comments. * Addressing the final PR comments. * Throttle shouldnt have a version check. --------- Co-authored-by: Toby Brain <[email protected]>
1 parent 27bf677 commit 7802f4c

File tree

7 files changed

+217
-24
lines changed

7 files changed

+217
-24
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
- Fix a provider panic when `elasticstack_kibana_action_connector` reads a non-existant connector ([#729](https://github.com/elastic/terraform-provider-elasticstack/pull/729))
66
- Add support for `remote_indicies` to `elasticstack_elasticsearch_security_role` & `elasticstack_kibana_security_role` (#723)[https://github.com/elastic/terraform-provider-elasticstack/pull/723]
77
- Fix error handling in `elasticstack_kibana_import_saved_objects` ([#738](https://github.com/elastic/terraform-provider-elasticstack/pull/738))
8-
- Remove `space_id` parameter from private locations to fix inconsistent state for `elasticstack_kibana_synthetics_private_location` `space_id` ([#733](https://github.com/elastic/terraform-provider-elasticstack/pull/733))
8+
- Remove `space_id` parameter from private locations to fix inconsistent state for `elasticstack_kibana_synthetics_private_location` `space_id` ([#733](https://github.com/elastic/terraform-provider-elasticstack/pull/733))
9+
- Add the `Frequency` field to the Create Rule API ([#753](https://github.com/elastic/terraform-provider-elasticstack/pull/753))
910
- Prevent a provider panic when the repository referenced in an `elasticstack_elasticsearch_snapshot_repository` does not exist ([#758](https://github.com/elastic/terraform-provider-elasticstack/pull/758))
1011

1112
## [0.11.6] - 2024-08-20

docs/resources/kibana_alerting_rule.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ Could not create API key - Unsupported scheme "ApiKey" for granting API Key
5555
- `consumer` (String) The name of the application or feature that owns the rule.
5656
- `interval` (String) The check interval, which specifies how frequently the rule conditions are checked. The interval must be specified in seconds, minutes, hours or days.
5757
- `name` (String) The name of the rule. While this name does not have to be unique, a distinctive name can help you identify a rule.
58-
- `notify_when` (String) Defines how often alerts generate actions. Valid values include: `onActionGroupChange`: Actions run when the alert status changes; `onActiveAlert`: Actions run when the alert becomes active and at each check interval while the rule conditions are met; `onThrottleInterval`: Actions run when the alert becomes active and at the interval specified in the throttle property while the rule conditions are met. NOTE: This is a rule level property; if you update the rule in Kibana, it is automatically changed to use action-specific `notify_when` values.
5958
- `params` (String) The rule parameters, which differ for each rule type.
6059
- `rule_type_id` (String) The ID of the rule type that you want to call when the rule is scheduled to run. For more information about the valid values, list the rule types using [Get rule types API](https://www.elastic.co/guide/en/kibana/master/list-rule-types-api.html) or refer to the [Rule types documentation](https://www.elastic.co/guide/en/kibana/master/rule-types.html).
6160

@@ -64,10 +63,11 @@ Could not create API key - Unsupported scheme "ApiKey" for granting API Key
6463
- `actions` (Block List) An action that runs under defined conditions. (see [below for nested schema](#nestedblock--actions))
6564
- `alert_delay` (Number) A number that indicates how many consecutive runs need to meet the rule conditions for an alert to occur.
6665
- `enabled` (Boolean) Indicates if you want to run the rule on an interval basis.
66+
- `notify_when` (String) Required until v8.6.0. Deprecated in v8.13.0. Use the `notify_when` property in the action `frequency` object instead. Defines how often alerts generate actions. Valid values include: `onActionGroupChange`: Actions run when the alert status changes; `onActiveAlert`: Actions run when the alert becomes active and at each check interval while the rule conditions are met; `onThrottleInterval`: Actions run when the alert becomes active and at the interval specified in the throttle property while the rule conditions are met. NOTE: This is a rule level property; if you update the rule in Kibana, it is automatically changed to use action-specific `notify_when` values.
6767
- `rule_id` (String) A UUID v1 or v4 to use instead of a randomly generated ID.
6868
- `space_id` (String) An identifier for the space. If space_id is not provided, the default space is used.
6969
- `tags` (List of String) A list of tag names that are applied to the rule.
70-
- `throttle` (String) Defines how often an alert generates repeated actions. This custom action interval must be specified in seconds, minutes, hours, or days. For example, 10m or 1h. This property is applicable only if `notify_when` is `onThrottleInterval`. NOTE: This is a rule level property; if you update the rule in Kibana, it is automatically changed to use action-specific `throttle` values.
70+
- `throttle` (String) Deprecated in 8.13.0. Defines how often an alert generates repeated actions. This custom action interval must be specified in seconds, minutes, hours, or days. For example, 10m or 1h. This property is applicable only if `notify_when` is `onThrottleInterval`. NOTE: This is a rule level property; if you update the rule in Kibana, it is automatically changed to use action-specific `throttle` values.
7171

7272
### Read-Only
7373

@@ -86,8 +86,21 @@ Required:
8686

8787
Optional:
8888

89+
- `frequency` (Block List, Max: 1) The properties that affect how often actions are generated. If the rule type supports setting summary to true, the action can be a summary of alerts at the specified notification interval. Otherwise, an action runs for each alert at the specified notification interval. NOTE: You cannot specify these parameters when `notify_when` or `throttle` are defined at the rule level. (see [below for nested schema](#nestedblock--actions--frequency))
8990
- `group` (String) The group name, which affects when the action runs (for example, when the threshold is met or when the alert is recovered). Each rule type has a list of valid action group names.
9091

92+
<a id="nestedblock--actions--frequency"></a>
93+
### Nested Schema for `actions.frequency`
94+
95+
Required:
96+
97+
- `notify_when` (String) Defines how often alerts generate actions. Valid values include: `onActionGroupChange`: Actions run when the alert status changes; `onActiveAlert`: Actions run when the alert becomes active and at each check interval while the rule conditions are met; `onThrottleInterval`: Actions run when the alert becomes active and at the interval specified in the throttle property while the rule conditions are met. NOTE: This is a rule level property; if you update the rule in Kibana, it is automatically changed to use action-specific `notify_when` values.
98+
- `summary` (Boolean) Indicates whether the action is a summary.
99+
100+
Optional:
101+
102+
- `throttle` (String) Defines how often an alert generates repeated actions. This custom action interval must be specified in seconds, minutes, hours, or days. For example, 10m or 1h. This property is applicable only if `notify_when` is `onThrottleInterval`. NOTE: This is a rule level property; if you update the rule in Kibana, it is automatically changed to use action-specific `throttle` values.
103+
91104
## Import
92105

93106
Import is supported using the following syntax:
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
provider "elasticstack" {
2+
kibana {}
3+
}
4+
5+
resource "elasticstack_kibana_alerting_rule" "example_with_action_frequency" {
6+
name = "%s"
7+
consumer = "alerts"
8+
params = jsonencode({
9+
aggType = "avg"
10+
groupBy = "top"
11+
termSize = 10
12+
timeWindowSize = 10
13+
timeWindowUnit = "s"
14+
threshold = [10]
15+
thresholdComparator = ">"
16+
index = ["test-index"]
17+
timeField = "@timestamp"
18+
aggField = "version"
19+
termField = "name"
20+
})
21+
rule_type_id = ".index-threshold"
22+
interval = "1m"
23+
enabled = true
24+
25+
actions {
26+
# Should be the id of a MS Teams connector
27+
id = elasticstack_kibana_action_connector.index_example.connector_id
28+
group = "threshold met"
29+
params = jsonencode({
30+
"message" : "foobar"
31+
})
32+
33+
frequency {
34+
summary = false
35+
notify_when = "onActionGroupChange"
36+
}
37+
}
38+
}

internal/clients/kibana/alerting.go

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,24 @@ func ruleResponseToModel(spaceID string, res *alerting.RuleResponseProperties) *
2020

2121
actions := []models.AlertingRuleAction{}
2222
for _, action := range res.Actions {
23-
actions = append(actions, models.AlertingRuleAction{
23+
24+
a := models.AlertingRuleAction{
2425
Group: action.Group,
2526
ID: action.Id,
2627
Params: action.Params,
27-
})
28+
}
29+
30+
if !alerting.IsNil(action.Frequency) {
31+
frequency := unwrapOptionalField(action.Frequency)
32+
33+
a.Frequency = &models.AlertingRuleActionFrequency{
34+
Summary: frequency.Summary,
35+
NotifyWhen: (string)(frequency.NotifyWhen),
36+
Throttle: frequency.Throttle.Get(),
37+
}
38+
}
39+
40+
actions = append(actions, a)
2841
}
2942

3043
var alertDelay *float32
@@ -68,11 +81,26 @@ func ruleActionsToActionsInner(ruleActions []models.AlertingRuleAction) []alerti
6881
actions := []alerting.ActionsInner{}
6982
for index := range ruleActions {
7083
action := ruleActions[index]
71-
actions = append(actions, alerting.ActionsInner{
84+
actionToAppend := alerting.ActionsInner{
7285
Group: action.Group,
7386
Id: action.ID,
7487
Params: action.Params,
75-
})
88+
}
89+
90+
if !alerting.IsNil(action.Frequency) {
91+
frequency := alerting.ActionsInnerFrequency{
92+
Summary: action.Frequency.Summary,
93+
NotifyWhen: (alerting.NotifyWhen)(action.Frequency.NotifyWhen),
94+
}
95+
96+
if action.Frequency.Throttle != nil {
97+
frequency.Throttle = *alerting.NewNullableString(action.Frequency.Throttle)
98+
}
99+
100+
actionToAppend.Frequency = &frequency
101+
}
102+
103+
actions = append(actions, actionToAppend)
76104
}
77105
return actions
78106
}

internal/clients/kibana/alerting_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,25 @@ func Test_ruleResponseToModel(t *testing.T) {
7171
Group: "group-1",
7272
Id: "id",
7373
Params: map[string]interface{}{},
74+
Frequency: makePtr(alerting.ActionsInnerFrequency{
75+
Summary: true,
76+
NotifyWhen: "onThrottleInterval",
77+
Throttle: *alerting.NewNullableString(makePtr("10s")),
78+
}),
7479
},
7580
{
7681
Group: "group-2",
7782
Id: "id",
7883
Params: map[string]interface{}{},
84+
Frequency: makePtr(alerting.ActionsInnerFrequency{
85+
Summary: true,
86+
NotifyWhen: "onActionGroupChange",
87+
}),
88+
},
89+
{
90+
Group: "group-3",
91+
Id: "id",
92+
Params: map[string]interface{}{},
7993
},
8094
},
8195
ExecutionStatus: alerting.RuleResponsePropertiesExecutionStatus{
@@ -113,11 +127,25 @@ func Test_ruleResponseToModel(t *testing.T) {
113127
Group: "group-1",
114128
ID: "id",
115129
Params: map[string]interface{}{},
130+
Frequency: &models.AlertingRuleActionFrequency{
131+
Summary: true,
132+
NotifyWhen: "onThrottleInterval",
133+
Throttle: makePtr("10s"),
134+
},
116135
},
117136
{
118137
Group: "group-2",
119138
ID: "id",
120139
Params: map[string]interface{}{},
140+
Frequency: &models.AlertingRuleActionFrequency{
141+
Summary: true,
142+
NotifyWhen: "onActionGroupChange",
143+
},
144+
},
145+
{
146+
Group: "group-3",
147+
ID: "id",
148+
Params: map[string]interface{}{},
121149
},
122150
},
123151
AlertDelay: makePtr(float32(4)),

internal/kibana/alerting.go

Lines changed: 89 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package kibana
33
import (
44
"context"
55
"encoding/json"
6+
"fmt"
67
"strings"
78

89
"github.com/elastic/terraform-provider-elasticstack/internal/clients"
@@ -17,6 +18,9 @@ import (
1718

1819
var alertDelayMinSupportedVersion = version.Must(version.NewVersion("8.13.0"))
1920

21+
// when notify_when and throttle became optional
22+
var frequencyMinSupportedVersion = version.Must(version.NewVersion("8.6.0"))
23+
2024
func ResourceAlertingRule() *schema.Resource {
2125
apikeySchema := map[string]*schema.Schema{
2226
"rule_id": {
@@ -45,9 +49,9 @@ func ResourceAlertingRule() *schema.Resource {
4549
ForceNew: true,
4650
},
4751
"notify_when": {
48-
Description: "Defines how often alerts generate actions. Valid values include: `onActionGroupChange`: Actions run when the alert status changes; `onActiveAlert`: Actions run when the alert becomes active and at each check interval while the rule conditions are met; `onThrottleInterval`: Actions run when the alert becomes active and at the interval specified in the throttle property while the rule conditions are met. NOTE: This is a rule level property; if you update the rule in Kibana, it is automatically changed to use action-specific `notify_when` values.",
52+
Description: "Required until v8.6.0. Deprecated in v8.13.0. Use the `notify_when` property in the action `frequency` object instead. Defines how often alerts generate actions. Valid values include: `onActionGroupChange`: Actions run when the alert status changes; `onActiveAlert`: Actions run when the alert becomes active and at each check interval while the rule conditions are met; `onThrottleInterval`: Actions run when the alert becomes active and at the interval specified in the throttle property while the rule conditions are met. NOTE: This is a rule level property; if you update the rule in Kibana, it is automatically changed to use action-specific `notify_when` values.",
4953
Type: schema.TypeString,
50-
Required: true,
54+
Optional: true,
5155
ValidateFunc: validation.StringInSlice([]string{"onActionGroupChange", "onActiveAlert", "onThrottleInterval"}, false),
5256
},
5357
"params": {
@@ -93,6 +97,34 @@ func ResourceAlertingRule() *schema.Resource {
9397
ValidateFunc: validation.StringIsJSON,
9498
DiffSuppressFunc: utils.DiffJsonSuppress,
9599
},
100+
"frequency": {
101+
Description: "The properties that affect how often actions are generated. If the rule type supports setting summary to true, the action can be a summary of alerts at the specified notification interval. Otherwise, an action runs for each alert at the specified notification interval. NOTE: You cannot specify these parameters when `notify_when` or `throttle` are defined at the rule level.",
102+
Type: schema.TypeList,
103+
MinItems: 0,
104+
MaxItems: 1,
105+
Optional: true,
106+
Elem: &schema.Resource{
107+
Schema: map[string]*schema.Schema{
108+
"summary": {
109+
Description: "Indicates whether the action is a summary.",
110+
Type: schema.TypeBool,
111+
Required: true,
112+
},
113+
"notify_when": {
114+
Description: "Defines how often alerts generate actions. Valid values include: `onActionGroupChange`: Actions run when the alert status changes; `onActiveAlert`: Actions run when the alert becomes active and at each check interval while the rule conditions are met; `onThrottleInterval`: Actions run when the alert becomes active and at the interval specified in the throttle property while the rule conditions are met. NOTE: This is a rule level property; if you update the rule in Kibana, it is automatically changed to use action-specific `notify_when` values.",
115+
Type: schema.TypeString,
116+
Required: true,
117+
ValidateFunc: validation.StringInSlice([]string{"onActionGroupChange", "onActiveAlert", "onThrottleInterval"}, false),
118+
},
119+
"throttle": {
120+
Description: "Defines how often an alert generates repeated actions. This custom action interval must be specified in seconds, minutes, hours, or days. For example, 10m or 1h. This property is applicable only if `notify_when` is `onThrottleInterval`. NOTE: This is a rule level property; if you update the rule in Kibana, it is automatically changed to use action-specific `throttle` values.",
121+
Type: schema.TypeString,
122+
Optional: true,
123+
ValidateFunc: utils.StringIsDuration,
124+
},
125+
},
126+
},
127+
},
96128
},
97129
},
98130
},
@@ -110,12 +142,11 @@ func ResourceAlertingRule() *schema.Resource {
110142
},
111143
},
112144
"throttle": {
113-
Description: "Defines how often an alert generates repeated actions. This custom action interval must be specified in seconds, minutes, hours, or days. For example, 10m or 1h. This property is applicable only if `notify_when` is `onThrottleInterval`. NOTE: This is a rule level property; if you update the rule in Kibana, it is automatically changed to use action-specific `throttle` values.",
145+
Description: "Deprecated in 8.13.0. Defines how often an alert generates repeated actions. This custom action interval must be specified in seconds, minutes, hours, or days. For example, 10m or 1h. This property is applicable only if `notify_when` is `onThrottleInterval`. NOTE: This is a rule level property; if you update the rule in Kibana, it is automatically changed to use action-specific `throttle` values.",
114146
Type: schema.TypeString,
115147
Optional: true,
116148
ValidateFunc: utils.StringIsDuration,
117149
},
118-
119150
"scheduled_task_id": {
120151
Description: "ID of the scheduled task that will execute the alert.",
121152
Type: schema.TypeString,
@@ -190,6 +221,16 @@ func getAlertingRuleFromResourceData(d *schema.ResourceData, serverVersion *vers
190221

191222
if v, ok := d.GetOk("notify_when"); ok {
192223
rule.NotifyWhen = utils.Pointer(v.(string))
224+
} else {
225+
if serverVersion.LessThan(frequencyMinSupportedVersion) {
226+
return models.AlertingRule{}, diag.Diagnostics{
227+
diag.Diagnostic{
228+
Severity: diag.Error,
229+
Summary: "notify_when is required until v8.6",
230+
Detail: "notify_when is required until v8.6",
231+
},
232+
}
233+
}
193234
}
194235

195236
if v, ok := d.GetOk("alert_delay"); ok {
@@ -201,13 +242,12 @@ func getAlertingRuleFromResourceData(d *schema.ResourceData, serverVersion *vers
201242
Detail: "alert_delay is only supported for Elasticsearch v8.13 or higher",
202243
},
203244
}
204-
205245
}
206246

207247
rule.AlertDelay = utils.Pointer(float32(v.(float64)))
208248
}
209249

210-
actions, diags := getActionsFromResourceData(d)
250+
actions, diags := getActionsFromResourceData(d, serverVersion)
211251
if diags.HasError() {
212252
return models.AlertingRule{}, diags
213253
}
@@ -222,11 +262,11 @@ func getAlertingRuleFromResourceData(d *schema.ResourceData, serverVersion *vers
222262
return rule, diags
223263
}
224264

225-
func getActionsFromResourceData(d *schema.ResourceData) ([]models.AlertingRuleAction, diag.Diagnostics) {
265+
func getActionsFromResourceData(d *schema.ResourceData, serverVersion *version.Version) ([]models.AlertingRuleAction, diag.Diagnostics) {
226266
actions := []models.AlertingRuleAction{}
227267
if v, ok := d.GetOk("actions"); ok {
228268
resourceActions := v.([]interface{})
229-
for _, a := range resourceActions {
269+
for i, a := range resourceActions {
230270
action := a.(map[string]interface{})
231271
paramsStr := action["params"].(string)
232272
var params map[string]interface{}
@@ -235,11 +275,32 @@ func getActionsFromResourceData(d *schema.ResourceData) ([]models.AlertingRuleAc
235275
return []models.AlertingRuleAction{}, diag.FromErr(err)
236276
}
237277

238-
actions = append(actions, models.AlertingRuleAction{
278+
a := models.AlertingRuleAction{
239279
Group: action["group"].(string),
240280
ID: action["id"].(string),
241281
Params: params,
242-
})
282+
}
283+
284+
currentAction := fmt.Sprintf("actions.%d", i)
285+
286+
if _, ok := d.GetOk(currentAction + ".frequency"); ok {
287+
if serverVersion.LessThan(frequencyMinSupportedVersion) {
288+
return []models.AlertingRuleAction{}, diag.Errorf("actions.frequency is only supported for Elasticsearch v8.6 or higher")
289+
}
290+
291+
frequency := models.AlertingRuleActionFrequency{
292+
Summary: d.Get(currentAction + ".frequency.0.summary").(bool),
293+
NotifyWhen: d.Get(currentAction + ".frequency.0.notify_when").(string),
294+
}
295+
296+
if throttle := getOrNilString(currentAction+".frequency.0.throttle", d); throttle != nil && *throttle != "" {
297+
frequency.Throttle = throttle
298+
}
299+
300+
a.Frequency = &frequency
301+
}
302+
303+
actions = append(actions, a)
243304
}
244305
}
245306

@@ -380,12 +441,27 @@ func resourceRuleRead(ctx context.Context, d *schema.ResourceData, meta interfac
380441
if err != nil {
381442
return diag.FromErr(err)
382443
}
444+
445+
frequency := []interface{}{}
446+
447+
if action.Frequency != nil {
448+
frequency = append(frequency, map[string]interface{}{
449+
"summary": action.Frequency.Summary,
450+
"notify_when": action.Frequency.NotifyWhen,
451+
"throttle": action.Frequency.Throttle,
452+
})
453+
} else {
454+
frequency = nil
455+
}
456+
383457
actions = append(actions, map[string]interface{}{
384-
"group": action.Group,
385-
"id": action.ID,
386-
"params": string(params),
458+
"group": action.Group,
459+
"id": action.ID,
460+
"params": string(params),
461+
"frequency": frequency,
387462
})
388463
}
464+
389465
if err := d.Set("actions", actions); err != nil {
390466
return diag.FromErr(err)
391467
}

0 commit comments

Comments
 (0)