diff --git a/docs/docs/en/guide/alert/http.md b/docs/docs/en/guide/alert/http.md index ba5c009211..f765b9db0c 100644 --- a/docs/docs/en/guide/alert/http.md +++ b/docs/docs/en/guide/alert/http.md @@ -7,25 +7,16 @@ If you need to use `Http script` for alerting, create an alert instance in the a | **Parameter** | **Description** | |---------------|-----------------------------------------------------------------------------------------------------| | URL | The `Http` request URL needs to contain protocol, host, path and parameters if the method is `GET`. | -| Request Type | Select the request type from `POST` or `GET`. | -| Headers | The headers of the `Http` request in JSON format. | -| Body | The request body of the `Http` request in JSON format, when using `POST` method to alert. | -| Content Field | The field name to place the alert information. | +| Request Type | Select the request type from `POST` or `GET` or `PUT`. | +| Headers | The headers of the `Http` request in JSON format. Not including content-type. | +| Body | The request body of the `Http` request in JSON format, when using `POST` or `PUT` method to alert. | +| Content Type | The content-type of header. | -## Send Type - -Using `POST` and `GET` method to send `Http` request in the `Request Type`. +> Alarm message supports variables `$msg`, which can be used in `URL`, `Headers`, and `Body`. ### GET HTTP Send alert information by `Http` GET method. The following shows the `GET` configuration example: -![enterprise-wechat-app-msg-config](../../../../img/alert/http-get-example.png) - -### POST HTTP - -Send alert information inside `Http` body by `Http` POST method. -The following shows the `POST` configuration example: - -![enterprise-wechat-app-msg-config](../../../../img/alert/http-post-example.png) +![http-alert-msg-config](../../../../img/alert/http-alert-example.png) diff --git a/docs/docs/zh/guide/alert/http.md b/docs/docs/zh/guide/alert/http.md index 9f72723d6c..51524ac786 100644 --- a/docs/docs/zh/guide/alert/http.md +++ b/docs/docs/zh/guide/alert/http.md @@ -4,40 +4,19 @@ ## 参数配置 -* URL +| **参数** | **描述** | +|--------------|------------------------------------------------| +| URL | 访问的`Http`连接URL,需要包含协议、Host、路径,如果是GET方法可以添加参数 | +| 请求方式 | 当前支持`GET`和`POST`以及`PUT`三种请求方式 | +| 请求头(Headers) | `Http`请求的完整请求头,以JSON为格式(注意不包含Content-Type),非必填 | +| 请求体(Body) | Http`请求的完整请求体,以JSON为格式,非必填 | +| Content-Type | 请求体的`Content-Type`,默认为`application/json` | - > 访问的`Http`连接URL,需要包含协议、Host、路径,如果是GET方法可以添加参数 - -* 请求方式 - - > 选择该请求为POST或GET方法 - -* 请求头 - - > `Http`请求的完整请求头,以JSON为格式 - -* 请求体 - - > `Http`请求的完整请求体,以JSON为格式,GET方法不需要写该参数 - -* 内容字段 - - > 放置本次告警告警信息的字段名称 - -## 发送类型 - -其中`Request Type`分别对应使用`POST`方法和`GET`方法进行`Http`告警。 +> 告警消息,支持变量`$msg`,可在`URL`,`请求头`,`请求体`中使用,非必填。 ### GET Http告警 GET `Http`告警指将告警结果作为参数通过`Http` GET方法进行请求。 下图是GET告警配置的示例: -![enterprise-wechat-app-msg-config](../../../../img/alert/http-get-example.png) - -### POST Http告警 - -POST `Http`告警指将告警结果作为`BODY`参数通过`Http`POST方法进行请求。 -下图是POST告警配置的示例: - -![enterprise-wechat-app-msg-config](../../../../img/alert/http-post-example.png) +![http-alert-msg-config](../../../../img/alert/http-alert-example.png) diff --git a/docs/img/alert/http-alert-example.png b/docs/img/alert/http-alert-example.png new file mode 100644 index 0000000000..b2fd5e4576 Binary files /dev/null and b/docs/img/alert/http-alert-example.png differ diff --git a/docs/img/alert/http-get-example.png b/docs/img/alert/http-get-example.png deleted file mode 100644 index a6c29b48c9..0000000000 Binary files a/docs/img/alert/http-get-example.png and /dev/null differ diff --git a/docs/img/alert/http-post-example.png b/docs/img/alert/http-post-example.png deleted file mode 100644 index 5cf0d3e64d..0000000000 Binary files a/docs/img/alert/http-post-example.png and /dev/null differ diff --git a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-http/pom.xml b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-http/pom.xml index 3ce4dfd186..274ec7f1d9 100644 --- a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-http/pom.xml +++ b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-http/pom.xml @@ -41,5 +41,17 @@ jackson-databind provided + + + com.squareup.okhttp3 + mockwebserver + test + + + junit + junit + + + diff --git a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-http/src/main/java/org/apache/dolphinscheduler/plugin/alert/http/HttpAlertChannelFactory.java b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-http/src/main/java/org/apache/dolphinscheduler/plugin/alert/http/HttpAlertChannelFactory.java index 0e117b0f20..3b7dc84d4b 100644 --- a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-http/src/main/java/org/apache/dolphinscheduler/plugin/alert/http/HttpAlertChannelFactory.java +++ b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-http/src/main/java/org/apache/dolphinscheduler/plugin/alert/http/HttpAlertChannelFactory.java @@ -20,11 +20,14 @@ package org.apache.dolphinscheduler.plugin.alert.http; import org.apache.dolphinscheduler.alert.api.AlertChannel; import org.apache.dolphinscheduler.alert.api.AlertChannelFactory; import org.apache.dolphinscheduler.alert.api.AlertInputTips; +import org.apache.dolphinscheduler.common.model.OkHttpRequestHeaderContentType; import org.apache.dolphinscheduler.spi.params.base.DataType; +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.input.number.InputNumberParam; +import org.apache.dolphinscheduler.spi.params.radio.RadioParam; import java.util.Arrays; import java.util.List; @@ -52,35 +55,42 @@ public final class HttpAlertChannelFactory implements AlertChannelFactory { InputParam headerParams = InputParam.newBuilder(HttpAlertConstants.NAME_HEADER_PARAMS, HttpAlertConstants.HEADER_PARAMS) .setPlaceholder(AlertInputTips.HEADER.getMsg()) - .addValidate(Validate.newBuilder() - .setRequired(true) - .build()) - .build(); - - InputParam bodyParams = - InputParam.newBuilder(HttpAlertConstants.NAME_BODY_PARAMS, HttpAlertConstants.BODY_PARAMS) - .setPlaceholder(AlertInputTips.JSON_BODY.getMsg()) .addValidate(Validate.newBuilder() .setRequired(false) .build()) .build(); - InputParam contentField = - InputParam.newBuilder(HttpAlertConstants.NAME_CONTENT_FIELD, HttpAlertConstants.CONTENT_FIELD) - .setPlaceholder(AlertInputTips.FIELD_NAME.getMsg()) + RadioParam contentType = + RadioParam.newBuilder(HttpAlertConstants.NAME_CONTENT_TYPE, HttpAlertConstants.CONTENT_TYPE) + .addParamsOptions(new ParamsOptions(OkHttpRequestHeaderContentType.APPLICATION_JSON.getValue(), + OkHttpRequestHeaderContentType.APPLICATION_JSON.getValue(), false)) + .addParamsOptions( + new ParamsOptions(OkHttpRequestHeaderContentType.APPLICATION_FORM_URLENCODED.getValue(), + OkHttpRequestHeaderContentType.APPLICATION_FORM_URLENCODED.getValue(), false)) + .setValue(OkHttpRequestHeaderContentType.APPLICATION_JSON.getValue()) .addValidate(Validate.newBuilder() .setRequired(true) .build()) .build(); - InputParam requestType = - InputParam.newBuilder(HttpAlertConstants.NAME_REQUEST_TYPE, HttpAlertConstants.REQUEST_TYPE) - .setPlaceholder(AlertInputTips.HTTP_METHOD.getMsg()) + InputParam bodyParams = + InputParam.newBuilder(HttpAlertConstants.NAME_BODY_PARAMS, HttpAlertConstants.BODY_PARAMS) + .setPlaceholder(AlertInputTips.JSON_BODY.getMsg()) .addValidate(Validate.newBuilder() - .setRequired(true) + .setRequired(false) .build()) .build(); + RadioParam requestType = RadioParam + .newBuilder(HttpAlertConstants.NAME_REQUEST_TYPE, HttpAlertConstants.REQUEST_TYPE) + .addParamsOptions(new ParamsOptions(HttpRequestMethod.GET.name(), HttpRequestMethod.GET.name(), false)) + .addParamsOptions( + new ParamsOptions(HttpRequestMethod.POST.name(), HttpRequestMethod.POST.name(), false)) + .addParamsOptions(new ParamsOptions(HttpRequestMethod.PUT.name(), HttpRequestMethod.PUT.name(), false)) + .setValue(HttpRequestMethod.GET.name()) + .addValidate(Validate.newBuilder().setRequired(true).build()) + .build(); + InputNumberParam timeout = InputNumberParam.newBuilder(HttpAlertConstants.NAME_TIMEOUT, HttpAlertConstants.TIMEOUT) .setValue(HttpAlertConstants.DEFAULT_TIMEOUT) @@ -90,7 +100,7 @@ public final class HttpAlertChannelFactory implements AlertChannelFactory { .build()) .build(); - return Arrays.asList(url, requestType, headerParams, bodyParams, contentField, timeout); + return Arrays.asList(url, requestType, headerParams, bodyParams, contentType, timeout); } @Override diff --git a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-http/src/main/java/org/apache/dolphinscheduler/plugin/alert/http/HttpAlertConstants.java b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-http/src/main/java/org/apache/dolphinscheduler/plugin/alert/http/HttpAlertConstants.java index ab4e6dd1c1..775bc03860 100644 --- a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-http/src/main/java/org/apache/dolphinscheduler/plugin/alert/http/HttpAlertConstants.java +++ b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-http/src/main/java/org/apache/dolphinscheduler/plugin/alert/http/HttpAlertConstants.java @@ -17,6 +17,9 @@ package org.apache.dolphinscheduler.plugin.alert.http; +import lombok.experimental.UtilityClass; + +@UtilityClass public final class HttpAlertConstants { public static final String URL = "$t('url')"; @@ -27,6 +30,10 @@ public final class HttpAlertConstants { public static final String NAME_HEADER_PARAMS = "headerParams"; + public static final String CONTENT_TYPE = "$t('contentType')"; + + public static final String NAME_CONTENT_TYPE = "contentType"; + public static final String BODY_PARAMS = "$t('bodyParams')"; public static final String NAME_BODY_PARAMS = "bodyParams"; @@ -45,7 +52,5 @@ public final class HttpAlertConstants { public static final int DEFAULT_TIMEOUT = 120; - private HttpAlertConstants() { - throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); - } + public static final String MSG_PARAMS = "${msg}"; } diff --git a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-http/src/main/java/org/apache/dolphinscheduler/plugin/alert/http/HttpRequestMethod.java b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-http/src/main/java/org/apache/dolphinscheduler/plugin/alert/http/HttpRequestMethod.java new file mode 100644 index 0000000000..1f8b3a27b5 --- /dev/null +++ b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-http/src/main/java/org/apache/dolphinscheduler/plugin/alert/http/HttpRequestMethod.java @@ -0,0 +1,22 @@ +/* + * 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.http; + +public enum HttpRequestMethod { + GET, POST, PUT +} diff --git a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-http/src/main/java/org/apache/dolphinscheduler/plugin/alert/http/HttpSender.java b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-http/src/main/java/org/apache/dolphinscheduler/plugin/alert/http/HttpSender.java index e2a6606a39..42f1474de4 100644 --- a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-http/src/main/java/org/apache/dolphinscheduler/plugin/alert/http/HttpSender.java +++ b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-http/src/main/java/org/apache/dolphinscheduler/plugin/alert/http/HttpSender.java @@ -18,146 +18,172 @@ package org.apache.dolphinscheduler.plugin.alert.http; import org.apache.dolphinscheduler.alert.api.AlertResult; -import org.apache.dolphinscheduler.alert.api.HttpServiceRetryStrategy; +import org.apache.dolphinscheduler.common.model.OkHttpRequestHeaderContentType; +import org.apache.dolphinscheduler.common.model.OkHttpRequestHeaders; +import org.apache.dolphinscheduler.common.model.OkHttpResponse; import org.apache.dolphinscheduler.common.utils.JSONUtils; +import org.apache.dolphinscheduler.common.utils.OkHttpUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.http.HttpEntity; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.CloseableHttpResponse; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.methods.HttpRequestBase; -import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.util.EntityUtils; +import org.apache.http.HttpStatus; import java.io.UnsupportedEncodingException; -import java.net.MalformedURLException; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; +import java.util.Collections; import java.util.HashMap; import java.util.Map; +import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; -import com.fasterxml.jackson.databind.node.ObjectNode; - @Slf4j public final class HttpSender { - private static final String URL_SPLICE_CHAR = "?"; - /** - * request type post - */ - private static final String REQUEST_TYPE_POST = "POST"; - /** - * request type get - */ - private static final String REQUEST_TYPE_GET = "GET"; - private final String headerParams; - private final String bodyParams; - private final String contentField; - private final String requestType; - private final int timeout; + private Map headerParams; + private OkHttpRequestHeaderContentType contentType; + private Map bodyParams; + private HttpRequestMethod requestType; + private int timeout; private String url; - private HttpRequestBase httpRequest; public HttpSender(Map paramsMap) { + paramsValidator(paramsMap); + } + private void paramsValidator(Map paramsMap) { url = paramsMap.get(HttpAlertConstants.NAME_URL); - headerParams = paramsMap.get(HttpAlertConstants.NAME_HEADER_PARAMS); - bodyParams = paramsMap.get(HttpAlertConstants.NAME_BODY_PARAMS); - contentField = paramsMap.get(HttpAlertConstants.NAME_CONTENT_FIELD); - requestType = paramsMap.get(HttpAlertConstants.NAME_REQUEST_TYPE); + if (StringUtils.isBlank(url)) { + throw new IllegalArgumentException("url can not be null"); + } + + String headerParamsString = paramsMap.get(HttpAlertConstants.NAME_HEADER_PARAMS); + if (StringUtils.isNotBlank(headerParamsString)) { + headerParams = JSONUtils.toMap(headerParamsString); + if (headerParams == null) { + throw new IllegalArgumentException("headerParams is not a valid json"); + } + } else { + headerParams = new HashMap<>(); + } + + String bodyParamsString = paramsMap.get(HttpAlertConstants.NAME_BODY_PARAMS); + if (StringUtils.isNotBlank(bodyParamsString)) { + bodyParams = JSONUtils.toMap(bodyParamsString); + if (bodyParams == null) { + throw new IllegalArgumentException("bodyParams is not a valid json"); + } + } else { + bodyParams = new HashMap<>(); + } + + try { + requestType = HttpRequestMethod.valueOf(paramsMap.get(HttpAlertConstants.NAME_REQUEST_TYPE)); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("requestType is not a valid value"); + } + + contentType = OkHttpRequestHeaderContentType.fromValue(paramsMap.get(HttpAlertConstants.NAME_CONTENT_TYPE)); + if (contentType == null) { + throw new IllegalArgumentException("contentType is not a valid value"); + } + timeout = StringUtils.isNotBlank(paramsMap.get(HttpAlertConstants.NAME_TIMEOUT)) ? Integer.parseInt(paramsMap.get(HttpAlertConstants.NAME_TIMEOUT)) - : HttpAlertConstants.DEFAULT_TIMEOUT; + : HttpAlertConstants.DEFAULT_TIMEOUT * 1000; } public AlertResult send(String msg) { AlertResult alertResult = new AlertResult(); + OkHttpResponse okHttpResponse; try { - createHttpRequest(msg); - } catch (MalformedURLException e) { - throw new RuntimeException(e); - } catch (URISyntaxException e) { + okHttpResponse = sendHttpRequest(msg); + } catch (RuntimeException e) { throw new RuntimeException(e); } - if (httpRequest == null) { - alertResult.setSuccess(false); - alertResult.setMessage("Request types are not supported"); - return alertResult; - } + validateResponse(okHttpResponse, alertResult); - try { - String resp = this.getResponseString(httpRequest); - alertResult.setSuccess(true); - alertResult.setMessage(resp); - } catch (Exception e) { - log.error("send http alert msg exception : {}", e.getMessage()); + return alertResult; + } + + private void validateResponse(OkHttpResponse okHttpResponse, AlertResult alertResult) { + if (okHttpResponse.getStatusCode() != HttpStatus.SC_OK) { alertResult.setSuccess(false); - alertResult.setMessage( - String.format("Send http request alert failed: %s", e.getMessage())); + alertResult + .setMessage(String.format("send http alert failed, response body: %s", okHttpResponse.getBody())); + } else { + alertResult.setSuccess(true); + alertResult + .setMessage(String.format("send http alert success, response body: %s", okHttpResponse.getBody())); } - - return alertResult; } - public String getResponseString(HttpRequestBase httpRequest) throws Exception { + private OkHttpResponse sendHttpRequest(String msg) throws RuntimeException { + switch (requestType) { + case POST: + setMsgInHeader(msg); + setMsgInRequestBody(msg); + return sendPostRequest(); + case GET: + setMsgInUrl(msg); + setMsgInHeader(msg); + return sendGetRequest(); + case PUT: + setMsgInHeader(msg); + setMsgInRequestBody(msg); + return sendPutRequest(); + default: + throw new RuntimeException(String.format("http request method %s not supported", + requestType)); + } + } - RequestConfig requestConfig = RequestConfig.custom() - .setConnectTimeout(timeout * 1000) - .setConnectionRequestTimeout(timeout * 1000) - .setSocketTimeout(timeout * 1000) - .build(); - CloseableHttpClient httpClient = HttpClients.custom() - .setDefaultRequestConfig(requestConfig) - .setRetryHandler(HttpServiceRetryStrategy.retryStrategy).build(); + @SneakyThrows + private OkHttpResponse sendGetRequest() { + OkHttpRequestHeaders okHttpRequestHeaders = new OkHttpRequestHeaders(); + okHttpRequestHeaders.setHeaders(headerParams); + okHttpRequestHeaders.setOkHttpRequestHeaderContentType(contentType); + Map requestParams = new HashMap<>(); + log.info("sending http alert get request, url: {}, header: {}, requestParams: {}, contentType: {}", + url, headerParams, requestParams, contentType.getValue()); + return OkHttpUtils.get(url, okHttpRequestHeaders, + requestParams, timeout, timeout, timeout); + } - CloseableHttpResponse response = httpClient.execute(httpRequest); - HttpEntity entity = response.getEntity(); - return EntityUtils.toString(entity, StandardCharsets.UTF_8); + @SneakyThrows + private OkHttpResponse sendPostRequest() { + OkHttpRequestHeaders okHttpRequestHeaders = new OkHttpRequestHeaders(); + okHttpRequestHeaders.setHeaders(headerParams); + okHttpRequestHeaders.setOkHttpRequestHeaderContentType(contentType); + Map requestBody = Collections.unmodifiableMap(bodyParams); + log.info("sending http alert post request, url: {}, header: {}, requestBody: {}, contentType: {}", + url, headerParams, requestBody, contentType.getValue()); + return OkHttpUtils.post(url, okHttpRequestHeaders, null, + requestBody, timeout, timeout, timeout); } - private void createHttpRequest(String msg) throws MalformedURLException, URISyntaxException { - if (REQUEST_TYPE_POST.equalsIgnoreCase(requestType)) { - httpRequest = new HttpPost(url); - setHeader(); - // POST request add param in request body - setMsgInRequestBody(msg); - } else if (REQUEST_TYPE_GET.equalsIgnoreCase(requestType)) { - // GET request add param in url - setMsgInUrl(msg); - URL unencodeUrl = new URL(url); - URI uri = new URI(unencodeUrl.getProtocol(), unencodeUrl.getAuthority(), unencodeUrl.getPath(), - unencodeUrl.getQuery(), null); - - httpRequest = new HttpGet(uri); - setHeader(); - } + @SneakyThrows + private OkHttpResponse sendPutRequest() { + OkHttpRequestHeaders okHttpRequestHeaders = new OkHttpRequestHeaders(); + okHttpRequestHeaders.setHeaders(headerParams); + okHttpRequestHeaders.setOkHttpRequestHeaderContentType(contentType); + Map requestBody = Collections.unmodifiableMap(bodyParams); + log.info("sending http alert put request, url: {}, header: {}, requestBody: {}, contentType: {}", + url, headerParams, requestBody, contentType.getValue()); + return OkHttpUtils.put(url, okHttpRequestHeaders, + requestBody, timeout, timeout, timeout); } /** * add msg param in url */ private void setMsgInUrl(String msg) { - - if (StringUtils.isNotBlank(contentField)) { - String type = "&"; - // check splice char is & or ? - if (!url.contains(URL_SPLICE_CHAR)) { - type = URL_SPLICE_CHAR; - } + if (url.contains(HttpAlertConstants.MSG_PARAMS)) { try { - url = String.format("%s%s%s=%s", url, type, contentField, + url = url.replace(HttpAlertConstants.MSG_PARAMS, URLEncoder.encode(msg, StandardCharsets.UTF_8.name())); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); @@ -168,37 +194,31 @@ public final class HttpSender { /** * set header params */ - private void setHeader() { - - if (httpRequest == null) { + private void setMsgInHeader(String msg) { + if (msg == null) { return; } - HashMap map = JSONUtils.parseObject(headerParams, HashMap.class); - for (Map.Entry entry : map.entrySet()) { - httpRequest.setHeader(entry.getKey(), String.valueOf(entry.getValue())); - } + headerParams.forEach((key, value) -> { + if (value.contains(HttpAlertConstants.MSG_PARAMS)) { + headerParams.put(key, value.replace(HttpAlertConstants.MSG_PARAMS, msg)); + } + }); } /** * set body params */ private void setMsgInRequestBody(String msg) { - try { - ObjectNode objectNode = JSONUtils.createObjectNode(); - if (StringUtils.isNotBlank(bodyParams)) { - objectNode = JSONUtils.parseObject(bodyParams); - } - // set msg content field - objectNode.put(contentField, msg); - StringEntity entity = new StringEntity(JSONUtils.toJsonString(objectNode), StandardCharsets.UTF_8); - ((HttpPost) httpRequest).setEntity(entity); - } catch (Exception e) { - log.error("send http alert msg exception : {}", e.getMessage()); + if (bodyParams == null) { + return; } - } - public String getRequestUrl() { - return httpRequest.getURI().toString(); + bodyParams.forEach((key, value) -> { + if (value.contains(HttpAlertConstants.MSG_PARAMS)) { + bodyParams.put(key, value.replace(HttpAlertConstants.MSG_PARAMS, msg)); + } + }); } + } diff --git a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-http/src/test/java/org/apache/dolphinscheduler/plugin/alert/http/HttpSenderTest.java b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-http/src/test/java/org/apache/dolphinscheduler/plugin/alert/http/HttpSenderTest.java index 40f589a10b..e833a70f9e 100644 --- a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-http/src/test/java/org/apache/dolphinscheduler/plugin/alert/http/HttpSenderTest.java +++ b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-http/src/test/java/org/apache/dolphinscheduler/plugin/alert/http/HttpSenderTest.java @@ -17,37 +17,131 @@ package org.apache.dolphinscheduler.plugin.alert.http; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; - import org.apache.dolphinscheduler.alert.api.AlertResult; +import org.apache.dolphinscheduler.common.model.OkHttpRequestHeaderContentType; +import org.apache.dolphinscheduler.common.utils.JSONUtils; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpStatus; +import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; +import okhttp3.mockwebserver.Dispatcher; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; + +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; +@ExtendWith(MockitoExtension.class) public class HttpSenderTest { + private final List mockWebServers = new ArrayList<>(); + + private Map paramsMap = new HashMap<>(); + + @AfterEach + public void after() { + mockWebServers.forEach(IOUtils::closeQuietly); + mockWebServers.clear(); + } + @Test - public void sendTest() throws Exception { - Map paramsMap = new HashMap<>(); - String url = "https://www.dolphinscheduler-not-exists-web.com:12345"; - String contentField = "content"; - paramsMap.put(HttpAlertConstants.NAME_URL, url); - paramsMap.put(HttpAlertConstants.NAME_REQUEST_TYPE, "GET"); - paramsMap.put(HttpAlertConstants.NAME_HEADER_PARAMS, "{\"Content-Type\":\"application/json\"}"); - paramsMap.put(HttpAlertConstants.NAME_BODY_PARAMS, "{\"number\":\"123456\"}"); - paramsMap.put(HttpAlertConstants.NAME_CONTENT_FIELD, contentField); - paramsMap.put(HttpAlertConstants.NAME_TIMEOUT, String.valueOf(HttpAlertConstants.DEFAULT_TIMEOUT)); - - HttpSender httpSender = spy(new HttpSender(paramsMap)); - doReturn("success").when(httpSender).getResponseString(any()); - AlertResult alertResult = httpSender.send("Fault tolerance warning"); + void testHttpSenderGet() throws Exception { + String msg = "msg_test"; + Map headerParams = new HashMap<>(); + headerParams.put("msg", msg); + paramsMap.put(HttpAlertConstants.NAME_HEADER_PARAMS, JSONUtils.toJsonString(headerParams)); + paramsMap.put(HttpAlertConstants.NAME_CONTENT_TYPE, OkHttpRequestHeaderContentType.APPLICATION_JSON.getValue()); + + String mockGetUrl = createMockWebServer(String.format("/get/%s", msg), HttpStatus.SC_OK); + String actualGetUrl = mockGetUrl.replace(msg, HttpAlertConstants.MSG_PARAMS); + paramsMap.put(HttpAlertConstants.NAME_URL, actualGetUrl); + + paramsMap.put(HttpAlertConstants.NAME_REQUEST_TYPE, HttpRequestMethod.GET.name()); + + HttpSender httpSender = new HttpSender(paramsMap); + + AlertResult alertResult = httpSender.send(msg); + Assertions.assertTrue(alertResult.isSuccess()); - Assertions.assertTrue(httpSender.getRequestUrl().contains(url)); - Assertions.assertTrue(httpSender.getRequestUrl().contains(contentField)); + Assertions.assertTrue(alertResult.getMessage().contains(msg)); + } + + @Test + void testHttpSenderPost() throws Exception { + String msg = "msg_test"; + Map bodyParams = new HashMap<>(); + bodyParams.put("msg", msg); + paramsMap.put(HttpAlertConstants.NAME_BODY_PARAMS, JSONUtils.toJsonString(bodyParams)); + paramsMap.put(HttpAlertConstants.NAME_CONTENT_TYPE, OkHttpRequestHeaderContentType.APPLICATION_JSON.getValue()); + + String mockPostUrl = createMockWebServer("/post", HttpStatus.SC_OK); + paramsMap.put(HttpAlertConstants.NAME_URL, mockPostUrl); + + paramsMap.put(HttpAlertConstants.NAME_REQUEST_TYPE, HttpRequestMethod.POST.name()); + + HttpSender httpSender = new HttpSender(paramsMap); + + AlertResult alertResult = httpSender.send(msg); + + Assertions.assertTrue(alertResult.isSuccess()); + Assertions.assertTrue(alertResult.getMessage().contains(msg)); + } + + @Test + void testHttpSenderPut() throws Exception { + String msg = "msg_test"; + Map bodyParams = new HashMap<>(); + bodyParams.put("msg", msg); + paramsMap.put(HttpAlertConstants.NAME_BODY_PARAMS, JSONUtils.toJsonString(bodyParams)); + paramsMap.put(HttpAlertConstants.NAME_CONTENT_TYPE, OkHttpRequestHeaderContentType.APPLICATION_JSON.getValue()); + + String mockPostUrl = createMockWebServer("/post", HttpStatus.SC_OK); + paramsMap.put(HttpAlertConstants.NAME_URL, mockPostUrl); + + paramsMap.put(HttpAlertConstants.NAME_REQUEST_TYPE, HttpRequestMethod.PUT.name()); + + HttpSender httpSender = new HttpSender(paramsMap); + + AlertResult alertResult = httpSender.send(msg); + + Assertions.assertTrue(alertResult.isSuccess()); + Assertions.assertTrue(alertResult.getMessage().contains(msg)); + } + + private String createMockWebServer(String path, int actualResponseCode) throws IOException { + MockWebServer server = new MockWebServer(); + mockWebServers.add(server); + server.start(); + server.setDispatcher(generateMockDispatcher(actualResponseCode)); + return server.url(path).toString(); + } + + private Dispatcher generateMockDispatcher(int actualResponseCode) { + return new Dispatcher() { + + @NotNull + @Override + public MockResponse dispatch(@NotNull RecordedRequest request) { + Map responseMap = new HashMap<>(); + responseMap.put("url", request.getRequestUrl().toString()); + responseMap.put("headers", request.getHeaders().toString()); + responseMap.put("body", request.getBody().toString()); + String responseBody = JSONUtils.toJsonString(responseMap); + return new MockResponse() + .setResponseCode(actualResponseCode) + .setBody(responseBody); + } + }; } } diff --git a/dolphinscheduler-alert/dolphinscheduler-alert-server/src/main/java/org/apache/dolphinscheduler/alert/plugin/AlertPluginManager.java b/dolphinscheduler-alert/dolphinscheduler-alert-server/src/main/java/org/apache/dolphinscheduler/alert/plugin/AlertPluginManager.java index 35d75297a3..2a701ab143 100644 --- a/dolphinscheduler-alert/dolphinscheduler-alert-server/src/main/java/org/apache/dolphinscheduler/alert/plugin/AlertPluginManager.java +++ b/dolphinscheduler-alert/dolphinscheduler-alert-server/src/main/java/org/apache/dolphinscheduler/alert/plugin/AlertPluginManager.java @@ -54,10 +54,10 @@ public final class AlertPluginManager { private final Map alertPluginMap = new HashMap<>(); public void start() { - log.info("AlertPluginManager start ..."); + log.info("AlertPluginManager start..."); checkAlertPluginExist(); installAlertPlugin(); - log.info("AlertPluginManager started ..."); + log.info("AlertPluginManager started..."); } public Optional getAlertChannel(int id) { @@ -70,7 +70,7 @@ public final class AlertPluginManager { private void checkAlertPluginExist() { if (!pluginDao.checkPluginDefineTableExist()) { - log.error("Plugin Define Table t_ds_plugin_define Not Exist . Please Create it First !"); + log.error("Plugin Define Table t_ds_plugin_define Not Exist. Please Create it First!"); System.exit(1); } } diff --git a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/interceptor/LocaleChangeInterceptor.java b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/interceptor/LocaleChangeInterceptor.java index 69c358dc28..27b7fb8c74 100644 --- a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/interceptor/LocaleChangeInterceptor.java +++ b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/interceptor/LocaleChangeInterceptor.java @@ -28,10 +28,10 @@ import javax.servlet.http.HttpServletResponse; import org.springframework.context.i18n.LocaleContextHolder; import org.springframework.lang.Nullable; import org.springframework.util.StringUtils; -import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; +import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.util.WebUtils; -public class LocaleChangeInterceptor extends HandlerInterceptorAdapter { +public class LocaleChangeInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { diff --git a/dolphinscheduler-spi/src/main/java/org/apache/dolphinscheduler/spi/params/base/DataType.java b/dolphinscheduler-spi/src/main/java/org/apache/dolphinscheduler/spi/params/base/DataType.java index 2b94ac1a73..0b33e56127 100644 --- a/dolphinscheduler-spi/src/main/java/org/apache/dolphinscheduler/spi/params/base/DataType.java +++ b/dolphinscheduler-spi/src/main/java/org/apache/dolphinscheduler/spi/params/base/DataType.java @@ -17,9 +17,12 @@ package org.apache.dolphinscheduler.spi.params.base; +import lombok.Getter; + /** * param datetype */ +@Getter public enum DataType { STRING("string"), @@ -32,8 +35,4 @@ public enum DataType { this.dataType = dataType; } - public String getDataType() { - return this.dataType; - } - } diff --git a/dolphinscheduler-spi/src/main/java/org/apache/dolphinscheduler/spi/params/base/Validate.java b/dolphinscheduler-spi/src/main/java/org/apache/dolphinscheduler/spi/params/base/Validate.java index cc02e9581f..17cccb12f8 100644 --- a/dolphinscheduler-spi/src/main/java/org/apache/dolphinscheduler/spi/params/base/Validate.java +++ b/dolphinscheduler-spi/src/main/java/org/apache/dolphinscheduler/spi/params/base/Validate.java @@ -17,6 +17,8 @@ package org.apache.dolphinscheduler.spi.params.base; +import lombok.Data; + import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; @@ -25,6 +27,7 @@ import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; * form validate */ @JsonDeserialize(builder = Validate.Builder.class) +@Data public class Validate { @JsonProperty("required") @@ -62,7 +65,7 @@ public class Validate { return new Builder(); } - @JsonPOJOBuilder(buildMethodName = "build", withPrefix = "set") + @JsonPOJOBuilder(withPrefix = "set") public static class Builder { private boolean required = false; @@ -111,28 +114,4 @@ public class Validate { return new Validate(this); } } - - public boolean isRequired() { - return required; - } - - public String getMessage() { - return message; - } - - public String getType() { - return type; - } - - public String getTrigger() { - return trigger; - } - - public Double getMin() { - return min; - } - - public Double getMax() { - return max; - } } diff --git a/dolphinscheduler-ui/src/locales/en_US/security.ts b/dolphinscheduler-ui/src/locales/en_US/security.ts index f43adb839e..a79211bec7 100644 --- a/dolphinscheduler-ui/src/locales/en_US/security.ts +++ b/dolphinscheduler-ui/src/locales/en_US/security.ts @@ -244,7 +244,7 @@ export default { requestType: 'Request Type', headerParams: 'Headers', bodyParams: 'Body', - contentField: 'Content Field', + contentType: 'Content Type', timeout: 'Timeout(s)', Keyword: 'Keyword', userParams: 'User Params', diff --git a/dolphinscheduler-ui/src/locales/zh_CN/security.ts b/dolphinscheduler-ui/src/locales/zh_CN/security.ts index 463b18f33f..03a4ce7051 100644 --- a/dolphinscheduler-ui/src/locales/zh_CN/security.ts +++ b/dolphinscheduler-ui/src/locales/zh_CN/security.ts @@ -240,7 +240,7 @@ export default { requestType: '请求方式', headerParams: '请求头', bodyParams: '请求体', - contentField: '内容字段', + contentType: 'Content Type', timeout: '超时时间(秒)', Keyword: '关键词', userParams: '自定义参数', diff --git a/dolphinscheduler-ui/src/views/security/alarm-instance-manage/detail.tsx b/dolphinscheduler-ui/src/views/security/alarm-instance-manage/detail.tsx index da77305eff..4970a02b62 100644 --- a/dolphinscheduler-ui/src/views/security/alarm-instance-manage/detail.tsx +++ b/dolphinscheduler-ui/src/views/security/alarm-instance-manage/detail.tsx @@ -203,6 +203,7 @@ const DetailModal = defineComponent({ 'security.alarm_instance.select_plugin_tips' )} on-update:value={onChangePlugin} + filterable /> ) },