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

Commit 4afcb2f

Browse files
qreshidchauviereDavid Chauviere
authored
Refactor Email Destination (#244)
* Add Mail destination * Support SSL/TLS * Authentification * Message's body is html by dedault * Mail destination : move settings to elasticsearch settings * Add loading of mail settings * Remove Dynamic setting property for mail settings. Update README.md about mail destination * Changes from review: - exception handling for mail server username and password - default mail server port is 587 * Make keystore destination settings reloadable * Updated scheduled-jobs mapping * Removed DestinationSettings and DestinationMailSettings, added Recipient data class and updated Email data class to use new fields * Added EmailAccount and EmailGroup data classes * Refactored publishing of Email Destination to use EmailAccount and EmailGroup * Refactored MailMessage and renamed to EmailMessage * Refactored DestinationMailClient and renamed references to 'Mail' to be 'Email' in class names * Added rest handlers for EmailAccount and EmailGroup index and delete actions * Fix style issues * Updated schema version for scheduled jobs index in tests * Fixed existing email destination tests to pass with refactored changes * Added new RestHandlers to AlertingPlugin * Added tests for new components * Added rest handlers for searching and getting EmailAccount and EmailGroup * Fixed parsing error with GET API for EmailAccount and EmailGroup * Moved Email settings from AlertingSettings to DestinationSettings and fixed issue for loading keystore settings * Add license headers to new files * Updated README * Fixed incorrect call to ScheduledJob.parse in search rest handlers for EmailAccount and EmailGroup * Change to use exists query in EmailAccount and EmailGroup search APIs * Make Email model class streamable * Fix tests * Use 'use' scoped function instead of 'let' for Closeable secure settings * Add/update tests * Update UNCHECKED_CAST suppressions to match 'master' branch implementation * Make Email extend Writeable * Combine DestinationHttpResponse and DestinationEmailResponse to DestinationResponse * Move email_accounts and email_groups APIs under 'destinations' namespace * Make EmailAccount and EmailGroup writeable * Add action to DELETE email_account API * Add action to DELETE email_group API * Add action to INDEX/UPDATE email_account API * Add action to INDEX/UPDATE email_group API * Add validation for name when creating/updating email_account * Remove duplicate code from EmailAccount and EmailGroup TransportIndexAction classes * Add action to SEARCH email_account API * Add action to SEARCH email_group API * Add version to EmailAccount * Add version to EmailGroup * Add action to GET email_account API * Add action to GET email_group API * Add rest tests for EmailAccount and EmailGroup * Added validation for name and email in email model classes * Separated calls to get info from alerting confix index in MonitorRunner to separate classes * Fix IllegalStateException warn messages and handle null in EmailAccount/EmailGroup GetRequest * Add JavaMail to third-party libraries list * Fix failing test after resolving merge conflict from master * Add missing return and remove unnecessary comments Co-authored-by: David Chauvière <[email protected]> Co-authored-by: David Chauviere <David Chauviere [email protected]>
1 parent 67b5598 commit 4afcb2f

File tree

97 files changed

+5680
-79
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

97 files changed

+5680
-79
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ When trigger conditions are met, you can publish messages to the following desti
2121
* [Slack](https://slack.com/)
2222
* Custom webhook
2323
* [Amazon Chime](https://aws.amazon.com/chime/)
24+
* Email
2425

2526
Messages can be static strings, or you can use the [Mustache](https://mustache.github.io/mustache.5.html) templates to include contextual information.
2627

THIRD-PARTY

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
** kotlin-test; version 1.2.60 -- https://github.com/JetBrains/kotlin/tree/1.2.60
1212
** kotlin-test-junit; version 1.2.60 -- https://github.com/JetBrains/kotlin/tree/1.2.60
1313
** Maven-org-jetbrains_annotations; version 13.0 -- http://www.jetbrains.org/display/IJOS/Home;jsessionid=1881AA3B9F1A3A8D98C0EDD69082DC85
14-
** PowerMock; version 1.7.4 -- http://www.powermock.org
14+
** PowerMock; version 1.7.4 -- http://www.powermock.org
15+
** JavaMail; version 1.6.2 -- https://javaee.github.io/javamail/
1516

1617
Apache License
1718

alerting/src/main/kotlin/com/amazon/opendistroforelasticsearch/alerting/AlertingPlugin.kt

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,19 @@ package com.amazon.opendistroforelasticsearch.alerting
1616

1717
import com.amazon.opendistroforelasticsearch.alerting.action.AcknowledgeAlertAction
1818
import com.amazon.opendistroforelasticsearch.alerting.action.DeleteDestinationAction
19+
import com.amazon.opendistroforelasticsearch.alerting.action.DeleteEmailAccountAction
20+
import com.amazon.opendistroforelasticsearch.alerting.action.DeleteEmailGroupAction
1921
import com.amazon.opendistroforelasticsearch.alerting.action.IndexDestinationAction
2022
import com.amazon.opendistroforelasticsearch.alerting.action.DeleteMonitorAction
2123
import com.amazon.opendistroforelasticsearch.alerting.action.ExecuteMonitorAction
24+
import com.amazon.opendistroforelasticsearch.alerting.action.GetEmailAccountAction
25+
import com.amazon.opendistroforelasticsearch.alerting.action.GetEmailGroupAction
2226
import com.amazon.opendistroforelasticsearch.alerting.action.GetMonitorAction
27+
import com.amazon.opendistroforelasticsearch.alerting.action.IndexEmailAccountAction
28+
import com.amazon.opendistroforelasticsearch.alerting.action.IndexEmailGroupAction
2329
import com.amazon.opendistroforelasticsearch.alerting.action.IndexMonitorAction
30+
import com.amazon.opendistroforelasticsearch.alerting.action.SearchEmailAccountAction
31+
import com.amazon.opendistroforelasticsearch.alerting.action.SearchEmailGroupAction
2432
import com.amazon.opendistroforelasticsearch.alerting.action.SearchMonitorAction
2533
import com.amazon.opendistroforelasticsearch.alerting.alerts.AlertIndices
2634
import com.amazon.opendistroforelasticsearch.alerting.core.JobSweeper
@@ -35,21 +43,38 @@ import com.amazon.opendistroforelasticsearch.alerting.core.settings.ScheduledJob
3543
import com.amazon.opendistroforelasticsearch.alerting.model.Monitor
3644
import com.amazon.opendistroforelasticsearch.alerting.resthandler.RestAcknowledgeAlertAction
3745
import com.amazon.opendistroforelasticsearch.alerting.resthandler.RestDeleteDestinationAction
46+
import com.amazon.opendistroforelasticsearch.alerting.resthandler.RestDeleteEmailAccountAction
47+
import com.amazon.opendistroforelasticsearch.alerting.resthandler.RestDeleteEmailGroupAction
3848
import com.amazon.opendistroforelasticsearch.alerting.resthandler.RestDeleteMonitorAction
3949
import com.amazon.opendistroforelasticsearch.alerting.resthandler.RestExecuteMonitorAction
50+
import com.amazon.opendistroforelasticsearch.alerting.resthandler.RestGetEmailAccountAction
51+
import com.amazon.opendistroforelasticsearch.alerting.resthandler.RestGetEmailGroupAction
4052
import com.amazon.opendistroforelasticsearch.alerting.resthandler.RestGetMonitorAction
4153
import com.amazon.opendistroforelasticsearch.alerting.resthandler.RestIndexDestinationAction
54+
import com.amazon.opendistroforelasticsearch.alerting.resthandler.RestIndexEmailAccountAction
55+
import com.amazon.opendistroforelasticsearch.alerting.resthandler.RestIndexEmailGroupAction
4256
import com.amazon.opendistroforelasticsearch.alerting.resthandler.RestIndexMonitorAction
57+
import com.amazon.opendistroforelasticsearch.alerting.resthandler.RestSearchEmailAccountAction
58+
import com.amazon.opendistroforelasticsearch.alerting.resthandler.RestSearchEmailGroupAction
4359
import com.amazon.opendistroforelasticsearch.alerting.resthandler.RestSearchMonitorAction
4460
import com.amazon.opendistroforelasticsearch.alerting.script.TriggerScript
4561
import com.amazon.opendistroforelasticsearch.alerting.settings.AlertingSettings
62+
import com.amazon.opendistroforelasticsearch.alerting.settings.DestinationSettings
4663
import com.amazon.opendistroforelasticsearch.alerting.transport.TransportAcknowledgeAlertAction
4764
import com.amazon.opendistroforelasticsearch.alerting.transport.TransportDeleteDestinationAction
65+
import com.amazon.opendistroforelasticsearch.alerting.transport.TransportDeleteEmailAccountAction
66+
import com.amazon.opendistroforelasticsearch.alerting.transport.TransportDeleteEmailGroupAction
4867
import com.amazon.opendistroforelasticsearch.alerting.transport.TransportIndexDestinationAction
4968
import com.amazon.opendistroforelasticsearch.alerting.transport.TransportDeleteMonitorAction
5069
import com.amazon.opendistroforelasticsearch.alerting.transport.TransportExecuteMonitorAction
70+
import com.amazon.opendistroforelasticsearch.alerting.transport.TransportGetEmailAccountAction
71+
import com.amazon.opendistroforelasticsearch.alerting.transport.TransportGetEmailGroupAction
5172
import com.amazon.opendistroforelasticsearch.alerting.transport.TransportGetMonitorAction
73+
import com.amazon.opendistroforelasticsearch.alerting.transport.TransportIndexEmailAccountAction
74+
import com.amazon.opendistroforelasticsearch.alerting.transport.TransportIndexEmailGroupAction
5275
import com.amazon.opendistroforelasticsearch.alerting.transport.TransportIndexMonitorAction
76+
import com.amazon.opendistroforelasticsearch.alerting.transport.TransportSearchEmailAccountAction
77+
import com.amazon.opendistroforelasticsearch.alerting.transport.TransportSearchEmailGroupAction
5378
import com.amazon.opendistroforelasticsearch.alerting.transport.TransportSearchMonitorAction
5479
import org.elasticsearch.action.ActionRequest
5580
import org.elasticsearch.action.ActionResponse
@@ -72,6 +97,7 @@ import org.elasticsearch.painless.spi.Whitelist
7297
import org.elasticsearch.painless.spi.WhitelistLoader
7398
import org.elasticsearch.plugins.ActionPlugin
7499
import org.elasticsearch.plugins.Plugin
100+
import org.elasticsearch.plugins.ReloadablePlugin
75101
import org.elasticsearch.plugins.ScriptPlugin
76102
import org.elasticsearch.repositories.RepositoriesService
77103
import org.elasticsearch.rest.RestController
@@ -88,7 +114,7 @@ import java.util.function.Supplier
88114
* It also adds [Monitor.XCONTENT_REGISTRY], [SearchInput.XCONTENT_REGISTRY] to the
89115
* [NamedXContentRegistry] so that we are able to deserialize the custom named objects.
90116
*/
91-
internal class AlertingPlugin : PainlessExtension, ActionPlugin, ScriptPlugin, Plugin() {
117+
internal class AlertingPlugin : PainlessExtension, ActionPlugin, ScriptPlugin, ReloadablePlugin, Plugin() {
92118
override fun getContextWhitelists(): Map<ScriptContext<*>, List<Whitelist>> {
93119
val whitelist = WhitelistLoader.loadFromResourceFiles(javaClass, "com.amazon.opendistroforelasticsearch.alerting.txt")
94120
return mapOf(TriggerScript.CONTEXT to listOf(whitelist))
@@ -99,6 +125,8 @@ internal class AlertingPlugin : PainlessExtension, ActionPlugin, ScriptPlugin, P
99125
@JvmField val UI_METADATA_EXCLUDE = arrayOf("monitor.${Monitor.UI_METADATA_FIELD}")
100126
@JvmField val MONITOR_BASE_URI = "/_opendistro/_alerting/monitors"
101127
@JvmField val DESTINATION_BASE_URI = "/_opendistro/_alerting/destinations"
128+
@JvmField val EMAIL_ACCOUNT_BASE_URI = "$DESTINATION_BASE_URI/email_accounts"
129+
@JvmField val EMAIL_GROUP_BASE_URI = "$DESTINATION_BASE_URI/email_groups"
102130
@JvmField val ALERTING_JOB_TYPES = listOf("monitor")
103131
}
104132

@@ -127,7 +155,15 @@ internal class AlertingPlugin : PainlessExtension, ActionPlugin, ScriptPlugin, P
127155
RestAcknowledgeAlertAction(),
128156
RestScheduledJobStatsHandler("_alerting"),
129157
RestIndexDestinationAction(settings),
130-
RestDeleteDestinationAction())
158+
RestDeleteDestinationAction(),
159+
RestIndexEmailAccountAction(),
160+
RestDeleteEmailAccountAction(),
161+
RestSearchEmailAccountAction(),
162+
RestGetEmailAccountAction(),
163+
RestIndexEmailGroupAction(),
164+
RestDeleteEmailGroupAction(),
165+
RestSearchEmailGroupAction(),
166+
RestGetEmailGroupAction())
131167
}
132168

133169
override fun getActions(): List<ActionPlugin.ActionHandler<out ActionRequest, out ActionResponse>> {
@@ -140,7 +176,15 @@ internal class AlertingPlugin : PainlessExtension, ActionPlugin, ScriptPlugin, P
140176
ActionPlugin.ActionHandler(SearchMonitorAction.INSTANCE, TransportSearchMonitorAction::class.java),
141177
ActionPlugin.ActionHandler(DeleteMonitorAction.INSTANCE, TransportDeleteMonitorAction::class.java),
142178
ActionPlugin.ActionHandler(DeleteDestinationAction.INSTANCE, TransportDeleteDestinationAction::class.java),
143-
ActionPlugin.ActionHandler(AcknowledgeAlertAction.INSTANCE, TransportAcknowledgeAlertAction::class.java)
179+
ActionPlugin.ActionHandler(AcknowledgeAlertAction.INSTANCE, TransportAcknowledgeAlertAction::class.java),
180+
ActionPlugin.ActionHandler(IndexEmailAccountAction.INSTANCE, TransportIndexEmailAccountAction::class.java),
181+
ActionPlugin.ActionHandler(GetEmailAccountAction.INSTANCE, TransportGetEmailAccountAction::class.java),
182+
ActionPlugin.ActionHandler(SearchEmailAccountAction.INSTANCE, TransportSearchEmailAccountAction::class.java),
183+
ActionPlugin.ActionHandler(DeleteEmailAccountAction.INSTANCE, TransportDeleteEmailAccountAction::class.java),
184+
ActionPlugin.ActionHandler(IndexEmailGroupAction.INSTANCE, TransportIndexEmailGroupAction::class.java),
185+
ActionPlugin.ActionHandler(GetEmailGroupAction.INSTANCE, TransportGetEmailGroupAction::class.java),
186+
ActionPlugin.ActionHandler(SearchEmailGroupAction.INSTANCE, TransportSearchEmailGroupAction::class.java),
187+
ActionPlugin.ActionHandler(DeleteEmailGroupAction.INSTANCE, TransportDeleteEmailGroupAction::class.java)
144188
)
145189
}
146190

@@ -195,7 +239,10 @@ internal class AlertingPlugin : PainlessExtension, ActionPlugin, ScriptPlugin, P
195239
AlertingSettings.ALERT_HISTORY_RETENTION_PERIOD,
196240
AlertingSettings.ALERTING_MAX_MONITORS,
197241
AlertingSettings.REQUEST_TIMEOUT,
198-
AlertingSettings.MAX_ACTION_THROTTLE_VALUE)
242+
AlertingSettings.MAX_ACTION_THROTTLE_VALUE,
243+
DestinationSettings.EMAIL_USERNAME,
244+
DestinationSettings.EMAIL_PASSWORD
245+
)
199246
}
200247

201248
override fun onIndexModule(indexModule: IndexModule) {
@@ -207,4 +254,8 @@ internal class AlertingPlugin : PainlessExtension, ActionPlugin, ScriptPlugin, P
207254
override fun getContexts(): List<ScriptContext<*>> {
208255
return listOf(TriggerScript.CONTEXT)
209256
}
257+
258+
override fun reload(settings: Settings) {
259+
runner.reloadDestinationSettings(settings)
260+
}
210261
}

alerting/src/main/kotlin/com/amazon/opendistroforelasticsearch/alerting/MonitorRunner.kt

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import com.amazon.opendistroforelasticsearch.alerting.alerts.AlertIndices
2020
import com.amazon.opendistroforelasticsearch.alerting.alerts.moveAlerts
2121
import com.amazon.opendistroforelasticsearch.alerting.core.JobRunner
2222
import com.amazon.opendistroforelasticsearch.alerting.core.model.ScheduledJob
23-
import com.amazon.opendistroforelasticsearch.alerting.core.model.ScheduledJob.Companion.SCHEDULED_JOBS_INDEX
2423
import com.amazon.opendistroforelasticsearch.alerting.core.model.SearchInput
2524
import com.amazon.opendistroforelasticsearch.alerting.elasticapi.convertToMap
2625
import com.amazon.opendistroforelasticsearch.alerting.elasticapi.firstFailureOrNull
@@ -34,6 +33,7 @@ import com.amazon.opendistroforelasticsearch.alerting.model.Alert.State.ACTIVE
3433
import com.amazon.opendistroforelasticsearch.alerting.model.Alert.State.COMPLETED
3534
import com.amazon.opendistroforelasticsearch.alerting.model.Alert.State.DELETED
3635
import com.amazon.opendistroforelasticsearch.alerting.model.Alert.State.ERROR
36+
import com.amazon.opendistroforelasticsearch.alerting.model.AlertingConfigAccessor
3737
import com.amazon.opendistroforelasticsearch.alerting.model.InputRunResults
3838
import com.amazon.opendistroforelasticsearch.alerting.model.Monitor
3939
import com.amazon.opendistroforelasticsearch.alerting.model.MonitorRunResult
@@ -43,13 +43,14 @@ import com.amazon.opendistroforelasticsearch.alerting.model.action.Action
4343
import com.amazon.opendistroforelasticsearch.alerting.model.action.Action.Companion.MESSAGE
4444
import com.amazon.opendistroforelasticsearch.alerting.model.action.Action.Companion.MESSAGE_ID
4545
import com.amazon.opendistroforelasticsearch.alerting.model.action.Action.Companion.SUBJECT
46-
import com.amazon.opendistroforelasticsearch.alerting.model.destination.Destination
46+
import com.amazon.opendistroforelasticsearch.alerting.model.destination.DestinationContextFactory
4747
import com.amazon.opendistroforelasticsearch.alerting.script.TriggerExecutionContext
4848
import com.amazon.opendistroforelasticsearch.alerting.script.TriggerScript
4949
import com.amazon.opendistroforelasticsearch.alerting.settings.AlertingSettings.Companion.ALERT_BACKOFF_COUNT
5050
import com.amazon.opendistroforelasticsearch.alerting.settings.AlertingSettings.Companion.ALERT_BACKOFF_MILLIS
5151
import com.amazon.opendistroforelasticsearch.alerting.settings.AlertingSettings.Companion.MOVE_ALERTS_BACKOFF_COUNT
5252
import com.amazon.opendistroforelasticsearch.alerting.settings.AlertingSettings.Companion.MOVE_ALERTS_BACKOFF_MILLIS
53+
import com.amazon.opendistroforelasticsearch.alerting.settings.DestinationSettings.Companion.loadDestinationSettings
5354
import com.amazon.opendistroforelasticsearch.alerting.util.IndexUtils
5455
import org.apache.logging.log4j.LogManager
5556
import kotlinx.coroutines.CoroutineScope
@@ -64,8 +65,6 @@ import org.elasticsearch.action.bulk.BackoffPolicy
6465
import org.elasticsearch.action.bulk.BulkRequest
6566
import org.elasticsearch.action.bulk.BulkResponse
6667
import org.elasticsearch.action.delete.DeleteRequest
67-
import org.elasticsearch.action.get.GetRequest
68-
import org.elasticsearch.action.get.GetResponse
6968
import org.elasticsearch.action.index.IndexRequest
7069
import org.elasticsearch.action.search.SearchRequest
7170
import org.elasticsearch.action.search.SearchResponse
@@ -115,6 +114,9 @@ class MonitorRunner(
115114
@Volatile private var moveAlertsRetryPolicy =
116115
BackoffPolicy.exponentialBackoff(MOVE_ALERTS_BACKOFF_MILLIS.get(settings), MOVE_ALERTS_BACKOFF_COUNT.get(settings))
117116

117+
@Volatile private var destinationSettings = loadDestinationSettings(settings)
118+
@Volatile private var destinationContextFactory = DestinationContextFactory(client, xContentRegistry, destinationSettings)
119+
118120
init {
119121
clusterService.clusterSettings.addSettingsUpdateConsumer(ALERT_BACKOFF_MILLIS, ALERT_BACKOFF_COUNT) {
120122
millis, count -> retryPolicy = BackoffPolicy.constantBackoff(millis, count)
@@ -124,6 +126,14 @@ class MonitorRunner(
124126
}
125127
}
126128

129+
/** Update destination settings when the reload API is called so that new keystore values are visible */
130+
fun reloadDestinationSettings(settings: Settings) {
131+
destinationSettings = loadDestinationSettings(settings)
132+
133+
// Update destinationContextFactory as well since destinationSettings has been updated
134+
destinationContextFactory.updateDestinationSettings(destinationSettings)
135+
}
136+
127137
override fun doStart() {
128138
runnerSupervisor = SupervisorJob()
129139
}
@@ -432,8 +442,13 @@ class MonitorRunner(
432442
}
433443
if (!dryrun) {
434444
withContext(Dispatchers.IO) {
435-
val destination = getDestinationInfo(action.destinationId)
436-
actionOutput[MESSAGE_ID] = destination.publish(actionOutput[SUBJECT], actionOutput[MESSAGE]!!)
445+
val destination = AlertingConfigAccessor.getDestinationInfo(client, xContentRegistry, action.destinationId)
446+
val destinationCtx = destinationContextFactory.getDestinationContext(destination)
447+
actionOutput[MESSAGE_ID] = destination.publish(
448+
actionOutput[SUBJECT],
449+
actionOutput[MESSAGE]!!,
450+
destinationCtx
451+
)
437452
}
438453
}
439454
ActionRunResult(action.id, action.name, actionOutput, false, currentTime(), null)
@@ -448,26 +463,6 @@ class MonitorRunner(
448463
.execute()
449464
}
450465

451-
private suspend fun getDestinationInfo(destinationId: String): Destination {
452-
val getRequest = GetRequest(SCHEDULED_JOBS_INDEX, destinationId).routing(destinationId)
453-
val getResponse: GetResponse = client.suspendUntil { client.get(getRequest, it) }
454-
if (!getResponse.isExists || getResponse.isSourceEmpty) {
455-
throw IllegalStateException("Destination document with id $destinationId not found or source is empty")
456-
}
457-
458-
val jobSource = getResponse.sourceAsBytesRef
459-
return withContext(Dispatchers.IO) {
460-
val xcp = XContentHelper.createParser(xContentRegistry, LoggingDeprecationHandler.INSTANCE,
461-
jobSource, XContentType.JSON)
462-
ensureExpectedToken(XContentParser.Token.START_OBJECT, xcp.nextToken(), xcp::getTokenLocation)
463-
ensureExpectedToken(XContentParser.Token.FIELD_NAME, xcp.nextToken(), xcp::getTokenLocation)
464-
ensureExpectedToken(XContentParser.Token.START_OBJECT, xcp.nextToken(), xcp::getTokenLocation)
465-
val destination = Destination.parse(xcp)
466-
ensureExpectedToken(XContentParser.Token.END_OBJECT, xcp.nextToken(), xcp::getTokenLocation)
467-
destination
468-
}
469-
}
470-
471466
private fun List<AlertError>?.update(alertError: AlertError?): List<AlertError> {
472467
return when {
473468
this == null && alertError == null -> emptyList()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package com.amazon.opendistroforelasticsearch.alerting.action
17+
18+
import org.elasticsearch.action.ActionType
19+
import org.elasticsearch.action.delete.DeleteResponse
20+
21+
class DeleteEmailAccountAction private constructor() : ActionType<DeleteResponse>(NAME, ::DeleteResponse) {
22+
companion object {
23+
val INSTANCE = DeleteEmailAccountAction()
24+
const val NAME = "cluster:admin/alerting/destination/email_account/delete"
25+
}
26+
}

0 commit comments

Comments
 (0)