Skip to content

Commit

Permalink
[Synthetics] Fix monitor status rule for empty kql query results !! (e…
Browse files Browse the repository at this point in the history
…lastic#208922)

## Summary

Fixes elastic#208915 !!

Fix monitor status rule for empty kql query results !!

1. Made sure if kql filter return no configs ids, rule break early to
not cover all monitors

### Testing

Create a synthetics rule with a kql filter which matches no monitors and
make sure rule doesn't trigger for other down monitors in the system
<img width="661" alt="image"
src="https://github.com/user-attachments/assets/ed0b3a1f-e8d1-4e22-a77d-1237ce557ac5"
/>


### Before

Create a rule and you can observe that rule would get triggered for all
monitors down in the system with matching condition criteria
  • Loading branch information
shahzad31 authored Jan 31, 2025
1 parent 9112044 commit 5c350b4
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { getFilters } from './filter_monitors';

describe('getFilters', () => {
it('returns an empty array when all parameters are empty', () => {
const ruleParams = { monitorTypes: [], locations: [], tags: [], projects: [] };
expect(getFilters(ruleParams)).toEqual([]);
});

it('creates a terms filter for monitorTypes', () => {
const ruleParams = { monitorTypes: ['http', 'tcp'], locations: [], tags: [], projects: [] };
expect(getFilters(ruleParams)).toEqual([{ terms: { 'monitor.type': ['http', 'tcp'] } }]);
});

it('creates a terms filter for locations', () => {
const ruleParams = {
monitorTypes: [],
locations: ['us-east', 'us-west'],
tags: [],
projects: [],
};
expect(getFilters(ruleParams)).toEqual([
{ terms: { 'observer.name': ['us-east', 'us-west'] } },
]);
});

it('creates a bool must filter for tags', () => {
const ruleParams = { monitorTypes: [], locations: [], tags: ['tag1', 'tag2'], projects: [] };
expect(getFilters(ruleParams)).toEqual([
{
terms: { tags: ['tag1', 'tag2'] },
},
]);
});

it('creates a terms filter for projects', () => {
const ruleParams = { monitorTypes: [], locations: [], tags: [], projects: ['proj1', 'proj2'] };
expect(getFilters(ruleParams)).toEqual([
{ terms: { 'monitor.project.id': ['proj1', 'proj2'] } },
]);
});

it('handles all filters together', () => {
const ruleParams = {
monitorTypes: ['http'],
locations: ['us-east'],
tags: ['tag1', 'tag2'],
projects: ['proj1'],
};
expect(getFilters(ruleParams)).toEqual([
{ terms: { 'monitor.type': ['http'] } },
{ terms: { 'observer.name': ['us-east'] } },
{
terms: { tags: ['tag1', 'tag2'] },
},
{ terms: { 'monitor.project.id': ['proj1'] } },
]);
});

it('ignores undefined fields', () => {
const ruleParams = {
monitorTypes: undefined,
locations: undefined,
tags: undefined,
projects: undefined,
};
expect(getFilters(ruleParams)).toEqual([]);
});

it('ignores empty values in an otherwise valid object', () => {
const ruleParams = { monitorTypes: [], locations: ['us-east'], tags: [], projects: [] };
expect(getFilters(ruleParams)).toEqual([{ terms: { 'observer.name': ['us-east'] } }]);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export async function queryFilterMonitors({
return result.aggregations?.ids.buckets.map((bucket) => bucket.key as string);
}

const getFilters = (ruleParams: StatusRuleParams) => {
export const getFilters = (ruleParams: StatusRuleParams) => {
const { monitorTypes, locations, tags, projects } = ruleParams;
const filters: QueryDslQueryContainer[] = [];
if (monitorTypes?.length) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ export class StatusRuleExecutor {
ruleParams: this.params,
});

if (this.params.kqlQuery && isEmpty(configIds)) {
this.debug(`No monitor found with the given KQL query ${this.params.kqlQuery}`);
return processMonitors([]);
}

const { filtersStr } = parseArrayFilters({
configIds,
filter: baseFilter,
Expand Down

0 comments on commit 5c350b4

Please sign in to comment.