Skip to content

Commit 5cc4229

Browse files
Fixed a bug that prevented alerts from being generated for doc level monitors that use wildcard characters in index names. (#894) (#902)
Signed-off-by: AWSHurneyt <[email protected]> (cherry picked from commit 8c033b9) Co-authored-by: AWSHurneyt <[email protected]>
1 parent ed7f5d0 commit 5cc4229

File tree

3 files changed

+58
-9
lines changed

3 files changed

+58
-9
lines changed

alerting/src/main/kotlin/org/opensearch/alerting/DocumentLevelMonitorRunner.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import org.opensearch.commons.alerting.model.Monitor
4444
import org.opensearch.commons.alerting.model.action.PerAlertActionScope
4545
import org.opensearch.commons.alerting.util.string
4646
import org.opensearch.index.query.BoolQueryBuilder
47+
import org.opensearch.index.query.Operator
4748
import org.opensearch.index.query.QueryBuilders
4849
import org.opensearch.percolator.PercolateQueryBuilderExt
4950
import org.opensearch.rest.RestStatus
@@ -527,11 +528,11 @@ object DocumentLevelMonitorRunner : MonitorRunner() {
527528
monitorMetadata: MonitorMetadata,
528529
index: String
529530
): SearchHits {
530-
val boolQueryBuilder = BoolQueryBuilder().filter(QueryBuilders.matchQuery("index", index))
531+
val boolQueryBuilder = BoolQueryBuilder().must(QueryBuilders.matchQuery("index", index).operator(Operator.AND))
531532

532533
val percolateQueryBuilder = PercolateQueryBuilderExt("query", docs, XContentType.JSON)
533534
if (monitor.id.isNotEmpty()) {
534-
boolQueryBuilder.filter(QueryBuilders.matchQuery("monitor_id", monitor.id))
535+
boolQueryBuilder.must(QueryBuilders.matchQuery("monitor_id", monitor.id).operator(Operator.AND))
535536
}
536537
boolQueryBuilder.filter(percolateQueryBuilder)
537538

alerting/src/main/kotlin/org/opensearch/alerting/MonitorMetadataService.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ object MonitorMetadataService :
212212

213213
indices.forEach { indexName ->
214214
if (!lastRunContext.containsKey(indexName)) {
215-
lastRunContext[indexName] = createRunContextForIndex(index)
215+
lastRunContext[indexName] = createRunContextForIndex(indexName)
216216
}
217217
}
218218
} catch (e: RemoteTransportException) {

alerting/src/test/kotlin/org/opensearch/alerting/DocumentMonitorRunnerIT.kt

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import org.opensearch.script.Script
2121
import java.time.ZonedDateTime
2222
import java.time.format.DateTimeFormatter
2323
import java.time.temporal.ChronoUnit.MILLIS
24+
import java.util.Locale
2425

2526
class DocumentMonitorRunnerIT : AlertingRestTestCase() {
2627

@@ -343,20 +344,67 @@ class DocumentMonitorRunnerIT : AlertingRestTestCase() {
343344
assertTrue("Findings saved for test monitor", findings[1].relatedDocIds.contains("5"))
344345
}
345346

346-
fun `test execute monitor with wildcard index that generates alerts and findings`() {
347-
val testIndex = createTestIndex("test1")
348-
val testIndex2 = createTestIndex("test2")
347+
fun `test execute monitor with wildcard index that generates alerts and findings for EQUALS query operator`() {
348+
val testIndexPrefix = "test-index-${randomAlphaOfLength(10).lowercase(Locale.ROOT)}"
349+
val testQueryName = "wildcard-test-query"
350+
val testIndex = createTestIndex("${testIndexPrefix}1")
351+
val testIndex2 = createTestIndex("${testIndexPrefix}2")
352+
349353
val testTime = DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(ZonedDateTime.now().truncatedTo(MILLIS))
350354
val testDoc = """{
351355
"message" : "This is an error from IAD region",
352356
"test_strict_date_time" : "$testTime",
353357
"test_field" : "us-west-2"
354358
}"""
355359

356-
val docQuery = DocLevelQuery(query = "test_field:\"us-west-2\"", name = "3")
357-
val docLevelInput = DocLevelMonitorInput("description", listOf("test*"), listOf(docQuery))
360+
val docQuery = DocLevelQuery(query = "test_field:\"us-west-2\"", name = testQueryName)
361+
val docLevelInput = DocLevelMonitorInput("description", listOf("$testIndexPrefix*"), listOf(docQuery))
358362

359-
val trigger = randomDocumentLevelTrigger(condition = ALWAYS_RUN)
363+
val trigger = randomDocumentLevelTrigger(condition = Script("query[name=$testQueryName]"))
364+
val monitor = createMonitor(randomDocumentLevelMonitor(inputs = listOf(docLevelInput), triggers = listOf(trigger)))
365+
assertNotNull(monitor.id)
366+
367+
indexDoc(testIndex, "1", testDoc)
368+
indexDoc(testIndex2, "5", testDoc)
369+
370+
val response = executeMonitor(monitor.id)
371+
372+
val output = entityAsMap(response)
373+
374+
assertEquals(monitor.name, output["monitor_name"])
375+
@Suppress("UNCHECKED_CAST")
376+
val searchResult = (output.objectMap("input_results")["results"] as List<Map<String, Any>>).first()
377+
@Suppress("UNCHECKED_CAST")
378+
val matchingDocsToQuery = searchResult[docQuery.id] as List<String>
379+
assertEquals("Incorrect search result", 2, matchingDocsToQuery.size)
380+
assertTrue("Incorrect search result", matchingDocsToQuery.containsAll(listOf("1|$testIndex", "5|$testIndex2")))
381+
382+
val alerts = searchAlertsWithFilter(monitor)
383+
assertEquals("Alert saved for test monitor", 2, alerts.size)
384+
385+
val findings = searchFindings(monitor)
386+
assertEquals("Findings saved for test monitor", 2, findings.size)
387+
val foundFindings = findings.filter { it.relatedDocIds.contains("1") || it.relatedDocIds.contains("5") }
388+
assertEquals("Didn't find findings for docs 1 and 5", 2, foundFindings.size)
389+
}
390+
391+
fun `test execute monitor with wildcard index that generates alerts and findings for NOT EQUALS query operator`() {
392+
val testIndexPrefix = "test-index-${randomAlphaOfLength(10).lowercase(Locale.ROOT)}"
393+
val testQueryName = "wildcard-test-query"
394+
val testIndex = createTestIndex("${testIndexPrefix}1")
395+
val testIndex2 = createTestIndex("${testIndexPrefix}2")
396+
397+
val testTime = DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(ZonedDateTime.now().truncatedTo(MILLIS))
398+
val testDoc = """{
399+
"message" : "This is an error from IAD region",
400+
"test_strict_date_time" : "$testTime",
401+
"test_field" : "us-west-2"
402+
}"""
403+
404+
val docQuery = DocLevelQuery(query = "NOT (test_field:\"us-west-1\")", name = testQueryName)
405+
val docLevelInput = DocLevelMonitorInput("description", listOf("$testIndexPrefix*"), listOf(docQuery))
406+
407+
val trigger = randomDocumentLevelTrigger(condition = Script("query[name=$testQueryName]"))
360408
val monitor = createMonitor(randomDocumentLevelMonitor(inputs = listOf(docLevelInput), triggers = listOf(trigger)))
361409
assertNotNull(monitor.id)
362410

0 commit comments

Comments
 (0)