Skip to content
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

Findings search API draft #368

Closed
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
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import org.opensearch.alerting.action.GetAlertsAction
import org.opensearch.alerting.action.GetDestinationsAction
import org.opensearch.alerting.action.GetEmailAccountAction
import org.opensearch.alerting.action.GetEmailGroupAction
import org.opensearch.alerting.action.GetFindingsSearchAction
import org.opensearch.alerting.action.GetMonitorAction
import org.opensearch.alerting.action.IndexDestinationAction
import org.opensearch.alerting.action.IndexEmailAccountAction
Expand Down Expand Up @@ -51,6 +52,7 @@ import org.opensearch.alerting.resthandler.RestGetAlertsAction
import org.opensearch.alerting.resthandler.RestGetDestinationsAction
import org.opensearch.alerting.resthandler.RestGetEmailAccountAction
import org.opensearch.alerting.resthandler.RestGetEmailGroupAction
import org.opensearch.alerting.resthandler.RestGetFindingsSearchAction
import org.opensearch.alerting.resthandler.RestGetMonitorAction
import org.opensearch.alerting.resthandler.RestIndexDestinationAction
import org.opensearch.alerting.resthandler.RestIndexEmailAccountAction
Expand All @@ -74,6 +76,7 @@ import org.opensearch.alerting.transport.TransportGetAlertsAction
import org.opensearch.alerting.transport.TransportGetDestinationsAction
import org.opensearch.alerting.transport.TransportGetEmailAccountAction
import org.opensearch.alerting.transport.TransportGetEmailGroupAction
import org.opensearch.alerting.transport.TransportGetFindingsSearchAction
import org.opensearch.alerting.transport.TransportGetMonitorAction
import org.opensearch.alerting.transport.TransportIndexDestinationAction
import org.opensearch.alerting.transport.TransportIndexEmailAccountAction
Expand Down Expand Up @@ -139,6 +142,7 @@ internal class AlertingPlugin : PainlessExtension, ActionPlugin, ScriptPlugin, R
@JvmField val EMAIL_GROUP_BASE_URI = "$DESTINATION_BASE_URI/email_groups"
@JvmField val LEGACY_OPENDISTRO_EMAIL_ACCOUNT_BASE_URI = "$LEGACY_OPENDISTRO_DESTINATION_BASE_URI/email_accounts"
@JvmField val LEGACY_OPENDISTRO_EMAIL_GROUP_BASE_URI = "$LEGACY_OPENDISTRO_DESTINATION_BASE_URI/email_groups"
@JvmField val FINDING_BASE_URI = "/_plugins/_alerting/findings"
@JvmField val ALERTING_JOB_TYPES = listOf("monitor")
}

Expand Down Expand Up @@ -178,7 +182,8 @@ internal class AlertingPlugin : PainlessExtension, ActionPlugin, ScriptPlugin, R
RestSearchEmailGroupAction(),
RestGetEmailGroupAction(),
RestGetDestinationsAction(),
RestGetAlertsAction()
RestGetAlertsAction(),
RestGetFindingsSearchAction()
)
}

Expand All @@ -202,7 +207,9 @@ internal class AlertingPlugin : PainlessExtension, ActionPlugin, ScriptPlugin, R
ActionPlugin.ActionHandler(SearchEmailGroupAction.INSTANCE, TransportSearchEmailGroupAction::class.java),
ActionPlugin.ActionHandler(DeleteEmailGroupAction.INSTANCE, TransportDeleteEmailGroupAction::class.java),
ActionPlugin.ActionHandler(GetDestinationsAction.INSTANCE, TransportGetDestinationsAction::class.java),
ActionPlugin.ActionHandler(GetAlertsAction.INSTANCE, TransportGetAlertsAction::class.java)
ActionPlugin.ActionHandler(GetAlertsAction.INSTANCE, TransportGetAlertsAction::class.java),
ActionPlugin.ActionHandler(GetFindingsSearchAction.INSTANCE, TransportGetFindingsSearchAction::class.java)

)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

package org.opensearch.alerting.action

import org.opensearch.action.ActionType

class GetFindingsSearchAction private constructor() : ActionType<GetFindingsSearchResponse>(NAME, ::GetFindingsSearchResponse) {
companion object {
val INSTANCE = GetFindingsSearchAction()
val NAME = "cluster:admin/opendistro/alerting/findings/get"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

package org.opensearch.alerting.action

import org.opensearch.action.ActionRequest
import org.opensearch.action.ActionRequestValidationException
import org.opensearch.alerting.model.Table
import org.opensearch.common.io.stream.StreamInput
import org.opensearch.common.io.stream.StreamOutput
import org.opensearch.search.fetch.subphase.FetchSourceContext
import java.io.IOException

class GetFindingsSearchRequest : ActionRequest {
val findingId: String?
val version: Long
val srcContext: FetchSourceContext?
val table: Table

constructor(
findingId: String?,
version: Long,
srcContext: FetchSourceContext?,
table: Table
) : super() {
this.findingId = findingId
this.version = version
this.srcContext = srcContext
this.table = table
}

@Throws(IOException::class)
constructor(sin: StreamInput) : this(
findingId = sin.readOptionalString(),
version = sin.readLong(),
srcContext = if (sin.readBoolean()) {
FetchSourceContext(sin)
} else null,
table = Table.readFrom(sin)
)

override fun validate(): ActionRequestValidationException? {
return null
}

@Throws(IOException::class)
override fun writeTo(out: StreamOutput) {
out.writeOptionalString(findingId)
out.writeLong(version)
out.writeBoolean(srcContext != null)
srcContext?.writeTo(out)
table.writeTo(out)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

package org.opensearch.alerting.action

import org.opensearch.action.ActionResponse
import org.opensearch.alerting.model.FindingWithDocs
import org.opensearch.common.io.stream.StreamInput
import org.opensearch.common.io.stream.StreamOutput
import org.opensearch.common.xcontent.ToXContent
import org.opensearch.common.xcontent.ToXContentObject
import org.opensearch.common.xcontent.XContentBuilder
import org.opensearch.rest.RestStatus
import java.io.IOException

class GetFindingsSearchResponse : ActionResponse, ToXContentObject {
var status: RestStatus
var totalFindings: Int?
var findings: List<FindingWithDocs>

constructor(
status: RestStatus,
totalFindings: Int?,
findings: List<FindingWithDocs>
) : super() {
this.status = status
this.totalFindings = totalFindings
this.findings = findings
}

@Throws(IOException::class)
constructor(sin: StreamInput) {
this.status = sin.readEnum(RestStatus::class.java)
val findings = mutableListOf<FindingWithDocs>()
this.totalFindings = sin.readOptionalInt()
var currentSize = sin.readInt()
for (i in 0 until currentSize) {
findings.add(FindingWithDocs.readFrom(sin))
}
this.findings = findings
}

@Throws(IOException::class)
override fun writeTo(out: StreamOutput) {
out.writeEnum(status)
out.writeOptionalInt(totalFindings)
out.writeInt(findings.size)
for (finding in findings) {
finding.writeTo(out)
}
}

@Throws(IOException::class)
override fun toXContent(builder: XContentBuilder, params: ToXContent.Params): XContentBuilder {
builder.startObject()
.field("totalFindings", totalFindings)
.field("findings", findings)

return builder.endObject()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class Finding(
val triggerId: String?,
val triggerName: String?
) : Writeable, ToXContent {

@Throws(IOException::class)
constructor(sin: StreamInput) : this(
id = sin.readString(),
Expand Down Expand Up @@ -73,7 +74,7 @@ class Finding(
.field(QUERY_ID_FIELD, queryId)
.field(QUERY_TAGS_FIELD, queryTags.toTypedArray())
.field(SEVERITY_FIELD, severity)
.field(TIMESTAMP_FIELD, timestamp)
.field(TIMESTAMP_FIELD, timestamp.toEpochMilli())
.field(TRIGGER_ID_FIELD, triggerId)
.field(TRIGGER_NAME_FIELD, triggerName)
builder.endObject()
Expand Down Expand Up @@ -141,7 +142,9 @@ class Finding(
}
}
SEVERITY_FIELD -> severity = xcp.text()
TIMESTAMP_FIELD -> timestamp = requireNotNull(xcp.instant())
TIMESTAMP_FIELD -> {
timestamp = requireNotNull(xcp.instant())
}
TRIGGER_ID_FIELD -> triggerId = xcp.text()
TRIGGER_NAME_FIELD -> triggerName = xcp.text()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package org.opensearch.alerting.model

import org.apache.logging.log4j.LogManager
import org.opensearch.common.io.stream.StreamInput
import org.opensearch.common.io.stream.StreamOutput
import org.opensearch.common.io.stream.Writeable
import org.opensearch.common.xcontent.ToXContent
import org.opensearch.common.xcontent.XContentBuilder
import org.opensearch.common.xcontent.XContentParser
import org.opensearch.common.xcontent.XContentParserUtils
import java.io.IOException

private val log = LogManager.getLogger(FindingDocument::class.java)

class FindingDocument(
val index: String,
val id: String,
val found: Boolean,
val document: MutableMap<String, Any>
) : Writeable, ToXContent {

@Throws(IOException::class)
constructor(sin: StreamInput) : this(
index = sin.readString(),
id = sin.readString(),
found = sin.readBoolean(),
document = sin.readMap()
)

override fun toXContent(builder: XContentBuilder, params: ToXContent.Params): XContentBuilder {
builder.startObject()
.field(INDEX_FIELD, index)
.field(FINDING_DOCUMENT_ID_FIELD, id)
.field(FOUND_FIELD, found)

if (document.isEmpty()) builder.field(DOCUMENT_FIELD, document)
builder.endObject()
return builder
}

@Throws(IOException::class)
override fun writeTo(out: StreamOutput) {
out.writeString(index)
out.writeString(id)
out.writeBoolean(found)
out.writeMap(document)
}

companion object {
const val INDEX_FIELD = "index"
const val FINDING_DOCUMENT_ID_FIELD = "id"
const val FOUND_FIELD = "found"
const val DOCUMENT_FIELD = "document"
const val NO_ID = ""
const val NO_INDEX = ""

@JvmStatic @JvmOverloads
@Throws(IOException::class)
fun parse(xcp: XContentParser, id: String = NO_ID, index: String = NO_INDEX): FindingDocument {
var found = false
var document: MutableMap<String, Any> = mutableMapOf()

XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, xcp.currentToken(), xcp)
while (xcp.nextToken() != XContentParser.Token.END_OBJECT) {
val fieldName = xcp.currentName()
xcp.nextToken()

when (fieldName) {
FOUND_FIELD -> found = xcp.booleanValue()
DOCUMENT_FIELD -> document = xcp.map()
}
}

return FindingDocument(
index = index,
id = id,
found = found,
document = document
)
}

@JvmStatic
@Throws(IOException::class)
fun readFrom(sin: StreamInput): FindingDocument {
return FindingDocument(sin)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package org.opensearch.alerting.model

import org.apache.logging.log4j.LogManager
import org.opensearch.common.io.stream.StreamInput
import org.opensearch.common.io.stream.StreamOutput
import org.opensearch.common.io.stream.Writeable
import org.opensearch.common.xcontent.ToXContent
import org.opensearch.common.xcontent.XContentBuilder
import org.opensearch.common.xcontent.XContentParser
import org.opensearch.common.xcontent.XContentParserUtils
import java.io.IOException

private val log = LogManager.getLogger(Finding::class.java)

class FindingWithDocs(
val finding: Finding,
val documents: List<FindingDocument>
) : Writeable, ToXContent {

@Throws(IOException::class)
constructor(sin: StreamInput) : this(
finding = Finding.readFrom(sin),
documents = sin.readList((FindingDocument)::readFrom)
)

@Throws(IOException::class)
override fun writeTo(out: StreamOutput) {
finding.writeTo(out)
documents.forEach {
it.writeTo(out)
}
}

override fun toXContent(builder: XContentBuilder, params: ToXContent.Params): XContentBuilder {
builder.startObject()
.field(FINDING_FIELD, finding)
.field(DOCUMENTS_FIELD, documents)
builder.endObject()
return builder
}

companion object {
const val FINDING_FIELD = "finding"
const val DOCUMENTS_FIELD = "documents"

@JvmStatic
@Throws(IOException::class)
fun parse(xcp: XContentParser): FindingWithDocs {
lateinit var finding: Finding
val documents: MutableList<FindingDocument> = mutableListOf()

XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, xcp.currentToken(), xcp)
while (xcp.nextToken() != XContentParser.Token.END_OBJECT) {
val fieldName = xcp.currentName()
xcp.nextToken()

when (fieldName) {
FINDING_FIELD -> finding = Finding.parse(xcp)
DOCUMENTS_FIELD -> {
XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_ARRAY, xcp.currentToken(), xcp)
while (xcp.nextToken() != XContentParser.Token.END_ARRAY) {
documents.add(FindingDocument.parse(xcp))
}
}
}
}

return FindingWithDocs(
finding = finding,
documents = documents
)
}

@JvmStatic
@Throws(IOException::class)
fun readFrom(sin: StreamInput): FindingWithDocs {
return FindingWithDocs(sin)
}
}
}
Loading