Skip to content

Support alerting rules with only one of kql or timeframe fields #886

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

Merged
merged 4 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
- Use the auto-generated OAS schema from elastic/kibana for the Fleet API. ([#834](https://github.com/elastic/terraform-provider-elasticstack/issues/834))
- Support description in `elasticstack_elasticsearch_security_role` data sources. ([#884](https://github.com/elastic/terraform-provider-elasticstack/pull/884))
- Prevent spurious recreation of `elasticstack_fleet_agent_policy` resources due to 'changing' policy ids ([#885](https://github.com/elastic/terraform-provider-elasticstack/pull/885))
- Support `elasticstack_kibana_alerting_rule` resources with only one of `kql` or `timeframe` attributes set ([#886](https://github.com/elastic/terraform-provider-elasticstack/pull/886))

## [0.11.11] - 2024-10-25

Expand Down
33 changes: 21 additions & 12 deletions internal/clients/kibana/alerting.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,21 @@ func ruleResponseToModel(spaceID string, res *alerting.RuleResponseProperties) *

if !alerting.IsNil(action.AlertsFilter) {
filter := unwrapOptionalField(action.AlertsFilter)
timeframe := unwrapOptionalField(filter.Timeframe)

a.AlertsFilter = &models.ActionAlertsFilter{
Kql: *filter.Query.Kql,
Timeframe: models.AlertsFilterTimeframe{
a.AlertsFilter = &models.ActionAlertsFilter{}

if filter.Query != nil {
a.AlertsFilter.Kql = filter.Query.Kql
}

if filter.Timeframe != nil {
timeframe := unwrapOptionalField(filter.Timeframe)
a.AlertsFilter.Timeframe = &models.AlertsFilterTimeframe{
Days: timeframe.Days,
Timezone: *timeframe.Timezone,
HoursStart: *timeframe.Hours.Start,
HoursEnd: *timeframe.Hours.End,
},
}
}
}

Expand Down Expand Up @@ -116,21 +121,25 @@ func ruleActionsToActionsInner(ruleActions []models.AlertingRuleAction) []alerti
}

if !alerting.IsNil(action.AlertsFilter) {
timeframe := action.AlertsFilter.Timeframe
filter := alerting.ActionsInnerAlertsFilter{}

filter := alerting.ActionsInnerAlertsFilter{
Query: &alerting.ActionsInnerAlertsFilterQuery{
Kql: &action.AlertsFilter.Kql,
if action.AlertsFilter.Kql != nil {
filter.Query = &alerting.ActionsInnerAlertsFilterQuery{
Kql: action.AlertsFilter.Kql,
Filters: []alerting.Filter{},
},
Timeframe: &alerting.ActionsInnerAlertsFilterTimeframe{
}
}

if action.AlertsFilter.Timeframe != nil {
timeframe := action.AlertsFilter.Timeframe
filter.Timeframe = &alerting.ActionsInnerAlertsFilterTimeframe{
Timezone: &timeframe.Timezone,
Days: timeframe.Days,
Hours: &alerting.ActionsInnerAlertsFilterTimeframeHours{
Start: &timeframe.HoursStart,
End: &timeframe.HoursEnd,
},
},
}
}

actionToAppend.AlertsFilter = &filter
Expand Down
4 changes: 2 additions & 2 deletions internal/clients/kibana/alerting_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,8 @@ func Test_ruleResponseToModel(t *testing.T) {
Throttle: utils.Pointer("10s"),
},
AlertsFilter: &models.ActionAlertsFilter{
Kql: "foobar",
Timeframe: models.AlertsFilterTimeframe{
Kql: utils.Pointer("foobar"),
Timeframe: &models.AlertsFilterTimeframe{
Days: []int32{3, 5, 7},
Timezone: "UTC+1",
HoursStart: "00:00",
Expand Down
61 changes: 36 additions & 25 deletions internal/kibana/alerting.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,24 +367,29 @@ func getActionsFromResourceData(d *schema.ResourceData, serverVersion *version.V
return []models.AlertingRuleAction{}, diag.Errorf("actions.alerts_filter is only supported for Elasticsearch v8.9 or higher")
}

resourceDays := d.Get(currentAction + ".alerts_filter.0.timeframe.0.days").([]interface{})
days := []int32{}
filter := models.ActionAlertsFilter{}

for _, a := range resourceDays {
day := int32(a.(int))
days = append(days, day)
}
if _, ok := d.GetOk(currentAction + ".alerts_filter.0.timeframe"); ok {

resourceDays := d.Get(currentAction + ".alerts_filter.0.timeframe.0.days").([]interface{})
days := []int32{}

timeframe := models.AlertsFilterTimeframe{
Days: days,
Timezone: d.Get(currentAction + ".alerts_filter.0.timeframe.0.timezone").(string),
HoursStart: d.Get(currentAction + ".alerts_filter.0.timeframe.0.hours_start").(string),
HoursEnd: d.Get(currentAction + ".alerts_filter.0.timeframe.0.hours_end").(string),
for _, a := range resourceDays {
day := int32(a.(int))
days = append(days, day)
}

timeframe := models.AlertsFilterTimeframe{
Days: days,
Timezone: d.Get(currentAction + ".alerts_filter.0.timeframe.0.timezone").(string),
HoursStart: d.Get(currentAction + ".alerts_filter.0.timeframe.0.hours_start").(string),
HoursEnd: d.Get(currentAction + ".alerts_filter.0.timeframe.0.hours_end").(string),
}
filter.Timeframe = &timeframe
}

filter := models.ActionAlertsFilter{
Kql: d.Get(currentAction + ".alerts_filter.0.kql").(string),
Timeframe: timeframe,
if kql, ok := d.GetOk(currentAction + ".alerts_filter.0.kql"); ok {
filter.Kql = utils.Pointer(kql.(string))
}

a.AlertsFilter = &filter
Expand Down Expand Up @@ -547,18 +552,24 @@ func resourceRuleRead(ctx context.Context, d *schema.ResourceData, meta interfac
alerts_filter := []interface{}{}

if action.AlertsFilter != nil {
timeframe := []interface{}{}
timeframe = append(timeframe, map[string]interface{}{
"days": action.AlertsFilter.Timeframe.Days,
"timezone": action.AlertsFilter.Timeframe.Timezone,
"hours_start": action.AlertsFilter.Timeframe.HoursStart,
"hours_end": action.AlertsFilter.Timeframe.HoursEnd,
})
filter := map[string]interface{}{}

if action.AlertsFilter.Timeframe != nil {
timeframe := []interface{}{}
timeframe = append(timeframe, map[string]interface{}{
"days": action.AlertsFilter.Timeframe.Days,
"timezone": action.AlertsFilter.Timeframe.Timezone,
"hours_start": action.AlertsFilter.Timeframe.HoursStart,
"hours_end": action.AlertsFilter.Timeframe.HoursEnd,
})
filter["timeframe"] = timeframe
}

alerts_filter = append(alerts_filter, map[string]interface{}{
"kql": action.AlertsFilter.Kql,
"timeframe": timeframe,
})
if action.AlertsFilter.Kql != nil {
filter["kql"] = action.AlertsFilter.Kql
}

alerts_filter = append(alerts_filter, filter)
} else {
alerts_filter = nil
}
Expand Down
22 changes: 5 additions & 17 deletions internal/kibana/alerting_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func TestAccResourceAlertingRule(t *testing.T) {
resource.TestCheckResourceAttr("elasticstack_kibana_alerting_rule.test_rule", "actions.0.frequency.0.summary", "true"),
resource.TestCheckResourceAttr("elasticstack_kibana_alerting_rule.test_rule", "actions.0.frequency.0.notify_when", "onActionGroupChange"),
resource.TestCheckResourceAttr("elasticstack_kibana_alerting_rule.test_rule", "actions.0.frequency.0.throttle", "10m"),
resource.TestCheckResourceAttr("elasticstack_kibana_alerting_rule.test_rule", "actions.0.alerts_filter.0.kql", `kibana.alert.action_group: "slo.burnRate.alert" OR kibana.alert.action_group : "slo.burnRate.high"`),
resource.TestCheckResourceAttr("elasticstack_kibana_alerting_rule.test_rule", "actions.0.alerts_filter.0.kql", ""),
resource.TestCheckResourceAttr("elasticstack_kibana_alerting_rule.test_rule", "actions.0.alerts_filter.0.timeframe.0.days.0", "1"),
resource.TestCheckResourceAttr("elasticstack_kibana_alerting_rule.test_rule", "actions.0.alerts_filter.0.timeframe.0.days.1", "2"),
resource.TestCheckResourceAttr("elasticstack_kibana_alerting_rule.test_rule", "actions.0.alerts_filter.0.timeframe.0.days.2", "3"),
Expand All @@ -138,10 +138,7 @@ func TestAccResourceAlertingRule(t *testing.T) {
resource.TestCheckResourceAttr("elasticstack_kibana_alerting_rule.test_rule", "actions.0.frequency.0.notify_when", "onActionGroupChange"),
resource.TestCheckResourceAttr("elasticstack_kibana_alerting_rule.test_rule", "actions.0.frequency.0.throttle", "10m"),
resource.TestCheckResourceAttr("elasticstack_kibana_alerting_rule.test_rule", "actions.0.alerts_filter.0.kql", `kibana.alert.action_group: "slo.burnRate.alert"`),
resource.TestCheckResourceAttr("elasticstack_kibana_alerting_rule.test_rule", "actions.0.alerts_filter.0.timeframe.0.days.0", "7"),
resource.TestCheckResourceAttr("elasticstack_kibana_alerting_rule.test_rule", "actions.0.alerts_filter.0.timeframe.0.timezone", "Pacific/Honolulu"),
resource.TestCheckResourceAttr("elasticstack_kibana_alerting_rule.test_rule", "actions.0.alerts_filter.0.timeframe.0.hours_start", "02:00"),
resource.TestCheckResourceAttr("elasticstack_kibana_alerting_rule.test_rule", "actions.0.alerts_filter.0.timeframe.0.hours_end", "03:00"),
resource.TestCheckResourceAttr("elasticstack_kibana_alerting_rule.test_rule", "actions.0.alerts_filter.0.timeframe.#", "0"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the .#? length of the array?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, exactly.

),
},
{
Expand Down Expand Up @@ -428,13 +425,11 @@ resource "elasticstack_kibana_alerting_rule" "test_rule" {
}

alerts_filter {
kql = "kibana.alert.action_group: \"slo.burnRate.alert\" OR kibana.alert.action_group : \"slo.burnRate.high\""

timeframe {
days = [1,2,3]
timezone = "Africa/Accra"
hours_start = "01:00"
hours_end = "07:00"
timezone = "Africa/Accra"
hours_start = "01:00"
hours_end = "07:00"
}
}
}
Expand Down Expand Up @@ -503,13 +498,6 @@ resource "elasticstack_kibana_alerting_rule" "test_rule" {

alerts_filter {
kql = "kibana.alert.action_group: \"slo.burnRate.alert\""

timeframe {
days = [7]
timezone = "Pacific/Honolulu"
hours_start = "02:00"
hours_end = "03:00"
}
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions internal/models/alert_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ type ActionFrequency struct {
}

type ActionAlertsFilter struct {
Kql string
Timeframe AlertsFilterTimeframe
Kql *string
Timeframe *AlertsFilterTimeframe
}

type AlertsFilterTimeframe struct {
Expand Down
Loading