From 1c0718a059608598ff4164962f0868667567c268 Mon Sep 17 00:00:00 2001 From: Petar Dzepina Date: Tue, 2 May 2023 23:21:16 +0200 Subject: [PATCH] added noop trigger Signed-off-by: Petar Dzepina --- gradle/wrapper/gradle-wrapper.properties | 2 +- .../commons/alerting/model/Alert.kt | 18 +++++ .../commons/alerting/model/Monitor.kt | 3 + .../commons/alerting/model/NoOpTrigger.kt | 75 +++++++++++++++++++ .../commons/alerting/TestHelpers.kt | 4 +- .../commons/alerting/model/XContentTests.kt | 11 +++ 6 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 src/main/kotlin/org/opensearch/commons/alerting/model/NoOpTrigger.kt diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index aa991fce..774fae87 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/src/main/kotlin/org/opensearch/commons/alerting/model/Alert.kt b/src/main/kotlin/org/opensearch/commons/alerting/model/Alert.kt index c251e540..90c94e3c 100644 --- a/src/main/kotlin/org/opensearch/commons/alerting/model/Alert.kt +++ b/src/main/kotlin/org/opensearch/commons/alerting/model/Alert.kt @@ -125,6 +125,24 @@ data class Alert( aggregationResultBucket = null, findingIds = findingIds, relatedDocIds = relatedDocIds ) + constructor( + id: String = NO_ID, + monitor: Monitor, + trigger: NoOpTrigger, + startTime: Instant, + lastNotificationTime: Instant?, + state: State = State.ERROR, + errorMessage: String, + errorHistory: List = mutableListOf(), + schemaVersion: Int = NO_SCHEMA_VERSION + ) : this( + id = id, monitorId = monitor.id, monitorName = monitor.name, monitorVersion = monitor.version, monitorUser = monitor.user, + triggerId = trigger.id, triggerName = trigger.name, state = state, startTime = startTime, + lastNotificationTime = lastNotificationTime, errorMessage = errorMessage, errorHistory = errorHistory, + severity = trigger.severity, actionExecutionResults = listOf(), schemaVersion = schemaVersion, + aggregationResultBucket = null, findingIds = listOf(), relatedDocIds = listOf() + ) + enum class State { ACTIVE, ACKNOWLEDGED, COMPLETED, ERROR, DELETED } diff --git a/src/main/kotlin/org/opensearch/commons/alerting/model/Monitor.kt b/src/main/kotlin/org/opensearch/commons/alerting/model/Monitor.kt index e32f1b67..a7e7b639 100644 --- a/src/main/kotlin/org/opensearch/commons/alerting/model/Monitor.kt +++ b/src/main/kotlin/org/opensearch/commons/alerting/model/Monitor.kt @@ -50,6 +50,9 @@ data class Monitor( // Ensure that trigger ids are unique within a monitor val triggerIds = mutableSetOf() triggers.forEach { trigger -> + // NoOpTrigger is only used in "Monitor Error Alerts" as a placeholder + require(trigger !is NoOpTrigger) + require(triggerIds.add(trigger.id)) { "Duplicate trigger id: ${trigger.id}. Trigger ids must be unique." } // Verify Trigger type based on Monitor type when (monitorType) { diff --git a/src/main/kotlin/org/opensearch/commons/alerting/model/NoOpTrigger.kt b/src/main/kotlin/org/opensearch/commons/alerting/model/NoOpTrigger.kt new file mode 100644 index 00000000..6ffcddda --- /dev/null +++ b/src/main/kotlin/org/opensearch/commons/alerting/model/NoOpTrigger.kt @@ -0,0 +1,75 @@ +package org.opensearch.commons.alerting.model + +import org.opensearch.common.CheckedFunction +import org.opensearch.common.UUIDs +import org.opensearch.common.io.stream.StreamInput +import org.opensearch.common.io.stream.StreamOutput +import org.opensearch.common.xcontent.XContentParserUtils +import org.opensearch.commons.alerting.model.action.Action +import org.opensearch.core.ParseField +import org.opensearch.core.xcontent.NamedXContentRegistry +import org.opensearch.core.xcontent.ToXContent +import org.opensearch.core.xcontent.XContentBuilder +import org.opensearch.core.xcontent.XContentParser +import java.io.IOException + +data class NoOpTrigger( + override val id: String = UUIDs.base64UUID(), + override val name: String = "NoOp trigger", + override val severity: String = "", + override val actions: List = listOf(), +) : Trigger { + + @Throws(IOException::class) + constructor(sin: StreamInput) : this() + + override fun toXContent(builder: XContentBuilder, params: ToXContent.Params): XContentBuilder { + builder.startObject() + .startObject(NOOP_TRIGGER_FIELD) + .endObject() + return builder + } + + override fun name(): String { + return NOOP_TRIGGER_FIELD + } + + fun asTemplateArg(): Map { + return mapOf() + } + + @Throws(IOException::class) + override fun writeTo(out: StreamOutput) { + } + + companion object { + const val NOOP_TRIGGER_FIELD = "noop_trigger" + val XCONTENT_REGISTRY = NamedXContentRegistry.Entry( + Trigger::class.java, ParseField(NOOP_TRIGGER_FIELD), + CheckedFunction { parseInner(it) } + ) + + @JvmStatic @Throws(IOException::class) + fun parseInner(xcp: XContentParser): NoOpTrigger { + if (xcp.currentToken() != XContentParser.Token.START_OBJECT && xcp.currentToken() != XContentParser.Token.FIELD_NAME) { + XContentParserUtils.throwUnknownToken(xcp.currentToken(), xcp.tokenLocation) + } + + // If the parser began on START_OBJECT, move to the next token so that the while loop enters on + // the fieldName (or END_OBJECT if it's empty). + if (xcp.currentToken() == XContentParser.Token.START_OBJECT) xcp.nextToken() + if (xcp.currentToken() != XContentParser.Token.END_OBJECT) { + XContentParserUtils.throwUnknownToken(xcp.currentToken(), xcp.tokenLocation) + } else { + xcp.nextToken() + } + return NoOpTrigger() + } + + @JvmStatic + @Throws(IOException::class) + fun readFrom(sin: StreamInput): NoOpTrigger { + return NoOpTrigger(sin) + } + } +} diff --git a/src/test/kotlin/org/opensearch/commons/alerting/TestHelpers.kt b/src/test/kotlin/org/opensearch/commons/alerting/TestHelpers.kt index a16fee63..685898ec 100644 --- a/src/test/kotlin/org/opensearch/commons/alerting/TestHelpers.kt +++ b/src/test/kotlin/org/opensearch/commons/alerting/TestHelpers.kt @@ -29,6 +29,7 @@ import org.opensearch.commons.alerting.model.Finding import org.opensearch.commons.alerting.model.Input import org.opensearch.commons.alerting.model.IntervalSchedule import org.opensearch.commons.alerting.model.Monitor +import org.opensearch.commons.alerting.model.NoOpTrigger import org.opensearch.commons.alerting.model.QueryLevelTrigger import org.opensearch.commons.alerting.model.Schedule import org.opensearch.commons.alerting.model.SearchInput @@ -395,7 +396,8 @@ fun xContentRegistry(): NamedXContentRegistry { DocLevelMonitorInput.XCONTENT_REGISTRY, QueryLevelTrigger.XCONTENT_REGISTRY, BucketLevelTrigger.XCONTENT_REGISTRY, - DocumentLevelTrigger.XCONTENT_REGISTRY + DocumentLevelTrigger.XCONTENT_REGISTRY, + NoOpTrigger.XCONTENT_REGISTRY ) + SearchModule(Settings.EMPTY, emptyList()).namedXContents ) } diff --git a/src/test/kotlin/org/opensearch/commons/alerting/model/XContentTests.kt b/src/test/kotlin/org/opensearch/commons/alerting/model/XContentTests.kt index fa93da5f..9481c86f 100644 --- a/src/test/kotlin/org/opensearch/commons/alerting/model/XContentTests.kt +++ b/src/test/kotlin/org/opensearch/commons/alerting/model/XContentTests.kt @@ -30,6 +30,7 @@ import org.opensearch.core.xcontent.ToXContent import org.opensearch.index.query.QueryBuilders import org.opensearch.search.builder.SearchSourceBuilder import org.opensearch.test.OpenSearchTestCase +import java.time.Instant import java.time.temporal.ChronoUnit import kotlin.test.assertFailsWith @@ -357,6 +358,16 @@ class XContentTests { assertEquals("Round tripping alert doesn't work", alert, parsedAlert) } + @Test + fun `test alert parsing with noop trigger`() { + val monitor = randomQueryLevelMonitor() + val alert = Alert( + monitor = monitor, trigger = NoOpTrigger(), startTime = Instant.now().truncatedTo(ChronoUnit.MILLIS), + errorMessage = "some error", lastNotificationTime = Instant.now() + ) + assertEquals("Round tripping alert doesn't work", alert.triggerName, "NoOp trigger") + } + @Test fun `test alert parsing without user`() { val alertStr = "{\"id\":\"\",\"version\":-1,\"monitor_id\":\"\",\"schema_version\":0,\"monitor_version\":1," +