diff --git a/reports-scheduler/src/main/java/org/opensearch/reportsscheduler/metrics/Metrics.java b/reports-scheduler/src/main/java/org/opensearch/reportsscheduler/metrics/Metrics.java index 903bbbcb..59b42a7d 100644 --- a/reports-scheduler/src/main/java/org/opensearch/reportsscheduler/metrics/Metrics.java +++ b/reports-scheduler/src/main/java/org/opensearch/reportsscheduler/metrics/Metrics.java @@ -156,11 +156,6 @@ public enum Metrics { REPORT_FROM_DEFINITION_ID_SYSTEM_ERROR("on_demand_from_definition.create.system_error", new RollingCounter()), - // Notifications: POST _plugins/_reports/on_demand/{reportDefinitionId} and scheduled jobs - REPORT_NOTIFICATIONS_TOTAL("report_notifications.send.total", new BasicCounter()), - REPORT_NOTIFICATIONS_ERROR("report_notifications.send.error", new RollingCounter()), - - REPORT_SECURITY_PERMISSION_ERROR("es_security_permission_error", new RollingCounter()), REPORT_PERMISSION_USER_ERROR("permission_user_error", new RollingCounter()); diff --git a/reports-scheduler/src/main/kotlin/org/opensearch/reportsscheduler/ReportsSchedulerPlugin.kt b/reports-scheduler/src/main/kotlin/org/opensearch/reportsscheduler/ReportsSchedulerPlugin.kt index 63d8ab63..5f6ad2e0 100644 --- a/reports-scheduler/src/main/kotlin/org/opensearch/reportsscheduler/ReportsSchedulerPlugin.kt +++ b/reports-scheduler/src/main/kotlin/org/opensearch/reportsscheduler/ReportsSchedulerPlugin.kt @@ -26,7 +26,6 @@ */ package org.opensearch.reportsscheduler -import org.opensearch.OpenSearchStatusException import org.opensearch.jobscheduler.spi.JobSchedulerExtension import org.opensearch.jobscheduler.spi.ScheduledJobParser import org.opensearch.jobscheduler.spi.ScheduledJobRunner @@ -56,7 +55,6 @@ import org.opensearch.reportsscheduler.settings.PluginSettings import org.opensearch.action.ActionRequest import org.opensearch.action.ActionResponse import org.opensearch.client.Client -import org.opensearch.client.node.NodeClient import org.opensearch.cluster.metadata.IndexNameExpressionResolver import org.opensearch.cluster.node.DiscoveryNodes import org.opensearch.cluster.service.ClusterService @@ -71,11 +69,9 @@ import org.opensearch.env.Environment import org.opensearch.env.NodeEnvironment import org.opensearch.plugins.ActionPlugin import org.opensearch.plugins.Plugin -import org.opensearch.reportsscheduler.notifications.NotificationsActions import org.opensearch.repositories.RepositoriesService import org.opensearch.rest.RestController import org.opensearch.rest.RestHandler -import org.opensearch.rest.RestStatus import org.opensearch.script.ScriptService import org.opensearch.threadpool.ThreadPool import org.opensearch.watcher.ResourceWatcherService @@ -122,12 +118,6 @@ class ReportsSchedulerPlugin : Plugin(), ActionPlugin, JobSchedulerExtension { PluginSettings.addSettingsUpdateConsumer(clusterService) ReportDefinitionsIndex.initialize(client, clusterService) ReportInstancesIndex.initialize(client, clusterService) - (client as? NodeClient)?.let { NotificationsActions.initialize(it) } ?: run { - throw OpenSearchStatusException( - "Unable to cast client to NodeClient for Notifications call", - RestStatus.INTERNAL_SERVER_ERROR - ) - } return emptyList() } diff --git a/reports-scheduler/src/main/kotlin/org/opensearch/reportsscheduler/notifications/MessageBuilder.kt b/reports-scheduler/src/main/kotlin/org/opensearch/reportsscheduler/notifications/MessageBuilder.kt deleted file mode 100644 index df4ceb31..00000000 --- a/reports-scheduler/src/main/kotlin/org/opensearch/reportsscheduler/notifications/MessageBuilder.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -package org.opensearch.reportsscheduler.notifications - -import org.jsoup.Jsoup -import org.jsoup.nodes.Document -import org.opensearch.commons.utils.logger -import java.util.Base64 - -/** - * Provide functions to build email message with html template, or pure text message for non-email channels - */ -internal object MessageBuilder { - private val log by logger(MessageBuilder::class.java) - - private const val LOGO_ID = "logo" - private const val REPORT_NAME_ID = "report_name" - private const val OPEN_IN_REPORTING_BUTTON_ID = "open_in_reporting_button" - private const val OPTIONAL_MESSAGE_ID = "optional_message" - private const val EMAIL_HTML_TEMPLATE_PATH = "/notifications/template/email_content_template.html" - private const val LOGO_PATH = "/notifications/template/logo.png" - // load logo and html template - private val templateHtml = javaClass.getResource(EMAIL_HTML_TEMPLATE_PATH)!!.readText() - private val logo = javaClass.getResource(LOGO_PATH)!!.readBytes() - private val encodedLogo: String = Base64.getEncoder().encodeToString(logo) - - fun buildEmailMessageWithTemplate(htmlDescription: String, reportLink: String, reportName: String): String { - val doc: Document = Jsoup.parse(templateHtml) - doc.getElementById(LOGO_ID)?.attr("src", "data:image/png;base64,$encodedLogo") - doc.getElementById(REPORT_NAME_ID)?.attr("href", reportLink)?.text(reportName) - doc.getElementById(OPEN_IN_REPORTING_BUTTON_ID)?.attr("href", reportLink) - doc.getElementById(OPTIONAL_MESSAGE_ID)?.html(htmlDescription) - - return doc.html() - } - - fun buildTextMessage(textDescription: String, reportLink: String, reportName: String): String { - return "$textDescription\nYour Report [$reportName] is now available at $reportLink" - } -} diff --git a/reports-scheduler/src/main/kotlin/org/opensearch/reportsscheduler/notifications/NotificationsActions.kt b/reports-scheduler/src/main/kotlin/org/opensearch/reportsscheduler/notifications/NotificationsActions.kt deleted file mode 100644 index 0df6e67b..00000000 --- a/reports-scheduler/src/main/kotlin/org/opensearch/reportsscheduler/notifications/NotificationsActions.kt +++ /dev/null @@ -1,171 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -package org.opensearch.reportsscheduler.notifications - -import org.opensearch.OpenSearchException -import org.opensearch.action.ActionListener -import org.opensearch.client.node.NodeClient -import org.opensearch.common.util.concurrent.ThreadContext -import org.opensearch.commons.ConfigConstants -import org.opensearch.commons.notifications.NotificationConstants.FEATURE_REPORTS -import org.opensearch.commons.notifications.NotificationsPluginInterface -import org.opensearch.commons.notifications.action.SendNotificationResponse -import org.opensearch.commons.notifications.model.ChannelMessage -import org.opensearch.commons.notifications.model.EventSource -import org.opensearch.commons.notifications.model.SeverityType -import org.opensearch.reportsscheduler.ReportsSchedulerPlugin.Companion.LOG_PREFIX -import org.opensearch.reportsscheduler.metrics.Metrics -import org.opensearch.reportsscheduler.model.CreateReportDefinitionResponse -import org.opensearch.reportsscheduler.model.ReportDefinition -import org.opensearch.reportsscheduler.util.logger - -/** - * Report definitions index operation actions. - */ -internal object NotificationsActions { - private val log by logger(NotificationsActions::class.java) - - private lateinit var client: NodeClient - - /** - * Initialize the class - * @param client NodeClient for transport call - */ - fun initialize(client: NodeClient) { - this.client = client - } - - /** - * Send notifications based on delivery parameter - * @param delivery [ReportDefinition.Delivery] object - * @param referenceId [String] object - * @return [CreateReportDefinitionResponse] - */ - fun send(delivery: ReportDefinition.Delivery, referenceId: String, reportLink: String, reportName: String): SendNotificationResponse? { - return send(delivery, referenceId, reportLink, reportName, "") - } - - /** - * Send notifications based on delivery parameter - * @param delivery [ReportDefinition.Delivery] object - * @param referenceId [String] object - * @param userStr [String] object, - * @return [CreateReportDefinitionResponse] - */ - fun send( - delivery: ReportDefinition.Delivery, - referenceId: String, - reportLink: String, - reportName: String, - userStr: String? - ): SendNotificationResponse? { - if (userStr.isNullOrEmpty()) { - return sendNotificationHelper(delivery, referenceId, reportLink, reportName) - } - - var sendNotificationResponse: SendNotificationResponse? = null - client.threadPool().threadContext.stashContext().use { - client.threadPool().threadContext.putTransient( - ConfigConstants.OPENSEARCH_SECURITY_USER_INFO_THREAD_CONTEXT, - userStr - ) - sendNotificationResponse = sendNotificationHelper(delivery, referenceId, reportLink, reportName) - } - return sendNotificationResponse - } - - @Suppress("TooGenericExceptionCaught") - private fun sendNotificationHelper( - delivery: ReportDefinition.Delivery, - referenceId: String, - reportLink: String, - reportName: String - ): SendNotificationResponse? { - log.info("$LOG_PREFIX:NotificationsActions-send") - var sendNotificationResponse: SendNotificationResponse? = null - Metrics.REPORT_NOTIFICATIONS_TOTAL.counter.increment() - try { - NotificationsPluginInterface.sendNotification( - client, - EventSource(delivery.title, referenceId, FEATURE_REPORTS, SeverityType.INFO), - ChannelMessage( - MessageBuilder.buildTextMessage(delivery.textDescription, reportLink, reportName), - delivery.htmlDescription?.let { MessageBuilder.buildEmailMessageWithTemplate(it, reportLink, reportName) }, - null - ), - delivery.configIds, - object : ActionListener { - override fun onResponse(response: SendNotificationResponse) { - sendNotificationResponse = response - log.info("$LOG_PREFIX:NotificationsActions-send:$sendNotificationResponse") - } - - override fun onFailure(exception: Exception) { - log.error("$LOG_PREFIX:NotificationsActions-send Error:$exception") - throw exception - } - } - ) - } catch (e: Exception) { - Metrics.REPORT_NOTIFICATIONS_ERROR.counter.increment() - val isMissingNotificationPlugin = e.message?.contains("failed to find action") ?: false - if (isMissingNotificationPlugin) { - throw OpenSearchException( - "Notification plugin is not installed. Please install the Notification plugin.", - e - ) - } else { - throw e - } - } - return sendNotificationResponse - } - - /** - * Executes the given [block] function on this resource and then closes it down correctly whether an exception - * is thrown or not. - * - * In case if the resource is being closed due to an exception occurred in [block], and the closing also fails with an exception, - * the latter is added to the [suppressed][java.lang.Throwable.addSuppressed] exceptions of the former. - * - * @param block a function to process this [AutoCloseable] resource. - * @return the result of [block] function invoked on this resource. - */ - @Suppress("TooGenericExceptionCaught") - private inline fun T.use(block: (T) -> R): R { - var exception: Throwable? = null - try { - return block(this) - } catch (e: Throwable) { - exception = e - throw e - } finally { - closeFinally(exception) - } - } - - /** - * Closes this [AutoCloseable], suppressing possible exception or error thrown by [AutoCloseable.close] function when - * it's being closed due to some other [cause] exception occurred. - * - * The suppressed exception is added to the list of suppressed exceptions of [cause] exception. - */ - @Suppress("TooGenericExceptionCaught") - private fun ThreadContext.StoredContext.closeFinally(cause: Throwable?) = when (cause) { - null -> close() - else -> try { - close() - } catch (closeException: Throwable) { - cause.addSuppressed(closeException) - } - } -}