Browse Source
# Conflicts: # dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/ProcessInstanceService.java # dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProcessDefinitionServiceImpl.java # dolphinscheduler-api/src/main/java/org/apache/dolphinscheduler/api/service/impl/ProcessDefinitionVersionServiceImpl.javapull/3/MERGE
lenboo
4 years ago
170 changed files with 7561 additions and 5681 deletions
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,143 @@ |
|||||||
|
/* |
||||||
|
* 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.api.service.impl; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.api.enums.Status; |
||||||
|
import org.apache.dolphinscheduler.api.service.BaseService; |
||||||
|
import org.apache.dolphinscheduler.api.utils.Result; |
||||||
|
import org.apache.dolphinscheduler.common.Constants; |
||||||
|
import org.apache.dolphinscheduler.common.enums.UserType; |
||||||
|
import org.apache.dolphinscheduler.common.utils.HadoopUtils; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.User; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.text.MessageFormat; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* base service impl |
||||||
|
*/ |
||||||
|
public class BaseServiceImpl implements BaseService { |
||||||
|
|
||||||
|
/** |
||||||
|
* check admin |
||||||
|
* |
||||||
|
* @param user input user |
||||||
|
* @return ture if administrator, otherwise return false |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public boolean isAdmin(User user) { |
||||||
|
return user.getUserType() == UserType.ADMIN_USER; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* isNotAdmin |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param result result code |
||||||
|
* @return true if not administrator, otherwise false |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public boolean isNotAdmin(User loginUser, Map<String, Object> result) { |
||||||
|
//only admin can operate
|
||||||
|
if (!isAdmin(loginUser)) { |
||||||
|
putMsg(result, Status.USER_NO_OPERATION_PERM); |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* put message to map |
||||||
|
* |
||||||
|
* @param result result code |
||||||
|
* @param status status |
||||||
|
* @param statusParams status message |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void putMsg(Map<String, Object> result, Status status, Object... statusParams) { |
||||||
|
result.put(Constants.STATUS, status); |
||||||
|
if (statusParams != null && statusParams.length > 0) { |
||||||
|
result.put(Constants.MSG, MessageFormat.format(status.getMsg(), statusParams)); |
||||||
|
} else { |
||||||
|
result.put(Constants.MSG, status.getMsg()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* put message to result object |
||||||
|
* |
||||||
|
* @param result result code |
||||||
|
* @param status status |
||||||
|
* @param statusParams status message |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void putMsg(Result result, Status status, Object... statusParams) { |
||||||
|
result.setCode(status.getCode()); |
||||||
|
if (statusParams != null && statusParams.length > 0) { |
||||||
|
result.setMsg(MessageFormat.format(status.getMsg(), statusParams)); |
||||||
|
} else { |
||||||
|
result.setMsg(status.getMsg()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* check |
||||||
|
* |
||||||
|
* @param result result |
||||||
|
* @param bool bool |
||||||
|
* @param userNoOperationPerm status |
||||||
|
* @return check result |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public boolean check(Map<String, Object> result, boolean bool, Status userNoOperationPerm) { |
||||||
|
// only admin can operate
|
||||||
|
if (bool) { |
||||||
|
result.put(Constants.STATUS, userNoOperationPerm); |
||||||
|
result.put(Constants.MSG, userNoOperationPerm.getMsg()); |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* create tenant dir if not exists |
||||||
|
* |
||||||
|
* @param tenantCode tenant code |
||||||
|
* @throws IOException if hdfs operation exception |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void createTenantDirIfNotExists(String tenantCode) throws IOException { |
||||||
|
String resourcePath = HadoopUtils.getHdfsResDir(tenantCode); |
||||||
|
String udfsPath = HadoopUtils.getHdfsUdfDir(tenantCode); |
||||||
|
// init resource path and udf path
|
||||||
|
HadoopUtils.getInstance().mkdir(resourcePath); |
||||||
|
HadoopUtils.getInstance().mkdir(udfsPath); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* has perm |
||||||
|
* |
||||||
|
* @param operateUser operate user |
||||||
|
* @param createUserId create user id |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public boolean hasPerm(User operateUser, int createUserId) { |
||||||
|
return operateUser.getId() == createUserId || isAdmin(operateUser); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,671 @@ |
|||||||
|
/* |
||||||
|
* 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.api.service.impl; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.api.enums.Status; |
||||||
|
import org.apache.dolphinscheduler.api.service.DataSourceService; |
||||||
|
import org.apache.dolphinscheduler.api.utils.PageInfo; |
||||||
|
import org.apache.dolphinscheduler.api.utils.Result; |
||||||
|
import org.apache.dolphinscheduler.common.Constants; |
||||||
|
import org.apache.dolphinscheduler.common.enums.DbConnectType; |
||||||
|
import org.apache.dolphinscheduler.common.enums.DbType; |
||||||
|
import org.apache.dolphinscheduler.common.utils.CommonUtils; |
||||||
|
import org.apache.dolphinscheduler.common.utils.JSONUtils; |
||||||
|
import org.apache.dolphinscheduler.common.utils.StringUtils; |
||||||
|
import org.apache.dolphinscheduler.dao.datasource.BaseDataSource; |
||||||
|
import org.apache.dolphinscheduler.dao.datasource.DataSourceFactory; |
||||||
|
import org.apache.dolphinscheduler.dao.datasource.OracleDataSource; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.DataSource; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.User; |
||||||
|
import org.apache.dolphinscheduler.dao.mapper.DataSourceMapper; |
||||||
|
import org.apache.dolphinscheduler.dao.mapper.DataSourceUserMapper; |
||||||
|
|
||||||
|
import java.sql.Connection; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Date; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.HashSet; |
||||||
|
import java.util.LinkedHashMap; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
import org.springframework.transaction.annotation.Transactional; |
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||||
|
import com.fasterxml.jackson.databind.node.ObjectNode; |
||||||
|
|
||||||
|
/** |
||||||
|
* data source service impl |
||||||
|
*/ |
||||||
|
@Service |
||||||
|
public class DataSourceServiceImpl extends BaseServiceImpl implements DataSourceService { |
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(DataSourceServiceImpl.class); |
||||||
|
|
||||||
|
public static final String NAME = "name"; |
||||||
|
public static final String NOTE = "note"; |
||||||
|
public static final String TYPE = "type"; |
||||||
|
public static final String HOST = "host"; |
||||||
|
public static final String PORT = "port"; |
||||||
|
public static final String PRINCIPAL = "principal"; |
||||||
|
public static final String DATABASE = "database"; |
||||||
|
public static final String USER_NAME = "userName"; |
||||||
|
public static final String OTHER = "other"; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private DataSourceMapper dataSourceMapper; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private DataSourceUserMapper datasourceUserMapper; |
||||||
|
|
||||||
|
/** |
||||||
|
* create data source |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param name data source name |
||||||
|
* @param desc data source description |
||||||
|
* @param type data source type |
||||||
|
* @param parameter datasource parameters |
||||||
|
* @return create result code |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Result<Object> createDataSource(User loginUser, String name, String desc, DbType type, String parameter) { |
||||||
|
|
||||||
|
Result<Object> result = new Result<>(); |
||||||
|
// check name can use or not
|
||||||
|
if (checkName(name)) { |
||||||
|
putMsg(result, Status.DATASOURCE_EXIST); |
||||||
|
return result; |
||||||
|
} |
||||||
|
Result<Object> isConnection = checkConnection(type, parameter); |
||||||
|
if (Status.SUCCESS.getCode() != isConnection.getCode()) { |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
// build datasource
|
||||||
|
DataSource dataSource = new DataSource(); |
||||||
|
Date now = new Date(); |
||||||
|
|
||||||
|
dataSource.setName(name.trim()); |
||||||
|
dataSource.setNote(desc); |
||||||
|
dataSource.setUserId(loginUser.getId()); |
||||||
|
dataSource.setUserName(loginUser.getUserName()); |
||||||
|
dataSource.setType(type); |
||||||
|
dataSource.setConnectionParams(parameter); |
||||||
|
dataSource.setCreateTime(now); |
||||||
|
dataSource.setUpdateTime(now); |
||||||
|
dataSourceMapper.insert(dataSource); |
||||||
|
|
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* updateProcessInstance datasource |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param name data source name |
||||||
|
* @param desc data source description |
||||||
|
* @param type data source type |
||||||
|
* @param parameter datasource parameters |
||||||
|
* @param id data source id |
||||||
|
* @return update result code |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Result<Object> updateDataSource(int id, User loginUser, String name, String desc, DbType type, String parameter) { |
||||||
|
|
||||||
|
Result<Object> result = new Result<>(); |
||||||
|
// determine whether the data source exists
|
||||||
|
DataSource dataSource = dataSourceMapper.selectById(id); |
||||||
|
if (dataSource == null) { |
||||||
|
putMsg(result, Status.RESOURCE_NOT_EXIST); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
if (!hasPerm(loginUser, dataSource.getUserId())) { |
||||||
|
putMsg(result, Status.USER_NO_OPERATION_PERM); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
//check name can use or not
|
||||||
|
if (!name.trim().equals(dataSource.getName()) && checkName(name)) { |
||||||
|
putMsg(result, Status.DATASOURCE_EXIST); |
||||||
|
return result; |
||||||
|
} |
||||||
|
//check password,if the password is not updated, set to the old password.
|
||||||
|
ObjectNode paramObject = JSONUtils.parseObject(parameter); |
||||||
|
String password = paramObject.path(Constants.PASSWORD).asText(); |
||||||
|
if (StringUtils.isBlank(password)) { |
||||||
|
String oldConnectionParams = dataSource.getConnectionParams(); |
||||||
|
ObjectNode oldParams = JSONUtils.parseObject(oldConnectionParams); |
||||||
|
paramObject.put(Constants.PASSWORD, oldParams.path(Constants.PASSWORD).asText()); |
||||||
|
} |
||||||
|
// connectionParams json
|
||||||
|
String connectionParams = paramObject.toString(); |
||||||
|
|
||||||
|
Result<Object> isConnection = checkConnection(type, parameter); |
||||||
|
if (Status.SUCCESS.getCode() != isConnection.getCode()) { |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
Date now = new Date(); |
||||||
|
|
||||||
|
dataSource.setName(name.trim()); |
||||||
|
dataSource.setNote(desc); |
||||||
|
dataSource.setUserName(loginUser.getUserName()); |
||||||
|
dataSource.setType(type); |
||||||
|
dataSource.setConnectionParams(connectionParams); |
||||||
|
dataSource.setUpdateTime(now); |
||||||
|
dataSourceMapper.updateById(dataSource); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
private boolean checkName(String name) { |
||||||
|
List<DataSource> queryDataSource = dataSourceMapper.queryDataSourceByName(name.trim()); |
||||||
|
return queryDataSource != null && !queryDataSource.isEmpty(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* updateProcessInstance datasource |
||||||
|
* |
||||||
|
* @param id datasource id |
||||||
|
* @return data source detail |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> queryDataSource(int id) { |
||||||
|
|
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
DataSource dataSource = dataSourceMapper.selectById(id); |
||||||
|
if (dataSource == null) { |
||||||
|
putMsg(result, Status.RESOURCE_NOT_EXIST); |
||||||
|
return result; |
||||||
|
} |
||||||
|
// type
|
||||||
|
String dataSourceType = dataSource.getType().toString(); |
||||||
|
// name
|
||||||
|
String dataSourceName = dataSource.getName(); |
||||||
|
// desc
|
||||||
|
String desc = dataSource.getNote(); |
||||||
|
// parameter
|
||||||
|
String parameter = dataSource.getConnectionParams(); |
||||||
|
|
||||||
|
BaseDataSource datasourceForm = DataSourceFactory.getDatasource(dataSource.getType(), parameter); |
||||||
|
DbConnectType connectType = null; |
||||||
|
String hostSeperator = Constants.DOUBLE_SLASH; |
||||||
|
if (DbType.ORACLE.equals(dataSource.getType())) { |
||||||
|
connectType = ((OracleDataSource) datasourceForm).getConnectType(); |
||||||
|
if (DbConnectType.ORACLE_SID.equals(connectType)) { |
||||||
|
hostSeperator = Constants.AT_SIGN; |
||||||
|
} |
||||||
|
} |
||||||
|
String database = datasourceForm.getDatabase(); |
||||||
|
// jdbc connection params
|
||||||
|
String other = datasourceForm.getOther(); |
||||||
|
String address = datasourceForm.getAddress(); |
||||||
|
|
||||||
|
String[] hostsPorts = getHostsAndPort(address, hostSeperator); |
||||||
|
// ip host
|
||||||
|
String host = hostsPorts[0]; |
||||||
|
// prot
|
||||||
|
String port = hostsPorts[1]; |
||||||
|
String separator = ""; |
||||||
|
|
||||||
|
switch (dataSource.getType()) { |
||||||
|
case HIVE: |
||||||
|
case SQLSERVER: |
||||||
|
separator = ";"; |
||||||
|
break; |
||||||
|
case MYSQL: |
||||||
|
case POSTGRESQL: |
||||||
|
case CLICKHOUSE: |
||||||
|
case ORACLE: |
||||||
|
case PRESTO: |
||||||
|
separator = "&"; |
||||||
|
break; |
||||||
|
default: |
||||||
|
separator = "&"; |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
Map<String, String> otherMap = new LinkedHashMap<>(); |
||||||
|
if (other != null) { |
||||||
|
String[] configs = other.split(separator); |
||||||
|
for (String config : configs) { |
||||||
|
otherMap.put(config.split("=")[0], config.split("=")[1]); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
Map<String, Object> map = new HashMap<>(); |
||||||
|
map.put(NAME, dataSourceName); |
||||||
|
map.put(NOTE, desc); |
||||||
|
map.put(TYPE, dataSourceType); |
||||||
|
if (connectType != null) { |
||||||
|
map.put(Constants.ORACLE_DB_CONNECT_TYPE, connectType); |
||||||
|
} |
||||||
|
|
||||||
|
map.put(HOST, host); |
||||||
|
map.put(PORT, port); |
||||||
|
map.put(PRINCIPAL, datasourceForm.getPrincipal()); |
||||||
|
map.put(Constants.KERBEROS_KRB5_CONF_PATH, datasourceForm.getJavaSecurityKrb5Conf()); |
||||||
|
map.put(Constants.KERBEROS_KEY_TAB_USERNAME, datasourceForm.getLoginUserKeytabUsername()); |
||||||
|
map.put(Constants.KERBEROS_KEY_TAB_PATH, datasourceForm.getLoginUserKeytabPath()); |
||||||
|
map.put(DATABASE, database); |
||||||
|
map.put(USER_NAME, datasourceForm.getUser()); |
||||||
|
map.put(OTHER, otherMap); |
||||||
|
result.put(Constants.DATA_LIST, map); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* query datasource list by keyword |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param searchVal search value |
||||||
|
* @param pageNo page number |
||||||
|
* @param pageSize page size |
||||||
|
* @return data source list page |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> queryDataSourceListPaging(User loginUser, String searchVal, Integer pageNo, Integer pageSize) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
IPage<DataSource> dataSourceList; |
||||||
|
Page<DataSource> dataSourcePage = new Page<>(pageNo, pageSize); |
||||||
|
|
||||||
|
if (isAdmin(loginUser)) { |
||||||
|
dataSourceList = dataSourceMapper.selectPaging(dataSourcePage, 0, searchVal); |
||||||
|
} else { |
||||||
|
dataSourceList = dataSourceMapper.selectPaging(dataSourcePage, loginUser.getId(), searchVal); |
||||||
|
} |
||||||
|
|
||||||
|
List<DataSource> dataSources = dataSourceList != null ? dataSourceList.getRecords() : new ArrayList<>(); |
||||||
|
handlePasswd(dataSources); |
||||||
|
PageInfo<DataSource> pageInfo = new PageInfo<>(pageNo, pageSize); |
||||||
|
pageInfo.setTotalCount((int) (dataSourceList != null ? dataSourceList.getTotal() : 0L)); |
||||||
|
pageInfo.setLists(dataSources); |
||||||
|
result.put(Constants.DATA_LIST, pageInfo); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* handle datasource connection password for safety |
||||||
|
* |
||||||
|
* @param dataSourceList |
||||||
|
*/ |
||||||
|
private void handlePasswd(List<DataSource> dataSourceList) { |
||||||
|
for (DataSource dataSource : dataSourceList) { |
||||||
|
String connectionParams = dataSource.getConnectionParams(); |
||||||
|
ObjectNode object = JSONUtils.parseObject(connectionParams); |
||||||
|
object.put(Constants.PASSWORD, getHiddenPassword()); |
||||||
|
dataSource.setConnectionParams(object.toString()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* get hidden password (resolve the security hotspot) |
||||||
|
* |
||||||
|
* @return hidden password |
||||||
|
*/ |
||||||
|
private String getHiddenPassword() { |
||||||
|
return Constants.XXXXXX; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* query data resource list |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param type data source type |
||||||
|
* @return data source list page |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> queryDataSourceList(User loginUser, Integer type) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
|
||||||
|
List<DataSource> datasourceList; |
||||||
|
|
||||||
|
if (isAdmin(loginUser)) { |
||||||
|
datasourceList = dataSourceMapper.listAllDataSourceByType(type); |
||||||
|
} else { |
||||||
|
datasourceList = dataSourceMapper.queryDataSourceByType(loginUser.getId(), type); |
||||||
|
} |
||||||
|
|
||||||
|
result.put(Constants.DATA_LIST, datasourceList); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* verify datasource exists |
||||||
|
* |
||||||
|
* @param name datasource name |
||||||
|
* @return true if data datasource not exists, otherwise return false |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Result<Object> verifyDataSourceName(String name) { |
||||||
|
Result<Object> result = new Result<>(); |
||||||
|
List<DataSource> dataSourceList = dataSourceMapper.queryDataSourceByName(name); |
||||||
|
if (dataSourceList != null && !dataSourceList.isEmpty()) { |
||||||
|
putMsg(result, Status.DATASOURCE_EXIST); |
||||||
|
} else { |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
} |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* check connection |
||||||
|
* |
||||||
|
* @param type data source type |
||||||
|
* @param parameter data source parameters |
||||||
|
* @return true if connect successfully, otherwise false |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Result<Object> checkConnection(DbType type, String parameter) { |
||||||
|
Result<Object> result = new Result<>(); |
||||||
|
BaseDataSource datasource = DataSourceFactory.getDatasource(type, parameter); |
||||||
|
if (datasource == null) { |
||||||
|
putMsg(result, Status.DATASOURCE_TYPE_NOT_EXIST, type); |
||||||
|
return result; |
||||||
|
} |
||||||
|
try (Connection connection = datasource.getConnection()) { |
||||||
|
if (connection == null) { |
||||||
|
putMsg(result, Status.CONNECTION_TEST_FAILURE); |
||||||
|
return result; |
||||||
|
} |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} catch (Exception e) { |
||||||
|
logger.error("datasource test connection error, dbType:{}, jdbcUrl:{}, message:{}.", type, datasource.getJdbcUrl(), e.getMessage()); |
||||||
|
return new Result<>(Status.CONNECTION_TEST_FAILURE.getCode(),e.getMessage()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* test connection |
||||||
|
* |
||||||
|
* @param id datasource id |
||||||
|
* @return connect result code |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Result<Object> connectionTest(int id) { |
||||||
|
DataSource dataSource = dataSourceMapper.selectById(id); |
||||||
|
if (dataSource == null) { |
||||||
|
Result<Object> result = new Result<>(); |
||||||
|
putMsg(result, Status.RESOURCE_NOT_EXIST); |
||||||
|
return result; |
||||||
|
} |
||||||
|
return checkConnection(dataSource.getType(), dataSource.getConnectionParams()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* build paramters |
||||||
|
* |
||||||
|
* @param type data source type |
||||||
|
* @param host data source host |
||||||
|
* @param port data source port |
||||||
|
* @param database data source database name |
||||||
|
* @param userName user name |
||||||
|
* @param password password |
||||||
|
* @param other other parameters |
||||||
|
* @param principal principal |
||||||
|
* @return datasource parameter |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public String buildParameter(DbType type, String host, |
||||||
|
String port, String database, String principal, String userName, |
||||||
|
String password, DbConnectType connectType, String other, |
||||||
|
String javaSecurityKrb5Conf, String loginUserKeytabUsername, String loginUserKeytabPath) { |
||||||
|
|
||||||
|
String address = buildAddress(type, host, port, connectType); |
||||||
|
Map<String, Object> parameterMap = new LinkedHashMap<>(); |
||||||
|
String jdbcUrl; |
||||||
|
if (DbType.SQLSERVER == type) { |
||||||
|
jdbcUrl = address + ";databaseName=" + database; |
||||||
|
} else { |
||||||
|
jdbcUrl = address + "/" + database; |
||||||
|
} |
||||||
|
|
||||||
|
if (Constants.ORACLE.equals(type.name())) { |
||||||
|
parameterMap.put(Constants.ORACLE_DB_CONNECT_TYPE, connectType); |
||||||
|
} |
||||||
|
|
||||||
|
if (CommonUtils.getKerberosStartupState() |
||||||
|
&& (type == DbType.HIVE || type == DbType.SPARK)) { |
||||||
|
jdbcUrl += ";principal=" + principal; |
||||||
|
} |
||||||
|
|
||||||
|
String separator = ""; |
||||||
|
if (Constants.MYSQL.equals(type.name()) |
||||||
|
|| Constants.POSTGRESQL.equals(type.name()) |
||||||
|
|| Constants.CLICKHOUSE.equals(type.name()) |
||||||
|
|| Constants.ORACLE.equals(type.name()) |
||||||
|
|| Constants.PRESTO.equals(type.name())) { |
||||||
|
separator = "&"; |
||||||
|
} else if (Constants.HIVE.equals(type.name()) |
||||||
|
|| Constants.SPARK.equals(type.name()) |
||||||
|
|| Constants.DB2.equals(type.name()) |
||||||
|
|| Constants.SQLSERVER.equals(type.name())) { |
||||||
|
separator = ";"; |
||||||
|
} |
||||||
|
|
||||||
|
parameterMap.put(TYPE, connectType); |
||||||
|
parameterMap.put(Constants.ADDRESS, address); |
||||||
|
parameterMap.put(Constants.DATABASE, database); |
||||||
|
parameterMap.put(Constants.JDBC_URL, jdbcUrl); |
||||||
|
parameterMap.put(Constants.USER, userName); |
||||||
|
parameterMap.put(Constants.PASSWORD, CommonUtils.encodePassword(password)); |
||||||
|
if (CommonUtils.getKerberosStartupState() |
||||||
|
&& (type == DbType.HIVE || type == DbType.SPARK)) { |
||||||
|
parameterMap.put(Constants.PRINCIPAL, principal); |
||||||
|
parameterMap.put(Constants.KERBEROS_KRB5_CONF_PATH, javaSecurityKrb5Conf); |
||||||
|
parameterMap.put(Constants.KERBEROS_KEY_TAB_USERNAME, loginUserKeytabUsername); |
||||||
|
parameterMap.put(Constants.KERBEROS_KEY_TAB_PATH, loginUserKeytabPath); |
||||||
|
} |
||||||
|
|
||||||
|
Map<String, String> map = JSONUtils.toMap(other); |
||||||
|
if (map != null) { |
||||||
|
StringBuilder otherSb = new StringBuilder(); |
||||||
|
for (Map.Entry<String, String> entry: map.entrySet()) { |
||||||
|
otherSb.append(String.format("%s=%s%s", entry.getKey(), entry.getValue(), separator)); |
||||||
|
} |
||||||
|
if (!Constants.DB2.equals(type.name())) { |
||||||
|
otherSb.deleteCharAt(otherSb.length() - 1); |
||||||
|
} |
||||||
|
parameterMap.put(Constants.OTHER, otherSb); |
||||||
|
} |
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) { |
||||||
|
logger.info("parameters map:{}", JSONUtils.toJsonString(parameterMap)); |
||||||
|
} |
||||||
|
return JSONUtils.toJsonString(parameterMap); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private String buildAddress(DbType type, String host, String port, DbConnectType connectType) { |
||||||
|
StringBuilder sb = new StringBuilder(); |
||||||
|
if (Constants.MYSQL.equals(type.name())) { |
||||||
|
sb.append(Constants.JDBC_MYSQL); |
||||||
|
sb.append(host).append(":").append(port); |
||||||
|
} else if (Constants.POSTGRESQL.equals(type.name())) { |
||||||
|
sb.append(Constants.JDBC_POSTGRESQL); |
||||||
|
sb.append(host).append(":").append(port); |
||||||
|
} else if (Constants.HIVE.equals(type.name()) || Constants.SPARK.equals(type.name())) { |
||||||
|
sb.append(Constants.JDBC_HIVE_2); |
||||||
|
String[] hostArray = host.split(","); |
||||||
|
if (hostArray.length > 0) { |
||||||
|
for (String zkHost : hostArray) { |
||||||
|
sb.append(String.format("%s:%s,", zkHost, port)); |
||||||
|
} |
||||||
|
sb.deleteCharAt(sb.length() - 1); |
||||||
|
} |
||||||
|
} else if (Constants.CLICKHOUSE.equals(type.name())) { |
||||||
|
sb.append(Constants.JDBC_CLICKHOUSE); |
||||||
|
sb.append(host).append(":").append(port); |
||||||
|
} else if (Constants.ORACLE.equals(type.name())) { |
||||||
|
if (connectType == DbConnectType.ORACLE_SID) { |
||||||
|
sb.append(Constants.JDBC_ORACLE_SID); |
||||||
|
} else { |
||||||
|
sb.append(Constants.JDBC_ORACLE_SERVICE_NAME); |
||||||
|
} |
||||||
|
sb.append(host).append(":").append(port); |
||||||
|
} else if (Constants.SQLSERVER.equals(type.name())) { |
||||||
|
sb.append(Constants.JDBC_SQLSERVER); |
||||||
|
sb.append(host).append(":").append(port); |
||||||
|
} else if (Constants.DB2.equals(type.name())) { |
||||||
|
sb.append(Constants.JDBC_DB2); |
||||||
|
sb.append(host).append(":").append(port); |
||||||
|
} else if (Constants.PRESTO.equals(type.name())) { |
||||||
|
sb.append(Constants.JDBC_PRESTO); |
||||||
|
sb.append(host).append(":").append(port); |
||||||
|
} |
||||||
|
|
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* delete datasource |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param datasourceId data source id |
||||||
|
* @return delete result code |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
@Transactional(rollbackFor = RuntimeException.class) |
||||||
|
public Result<Object> delete(User loginUser, int datasourceId) { |
||||||
|
Result<Object> result = new Result<>(); |
||||||
|
try { |
||||||
|
//query datasource by id
|
||||||
|
DataSource dataSource = dataSourceMapper.selectById(datasourceId); |
||||||
|
if (dataSource == null) { |
||||||
|
logger.error("resource id {} not exist", datasourceId); |
||||||
|
putMsg(result, Status.RESOURCE_NOT_EXIST); |
||||||
|
return result; |
||||||
|
} |
||||||
|
if (!hasPerm(loginUser, dataSource.getUserId())) { |
||||||
|
putMsg(result, Status.USER_NO_OPERATION_PERM); |
||||||
|
return result; |
||||||
|
} |
||||||
|
dataSourceMapper.deleteById(datasourceId); |
||||||
|
datasourceUserMapper.deleteByDatasourceId(datasourceId); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
} catch (Exception e) { |
||||||
|
logger.error("delete datasource error", e); |
||||||
|
throw new RuntimeException("delete datasource error"); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* unauthorized datasource |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param userId user id |
||||||
|
* @return unauthed data source result code |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> unauthDatasource(User loginUser, Integer userId) { |
||||||
|
|
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
//only admin operate
|
||||||
|
if (!isAdmin(loginUser)) { |
||||||
|
putMsg(result, Status.USER_NO_OPERATION_PERM); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* query all data sources except userId |
||||||
|
*/ |
||||||
|
List<DataSource> resultList = new ArrayList<>(); |
||||||
|
List<DataSource> datasourceList = dataSourceMapper.queryDatasourceExceptUserId(userId); |
||||||
|
Set<DataSource> datasourceSet = null; |
||||||
|
if (datasourceList != null && !datasourceList.isEmpty()) { |
||||||
|
datasourceSet = new HashSet<>(datasourceList); |
||||||
|
|
||||||
|
List<DataSource> authedDataSourceList = dataSourceMapper.queryAuthedDatasource(userId); |
||||||
|
|
||||||
|
Set<DataSource> authedDataSourceSet = null; |
||||||
|
if (authedDataSourceList != null && !authedDataSourceList.isEmpty()) { |
||||||
|
authedDataSourceSet = new HashSet<>(authedDataSourceList); |
||||||
|
datasourceSet.removeAll(authedDataSourceSet); |
||||||
|
|
||||||
|
} |
||||||
|
resultList = new ArrayList<>(datasourceSet); |
||||||
|
} |
||||||
|
result.put(Constants.DATA_LIST, resultList); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* authorized datasource |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param userId user id |
||||||
|
* @return authorized result code |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> authedDatasource(User loginUser, Integer userId) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
|
||||||
|
if (!isAdmin(loginUser)) { |
||||||
|
putMsg(result, Status.USER_NO_OPERATION_PERM); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
List<DataSource> authedDatasourceList = dataSourceMapper.queryAuthedDatasource(userId); |
||||||
|
result.put(Constants.DATA_LIST, authedDatasourceList); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* get host and port by address |
||||||
|
* |
||||||
|
* @param address address |
||||||
|
* @param separator separator |
||||||
|
* @return sting array: [host,port] |
||||||
|
*/ |
||||||
|
private String[] getHostsAndPort(String address, String separator) { |
||||||
|
String[] result = new String[2]; |
||||||
|
String[] tmpArray = address.split(separator); |
||||||
|
String hostsAndPorts = tmpArray[tmpArray.length - 1]; |
||||||
|
StringBuilder hosts = new StringBuilder(); |
||||||
|
String[] hostPortArray = hostsAndPorts.split(Constants.COMMA); |
||||||
|
String port = hostPortArray[0].split(Constants.COLON)[1]; |
||||||
|
for (String hostPort : hostPortArray) { |
||||||
|
hosts.append(hostPort.split(Constants.COLON)[0]).append(Constants.COMMA); |
||||||
|
} |
||||||
|
hosts.deleteCharAt(hosts.length() - 1); |
||||||
|
result[0] = hosts.toString(); |
||||||
|
result[1] = port; |
||||||
|
return result; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,582 @@ |
|||||||
|
/* |
||||||
|
* 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.api.service.impl; |
||||||
|
|
||||||
|
import static org.apache.dolphinscheduler.common.Constants.CMDPARAM_COMPLEMENT_DATA_END_DATE; |
||||||
|
import static org.apache.dolphinscheduler.common.Constants.CMDPARAM_COMPLEMENT_DATA_START_DATE; |
||||||
|
import static org.apache.dolphinscheduler.common.Constants.CMD_PARAM_RECOVER_PROCESS_ID_STRING; |
||||||
|
import static org.apache.dolphinscheduler.common.Constants.CMD_PARAM_START_NODE_NAMES; |
||||||
|
import static org.apache.dolphinscheduler.common.Constants.CMD_PARAM_START_PARAMS; |
||||||
|
import static org.apache.dolphinscheduler.common.Constants.MAX_TASK_TIMEOUT; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.api.enums.ExecuteType; |
||||||
|
import org.apache.dolphinscheduler.api.enums.Status; |
||||||
|
import org.apache.dolphinscheduler.api.service.ExecutorService; |
||||||
|
import org.apache.dolphinscheduler.api.service.MonitorService; |
||||||
|
import org.apache.dolphinscheduler.api.service.ProjectService; |
||||||
|
import org.apache.dolphinscheduler.common.Constants; |
||||||
|
import org.apache.dolphinscheduler.common.enums.CommandType; |
||||||
|
import org.apache.dolphinscheduler.common.enums.ExecutionStatus; |
||||||
|
import org.apache.dolphinscheduler.common.enums.FailureStrategy; |
||||||
|
import org.apache.dolphinscheduler.common.enums.Priority; |
||||||
|
import org.apache.dolphinscheduler.common.enums.ReleaseState; |
||||||
|
import org.apache.dolphinscheduler.common.enums.RunMode; |
||||||
|
import org.apache.dolphinscheduler.common.enums.TaskDependType; |
||||||
|
import org.apache.dolphinscheduler.common.enums.WarningType; |
||||||
|
import org.apache.dolphinscheduler.common.model.Server; |
||||||
|
import org.apache.dolphinscheduler.common.utils.CollectionUtils; |
||||||
|
import org.apache.dolphinscheduler.common.utils.DateUtils; |
||||||
|
import org.apache.dolphinscheduler.common.utils.JSONUtils; |
||||||
|
import org.apache.dolphinscheduler.common.utils.StringUtils; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.Command; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.ProcessDefinition; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.ProcessInstance; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.Project; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.Schedule; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.Tenant; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.User; |
||||||
|
import org.apache.dolphinscheduler.dao.mapper.ProcessDefinitionMapper; |
||||||
|
import org.apache.dolphinscheduler.dao.mapper.ProcessInstanceMapper; |
||||||
|
import org.apache.dolphinscheduler.dao.mapper.ProjectMapper; |
||||||
|
import org.apache.dolphinscheduler.service.process.ProcessService; |
||||||
|
import org.apache.dolphinscheduler.service.quartz.cron.CronUtils; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Date; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.LinkedList; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
|
||||||
|
/** |
||||||
|
* executor service impl |
||||||
|
*/ |
||||||
|
@Service |
||||||
|
public class ExecutorServiceImpl extends BaseServiceImpl implements ExecutorService { |
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ExecutorServiceImpl.class); |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private ProjectMapper projectMapper; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private ProjectService projectService; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private ProcessDefinitionMapper processDefinitionMapper; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private MonitorService monitorService; |
||||||
|
|
||||||
|
|
||||||
|
@Autowired |
||||||
|
private ProcessInstanceMapper processInstanceMapper; |
||||||
|
|
||||||
|
|
||||||
|
@Autowired |
||||||
|
private ProcessService processService; |
||||||
|
|
||||||
|
/** |
||||||
|
* execute process instance |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param projectName project name |
||||||
|
* @param processDefinitionId process Definition Id |
||||||
|
* @param cronTime cron time |
||||||
|
* @param commandType command type |
||||||
|
* @param failureStrategy failuer strategy |
||||||
|
* @param startNodeList start nodelist |
||||||
|
* @param taskDependType node dependency type |
||||||
|
* @param warningType warning type |
||||||
|
* @param warningGroupId notify group id |
||||||
|
* @param processInstancePriority process instance priority |
||||||
|
* @param workerGroup worker group name |
||||||
|
* @param runMode run mode |
||||||
|
* @param timeout timeout |
||||||
|
* @param startParams the global param values which pass to new process instance |
||||||
|
* @return execute process instance code |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> execProcessInstance(User loginUser, String projectName, |
||||||
|
int processDefinitionId, String cronTime, CommandType commandType, |
||||||
|
FailureStrategy failureStrategy, String startNodeList, |
||||||
|
TaskDependType taskDependType, WarningType warningType, int warningGroupId, |
||||||
|
RunMode runMode, |
||||||
|
Priority processInstancePriority, String workerGroup, Integer timeout, |
||||||
|
Map<String, String> startParams) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
// timeout is invalid
|
||||||
|
if (timeout <= 0 || timeout > MAX_TASK_TIMEOUT) { |
||||||
|
putMsg(result, Status.TASK_TIMEOUT_PARAMS_ERROR); |
||||||
|
return result; |
||||||
|
} |
||||||
|
Project project = projectMapper.queryByName(projectName); |
||||||
|
Map<String, Object> checkResultAndAuth = checkResultAndAuth(loginUser, projectName, project); |
||||||
|
if (checkResultAndAuth != null) { |
||||||
|
return checkResultAndAuth; |
||||||
|
} |
||||||
|
|
||||||
|
// check process define release state
|
||||||
|
ProcessDefinition processDefinition = processDefinitionMapper.selectById(processDefinitionId); |
||||||
|
result = checkProcessDefinitionValid(processDefinition, processDefinitionId); |
||||||
|
if (result.get(Constants.STATUS) != Status.SUCCESS) { |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
if (!checkTenantSuitable(processDefinition)) { |
||||||
|
logger.error("there is not any valid tenant for the process definition: id:{},name:{}, ", |
||||||
|
processDefinition.getId(), processDefinition.getName()); |
||||||
|
putMsg(result, Status.TENANT_NOT_SUITABLE); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
// check master exists
|
||||||
|
if (!checkMasterExists(result)) { |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* create command |
||||||
|
*/ |
||||||
|
int create = this.createCommand(commandType, processDefinitionId, |
||||||
|
taskDependType, failureStrategy, startNodeList, cronTime, warningType, loginUser.getId(), |
||||||
|
warningGroupId, runMode, processInstancePriority, workerGroup, startParams); |
||||||
|
|
||||||
|
if (create > 0) { |
||||||
|
processDefinition.setWarningGroupId(warningGroupId); |
||||||
|
processDefinitionMapper.updateById(processDefinition); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
} else { |
||||||
|
putMsg(result, Status.START_PROCESS_INSTANCE_ERROR); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* check whether master exists |
||||||
|
* |
||||||
|
* @param result result |
||||||
|
* @return master exists return true , otherwise return false |
||||||
|
*/ |
||||||
|
private boolean checkMasterExists(Map<String, Object> result) { |
||||||
|
// check master server exists
|
||||||
|
List<Server> masterServers = monitorService.getServerListFromZK(true); |
||||||
|
|
||||||
|
// no master
|
||||||
|
if (masterServers.isEmpty()) { |
||||||
|
putMsg(result, Status.MASTER_NOT_EXISTS); |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* check whether the process definition can be executed |
||||||
|
* |
||||||
|
* @param processDefinition process definition |
||||||
|
* @param processDefineId process definition id |
||||||
|
* @return check result code |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> checkProcessDefinitionValid(ProcessDefinition processDefinition, int processDefineId) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
if (processDefinition == null) { |
||||||
|
// check process definition exists
|
||||||
|
putMsg(result, Status.PROCESS_DEFINE_NOT_EXIST, processDefineId); |
||||||
|
} else if (processDefinition.getReleaseState() != ReleaseState.ONLINE) { |
||||||
|
// check process definition online
|
||||||
|
putMsg(result, Status.PROCESS_DEFINE_NOT_RELEASE, processDefineId); |
||||||
|
} else { |
||||||
|
result.put(Constants.STATUS, Status.SUCCESS); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* do action to process instance:pause, stop, repeat, recover from pause, recover from stop |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param projectName project name |
||||||
|
* @param processInstanceId process instance id |
||||||
|
* @param executeType execute type |
||||||
|
* @return execute result code |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> execute(User loginUser, String projectName, Integer processInstanceId, ExecuteType executeType) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
Project project = projectMapper.queryByName(projectName); |
||||||
|
|
||||||
|
Map<String, Object> checkResult = checkResultAndAuth(loginUser, projectName, project); |
||||||
|
if (checkResult != null) { |
||||||
|
return checkResult; |
||||||
|
} |
||||||
|
|
||||||
|
// check master exists
|
||||||
|
if (!checkMasterExists(result)) { |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
ProcessInstance processInstance = processService.findProcessInstanceDetailById(processInstanceId); |
||||||
|
if (processInstance == null) { |
||||||
|
putMsg(result, Status.PROCESS_INSTANCE_NOT_EXIST, processInstanceId); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
ProcessDefinition processDefinition = processService.findProcessDefineById(processInstance.getProcessDefinitionId()); |
||||||
|
if (executeType != ExecuteType.STOP && executeType != ExecuteType.PAUSE) { |
||||||
|
result = checkProcessDefinitionValid(processDefinition, processInstance.getProcessDefinitionId()); |
||||||
|
if (result.get(Constants.STATUS) != Status.SUCCESS) { |
||||||
|
return result; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
checkResult = checkExecuteType(processInstance, executeType); |
||||||
|
Status status = (Status) checkResult.get(Constants.STATUS); |
||||||
|
if (status != Status.SUCCESS) { |
||||||
|
return checkResult; |
||||||
|
} |
||||||
|
if (!checkTenantSuitable(processDefinition)) { |
||||||
|
logger.error("there is not any valid tenant for the process definition: id:{},name:{}, ", |
||||||
|
processDefinition.getId(), processDefinition.getName()); |
||||||
|
putMsg(result, Status.TENANT_NOT_SUITABLE); |
||||||
|
} |
||||||
|
|
||||||
|
switch (executeType) { |
||||||
|
case REPEAT_RUNNING: |
||||||
|
result = insertCommand(loginUser, processInstanceId, processDefinition.getId(), CommandType.REPEAT_RUNNING); |
||||||
|
break; |
||||||
|
case RECOVER_SUSPENDED_PROCESS: |
||||||
|
result = insertCommand(loginUser, processInstanceId, processDefinition.getId(), CommandType.RECOVER_SUSPENDED_PROCESS); |
||||||
|
break; |
||||||
|
case START_FAILURE_TASK_PROCESS: |
||||||
|
result = insertCommand(loginUser, processInstanceId, processDefinition.getId(), CommandType.START_FAILURE_TASK_PROCESS); |
||||||
|
break; |
||||||
|
case STOP: |
||||||
|
if (processInstance.getState() == ExecutionStatus.READY_STOP) { |
||||||
|
putMsg(result, Status.PROCESS_INSTANCE_ALREADY_CHANGED, processInstance.getName(), processInstance.getState()); |
||||||
|
} else { |
||||||
|
result = updateProcessInstancePrepare(processInstance, CommandType.STOP, ExecutionStatus.READY_STOP); |
||||||
|
} |
||||||
|
break; |
||||||
|
case PAUSE: |
||||||
|
if (processInstance.getState() == ExecutionStatus.READY_PAUSE) { |
||||||
|
putMsg(result, Status.PROCESS_INSTANCE_ALREADY_CHANGED, processInstance.getName(), processInstance.getState()); |
||||||
|
} else { |
||||||
|
result = updateProcessInstancePrepare(processInstance, CommandType.PAUSE, ExecutionStatus.READY_PAUSE); |
||||||
|
} |
||||||
|
break; |
||||||
|
default: |
||||||
|
logger.error("unknown execute type : {}", executeType); |
||||||
|
putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, "unknown execute type"); |
||||||
|
|
||||||
|
break; |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* check tenant suitable |
||||||
|
* |
||||||
|
* @param processDefinition process definition |
||||||
|
* @return true if tenant suitable, otherwise return false |
||||||
|
*/ |
||||||
|
private boolean checkTenantSuitable(ProcessDefinition processDefinition) { |
||||||
|
Tenant tenant = processService.getTenantForProcess(processDefinition.getTenantId(), |
||||||
|
processDefinition.getUserId()); |
||||||
|
return tenant != null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Check the state of process instance and the type of operation match |
||||||
|
* |
||||||
|
* @param processInstance process instance |
||||||
|
* @param executeType execute type |
||||||
|
* @return check result code |
||||||
|
*/ |
||||||
|
private Map<String, Object> checkExecuteType(ProcessInstance processInstance, ExecuteType executeType) { |
||||||
|
|
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
ExecutionStatus executionStatus = processInstance.getState(); |
||||||
|
boolean checkResult = false; |
||||||
|
switch (executeType) { |
||||||
|
case PAUSE: |
||||||
|
case STOP: |
||||||
|
if (executionStatus.typeIsRunning()) { |
||||||
|
checkResult = true; |
||||||
|
} |
||||||
|
break; |
||||||
|
case REPEAT_RUNNING: |
||||||
|
if (executionStatus.typeIsFinished()) { |
||||||
|
checkResult = true; |
||||||
|
} |
||||||
|
break; |
||||||
|
case START_FAILURE_TASK_PROCESS: |
||||||
|
if (executionStatus.typeIsFailure()) { |
||||||
|
checkResult = true; |
||||||
|
} |
||||||
|
break; |
||||||
|
case RECOVER_SUSPENDED_PROCESS: |
||||||
|
if (executionStatus.typeIsPause() || executionStatus.typeIsCancel()) { |
||||||
|
checkResult = true; |
||||||
|
} |
||||||
|
break; |
||||||
|
default: |
||||||
|
break; |
||||||
|
} |
||||||
|
if (!checkResult) { |
||||||
|
putMsg(result, Status.PROCESS_INSTANCE_STATE_OPERATION_ERROR, processInstance.getName(), executionStatus.toString(), executeType.toString()); |
||||||
|
} else { |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* prepare to update process instance command type and status |
||||||
|
* |
||||||
|
* @param processInstance process instance |
||||||
|
* @param commandType command type |
||||||
|
* @param executionStatus execute status |
||||||
|
* @return update result |
||||||
|
*/ |
||||||
|
private Map<String, Object> updateProcessInstancePrepare(ProcessInstance processInstance, CommandType commandType, ExecutionStatus executionStatus) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
|
||||||
|
processInstance.setCommandType(commandType); |
||||||
|
processInstance.addHistoryCmd(commandType); |
||||||
|
processInstance.setState(executionStatus); |
||||||
|
int update = processService.updateProcessInstance(processInstance); |
||||||
|
|
||||||
|
// determine whether the process is normal
|
||||||
|
if (update > 0) { |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
} else { |
||||||
|
putMsg(result, Status.EXECUTE_PROCESS_INSTANCE_ERROR); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* insert command, used in the implementation of the page, re run, recovery (pause / failure) execution |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param instanceId instance id |
||||||
|
* @param processDefinitionId process definition id |
||||||
|
* @param commandType command type |
||||||
|
* @return insert result code |
||||||
|
*/ |
||||||
|
private Map<String, Object> insertCommand(User loginUser, Integer instanceId, Integer processDefinitionId, CommandType commandType) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
Command command = new Command(); |
||||||
|
command.setCommandType(commandType); |
||||||
|
command.setProcessDefinitionId(processDefinitionId); |
||||||
|
command.setCommandParam(String.format("{\"%s\":%d}", |
||||||
|
CMD_PARAM_RECOVER_PROCESS_ID_STRING, instanceId)); |
||||||
|
command.setExecutorId(loginUser.getId()); |
||||||
|
|
||||||
|
if (!processService.verifyIsNeedCreateCommand(command)) { |
||||||
|
putMsg(result, Status.PROCESS_INSTANCE_EXECUTING_COMMAND, processDefinitionId); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
int create = processService.createCommand(command); |
||||||
|
|
||||||
|
if (create > 0) { |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
} else { |
||||||
|
putMsg(result, Status.EXECUTE_PROCESS_INSTANCE_ERROR); |
||||||
|
} |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* check if sub processes are offline before starting process definition |
||||||
|
* |
||||||
|
* @param processDefineId process definition id |
||||||
|
* @return check result code |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> startCheckByProcessDefinedId(int processDefineId) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
|
||||||
|
if (processDefineId == 0) { |
||||||
|
logger.error("process definition id is null"); |
||||||
|
putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, "process definition id"); |
||||||
|
} |
||||||
|
List<Integer> ids = new ArrayList<>(); |
||||||
|
processService.recurseFindSubProcessId(processDefineId, ids); |
||||||
|
Integer[] idArray = ids.toArray(new Integer[ids.size()]); |
||||||
|
if (!ids.isEmpty()) { |
||||||
|
List<ProcessDefinition> processDefinitionList = processDefinitionMapper.queryDefinitionListByIdList(idArray); |
||||||
|
if (processDefinitionList != null) { |
||||||
|
for (ProcessDefinition processDefinition : processDefinitionList) { |
||||||
|
/** |
||||||
|
* if there is no online process, exit directly |
||||||
|
*/ |
||||||
|
if (processDefinition.getReleaseState() != ReleaseState.ONLINE) { |
||||||
|
putMsg(result, Status.PROCESS_DEFINE_NOT_RELEASE, processDefinition.getName()); |
||||||
|
logger.info("not release process definition id: {} , name : {}", |
||||||
|
processDefinition.getId(), processDefinition.getName()); |
||||||
|
return result; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* create command |
||||||
|
* |
||||||
|
* @param commandType commandType |
||||||
|
* @param processDefineId processDefineId |
||||||
|
* @param nodeDep nodeDep |
||||||
|
* @param failureStrategy failureStrategy |
||||||
|
* @param startNodeList startNodeList |
||||||
|
* @param schedule schedule |
||||||
|
* @param warningType warningType |
||||||
|
* @param executorId executorId |
||||||
|
* @param warningGroupId warningGroupId |
||||||
|
* @param runMode runMode |
||||||
|
* @param processInstancePriority processInstancePriority |
||||||
|
* @param workerGroup workerGroup |
||||||
|
* @return command id |
||||||
|
*/ |
||||||
|
private int createCommand(CommandType commandType, int processDefineId, |
||||||
|
TaskDependType nodeDep, FailureStrategy failureStrategy, |
||||||
|
String startNodeList, String schedule, WarningType warningType, |
||||||
|
int executorId, int warningGroupId, |
||||||
|
RunMode runMode, Priority processInstancePriority, String workerGroup, |
||||||
|
Map<String, String> startParams) { |
||||||
|
|
||||||
|
/** |
||||||
|
* instantiate command schedule instance |
||||||
|
*/ |
||||||
|
Command command = new Command(); |
||||||
|
|
||||||
|
Map<String, String> cmdParam = new HashMap<>(); |
||||||
|
if (commandType == null) { |
||||||
|
command.setCommandType(CommandType.START_PROCESS); |
||||||
|
} else { |
||||||
|
command.setCommandType(commandType); |
||||||
|
} |
||||||
|
command.setProcessDefinitionId(processDefineId); |
||||||
|
if (nodeDep != null) { |
||||||
|
command.setTaskDependType(nodeDep); |
||||||
|
} |
||||||
|
if (failureStrategy != null) { |
||||||
|
command.setFailureStrategy(failureStrategy); |
||||||
|
} |
||||||
|
|
||||||
|
if (StringUtils.isNotEmpty(startNodeList)) { |
||||||
|
cmdParam.put(CMD_PARAM_START_NODE_NAMES, startNodeList); |
||||||
|
} |
||||||
|
if (warningType != null) { |
||||||
|
command.setWarningType(warningType); |
||||||
|
} |
||||||
|
if (startParams != null && startParams.size() > 0) { |
||||||
|
cmdParam.put(CMD_PARAM_START_PARAMS, JSONUtils.toJsonString(startParams)); |
||||||
|
} |
||||||
|
command.setCommandParam(JSONUtils.toJsonString(cmdParam)); |
||||||
|
command.setExecutorId(executorId); |
||||||
|
command.setWarningGroupId(warningGroupId); |
||||||
|
command.setProcessInstancePriority(processInstancePriority); |
||||||
|
command.setWorkerGroup(workerGroup); |
||||||
|
|
||||||
|
Date start = null; |
||||||
|
Date end = null; |
||||||
|
if (StringUtils.isNotEmpty(schedule)) { |
||||||
|
String[] interval = schedule.split(","); |
||||||
|
if (interval.length == 2) { |
||||||
|
start = DateUtils.getScheduleDate(interval[0]); |
||||||
|
end = DateUtils.getScheduleDate(interval[1]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// determine whether to complement
|
||||||
|
if (commandType == CommandType.COMPLEMENT_DATA) { |
||||||
|
runMode = (runMode == null) ? RunMode.RUN_MODE_SERIAL : runMode; |
||||||
|
if (null != start && null != end && !start.after(end)) { |
||||||
|
if (runMode == RunMode.RUN_MODE_SERIAL) { |
||||||
|
cmdParam.put(CMDPARAM_COMPLEMENT_DATA_START_DATE, DateUtils.dateToString(start)); |
||||||
|
cmdParam.put(CMDPARAM_COMPLEMENT_DATA_END_DATE, DateUtils.dateToString(end)); |
||||||
|
command.setCommandParam(JSONUtils.toJsonString(cmdParam)); |
||||||
|
return processService.createCommand(command); |
||||||
|
} else if (runMode == RunMode.RUN_MODE_PARALLEL) { |
||||||
|
List<Schedule> schedules = processService.queryReleaseSchedulerListByProcessDefinitionId(processDefineId); |
||||||
|
List<Date> listDate = new LinkedList<>(); |
||||||
|
if (!CollectionUtils.isEmpty(schedules)) { |
||||||
|
for (Schedule item : schedules) { |
||||||
|
listDate.addAll(CronUtils.getSelfFireDateList(start, end, item.getCrontab())); |
||||||
|
} |
||||||
|
} |
||||||
|
if (!CollectionUtils.isEmpty(listDate)) { |
||||||
|
// loop by schedule date
|
||||||
|
for (Date date : listDate) { |
||||||
|
cmdParam.put(CMDPARAM_COMPLEMENT_DATA_START_DATE, DateUtils.dateToString(date)); |
||||||
|
cmdParam.put(CMDPARAM_COMPLEMENT_DATA_END_DATE, DateUtils.dateToString(date)); |
||||||
|
command.setCommandParam(JSONUtils.toJsonString(cmdParam)); |
||||||
|
processService.createCommand(command); |
||||||
|
} |
||||||
|
return listDate.size(); |
||||||
|
} else { |
||||||
|
// loop by day
|
||||||
|
int runCunt = 0; |
||||||
|
while (!start.after(end)) { |
||||||
|
runCunt += 1; |
||||||
|
cmdParam.put(CMDPARAM_COMPLEMENT_DATA_START_DATE, DateUtils.dateToString(start)); |
||||||
|
cmdParam.put(CMDPARAM_COMPLEMENT_DATA_END_DATE, DateUtils.dateToString(start)); |
||||||
|
command.setCommandParam(JSONUtils.toJsonString(cmdParam)); |
||||||
|
processService.createCommand(command); |
||||||
|
start = DateUtils.getSomeDay(start, 1); |
||||||
|
} |
||||||
|
return runCunt; |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
logger.error("there is not valid schedule date for the process definition: id:{}", processDefineId); |
||||||
|
} |
||||||
|
} else { |
||||||
|
command.setCommandParam(JSONUtils.toJsonString(cmdParam)); |
||||||
|
return processService.createCommand(command); |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* check result and auth |
||||||
|
*/ |
||||||
|
private Map<String, Object> checkResultAndAuth(User loginUser, String projectName, Project project) { |
||||||
|
// check project auth
|
||||||
|
Map<String, Object> checkResult = projectService.checkProjectAndAuth(loginUser, project, projectName); |
||||||
|
Status status = (Status) checkResult.get(Constants.STATUS); |
||||||
|
if (status != Status.SUCCESS) { |
||||||
|
return checkResult; |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,165 @@ |
|||||||
|
/* |
||||||
|
* 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.api.service.impl; |
||||||
|
|
||||||
|
import static org.apache.dolphinscheduler.common.utils.Preconditions.checkNotNull; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.api.enums.Status; |
||||||
|
import org.apache.dolphinscheduler.api.service.MonitorService; |
||||||
|
import org.apache.dolphinscheduler.api.utils.ZookeeperMonitor; |
||||||
|
import org.apache.dolphinscheduler.common.Constants; |
||||||
|
import org.apache.dolphinscheduler.common.enums.ZKNodeType; |
||||||
|
import org.apache.dolphinscheduler.common.model.Server; |
||||||
|
import org.apache.dolphinscheduler.common.model.WorkerServerModel; |
||||||
|
import org.apache.dolphinscheduler.dao.MonitorDBDao; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.MonitorRecord; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.User; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.ZookeeperRecord; |
||||||
|
|
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.function.Function; |
||||||
|
import java.util.stream.Collectors; |
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
|
||||||
|
import com.google.common.collect.Sets; |
||||||
|
|
||||||
|
/** |
||||||
|
* monitor service impl |
||||||
|
*/ |
||||||
|
@Service |
||||||
|
public class MonitorServiceImpl extends BaseServiceImpl implements MonitorService { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private ZookeeperMonitor zookeeperMonitor; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private MonitorDBDao monitorDBDao; |
||||||
|
|
||||||
|
/** |
||||||
|
* query database state |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @return data base state |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String,Object> queryDatabaseState(User loginUser) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
|
||||||
|
List<MonitorRecord> monitorRecordList = monitorDBDao.queryDatabaseState(); |
||||||
|
|
||||||
|
result.put(Constants.DATA_LIST, monitorRecordList); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
|
||||||
|
return result; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* query master list |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @return master information list |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String,Object> queryMaster(User loginUser) { |
||||||
|
|
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
|
||||||
|
List<Server> masterServers = getServerListFromZK(true); |
||||||
|
result.put(Constants.DATA_LIST, masterServers); |
||||||
|
putMsg(result,Status.SUCCESS); |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* query zookeeper state |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @return zookeeper information list |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String,Object> queryZookeeperState(User loginUser) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
|
||||||
|
List<ZookeeperRecord> zookeeperRecordList = zookeeperMonitor.zookeeperInfoList(); |
||||||
|
|
||||||
|
result.put(Constants.DATA_LIST, zookeeperRecordList); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
|
||||||
|
return result; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* query worker list |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @return worker information list |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String,Object> queryWorker(User loginUser) { |
||||||
|
|
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
List<WorkerServerModel> workerServers = getServerListFromZK(false) |
||||||
|
.stream() |
||||||
|
.map((Server server) -> { |
||||||
|
WorkerServerModel model = new WorkerServerModel(); |
||||||
|
model.setId(server.getId()); |
||||||
|
model.setHost(server.getHost()); |
||||||
|
model.setPort(server.getPort()); |
||||||
|
model.setZkDirectories(Sets.newHashSet(server.getZkDirectory())); |
||||||
|
model.setResInfo(server.getResInfo()); |
||||||
|
model.setCreateTime(server.getCreateTime()); |
||||||
|
model.setLastHeartbeatTime(server.getLastHeartbeatTime()); |
||||||
|
return model; |
||||||
|
}) |
||||||
|
.collect(Collectors.toList()); |
||||||
|
|
||||||
|
Map<String, WorkerServerModel> workerHostPortServerMapping = workerServers |
||||||
|
.stream() |
||||||
|
.collect(Collectors.toMap( |
||||||
|
(WorkerServerModel worker) -> { |
||||||
|
String[] s = worker.getZkDirectories().iterator().next().split("/"); |
||||||
|
return s[s.length - 1]; |
||||||
|
} |
||||||
|
, Function.identity() |
||||||
|
, (WorkerServerModel oldOne, WorkerServerModel newOne) -> { |
||||||
|
oldOne.getZkDirectories().addAll(newOne.getZkDirectories()); |
||||||
|
return oldOne; |
||||||
|
})); |
||||||
|
|
||||||
|
result.put(Constants.DATA_LIST, workerHostPortServerMapping.values()); |
||||||
|
putMsg(result,Status.SUCCESS); |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public List<Server> getServerListFromZK(boolean isMaster) { |
||||||
|
|
||||||
|
checkNotNull(zookeeperMonitor); |
||||||
|
ZKNodeType zkNodeType = isMaster ? ZKNodeType.MASTER : ZKNodeType.WORKER; |
||||||
|
return zookeeperMonitor.getServersList(zkNodeType); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,773 @@ |
|||||||
|
/* |
||||||
|
* 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.api.service.impl; |
||||||
|
|
||||||
|
import static org.apache.dolphinscheduler.common.Constants.DATA_LIST; |
||||||
|
import static org.apache.dolphinscheduler.common.Constants.DEPENDENT_SPLIT; |
||||||
|
import static org.apache.dolphinscheduler.common.Constants.GLOBAL_PARAMS; |
||||||
|
import static org.apache.dolphinscheduler.common.Constants.LOCAL_PARAMS; |
||||||
|
import static org.apache.dolphinscheduler.common.Constants.PROCESS_INSTANCE_STATE; |
||||||
|
import static org.apache.dolphinscheduler.common.Constants.TASK_LIST; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.api.dto.gantt.GanttDto; |
||||||
|
import org.apache.dolphinscheduler.api.dto.gantt.Task; |
||||||
|
import org.apache.dolphinscheduler.api.enums.Status; |
||||||
|
import org.apache.dolphinscheduler.api.service.ExecutorService; |
||||||
|
import org.apache.dolphinscheduler.api.service.LoggerService; |
||||||
|
import org.apache.dolphinscheduler.api.service.ProcessDefinitionService; |
||||||
|
import org.apache.dolphinscheduler.api.service.ProcessDefinitionVersionService; |
||||||
|
import org.apache.dolphinscheduler.api.service.ProcessInstanceService; |
||||||
|
import org.apache.dolphinscheduler.api.service.ProjectService; |
||||||
|
import org.apache.dolphinscheduler.api.service.UsersService; |
||||||
|
import org.apache.dolphinscheduler.api.utils.PageInfo; |
||||||
|
import org.apache.dolphinscheduler.api.utils.Result; |
||||||
|
import org.apache.dolphinscheduler.common.Constants; |
||||||
|
import org.apache.dolphinscheduler.common.enums.DependResult; |
||||||
|
import org.apache.dolphinscheduler.common.enums.ExecutionStatus; |
||||||
|
import org.apache.dolphinscheduler.common.enums.Flag; |
||||||
|
import org.apache.dolphinscheduler.common.enums.TaskType; |
||||||
|
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.process.Property; |
||||||
|
import org.apache.dolphinscheduler.common.utils.CollectionUtils; |
||||||
|
import org.apache.dolphinscheduler.common.utils.DateUtils; |
||||||
|
import org.apache.dolphinscheduler.common.utils.JSONUtils; |
||||||
|
import org.apache.dolphinscheduler.common.utils.ParameterUtils; |
||||||
|
import org.apache.dolphinscheduler.common.utils.StringUtils; |
||||||
|
import org.apache.dolphinscheduler.common.utils.placeholder.BusinessTimeUtils; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.ProcessData; |
||||||
|
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.TaskDefinitionLog; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.TaskInstance; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.Tenant; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.User; |
||||||
|
import org.apache.dolphinscheduler.dao.mapper.ProcessDefinitionLogMapper; |
||||||
|
import org.apache.dolphinscheduler.dao.mapper.ProcessDefinitionMapper; |
||||||
|
import org.apache.dolphinscheduler.dao.mapper.ProcessInstanceMapper; |
||||||
|
import org.apache.dolphinscheduler.dao.mapper.ProjectMapper; |
||||||
|
import org.apache.dolphinscheduler.dao.mapper.TaskDefinitionLogMapper; |
||||||
|
import org.apache.dolphinscheduler.dao.mapper.TaskInstanceMapper; |
||||||
|
import org.apache.dolphinscheduler.service.process.ProcessService; |
||||||
|
|
||||||
|
import java.io.BufferedReader; |
||||||
|
import java.io.ByteArrayInputStream; |
||||||
|
import java.io.IOException; |
||||||
|
import java.io.InputStreamReader; |
||||||
|
import java.nio.charset.StandardCharsets; |
||||||
|
import java.text.ParseException; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.Date; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Objects; |
||||||
|
import java.util.Optional; |
||||||
|
import java.util.stream.Collectors; |
||||||
|
|
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
import org.springframework.transaction.annotation.Transactional; |
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||||
|
|
||||||
|
/** |
||||||
|
* process instance service impl |
||||||
|
*/ |
||||||
|
@Service |
||||||
|
public class ProcessInstanceServiceImpl extends BaseServiceImpl implements ProcessInstanceService { |
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ProcessInstanceService.class); |
||||||
|
|
||||||
|
public static final String TASK_TYPE = "taskType"; |
||||||
|
public static final String LOCAL_PARAMS_LIST = "localParamsList"; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
ProjectMapper projectMapper; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
ProjectService projectService; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
ProcessService processService; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
ProcessInstanceMapper processInstanceMapper; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
ProcessDefinitionMapper processDefineMapper; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
ProcessDefinitionService processDefinitionService; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
ProcessDefinitionVersionService processDefinitionVersionService; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
ExecutorService execService; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
TaskInstanceMapper taskInstanceMapper; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
LoggerService loggerService; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
ProcessDefinitionLogMapper processDefinitionLogMapper; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
TaskDefinitionLogMapper taskDefinitionLogMapper; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
UsersService usersService; |
||||||
|
|
||||||
|
/** |
||||||
|
* return top n SUCCESS process instance order by running time which started between startTime and endTime |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> queryTopNLongestRunningProcessInstance(User loginUser, String projectName, int size, String startTime, String endTime) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
|
||||||
|
Project project = projectMapper.queryByName(projectName); |
||||||
|
Map<String, Object> checkResult = projectService.checkProjectAndAuth(loginUser, project, projectName); |
||||||
|
Status resultEnum = (Status) checkResult.get(Constants.STATUS); |
||||||
|
if (resultEnum != Status.SUCCESS) { |
||||||
|
return checkResult; |
||||||
|
} |
||||||
|
|
||||||
|
if (0 > size) { |
||||||
|
putMsg(result, Status.NEGTIVE_SIZE_NUMBER_ERROR, size); |
||||||
|
return result; |
||||||
|
} |
||||||
|
if (Objects.isNull(startTime)) { |
||||||
|
putMsg(result, Status.DATA_IS_NULL, Constants.START_TIME); |
||||||
|
return result; |
||||||
|
} |
||||||
|
Date start = DateUtils.stringToDate(startTime); |
||||||
|
if (Objects.isNull(endTime)) { |
||||||
|
putMsg(result, Status.DATA_IS_NULL, Constants.END_TIME); |
||||||
|
return result; |
||||||
|
} |
||||||
|
Date end = DateUtils.stringToDate(endTime); |
||||||
|
if (start == null || end == null) { |
||||||
|
putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, Constants.START_END_DATE); |
||||||
|
return result; |
||||||
|
} |
||||||
|
if (start.getTime() > end.getTime()) { |
||||||
|
putMsg(result, Status.START_TIME_BIGGER_THAN_END_TIME_ERROR, startTime, endTime); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
List<ProcessInstance> processInstances = processInstanceMapper.queryTopNProcessInstance(size, start, end, ExecutionStatus.SUCCESS); |
||||||
|
result.put(DATA_LIST, processInstances); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* query process instance by id |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param projectName project name |
||||||
|
* @param processId process instance id |
||||||
|
* @return process instance detail |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> queryProcessInstanceById(User loginUser, String projectName, Integer processId) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
Project project = projectMapper.queryByName(projectName); |
||||||
|
|
||||||
|
Map<String, Object> checkResult = projectService.checkProjectAndAuth(loginUser, project, projectName); |
||||||
|
Status resultEnum = (Status) checkResult.get(Constants.STATUS); |
||||||
|
if (resultEnum != Status.SUCCESS) { |
||||||
|
return checkResult; |
||||||
|
} |
||||||
|
ProcessInstance processInstance = processService.findProcessInstanceDetailById(processId); |
||||||
|
|
||||||
|
ProcessDefinition processDefinition = processService.findProcessDefineById(processInstance.getProcessDefinitionId()); |
||||||
|
processInstance.setWarningGroupId(processDefinition.getWarningGroupId()); |
||||||
|
result.put(DATA_LIST, processInstance); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* paging query process instance list, filtering according to project, process definition, time range, keyword, process status |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param projectName project name |
||||||
|
* @param pageNo page number |
||||||
|
* @param pageSize page size |
||||||
|
* @param processDefineId process definition id |
||||||
|
* @param searchVal search value |
||||||
|
* @param stateType state type |
||||||
|
* @param host host |
||||||
|
* @param startDate start time |
||||||
|
* @param endDate end time |
||||||
|
* @return process instance list |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> queryProcessInstanceList(User loginUser, String projectName, Integer processDefineId, |
||||||
|
String startDate, String endDate, |
||||||
|
String searchVal, String executorName, ExecutionStatus stateType, String host, |
||||||
|
Integer pageNo, Integer pageSize) { |
||||||
|
|
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
Project project = projectMapper.queryByName(projectName); |
||||||
|
|
||||||
|
Map<String, Object> checkResult = projectService.checkProjectAndAuth(loginUser, project, projectName); |
||||||
|
Status resultEnum = (Status) checkResult.get(Constants.STATUS); |
||||||
|
if (resultEnum != Status.SUCCESS) { |
||||||
|
return checkResult; |
||||||
|
} |
||||||
|
|
||||||
|
int[] statusArray = null; |
||||||
|
// filter by state
|
||||||
|
if (stateType != null) { |
||||||
|
statusArray = new int[]{stateType.ordinal()}; |
||||||
|
} |
||||||
|
|
||||||
|
Date start = null; |
||||||
|
Date end = null; |
||||||
|
try { |
||||||
|
if (StringUtils.isNotEmpty(startDate)) { |
||||||
|
start = DateUtils.getScheduleDate(startDate); |
||||||
|
} |
||||||
|
if (StringUtils.isNotEmpty(endDate)) { |
||||||
|
end = DateUtils.getScheduleDate(endDate); |
||||||
|
} |
||||||
|
} catch (Exception e) { |
||||||
|
putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, Constants.START_END_DATE); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
Page<ProcessInstance> page = new Page<>(pageNo, pageSize); |
||||||
|
PageInfo<ProcessInstance> pageInfo = new PageInfo<>(pageNo, pageSize); |
||||||
|
int executorId = usersService.getUserIdByName(executorName); |
||||||
|
|
||||||
|
IPage<ProcessInstance> processInstanceList = |
||||||
|
processInstanceMapper.queryProcessInstanceListPaging(page, |
||||||
|
project.getId(), processDefineId, searchVal, executorId, statusArray, host, start, end); |
||||||
|
|
||||||
|
List<ProcessInstance> processInstances = processInstanceList.getRecords(); |
||||||
|
|
||||||
|
for (ProcessInstance processInstance : processInstances) { |
||||||
|
processInstance.setDuration(DateUtils.format2Duration(processInstance.getStartTime(), processInstance.getEndTime())); |
||||||
|
User executor = usersService.queryUser(processInstance.getExecutorId()); |
||||||
|
if (null != executor) { |
||||||
|
processInstance.setExecutorName(executor.getUserName()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
pageInfo.setTotalCount((int) processInstanceList.getTotal()); |
||||||
|
pageInfo.setLists(processInstances); |
||||||
|
result.put(DATA_LIST, pageInfo); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* query task list by process instance id |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param projectName project name |
||||||
|
* @param processId process instance id |
||||||
|
* @return task list for the process instance |
||||||
|
* @throws IOException io exception |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> queryTaskListByProcessId(User loginUser, String projectName, Integer processId) throws IOException { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
Project project = projectMapper.queryByName(projectName); |
||||||
|
|
||||||
|
Map<String, Object> checkResult = projectService.checkProjectAndAuth(loginUser, project, projectName); |
||||||
|
Status resultEnum = (Status) checkResult.get(Constants.STATUS); |
||||||
|
if (resultEnum != Status.SUCCESS) { |
||||||
|
return checkResult; |
||||||
|
} |
||||||
|
ProcessInstance processInstance = processService.findProcessInstanceDetailById(processId); |
||||||
|
List<TaskInstance> taskInstanceList = processService.findValidTaskListByProcessId(processId); |
||||||
|
addDependResultForTaskList(taskInstanceList); |
||||||
|
Map<String, Object> resultMap = new HashMap<>(); |
||||||
|
resultMap.put(PROCESS_INSTANCE_STATE, processInstance.getState().toString()); |
||||||
|
resultMap.put(TASK_LIST, taskInstanceList); |
||||||
|
result.put(DATA_LIST, resultMap); |
||||||
|
|
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* add dependent result for dependent task |
||||||
|
*/ |
||||||
|
private void addDependResultForTaskList(List<TaskInstance> taskInstanceList) throws IOException { |
||||||
|
for (TaskInstance taskInstance : taskInstanceList) { |
||||||
|
if (taskInstance.getTaskType().equalsIgnoreCase(TaskType.DEPENDENT.toString())) { |
||||||
|
Result<String> logResult = loggerService.queryLog( |
||||||
|
taskInstance.getId(), Constants.LOG_QUERY_SKIP_LINE_NUMBER, Constants.LOG_QUERY_LIMIT); |
||||||
|
if (logResult.getCode() == Status.SUCCESS.ordinal()) { |
||||||
|
String log = logResult.getData(); |
||||||
|
Map<String, DependResult> resultMap = parseLogForDependentResult(log); |
||||||
|
taskInstance.setDependentResult(JSONUtils.toJsonString(resultMap)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Map<String, DependResult> parseLogForDependentResult(String log) throws IOException { |
||||||
|
Map<String, DependResult> resultMap = new HashMap<>(); |
||||||
|
if (StringUtils.isEmpty(log)) { |
||||||
|
return resultMap; |
||||||
|
} |
||||||
|
|
||||||
|
BufferedReader br = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(log.getBytes( |
||||||
|
StandardCharsets.UTF_8)), StandardCharsets.UTF_8)); |
||||||
|
String line; |
||||||
|
while ((line = br.readLine()) != null) { |
||||||
|
if (line.contains(DEPENDENT_SPLIT)) { |
||||||
|
String[] tmpStringArray = line.split(":\\|\\|"); |
||||||
|
if (tmpStringArray.length != 2) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
String dependResultString = tmpStringArray[1]; |
||||||
|
String[] dependStringArray = dependResultString.split(","); |
||||||
|
if (dependStringArray.length != 2) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
String key = dependStringArray[0].trim(); |
||||||
|
DependResult dependResult = DependResult.valueOf(dependStringArray[1].trim()); |
||||||
|
resultMap.put(key, dependResult); |
||||||
|
} |
||||||
|
} |
||||||
|
return resultMap; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* query sub process instance detail info by task id |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param projectName project name |
||||||
|
* @param taskId task id |
||||||
|
* @return sub process instance detail |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> querySubProcessInstanceByTaskId(User loginUser, String projectName, Integer taskId) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
Project project = projectMapper.queryByName(projectName); |
||||||
|
|
||||||
|
Map<String, Object> checkResult = projectService.checkProjectAndAuth(loginUser, project, projectName); |
||||||
|
Status resultEnum = (Status) checkResult.get(Constants.STATUS); |
||||||
|
if (resultEnum != Status.SUCCESS) { |
||||||
|
return checkResult; |
||||||
|
} |
||||||
|
|
||||||
|
TaskInstance taskInstance = processService.findTaskInstanceById(taskId); |
||||||
|
if (taskInstance == null) { |
||||||
|
putMsg(result, Status.TASK_INSTANCE_NOT_EXISTS, taskId); |
||||||
|
return result; |
||||||
|
} |
||||||
|
if (!taskInstance.isSubProcess()) { |
||||||
|
putMsg(result, Status.TASK_INSTANCE_NOT_SUB_WORKFLOW_INSTANCE, taskInstance.getName()); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
ProcessInstance subWorkflowInstance = processService.findSubProcessInstance( |
||||||
|
taskInstance.getProcessInstanceId(), taskInstance.getId()); |
||||||
|
if (subWorkflowInstance == null) { |
||||||
|
putMsg(result, Status.SUB_PROCESS_INSTANCE_NOT_EXIST, taskId); |
||||||
|
return result; |
||||||
|
} |
||||||
|
Map<String, Object> dataMap = new HashMap<>(); |
||||||
|
dataMap.put(Constants.SUBPROCESS_INSTANCE_ID, subWorkflowInstance.getId()); |
||||||
|
result.put(DATA_LIST, dataMap); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* update process instance |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param projectName project name |
||||||
|
* @param processInstanceJson process instance json |
||||||
|
* @param processInstanceId process instance id |
||||||
|
* @param scheduleTime schedule time |
||||||
|
* @param syncDefine sync define |
||||||
|
* @param flag flag |
||||||
|
* @param locations locations |
||||||
|
* @param connects connects |
||||||
|
* @return update result code |
||||||
|
* @throws ParseException parse exception for json parse |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> updateProcessInstance(User loginUser, String projectName, Integer processInstanceId, |
||||||
|
String processInstanceJson, String scheduleTime, Boolean syncDefine, |
||||||
|
Flag flag, String locations, String connects) throws ParseException { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
Project project = projectMapper.queryByName(projectName); |
||||||
|
//check project permission
|
||||||
|
Map<String, Object> checkResult = projectService.checkProjectAndAuth(loginUser, project, projectName); |
||||||
|
Status resultEnum = (Status) checkResult.get(Constants.STATUS); |
||||||
|
if (resultEnum != Status.SUCCESS) { |
||||||
|
return checkResult; |
||||||
|
} |
||||||
|
//check process instance exists
|
||||||
|
ProcessInstance processInstance = processService.findProcessInstanceDetailById(processInstanceId); |
||||||
|
if (processInstance == null) { |
||||||
|
putMsg(result, Status.PROCESS_INSTANCE_NOT_EXIST, processInstanceId); |
||||||
|
return result; |
||||||
|
} |
||||||
|
//check process instance status
|
||||||
|
if (!processInstance.getState().typeIsFinished()) { |
||||||
|
putMsg(result, Status.PROCESS_INSTANCE_STATE_OPERATION_ERROR, |
||||||
|
processInstance.getName(), processInstance.getState().toString(), "update"); |
||||||
|
return result; |
||||||
|
} |
||||||
|
ProcessDefinition processDefinition = processService.findProcessDefinition(processInstance.getProcessDefinitionCode(), |
||||||
|
processInstance.getProcessDefinitionVersion()); |
||||||
|
ProcessData processData = JSONUtils.parseObject(processInstanceJson, ProcessData.class); |
||||||
|
//check workflow json is valid
|
||||||
|
result = processDefinitionService.checkProcessNodeList(processData, processInstanceJson); |
||||||
|
if (result.get(Constants.STATUS) != Status.SUCCESS) { |
||||||
|
return result; |
||||||
|
} |
||||||
|
Tenant tenant = processService.getTenantForProcess(processData.getTenantId(), |
||||||
|
processDefinition.getUserId()); |
||||||
|
// get the processinstancejson before saving,and then save the name and taskid
|
||||||
|
String oldJson = processInstance.getProcessInstanceJson(); |
||||||
|
if (StringUtils.isNotEmpty(oldJson)) { |
||||||
|
processInstanceJson = processService.changeJson(processData, oldJson); |
||||||
|
} |
||||||
|
setProcessInstance(processInstance, tenant, scheduleTime, locations, |
||||||
|
connects, processInstanceJson, processData); |
||||||
|
int update = processService.updateProcessInstance(processInstance); |
||||||
|
int updateDefine = 1; |
||||||
|
if (Boolean.TRUE.equals(syncDefine)) { |
||||||
|
updateDefine = syncDefinition(loginUser, project, processInstanceJson, locations, connects, |
||||||
|
processInstance, processDefinition, processData); |
||||||
|
} |
||||||
|
if (update > 0 && updateDefine > 0) { |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
} else { |
||||||
|
putMsg(result, Status.UPDATE_PROCESS_INSTANCE_ERROR); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* sync definition according process instance |
||||||
|
*/ |
||||||
|
private int syncDefinition(User loginUser, Project project, String processInstanceJson, String locations, String connects, |
||||||
|
ProcessInstance processInstance, ProcessDefinition processDefinition, |
||||||
|
ProcessData processData) { |
||||||
|
|
||||||
|
String originDefParams = JSONUtils.toJsonString(processData.getGlobalParams()); |
||||||
|
processDefinition.setProcessDefinitionJson(processInstanceJson); |
||||||
|
processDefinition.setGlobalParams(originDefParams); |
||||||
|
processDefinition.setLocations(locations); |
||||||
|
processDefinition.setConnects(connects); |
||||||
|
processDefinition.setTimeout(processInstance.getTimeout()); |
||||||
|
processDefinition.setUpdateTime(new Date()); |
||||||
|
|
||||||
|
int updateDefine = processService.saveProcessDefinition(loginUser, project, processDefinition.getName(), |
||||||
|
processDefinition.getDescription(), locations, connects, |
||||||
|
processData, processDefinition); |
||||||
|
return updateDefine; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* update process instance attributes |
||||||
|
* |
||||||
|
* @return false if check failed or |
||||||
|
*/ |
||||||
|
private void setProcessInstance(ProcessInstance processInstance, Tenant tenant, |
||||||
|
String scheduleTime, String locations, String connects, String processInstanceJson, |
||||||
|
ProcessData processData) { |
||||||
|
|
||||||
|
Date schedule = processInstance.getScheduleTime(); |
||||||
|
if (scheduleTime != null) { |
||||||
|
schedule = DateUtils.getScheduleDate(scheduleTime); |
||||||
|
} |
||||||
|
processInstance.setScheduleTime(schedule); |
||||||
|
processInstance.setLocations(locations); |
||||||
|
processInstance.setConnects(connects); |
||||||
|
if (StringUtils.isNotEmpty(processInstanceJson)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
List<Property> globalParamList = processData.getGlobalParams(); |
||||||
|
Map<String, String> globalParamMap = Optional.ofNullable(globalParamList).orElse(Collections.emptyList()).stream().collect(Collectors.toMap(Property::getProp, Property::getValue)); |
||||||
|
String globalParams = ParameterUtils.curingGlobalParams(globalParamMap, globalParamList, |
||||||
|
processInstance.getCmdTypeIfComplement(), schedule); |
||||||
|
int timeout = processData.getTimeout(); |
||||||
|
processInstance.setTimeout(timeout); |
||||||
|
if (tenant != null) { |
||||||
|
processInstance.setTenantCode(tenant.getTenantCode()); |
||||||
|
} |
||||||
|
processInstance.setProcessInstanceJson(processInstanceJson); |
||||||
|
processInstance.setGlobalParams(globalParams); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* query parent process instance detail info by sub process instance id |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param projectName project name |
||||||
|
* @param subId sub process id |
||||||
|
* @return parent instance detail |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> queryParentInstanceBySubId(User loginUser, String projectName, Integer subId) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
Project project = projectMapper.queryByName(projectName); |
||||||
|
|
||||||
|
Map<String, Object> checkResult = projectService.checkProjectAndAuth(loginUser, project, projectName); |
||||||
|
Status resultEnum = (Status) checkResult.get(Constants.STATUS); |
||||||
|
if (resultEnum != Status.SUCCESS) { |
||||||
|
return checkResult; |
||||||
|
} |
||||||
|
|
||||||
|
ProcessInstance subInstance = processService.findProcessInstanceDetailById(subId); |
||||||
|
if (subInstance == null) { |
||||||
|
putMsg(result, Status.PROCESS_INSTANCE_NOT_EXIST, subId); |
||||||
|
return result; |
||||||
|
} |
||||||
|
if (subInstance.getIsSubProcess() == Flag.NO) { |
||||||
|
putMsg(result, Status.PROCESS_INSTANCE_NOT_SUB_PROCESS_INSTANCE, subInstance.getName()); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
ProcessInstance parentWorkflowInstance = processService.findParentProcessInstance(subId); |
||||||
|
if (parentWorkflowInstance == null) { |
||||||
|
putMsg(result, Status.SUB_PROCESS_INSTANCE_NOT_EXIST); |
||||||
|
return result; |
||||||
|
} |
||||||
|
Map<String, Object> dataMap = new HashMap<>(); |
||||||
|
dataMap.put(Constants.PARENT_WORKFLOW_INSTANCE, parentWorkflowInstance.getId()); |
||||||
|
result.put(DATA_LIST, dataMap); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* delete process instance by id, at the same time,delete task instance and their mapping relation data |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param projectName project name |
||||||
|
* @param processInstanceId process instance id |
||||||
|
* @return delete result code |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
@Transactional(rollbackFor = RuntimeException.class) |
||||||
|
public Map<String, Object> deleteProcessInstanceById(User loginUser, String projectName, Integer processInstanceId) { |
||||||
|
|
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
Project project = projectMapper.queryByName(projectName); |
||||||
|
|
||||||
|
Map<String, Object> checkResult = projectService.checkProjectAndAuth(loginUser, project, projectName); |
||||||
|
Status resultEnum = (Status) checkResult.get(Constants.STATUS); |
||||||
|
if (resultEnum != Status.SUCCESS) { |
||||||
|
return checkResult; |
||||||
|
} |
||||||
|
ProcessInstance processInstance = processService.findProcessInstanceDetailById(processInstanceId); |
||||||
|
if (null == processInstance) { |
||||||
|
putMsg(result, Status.PROCESS_INSTANCE_NOT_EXIST, processInstanceId); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
processService.removeTaskLogFile(processInstanceId); |
||||||
|
// delete database cascade
|
||||||
|
int delete = processService.deleteWorkProcessInstanceById(processInstanceId); |
||||||
|
|
||||||
|
processService.deleteAllSubWorkProcessByParentId(processInstanceId); |
||||||
|
processService.deleteWorkProcessMapByParentId(processInstanceId); |
||||||
|
|
||||||
|
if (delete > 0) { |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
} else { |
||||||
|
putMsg(result, Status.DELETE_PROCESS_INSTANCE_BY_ID_ERROR); |
||||||
|
} |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* view process instance variables |
||||||
|
* |
||||||
|
* @param processInstanceId process instance id |
||||||
|
* @return variables data |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> viewVariables(Integer processInstanceId) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
|
||||||
|
ProcessInstance processInstance = processInstanceMapper.queryDetailById(processInstanceId); |
||||||
|
|
||||||
|
if (processInstance == null) { |
||||||
|
throw new RuntimeException("workflow instance is null"); |
||||||
|
} |
||||||
|
|
||||||
|
Map<String, String> timeParams = BusinessTimeUtils |
||||||
|
.getBusinessTime(processInstance.getCmdTypeIfComplement(), |
||||||
|
processInstance.getScheduleTime()); |
||||||
|
String userDefinedParams = processInstance.getGlobalParams(); |
||||||
|
// global params
|
||||||
|
List<Property> globalParams = new ArrayList<>(); |
||||||
|
|
||||||
|
// global param string
|
||||||
|
String globalParamStr = ParameterUtils.convertParameterPlaceholders(JSONUtils.toJsonString(globalParams), timeParams); |
||||||
|
globalParams = JSONUtils.toList(globalParamStr, Property.class); |
||||||
|
for (Property property : globalParams) { |
||||||
|
timeParams.put(property.getProp(), property.getValue()); |
||||||
|
} |
||||||
|
|
||||||
|
if (userDefinedParams != null && userDefinedParams.length() > 0) { |
||||||
|
globalParams = JSONUtils.toList(userDefinedParams, Property.class); |
||||||
|
} |
||||||
|
|
||||||
|
Map<String, Map<String, Object>> localUserDefParams = getLocalParams(processInstance, timeParams); |
||||||
|
|
||||||
|
Map<String, Object> resultMap = new HashMap<>(); |
||||||
|
|
||||||
|
resultMap.put(GLOBAL_PARAMS, globalParams); |
||||||
|
resultMap.put(LOCAL_PARAMS, localUserDefParams); |
||||||
|
|
||||||
|
result.put(DATA_LIST, resultMap); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* get local params |
||||||
|
* |
||||||
|
* @param processInstance |
||||||
|
* @param timeParams |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
private Map<String, Map<String, Object>> getLocalParams(ProcessInstance processInstance, Map<String, String> timeParams) { |
||||||
|
Map<String, Map<String, Object>> localUserDefParams = new HashMap<>(); |
||||||
|
List<TaskInstance> taskInstanceList = taskInstanceMapper.findValidTaskListByProcessId(processInstance.getId(), Flag.YES); |
||||||
|
for (TaskInstance taskInstance : taskInstanceList) { |
||||||
|
TaskDefinitionLog taskDefinitionLog = taskDefinitionLogMapper.queryByDefinitionCodeAndVersion( |
||||||
|
taskInstance.getTaskCode(), taskInstance.getTaskDefinitionVersion()); |
||||||
|
String parameter = taskDefinitionLog.getTaskParams(); |
||||||
|
Map<String, String> map = JSONUtils.toMap(parameter); |
||||||
|
String localParams = map.get(LOCAL_PARAMS); |
||||||
|
if (localParams != null && !localParams.isEmpty()) { |
||||||
|
localParams = ParameterUtils.convertParameterPlaceholders(localParams, timeParams); |
||||||
|
List<Property> localParamsList = JSONUtils.toList(localParams, Property.class); |
||||||
|
|
||||||
|
Map<String, Object> localParamsMap = new HashMap<>(); |
||||||
|
localParamsMap.put(TASK_TYPE, taskDefinitionLog.getTaskType()); |
||||||
|
localParamsMap.put(LOCAL_PARAMS_LIST, localParamsList); |
||||||
|
if (CollectionUtils.isNotEmpty(localParamsList)) { |
||||||
|
localUserDefParams.put(taskDefinitionLog.getName(), localParamsMap); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
return localUserDefParams; |
||||||
|
} |
||||||
|
/** |
||||||
|
* encapsulation gantt structure |
||||||
|
* |
||||||
|
* @param processInstanceId process instance id |
||||||
|
* @return gantt tree data |
||||||
|
* @throws Exception exception when json parse |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> viewGantt(Integer processInstanceId) throws Exception { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
|
||||||
|
ProcessInstance processInstance = processInstanceMapper.queryDetailById(processInstanceId); |
||||||
|
|
||||||
|
if (processInstance == null) { |
||||||
|
throw new RuntimeException("workflow instance is null"); |
||||||
|
} |
||||||
|
|
||||||
|
ProcessDefinitionLog processDefinitionLog = processDefinitionLogMapper.queryByDefinitionCodeAndVersion( |
||||||
|
processInstance.getProcessDefinitionCode(), |
||||||
|
processInstance.getProcessDefinitionVersion() |
||||||
|
); |
||||||
|
ProcessDefinition processDefinition = JSONUtils.parseObject(JSONUtils.toJsonString(processDefinitionLog), |
||||||
|
ProcessDefinition.class); |
||||||
|
|
||||||
|
GanttDto ganttDto = new GanttDto(); |
||||||
|
DAG<String, TaskNode, TaskNodeRelation> dag = processService.genDagGraph(processDefinition); |
||||||
|
//topological sort
|
||||||
|
List<String> nodeList = dag.topologicalSort(); |
||||||
|
|
||||||
|
ganttDto.setTaskNames(nodeList); |
||||||
|
|
||||||
|
List<Task> taskList = new ArrayList<>(); |
||||||
|
for (String node : nodeList) { |
||||||
|
TaskInstance taskInstance = taskInstanceMapper.queryByInstanceIdAndName(processInstanceId, node); |
||||||
|
if (taskInstance == null) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
Date startTime = taskInstance.getStartTime() == null ? new Date() : taskInstance.getStartTime(); |
||||||
|
Date endTime = taskInstance.getEndTime() == null ? new Date() : taskInstance.getEndTime(); |
||||||
|
Task task = new Task(); |
||||||
|
task.setTaskName(taskInstance.getName()); |
||||||
|
task.getStartDate().add(startTime.getTime()); |
||||||
|
task.getEndDate().add(endTime.getTime()); |
||||||
|
task.setIsoStart(startTime); |
||||||
|
task.setIsoEnd(endTime); |
||||||
|
task.setStatus(taskInstance.getState().toString()); |
||||||
|
task.setExecutionDate(taskInstance.getStartTime()); |
||||||
|
task.setDuration(DateUtils.format2Readable(endTime.getTime() - startTime.getTime())); |
||||||
|
taskList.add(task); |
||||||
|
} |
||||||
|
ganttDto.setTasks(taskList); |
||||||
|
|
||||||
|
result.put(DATA_LIST, ganttDto); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* query process instance by processDefinitionId and stateArray |
||||||
|
* @param processDefinitionId processDefinitionId |
||||||
|
* @param states states array |
||||||
|
* @return process instance list |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public List<ProcessInstance> queryByProcessDefineIdAndStatus(int processDefinitionId, int[] states) { |
||||||
|
return processInstanceMapper.queryByProcessDefineIdAndStatus(processDefinitionId, states); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* query process instance by processDefinitionId |
||||||
|
* @param processDefinitionId processDefinitionId |
||||||
|
* @param size size |
||||||
|
* @return process instance list |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public List<ProcessInstance> queryByProcessDefineId(int processDefinitionId, int size) { |
||||||
|
return processInstanceMapper.queryByProcessDefineId(processDefinitionId, size); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,299 @@ |
|||||||
|
/* |
||||||
|
* 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.api.service.impl; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.api.enums.Status; |
||||||
|
import org.apache.dolphinscheduler.api.service.QueueService; |
||||||
|
import org.apache.dolphinscheduler.api.utils.PageInfo; |
||||||
|
import org.apache.dolphinscheduler.api.utils.Result; |
||||||
|
import org.apache.dolphinscheduler.common.Constants; |
||||||
|
import org.apache.dolphinscheduler.common.utils.CollectionUtils; |
||||||
|
import org.apache.dolphinscheduler.common.utils.StringUtils; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.Queue; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.User; |
||||||
|
import org.apache.dolphinscheduler.dao.mapper.QueueMapper; |
||||||
|
import org.apache.dolphinscheduler.dao.mapper.UserMapper; |
||||||
|
|
||||||
|
import java.util.Date; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||||
|
|
||||||
|
/** |
||||||
|
* queue service impl |
||||||
|
*/ |
||||||
|
@Service |
||||||
|
public class QueueServiceImpl extends BaseServiceImpl implements QueueService { |
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(QueueServiceImpl.class); |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private QueueMapper queueMapper; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private UserMapper userMapper; |
||||||
|
|
||||||
|
/** |
||||||
|
* query queue list |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @return queue list |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> queryList(User loginUser) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
if (isNotAdmin(loginUser, result)) { |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
List<Queue> queueList = queueMapper.selectList(null); |
||||||
|
result.put(Constants.DATA_LIST, queueList); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* query queue list paging |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param pageNo page number |
||||||
|
* @param searchVal search value |
||||||
|
* @param pageSize page size |
||||||
|
* @return queue list |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> queryList(User loginUser, String searchVal, Integer pageNo, Integer pageSize) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
if (isNotAdmin(loginUser, result)) { |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
Page<Queue> page = new Page<>(pageNo, pageSize); |
||||||
|
|
||||||
|
IPage<Queue> queueList = queueMapper.queryQueuePaging(page, searchVal); |
||||||
|
|
||||||
|
Integer count = (int) queueList.getTotal(); |
||||||
|
PageInfo<Queue> pageInfo = new PageInfo<>(pageNo, pageSize); |
||||||
|
pageInfo.setTotalCount(count); |
||||||
|
pageInfo.setLists(queueList.getRecords()); |
||||||
|
result.put(Constants.DATA_LIST, pageInfo); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* create queue |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param queue queue |
||||||
|
* @param queueName queue name |
||||||
|
* @return create result |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> createQueue(User loginUser, String queue, String queueName) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
if (isNotAdmin(loginUser, result)) { |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
if (StringUtils.isEmpty(queue)) { |
||||||
|
putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, Constants.QUEUE); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
if (StringUtils.isEmpty(queueName)) { |
||||||
|
putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, Constants.QUEUE_NAME); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
if (checkQueueNameExist(queueName)) { |
||||||
|
putMsg(result, Status.QUEUE_NAME_EXIST, queueName); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
if (checkQueueExist(queue)) { |
||||||
|
putMsg(result, Status.QUEUE_VALUE_EXIST, queue); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
Queue queueObj = new Queue(); |
||||||
|
Date now = new Date(); |
||||||
|
|
||||||
|
queueObj.setQueue(queue); |
||||||
|
queueObj.setQueueName(queueName); |
||||||
|
queueObj.setCreateTime(now); |
||||||
|
queueObj.setUpdateTime(now); |
||||||
|
|
||||||
|
queueMapper.insert(queueObj); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* update queue |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param queue queue |
||||||
|
* @param id queue id |
||||||
|
* @param queueName queue name |
||||||
|
* @return update result code |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> updateQueue(User loginUser, int id, String queue, String queueName) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
if (isNotAdmin(loginUser, result)) { |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
if (StringUtils.isEmpty(queue)) { |
||||||
|
putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, Constants.QUEUE); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
if (StringUtils.isEmpty(queueName)) { |
||||||
|
putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, Constants.QUEUE_NAME); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
Queue queueObj = queueMapper.selectById(id); |
||||||
|
if (queueObj == null) { |
||||||
|
putMsg(result, Status.QUEUE_NOT_EXIST, id); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
// whether queue value or queueName is changed
|
||||||
|
if (queue.equals(queueObj.getQueue()) && queueName.equals(queueObj.getQueueName())) { |
||||||
|
putMsg(result, Status.NEED_NOT_UPDATE_QUEUE); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
// check queue name is exist
|
||||||
|
if (!queueName.equals(queueObj.getQueueName()) |
||||||
|
&& checkQueueNameExist(queueName)) { |
||||||
|
putMsg(result, Status.QUEUE_NAME_EXIST, queueName); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
// check queue value is exist
|
||||||
|
if (!queue.equals(queueObj.getQueue()) && checkQueueExist(queue)) { |
||||||
|
putMsg(result, Status.QUEUE_VALUE_EXIST, queue); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
// check old queue using by any user
|
||||||
|
if (checkIfQueueIsInUsing(queueObj.getQueueName(), queueName)) { |
||||||
|
//update user related old queue
|
||||||
|
Integer relatedUserNums = userMapper.updateUserQueue(queueObj.getQueueName(), queueName); |
||||||
|
logger.info("old queue have related {} user, exec update user success.", relatedUserNums); |
||||||
|
} |
||||||
|
|
||||||
|
// update queue
|
||||||
|
Date now = new Date(); |
||||||
|
queueObj.setQueue(queue); |
||||||
|
queueObj.setQueueName(queueName); |
||||||
|
queueObj.setUpdateTime(now); |
||||||
|
|
||||||
|
queueMapper.updateById(queueObj); |
||||||
|
|
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* verify queue and queueName |
||||||
|
* |
||||||
|
* @param queue queue |
||||||
|
* @param queueName queue name |
||||||
|
* @return true if the queue name not exists, otherwise return false |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Result<Object> verifyQueue(String queue, String queueName) { |
||||||
|
Result<Object> result = new Result<>(); |
||||||
|
|
||||||
|
if (StringUtils.isEmpty(queue)) { |
||||||
|
putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, Constants.QUEUE); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
if (StringUtils.isEmpty(queueName)) { |
||||||
|
putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, Constants.QUEUE_NAME); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
if (checkQueueNameExist(queueName)) { |
||||||
|
putMsg(result, Status.QUEUE_NAME_EXIST, queueName); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
if (checkQueueExist(queue)) { |
||||||
|
putMsg(result, Status.QUEUE_VALUE_EXIST, queue); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* check queue exist |
||||||
|
* if exists return true,not exists return false |
||||||
|
* check queue exist |
||||||
|
* |
||||||
|
* @param queue queue |
||||||
|
* @return true if the queue not exists, otherwise return false |
||||||
|
*/ |
||||||
|
private boolean checkQueueExist(String queue) { |
||||||
|
return CollectionUtils.isNotEmpty(queueMapper.queryAllQueueList(queue, null)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* check queue name exist |
||||||
|
* if exists return true,not exists return false |
||||||
|
* |
||||||
|
* @param queueName queue name |
||||||
|
* @return true if the queue name not exists, otherwise return false |
||||||
|
*/ |
||||||
|
private boolean checkQueueNameExist(String queueName) { |
||||||
|
return CollectionUtils.isNotEmpty(queueMapper.queryAllQueueList(null, queueName)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* check old queue name using by any user |
||||||
|
* if need to update user |
||||||
|
* |
||||||
|
* @param oldQueue old queue name |
||||||
|
* @param newQueue new queue name |
||||||
|
* @return true if need to update user |
||||||
|
*/ |
||||||
|
private boolean checkIfQueueIsInUsing (String oldQueue, String newQueue) { |
||||||
|
return !oldQueue.equals(newQueue) && CollectionUtils.isNotEmpty(userMapper.queryUserListByQueue(oldQueue)); |
||||||
|
} |
||||||
|
|
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,607 @@ |
|||||||
|
/* |
||||||
|
* 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.api.service.impl; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.api.dto.ScheduleParam; |
||||||
|
import org.apache.dolphinscheduler.api.enums.Status; |
||||||
|
import org.apache.dolphinscheduler.api.exceptions.ServiceException; |
||||||
|
import org.apache.dolphinscheduler.api.service.ExecutorService; |
||||||
|
import org.apache.dolphinscheduler.api.service.MonitorService; |
||||||
|
import org.apache.dolphinscheduler.api.service.ProjectService; |
||||||
|
import org.apache.dolphinscheduler.api.service.SchedulerService; |
||||||
|
import org.apache.dolphinscheduler.api.utils.PageInfo; |
||||||
|
import org.apache.dolphinscheduler.common.Constants; |
||||||
|
import org.apache.dolphinscheduler.common.enums.FailureStrategy; |
||||||
|
import org.apache.dolphinscheduler.common.enums.Priority; |
||||||
|
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.model.Server; |
||||||
|
import org.apache.dolphinscheduler.common.utils.DateUtils; |
||||||
|
import org.apache.dolphinscheduler.common.utils.JSONUtils; |
||||||
|
import org.apache.dolphinscheduler.common.utils.StringUtils; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.ProcessDefinition; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.Project; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.Schedule; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.User; |
||||||
|
import org.apache.dolphinscheduler.dao.mapper.ProcessDefinitionMapper; |
||||||
|
import org.apache.dolphinscheduler.dao.mapper.ProjectMapper; |
||||||
|
import org.apache.dolphinscheduler.dao.mapper.ScheduleMapper; |
||||||
|
import org.apache.dolphinscheduler.service.process.ProcessService; |
||||||
|
import org.apache.dolphinscheduler.service.quartz.ProcessScheduleJob; |
||||||
|
import org.apache.dolphinscheduler.service.quartz.QuartzExecutors; |
||||||
|
import org.apache.dolphinscheduler.service.quartz.cron.CronUtils; |
||||||
|
|
||||||
|
import java.text.ParseException; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Date; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import org.quartz.CronExpression; |
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
import org.springframework.transaction.annotation.Transactional; |
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||||
|
|
||||||
|
/** |
||||||
|
* scheduler service impl |
||||||
|
*/ |
||||||
|
@Service |
||||||
|
public class SchedulerServiceImpl extends BaseServiceImpl implements SchedulerService { |
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(SchedulerServiceImpl.class); |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private ProjectService projectService; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private ExecutorService executorService; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private MonitorService monitorService; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private ProcessService processService; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private ScheduleMapper scheduleMapper; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private ProjectMapper projectMapper; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private ProcessDefinitionMapper processDefinitionMapper; |
||||||
|
|
||||||
|
/** |
||||||
|
* save schedule |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param projectName project name |
||||||
|
* @param processDefineId process definition id |
||||||
|
* @param schedule scheduler |
||||||
|
* @param warningType warning type |
||||||
|
* @param warningGroupId warning group id |
||||||
|
* @param failureStrategy failure strategy |
||||||
|
* @param processInstancePriority process instance priority |
||||||
|
* @param workerGroup worker group |
||||||
|
* @return create result code |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
@Transactional(rollbackFor = RuntimeException.class) |
||||||
|
public Map<String, Object> insertSchedule(User loginUser, String projectName, |
||||||
|
Integer processDefineId, |
||||||
|
String schedule, |
||||||
|
WarningType warningType, |
||||||
|
int warningGroupId, |
||||||
|
FailureStrategy failureStrategy, |
||||||
|
Priority processInstancePriority, |
||||||
|
String workerGroup) { |
||||||
|
|
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
|
||||||
|
Project project = projectMapper.queryByName(projectName); |
||||||
|
|
||||||
|
// check project auth
|
||||||
|
boolean hasProjectAndPerm = projectService.hasProjectAndPerm(loginUser, project, result); |
||||||
|
if (!hasProjectAndPerm) { |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
// check work flow define release state
|
||||||
|
ProcessDefinition processDefinition = processService.findProcessDefineById(processDefineId); |
||||||
|
result = executorService.checkProcessDefinitionValid(processDefinition, processDefineId); |
||||||
|
if (result.get(Constants.STATUS) != Status.SUCCESS) { |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
Schedule scheduleObj = new Schedule(); |
||||||
|
Date now = new Date(); |
||||||
|
|
||||||
|
scheduleObj.setProjectName(projectName); |
||||||
|
scheduleObj.setProcessDefinitionId(processDefinition.getId()); |
||||||
|
scheduleObj.setProcessDefinitionName(processDefinition.getName()); |
||||||
|
|
||||||
|
ScheduleParam scheduleParam = JSONUtils.parseObject(schedule, ScheduleParam.class); |
||||||
|
if (DateUtils.differSec(scheduleParam.getStartTime(), scheduleParam.getEndTime()) == 0) { |
||||||
|
logger.warn("The start time must not be the same as the end"); |
||||||
|
putMsg(result, Status.SCHEDULE_START_TIME_END_TIME_SAME); |
||||||
|
return result; |
||||||
|
} |
||||||
|
scheduleObj.setStartTime(scheduleParam.getStartTime()); |
||||||
|
scheduleObj.setEndTime(scheduleParam.getEndTime()); |
||||||
|
if (!org.quartz.CronExpression.isValidExpression(scheduleParam.getCrontab())) { |
||||||
|
logger.error("{} verify failure", scheduleParam.getCrontab()); |
||||||
|
|
||||||
|
putMsg(result, Status.REQUEST_PARAMS_NOT_VALID_ERROR, scheduleParam.getCrontab()); |
||||||
|
return result; |
||||||
|
} |
||||||
|
scheduleObj.setCrontab(scheduleParam.getCrontab()); |
||||||
|
scheduleObj.setWarningType(warningType); |
||||||
|
scheduleObj.setWarningGroupId(warningGroupId); |
||||||
|
scheduleObj.setFailureStrategy(failureStrategy); |
||||||
|
scheduleObj.setCreateTime(now); |
||||||
|
scheduleObj.setUpdateTime(now); |
||||||
|
scheduleObj.setUserId(loginUser.getId()); |
||||||
|
scheduleObj.setUserName(loginUser.getUserName()); |
||||||
|
scheduleObj.setReleaseState(ReleaseState.OFFLINE); |
||||||
|
scheduleObj.setProcessInstancePriority(processInstancePriority); |
||||||
|
scheduleObj.setWorkerGroup(workerGroup); |
||||||
|
scheduleMapper.insert(scheduleObj); |
||||||
|
|
||||||
|
/** |
||||||
|
* updateProcessInstance receivers and cc by process definition id |
||||||
|
*/ |
||||||
|
processDefinition.setWarningGroupId(warningGroupId); |
||||||
|
processDefinitionMapper.updateById(processDefinition); |
||||||
|
|
||||||
|
// return scheduler object with ID
|
||||||
|
result.put(Constants.DATA_LIST, scheduleMapper.selectById(scheduleObj.getId())); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
|
||||||
|
result.put("scheduleId", scheduleObj.getId()); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* updateProcessInstance schedule |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param projectName project name |
||||||
|
* @param id scheduler id |
||||||
|
* @param scheduleExpression scheduler |
||||||
|
* @param warningType warning type |
||||||
|
* @param warningGroupId warning group id |
||||||
|
* @param failureStrategy failure strategy |
||||||
|
* @param workerGroup worker group |
||||||
|
* @param processInstancePriority process instance priority |
||||||
|
* @param scheduleStatus schedule status |
||||||
|
* @return update result code |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
@Transactional(rollbackFor = RuntimeException.class) |
||||||
|
public Map<String, Object> updateSchedule(User loginUser, |
||||||
|
String projectName, |
||||||
|
Integer id, |
||||||
|
String scheduleExpression, |
||||||
|
WarningType warningType, |
||||||
|
int warningGroupId, |
||||||
|
FailureStrategy failureStrategy, |
||||||
|
ReleaseState scheduleStatus, |
||||||
|
Priority processInstancePriority, |
||||||
|
String workerGroup) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
|
||||||
|
Project project = projectMapper.queryByName(projectName); |
||||||
|
|
||||||
|
// check project auth
|
||||||
|
boolean hasProjectAndPerm = projectService.hasProjectAndPerm(loginUser, project, result); |
||||||
|
if (!hasProjectAndPerm) { |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
// check schedule exists
|
||||||
|
Schedule schedule = scheduleMapper.selectById(id); |
||||||
|
|
||||||
|
if (schedule == null) { |
||||||
|
putMsg(result, Status.SCHEDULE_CRON_NOT_EXISTS, id); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
ProcessDefinition processDefinition = processService.findProcessDefineById(schedule.getProcessDefinitionId()); |
||||||
|
if (processDefinition == null) { |
||||||
|
putMsg(result, Status.PROCESS_DEFINE_NOT_EXIST, schedule.getProcessDefinitionId()); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* scheduling on-line status forbid modification |
||||||
|
*/ |
||||||
|
if (checkValid(result, schedule.getReleaseState() == ReleaseState.ONLINE, Status.SCHEDULE_CRON_ONLINE_FORBID_UPDATE)) { |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
Date now = new Date(); |
||||||
|
|
||||||
|
// updateProcessInstance param
|
||||||
|
if (StringUtils.isNotEmpty(scheduleExpression)) { |
||||||
|
ScheduleParam scheduleParam = JSONUtils.parseObject(scheduleExpression, ScheduleParam.class); |
||||||
|
if (DateUtils.differSec(scheduleParam.getStartTime(), scheduleParam.getEndTime()) == 0) { |
||||||
|
logger.warn("The start time must not be the same as the end"); |
||||||
|
putMsg(result, Status.SCHEDULE_START_TIME_END_TIME_SAME); |
||||||
|
return result; |
||||||
|
} |
||||||
|
schedule.setStartTime(scheduleParam.getStartTime()); |
||||||
|
schedule.setEndTime(scheduleParam.getEndTime()); |
||||||
|
if (!org.quartz.CronExpression.isValidExpression(scheduleParam.getCrontab())) { |
||||||
|
putMsg(result, Status.SCHEDULE_CRON_CHECK_FAILED, scheduleParam.getCrontab()); |
||||||
|
return result; |
||||||
|
} |
||||||
|
schedule.setCrontab(scheduleParam.getCrontab()); |
||||||
|
} |
||||||
|
|
||||||
|
if (warningType != null) { |
||||||
|
schedule.setWarningType(warningType); |
||||||
|
} |
||||||
|
|
||||||
|
schedule.setWarningGroupId(warningGroupId); |
||||||
|
|
||||||
|
if (failureStrategy != null) { |
||||||
|
schedule.setFailureStrategy(failureStrategy); |
||||||
|
} |
||||||
|
|
||||||
|
if (scheduleStatus != null) { |
||||||
|
schedule.setReleaseState(scheduleStatus); |
||||||
|
} |
||||||
|
schedule.setWorkerGroup(workerGroup); |
||||||
|
schedule.setUpdateTime(now); |
||||||
|
schedule.setProcessInstancePriority(processInstancePriority); |
||||||
|
scheduleMapper.updateById(schedule); |
||||||
|
|
||||||
|
/** |
||||||
|
* updateProcessInstance recipients and cc by process definition ID |
||||||
|
*/ |
||||||
|
processDefinition.setWarningGroupId(warningGroupId); |
||||||
|
|
||||||
|
processDefinitionMapper.updateById(processDefinition); |
||||||
|
|
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* set schedule online or offline |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param projectName project name |
||||||
|
* @param id scheduler id |
||||||
|
* @param scheduleStatus schedule status |
||||||
|
* @return publish result code |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
@Transactional(rollbackFor = RuntimeException.class) |
||||||
|
public Map<String, Object> setScheduleState(User loginUser, |
||||||
|
String projectName, |
||||||
|
Integer id, |
||||||
|
ReleaseState scheduleStatus) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
|
||||||
|
Project project = projectMapper.queryByName(projectName); |
||||||
|
// check project auth
|
||||||
|
boolean hasProjectAndPerm = projectService.hasProjectAndPerm(loginUser, project, result); |
||||||
|
if (!hasProjectAndPerm) { |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
// check schedule exists
|
||||||
|
Schedule scheduleObj = scheduleMapper.selectById(id); |
||||||
|
|
||||||
|
if (scheduleObj == null) { |
||||||
|
putMsg(result, Status.SCHEDULE_CRON_NOT_EXISTS, id); |
||||||
|
return result; |
||||||
|
} |
||||||
|
// check schedule release state
|
||||||
|
if (scheduleObj.getReleaseState() == scheduleStatus) { |
||||||
|
logger.info("schedule release is already {},needn't to change schedule id: {} from {} to {}", |
||||||
|
scheduleObj.getReleaseState(), scheduleObj.getId(), scheduleObj.getReleaseState(), scheduleStatus); |
||||||
|
putMsg(result, Status.SCHEDULE_CRON_REALEASE_NEED_NOT_CHANGE, scheduleStatus); |
||||||
|
return result; |
||||||
|
} |
||||||
|
ProcessDefinition processDefinition = processService.findProcessDefineById(scheduleObj.getProcessDefinitionId()); |
||||||
|
if (processDefinition == null) { |
||||||
|
putMsg(result, Status.PROCESS_DEFINE_NOT_EXIST, scheduleObj.getProcessDefinitionId()); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
if (scheduleStatus == ReleaseState.ONLINE) { |
||||||
|
// check process definition release state
|
||||||
|
if (processDefinition.getReleaseState() != ReleaseState.ONLINE) { |
||||||
|
logger.info("not release process definition id: {} , name : {}", |
||||||
|
processDefinition.getId(), processDefinition.getName()); |
||||||
|
putMsg(result, Status.PROCESS_DEFINE_NOT_RELEASE, processDefinition.getName()); |
||||||
|
return result; |
||||||
|
} |
||||||
|
// check sub process definition release state
|
||||||
|
List<Integer> subProcessDefineIds = new ArrayList<>(); |
||||||
|
processService.recurseFindSubProcessId(scheduleObj.getProcessDefinitionId(), subProcessDefineIds); |
||||||
|
Integer[] idArray = subProcessDefineIds.toArray(new Integer[subProcessDefineIds.size()]); |
||||||
|
if (!subProcessDefineIds.isEmpty()) { |
||||||
|
List<ProcessDefinition> subProcessDefinitionList = |
||||||
|
processDefinitionMapper.queryDefinitionListByIdList(idArray); |
||||||
|
if (subProcessDefinitionList != null && !subProcessDefinitionList.isEmpty()) { |
||||||
|
for (ProcessDefinition subProcessDefinition : subProcessDefinitionList) { |
||||||
|
/** |
||||||
|
* if there is no online process, exit directly |
||||||
|
*/ |
||||||
|
if (subProcessDefinition.getReleaseState() != ReleaseState.ONLINE) { |
||||||
|
logger.info("not release process definition id: {} , name : {}", |
||||||
|
subProcessDefinition.getId(), subProcessDefinition.getName()); |
||||||
|
putMsg(result, Status.PROCESS_DEFINE_NOT_RELEASE, subProcessDefinition.getId()); |
||||||
|
return result; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// check master server exists
|
||||||
|
List<Server> masterServers = monitorService.getServerListFromZK(true); |
||||||
|
|
||||||
|
if (masterServers.isEmpty()) { |
||||||
|
putMsg(result, Status.MASTER_NOT_EXISTS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
// set status
|
||||||
|
scheduleObj.setReleaseState(scheduleStatus); |
||||||
|
|
||||||
|
scheduleMapper.updateById(scheduleObj); |
||||||
|
|
||||||
|
try { |
||||||
|
switch (scheduleStatus) { |
||||||
|
case ONLINE: |
||||||
|
logger.info("Call master client set schedule online, project id: {}, flow id: {},host: {}", project.getId(), processDefinition.getId(), masterServers); |
||||||
|
setSchedule(project.getId(), scheduleObj); |
||||||
|
break; |
||||||
|
case OFFLINE: |
||||||
|
logger.info("Call master client set schedule offline, project id: {}, flow id: {},host: {}", project.getId(), processDefinition.getId(), masterServers); |
||||||
|
deleteSchedule(project.getId(), id); |
||||||
|
break; |
||||||
|
default: |
||||||
|
putMsg(result, Status.SCHEDULE_STATUS_UNKNOWN, scheduleStatus.toString()); |
||||||
|
return result; |
||||||
|
} |
||||||
|
} catch (Exception e) { |
||||||
|
result.put(Constants.MSG, scheduleStatus == ReleaseState.ONLINE ? "set online failure" : "set offline failure"); |
||||||
|
throw new ServiceException(result.get(Constants.MSG).toString()); |
||||||
|
} |
||||||
|
|
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* query schedule |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param projectName project name |
||||||
|
* @param processDefineId process definition id |
||||||
|
* @param pageNo page number |
||||||
|
* @param pageSize page size |
||||||
|
* @param searchVal search value |
||||||
|
* @return schedule list page |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> querySchedule(User loginUser, String projectName, Integer processDefineId, String searchVal, Integer pageNo, Integer pageSize) { |
||||||
|
|
||||||
|
HashMap<String, Object> result = new HashMap<>(); |
||||||
|
|
||||||
|
Project project = projectMapper.queryByName(projectName); |
||||||
|
|
||||||
|
// check project auth
|
||||||
|
boolean hasProjectAndPerm = projectService.hasProjectAndPerm(loginUser, project, result); |
||||||
|
if (!hasProjectAndPerm) { |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
ProcessDefinition processDefinition = processService.findProcessDefineById(processDefineId); |
||||||
|
if (processDefinition == null) { |
||||||
|
putMsg(result, Status.PROCESS_DEFINE_NOT_EXIST, processDefineId); |
||||||
|
return result; |
||||||
|
} |
||||||
|
Page<Schedule> page = new Page<>(pageNo, pageSize); |
||||||
|
IPage<Schedule> scheduleIPage = scheduleMapper.queryByProcessDefineIdPaging( |
||||||
|
page, processDefineId, searchVal |
||||||
|
); |
||||||
|
|
||||||
|
PageInfo<Schedule> pageInfo = new PageInfo<>(pageNo, pageSize); |
||||||
|
pageInfo.setTotalCount((int) scheduleIPage.getTotal()); |
||||||
|
pageInfo.setLists(scheduleIPage.getRecords()); |
||||||
|
result.put(Constants.DATA_LIST, pageInfo); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* query schedule list |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param projectName project name |
||||||
|
* @return schedule list |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> queryScheduleList(User loginUser, String projectName) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
Project project = projectMapper.queryByName(projectName); |
||||||
|
|
||||||
|
// check project auth
|
||||||
|
boolean hasProjectAndPerm = projectService.hasProjectAndPerm(loginUser, project, result); |
||||||
|
if (!hasProjectAndPerm) { |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
List<Schedule> schedules = scheduleMapper.querySchedulerListByProjectName(projectName); |
||||||
|
|
||||||
|
result.put(Constants.DATA_LIST, schedules); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
public void setSchedule(int projectId, Schedule schedule) { |
||||||
|
int scheduleId = schedule.getId(); |
||||||
|
logger.info("set schedule, project id: {}, scheduleId: {}", projectId, scheduleId); |
||||||
|
|
||||||
|
Date startDate = schedule.getStartTime(); |
||||||
|
Date endDate = schedule.getEndTime(); |
||||||
|
|
||||||
|
String jobName = QuartzExecutors.buildJobName(scheduleId); |
||||||
|
String jobGroupName = QuartzExecutors.buildJobGroupName(projectId); |
||||||
|
|
||||||
|
Map<String, Object> dataMap = QuartzExecutors.buildDataMap(projectId, scheduleId, schedule); |
||||||
|
|
||||||
|
QuartzExecutors.getInstance().addJob(ProcessScheduleJob.class, jobName, jobGroupName, startDate, endDate, |
||||||
|
schedule.getCrontab(), dataMap); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* delete schedule |
||||||
|
* |
||||||
|
* @param projectId project id |
||||||
|
* @param scheduleId schedule id |
||||||
|
* @throws RuntimeException runtime exception |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void deleteSchedule(int projectId, int scheduleId) { |
||||||
|
logger.info("delete schedules of project id:{}, schedule id:{}", projectId, scheduleId); |
||||||
|
|
||||||
|
String jobName = QuartzExecutors.buildJobName(scheduleId); |
||||||
|
String jobGroupName = QuartzExecutors.buildJobGroupName(projectId); |
||||||
|
|
||||||
|
if (!QuartzExecutors.getInstance().deleteJob(jobName, jobGroupName)) { |
||||||
|
logger.warn("set offline failure:projectId:{},scheduleId:{}", projectId, scheduleId); |
||||||
|
throw new ServiceException("set offline failure"); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* check valid |
||||||
|
* |
||||||
|
* @param result result |
||||||
|
* @param bool bool |
||||||
|
* @param status status |
||||||
|
* @return check result code |
||||||
|
*/ |
||||||
|
private boolean checkValid(Map<String, Object> result, boolean bool, Status status) { |
||||||
|
// timeout is valid
|
||||||
|
if (bool) { |
||||||
|
putMsg(result, status); |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* delete schedule by id |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param projectName project name |
||||||
|
* @param scheduleId scheule id |
||||||
|
* @return delete result code |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> deleteScheduleById(User loginUser, String projectName, Integer scheduleId) { |
||||||
|
|
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
Project project = projectMapper.queryByName(projectName); |
||||||
|
|
||||||
|
Map<String, Object> checkResult = projectService.checkProjectAndAuth(loginUser, project, projectName); |
||||||
|
Status resultEnum = (Status) checkResult.get(Constants.STATUS); |
||||||
|
if (resultEnum != Status.SUCCESS) { |
||||||
|
return checkResult; |
||||||
|
} |
||||||
|
|
||||||
|
Schedule schedule = scheduleMapper.selectById(scheduleId); |
||||||
|
|
||||||
|
if (schedule == null) { |
||||||
|
putMsg(result, Status.SCHEDULE_CRON_NOT_EXISTS, scheduleId); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
// Determine if the login user is the owner of the schedule
|
||||||
|
if (loginUser.getId() != schedule.getUserId() |
||||||
|
&& loginUser.getUserType() != UserType.ADMIN_USER) { |
||||||
|
putMsg(result, Status.USER_NO_OPERATION_PERM); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
// check schedule is already online
|
||||||
|
if (schedule.getReleaseState() == ReleaseState.ONLINE) { |
||||||
|
putMsg(result, Status.SCHEDULE_CRON_STATE_ONLINE, schedule.getId()); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
int delete = scheduleMapper.deleteById(scheduleId); |
||||||
|
|
||||||
|
if (delete > 0) { |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
} else { |
||||||
|
putMsg(result, Status.DELETE_SCHEDULE_CRON_BY_ID_ERROR); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* preview schedule |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param projectName project name |
||||||
|
* @param schedule schedule expression |
||||||
|
* @return the next five fire time |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> previewSchedule(User loginUser, String projectName, String schedule) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
CronExpression cronExpression; |
||||||
|
ScheduleParam scheduleParam = JSONUtils.parseObject(schedule, ScheduleParam.class); |
||||||
|
Date now = new Date(); |
||||||
|
|
||||||
|
Date startTime = now.after(scheduleParam.getStartTime()) ? now : scheduleParam.getStartTime(); |
||||||
|
Date endTime = scheduleParam.getEndTime(); |
||||||
|
try { |
||||||
|
cronExpression = CronUtils.parse2CronExpression(scheduleParam.getCrontab()); |
||||||
|
} catch (ParseException e) { |
||||||
|
logger.error(e.getMessage(), e); |
||||||
|
putMsg(result, Status.PARSE_TO_CRON_EXPRESSION_ERROR); |
||||||
|
return result; |
||||||
|
} |
||||||
|
List<Date> selfFireDateList = CronUtils.getSelfFireDateList(startTime, endTime, cronExpression, Constants.PREVIEW_SCHEDULE_EXECUTE_COUNT); |
||||||
|
result.put(Constants.DATA_LIST, selfFireDateList.stream().map(DateUtils::dateToString)); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,209 @@ |
|||||||
|
/* |
||||||
|
* 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.api.service.impl; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.api.enums.Status; |
||||||
|
import org.apache.dolphinscheduler.api.service.ProcessInstanceService; |
||||||
|
import org.apache.dolphinscheduler.api.service.ProjectService; |
||||||
|
import org.apache.dolphinscheduler.api.service.TaskInstanceService; |
||||||
|
import org.apache.dolphinscheduler.api.service.UsersService; |
||||||
|
import org.apache.dolphinscheduler.api.utils.PageInfo; |
||||||
|
import org.apache.dolphinscheduler.common.Constants; |
||||||
|
import org.apache.dolphinscheduler.common.enums.ExecutionStatus; |
||||||
|
import org.apache.dolphinscheduler.common.utils.CollectionUtils; |
||||||
|
import org.apache.dolphinscheduler.common.utils.DateUtils; |
||||||
|
import org.apache.dolphinscheduler.common.utils.StringUtils; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.Project; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.TaskInstance; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.User; |
||||||
|
import org.apache.dolphinscheduler.dao.mapper.ProjectMapper; |
||||||
|
import org.apache.dolphinscheduler.dao.mapper.TaskInstanceMapper; |
||||||
|
import org.apache.dolphinscheduler.service.process.ProcessService; |
||||||
|
|
||||||
|
import java.text.MessageFormat; |
||||||
|
import java.util.Date; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.HashSet; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||||
|
|
||||||
|
/** |
||||||
|
* task instance service impl |
||||||
|
*/ |
||||||
|
@Service |
||||||
|
public class TaskInstanceServiceImpl extends BaseServiceImpl implements TaskInstanceService { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
ProjectMapper projectMapper; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
ProjectService projectService; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
ProcessService processService; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
TaskInstanceMapper taskInstanceMapper; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
ProcessInstanceService processInstanceService; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
UsersService usersService; |
||||||
|
|
||||||
|
/** |
||||||
|
* query task list by project, process instance, task name, task start time, task end time, task status, keyword paging |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param projectName project name |
||||||
|
* @param processInstanceId process instance id |
||||||
|
* @param searchVal search value |
||||||
|
* @param taskName task name |
||||||
|
* @param stateType state type |
||||||
|
* @param host host |
||||||
|
* @param startDate start time |
||||||
|
* @param endDate end time |
||||||
|
* @param pageNo page number |
||||||
|
* @param pageSize page size |
||||||
|
* @return task list page |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> queryTaskListPaging(User loginUser, String projectName, |
||||||
|
Integer processInstanceId, String processInstanceName, String taskName, String executorName, String startDate, |
||||||
|
String endDate, String searchVal, ExecutionStatus stateType, String host, |
||||||
|
Integer pageNo, Integer pageSize) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
Project project = projectMapper.queryByName(projectName); |
||||||
|
|
||||||
|
Map<String, Object> checkResult = projectService.checkProjectAndAuth(loginUser, project, projectName); |
||||||
|
Status status = (Status) checkResult.get(Constants.STATUS); |
||||||
|
if (status != Status.SUCCESS) { |
||||||
|
return checkResult; |
||||||
|
} |
||||||
|
|
||||||
|
int[] statusArray = null; |
||||||
|
if (stateType != null) { |
||||||
|
statusArray = new int[]{stateType.ordinal()}; |
||||||
|
} |
||||||
|
|
||||||
|
Date start = null; |
||||||
|
Date end = null; |
||||||
|
if (StringUtils.isNotEmpty(startDate)) { |
||||||
|
start = DateUtils.getScheduleDate(startDate); |
||||||
|
if (start == null) { |
||||||
|
return generateInvalidParamRes(result, "startDate"); |
||||||
|
} |
||||||
|
} |
||||||
|
if (StringUtils.isNotEmpty(endDate)) { |
||||||
|
end = DateUtils.getScheduleDate(endDate); |
||||||
|
if (end == null) { |
||||||
|
return generateInvalidParamRes(result, "endDate"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Page<TaskInstance> page = new Page<>(pageNo, pageSize); |
||||||
|
PageInfo<Map<String, Object>> pageInfo = new PageInfo<>(pageNo, pageSize); |
||||||
|
int executorId = usersService.getUserIdByName(executorName); |
||||||
|
|
||||||
|
IPage<TaskInstance> taskInstanceIPage = taskInstanceMapper.queryTaskInstanceListPaging( |
||||||
|
page, project.getId(), processInstanceId, processInstanceName, searchVal, taskName, executorId, statusArray, host, start, end |
||||||
|
); |
||||||
|
Set<String> exclusionSet = new HashSet<>(); |
||||||
|
exclusionSet.add(Constants.CLASS); |
||||||
|
exclusionSet.add("taskJson"); |
||||||
|
List<TaskInstance> taskInstanceList = taskInstanceIPage.getRecords(); |
||||||
|
|
||||||
|
for (TaskInstance taskInstance : taskInstanceList) { |
||||||
|
taskInstance.setDuration(DateUtils.format2Duration(taskInstance.getStartTime(), taskInstance.getEndTime())); |
||||||
|
User executor = usersService.queryUser(taskInstance.getExecutorId()); |
||||||
|
if (null != executor) { |
||||||
|
taskInstance.setExecutorName(executor.getUserName()); |
||||||
|
} |
||||||
|
} |
||||||
|
pageInfo.setTotalCount((int) taskInstanceIPage.getTotal()); |
||||||
|
pageInfo.setLists(CollectionUtils.getListByExclusion(taskInstanceIPage.getRecords(), exclusionSet)); |
||||||
|
result.put(Constants.DATA_LIST, pageInfo); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* change one task instance's state from failure to forced success |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param projectName project name |
||||||
|
* @param taskInstanceId task instance id |
||||||
|
* @return the result code and msg |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> forceTaskSuccess(User loginUser, String projectName, Integer taskInstanceId) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
Project project = projectMapper.queryByName(projectName); |
||||||
|
|
||||||
|
// check user auth
|
||||||
|
Map<String, Object> checkResult = projectService.checkProjectAndAuth(loginUser, project, projectName); |
||||||
|
Status status = (Status) checkResult.get(Constants.STATUS); |
||||||
|
if (status != Status.SUCCESS) { |
||||||
|
return checkResult; |
||||||
|
} |
||||||
|
|
||||||
|
// check whether the task instance can be found
|
||||||
|
TaskInstance task = taskInstanceMapper.selectById(taskInstanceId); |
||||||
|
if (task == null) { |
||||||
|
putMsg(result, Status.TASK_INSTANCE_NOT_FOUND); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
// check whether the task instance state type is failure
|
||||||
|
if (!task.getState().typeIsFailure()) { |
||||||
|
putMsg(result, Status.TASK_INSTANCE_STATE_OPERATION_ERROR, taskInstanceId, task.getState().toString()); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
// change the state of the task instance
|
||||||
|
task.setState(ExecutionStatus.FORCED_SUCCESS); |
||||||
|
int changedNum = taskInstanceMapper.updateById(task); |
||||||
|
if (changedNum > 0) { |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
} else { |
||||||
|
putMsg(result, Status.FORCE_TASK_SUCCESS_ERROR); |
||||||
|
} |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/*** |
||||||
|
* generate {@link org.apache.dolphinscheduler.api.enums.Status#REQUEST_PARAMS_NOT_VALID_ERROR} res with param name |
||||||
|
* @param result exist result map |
||||||
|
* @param params invalid params name |
||||||
|
* @return update result map |
||||||
|
*/ |
||||||
|
private Map<String, Object> generateInvalidParamRes(Map<String, Object> result, String params) { |
||||||
|
result.put(Constants.STATUS, Status.REQUEST_PARAMS_NOT_VALID_ERROR); |
||||||
|
result.put(Constants.MSG, MessageFormat.format(Status.REQUEST_PARAMS_NOT_VALID_ERROR.getMsg(), params)); |
||||||
|
return result; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,86 @@ |
|||||||
|
/* |
||||||
|
* 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.api.service.impl; |
||||||
|
|
||||||
|
import static org.apache.dolphinscheduler.common.Constants.TASK_RECORD_TABLE_HISTORY_HIVE_LOG; |
||||||
|
import static org.apache.dolphinscheduler.common.Constants.TASK_RECORD_TABLE_HIVE_LOG; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.api.enums.Status; |
||||||
|
import org.apache.dolphinscheduler.api.service.TaskRecordService; |
||||||
|
import org.apache.dolphinscheduler.api.utils.PageInfo; |
||||||
|
import org.apache.dolphinscheduler.common.Constants; |
||||||
|
import org.apache.dolphinscheduler.dao.TaskRecordDao; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.TaskRecord; |
||||||
|
|
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
|
||||||
|
/** |
||||||
|
* task record service impl |
||||||
|
*/ |
||||||
|
@Service |
||||||
|
public class TaskRecordServiceImpl extends BaseServiceImpl implements TaskRecordService { |
||||||
|
|
||||||
|
/** |
||||||
|
* query task record list paging |
||||||
|
* |
||||||
|
* @param taskName task name |
||||||
|
* @param state state |
||||||
|
* @param sourceTable source table |
||||||
|
* @param destTable destination table |
||||||
|
* @param taskDate task date |
||||||
|
* @param startDate start time |
||||||
|
* @param endDate end time |
||||||
|
* @param pageNo page numbere |
||||||
|
* @param pageSize page size |
||||||
|
* @param isHistory is history |
||||||
|
* @return task record list |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String,Object> queryTaskRecordListPaging(boolean isHistory, String taskName, String startDate, |
||||||
|
String taskDate, String sourceTable, |
||||||
|
String destTable, String endDate, |
||||||
|
String state, Integer pageNo, Integer pageSize) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
PageInfo<TaskRecord> pageInfo = new PageInfo<>(pageNo, pageSize); |
||||||
|
|
||||||
|
Map<String, String> map = new HashMap<>(); |
||||||
|
map.put("taskName", taskName); |
||||||
|
map.put("taskDate", taskDate); |
||||||
|
map.put("state", state); |
||||||
|
map.put("sourceTable", sourceTable); |
||||||
|
map.put("targetTable", destTable); |
||||||
|
map.put("startTime", startDate); |
||||||
|
map.put("endTime", endDate); |
||||||
|
map.put("offset", pageInfo.getStart().toString()); |
||||||
|
map.put("pageSize", pageInfo.getPageSize().toString()); |
||||||
|
|
||||||
|
String table = isHistory ? TASK_RECORD_TABLE_HISTORY_HIVE_LOG : TASK_RECORD_TABLE_HIVE_LOG; |
||||||
|
int count = TaskRecordDao.countTaskRecord(map, table); |
||||||
|
List<TaskRecord> recordList = TaskRecordDao.queryAllTaskRecord(map, table); |
||||||
|
pageInfo.setTotalCount(count); |
||||||
|
pageInfo.setLists(recordList); |
||||||
|
result.put(Constants.DATA_LIST, pageInfo); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
|
||||||
|
return result; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,332 @@ |
|||||||
|
/* |
||||||
|
* 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.api.service.impl; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.api.enums.Status; |
||||||
|
import org.apache.dolphinscheduler.api.service.UdfFuncService; |
||||||
|
import org.apache.dolphinscheduler.api.utils.PageInfo; |
||||||
|
import org.apache.dolphinscheduler.api.utils.Result; |
||||||
|
import org.apache.dolphinscheduler.common.Constants; |
||||||
|
import org.apache.dolphinscheduler.common.enums.UdfType; |
||||||
|
import org.apache.dolphinscheduler.common.utils.PropertyUtils; |
||||||
|
import org.apache.dolphinscheduler.common.utils.StringUtils; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.Resource; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.UdfFunc; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.User; |
||||||
|
import org.apache.dolphinscheduler.dao.mapper.ResourceMapper; |
||||||
|
import org.apache.dolphinscheduler.dao.mapper.UDFUserMapper; |
||||||
|
import org.apache.dolphinscheduler.dao.mapper.UdfFuncMapper; |
||||||
|
|
||||||
|
import java.util.Date; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import org.slf4j.Logger; |
||||||
|
import org.slf4j.LoggerFactory; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
import org.springframework.transaction.annotation.Transactional; |
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage; |
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||||
|
|
||||||
|
/** |
||||||
|
* udf func service impl |
||||||
|
*/ |
||||||
|
@Service |
||||||
|
public class UdfFuncServiceImpl extends BaseServiceImpl implements UdfFuncService { |
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(UdfFuncServiceImpl.class); |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private ResourceMapper resourceMapper; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private UdfFuncMapper udfFuncMapper; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private UDFUserMapper udfUserMapper; |
||||||
|
|
||||||
|
/** |
||||||
|
* create udf function |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param type udf type |
||||||
|
* @param funcName function name |
||||||
|
* @param argTypes argument types |
||||||
|
* @param database database |
||||||
|
* @param desc description |
||||||
|
* @param resourceId resource id |
||||||
|
* @param className class name |
||||||
|
* @return create result code |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Result<Object> createUdfFunction(User loginUser, |
||||||
|
String funcName, |
||||||
|
String className, |
||||||
|
String argTypes, |
||||||
|
String database, |
||||||
|
String desc, |
||||||
|
UdfType type, |
||||||
|
int resourceId) { |
||||||
|
Result<Object> result = new Result<>(); |
||||||
|
|
||||||
|
// if resource upload startup
|
||||||
|
if (!PropertyUtils.getResUploadStartupState()) { |
||||||
|
logger.error("resource upload startup state: {}", PropertyUtils.getResUploadStartupState()); |
||||||
|
putMsg(result, Status.HDFS_NOT_STARTUP); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
// verify udf func name exist
|
||||||
|
if (checkUdfFuncNameExists(funcName)) { |
||||||
|
putMsg(result, Status.UDF_FUNCTION_EXISTS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
Resource resource = resourceMapper.selectById(resourceId); |
||||||
|
if (resource == null) { |
||||||
|
logger.error("resourceId {} is not exist", resourceId); |
||||||
|
putMsg(result, Status.RESOURCE_NOT_EXIST); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
//save data
|
||||||
|
UdfFunc udf = new UdfFunc(); |
||||||
|
Date now = new Date(); |
||||||
|
udf.setUserId(loginUser.getId()); |
||||||
|
udf.setFuncName(funcName); |
||||||
|
udf.setClassName(className); |
||||||
|
if (StringUtils.isNotEmpty(argTypes)) { |
||||||
|
udf.setArgTypes(argTypes); |
||||||
|
} |
||||||
|
if (StringUtils.isNotEmpty(database)) { |
||||||
|
udf.setDatabase(database); |
||||||
|
} |
||||||
|
udf.setDescription(desc); |
||||||
|
udf.setResourceId(resourceId); |
||||||
|
udf.setResourceName(resource.getFullName()); |
||||||
|
udf.setType(type); |
||||||
|
|
||||||
|
udf.setCreateTime(now); |
||||||
|
udf.setUpdateTime(now); |
||||||
|
|
||||||
|
udfFuncMapper.insert(udf); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @param name name |
||||||
|
* @return check result code |
||||||
|
*/ |
||||||
|
private boolean checkUdfFuncNameExists(String name) { |
||||||
|
List<UdfFunc> resource = udfFuncMapper.queryUdfByIdStr(null, name); |
||||||
|
return resource != null && !resource.isEmpty(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* query udf function |
||||||
|
* |
||||||
|
* @param id udf function id |
||||||
|
* @return udf function detail |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> queryUdfFuncDetail(int id) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
UdfFunc udfFunc = udfFuncMapper.selectById(id); |
||||||
|
if (udfFunc == null) { |
||||||
|
putMsg(result, Status.RESOURCE_NOT_EXIST); |
||||||
|
return result; |
||||||
|
} |
||||||
|
result.put(Constants.DATA_LIST, udfFunc); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* updateProcessInstance udf function |
||||||
|
* |
||||||
|
* @param udfFuncId udf function id |
||||||
|
* @param type resource type |
||||||
|
* @param funcName function name |
||||||
|
* @param argTypes argument types |
||||||
|
* @param database data base |
||||||
|
* @param desc description |
||||||
|
* @param resourceId resource id |
||||||
|
* @param className class name |
||||||
|
* @return update result code |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> updateUdfFunc(int udfFuncId, |
||||||
|
String funcName, |
||||||
|
String className, |
||||||
|
String argTypes, |
||||||
|
String database, |
||||||
|
String desc, |
||||||
|
UdfType type, |
||||||
|
int resourceId) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
// verify udfFunc is exist
|
||||||
|
UdfFunc udf = udfFuncMapper.selectUdfById(udfFuncId); |
||||||
|
|
||||||
|
if (udf == null) { |
||||||
|
result.put(Constants.STATUS, Status.UDF_FUNCTION_NOT_EXIST); |
||||||
|
result.put(Constants.MSG, Status.UDF_FUNCTION_NOT_EXIST.getMsg()); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
// if resource upload startup
|
||||||
|
if (!PropertyUtils.getResUploadStartupState()) { |
||||||
|
logger.error("resource upload startup state: {}", PropertyUtils.getResUploadStartupState()); |
||||||
|
putMsg(result, Status.HDFS_NOT_STARTUP); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
// verify udfFuncName is exist
|
||||||
|
if (!funcName.equals(udf.getFuncName())) { |
||||||
|
if (checkUdfFuncNameExists(funcName)) { |
||||||
|
logger.error("UdfFunc {} has exist, can't create again.", funcName); |
||||||
|
result.put(Constants.STATUS, Status.UDF_FUNCTION_EXISTS); |
||||||
|
result.put(Constants.MSG, Status.UDF_FUNCTION_EXISTS.getMsg()); |
||||||
|
return result; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Resource resource = resourceMapper.selectById(resourceId); |
||||||
|
if (resource == null) { |
||||||
|
logger.error("resourceId {} is not exist", resourceId); |
||||||
|
result.put(Constants.STATUS, Status.RESOURCE_NOT_EXIST); |
||||||
|
result.put(Constants.MSG, Status.RESOURCE_NOT_EXIST.getMsg()); |
||||||
|
return result; |
||||||
|
} |
||||||
|
Date now = new Date(); |
||||||
|
udf.setFuncName(funcName); |
||||||
|
udf.setClassName(className); |
||||||
|
udf.setArgTypes(argTypes); |
||||||
|
if (StringUtils.isNotEmpty(database)) { |
||||||
|
udf.setDatabase(database); |
||||||
|
} |
||||||
|
udf.setDescription(desc); |
||||||
|
udf.setResourceId(resourceId); |
||||||
|
udf.setResourceName(resource.getFullName()); |
||||||
|
udf.setType(type); |
||||||
|
|
||||||
|
udf.setUpdateTime(now); |
||||||
|
|
||||||
|
udfFuncMapper.updateById(udf); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* query udf function list paging |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param pageNo page number |
||||||
|
* @param pageSize page size |
||||||
|
* @param searchVal search value |
||||||
|
* @return udf function list page |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> queryUdfFuncListPaging(User loginUser, String searchVal, Integer pageNo, Integer pageSize) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
PageInfo<UdfFunc> pageInfo = new PageInfo<>(pageNo, pageSize); |
||||||
|
IPage<UdfFunc> udfFuncList = getUdfFuncsPage(loginUser, searchVal, pageSize, pageNo); |
||||||
|
pageInfo.setTotalCount((int)udfFuncList.getTotal()); |
||||||
|
pageInfo.setLists(udfFuncList.getRecords()); |
||||||
|
result.put(Constants.DATA_LIST, pageInfo); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* get udf functions |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param searchVal search value |
||||||
|
* @param pageSize page size |
||||||
|
* @param pageNo page number |
||||||
|
* @return udf function list page |
||||||
|
*/ |
||||||
|
private IPage<UdfFunc> getUdfFuncsPage(User loginUser, String searchVal, Integer pageSize, int pageNo) { |
||||||
|
int userId = loginUser.getId(); |
||||||
|
if (isAdmin(loginUser)) { |
||||||
|
userId = 0; |
||||||
|
} |
||||||
|
Page<UdfFunc> page = new Page<>(pageNo, pageSize); |
||||||
|
return udfFuncMapper.queryUdfFuncPaging(page, userId, searchVal); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* query udf list |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param type udf type |
||||||
|
* @return udf func list |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> queryUdfFuncList(User loginUser, Integer type) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
int userId = loginUser.getId(); |
||||||
|
if (isAdmin(loginUser)) { |
||||||
|
userId = 0; |
||||||
|
} |
||||||
|
List<UdfFunc> udfFuncList = udfFuncMapper.getUdfFuncByType(userId, type); |
||||||
|
|
||||||
|
result.put(Constants.DATA_LIST, udfFuncList); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* delete udf function |
||||||
|
* |
||||||
|
* @param id udf function id |
||||||
|
* @return delete result code |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
@Transactional(rollbackFor = RuntimeException.class) |
||||||
|
public Result<Object> delete(int id) { |
||||||
|
Result<Object> result = new Result<>(); |
||||||
|
udfFuncMapper.deleteById(id); |
||||||
|
udfUserMapper.deleteByUdfFuncId(id); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* verify udf function by name |
||||||
|
* |
||||||
|
* @param name name |
||||||
|
* @return true if the name can user, otherwise return false |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Result<Object> verifyUdfFuncByName(String name) { |
||||||
|
Result<Object> result = new Result<>(); |
||||||
|
if (checkUdfFuncNameExists(name)) { |
||||||
|
putMsg(result, Status.UDF_FUNCTION_EXISTS); |
||||||
|
} else { |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,110 @@ |
|||||||
|
/* |
||||||
|
* 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.api.service.impl; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.api.enums.Status; |
||||||
|
import org.apache.dolphinscheduler.api.service.WorkFlowLineageService; |
||||||
|
import org.apache.dolphinscheduler.common.Constants; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.WorkFlowLineage; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.WorkFlowRelation; |
||||||
|
import org.apache.dolphinscheduler.dao.mapper.WorkFlowLineageMapper; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.HashSet; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
|
||||||
|
/** |
||||||
|
* work flow lineage service impl |
||||||
|
*/ |
||||||
|
@Service |
||||||
|
public class WorkFlowLineageServiceImpl extends BaseServiceImpl implements WorkFlowLineageService { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private WorkFlowLineageMapper workFlowLineageMapper; |
||||||
|
|
||||||
|
@Override |
||||||
|
public Map<String, Object> queryWorkFlowLineageByName(String workFlowName, int projectId) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
List<WorkFlowLineage> workFlowLineageList = workFlowLineageMapper.queryByName(workFlowName, projectId); |
||||||
|
result.put(Constants.DATA_LIST, workFlowLineageList); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
private void getWorkFlowRelationRecursion(Set<Integer> ids, List<WorkFlowRelation> workFlowRelations, Set<Integer> sourceIds) { |
||||||
|
for (int id : ids) { |
||||||
|
sourceIds.addAll(ids); |
||||||
|
List<WorkFlowRelation> workFlowRelationsTmp = workFlowLineageMapper.querySourceTarget(id); |
||||||
|
if (workFlowRelationsTmp != null && !workFlowRelationsTmp.isEmpty()) { |
||||||
|
Set<Integer> idsTmp = new HashSet<>(); |
||||||
|
for (WorkFlowRelation workFlowRelation:workFlowRelationsTmp) { |
||||||
|
if (!sourceIds.contains(workFlowRelation.getTargetWorkFlowId())) { |
||||||
|
idsTmp.add(workFlowRelation.getTargetWorkFlowId()); |
||||||
|
} |
||||||
|
} |
||||||
|
workFlowRelations.addAll(workFlowRelationsTmp); |
||||||
|
getWorkFlowRelationRecursion(idsTmp, workFlowRelations,sourceIds); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Map<String, Object> queryWorkFlowLineageByIds(Set<Integer> ids, int projectId) { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
List<WorkFlowLineage> workFlowLineageList = workFlowLineageMapper.queryByIds(ids, projectId); |
||||||
|
Map<String, Object> workFlowLists = new HashMap<>(); |
||||||
|
Set<Integer> idsV = new HashSet<>(); |
||||||
|
if (ids == null || ids.isEmpty()) { |
||||||
|
for (WorkFlowLineage workFlowLineage:workFlowLineageList) { |
||||||
|
idsV.add(workFlowLineage.getWorkFlowId()); |
||||||
|
} |
||||||
|
} else { |
||||||
|
idsV = ids; |
||||||
|
} |
||||||
|
List<WorkFlowRelation> workFlowRelations = new ArrayList<>(); |
||||||
|
Set<Integer> sourceIds = new HashSet<>(); |
||||||
|
getWorkFlowRelationRecursion(idsV, workFlowRelations, sourceIds); |
||||||
|
|
||||||
|
Set<Integer> idSet = new HashSet<>(); |
||||||
|
//If the incoming parameter is not empty, you need to add downstream workflow detail attributes
|
||||||
|
if (ids != null && !ids.isEmpty()) { |
||||||
|
for (WorkFlowRelation workFlowRelation : workFlowRelations) { |
||||||
|
idSet.add(workFlowRelation.getTargetWorkFlowId()); |
||||||
|
} |
||||||
|
for (int id : ids) { |
||||||
|
idSet.remove(id); |
||||||
|
} |
||||||
|
if (!idSet.isEmpty()) { |
||||||
|
workFlowLineageList.addAll(workFlowLineageMapper.queryByIds(idSet, projectId)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
workFlowLists.put(Constants.WORKFLOW_LIST, workFlowLineageList); |
||||||
|
workFlowLists.put(Constants.WORKFLOW_RELATION_LIST, workFlowRelations); |
||||||
|
result.put(Constants.DATA_LIST, workFlowLists); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,181 @@ |
|||||||
|
/* |
||||||
|
* 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.api.service.impl; |
||||||
|
|
||||||
|
import static org.apache.dolphinscheduler.common.Constants.DEFAULT_WORKER_GROUP; |
||||||
|
|
||||||
|
import org.apache.dolphinscheduler.api.enums.Status; |
||||||
|
import org.apache.dolphinscheduler.api.service.WorkerGroupService; |
||||||
|
import org.apache.dolphinscheduler.api.utils.PageInfo; |
||||||
|
import org.apache.dolphinscheduler.common.Constants; |
||||||
|
import org.apache.dolphinscheduler.common.utils.CollectionUtils; |
||||||
|
import org.apache.dolphinscheduler.common.utils.DateUtils; |
||||||
|
import org.apache.dolphinscheduler.common.utils.StringUtils; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.User; |
||||||
|
import org.apache.dolphinscheduler.dao.entity.WorkerGroup; |
||||||
|
import org.apache.dolphinscheduler.dao.mapper.ProcessInstanceMapper; |
||||||
|
import org.apache.dolphinscheduler.service.zk.ZookeeperCachedOperator; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Set; |
||||||
|
import java.util.stream.Collectors; |
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* worker group service impl |
||||||
|
*/ |
||||||
|
@Service |
||||||
|
public class WorkerGroupServiceImpl extends BaseServiceImpl implements WorkerGroupService { |
||||||
|
|
||||||
|
private static final String NO_NODE_EXCEPTION_REGEX = "KeeperException$NoNodeException"; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
protected ZookeeperCachedOperator zookeeperCachedOperator; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
ProcessInstanceMapper processInstanceMapper; |
||||||
|
|
||||||
|
/** |
||||||
|
* query worker group paging |
||||||
|
* |
||||||
|
* @param loginUser login user |
||||||
|
* @param pageNo page number |
||||||
|
* @param searchVal search value |
||||||
|
* @param pageSize page size |
||||||
|
* @return worker group list page |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> queryAllGroupPaging(User loginUser, Integer pageNo, Integer pageSize, String searchVal) { |
||||||
|
// list from index
|
||||||
|
int fromIndex = (pageNo - 1) * pageSize; |
||||||
|
// list to index
|
||||||
|
int toIndex = (pageNo - 1) * pageSize + pageSize; |
||||||
|
|
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
if (isNotAdmin(loginUser, result)) { |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
List<WorkerGroup> workerGroups = getWorkerGroups(true); |
||||||
|
|
||||||
|
List<WorkerGroup> resultDataList = new ArrayList<>(); |
||||||
|
|
||||||
|
if (CollectionUtils.isNotEmpty(workerGroups)) { |
||||||
|
List<WorkerGroup> searchValDataList = new ArrayList<>(); |
||||||
|
|
||||||
|
if (StringUtils.isNotEmpty(searchVal)) { |
||||||
|
for (WorkerGroup workerGroup : workerGroups) { |
||||||
|
if (workerGroup.getName().contains(searchVal)) { |
||||||
|
searchValDataList.add(workerGroup); |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
searchValDataList = workerGroups; |
||||||
|
} |
||||||
|
|
||||||
|
if (searchValDataList.size() < pageSize) { |
||||||
|
toIndex = (pageNo - 1) * pageSize + searchValDataList.size(); |
||||||
|
} |
||||||
|
resultDataList = searchValDataList.subList(fromIndex, toIndex); |
||||||
|
} |
||||||
|
|
||||||
|
PageInfo<WorkerGroup> pageInfo = new PageInfo<>(pageNo, pageSize); |
||||||
|
pageInfo.setTotalCount(resultDataList.size()); |
||||||
|
pageInfo.setLists(resultDataList); |
||||||
|
|
||||||
|
result.put(Constants.DATA_LIST, pageInfo); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* query all worker group |
||||||
|
* |
||||||
|
* @return all worker group list |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public Map<String, Object> queryAllGroup() { |
||||||
|
Map<String, Object> result = new HashMap<>(); |
||||||
|
|
||||||
|
List<WorkerGroup> workerGroups = getWorkerGroups(false); |
||||||
|
|
||||||
|
Set<String> availableWorkerGroupSet = workerGroups.stream() |
||||||
|
.map(WorkerGroup::getName) |
||||||
|
.collect(Collectors.toSet()); |
||||||
|
result.put(Constants.DATA_LIST, availableWorkerGroupSet); |
||||||
|
putMsg(result, Status.SUCCESS); |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* get worker groups |
||||||
|
* |
||||||
|
* @param isPaging whether paging |
||||||
|
* @return WorkerGroup list |
||||||
|
*/ |
||||||
|
private List<WorkerGroup> getWorkerGroups(boolean isPaging) { |
||||||
|
String workerPath = zookeeperCachedOperator.getZookeeperConfig().getDsRoot() + Constants.ZOOKEEPER_DOLPHINSCHEDULER_WORKERS; |
||||||
|
List<WorkerGroup> workerGroups = new ArrayList<>(); |
||||||
|
List<String> workerGroupList; |
||||||
|
try { |
||||||
|
workerGroupList = zookeeperCachedOperator.getChildrenKeys(workerPath); |
||||||
|
} catch (Exception e) { |
||||||
|
if (e.getMessage().contains(NO_NODE_EXCEPTION_REGEX)) { |
||||||
|
if (!isPaging) { |
||||||
|
//ignore noNodeException return Default
|
||||||
|
WorkerGroup wg = new WorkerGroup(); |
||||||
|
wg.setName(DEFAULT_WORKER_GROUP); |
||||||
|
workerGroups.add(wg); |
||||||
|
} |
||||||
|
return workerGroups; |
||||||
|
} else { |
||||||
|
throw e; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
for (String workerGroup : workerGroupList) { |
||||||
|
String workerGroupPath = String.format("%s/%s", workerPath, workerGroup); |
||||||
|
List<String> childrenNodes = zookeeperCachedOperator.getChildrenKeys(workerGroupPath); |
||||||
|
String timeStamp = ""; |
||||||
|
for (int i = 0; i < childrenNodes.size(); i++) { |
||||||
|
String ip = childrenNodes.get(i); |
||||||
|
childrenNodes.set(i, ip.substring(0, ip.lastIndexOf(":"))); |
||||||
|
timeStamp = ip.substring(ip.lastIndexOf(":")); |
||||||
|
} |
||||||
|
if (CollectionUtils.isNotEmpty(childrenNodes)) { |
||||||
|
WorkerGroup wg = new WorkerGroup(); |
||||||
|
wg.setName(workerGroup); |
||||||
|
if (isPaging) { |
||||||
|
wg.setIpList(childrenNodes); |
||||||
|
String registeredIpValue = zookeeperCachedOperator.get(workerGroupPath + "/" + childrenNodes.get(0) + timeStamp); |
||||||
|
wg.setCreateTime(DateUtils.stringToDate(registeredIpValue.split(",")[6])); |
||||||
|
wg.setUpdateTime(DateUtils.stringToDate(registeredIpValue.split(",")[7])); |
||||||
|
} |
||||||
|
workerGroups.add(wg); |
||||||
|
} |
||||||
|
} |
||||||
|
return workerGroups; |
||||||
|
} |
||||||
|
|
||||||
|
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue