diff --git a/.github/actions/reviewdog-setup b/.github/actions/reviewdog-setup index 2fc905b187..c2fa3e5a37 160000 --- a/.github/actions/reviewdog-setup +++ b/.github/actions/reviewdog-setup @@ -1 +1 @@ -Subproject commit 2fc905b1875f2e6b91c4201a4dc6eaa21b86547e +Subproject commit c2fa3e5a37b75a5819e2c8127caec1c2a0d088e8 diff --git a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-slack/src/main/java/org/apache/dolphinscheduler/plugin/alert/slack/SlackAlertChannelFactory.java b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-slack/src/main/java/org/apache/dolphinscheduler/plugin/alert/slack/SlackAlertChannelFactory.java index 9819ed4b33..f86e32933f 100644 --- a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-slack/src/main/java/org/apache/dolphinscheduler/plugin/alert/slack/SlackAlertChannelFactory.java +++ b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-slack/src/main/java/org/apache/dolphinscheduler/plugin/alert/slack/SlackAlertChannelFactory.java @@ -39,7 +39,7 @@ public final class SlackAlertChannelFactory implements AlertChannelFactory { public List params() { List paramsList = new LinkedList<>(); - InputParam webHookParam = InputParam.newBuilder(SlackParamsConstants.SLACK_WEN_HOOK_URL_NAME, SlackParamsConstants.SLACK_WEB_HOOK_URL) + InputParam webHookParam = InputParam.newBuilder(SlackParamsConstants.SLACK_WEB_HOOK_URL_NAME, SlackParamsConstants.SLACK_WEB_HOOK_URL) .addValidate(Validate.newBuilder() .setRequired(true) .build()) diff --git a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-slack/src/main/java/org/apache/dolphinscheduler/plugin/alert/slack/SlackParamsConstants.java b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-slack/src/main/java/org/apache/dolphinscheduler/plugin/alert/slack/SlackParamsConstants.java index 928eba6719..a3c9f19ac5 100644 --- a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-slack/src/main/java/org/apache/dolphinscheduler/plugin/alert/slack/SlackParamsConstants.java +++ b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-slack/src/main/java/org/apache/dolphinscheduler/plugin/alert/slack/SlackParamsConstants.java @@ -19,7 +19,7 @@ package org.apache.dolphinscheduler.plugin.alert.slack; public final class SlackParamsConstants { public static final String SLACK_WEB_HOOK_URL = "$t('webhook')"; - public static final String SLACK_WEN_HOOK_URL_NAME = "webHook"; + public static final String SLACK_WEB_HOOK_URL_NAME = "webHook"; public static final String SLACK_BOT = "$t('Username')"; public static final String SLACK_BOT_NAME = "username"; public static final String TEXT = "text"; diff --git a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-slack/src/main/java/org/apache/dolphinscheduler/plugin/alert/slack/SlackSender.java b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-slack/src/main/java/org/apache/dolphinscheduler/plugin/alert/slack/SlackSender.java index 95eeca69cb..1017c839fd 100644 --- a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-slack/src/main/java/org/apache/dolphinscheduler/plugin/alert/slack/SlackSender.java +++ b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-slack/src/main/java/org/apache/dolphinscheduler/plugin/alert/slack/SlackSender.java @@ -50,7 +50,7 @@ public final class SlackSender { private final String botName; public SlackSender(Map slackAlertParam) { - webHookUrl = slackAlertParam.get(SlackParamsConstants.SLACK_WEN_HOOK_URL_NAME); + webHookUrl = slackAlertParam.get(SlackParamsConstants.SLACK_WEB_HOOK_URL_NAME); botName = slackAlertParam.get(SlackParamsConstants.SLACK_BOT_NAME); Preconditions.checkArgument(!Objects.isNull(webHookUrl), "SlackWebHookURL can not be null"); Preconditions.checkArgument(webHookUrl.startsWith("https://hooks.slack.com/services/"), "SlackWebHookURL invalidate"); diff --git a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-slack/src/test/java/org/apache/dolphinscheduler/plugin/alert/slack/SlackSenderTest.java b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-slack/src/test/java/org/apache/dolphinscheduler/plugin/alert/slack/SlackSenderTest.java index c675aca0e8..7e261309b7 100644 --- a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-slack/src/test/java/org/apache/dolphinscheduler/plugin/alert/slack/SlackSenderTest.java +++ b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-slack/src/test/java/org/apache/dolphinscheduler/plugin/alert/slack/SlackSenderTest.java @@ -28,7 +28,7 @@ public class SlackSenderTest { @Test public void testSendMessage() { Map alertparam = new HashMap<>(); - alertparam.put(SlackParamsConstants.SLACK_WEN_HOOK_URL_NAME, + alertparam.put(SlackParamsConstants.SLACK_WEB_HOOK_URL_NAME, "https://hooks.slack.com/services/123456"); alertparam.put(SlackParamsConstants.SLACK_BOT_NAME, "Dolphinscheduler"); diff --git a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-telegram/pom.xml b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-telegram/pom.xml new file mode 100644 index 0000000000..b5685f66d3 --- /dev/null +++ b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-telegram/pom.xml @@ -0,0 +1,41 @@ + + + + + dolphinscheduler-alert-plugins + org.apache.dolphinscheduler + 2.0.4-SNAPSHOT + + 4.0.0 + dolphinscheduler-alert-telegram + jar + + + + org.apache.httpcomponents + httpclient + + + + com.google.guava + guava + + + diff --git a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-telegram/src/main/java/org/apache/dolphinscheduler/plugin/alert/telegram/TelegramAlertChannel.java b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-telegram/src/main/java/org/apache/dolphinscheduler/plugin/alert/telegram/TelegramAlertChannel.java new file mode 100644 index 0000000000..26db453dd4 --- /dev/null +++ b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-telegram/src/main/java/org/apache/dolphinscheduler/plugin/alert/telegram/TelegramAlertChannel.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.plugin.alert.telegram; + +import org.apache.dolphinscheduler.alert.api.AlertChannel; +import org.apache.dolphinscheduler.alert.api.AlertData; +import org.apache.dolphinscheduler.alert.api.AlertInfo; +import org.apache.dolphinscheduler.alert.api.AlertResult; + +import java.util.Map; + +public final class TelegramAlertChannel implements AlertChannel { + @Override + public AlertResult process(AlertInfo info) { + Map alertParams = info.getAlertParams(); + if (alertParams == null || alertParams.isEmpty()) { + return new AlertResult("false", "Telegram alert params is empty"); + } + AlertData data = info.getAlertData(); + return new TelegramSender(alertParams).sendMessage(data); + } +} diff --git a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-telegram/src/main/java/org/apache/dolphinscheduler/plugin/alert/telegram/TelegramAlertChannelFactory.java b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-telegram/src/main/java/org/apache/dolphinscheduler/plugin/alert/telegram/TelegramAlertChannelFactory.java new file mode 100644 index 0000000000..f282cb5153 --- /dev/null +++ b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-telegram/src/main/java/org/apache/dolphinscheduler/plugin/alert/telegram/TelegramAlertChannelFactory.java @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.plugin.alert.telegram; + +import com.google.auto.service.AutoService; +import org.apache.dolphinscheduler.alert.api.AlertChannel; +import org.apache.dolphinscheduler.alert.api.AlertChannelFactory; +import org.apache.dolphinscheduler.spi.params.PasswordParam; +import org.apache.dolphinscheduler.spi.params.base.ParamsOptions; +import org.apache.dolphinscheduler.spi.params.base.PluginParams; +import org.apache.dolphinscheduler.spi.params.base.Validate; +import org.apache.dolphinscheduler.spi.params.input.InputParam; +import org.apache.dolphinscheduler.spi.params.radio.RadioParam; +import org.apache.dolphinscheduler.spi.params.select.SelectParam; + +import java.util.Arrays; +import java.util.List; + +import static org.apache.dolphinscheduler.spi.utils.Constants.*; + +@AutoService(AlertChannelFactory.class) +public final class TelegramAlertChannelFactory implements AlertChannelFactory { + + @Override + public String name() { + return "Telegram"; + } + + @Override + public AlertChannel create() { + return new TelegramAlertChannel(); + } + + @Override + public List params() { + + + InputParam webHookParam = InputParam.newBuilder(TelegramParamsConstants.NAME_TELEGRAM_WEB_HOOK, TelegramParamsConstants.TELEGRAM_WEB_HOOK) + .addValidate(Validate.newBuilder() + .setRequired(true) + .build()) + .setPlaceholder("telegram web hook") + .build(); + + InputParam botTokenParam = InputParam.newBuilder(TelegramParamsConstants.NAME_TELEGRAM_BOT_TOKEN, TelegramParamsConstants.TELEGRAM_BOT_TOKEN) + .addValidate(Validate.newBuilder() + .setRequired(true) + .build()) + .setPlaceholder("telegram bot token") + .build(); + + InputParam chatIdParam = InputParam.newBuilder(TelegramParamsConstants.NAME_TELEGRAM_CHAT_ID, TelegramParamsConstants.TELEGRAM_CHAT_ID) + .addValidate(Validate.newBuilder() + .setRequired(true) + .build()) + .setPlaceholder("telegram channel chat id") + .build(); + + SelectParam parseMode = SelectParam.newBuilder(TelegramParamsConstants.NAME_TELEGRAM_PARSE_MODE, TelegramParamsConstants.TELEGRAM_PARSE_MODE) + .addOptions(new ParamsOptions(TelegramAlertConstants.PARSE_MODE_TXT, TelegramAlertConstants.PARSE_MODE_TXT, false)) + .addOptions(new ParamsOptions(TelegramAlertConstants.PARSE_MODE_MARKDOWN, TelegramAlertConstants.PARSE_MODE_MARKDOWN, false)) + .addOptions(new ParamsOptions(TelegramAlertConstants.PARSE_MODE_MARKDOWN_V2, TelegramAlertConstants.PARSE_MODE_MARKDOWN_V2, false)) + .addOptions(new ParamsOptions(TelegramAlertConstants.PARSE_MODE_HTML, TelegramAlertConstants.PARSE_MODE_HTML, false)) + .setValue(TelegramAlertConstants.PARSE_MODE_TXT) + .addValidate(Validate.newBuilder() + .setRequired(true) + .build()) + .build(); + + RadioParam isEnableProxy = RadioParam.newBuilder(TelegramParamsConstants.NAME_TELEGRAM_PROXY_ENABLE, TelegramParamsConstants.TELEGRAM_PROXY_ENABLE) + .addParamsOptions(new ParamsOptions(STRING_YES, STRING_TRUE, false)) + .addParamsOptions(new ParamsOptions(STRING_NO, STRING_FALSE, false)) + .setValue(STRING_FALSE) + .addValidate(Validate.newBuilder() + .setRequired(false) + .build()) + .build(); + + InputParam proxyParam = InputParam.newBuilder(TelegramParamsConstants.NAME_TELEGRAM_PROXY, TelegramParamsConstants.TELEGRAM_PROXY) + .addValidate(Validate.newBuilder() + .setRequired(false) + .build()) + .build(); + + InputParam portParam = InputParam.newBuilder(TelegramParamsConstants.NAME_TELEGRAM_PORT, TelegramParamsConstants.TELEGRAM_PORT) + .addValidate(Validate.newBuilder() + .setRequired(false) + .build()) + .build(); + + InputParam userParam = InputParam.newBuilder(TelegramParamsConstants.NAME_TELEGRAM_USER, TelegramParamsConstants.TELEGRAM_USER) + .addValidate(Validate.newBuilder() + .setRequired(false) + .build()) + .build(); + + PasswordParam passwordParam = PasswordParam.newBuilder(TelegramParamsConstants.NAME_TELEGRAM_PASSWORD, TelegramParamsConstants.TELEGRAM_PASSWORD) + .addValidate(Validate.newBuilder() + .setRequired(false) + .build()) + .setPlaceholder("if enable use authentication, you need input password") + .build(); + + return Arrays.asList(webHookParam, botTokenParam, chatIdParam, parseMode, isEnableProxy, proxyParam, portParam, userParam, passwordParam); + } + + +} diff --git a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-telegram/src/main/java/org/apache/dolphinscheduler/plugin/alert/telegram/TelegramAlertConstants.java b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-telegram/src/main/java/org/apache/dolphinscheduler/plugin/alert/telegram/TelegramAlertConstants.java new file mode 100644 index 0000000000..30925069bd --- /dev/null +++ b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-telegram/src/main/java/org/apache/dolphinscheduler/plugin/alert/telegram/TelegramAlertConstants.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.plugin.alert.telegram; + +public final class TelegramAlertConstants { + + static final String PARSE_MODE_TXT = "Txt"; + + static final String PARSE_MODE_MARKDOWN = "Markdown"; + + static final String PARSE_MODE_MARKDOWN_V2 = "MarkdownV2"; + + static final String PARSE_MODE_HTML = "Html"; + + /** + * TELEGRAM_PUSH_URL + * + *
+     *     https://api.telegram.org/bot{botToken}/sendMessage
+     * 
+ */ + static final String TELEGRAM_PUSH_URL = "https://api.telegram.org/bot{botToken}/sendMessage"; + + private TelegramAlertConstants() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } +} diff --git a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-telegram/src/main/java/org/apache/dolphinscheduler/plugin/alert/telegram/TelegramParamsConstants.java b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-telegram/src/main/java/org/apache/dolphinscheduler/plugin/alert/telegram/TelegramParamsConstants.java new file mode 100644 index 0000000000..d9fbb3f218 --- /dev/null +++ b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-telegram/src/main/java/org/apache/dolphinscheduler/plugin/alert/telegram/TelegramParamsConstants.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.plugin.alert.telegram; + + +public final class TelegramParamsConstants { + + static final String TELEGRAM_WEB_HOOK = "$t('webHook')"; + static final String NAME_TELEGRAM_WEB_HOOK = "webHook"; + + static final String TELEGRAM_BOT_TOKEN = "botToken"; + static final String NAME_TELEGRAM_BOT_TOKEN = "botToken"; + + static final String TELEGRAM_CHAT_ID = "chatId"; + static final String NAME_TELEGRAM_CHAT_ID = "chatId"; + + static final String TELEGRAM_PARSE_MODE = "parseMode"; + static final String NAME_TELEGRAM_PARSE_MODE = "parseMode"; + + static final String TELEGRAM_PROXY_ENABLE = "$t('isEnableProxy')"; + static final String NAME_TELEGRAM_PROXY_ENABLE = "IsEnableProxy"; + + static final String TELEGRAM_PROXY = "$t('proxy')"; + static final String NAME_TELEGRAM_PROXY = "Proxy"; + + static final String TELEGRAM_PORT = "$t('port')"; + static final String NAME_TELEGRAM_PORT = "Port"; + + static final String TELEGRAM_USER = "$t('user')"; + static final String NAME_TELEGRAM_USER = "User"; + + static final String TELEGRAM_PASSWORD = "$t('password')"; + static final String NAME_TELEGRAM_PASSWORD = "Password"; + + private TelegramParamsConstants() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } + +} diff --git a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-telegram/src/main/java/org/apache/dolphinscheduler/plugin/alert/telegram/TelegramSender.java b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-telegram/src/main/java/org/apache/dolphinscheduler/plugin/alert/telegram/TelegramSender.java new file mode 100644 index 0000000000..dd9ac0df57 --- /dev/null +++ b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-telegram/src/main/java/org/apache/dolphinscheduler/plugin/alert/telegram/TelegramSender.java @@ -0,0 +1,251 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.plugin.alert.telegram; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.dolphinscheduler.alert.api.AlertData; +import org.apache.dolphinscheduler.alert.api.AlertResult; +import org.apache.dolphinscheduler.spi.utils.JSONUtils; +import org.apache.http.HttpEntity; +import org.apache.http.HttpHeaders; +import org.apache.http.HttpHost; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.client.CredentialsProvider; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.BasicCredentialsProvider; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +public final class TelegramSender { + + private static final Logger logger = LoggerFactory.getLogger(TelegramSender.class); + + private static final String BOT_TOKEN_REGEX = "{botToken}"; + + private final String chatId; + + private final String parseMode; + + private final Boolean enableProxy; + + private String botToken; + + private String url; + + private String proxy; + + private Integer port; + + private String user; + + private String password; + + + TelegramSender(Map config) { + url = config.get(TelegramParamsConstants.NAME_TELEGRAM_WEB_HOOK); + botToken = config.get(TelegramParamsConstants.NAME_TELEGRAM_BOT_TOKEN); + chatId = config.get(TelegramParamsConstants.NAME_TELEGRAM_CHAT_ID); + parseMode = config.get(TelegramParamsConstants.NAME_TELEGRAM_PARSE_MODE); + if (url == null || url.isEmpty()) { + url = TelegramAlertConstants.TELEGRAM_PUSH_URL.replace(BOT_TOKEN_REGEX, botToken); + } else { + url = url.replace(BOT_TOKEN_REGEX, botToken); + } + enableProxy = Boolean.valueOf(config.get(TelegramParamsConstants.NAME_TELEGRAM_PROXY_ENABLE)); + if (Boolean.TRUE.equals(enableProxy)) { + port = Integer.parseInt(config.get(TelegramParamsConstants.NAME_TELEGRAM_PORT)); + proxy = config.get(TelegramParamsConstants.NAME_TELEGRAM_PROXY); + user = config.get(TelegramParamsConstants.NAME_TELEGRAM_USER); + password = config.get(TelegramParamsConstants.NAME_TELEGRAM_PASSWORD); + } + } + + /** + * sendMessage + * + * @param alertData alert data + * @return alert result + * @see telegram bot api + */ + public AlertResult sendMessage(AlertData alertData) { + AlertResult result; + try { + String resp = sendInvoke(alertData.getTitle(), alertData.getContent()); + result = parseRespToResult(resp); + } catch (Exception e) { + logger.warn("send telegram alert msg exception : {}", e.getMessage()); + result = new AlertResult(); + result.setStatus("false"); + result.setMessage(String.format("send telegram alert fail. %s", e.getMessage())); + } + return result; + } + + private AlertResult parseRespToResult(String resp) { + AlertResult result = new AlertResult(); + result.setStatus("false"); + if (null == resp || resp.isEmpty()) { + result.setMessage("send telegram msg error. telegram server resp is empty"); + return result; + } + TelegramSendMsgResponse response = JSONUtils.parseObject(resp, TelegramSendMsgResponse.class); + if (null == response) { + result.setMessage("send telegram msg fail."); + return result; + } + if (!response.isOk()) { + result.setMessage(String.format("send telegram alert fail. telegram server error_code: %d, description: %s", + response.errorCode, response.description)); + } else { + result.setStatus("true"); + result.setMessage("send telegram msg success."); + } + return result; + } + + + private String sendInvoke(String title, String content) throws IOException { + HttpPost httpPost = buildHttpPost(url, buildMsgJsonStr(content)); + CloseableHttpClient httpClient; + if (Boolean.TRUE.equals(enableProxy)) { + httpClient = getProxyClient(proxy, port, user, password); + RequestConfig rcf = getProxyConfig(proxy, port); + httpPost.setConfig(rcf); + } else { + httpClient = getDefaultClient(); + } + + try { + CloseableHttpResponse response = httpClient.execute(httpPost); + String resp; + try { + HttpEntity entity = response.getEntity(); + resp = EntityUtils.toString(entity, "UTF-8"); + EntityUtils.consume(entity); + } finally { + response.close(); + } + logger.info("Telegram send title :{},content : {}, resp: {}", title, content, resp); + return resp; + } finally { + httpClient.close(); + } + } + + private String buildMsgJsonStr(String content) { + Map items = new HashMap<>(); + items.put("chat_id", chatId); + if (!isTextParseMode()) { + items.put("parse_mode", parseMode); + } + items.put("text", content); + return JSONUtils.toJsonString(items); + } + + private boolean isTextParseMode() { + return null == parseMode || TelegramAlertConstants.PARSE_MODE_TXT.equals(parseMode); + } + + static class TelegramSendMsgResponse { + @JsonProperty("ok") + private Boolean ok; + @JsonProperty("error_code") + private Integer errorCode; + @JsonProperty("description") + private String description; + @JsonProperty("result") + private Object result; + + public boolean isOk() { + return null != ok && ok; + } + + public Boolean getOk() { + return ok; + } + + @JsonProperty("ok") + public void setOk(Boolean ok) { + this.ok = ok; + } + + @JsonProperty("error_code") + public void setErrorCode(Integer errorCode) { + this.errorCode = errorCode; + } + + public Integer getErrorCode() { + return errorCode; + } + + public String getDescription() { + return description; + } + + @JsonProperty("description") + public void setDescription(String description) { + this.description = description; + } + + public Object getResult() { + return result; + } + + @JsonProperty("result") + public void setResult(Object result) { + this.result = result; + } + } + + private static HttpPost buildHttpPost(String url, String msg) { + HttpPost post = new HttpPost(url); + StringEntity entity = new StringEntity(msg, StandardCharsets.UTF_8); + post.setEntity(entity); + post.addHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString()); + return post; + } + + private static CloseableHttpClient getDefaultClient() { + return HttpClients.createDefault(); + } + + private static CloseableHttpClient getProxyClient(String proxy, int port, String user, String password) { + HttpHost httpProxy = new HttpHost(proxy, port); + CredentialsProvider provider = new BasicCredentialsProvider(); + provider.setCredentials(new AuthScope(httpProxy), new UsernamePasswordCredentials(user, password)); + return HttpClients.custom().setDefaultCredentialsProvider(provider).build(); + } + + private static RequestConfig getProxyConfig(String proxy, int port) { + HttpHost httpProxy = new HttpHost(proxy, port); + return RequestConfig.custom().setProxy(httpProxy).build(); + } +} diff --git a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-telegram/src/test/java/org/apache/dolphinscheduler/plugin/alert/telegram/TelegramAlertChannelFactoryTest.java b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-telegram/src/test/java/org/apache/dolphinscheduler/plugin/alert/telegram/TelegramAlertChannelFactoryTest.java new file mode 100644 index 0000000000..0ffe062bf4 --- /dev/null +++ b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-telegram/src/test/java/org/apache/dolphinscheduler/plugin/alert/telegram/TelegramAlertChannelFactoryTest.java @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.plugin.alert.telegram; + +import org.apache.dolphinscheduler.alert.api.AlertChannel; +import org.apache.dolphinscheduler.spi.params.base.PluginParams; +import org.junit.Assert; +import org.junit.Test; + +import java.util.List; + +public class TelegramAlertChannelFactoryTest { + + private TelegramAlertChannelFactory telegramAlertChannelFactory = new TelegramAlertChannelFactory(); + + @Test + public void testTestGetName() { + Assert.assertEquals("Telegram", telegramAlertChannelFactory.name()); + } + + @Test + public void testGetParams() { + List params = telegramAlertChannelFactory.params(); + Assert.assertEquals(9, params.size()); + } + + @Test + public void testCreate() { + AlertChannel alertChannel = telegramAlertChannelFactory.create(); + Assert.assertTrue(alertChannel instanceof TelegramAlertChannel); + } +} diff --git a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-telegram/src/test/java/org/apache/dolphinscheduler/plugin/alert/telegram/TelegramSenderTest.java b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-telegram/src/test/java/org/apache/dolphinscheduler/plugin/alert/telegram/TelegramSenderTest.java new file mode 100644 index 0000000000..8ebd6fcd9d --- /dev/null +++ b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-telegram/src/test/java/org/apache/dolphinscheduler/plugin/alert/telegram/TelegramSenderTest.java @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.plugin.alert.telegram; + +import org.apache.dolphinscheduler.alert.api.AlertData; +import org.apache.dolphinscheduler.alert.api.AlertResult; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +public class TelegramSenderTest { + + private static Map telegramConfig = new HashMap<>(); + + @Before + public void initConfig() { + telegramConfig.put(TelegramParamsConstants.NAME_TELEGRAM_WEB_HOOK, + "https://api.telegram.org/bot{botToken}/sendMessage"); + telegramConfig.put( + TelegramParamsConstants.NAME_TELEGRAM_BOT_TOKEN, "BOT_TOKEN"); + telegramConfig.put( + TelegramParamsConstants.NAME_TELEGRAM_CHAT_ID, "CHAT_ID"); + telegramConfig.put( + TelegramParamsConstants.NAME_TELEGRAM_PARSE_MODE, TelegramAlertConstants.PARSE_MODE_TXT); + } + + + @Test + public void testSendMessageFailByParamToken() { + AlertData alertData = new AlertData(); + alertData.setTitle("[telegram alert] test title"); + alertData.setContent("telegram test content"); + telegramConfig.put( + TelegramParamsConstants.NAME_TELEGRAM_BOT_TOKEN, "XXXXXXX"); + TelegramSender telegramSender = new TelegramSender(telegramConfig); + AlertResult result = telegramSender.sendMessage(alertData); + Assert.assertEquals("false", result.getStatus()); + + } + + @Test + public void testSendMessageFailByChatId() { + AlertData alertData = new AlertData(); + alertData.setTitle("[telegram alert] test title"); + alertData.setContent("telegram test content"); + telegramConfig.put( + TelegramParamsConstants.NAME_TELEGRAM_CHAT_ID, "-XXXXXXX"); + TelegramSender telegramSender = new TelegramSender(telegramConfig); + AlertResult result = telegramSender.sendMessage(alertData); + Assert.assertEquals("false", result.getStatus()); + } + + + + @Test + public void testSendMessage() { + AlertData alertData = new AlertData(); + alertData.setTitle("[telegram alert] test title"); + alertData.setContent("telegram test content"); + TelegramSender telegramSender = new TelegramSender(telegramConfig); + AlertResult result = telegramSender.sendMessage(alertData); + Assert.assertEquals("false", result.getStatus()); + + } + + @Test + public void testSendMessageByMarkdown() { + AlertData alertData = new AlertData(); + alertData.setTitle("[telegram alert]test markdown"); + alertData.setContent("```python \npre-formatted fixed-width code block written in the Python programming language```"); + telegramConfig.put( + TelegramParamsConstants.NAME_TELEGRAM_PARSE_MODE, TelegramAlertConstants.PARSE_MODE_MARKDOWN); + TelegramSender telegramSender = new TelegramSender(telegramConfig); + AlertResult result = telegramSender.sendMessage(alertData); + Assert.assertEquals("false", result.getStatus()); + + } + + @Test + public void testSendMessageByHtml() { + AlertData alertData = new AlertData(); + alertData.setTitle("[telegram alert]test html"); + alertData.setContent("bold"); + telegramConfig.put( + TelegramParamsConstants.NAME_TELEGRAM_PARSE_MODE, TelegramAlertConstants.PARSE_MODE_HTML); + TelegramSender telegramSender = new TelegramSender(telegramConfig); + AlertResult result = telegramSender.sendMessage(alertData); + Assert.assertEquals("false", result.getStatus()); + + } + + +} diff --git a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/pom.xml b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/pom.xml index c3b9be85ff..42f2db2294 100644 --- a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/pom.xml +++ b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/pom.xml @@ -37,6 +37,7 @@ dolphinscheduler-alert-slack dolphinscheduler-alert-pagerduty dolphinscheduler-alert-webexteams + dolphinscheduler-alert-telegram diff --git a/dolphinscheduler-alert/dolphinscheduler-alert-server/pom.xml b/dolphinscheduler-alert/dolphinscheduler-alert-server/pom.xml index 8be15f4fb6..750ea50a45 100644 --- a/dolphinscheduler-alert/dolphinscheduler-alert-server/pom.xml +++ b/dolphinscheduler-alert/dolphinscheduler-alert-server/pom.xml @@ -75,6 +75,11 @@ dolphinscheduler-alert-webexteams + + org.apache.dolphinscheduler + dolphinscheduler-alert-telegram + + org.apache.dolphinscheduler dolphinscheduler-dao diff --git a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts index db1fb23ca9..dd49a2190c 100644 --- a/dolphinscheduler-ui-next/src/locales/modules/en_US.ts +++ b/dolphinscheduler-ui-next/src/locales/modules/en_US.ts @@ -664,7 +664,10 @@ const security = { path: 'Script Path', type: 'Type', sendType: 'Send Type', - username: 'Username' + username: 'Username', + botToken: 'Bot Token', + chatId: 'Channel Chat Id', + parseMode: 'Parse Mode' } } diff --git a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts index 20c41a870f..3878cddc92 100644 --- a/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts +++ b/dolphinscheduler-ui-next/src/locales/modules/zh_CN.ts @@ -660,7 +660,10 @@ const security = { path: '脚本路径', type: '类型', sendType: '发送类型', - username: '用户名' + username: '用户名', + botToken: '机器人Token', + chatId: '频道ID', + parseMode: '解析类型' } } diff --git a/pom.xml b/pom.xml index e2cae23b4d..9c7bcebac9 100644 --- a/pom.xml +++ b/pom.xml @@ -362,6 +362,11 @@ dolphinscheduler-alert-webexteams ${project.version} + + org.apache.dolphinscheduler + dolphinscheduler-alert-telegram + ${project.version} + org.apache.dolphinscheduler dolphinscheduler-registry-api