Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Add logged-on User details to the Monitor and Destination #255

Merged
merged 8 commits into from
Sep 25, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,7 @@ class GetMonitorRequest : ActionRequest {
out.writeString(monitorId)
out.writeLong(version)
out.writeEnum(method)
if (srcContext != null) {
out.writeBoolean(true)
srcContext?.writeTo(out)
} else {
out.writeBoolean(false)
}
out.writeBoolean(srcContext != null)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is nice!

srcContext?.writeTo(out)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ import com.amazon.opendistroforelasticsearch.alerting.core.model.Input
import com.amazon.opendistroforelasticsearch.alerting.core.model.Schedule
import com.amazon.opendistroforelasticsearch.alerting.core.model.ScheduledJob
import com.amazon.opendistroforelasticsearch.alerting.core.model.SearchInput
import com.amazon.opendistroforelasticsearch.alerting.core.model.User
import com.amazon.opendistroforelasticsearch.alerting.elasticapi.instant
import com.amazon.opendistroforelasticsearch.alerting.elasticapi.optionalTimeField
import com.amazon.opendistroforelasticsearch.alerting.elasticapi.optionalUserField
import com.amazon.opendistroforelasticsearch.alerting.settings.AlertingSettings.Companion.MONITOR_MAX_INPUTS
import com.amazon.opendistroforelasticsearch.alerting.settings.AlertingSettings.Companion.MONITOR_MAX_TRIGGERS
import com.amazon.opendistroforelasticsearch.alerting.util.IndexUtils.Companion.NO_SCHEMA_VERSION
Expand Down Expand Up @@ -52,6 +54,7 @@ data class Monitor(
override val schedule: Schedule,
override val lastUpdateTime: Instant,
override val enabledTime: Instant?,
val user: User?,
val schemaVersion: Int = NO_SCHEMA_VERSION,
val inputs: List<Input>,
val triggers: List<Trigger>,
Expand All @@ -77,17 +80,20 @@ data class Monitor(

@Throws(IOException::class)
constructor(sin: StreamInput): this(
sin.readString(), // id
sin.readLong(), // version
sin.readString(), // name
sin.readBoolean(), // enabled
Schedule.readFrom(sin),
sin.readInstant(), // lastUpdateTime
sin.readOptionalInstant(), // enabledTime
sin.readInt(), // schemaVersion
sin.readList(::SearchInput), // inputs
sin.readList(::Trigger), // triggers
suppressWarning(sin.readMap()) // uiMetadata
id = sin.readString(),
version = sin.readLong(),
name = sin.readString(),
enabled = sin.readBoolean(),
schedule = Schedule.readFrom(sin),
lastUpdateTime = sin.readInstant(),
enabledTime = sin.readOptionalInstant(),
user = if (sin.readBoolean()) {
User(sin)
} else null,
schemaVersion = sin.readInt(),
inputs = sin.readList(::SearchInput),
triggers = sin.readList(::Trigger),
uiMetadata = suppressWarning(sin.readMap())
)
fun toXContent(builder: XContentBuilder): XContentBuilder {
return toXContent(builder, ToXContent.EMPTY_PARAMS)
Expand All @@ -104,6 +110,7 @@ data class Monitor(
builder.field(TYPE_FIELD, type)
.field(SCHEMA_VERSION_FIELD, schemaVersion)
.field(NAME_FIELD, name)
.optionalUserField(USER_FIELD, user)
.field(ENABLED_FIELD, enabled)
.optionalTimeField(ENABLED_TIME_FIELD, enabledTime)
.field(SCHEDULE_FIELD, schedule)
Expand All @@ -118,7 +125,7 @@ data class Monitor(
override fun fromDocument(id: String, version: Long): Monitor = copy(id = id, version = version)

@Throws(IOException::class)
fun writeTo(out: StreamOutput) {
override fun writeTo(out: StreamOutput) {
out.writeString(id)
out.writeLong(version)
out.writeString(name)
Expand All @@ -131,6 +138,8 @@ data class Monitor(
schedule.writeTo(out)
out.writeInstant(lastUpdateTime)
out.writeOptionalInstant(enabledTime)
out.writeBoolean(user != null)
user?.writeTo(out)
out.writeInt(schemaVersion)
out.writeCollection(inputs)
out.writeCollection(triggers)
Expand All @@ -142,6 +151,7 @@ data class Monitor(
const val TYPE_FIELD = "type"
const val SCHEMA_VERSION_FIELD = "schema_version"
const val NAME_FIELD = "name"
const val USER_FIELD = "user"
const val ENABLED_FIELD = "enabled"
const val SCHEDULE_FIELD = "schedule"
const val TRIGGERS_FIELD = "triggers"
Expand All @@ -163,6 +173,7 @@ data class Monitor(
@Throws(IOException::class)
fun parse(xcp: XContentParser, id: String = NO_ID, version: Long = NO_VERSION): Monitor {
lateinit var name: String
var user: User? = null
lateinit var schedule: Schedule
var lastUpdateTime: Instant? = null
var enabledTime: Instant? = null
Expand All @@ -180,6 +191,7 @@ data class Monitor(
when (fieldName) {
SCHEMA_VERSION_FIELD -> schemaVersion = xcp.intValue()
NAME_FIELD -> name = xcp.text()
USER_FIELD -> user = User.parse(xcp)
ENABLED_FIELD -> enabled = xcp.booleanValue()
SCHEDULE_FIELD -> schedule = Schedule.parse(xcp)
INPUTS_FIELD -> {
Expand Down Expand Up @@ -215,6 +227,7 @@ data class Monitor(
requireNotNull(schedule) { "Monitor schedule is null" },
lastUpdateTime ?: Instant.now(),
enabledTime,
user,
schemaVersion,
inputs.toList(),
triggers.toList(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import com.amazon.opendistroforelasticsearch.alerting.destination.response.Desti
import com.amazon.opendistroforelasticsearch.alerting.elasticapi.convertToMap
import com.amazon.opendistroforelasticsearch.alerting.elasticapi.instant
import com.amazon.opendistroforelasticsearch.alerting.elasticapi.optionalTimeField
import com.amazon.opendistroforelasticsearch.alerting.core.model.User
import com.amazon.opendistroforelasticsearch.alerting.elasticapi.optionalUserField
import com.amazon.opendistroforelasticsearch.alerting.model.destination.email.Email
import com.amazon.opendistroforelasticsearch.alerting.util.DestinationType
import com.amazon.opendistroforelasticsearch.alerting.util.IndexUtils.Companion.NO_SCHEMA_VERSION
Expand All @@ -48,6 +50,7 @@ data class Destination(
val schemaVersion: Int = NO_SCHEMA_VERSION,
val type: DestinationType,
val name: String,
val user: User?,
val lastUpdateTime: Instant,
val chime: Chime?,
val slack: Slack?,
Expand All @@ -60,6 +63,7 @@ data class Destination(
if (params.paramAsBoolean("with_type", false)) builder.startObject(DESTINATION)
builder.field(TYPE_FIELD, type.value)
.field(NAME_FIELD, name)
.optionalUserField(USER_FIELD, user)
.field(SCHEMA_VERSION, schemaVersion)
.optionalTimeField(LAST_UPDATE_TIME_FIELD, lastUpdateTime)
.field(type.value, constructResponseForDestinationType(type))
Expand All @@ -78,37 +82,24 @@ data class Destination(
out.writeInt(schemaVersion)
out.writeEnum(type)
out.writeString(name)
out.writeBoolean(user != null)
user?.writeTo(out)
out.writeInstant(lastUpdateTime)
if (chime != null) {
out.writeBoolean(true)
chime.writeTo(out)
} else {
out.writeBoolean(false)
}
if (slack != null) {
out.writeBoolean(true)
slack.writeTo(out)
} else {
out.writeBoolean(false)
}
if (customWebhook != null) {
out.writeBoolean(true)
customWebhook.writeTo(out)
} else {
out.writeBoolean(false)
}
if (email != null) {
out.writeBoolean(true)
email.writeTo(out)
} else {
out.writeBoolean(false)
}
out.writeBoolean(chime != null)
chime?.writeTo(out)
out.writeBoolean(slack != null)
slack?.writeTo(out)
out.writeBoolean(customWebhook != null)
customWebhook?.writeTo(out)
out.writeBoolean(email != null)
email?.writeTo(out)
}

companion object {
const val DESTINATION = "destination"
const val TYPE_FIELD = "type"
const val NAME_FIELD = "name"
const val USER_FIELD = "user"
const val NO_ID = ""
const val NO_VERSION = 1L
const val SCHEMA_VERSION = "schema_version"
Expand All @@ -128,6 +119,7 @@ data class Destination(
@Throws(IOException::class)
fun parse(xcp: XContentParser, id: String = NO_ID, version: Long = NO_VERSION): Destination {
lateinit var name: String
var user: User? = null
lateinit var type: String
var slack: Slack? = null
var chime: Chime? = null
Expand All @@ -143,6 +135,7 @@ data class Destination(

when (fieldName) {
NAME_FIELD -> name = xcp.text()
USER_FIELD -> user = User.parse(xcp)
TYPE_FIELD -> {
type = xcp.text()
val allowedTypes = DestinationType.values().map { it.value }
Expand Down Expand Up @@ -179,6 +172,7 @@ data class Destination(
schemaVersion,
DestinationType.valueOf(type.toUpperCase(Locale.ROOT)),
requireNotNull(name) { "Destination name is null" },
user,
lastUpdateTime ?: Instant.now(),
chime,
slack,
Expand All @@ -190,16 +184,19 @@ data class Destination(
@Throws(IOException::class)
fun readFrom(sin: StreamInput): Destination {
return Destination(
sin.readString(), // id
sin.readLong(), // version
sin.readInt(), // schemaVersion
sin.readEnum(DestinationType::class.java), // type
sin.readString(), // name
sin.readInstant(), // lastUpdateTime
Chime.readFrom(sin), // chime
Slack.readFrom(sin), // slack
CustomWebhook.readFrom(sin), // customWebhook
Email.readFrom(sin) // email
id = sin.readString(),
version = sin.readLong(),
schemaVersion = sin.readInt(),
type = sin.readEnum(DestinationType::class.java),
name = sin.readString(),
user = if (sin.readBoolean()) {
User(sin)
} else null,
lastUpdateTime = sin.readInstant(),
chime = Chime.readFrom(sin),
slack = Slack.readFrom(sin),
customWebhook = CustomWebhook.readFrom(sin),
email = Email.readFrom(sin)
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ abstract class AlertingRestTestCase : ODFERestTestCase() {
return Destination(
type = DestinationType.TEST_ACTION,
name = "test",
user = randomUser(),
lastUpdateTime = Instant.now(),
chime = null,
slack = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import com.amazon.opendistroforelasticsearch.alerting.model.ActionRunResult
import com.amazon.opendistroforelasticsearch.alerting.model.InputRunResults
import com.amazon.opendistroforelasticsearch.alerting.model.MonitorRunResult
import com.amazon.opendistroforelasticsearch.alerting.model.TriggerRunResult
import com.amazon.opendistroforelasticsearch.alerting.core.model.User
import com.amazon.opendistroforelasticsearch.alerting.model.action.Throttle
import com.amazon.opendistroforelasticsearch.alerting.model.destination.email.EmailAccount
import com.amazon.opendistroforelasticsearch.alerting.model.destination.email.EmailEntry
Expand Down Expand Up @@ -61,6 +62,7 @@ import java.time.temporal.ChronoUnit

fun randomMonitor(
name: String = ESRestTestCase.randomAlphaOfLength(10),
user: User = randomUser(),
inputs: List<Input> = listOf(SearchInput(emptyList(), SearchSourceBuilder().query(QueryBuilders.matchAllQuery()))),
schedule: Schedule = IntervalSchedule(interval = 5, unit = ChronoUnit.MINUTES),
enabled: Boolean = ESTestCase.randomBoolean(),
Expand All @@ -71,7 +73,23 @@ fun randomMonitor(
): Monitor {
return Monitor(name = name, enabled = enabled, inputs = inputs, schedule = schedule, triggers = triggers,
enabledTime = enabledTime, lastUpdateTime = lastUpdateTime,
uiMetadata = if (withMetadata) mapOf("foo" to "bar") else mapOf())
user = user, uiMetadata = if (withMetadata) mapOf("foo" to "bar") else mapOf())
}

// Monitor of older versions without security.
fun randomMonitorWithoutUser(
name: String = ESRestTestCase.randomAlphaOfLength(10),
inputs: List<Input> = listOf(SearchInput(emptyList(), SearchSourceBuilder().query(QueryBuilders.matchAllQuery()))),
schedule: Schedule = IntervalSchedule(interval = 5, unit = ChronoUnit.MINUTES),
enabled: Boolean = ESTestCase.randomBoolean(),
triggers: List<Trigger> = (1..randomInt(10)).map { randomTrigger() },
enabledTime: Instant? = if (enabled) Instant.now().truncatedTo(ChronoUnit.MILLIS) else null,
lastUpdateTime: Instant = Instant.now().truncatedTo(ChronoUnit.MILLIS),
withMetadata: Boolean = false
): Monitor {
return Monitor(name = name, enabled = enabled, inputs = inputs, schedule = schedule, triggers = triggers,
enabledTime = enabledTime, lastUpdateTime = lastUpdateTime,
user = null, uiMetadata = if (withMetadata) mapOf("foo" to "bar") else mapOf())
}

fun randomTrigger(
Expand Down Expand Up @@ -201,6 +219,15 @@ fun Monitor.toJsonString(): String {
return this.toXContent(builder).string()
}

fun randomUser(): User {
return User(ESRestTestCase.randomAlphaOfLength(10), listOf(ESRestTestCase.randomAlphaOfLength(10),
ESRestTestCase.randomAlphaOfLength(10)), listOf("all_access"), listOf("test_attr=test"))
}

fun randomUserEmpty(): User {
return User("", listOf(), listOf(), listOf())
}

fun EmailAccount.toJsonString(): String {
val builder = XContentFactory.jsonBuilder()
return this.toXContent(builder).string()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package com.amazon.opendistroforelasticsearch.alerting.action

import com.amazon.opendistroforelasticsearch.alerting.core.model.CronSchedule
import com.amazon.opendistroforelasticsearch.alerting.model.Monitor
import com.amazon.opendistroforelasticsearch.alerting.randomUser
import org.elasticsearch.common.io.stream.BytesStreamOutput
import org.elasticsearch.common.io.stream.StreamInput
import org.elasticsearch.rest.RestStatus
Expand Down Expand Up @@ -47,7 +48,7 @@ class GetMonitorResponseTests : ESTestCase() {
val cronSchedule = CronSchedule(cronExpression, ZoneId.of("Asia/Kolkata"), testInstance)
val req = GetMonitorResponse("1234", 1L, 2L, 0L, RestStatus.OK,
Monitor("123", 0L, "test-monitor", true, cronSchedule, Instant.now(),
Instant.now(), 0, mutableListOf(), mutableListOf(), mutableMapOf()))
Instant.now(), randomUser(), 0, mutableListOf(), mutableListOf(), mutableMapOf()))
assertNotNull(req)

val out = BytesStreamOutput()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package com.amazon.opendistroforelasticsearch.alerting.action

import com.amazon.opendistroforelasticsearch.alerting.model.destination.Chime
import com.amazon.opendistroforelasticsearch.alerting.model.destination.Destination
import com.amazon.opendistroforelasticsearch.alerting.randomUser
import com.amazon.opendistroforelasticsearch.alerting.util.DestinationType
import org.elasticsearch.action.support.WriteRequest
import org.elasticsearch.common.io.stream.BytesStreamOutput
Expand All @@ -41,6 +42,7 @@ class IndexDestinationRequestTests : ESTestCase() {
1,
DestinationType.CHIME,
"TestChimeDest",
randomUser(),
Instant.now(),
Chime("test.com"),
null,
Expand Down Expand Up @@ -77,6 +79,7 @@ class IndexDestinationRequestTests : ESTestCase() {
1,
DestinationType.CHIME,
"TestChimeDest",
randomUser(),
Instant.now(),
Chime("test.com"),
null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package com.amazon.opendistroforelasticsearch.alerting.action

import com.amazon.opendistroforelasticsearch.alerting.model.destination.Chime
import com.amazon.opendistroforelasticsearch.alerting.model.destination.Destination
import com.amazon.opendistroforelasticsearch.alerting.randomUser
import com.amazon.opendistroforelasticsearch.alerting.util.DestinationType
import org.elasticsearch.common.io.stream.BytesStreamOutput
import org.elasticsearch.common.io.stream.StreamInput
Expand All @@ -30,8 +31,7 @@ class IndexDestinationResponseTests : ESTestCase() {

val req = IndexDestinationResponse("1234", 0L, 1L, 2L, RestStatus.CREATED,
Destination("1234", 0L, 1, DestinationType.CHIME, "TestChimeDest",
Instant.now(), Chime("test.com"), null, null, null))

randomUser(), Instant.now(), Chime("test.com"), null, null, null))
assertNotNull(req)

val out = BytesStreamOutput()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package com.amazon.opendistroforelasticsearch.alerting.action

import com.amazon.opendistroforelasticsearch.alerting.core.model.CronSchedule
import com.amazon.opendistroforelasticsearch.alerting.model.Monitor
import com.amazon.opendistroforelasticsearch.alerting.randomUser
import org.elasticsearch.common.io.stream.BytesStreamOutput
import org.elasticsearch.common.io.stream.StreamInput
import org.elasticsearch.rest.RestStatus
Expand All @@ -33,7 +34,7 @@ class IndexMonitorResponseTests : ESTestCase() {
val cronSchedule = CronSchedule(cronExpression, ZoneId.of("Asia/Kolkata"), testInstance)
val req = IndexMonitorResponse("1234", 1L, 2L, 0L, RestStatus.OK,
Monitor("123", 0L, "test-monitor", true, cronSchedule, Instant.now(),
Instant.now(), 0, mutableListOf(), mutableListOf(), mutableMapOf()))
Instant.now(), randomUser(), 0, mutableListOf(), mutableListOf(), mutableMapOf()))
assertNotNull(req)

val out = BytesStreamOutput()
Expand Down
Loading