Skip to content

Commit

Permalink
Move Findings and Alerts action, request, response and models from al…
Browse files Browse the repository at this point in the history
…erting to common-utils (#254)

Signed-off-by: Surya Sashank Nistala <[email protected]>
  • Loading branch information
eirsep authored Sep 23, 2022
1 parent 68da168 commit d4a4aaa
Show file tree
Hide file tree
Showing 23 changed files with 1,678 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ import org.opensearch.common.io.stream.Writeable
import org.opensearch.commons.alerting.action.AlertingActions
import org.opensearch.commons.alerting.action.DeleteMonitorRequest
import org.opensearch.commons.alerting.action.DeleteMonitorResponse
import org.opensearch.commons.alerting.action.GetAlertsRequest
import org.opensearch.commons.alerting.action.GetAlertsResponse
import org.opensearch.commons.alerting.action.GetFindingsRequest
import org.opensearch.commons.alerting.action.GetFindingsResponse
import org.opensearch.commons.alerting.action.IndexMonitorRequest
import org.opensearch.commons.alerting.action.IndexMonitorResponse
import org.opensearch.commons.notifications.action.BaseResponse
Expand Down Expand Up @@ -63,6 +67,54 @@ object AlertingPluginInterface {
)
}

/**
* Get Alerts interface.
* @param client Node client for making transport action
* @param request The request object
* @param listener The listener for getting response
*/
fun getAlerts(
client: NodeClient,
request: GetAlertsRequest,
listener: ActionListener<GetAlertsResponse>
) {
client.execute(
AlertingActions.GET_ALERTS_ACTION_TYPE,
request,
wrapActionListener(listener) { response ->
recreateObject(response) {
GetAlertsResponse(
it
)
}
}
)
}

/**
* Get Findings interface.
* @param client Node client for making transport action
* @param request The request object
* @param listener The listener for getting response
*/
fun getFindings(
client: NodeClient,
request: GetFindingsRequest,
listener: ActionListener<GetFindingsResponse>
) {
client.execute(
AlertingActions.GET_FINDINGS_ACTION_TYPE,
request,
wrapActionListener(listener) { response ->
recreateObject(response) {
GetFindingsResponse(
it
)
}
}
)
}

@Suppress("UNCHECKED_CAST")
private fun <Response : BaseResponse> wrapActionListener(
listener: ActionListener<Response>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,19 @@ import org.opensearch.action.ActionType

object AlertingActions {
const val INDEX_MONITOR_ACTION_NAME = "cluster:admin/opendistro/alerting/monitor/write"
const val GET_ALERTS_ACTION_NAME = "cluster:admin/opendistro/alerting/alerts/get"
const val DELETE_MONITOR_ACTION_NAME = "cluster:admin/opendistro/alerting/monitor/delete"
const val GET_FINDINGS_ACTION_NAME = "cluster:admin/opensearch/alerting/findings/get"

val INDEX_MONITOR_ACTION_TYPE =
ActionType(INDEX_MONITOR_ACTION_NAME, ::IndexMonitorResponse)

const val DELETE_MONITOR_ACTION_NAME = "cluster:admin/opendistro/alerting/monitor/delete"
val GET_ALERTS_ACTION_TYPE =
ActionType(GET_ALERTS_ACTION_NAME, ::GetAlertsResponse)

val DELETE_MONITOR_ACTION_TYPE =
ActionType(DELETE_MONITOR_ACTION_NAME, ::DeleteMonitorResponse)

val GET_FINDINGS_ACTION_TYPE =
ActionType(GET_FINDINGS_ACTION_NAME, ::GetFindingsResponse)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package org.opensearch.commons.alerting.action

import org.opensearch.action.ActionRequest
import org.opensearch.action.ActionRequestValidationException
import org.opensearch.common.io.stream.StreamInput
import org.opensearch.common.io.stream.StreamOutput
import org.opensearch.commons.alerting.model.Table
import java.io.IOException

class GetAlertsRequest : ActionRequest {
val table: Table
val severityLevel: String
val alertState: String
val monitorId: String?
val alertIndex: String?

constructor(
table: Table,
severityLevel: String,
alertState: String,
monitorId: String?,
alertIndex: String?
) : super() {
this.table = table
this.severityLevel = severityLevel
this.alertState = alertState
this.monitorId = monitorId
this.alertIndex = alertIndex
}

@Throws(IOException::class)
constructor(sin: StreamInput) : this(
table = Table.readFrom(sin),
severityLevel = sin.readString(),
alertState = sin.readString(),
monitorId = sin.readOptionalString(),
alertIndex = sin.readOptionalString()
)

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

@Throws(IOException::class)
override fun writeTo(out: StreamOutput) {
table.writeTo(out)
out.writeString(severityLevel)
out.writeString(alertState)
out.writeOptionalString(monitorId)
out.writeOptionalString(alertIndex)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package org.opensearch.commons.alerting.action

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.XContentBuilder
import org.opensearch.commons.alerting.model.Alert
import org.opensearch.commons.notifications.action.BaseResponse
import java.io.IOException
import java.util.Collections

class GetAlertsResponse : BaseResponse {
val alerts: List<Alert>

// totalAlerts is not the same as the size of alerts because there can be 30 alerts from the request, but
// the request only asked for 5 alerts, so totalAlerts will be 30, but alerts will only contain 5 alerts
val totalAlerts: Int?

constructor(
alerts: List<Alert>,
totalAlerts: Int?
) : super() {
this.alerts = alerts
this.totalAlerts = totalAlerts
}

@Throws(IOException::class)
constructor(sin: StreamInput) : this(
alerts = Collections.unmodifiableList(sin.readList(::Alert)),
totalAlerts = sin.readOptionalInt()
)

@Throws(IOException::class)
override fun writeTo(out: StreamOutput) {
out.writeCollection(alerts)
out.writeOptionalInt(totalAlerts)
}

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

return builder.endObject()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package org.opensearch.commons.alerting.action

import org.opensearch.action.ActionRequest
import org.opensearch.action.ActionRequestValidationException
import org.opensearch.common.io.stream.StreamInput
import org.opensearch.common.io.stream.StreamOutput
import org.opensearch.commons.alerting.model.Table
import java.io.IOException

class GetFindingsRequest : ActionRequest {
val findingId: String?
val table: Table
val monitorId: String?
val findingIndex: String?

constructor(
findingId: String?,
table: Table,
monitorId: String? = null,
findingIndexName: String? = null
) : super() {
this.findingId = findingId
this.table = table
this.monitorId = monitorId
this.findingIndex = findingIndexName
}

@Throws(IOException::class)
constructor(sin: StreamInput) : this(
findingId = sin.readOptionalString(),
table = Table.readFrom(sin),
monitorId = sin.readOptionalString(),
findingIndexName = sin.readOptionalString()
)

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

@Throws(IOException::class)
override fun writeTo(out: StreamOutput) {
out.writeOptionalString(findingId)
table.writeTo(out)
out.writeOptionalString(monitorId)
out.writeOptionalString(findingIndex)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package org.opensearch.commons.alerting.action

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.XContentBuilder
import org.opensearch.commons.alerting.model.FindingWithDocs
import org.opensearch.commons.notifications.action.BaseResponse
import org.opensearch.rest.RestStatus
import java.io.IOException

class GetFindingsResponse : BaseResponse {
private 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("total_findings", totalFindings)
.field("findings", findings)

return builder.endObject()
}

override fun getStatus(): RestStatus {
return this.status
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package org.opensearch.commons.alerting.alerts

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.ensureExpectedToken
import org.opensearch.commons.alerting.util.instant
import org.opensearch.commons.alerting.util.optionalTimeField
import java.io.IOException
import java.time.Instant

data class AlertError(val timestamp: Instant, val message: String) : Writeable, ToXContent {

@Throws(IOException::class)
constructor(sin: StreamInput) : this(
sin.readInstant(), // timestamp
sin.readString() // message
)

@Throws(IOException::class)
override fun writeTo(out: StreamOutput) {
out.writeInstant(timestamp)
out.writeString(message)
}
companion object {

const val TIMESTAMP_FIELD = "timestamp"
const val MESSAGE_FIELD = "message"

@JvmStatic
@Throws(IOException::class)
fun parse(xcp: XContentParser): AlertError {

lateinit var timestamp: Instant
lateinit var message: String

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

when (fieldName) {
TIMESTAMP_FIELD -> timestamp = requireNotNull(xcp.instant())
MESSAGE_FIELD -> message = xcp.text()
}
}
return AlertError(timestamp = timestamp, message = message)
}

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

override fun toXContent(builder: XContentBuilder, params: ToXContent.Params): XContentBuilder {
return builder.startObject()
.optionalTimeField(TIMESTAMP_FIELD, timestamp)
.field(MESSAGE_FIELD, message)
.endObject()
}
}
Loading

0 comments on commit d4a4aaa

Please sign in to comment.