Skip to content

Commit 1cc0cfa

Browse files
authored
allow action parameters to be specified as JSON (#335)
* allow action parameters to be specified as JSON * add test * fix change on each run * add notify_when to action test * change test indent * fix test for es < 7.11.0
1 parent a0a5055 commit 1cc0cfa

File tree

2 files changed

+134
-14
lines changed

2 files changed

+134
-14
lines changed

es/resource_elasticsearch_kibana_alert.go

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
"github.com/hashicorp/go-version"
1010
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
11+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure"
1112
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
1213
"github.com/olivere/elastic/uritemplates"
1314

@@ -152,7 +153,7 @@ func resourceElasticsearchKibanaAlert() *schema.Resource {
152153
DiffSuppressFunc: suppressEquivalentJson,
153154
},
154155
"actions": {
155-
Type: schema.TypeSet,
156+
Type: schema.TypeList,
156157
Optional: true,
157158
Description: "Actions are invocations of Kibana services or integrations with third-party systems, that run as background tasks on the Kibana server when alert conditions are met.",
158159
Elem: &schema.Resource{
@@ -178,6 +179,22 @@ func resourceElasticsearchKibanaAlert() *schema.Resource {
178179
Optional: true,
179180
Description: "Key value pairs passed to the action executor, e.g. a Mustache formatted `message`.",
180181
},
182+
"params_json": {
183+
Type: schema.TypeString,
184+
Optional: true,
185+
Default: "",
186+
ValidateFunc: validation.StringIsJSON,
187+
Description: "JSON body of actions `params`. Either `params_json` or `params` must be specified.",
188+
StateFunc: func(v interface{}) string {
189+
json, _ := structure.NormalizeJsonString(v)
190+
return json
191+
},
192+
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
193+
newJson, _ := structure.NormalizeJsonString(new)
194+
oldJson, _ := structure.NormalizeJsonString(old)
195+
return newJson == oldJson
196+
},
197+
},
181198
},
182199
},
183200
},
@@ -218,12 +235,12 @@ func resourceElasticsearchKibanaAlertRead(d *schema.ResourceData, meta interface
218235
var alert kibana.Alert
219236

220237
providerConf := meta.(*ProviderConf)
221-
esClient, err := getKibanaClient(providerConf)
238+
kibanaClient, err := getKibanaClient(providerConf)
222239
if err != nil {
223240
return err
224241
}
225242

226-
switch client := esClient.(type) {
243+
switch client := kibanaClient.(type) {
227244
case *elastic7.Client:
228245
alert, err = kibanaGetAlert(client, id, spaceID)
229246
default:
@@ -261,7 +278,12 @@ func resourceElasticsearchKibanaAlertRead(d *schema.ResourceData, meta interface
261278
} else {
262279
ds.set("conditions", flattenKibanaAlertConditions(alert.Params))
263280
}
264-
ds.set("actions", flattenKibanaAlertActions(alert.Actions))
281+
282+
actions, err := flattenKibanaAlertActions(alert.Actions, d.Get("actions").([]interface{}))
283+
if err != nil {
284+
return err
285+
}
286+
ds.set("actions", actions)
265287

266288
return ds.err
267289
}
@@ -319,7 +341,7 @@ func resourceElasticsearchPostKibanaAlert(d *schema.ResourceData, meta interface
319341
scheduleEntry := schedule[0].(map[string]interface{})
320342
alertSchedule.Interval = scheduleEntry["interval"].(string)
321343
}
322-
actions, err := expandKibanaActionsList(d.Get("actions").(*schema.Set).List())
344+
actions, err := expandKibanaActionsList(d.Get("actions").([]interface{}))
323345
if err != nil {
324346
return "", err
325347
}
@@ -367,36 +389,55 @@ func resourceElasticsearchPostKibanaAlert(d *schema.ResourceData, meta interface
367389
}
368390

369391
func expandKibanaActionsList(resourcesArray []interface{}) ([]kibana.AlertAction, error) {
370-
actions := make([]kibana.AlertAction, 0, len(resourcesArray))
392+
actions := []kibana.AlertAction{}
371393
for _, resource := range resourcesArray {
372394
data, ok := resource.(map[string]interface{})
373395
if !ok {
374396
return actions, fmt.Errorf("Error asserting data: %+v, %T", resource, resource)
375397
}
398+
399+
var params map[string]interface{}
400+
401+
if paramsString, ok := data["params_json"]; ok && paramsString != "" {
402+
err := json.Unmarshal([]byte(paramsString.(string)), &params)
403+
if err != nil {
404+
return actions, fmt.Errorf("error paramasString %v: %w", paramsString, err)
405+
}
406+
} else {
407+
params = data["params"].(map[string]interface{})
408+
}
376409
action := kibana.AlertAction{
377410
ID: data["id"].(string),
378411
Group: data["group"].(string),
379412
ActionTypeId: data["action_type_id"].(string),
380-
Params: data["params"].(map[string]interface{}),
413+
Params: params,
381414
}
382415
actions = append(actions, action)
383416
}
384417

385418
return actions, nil
386419
}
387420

388-
func flattenKibanaAlertActions(actions []kibana.AlertAction) []map[string]interface{} {
389-
result := make([]map[string]interface{}, 0, len(actions))
390-
391-
for _, a := range actions {
392-
m := make(map[string]interface{})
421+
func flattenKibanaAlertActions(actions []kibana.AlertAction, actionsSchema []interface{}) ([]interface{}, error) {
422+
result := []interface{}{}
423+
for index, a := range actions {
424+
m := map[string]interface{}{}
393425
m["id"] = a.ID
394426
m["group"] = a.Group
395427
m["action_type_id"] = a.ActionTypeId
396-
m["params"] = flattenMap(a.Params)
428+
item := actionsSchema[index].(map[string]interface{})
429+
if paramJson, ok := item["params_json"]; ok && paramJson != "" {
430+
data, err := json.Marshal(a.Params)
431+
if err != nil {
432+
return nil, err
433+
}
434+
m["params_json"] = string(data)
435+
} else {
436+
m["params"] = flattenMap(a.Params)
437+
}
397438
result = append(result, m)
398439
}
399-
return result
440+
return result, nil
400441
}
401442

402443
func expandKibanaAlertConditions(raw map[string]interface{}) map[string]interface{} {

es/resource_elasticsearch_kibana_alert_test.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ func TestAccElasticsearchKibanaAlert(t *testing.T) {
5555

5656
testConfig := testAccElasticsearchKibanaAlertV77(defaultActionID)
5757
testParmsConfig := testAccElasticsearchKibanaAlertParamsJSONV77
58+
testActionParmsConfig := testAccElasticsearchKibanaAlertJsonV77(defaultActionID)
5859
elasticVersion, err := resourceElasticsearchKibanaGetVersion(meta)
5960
if err != nil {
6061
t.Skipf("err: %s", err)
@@ -67,6 +68,7 @@ func TestAccElasticsearchKibanaAlert(t *testing.T) {
6768
if elasticVersion.GreaterThanOrEqual(versionV711) {
6869
testConfig = testAccElasticsearchKibanaAlertV711
6970
testParmsConfig = testAccElasticsearchKibanaAlertParamsJSONV711
71+
testActionParmsConfig = testAccElasticsearchKibanaAlertJsonV711(defaultActionID)
7072
}
7173

7274
log.Printf("[INFO] TestAccElasticsearchKibanaAlert %+v", elasticVersion)
@@ -92,6 +94,12 @@ func TestAccElasticsearchKibanaAlert(t *testing.T) {
9294
testCheckElasticsearchKibanaAlertExists("elasticsearch_kibana_alert.test_params_json"),
9395
),
9496
},
97+
{
98+
Config: testActionParmsConfig,
99+
Check: resource.ComposeTestCheckFunc(
100+
testCheckElasticsearchKibanaAlertExists("elasticsearch_kibana_alert.test_action_json"),
101+
),
102+
},
95103
},
96104
})
97105
}
@@ -286,6 +294,77 @@ resource "elasticsearch_kibana_alert" "test" {
286294
`, actionID)
287295
}
288296

297+
func testAccElasticsearchKibanaAlertJsonV77(actionID string) string {
298+
return fmt.Sprintf(`
299+
resource "elasticsearch_kibana_alert" "test_action_json" {
300+
name = "terraform-alert"
301+
schedule {
302+
interval = "1m"
303+
}
304+
conditions {
305+
aggregation_type = "avg"
306+
term_size = 6
307+
threshold_comparator = ">"
308+
time_window_size = 5
309+
time_window_unit = "m"
310+
group_by = "top"
311+
threshold = [1000]
312+
index = [".test-index"]
313+
time_field = "@timestamp"
314+
aggregation_field = "sheet.version"
315+
term_field = "name.keyword"
316+
}
317+
actions {
318+
id = "%s"
319+
action_type_id = ".index"
320+
group = "threshold met"
321+
params_json = <<EOF
322+
{
323+
"level" : "info",
324+
"message" : "alert '{{alertName}}' is active for group '{{context.group}}':\n\n- Value: {{context.value}}\n- Conditions Met: {{context.conditions}} over {{params.timeWindowSize}}{{params.timeWindowUnit}}\n- Timestamp: {{context.date}}"
325+
}
326+
EOF
327+
}
328+
}
329+
`, actionID)
330+
}
331+
332+
func testAccElasticsearchKibanaAlertJsonV711(actionID string) string {
333+
return fmt.Sprintf(`
334+
resource "elasticsearch_kibana_alert" "test_action_json" {
335+
name = "terraform-alert"
336+
notify_when = "onActiveAlert"
337+
schedule {
338+
interval = "1m"
339+
}
340+
conditions {
341+
aggregation_type = "avg"
342+
term_size = 6
343+
threshold_comparator = ">"
344+
time_window_size = 5
345+
time_window_unit = "m"
346+
group_by = "top"
347+
threshold = [1000]
348+
index = [".test-index"]
349+
time_field = "@timestamp"
350+
aggregation_field = "sheet.version"
351+
term_field = "name.keyword"
352+
}
353+
actions {
354+
id = "%s"
355+
action_type_id = ".index"
356+
group = "threshold met"
357+
params_json = <<EOF
358+
{
359+
"level" : "info",
360+
"message" : "alert '{{alertName}}' is active for group '{{context.group}}':\n\n- Value: {{context.value}}\n- Conditions Met: {{context.conditions}} over {{params.timeWindowSize}}{{params.timeWindowUnit}}\n- Timestamp: {{context.date}}"
361+
}
362+
EOF
363+
}
364+
}
365+
`, actionID)
366+
}
367+
289368
var testAccElasticsearchKibanaAlertNoActionsV77 = `
290369
resource "elasticsearch_kibana_alert" "test" {
291370
name = "terraform-alert"

0 commit comments

Comments
 (0)