This is an automated email from the ASF dual-hosted git repository.
jinyleechina pushed a commit to branch 2.0.4-prepare
in repository https://gitbox.apache.org/repos/asf/dolphinscheduler.git
The following commit(s) were added to refs/heads/2.0.4-prepare by this push:
new 2aa5b4c [Cherry-pick-to-204] pick to 204-prepare (#8429)
2aa5b4c is described below
commit 2aa5b4c6cccb2dfa5de02215041d18d63580b5be
Author: JinYong Li <[email protected]>
AuthorDate: Fri Feb 18 20:30:36 2022 +0800
[Cherry-pick-to-204] pick to 204-prepare (#8429)
* fix relation unbinding bug
* [Bug-8053] Fix CronUtils.getMaxCycle return null (#8086)
* [bug] Fix datax task type error parse clickhouse reader sql (#8091)
* [Fix-8119][API] Update ProcessInstance error and without reason output
(#8122)
* fix bug_8119
* fix bug_8119
* fix bug_8119
* fix bug_8119
* fix bug_8119
* pick-8086/8091/8122/8139
* [Bug-8169] [dolphinscheduler-ui] Fix `After you save the workflow, it…
(#8198)
* [Fix-8187][UI] Add the function to the module of resource that you can
re-upload the file on the page of the file management. (#8359)
* add reupload file
* develop reupload file
* fix this issue
* [Improvement-8284][Alert] Dingtalk alert plugin supports markdown message
type (#8285)
* add msgtype in the dingtalk alert plugin
* update markdown msgtype 'at persion'
* fix sudo.enable=false Is invalid (#8388)
* [Fix][UI] Rectify this issue with missing the re-uploading file button
when the file is under the root directory.
Co-authored-by: springmonster <[email protected]>
Co-authored-by: seagle <[email protected]>
Co-authored-by: xiangzihao <[email protected]>
Co-authored-by: Kerwin <[email protected]>
Co-authored-by: calvin <[email protected]>
Co-authored-by: ShuiMuNianHuaLP
<[email protected]>
---
.../dingtalk/DingTalkAlertChannelFactory.java | 35 ++++-
.../alert/dingtalk/DingTalkParamsConstants.java | 36 +++--
.../plugin/alert/dingtalk/DingTalkSender.java | 157 +++++++++++++++++----
.../dingtalk/DingTalkAlertChannelFactoryTest.java | 2 +-
.../plugin/alert/dingtalk/DingTalkSenderTest.java | 4 +-
.../api/service/ProcessDefinitionService.java | 4 +-
.../service/impl/ProcessDefinitionServiceImpl.java | 10 +-
.../service/impl/ProcessInstanceServiceImpl.java | 2 +-
.../api/service/ProcessDefinitionServiceTest.java | 16 ++-
.../api/service/ProcessInstanceServiceTest.java | 24 +++-
.../service/quartz/cron/AbstractCycle.java | 10 ++
.../service/quartz/cron/CronUtils.java | 7 +-
.../service/quartz/cron/CycleFactory.java | 57 ++++++++
.../service/quartz/cron/CronUtilsTest.java | 26 +++-
.../plugin/task/api/AbstractCommandExecutor.java | 10 +-
.../dolphinscheduler/plugin/task/util/OSUtils.java | 10 ++
.../plugin/task/datax/DataxUtils.java | 3 +
.../src/js/conf/home/pages/dag/_source/dag.vue | 4 +-
.../pages/file/pages/list/_source/list.vue | 10 +-
.../pages/file/pages/subdirectory/_source/list.vue | 9 +-
.../module/components/fileUpdate/fileReUpload.vue | 110 +++++++++------
.../src/js/module/components/nav/nav.vue | 46 ++++--
.../src/js/module/i18n/locale/en_US.js | 4 +
.../src/js/module/i18n/locale/zh_CN.js | 4 +
24 files changed, 481 insertions(+), 119 deletions(-)
diff --git
a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/main/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkAlertChannelFactory.java
b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/main/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkAlertChannelFactory.java
index 01b9060..2f7afee 100644
---
a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/main/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkAlertChannelFactory.java
+++
b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/main/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkAlertChannelFactory.java
@@ -71,6 +71,39 @@ public final class DingTalkAlertChannelFactory implements
AlertChannelFactory {
.setRequired(false)
.build())
.build();
+
+ RadioParam msgTypeParam = RadioParam
+ .newBuilder(DingTalkParamsConstants.NAME_DING_TALK_MSG_TYPE,
DingTalkParamsConstants.DING_TALK_MSG_TYPE)
+ .addParamsOptions(new
ParamsOptions(DingTalkParamsConstants.DING_TALK_MSG_TYPE_TEXT,
DingTalkParamsConstants.DING_TALK_MSG_TYPE_TEXT, false))
+ .addParamsOptions(new
ParamsOptions(DingTalkParamsConstants.DING_TALK_MSG_TYPE_MARKDOWN,
DingTalkParamsConstants.DING_TALK_MSG_TYPE_MARKDOWN, false))
+ .setValue(DingTalkParamsConstants.DING_TALK_MSG_TYPE_TEXT)
+ .addValidate(Validate.newBuilder()
+ .setRequired(false)
+ .build())
+ .build();
+
+ InputParam atMobilesParam = InputParam
+ .newBuilder(DingTalkParamsConstants.NAME_DING_TALK_AT_MOBILES,
DingTalkParamsConstants.DING_TALK_AT_MOBILES)
+ .addValidate(Validate.newBuilder()
+ .setRequired(false)
+ .build())
+ .build();
+ InputParam atUserIdsParam = InputParam
+ .newBuilder(DingTalkParamsConstants.NAME_DING_TALK_AT_USERIDS,
DingTalkParamsConstants.DING_TALK_AT_USERIDS)
+ .addValidate(Validate.newBuilder()
+ .setRequired(false)
+ .build())
+ .build();
+ RadioParam isAtAll = RadioParam
+ .newBuilder(DingTalkParamsConstants.NAME_DING_TALK_AT_ALL,
DingTalkParamsConstants.DING_TALK_AT_ALL)
+ .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();
+
RadioParam isEnableProxy = RadioParam
.newBuilder(DingTalkParamsConstants.NAME_DING_TALK_PROXY_ENABLE,
DingTalkParamsConstants.DING_TALK_PROXY_ENABLE)
.addParamsOptions(new ParamsOptions(STRING_YES, STRING_TRUE,
false))
@@ -105,7 +138,7 @@ public final class DingTalkAlertChannelFactory implements
AlertChannelFactory {
.setPlaceholder("if enable use authentication, you need input
password")
.build();
- return Arrays.asList(webHookParam, keywordParam, secretParam,
isEnableProxy, proxyParam, portParam, userParam, passwordParam);
+ return Arrays.asList(webHookParam, keywordParam, secretParam,
msgTypeParam, atMobilesParam, atUserIdsParam, isAtAll, isEnableProxy,
proxyParam, portParam, userParam, passwordParam);
}
}
diff --git
a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/main/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkParamsConstants.java
b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/main/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkParamsConstants.java
index fa47b0c..e5b667a 100644
---
a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/main/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkParamsConstants.java
+++
b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/main/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkParamsConstants.java
@@ -18,25 +18,43 @@
package org.apache.dolphinscheduler.plugin.alert.dingtalk;
public final class DingTalkParamsConstants {
-
- static final String DING_TALK_PROXY_ENABLE = "isEnableProxy";
+ static final String DING_TALK_PROXY_ENABLE = "$t('isEnableProxy')";
static final String NAME_DING_TALK_PROXY_ENABLE = "IsEnableProxy";
- static final String DING_TALK_WEB_HOOK = "webhook";
+ static final String DING_TALK_WEB_HOOK = "$t('webhook')";
static final String NAME_DING_TALK_WEB_HOOK = "WebHook";
- static final String DING_TALK_KEYWORD = "keyword";
+
+ static final String DING_TALK_KEYWORD = "$t('keyword')";
static final String NAME_DING_TALK_KEYWORD = "Keyword";
- static final String DING_TALK_SECRET = "secret";
+ static final String DING_TALK_SECRET = "$t('secret')";
static final String NAME_DING_TALK_SECRET = "Secret";
- static final String DING_TALK_PROXY = "proxy";
+ static final String DING_TALK_MSG_TYPE = "$t('msgType')";
+ static final String NAME_DING_TALK_MSG_TYPE = "MsgType";
+
+ static final String DING_TALK_MSG_TYPE_TEXT = "text";
+ static final String DING_TALK_MSG_TYPE_MARKDOWN = "markdown";
+
+ static final String DING_TALK_AT_MOBILES = "$t('atMobiles')";
+ static final String NAME_DING_TALK_AT_MOBILES = "AtMobiles";
+
+ static final String DING_TALK_AT_USERIDS = "$t('atUserIds')";
+ static final String NAME_DING_TALK_AT_USERIDS = "AtUserIds";
+
+ static final String DING_TALK_AT_ALL = "$t('isAtAll')";
+ static final String NAME_DING_TALK_AT_ALL = "IsAtAll";
+
+ static final String DING_TALK_PROXY = "$t('proxy')";
static final String NAME_DING_TALK_PROXY = "Proxy";
- static final String DING_TALK_PORT = "port";
+
+ static final String DING_TALK_PORT = "$t('port')";
static final String NAME_DING_TALK_PORT = "Port";
- static final String DING_TALK_USER = "user";
+
+ static final String DING_TALK_USER = "$t('user')";
static final String NAME_DING_TALK_USER = "User";
- static final String DING_TALK_PASSWORD = "password";
+
+ static final String DING_TALK_PASSWORD = "$t('password')";
static final String NAME_DING_TALK_PASSWORD = "Password";
private DingTalkParamsConstants() {
diff --git
a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/main/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkSender.java
b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/main/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkSender.java
index eeca8c0..8519e54 100644
---
a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/main/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkSender.java
+++
b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/main/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkSender.java
@@ -39,8 +39,10 @@ import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
+import java.util.Objects;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
@@ -61,6 +63,12 @@ public final class DingTalkSender {
private final String url;
private final String keyword;
private final String secret;
+ private String msgType;
+
+ private final String atMobiles;
+ private final String atUserIds;
+ private final Boolean atAll;
+
private final Boolean enableProxy;
private String proxy;
@@ -75,11 +83,17 @@ public final class DingTalkSender {
url = config.get(DingTalkParamsConstants.NAME_DING_TALK_WEB_HOOK);
keyword = config.get(DingTalkParamsConstants.NAME_DING_TALK_KEYWORD);
secret = config.get(DingTalkParamsConstants.NAME_DING_TALK_SECRET);
+ msgType = config.get(DingTalkParamsConstants.NAME_DING_TALK_MSG_TYPE);
+
+ atMobiles =
config.get(DingTalkParamsConstants.NAME_DING_TALK_AT_MOBILES);
+ atUserIds =
config.get(DingTalkParamsConstants.NAME_DING_TALK_AT_USERIDS);
+ atAll =
Boolean.valueOf(config.get(DingTalkParamsConstants.NAME_DING_TALK_AT_ALL));
+
enableProxy =
Boolean.valueOf(config.get(DingTalkParamsConstants.NAME_DING_TALK_PROXY_ENABLE));
if (Boolean.TRUE.equals(enableProxy)) {
port =
Integer.parseInt(config.get(DingTalkParamsConstants.NAME_DING_TALK_PORT));
proxy = config.get(DingTalkParamsConstants.NAME_DING_TALK_PROXY);
- user = config.get(DingTalkParamsConstants.DING_TALK_USER);
+ user = config.get(DingTalkParamsConstants.NAME_DING_TALK_USER);
password =
config.get(DingTalkParamsConstants.NAME_DING_TALK_PASSWORD);
}
}
@@ -108,18 +122,7 @@ public final class DingTalkSender {
return RequestConfig.custom().setProxy(httpProxy).build();
}
- private static String textToJsonString(String text) {
- Map<String, Object> items = new HashMap<>();
- items.put("msgtype", "text");
- Map<String, String> textContent = new HashMap<>();
- byte[] byt = StringUtils.getBytesUtf8(text);
- String txt = StringUtils.newStringUtf8(byt);
- textContent.put("content", txt);
- items.put("text", textContent);
- return JSONUtils.toJsonString(items);
- }
-
- private static AlertResult checkSendDingTalkSendMsgResult(String result) {
+ private AlertResult checkSendDingTalkSendMsgResult(String result) {
AlertResult alertResult = new AlertResult();
alertResult.setStatus("false");
@@ -144,6 +147,13 @@ public final class DingTalkSender {
return alertResult;
}
+ /**
+ * send dingtalk msg handler
+ *
+ * @param title title
+ * @param content content
+ * @return
+ */
public AlertResult sendDingTalkMsg(String title, String content) {
AlertResult alertResult;
try {
@@ -160,18 +170,9 @@ public final class DingTalkSender {
private String sendMsg(String title, String content) throws IOException {
- StringBuilder text = new StringBuilder();
- if
(org.apache.dolphinscheduler.spi.utils.StringUtils.isNotBlank(keyword)) {
- text.append(keyword);
- text.append(":");
- }
- text.append(title);
- text.append("\n");
- text.append(content);
-
- String msgToJson = textToJsonString(text.toString());
+ String msg = generateMsgJson(title, content);
- HttpPost httpPost =
constructHttpPost(org.apache.dolphinscheduler.spi.utils.StringUtils.isBlank(secret)
? url : generateSignedUrl(), msgToJson);
+ HttpPost httpPost =
constructHttpPost(org.apache.dolphinscheduler.spi.utils.StringUtils.isBlank(secret)
? url : generateSignedUrl(), msg);
CloseableHttpClient httpClient;
if (Boolean.TRUE.equals(enableProxy)) {
@@ -192,13 +193,119 @@ public final class DingTalkSender {
} finally {
response.close();
}
- logger.info("Ding Talk send title :{},content : {}, resp: {}",
title, content, resp);
+ logger.info("Ding Talk send msg :{}, resp: {}", msg, resp);
return resp;
} finally {
httpClient.close();
}
}
+ /**
+ * generate msg json
+ *
+ * @param title title
+ * @param content content
+ * @return msg
+ */
+ private String generateMsgJson(String title, String content) {
+ if
(org.apache.dolphinscheduler.spi.utils.StringUtils.isBlank(msgType)) {
+ msgType = DingTalkParamsConstants.DING_TALK_MSG_TYPE_TEXT;
+ }
+ Map<String, Object> items = new HashMap<>();
+ items.put("msgtype", msgType);
+ Map<String, Object> text = new HashMap<>();
+ items.put(msgType, text);
+
+ if
(DingTalkParamsConstants.DING_TALK_MSG_TYPE_MARKDOWN.equals(msgType)) {
+ generateMarkdownMsg(title, content, text);
+ } else {
+ generateTextMsg(title, content, text);
+ }
+
+ setMsgAt(items);
+ return JSONUtils.toJsonString(items);
+
+ }
+
+ /**
+ * generate text msg
+ *
+ * @param title title
+ * @param content content
+ * @param text text
+ */
+ private void generateTextMsg(String title, String content, Map<String,
Object> text) {
+ StringBuilder builder = new StringBuilder(title);
+ builder.append("\n");
+ builder.append(content);
+ if
(org.apache.dolphinscheduler.spi.utils.StringUtils.isNotBlank(keyword)) {
+ builder.append(" ");
+ builder.append(keyword);
+ }
+ byte[] byt = StringUtils.getBytesUtf8(builder.toString());
+ String txt = StringUtils.newStringUtf8(byt);
+ text.put("content", txt);
+ }
+
+ /**
+ * generate markdown msg
+ *
+ * @param title title
+ * @param content content
+ * @param text text
+ */
+ private void generateMarkdownMsg(String title, String content, Map<String,
Object> text) {
+ StringBuilder builder = new StringBuilder(content);
+ if
(org.apache.dolphinscheduler.spi.utils.StringUtils.isNotBlank(keyword)) {
+ builder.append(" ");
+ builder.append(keyword);
+ }
+ builder.append("\n\n");
+ if
(org.apache.dolphinscheduler.spi.utils.StringUtils.isNotBlank(atMobiles)) {
+ Arrays.stream(atMobiles.split(",")).forEach(value -> {
+ builder.append("@");
+ builder.append(value);
+ builder.append(" ");
+ });
+ }
+ if
(org.apache.dolphinscheduler.spi.utils.StringUtils.isNotBlank(atUserIds)) {
+ Arrays.stream(atUserIds.split(",")).forEach(value -> {
+ builder.append("@");
+ builder.append(value);
+ builder.append(" ");
+ });
+ }
+
+ byte[] byt = StringUtils.getBytesUtf8(builder.toString());
+ String txt = StringUtils.newStringUtf8(byt);
+ text.put("title", title);
+ text.put("text", txt);
+ }
+
+ /**
+ * configure msg @person
+ *
+ * @param items items
+ */
+ private void setMsgAt(Map<String, Object> items) {
+ Map<String, Object> at = new HashMap<>();
+
+ String[] atMobileArray =
org.apache.dolphinscheduler.spi.utils.StringUtils.isNotBlank(atMobiles) ?
atMobiles.split(",") : new String[0];
+ String[] atUserArray =
org.apache.dolphinscheduler.spi.utils.StringUtils.isNotBlank(atUserIds) ?
atUserIds.split(",") : new String[0];
+ boolean isAtAll = Objects.isNull(atAll) ? false : atAll;
+
+ at.put("atMobiles", atMobileArray);
+ at.put("atUserIds", atUserArray);
+ at.put("isAtAll", isAtAll);
+
+ items.put("at", at);
+ }
+
+ /**
+ * generate sign url
+ *
+ * @return sign url
+ */
private String generateSignedUrl() {
Long timestamp = System.currentTimeMillis();
String stringToSign = timestamp + "\n" + secret;
diff --git
a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/test/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkAlertChannelFactoryTest.java
b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/test/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkAlertChannelFactoryTest.java
index 9905195..ea1cd1a 100644
---
a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/test/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkAlertChannelFactoryTest.java
+++
b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/test/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkAlertChannelFactoryTest.java
@@ -32,7 +32,7 @@ public class DingTalkAlertChannelFactoryTest {
DingTalkAlertChannelFactory dingTalkAlertChannelFactory = new
DingTalkAlertChannelFactory();
List<PluginParams> params = dingTalkAlertChannelFactory.params();
JSONUtils.toJsonString(params);
- Assert.assertEquals(8, params.size());
+ Assert.assertEquals(12, params.size());
}
@Test
diff --git
a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/test/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkSenderTest.java
b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/test/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkSenderTest.java
index d2267a4..791a96f 100644
---
a/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/test/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkSenderTest.java
+++
b/dolphinscheduler-alert/dolphinscheduler-alert-plugins/dolphinscheduler-alert-dingtalk/src/test/java/org/apache/dolphinscheduler/plugin/alert/dingtalk/DingTalkSenderTest.java
@@ -33,8 +33,10 @@ public class DingTalkSenderTest {
@Before
public void initDingTalkConfig() {
- dingTalkConfig.put(DingTalkParamsConstants.NAME_DING_TALK_KEYWORD,
"keyWord");
+ dingTalkConfig.put(DingTalkParamsConstants.NAME_DING_TALK_KEYWORD,
"keyword");
dingTalkConfig.put(DingTalkParamsConstants.NAME_DING_TALK_WEB_HOOK,
"url");
+ dingTalkConfig.put(DingTalkParamsConstants.NAME_DING_TALK_MSG_TYPE,
DingTalkParamsConstants.DING_TALK_MSG_TYPE_MARKDOWN);
+
dingTalkConfig.put(DingTalkParamsConstants.NAME_DING_TALK_PROXY_ENABLE,
"false");
dingTalkConfig.put(DingTalkParamsConstants.NAME_DING_TALK_PASSWORD,
"password");
dingTalkConfig.put(DingTalkParamsConstants.NAME_DING_TALK_PORT,
"9988");
diff --git
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/ProcessDefinitionService.java
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/ProcessDefinitionService.java
index 755d697..4e7abf3 100644
---
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/ProcessDefinitionService.java
+++
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/ProcessDefinitionService.java
@@ -19,8 +19,10 @@ package org.apache.dolphinscheduler.api.service;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.enums.ReleaseState;
+import org.apache.dolphinscheduler.dao.entity.TaskDefinitionLog;
import org.apache.dolphinscheduler.dao.entity.User;
+import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
@@ -245,7 +247,7 @@ public interface ProcessDefinitionService {
* @param processTaskRelationJson process task relation json
* @return check result code
*/
- Map<String, Object> checkProcessNodeList(String processTaskRelationJson);
+ Map<String, Object> checkProcessNodeList(String processTaskRelationJson,
List<TaskDefinitionLog> taskDefinitionLogs);
/**
* get task node details based on process definition
diff --git
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProcessDefinitionServiceImpl.java
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProcessDefinitionServiceImpl.java
index 58c8ab4..ad38475 100644
---
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProcessDefinitionServiceImpl.java
+++
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProcessDefinitionServiceImpl.java
@@ -76,6 +76,7 @@ import
org.apache.dolphinscheduler.service.process.ProcessService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
+import org.apache.hadoop.fs.Stat;
import java.io.BufferedOutputStream;
import java.io.IOException;
@@ -1071,7 +1072,7 @@ public class ProcessDefinitionServiceImpl extends
BaseServiceImpl implements Pro
* @return check result code
*/
@Override
- public Map<String, Object> checkProcessNodeList(String
processTaskRelationJson) {
+ public Map<String, Object> checkProcessNodeList(String
processTaskRelationJson, List<TaskDefinitionLog> taskDefinitionLogsList) {
Map<String, Object> result = new HashMap<>();
try {
if (processTaskRelationJson == null) {
@@ -1082,7 +1083,7 @@ public class ProcessDefinitionServiceImpl extends
BaseServiceImpl implements Pro
List<ProcessTaskRelation> taskRelationList =
JSONUtils.toList(processTaskRelationJson, ProcessTaskRelation.class);
// Check whether the task node is normal
- List<TaskNode> taskNodes =
processService.transformTask(taskRelationList, Lists.newArrayList());
+ List<TaskNode> taskNodes =
processService.transformTask(taskRelationList, taskDefinitionLogsList);
if (CollectionUtils.isEmpty(taskNodes)) {
logger.error("process node info is empty");
@@ -1110,8 +1111,9 @@ public class ProcessDefinitionServiceImpl extends
BaseServiceImpl implements Pro
}
putMsg(result, Status.SUCCESS);
} catch (Exception e) {
- result.put(Constants.STATUS,
Status.REQUEST_PARAMS_NOT_VALID_ERROR);
- result.put(Constants.MSG, e.getMessage());
+ result.put(Constants.STATUS, Status.INTERNAL_SERVER_ERROR_ARGS);
+ putMsg(result, Status.INTERNAL_SERVER_ERROR_ARGS, e.getMessage());
+ logger.error(Status.INTERNAL_SERVER_ERROR_ARGS.getMsg(), e);
}
return result;
}
diff --git
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProcessInstanceServiceImpl.java
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProcessInstanceServiceImpl.java
index 57171c7..5189616 100644
---
a/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProcessInstanceServiceImpl.java
+++
b/dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProcessInstanceServiceImpl.java
@@ -506,7 +506,7 @@ public class ProcessInstanceServiceImpl extends
BaseServiceImpl implements Proce
ProcessDefinition processDefinition =
processDefineMapper.queryByCode(processInstance.getProcessDefinitionCode());
List<ProcessTaskRelationLog> taskRelationList =
JSONUtils.toList(taskRelationJson, ProcessTaskRelationLog.class);
//check workflow json is valid
- result =
processDefinitionService.checkProcessNodeList(taskRelationJson);
+ result =
processDefinitionService.checkProcessNodeList(taskRelationJson,
taskDefinitionLogs);
if (result.get(Constants.STATUS) != Status.SUCCESS) {
return result;
}
diff --git
a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ProcessDefinitionServiceTest.java
b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ProcessDefinitionServiceTest.java
index 497c3d3..5d7e87a 100644
---
a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ProcessDefinitionServiceTest.java
+++
b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ProcessDefinitionServiceTest.java
@@ -30,11 +30,13 @@ import
org.apache.dolphinscheduler.common.enums.ReleaseState;
import org.apache.dolphinscheduler.common.enums.UserType;
import org.apache.dolphinscheduler.common.enums.WarningType;
import org.apache.dolphinscheduler.common.graph.DAG;
+import org.apache.dolphinscheduler.common.utils.JSONUtils;
import org.apache.dolphinscheduler.dao.entity.DagData;
import org.apache.dolphinscheduler.dao.entity.ProcessDefinition;
import org.apache.dolphinscheduler.dao.entity.ProcessTaskRelation;
import org.apache.dolphinscheduler.dao.entity.Project;
import org.apache.dolphinscheduler.dao.entity.Schedule;
+import org.apache.dolphinscheduler.dao.entity.TaskDefinitionLog;
import org.apache.dolphinscheduler.dao.entity.Tenant;
import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.mapper.DataSourceMapper;
@@ -82,6 +84,14 @@ public class ProcessDefinitionServiceTest {
+
"\"postTaskVersion\":1,\"conditionType\":0,\"conditionParams\":\"{}\"},{\"name\":\"\",\"preTaskCode\":123456789,"
+
"\"preTaskVersion\":1,\"postTaskCode\":123451234,\"postTaskVersion\":1,\"conditionType\":0,\"conditionParams\":\"{}\"}]";
+ private static final String taskDefinitionJson =
"[{\"code\":123456789,\"name\":\"test1\",\"version\":1,\"description\":\"\",\"delayTime\":0,\"taskType\":\"SHELL\","
+
+
"\"taskParams\":{\"resourceList\":[],\"localParams\":[],\"rawScript\":\"echo
1\",\"dependence\":{},\"conditionResult\":{\"successNode\":[],\"failedNode\":[]},\"waitStartTimeout\":{},"
+
+
"\"switchResult\":{}},\"flag\":\"YES\",\"taskPriority\":\"MEDIUM\",\"workerGroup\":\"default\",\"failRetryTimes\":0,\"failRetryInterval\":1,\"timeoutFlag\":\"CLOSE\","
+
+
"\"timeoutNotifyStrategy\":null,\"timeout\":0,\"environmentCode\":-1},{\"code\":123451234,\"name\":\"test2\",\"version\":1,\"description\":\"\",\"delayTime\":0,\"taskType\":\"SHELL\","
+
+
"\"taskParams\":{\"resourceList\":[],\"localParams\":[],\"rawScript\":\"echo
2\",\"dependence\":{},\"conditionResult\":{\"successNode\":[],\"failedNode\":[]},\"waitStartTimeout\":{},"
+
+
"\"switchResult\":{}},\"flag\":\"YES\",\"taskPriority\":\"MEDIUM\",\"workerGroup\":\"default\",\"failRetryTimes\":0,\"failRetryInterval\":1,\"timeoutFlag\":\"CLOSE\","
+
+
"\"timeoutNotifyStrategy\":\"WARN\",\"timeout\":0,\"environmentCode\":-1}]";
+
@InjectMocks
private ProcessDefinitionServiceImpl processDefinitionService;
@@ -483,10 +493,12 @@ public class ProcessDefinitionServiceTest {
@Test
public void testCheckProcessNodeList() {
- Map<String, Object> dataNotValidRes =
processDefinitionService.checkProcessNodeList(null);
+ Map<String, Object> dataNotValidRes =
processDefinitionService.checkProcessNodeList(null, null);
Assert.assertEquals(Status.DATA_IS_NOT_VALID,
dataNotValidRes.get(Constants.STATUS));
- Map<String, Object> taskEmptyRes =
processDefinitionService.checkProcessNodeList(taskRelationJson);
+ List<TaskDefinitionLog> taskDefinitionLogs =
JSONUtils.toList(taskDefinitionJson, TaskDefinitionLog.class);
+
+ Map<String, Object> taskEmptyRes =
processDefinitionService.checkProcessNodeList(taskRelationJson,
taskDefinitionLogs);
Assert.assertEquals(Status.PROCESS_DAG_IS_EMPTY,
taskEmptyRes.get(Constants.STATUS));
}
diff --git
a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ProcessInstanceServiceTest.java
b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ProcessInstanceServiceTest.java
index 2074621..248ca68 100644
---
a/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ProcessInstanceServiceTest.java
+++
b/dolphinscheduler-api/src/test/java/org/apache/dolphinscheduler/api/service/ProcessInstanceServiceTest.java
@@ -36,11 +36,13 @@ import org.apache.dolphinscheduler.common.graph.DAG;
import org.apache.dolphinscheduler.common.model.TaskNode;
import org.apache.dolphinscheduler.common.model.TaskNodeRelation;
import org.apache.dolphinscheduler.common.utils.DateUtils;
+import org.apache.dolphinscheduler.common.utils.JSONUtils;
import org.apache.dolphinscheduler.dao.entity.ProcessDefinition;
import org.apache.dolphinscheduler.dao.entity.ProcessDefinitionLog;
import org.apache.dolphinscheduler.dao.entity.ProcessInstance;
import org.apache.dolphinscheduler.dao.entity.Project;
import org.apache.dolphinscheduler.dao.entity.TaskDefinition;
+import org.apache.dolphinscheduler.dao.entity.TaskDefinitionLog;
import org.apache.dolphinscheduler.dao.entity.TaskInstance;
import org.apache.dolphinscheduler.dao.entity.Tenant;
import org.apache.dolphinscheduler.dao.entity.User;
@@ -128,6 +130,17 @@ public class ProcessInstanceServiceTest {
+
":[\"\"],\"failedNode\":[\"\"]},\"dependence\":{}},\"flag\":\"NORMAL\",\"taskPriority\":\"MEDIUM\",\"workerGroup\":\"default\","
+
"\"failRetryTimes\":\"0\",\"failRetryInterval\":\"1\",\"timeoutFlag\":\"CLOSE\",\"timeoutNotifyStrategy\":\"\",\"timeout\":null,\"delayTime\":\"0\"}]";
+ private String taskRelationJson =
"[{\"name\":\"\",\"preTaskCode\":4254865123776,\"preTaskVersion\":1,\"postTaskCode\":4254862762304,\"postTaskVersion\":1,\"conditionType\":0,"
+
+
"\"conditionParams\":{}},{\"name\":\"\",\"preTaskCode\":0,\"preTaskVersion\":0,\"postTaskCode\":4254865123776,\"postTaskVersion\":1,\"conditionType\":0,\"conditionParams\":{}}]";
+
+ private String taskDefinitionJson =
"[{\"code\":4254862762304,\"name\":\"test1\",\"version\":1,\"description\":\"\",\"delayTime\":0,\"taskType\":\"SHELL\",\"taskParams\":{\"resourceList\":[],"
+
+ "\"localParams\":[],\"rawScript\":\"echo
1\",\"dependence\":{},\"conditionResult\":{\"successNode\":[],\"failedNode\":[]},\"waitStartTimeout\":{},\"switchResult\":{}},\"flag\":\"YES\","
+
+
"\"taskPriority\":\"MEDIUM\",\"workerGroup\":\"default\",\"failRetryTimes\":0,\"failRetryInterval\":1,\"timeoutFlag\":\"CLOSE\",\"timeoutNotifyStrategy\":null,\"timeout\":0,"
+
+
"\"environmentCode\":-1},{\"code\":4254865123776,\"name\":\"test2\",\"version\":1,\"description\":\"\",\"delayTime\":0,\"taskType\":\"SHELL\",\"taskParams\":{\"resourceList\":[],"
+
+ "\"localParams\":[],\"rawScript\":\"echo
2\",\"dependence\":{},\"conditionResult\":{\"successNode\":[],\"failedNode\":[]},\"waitStartTimeout\":{},\"switchResult\":{}},\"flag\":\"YES\","
+
+
"\"taskPriority\":\"MEDIUM\",\"workerGroup\":\"default\",\"failRetryTimes\":0,\"failRetryInterval\":1,\"timeoutFlag\":\"CLOSE\",\"timeoutNotifyStrategy\":\"WARN\",\"timeout\":0,"
+
+ "\"environmentCode\":-1}]";
+
@Test
public void testQueryProcessInstanceList() {
long projectCode = 1L;
@@ -425,10 +438,12 @@ public class ProcessInstanceServiceTest {
when(processService.getTenantForProcess(Mockito.anyInt(),
Mockito.anyInt())).thenReturn(tenant);
when(processService.updateProcessInstance(processInstance)).thenReturn(1);
when(processService.saveProcessDefine(loginUser, processDefinition,
Boolean.TRUE, Boolean.FALSE)).thenReturn(1);
-
when(processDefinitionService.checkProcessNodeList(shellJson)).thenReturn(result);
+
+ List<TaskDefinitionLog> taskDefinitionLogs =
JSONUtils.toList(taskDefinitionJson, TaskDefinitionLog.class);
+ when(processDefinitionService.checkProcessNodeList(taskRelationJson,
taskDefinitionLogs)).thenReturn(result);
putMsg(result, Status.SUCCESS, projectCode);
Map<String, Object> processInstanceFinishRes =
processInstanceService.updateProcessInstance(loginUser, projectCode, 1,
- shellJson, taskJson,"2020-02-21 00:00:00", true, "", "", 0,
"root");
+ taskRelationJson, taskDefinitionJson,"2020-02-21 00:00:00", true,
"", "", 0, "root");
Assert.assertEquals(Status.SUCCESS,
processInstanceFinishRes.get(Constants.STATUS));
//success
@@ -437,7 +452,7 @@ public class ProcessInstanceServiceTest {
when(processService.saveProcessDefine(loginUser, processDefinition,
Boolean.FALSE, Boolean.FALSE)).thenReturn(1);
Map<String, Object> successRes =
processInstanceService.updateProcessInstance(loginUser, projectCode, 1,
- shellJson, taskJson,"2020-02-21 00:00:00", Boolean.FALSE, "", "",
0, "root");
+ taskRelationJson, taskDefinitionJson,"2020-02-21 00:00:00",
Boolean.FALSE, "", "", 0, "root");
Assert.assertEquals(Status.SUCCESS, successRes.get(Constants.STATUS));
}
@@ -638,5 +653,4 @@ public class ProcessInstanceServiceTest {
result.put(Constants.MSG, status.getMsg());
}
}
-
-}
\ No newline at end of file
+}
diff --git
a/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/quartz/cron/AbstractCycle.java
b/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/quartz/cron/AbstractCycle.java
index 60c8623..b00f147 100644
---
a/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/quartz/cron/AbstractCycle.java
+++
b/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/quartz/cron/AbstractCycle.java
@@ -173,6 +173,16 @@ public abstract class AbstractCycle {
FieldExpression dayOfWeekFieldExpression =
dayOfWeekField.getExpression();
return (dayOfWeekFieldExpression instanceof Every ||
dayOfWeekFieldExpression instanceof Always);
}
+
+ /**
+ * whether the year field has a value of every or always
+ *
+ * @return if year field has a value of every or always return true,else
return false
+ */
+ protected boolean yearFieldIsEvery() {
+ FieldExpression yearFieldExpression = yearField.getExpression();
+ return (yearFieldExpression instanceof Every || yearFieldExpression
instanceof Always);
+ }
/**
* get cycle enum
diff --git
a/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/quartz/cron/CronUtils.java
b/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/quartz/cron/CronUtils.java
index d784722..49810cd 100644
---
a/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/quartz/cron/CronUtils.java
+++
b/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/quartz/cron/CronUtils.java
@@ -22,6 +22,7 @@ import static
org.apache.dolphinscheduler.service.quartz.cron.CycleFactory.hour;
import static org.apache.dolphinscheduler.service.quartz.cron.CycleFactory.min;
import static
org.apache.dolphinscheduler.service.quartz.cron.CycleFactory.month;
import static
org.apache.dolphinscheduler.service.quartz.cron.CycleFactory.week;
+import static
org.apache.dolphinscheduler.service.quartz.cron.CycleFactory.year;
import static com.cronutils.model.CronType.QUARTZ;
@@ -90,7 +91,7 @@ public class CronUtils {
* @return CycleEnum
*/
public static CycleEnum getMaxCycle(Cron cron) {
- return
min(cron).addCycle(hour(cron)).addCycle(day(cron)).addCycle(week(cron)).addCycle(month(cron)).getCycle();
+ return
min(cron).addCycle(hour(cron)).addCycle(day(cron)).addCycle(week(cron)).addCycle(month(cron)).addCycle(year(cron)).getCycle();
}
/**
@@ -100,7 +101,7 @@ public class CronUtils {
* @return CycleEnum
*/
public static CycleEnum getMiniCycle(Cron cron) {
- return
min(cron).addCycle(hour(cron)).addCycle(day(cron)).addCycle(week(cron)).addCycle(month(cron)).getMiniCycle();
+ return
min(cron).addCycle(hour(cron)).addCycle(day(cron)).addCycle(week(cron)).addCycle(month(cron)).addCycle(year(cron)).getMiniCycle();
}
/**
@@ -186,7 +187,7 @@ public class CronUtils {
*/
public static List<Date> getSelfFireDateList(final Date startTime, final
Date endTime, final List<Schedule> schedules) {
List<Date> result = new ArrayList<>();
- if(startTime.equals(endTime)){
+ if (startTime.equals(endTime)) {
result.add(startTime);
return result;
}
diff --git
a/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/quartz/cron/CycleFactory.java
b/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/quartz/cron/CycleFactory.java
index 1f807dc..9f931d2 100644
---
a/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/quartz/cron/CycleFactory.java
+++
b/dolphinscheduler-service/src/main/java/org/apache/dolphinscheduler/service/quartz/cron/CycleFactory.java
@@ -72,6 +72,15 @@ public class CycleFactory {
public static AbstractCycle month(Cron cron) {
return new MonthCycle(cron);
}
+
+ /**
+ * year
+ * @param cron cron
+ * @return AbstractCycle
+ */
+ public static AbstractCycle year(Cron cron) {
+ return new YearCycle(cron);
+ }
/**
* day cycle
@@ -275,4 +284,52 @@ public class CycleFactory {
return null;
}
}
+
+ /**
+ * year cycle
+ */
+ public static class YearCycle extends AbstractCycle {
+ public YearCycle(Cron cron) {
+ super(cron);
+ }
+
+ /**
+ * get cycle
+ * @return CycleEnum
+ */
+ @Override
+ protected CycleEnum getCycle() {
+ boolean flag = (minFiledIsSetAll()
+ && hourFiledIsSetAll()
+ && dayOfMonthFieldIsSetAll()
+ && dayOfWeekField.getExpression() instanceof QuestionMark
+ && monthFieldIsSetAll())
+ && yearFieldIsEvery() ||
+ (minFiledIsSetAll()
+ && hourFiledIsSetAll()
+ && dayOfMonthField.getExpression() instanceof
QuestionMark
+ && dayofWeekFieldIsSetAll()
+ && monthFieldIsSetAll()
+ && yearFieldIsEvery());
+
+ if (flag) {
+ return CycleEnum.YEAR;
+ }
+
+ return null;
+ }
+
+ /**
+ * get mini cycle
+ * @return CycleEnum
+ */
+ @Override
+ protected CycleEnum getMiniCycle() {
+ if (yearFieldIsEvery()) {
+ return CycleEnum.YEAR;
+ }
+
+ return null;
+ }
+ }
}
diff --git
a/dolphinscheduler-service/src/test/java/org/apache/dolphinscheduler/service/quartz/cron/CronUtilsTest.java
b/dolphinscheduler-service/src/test/java/org/apache/dolphinscheduler/service/quartz/cron/CronUtilsTest.java
index 55cc19d..4fbcd8f 100644
---
a/dolphinscheduler-service/src/test/java/org/apache/dolphinscheduler/service/quartz/cron/CronUtilsTest.java
+++
b/dolphinscheduler-service/src/test/java/org/apache/dolphinscheduler/service/quartz/cron/CronUtilsTest.java
@@ -95,6 +95,20 @@ public class CronUtilsTest {
CycleEnum cycleEnum3 = CronUtils.getMiniCycle(CronUtils.parse2Cron("0
* * * * ? *"));
Assert.assertEquals("MINUTE", cycleEnum3.name());
+
+ CycleEnum cycleEnum4 = CronUtils.getMaxCycle(CronUtils.parse2Cron("0 0
7 * 1 ? *"));
+ Assert.assertEquals("YEAR", cycleEnum4.name());
+ cycleEnum4 = CronUtils.getMiniCycle(CronUtils.parse2Cron("0 0 7 * 1 ?
*"));
+ Assert.assertEquals("DAY", cycleEnum4.name());
+
+ CycleEnum cycleEnum5 = CronUtils.getMaxCycle(CronUtils.parse2Cron("0 0
7 * 1/1 ? *"));
+ Assert.assertEquals("MONTH", cycleEnum5.name());
+
+ CycleEnum cycleEnum6 = CronUtils.getMaxCycle(CronUtils.parse2Cron("0 0
7 * 1-2 ? *"));
+ Assert.assertEquals("YEAR", cycleEnum6.name());
+
+ CycleEnum cycleEnum7 = CronUtils.getMaxCycle(CronUtils.parse2Cron("0 0
7 * 1,2 ? *"));
+ Assert.assertEquals("YEAR", cycleEnum7.name());
}
/**
@@ -113,7 +127,7 @@ public class CronUtilsTest {
.instance();
// minute cycle
String[] cronArayy = new String[]{"* * * * * ? *","* 0 * * * ? *",
- "* 5 * * 3/5 ? *","0 0 * * * ? *"};
+ "* 5 * * 3/5 ? *","0 0 * * * ? *", "0 0 7 * 1 ? *", "0 0 7 *
1/1 ? *", "0 0 7 * 1-2 ? *" , "0 0 7 * 1,2 ? *"};
for(String minCrontab:cronArayy){
if (!org.quartz.CronExpression.isValidExpression(minCrontab)) {
throw new RuntimeException(minCrontab+" verify failure, cron
expression not valid");
@@ -155,6 +169,14 @@ public class CronUtilsTest {
logger.info("dayOfWeekField instanceof
On:"+(dayOfWeekField.getExpression() instanceof On));
logger.info("dayOfWeekField instanceof
And:"+(dayOfWeekField.getExpression() instanceof And));
logger.info("dayOfWeekField instanceof
QuestionMark:"+(dayOfWeekField.getExpression() instanceof QuestionMark));
+
+ CronField yearField = cron.retrieve(CronFieldName.YEAR);
+ logger.info("yearField instanceof
Between:"+(yearField.getExpression() instanceof Between));
+ logger.info("yearField instanceof
Always:"+(yearField.getExpression() instanceof Always));
+ logger.info("yearField instanceof
Every:"+(yearField.getExpression() instanceof Every));
+ logger.info("yearField instanceof On:"+(yearField.getExpression()
instanceof On));
+ logger.info("yearField instanceof And:"+(yearField.getExpression()
instanceof And));
+ logger.info("yearField instanceof
QuestionMark:"+(yearField.getExpression() instanceof QuestionMark));
CycleEnum cycleEnum = CronUtils.getMaxCycle(minCrontab);
if(cycleEnum !=null){
@@ -204,4 +226,4 @@ public class CronUtilsTest {
expirationTime = CronUtils.getExpirationTime(startTime,
CycleEnum.YEAR);
Assert.assertEquals("2020-02-07 18:30:00",
DateUtils.dateToString(expirationTime));
}
-}
\ No newline at end of file
+}
diff --git
a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/AbstractCommandExecutor.java
b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/AbstractCommandExecutor.java
index 805d035..4112e2c 100644
---
a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/AbstractCommandExecutor.java
+++
b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/api/AbstractCommandExecutor.java
@@ -122,10 +122,12 @@ public abstract class AbstractCommandExecutor {
// merge error information to standard output stream
processBuilder.redirectErrorStream(true);
- // setting up user to run commands
- command.add("sudo");
- command.add("-u");
- command.add(taskRequest.getTenantCode());
+ // if sudo.enable=true,setting up user to run commands
+ if (OSUtils.isSudoEnable()) {
+ command.add("sudo");
+ command.add("-u");
+ command.add(taskRequest.getTenantCode());
+ }
command.add(commandInterpreter());
command.addAll(Collections.emptyList());
command.add(commandFile);
diff --git
a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/util/OSUtils.java
b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/util/OSUtils.java
index e8c66a7..f34268d 100644
---
a/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/util/OSUtils.java
+++
b/dolphinscheduler-task-plugin/dolphinscheduler-task-api/src/main/java/org/apache/dolphinscheduler/plugin/task/util/OSUtils.java
@@ -18,6 +18,7 @@
package org.apache.dolphinscheduler.plugin.task.util;
import org.apache.dolphinscheduler.plugin.task.api.ShellExecutor;
+import org.apache.dolphinscheduler.spi.utils.PropertyUtils;
import org.apache.dolphinscheduler.spi.utils.StringUtils;
import java.io.IOException;
@@ -41,6 +42,15 @@ public class OSUtils {
}
/**
+ * use sudo or not
+ *
+ * @return true is use sudo
+ */
+ public static boolean isSudoEnable() {
+ return PropertyUtils.getBoolean("sudo.enable", Boolean.TRUE);
+ }
+
+ /**
* whether is macOS
*
* @return true if mac
diff --git
a/dolphinscheduler-task-plugin/dolphinscheduler-task-datax/src/main/java/org/apache/dolphinscheduler/plugin/task/datax/DataxUtils.java
b/dolphinscheduler-task-plugin/dolphinscheduler-task-datax/src/main/java/org/apache/dolphinscheduler/plugin/task/datax/DataxUtils.java
index c4edc4e..42ba975 100644
---
a/dolphinscheduler-task-plugin/dolphinscheduler-task-datax/src/main/java/org/apache/dolphinscheduler/plugin/task/datax/DataxUtils.java
+++
b/dolphinscheduler-task-plugin/dolphinscheduler-task-datax/src/main/java/org/apache/dolphinscheduler/plugin/task/datax/DataxUtils.java
@@ -19,6 +19,7 @@ package org.apache.dolphinscheduler.plugin.task.datax;
import org.apache.dolphinscheduler.spi.enums.DbType;
+import
com.alibaba.druid.sql.dialect.clickhouse.parser.ClickhouseStatementParser;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.alibaba.druid.sql.dialect.oracle.parser.OracleStatementParser;
import com.alibaba.druid.sql.dialect.postgresql.parser.PGSQLStatementParser;
@@ -91,6 +92,8 @@ public class DataxUtils {
return new OracleStatementParser(sql);
case SQLSERVER:
return new SQLServerStatementParser(sql);
+ case CLICKHOUSE:
+ return new ClickhouseStatementParser(sql);
default:
return null;
}
diff --git a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/dag.vue
b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/dag.vue
index c79a59f..bac2aa1 100644
--- a/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/dag.vue
+++ b/dolphinscheduler-ui/src/js/conf/home/pages/dag/_source/dag.vue
@@ -330,11 +330,11 @@
})
if (this.type === 'instance') {
this.$router.push({
- path: `/projects/${this.projectCode}/instance/list`
+ path:
`/projects/${this.projectCode}/instance/list/${methodParam}`
})
} else {
this.$router.push({
- path: `/projects/${this.projectCode}/definition/list`
+ path:
`/projects/${this.projectCode}/definition/list/${methodParam}`
})
}
})
diff --git
a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/_source/list.vue
b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/_source/list.vue
index ab68e5a..98ab713 100755
---
a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/_source/list.vue
+++
b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/list/_source/list.vue
@@ -51,8 +51,11 @@
<span>{{scope.row.updateTime | formatDate}}</span>
</template>
</el-table-column>
- <el-table-column :label="$t('Operation')" width="150">
+ <el-table-column :label="$t('Operation')" width="180">
<template slot-scope="scope">
+ <el-tooltip :content="$t('ReUpload File')" placement="top"
:enterable="false">
+ <span><el-button type="primary" size="mini"
icon="el-icon-refresh-right" @click="_reUploadFile(scope.row)"
v-show="scope.row.directory? false: true" circle></el-button></span>
+ </el-tooltip>
<el-tooltip :content="$t('Edit')" placement="top">
<span><el-button type="primary" size="mini"
icon="el-icon-edit-outline" @click="_edit(scope.row)"
:disabled="_rtDisb(scope.row)" circle></el-button></span>
</el-tooltip>
@@ -92,7 +95,9 @@
import { filtTypeArr } from '../../_source/common'
import { bytesToSize } from '@/module/util/util'
import { downloadFile } from '@/module/download'
+ import { findComponentDownward } from '@/module/util/'
import localStore from '@/module/util/localStorage'
+
export default {
name: 'file-manage-list',
data () {
@@ -123,6 +128,9 @@
this.$router.push({ path: `/resource/file/list/${item.id}` })
}
},
+ _reUploadFile (item) {
+ findComponentDownward(this.$root, 'roof-nav')._fileReUpload(item)
+ },
_downloadFile (item) {
downloadFile(`resources/${item.id}/download`)
},
diff --git
a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/subdirectory/_source/list.vue
b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/subdirectory/_source/list.vue
index 3e1eac1..517e5e0 100755
---
a/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/subdirectory/_source/list.vue
+++
b/dolphinscheduler-ui/src/js/conf/home/pages/resource/pages/file/pages/subdirectory/_source/list.vue
@@ -50,8 +50,11 @@
<span>{{scope.row.updateTime | formatDate}}</span>
</template>
</el-table-column>
- <el-table-column :label="$t('Operation')" width="150">
+ <el-table-column :label="$t('Operation')" width="180">
<template slot-scope="scope">
+ <el-tooltip :content="$t('ReUpload File')" placement="top"
:enterable="false">
+ <span><el-button type="primary" size="mini"
icon="el-icon-refresh-right" @click="_reUploadFile(scope.row)"
v-show="scope.row.directory? false: true" circle></el-button></span>
+ </el-tooltip>
<el-tooltip :content="$t('Edit')" placement="top"
:enterable="false">
<span><el-button type="primary" size="mini"
icon="el-icon-edit-outline" @click="_edit(scope.row)"
:disabled="_rtDisb(scope.row)" circle></el-button></span>
</el-tooltip>
@@ -90,6 +93,7 @@
import { mapActions } from 'vuex'
import { filtTypeArr } from '../../_source/common'
import { bytesToSize } from '@/module/util/util'
+ import { findComponentDownward } from '@/module/util/'
import { downloadFile } from '@/module/download'
import localStore from '@/module/util/localStorage'
@@ -122,6 +126,9 @@
this.$router.push({ path: `/resource/file/list/${item.id}` })
}
},
+ _reUploadFile (item) {
+ findComponentDownward(this.$root, 'roof-nav')._fileReUpload(item)
+ },
_downloadFile (item) {
downloadFile(`resources/${item.id}/download`)
},
diff --git
a/dolphinscheduler-ui/src/js/module/components/fileUpdate/fileReUpload.vue
b/dolphinscheduler-ui/src/js/module/components/fileUpdate/fileReUpload.vue
index 4b64d66..c58f43b 100644
--- a/dolphinscheduler-ui/src/js/module/components/fileUpdate/fileReUpload.vue
+++ b/dolphinscheduler-ui/src/js/module/components/fileUpdate/fileReUpload.vue
@@ -1,26 +1,27 @@
/*
- * 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.
- */
+* 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.
+*/
<template>
<m-popup
- ref="popup"
- :ok-text="$t('Upload')"
- :nameText="$t('ReUpload File')"
- @ok="_ok"
- :disabled="progress === 0 ? false : true">
+ ref="popup"
+ :ok-text="$t('Upload')"
+ :nameText="$t('ReUpload File')"
+ @ok="_ok"
+ @close="_close"
+ :disabled="progress === 0 ? false : true">
<template slot="content">
<form name="files" enctype="multipart/form-data" method="post">
<div class="file-update-model"
@@ -44,11 +45,11 @@
<template slot="name"><strong>*</strong>{{$t('File
Name')}}</template>
<template slot="content">
<el-input
- type="input"
- size="small"
- v-model="name"
- :disabled="progress !== 0"
- :placeholder="$t('Please enter name')">
+ type="input"
+ size="small"
+ v-model="name"
+ :disabled="true"
+ :placeholder="$t('Please enter name')">
</el-input>
</template>
</m-list-box-f>
@@ -56,11 +57,11 @@
<template slot="name">{{$t('Description')}}</template>
<template slot="content">
<el-input
- type="textarea"
- size="small"
- v-model="description"
- :disabled="progress !== 0"
- :placeholder="$t('Please enter description')">
+ type="textarea"
+ size="small"
+ v-model="description"
+ :disabled="progress !== 0"
+ :placeholder="$t('Please enter description')">
</el-input>
</template>
</m-list-box-f>
@@ -92,7 +93,7 @@
import mProgressBar from '@/module/components/progressBar/progressBar'
export default {
- name: 'file-update',
+ name: 'file-upload',
data () {
return {
store,
@@ -105,17 +106,21 @@
// file
file: null,
currentDir: '/',
+ id: null,
// Whether to drag upload
dragOver: false
}
},
watch: {
+ originalFileData: {
+ deep: true,
+ handler () {
+ this._init()
+ }
+ }
},
props: {
- type: String,
- fileName: String,
- desc: String,
- id: Number
+ originalFileData: Object
},
methods: {
/**
@@ -124,7 +129,7 @@
_ok () {
this.$refs.popup.spinnerLoading = true
if (this._validation()) {
- if (this.fileName === this.name) {
+ if (this.originalFileData.fileName === this.name) {
const isLt1024M = this.file.size / 1024 / 1024 < 1024
if (isLt1024M) {
this._formDataUpdate().then(res => {
@@ -139,10 +144,8 @@
this.$refs.popup.spinnerLoading = false
}
} else {
- this.store.dispatch('resource/resourceVerifyName', {
- fullName: '/' + this.name,
- type: this.type
- }).then(res => {
+ const params = { fullName: this.currentDir + this.name, type:
'FILE' }
+ this.store.dispatch('resource/resourceVerifyName',
params).then(res => {
const isLt1024M = this.file.size / 1024 / 1024 < 1024
if (isLt1024M) {
this._formDataUpdate().then(res => {
@@ -165,6 +168,9 @@
this.$refs.popup.spinnerLoading = false
}
},
+ _close () {
+ this.$emit('closeFileUpload')
+ },
/**
* validation
*/
@@ -186,19 +192,19 @@
return new Promise((resolve, reject) => {
let self = this
let formData = new FormData()
+
formData.append('file', this.file)
formData.append('name', this.name)
formData.append('description', this.description)
- formData.append('id', this.id)
- formData.append('type', this.type)
- io.post('resources/update', res => {
+ formData.append('type', 'FILE')
+ io.put('resources/' + this.id, res => {
this.$message.success(res.msg)
resolve()
- self.$emit('onUpdate')
+ self.$emit('onUploadFile')
this.reset()
}, e => {
reject(e)
- self.$emit('close')
+ self.$emit('closeFileUpload')
this.$message.error(e.msg || '')
this.reset()
}, {
@@ -244,11 +250,21 @@
this.file = file
this.name = file.name
this.$refs.file.value = null
+ },
+ _init () {
+ if (this.originalFileData) {
+ this.id = this.originalFileData.id
+ this.name = this.originalFileData.fileName
+ if (this.originalFileData.desc) {
+ this.description = this.originalFileData.desc
+ }
+ this.currentDir = this.originalFileData.fullName.substring(0,
this.originalFileData.fullName.length - this.originalFileData.fileName.length)
+ }
}
},
mounted () {
- this.name = this.fileName
- this.description = this.desc
+ this.reset()
+ this._init()
},
components: { mPopup, mListBoxF, mProgressBar }
}
diff --git a/dolphinscheduler-ui/src/js/module/components/nav/nav.vue
b/dolphinscheduler-ui/src/js/module/components/nav/nav.vue
index 68ff673..27b0211 100644
--- a/dolphinscheduler-ui/src/js/module/components/nav/nav.vue
+++ b/dolphinscheduler-ui/src/js/module/components/nav/nav.vue
@@ -163,6 +163,17 @@
width="auto">
<m-resource-child-update :type="type" :id="id"
@onProgressResourceChildUpdate="onProgressResourceChildUpdate"
@onUpdateResourceChildUpdate="onUpdateResourceChildUpdate"
@onArchiveFileChildUpdate="onArchiveResourceChildUpdate"
@closeResourceChildUpdate="closeResourceChildUpdate"></m-resource-child-update>
</el-dialog>
+
+ <el-dialog
+ :visible.sync="fileUploadDialog"
+ append-to-body="true"
+ width="auto">
+ <m-file-upload
+ :originalFileData="originalFileData"
+ @onUploadFile="onUploadFile"
+ @closeFileUpload="closeFileUpload">
+ </m-file-upload>
+ </el-dialog>
</div>
</template>
<script>
@@ -174,6 +185,7 @@
import mFileChildUpdate from '@/module/components/fileUpdate/fileChildUpdate'
import mResourceChildUpdate from
'@/module/components/fileUpdate/resourceChildUpdate'
import mDefinitionUpdate from
'@/module/components/fileUpdate/definitionUpdate'
+ import mFileUpload from '@/module/components/fileUpdate/fileReUpload'
import mProgressBar from '@/module/components/progressBar/progressBar'
import { findLocale, localeList } from '@/module/i18n/config'
@@ -202,7 +214,11 @@
fileUpdateDialog: false,
fileChildUpdateDialog: false,
id: null,
- resourceChildUpdateDialog: false
+ fileName: '',
+ description: '',
+ originalFileData: {},
+ resourceChildUpdateDialog: false,
+ fileUploadDialog: false
}
},
@@ -250,16 +266,13 @@
this.progress = 0
this.definitionUpdateDialog = false
},
-
onArchiveDefinition () {
this.isUpdate = true
},
-
closeDefinition () {
this.progress = 0
this.definitionUpdateDialog = false
},
-
onProgressFileUpdate (val) {
this.progress = val
},
@@ -270,6 +283,17 @@
this.progress = 0
this.fileUpdateDialog = false
},
+ onUploadFile () {
+ let self = this
+ findComponentDownward(self.$root,
'resource-list-index-FILE')._updateList()
+ this.isUpdate = false
+ this.progress = 0
+ this.fileUploadDialog = false
+ },
+ closeFileUpload () {
+ this.progress = 0
+ this.fileUploadDialog = false
+ },
onArchiveFileUpdate () {
this.isUpdate = true
},
@@ -277,7 +301,6 @@
this.progress = 0
this.fileUpdateDialog = false
},
-
_fileChildUpdate (type, data) {
if (this.progress) {
this._toggleArchive()
@@ -287,7 +310,14 @@
this.id = data
this.fileChildUpdateDialog = true
},
-
+ _fileReUpload (item) {
+ if (this.progress) {
+ this._toggleArchive()
+ return
+ }
+ this.originalFileData = item
+ this.fileUploadDialog = true
+ },
onProgressFileChildUpdate (val) {
this.progress = val
},
@@ -307,7 +337,6 @@
this.progress = 0
this.fileChildUpdateDialog = false
},
-
_resourceChildUpdate (type, data) {
if (this.progress) {
this._toggleArchive()
@@ -350,7 +379,6 @@
* Language switching
*/
_toggleLanguage (language) {
- console.log(language)
cookies.set('language', language, { path: '/' })
setTimeout(() => {
window.location.reload()
@@ -365,7 +393,7 @@
computed: {
...mapState('user', ['userInfo'])
},
- components: { mFileUpdate, mProgressBar, mDefinitionUpdate,
mFileChildUpdate, mResourceChildUpdate }
+ components: { mFileUpdate, mProgressBar, mDefinitionUpdate,
mFileChildUpdate, mResourceChildUpdate, mFileUpload }
}
</script>
diff --git a/dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js
b/dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js
index c749142..05caaf3 100755
--- a/dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js
+++ b/dolphinscheduler-ui/src/js/module/i18n/locale/en_US.js
@@ -727,6 +727,10 @@ export default {
webHook: 'WebHook',
Keyword: 'Keyword',
Secret: 'Secret',
+ MsgType: 'MsgType',
+ AtMobiles: '@Mobiles',
+ AtUserIds: '@UserIds',
+ IsAtAll: '@All',
Proxy: 'Proxy',
receivers: 'Receivers',
receiverCcs: 'ReceiverCcs',
diff --git a/dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js
b/dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js
index 4d62bb9..8d76c72 100644
--- a/dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js
+++ b/dolphinscheduler-ui/src/js/module/i18n/locale/zh_CN.js
@@ -726,6 +726,10 @@ export default {
webHook: 'Web钩子',
Keyword: '关键词',
Secret: '密钥',
+ MsgType: '消息类型',
+ AtMobiles: '@手机号',
+ AtUserIds: '@用户ID',
+ IsAtAll: '@所有人',
Proxy: '代理',
receivers: '收件人',
receiverCcs: '抄送人',