Kerwin
3 years ago
committed by
GitHub
72 changed files with 6464 additions and 235 deletions
@ -0,0 +1,100 @@
|
||||
package org.apache.dolphinscheduler.server.worker.plugin;/* |
||||
* 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. |
||||
*/ |
||||
|
||||
import static java.lang.String.format; |
||||
import static java.util.Objects.requireNonNull; |
||||
|
||||
import static com.google.common.base.Preconditions.checkState; |
||||
|
||||
import org.apache.dolphinscheduler.common.enums.PluginType; |
||||
import org.apache.dolphinscheduler.dao.DaoFactory; |
||||
import org.apache.dolphinscheduler.dao.PluginDao; |
||||
import org.apache.dolphinscheduler.dao.entity.PluginDefine; |
||||
import org.apache.dolphinscheduler.spi.DolphinSchedulerPlugin; |
||||
import org.apache.dolphinscheduler.spi.classloader.ThreadContextClassLoader; |
||||
import org.apache.dolphinscheduler.spi.params.PluginParamsTransfer; |
||||
import org.apache.dolphinscheduler.spi.params.base.PluginParams; |
||||
import org.apache.dolphinscheduler.spi.plugin.AbstractDolphinPluginManager; |
||||
import org.apache.dolphinscheduler.spi.task.TaskChannel; |
||||
import org.apache.dolphinscheduler.spi.task.TaskChannelFactory; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
|
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
public class TaskPluginManager extends AbstractDolphinPluginManager { |
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(TaskPluginManager.class); |
||||
|
||||
private final Map<String, TaskChannelFactory> taskChannelFactoryMap = new ConcurrentHashMap<>(); |
||||
private final Map<String, TaskChannel> taskChannelMap = new ConcurrentHashMap<>(); |
||||
|
||||
/** |
||||
* k->pluginDefineId v->pluginDefineName |
||||
*/ |
||||
private final Map<Integer, String> pluginDefineMap = new HashMap<>(); |
||||
|
||||
private void addTaskChannelFactory(TaskChannelFactory taskChannelFactory) { |
||||
requireNonNull(taskChannelFactory, "taskChannelFactory is null"); |
||||
|
||||
if (taskChannelFactoryMap.putIfAbsent(taskChannelFactory.getName(), taskChannelFactory) != null) { |
||||
throw new IllegalArgumentException(format("Task Plugin '%s' is already registered", taskChannelFactory.getName())); |
||||
} |
||||
|
||||
try { |
||||
loadTaskChannel(taskChannelFactory.getName()); |
||||
} catch (Exception e) { |
||||
throw new IllegalArgumentException(format("Task Plugin '%s' is can not load .", taskChannelFactory.getName())); |
||||
} |
||||
} |
||||
|
||||
private void loadTaskChannel(String name) { |
||||
requireNonNull(name, "name is null"); |
||||
|
||||
TaskChannelFactory taskChannelFactory = taskChannelFactoryMap.get(name); |
||||
checkState(taskChannelFactory != null, "Task Plugin {} is not registered", name); |
||||
|
||||
try (ThreadContextClassLoader ignored = new ThreadContextClassLoader(taskChannelFactory.getClass().getClassLoader())) { |
||||
TaskChannel taskChannel = taskChannelFactory.create(); |
||||
this.taskChannelMap.put(name, taskChannel); |
||||
} |
||||
|
||||
logger.info("-- Loaded Task Plugin {} --", name); |
||||
} |
||||
|
||||
|
||||
private PluginDao pluginDao = DaoFactory.getDaoInstance(PluginDao.class); |
||||
|
||||
@Override |
||||
public void installPlugin(DolphinSchedulerPlugin dolphinSchedulerPlugin) { |
||||
for (TaskChannelFactory taskChannelFactory : dolphinSchedulerPlugin.getTaskChannelFactorys()) { |
||||
logger.info("Registering Task Plugin '{}'", taskChannelFactory.getName()); |
||||
this.addTaskChannelFactory(taskChannelFactory); |
||||
List<PluginParams> params = taskChannelFactory.getParams(); |
||||
String nameEn = taskChannelFactory.getName(); |
||||
String paramsJson = PluginParamsTransfer.transferParamsToJson(params); |
||||
|
||||
PluginDefine pluginDefine = new PluginDefine(nameEn, PluginType.TASK.getDesc(), paramsJson); |
||||
int id = pluginDao.addOrUpdatePluginDefine(pluginDefine); |
||||
pluginDefineMap.put(id, pluginDefine.getPluginName()); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,41 @@
|
||||
package org.apache.dolphinscheduler.spi.common;/* |
||||
* 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. |
||||
*/ |
||||
|
||||
import org.apache.dolphinscheduler.spi.params.base.PluginParams; |
||||
|
||||
import java.util.List; |
||||
|
||||
public interface UiChannelFactory { |
||||
|
||||
/** |
||||
* plugin name |
||||
* Must be UNIQUE . |
||||
* This alert plugin name eg: email , message ... |
||||
* Name can often be displayed on the page ui eg : email , message , MR , spark , hive ... |
||||
* |
||||
* @return this alert plugin name |
||||
*/ |
||||
String getName(); |
||||
|
||||
/** |
||||
* Returns the configurable parameters that this plugin needs to display on the web ui |
||||
* |
||||
* @return this alert plugin params |
||||
*/ |
||||
List<PluginParams> getParams(); |
||||
|
||||
} |
@ -0,0 +1,60 @@
|
||||
package org.apache.dolphinscheduler.spi.task;/* |
||||
* 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. |
||||
*/ |
||||
|
||||
import java.util.LinkedHashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* job params related class
|
||||
*/ |
||||
public abstract class AbstractParameters implements IParameters { |
||||
|
||||
/** |
||||
* local parameters |
||||
*/ |
||||
private List<Property> localParams; |
||||
|
||||
/** |
||||
* get local parameters list |
||||
* @return Property list |
||||
*/ |
||||
public List<Property> getLocalParams() { |
||||
return localParams; |
||||
} |
||||
|
||||
public void setLocalParams(List<Property> localParams) { |
||||
this.localParams = localParams; |
||||
} |
||||
|
||||
/** |
||||
* get local parameters map |
||||
* @return parameters map |
||||
*/ |
||||
public Map<String, Property> getLocalParametersMap() { |
||||
if (localParams != null) { |
||||
Map<String, Property> localParametersMaps = new LinkedHashMap<>(); |
||||
|
||||
for (Property property : localParams) { |
||||
localParametersMaps.put(property.getProp(),property); |
||||
} |
||||
return localParametersMaps; |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,210 @@
|
||||
/* |
||||
* 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.spi.task; |
||||
|
||||
import java.util.List; |
||||
|
||||
import org.slf4j.Logger; |
||||
import org.slf4j.Marker; |
||||
import org.slf4j.MarkerFactory; |
||||
|
||||
/** |
||||
* executive task |
||||
*/ |
||||
public abstract class AbstractTask { |
||||
|
||||
public static final Marker FINALIZE_SESSION_MARKER = MarkerFactory.getMarker("FINALIZE_SESSION"); |
||||
|
||||
/** |
||||
* varPool string |
||||
*/ |
||||
protected String varPool; |
||||
|
||||
/** |
||||
* taskExecutionContext |
||||
**/ |
||||
TaskRequest taskRequest; |
||||
|
||||
/** |
||||
* log record |
||||
*/ |
||||
protected Logger logger; |
||||
|
||||
/** |
||||
* SHELL process pid |
||||
*/ |
||||
protected int processId; |
||||
|
||||
/** |
||||
* SHELL result string |
||||
*/ |
||||
protected String resultString; |
||||
|
||||
/** |
||||
* other resource manager appId , for example : YARN etc |
||||
*/ |
||||
protected String appIds; |
||||
|
||||
|
||||
/** |
||||
* cancel |
||||
*/ |
||||
protected volatile boolean cancel = false; |
||||
|
||||
/** |
||||
* exit code |
||||
*/ |
||||
protected volatile int exitStatusCode = -1; |
||||
|
||||
/** |
||||
* constructor |
||||
* |
||||
* @param taskExecutionContext taskExecutionContext |
||||
* @param logger logger |
||||
*/ |
||||
protected AbstractTask(TaskRequest taskExecutionContext, Logger logger) { |
||||
this.taskRequest = taskExecutionContext; |
||||
this.logger = logger; |
||||
} |
||||
|
||||
/** |
||||
* init task |
||||
*/ |
||||
public void init() { |
||||
} |
||||
|
||||
public String getPreScript() { |
||||
return null; |
||||
} |
||||
|
||||
public void setCommand(String command) throws Exception { |
||||
|
||||
} |
||||
|
||||
/** |
||||
* task handle |
||||
* |
||||
* @throws Exception exception |
||||
*/ |
||||
public abstract void handle() throws Exception; |
||||
|
||||
/** |
||||
* cancel application |
||||
* |
||||
* @param status status |
||||
* @throws Exception exception |
||||
*/ |
||||
public void cancelApplication(boolean status) throws Exception { |
||||
this.cancel = status; |
||||
} |
||||
|
||||
/** |
||||
* log handle |
||||
* |
||||
* @param logs log list |
||||
*/ |
||||
public void logHandle(List<String> logs) { |
||||
// note that the "new line" is added here to facilitate log parsing
|
||||
if (logs.contains(FINALIZE_SESSION_MARKER.toString())) { |
||||
logger.info(FINALIZE_SESSION_MARKER, FINALIZE_SESSION_MARKER.toString()); |
||||
} else { |
||||
logger.info(" -> {}", String.join("\n\t", logs)); |
||||
} |
||||
} |
||||
|
||||
public void setVarPool(String varPool) { |
||||
this.varPool = varPool; |
||||
} |
||||
|
||||
public String getVarPool() { |
||||
return varPool; |
||||
} |
||||
|
||||
/** |
||||
* get exit status code |
||||
* |
||||
* @return exit status code |
||||
*/ |
||||
public int getExitStatusCode() { |
||||
return exitStatusCode; |
||||
} |
||||
|
||||
public void setExitStatusCode(int exitStatusCode) { |
||||
this.exitStatusCode = exitStatusCode; |
||||
} |
||||
|
||||
public String getAppIds() { |
||||
return appIds; |
||||
} |
||||
|
||||
public void setAppIds(String appIds) { |
||||
this.appIds = appIds; |
||||
} |
||||
|
||||
public int getProcessId() { |
||||
return processId; |
||||
} |
||||
|
||||
public void setProcessId(int processId) { |
||||
this.processId = processId; |
||||
} |
||||
|
||||
public String getResultString() { |
||||
return resultString; |
||||
} |
||||
|
||||
public void setResultString(String resultString) { |
||||
this.resultString = resultString; |
||||
} |
||||
|
||||
/** |
||||
* get task parameters |
||||
* |
||||
* @return AbstractParameters |
||||
*/ |
||||
public abstract AbstractParameters getParameters(); |
||||
|
||||
/** |
||||
* result processing maybe |
||||
*/ |
||||
public void after() { |
||||
|
||||
} |
||||
|
||||
/** |
||||
* get exit status according to exitCode |
||||
* |
||||
* @return exit status |
||||
*/ |
||||
public ExecutionStatus getExitStatus() { |
||||
ExecutionStatus status; |
||||
switch (getExitStatusCode()) { |
||||
case TaskConstants.EXIT_CODE_SUCCESS: |
||||
status = ExecutionStatus.SUCCESS; |
||||
break; |
||||
case TaskConstants.EXIT_CODE_KILL: |
||||
status = ExecutionStatus.KILL; |
||||
break; |
||||
default: |
||||
status = ExecutionStatus.FAILURE; |
||||
break; |
||||
} |
||||
return status; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,28 @@
|
||||
/* |
||||
* 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.spi.task; |
||||
|
||||
/** |
||||
* parameter of stored procedure |
||||
*/ |
||||
public enum Direct { |
||||
/** |
||||
* 0 in; 1 out; |
||||
*/ |
||||
IN,OUT |
||||
} |
@ -0,0 +1,162 @@
|
||||
/* |
||||
* 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.spi.task; |
||||
|
||||
import java.util.HashMap; |
||||
|
||||
/** |
||||
* running status for workflow and task nodes |
||||
*/ |
||||
public enum ExecutionStatus { |
||||
|
||||
/** |
||||
* status: |
||||
* 0 submit success |
||||
* 1 running |
||||
* 2 ready pause |
||||
* 3 pause |
||||
* 4 ready stop |
||||
* 5 stop |
||||
* 6 failure |
||||
* 7 success |
||||
* 8 need fault tolerance |
||||
* 9 kill |
||||
* 10 waiting thread |
||||
* 11 waiting depend node complete |
||||
* 12 delay execution |
||||
* 13 forced success |
||||
*/ |
||||
SUBMITTED_SUCCESS(0, "submit success"), |
||||
RUNNING_EXECUTION(1, "running"), |
||||
READY_PAUSE(2, "ready pause"), |
||||
PAUSE(3, "pause"), |
||||
READY_STOP(4, "ready stop"), |
||||
STOP(5, "stop"), |
||||
FAILURE(6, "failure"), |
||||
SUCCESS(7, "success"), |
||||
NEED_FAULT_TOLERANCE(8, "need fault tolerance"), |
||||
KILL(9, "kill"), |
||||
WAITTING_THREAD(10, "waiting thread"), |
||||
WAITTING_DEPEND(11, "waiting depend node complete"), |
||||
DELAY_EXECUTION(12, "delay execution"), |
||||
FORCED_SUCCESS(13, "forced success"); |
||||
|
||||
ExecutionStatus(int code, String descp) { |
||||
this.code = code; |
||||
this.descp = descp; |
||||
} |
||||
|
||||
private final int code; |
||||
private final String descp; |
||||
|
||||
private static final HashMap<Integer, ExecutionStatus> EXECUTION_STATUS_MAP = new HashMap<>(); |
||||
|
||||
static { |
||||
for (ExecutionStatus executionStatus : ExecutionStatus.values()) { |
||||
EXECUTION_STATUS_MAP.put(executionStatus.code, executionStatus); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* status is success |
||||
* |
||||
* @return status |
||||
*/ |
||||
public boolean typeIsSuccess() { |
||||
return this == SUCCESS || this == FORCED_SUCCESS; |
||||
} |
||||
|
||||
/** |
||||
* status is failure |
||||
* |
||||
* @return status |
||||
*/ |
||||
public boolean typeIsFailure() { |
||||
return this == FAILURE || this == NEED_FAULT_TOLERANCE || this == KILL; |
||||
} |
||||
|
||||
/** |
||||
* status is finished |
||||
* |
||||
* @return status |
||||
*/ |
||||
public boolean typeIsFinished() { |
||||
return typeIsSuccess() || typeIsFailure() || typeIsCancel() || typeIsPause() |
||||
|| typeIsStop(); |
||||
} |
||||
|
||||
/** |
||||
* status is waiting thread |
||||
* |
||||
* @return status |
||||
*/ |
||||
public boolean typeIsWaitingThread() { |
||||
return this == WAITTING_THREAD; |
||||
} |
||||
|
||||
/** |
||||
* status is pause |
||||
* |
||||
* @return status |
||||
*/ |
||||
public boolean typeIsPause() { |
||||
return this == PAUSE; |
||||
} |
||||
|
||||
/** |
||||
* status is pause |
||||
* |
||||
* @return status |
||||
*/ |
||||
public boolean typeIsStop() { |
||||
return this == STOP; |
||||
} |
||||
|
||||
/** |
||||
* status is running |
||||
* |
||||
* @return status |
||||
*/ |
||||
public boolean typeIsRunning() { |
||||
return this == RUNNING_EXECUTION || this == WAITTING_DEPEND || this == DELAY_EXECUTION; |
||||
} |
||||
|
||||
/** |
||||
* status is cancel |
||||
* |
||||
* @return status |
||||
*/ |
||||
public boolean typeIsCancel() { |
||||
return this == KILL || this == STOP; |
||||
} |
||||
|
||||
public int getCode() { |
||||
return code; |
||||
} |
||||
|
||||
public String getDescp() { |
||||
return descp; |
||||
} |
||||
|
||||
public static ExecutionStatus of(int status) { |
||||
if (EXECUTION_STATUS_MAP.containsKey(status)) { |
||||
return EXECUTION_STATUS_MAP.get(status); |
||||
} |
||||
throw new IllegalArgumentException("invalid status : " + status); |
||||
} |
||||
} |
@ -0,0 +1,37 @@
|
||||
package org.apache.dolphinscheduler.spi.task;/* |
||||
* 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. |
||||
*/ |
||||
|
||||
import java.util.List; |
||||
|
||||
/** |
||||
* job params interface
|
||||
*/ |
||||
public interface IParameters { |
||||
/** |
||||
* check parameters is valid |
||||
* |
||||
* @return result |
||||
*/ |
||||
boolean checkParameters(); |
||||
|
||||
/** |
||||
* get project resource files list |
||||
* |
||||
* @return resource files list |
||||
*/ |
||||
List<ResourceInfo> getResourceFilesList(); |
||||
} |
@ -0,0 +1,142 @@
|
||||
/* |
||||
* 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.spi.task; |
||||
|
||||
import org.apache.dolphinscheduler.spi.params.base.DataType; |
||||
|
||||
import java.io.Serializable; |
||||
import java.util.Objects; |
||||
|
||||
public class Property implements Serializable { |
||||
|
||||
private static final long serialVersionUID = -4045513703397452451L; |
||||
/** |
||||
* key |
||||
*/ |
||||
private String prop; |
||||
|
||||
/** |
||||
* input/output |
||||
*/ |
||||
private Direct direct; |
||||
|
||||
/** |
||||
* data type |
||||
*/ |
||||
private DataType type; |
||||
|
||||
/** |
||||
* value |
||||
*/ |
||||
private String value; |
||||
|
||||
public Property() { |
||||
} |
||||
|
||||
public Property(String prop, Direct direct, DataType type, String value) { |
||||
this.prop = prop; |
||||
this.direct = direct; |
||||
this.type = type; |
||||
this.value = value; |
||||
} |
||||
|
||||
/** |
||||
* getter method |
||||
* |
||||
* @return the prop |
||||
* @see Property#prop |
||||
*/ |
||||
public String getProp() { |
||||
return prop; |
||||
} |
||||
|
||||
/** |
||||
* setter method |
||||
* |
||||
* @param prop the prop to set |
||||
* @see Property#prop |
||||
*/ |
||||
public void setProp(String prop) { |
||||
this.prop = prop; |
||||
} |
||||
|
||||
/** |
||||
* getter method |
||||
* |
||||
* @return the value |
||||
* @see Property#value |
||||
*/ |
||||
public String getValue() { |
||||
return value; |
||||
} |
||||
|
||||
/** |
||||
* setter method |
||||
* |
||||
* @param value the value to set |
||||
* @see Property#value |
||||
*/ |
||||
public void setValue(String value) { |
||||
this.value = value; |
||||
} |
||||
|
||||
public Direct getDirect() { |
||||
return direct; |
||||
} |
||||
|
||||
public void setDirect(Direct direct) { |
||||
this.direct = direct; |
||||
} |
||||
|
||||
public DataType getType() { |
||||
return type; |
||||
} |
||||
|
||||
public void setType(DataType type) { |
||||
this.type = type; |
||||
} |
||||
|
||||
@Override |
||||
public boolean equals(Object o) { |
||||
if (this == o) { |
||||
return true; |
||||
} |
||||
if (o == null || getClass() != o.getClass()) { |
||||
return false; |
||||
} |
||||
Property property = (Property) o; |
||||
return Objects.equals(prop, property.prop) |
||||
&& Objects.equals(value, property.value); |
||||
} |
||||
|
||||
@Override |
||||
public int hashCode() { |
||||
return Objects.hash(prop, value); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return "Property{" |
||||
+ "prop='" + prop + '\'' |
||||
+ ", direct=" + direct |
||||
+ ", type=" + type |
||||
+ ", value='" + value + '\'' |
||||
+ '}'; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,57 @@
|
||||
/* |
||||
* 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.spi.task; |
||||
|
||||
/** |
||||
* resource info |
||||
*/ |
||||
public class ResourceInfo { |
||||
/** |
||||
* res the name of the resource that was uploaded |
||||
*/ |
||||
private int id; |
||||
|
||||
private String resourceName; |
||||
|
||||
|
||||
private String res; |
||||
|
||||
public int getId() { |
||||
return id; |
||||
} |
||||
|
||||
public void setId(int id) { |
||||
this.id = id; |
||||
} |
||||
|
||||
public String getRes() { |
||||
return res; |
||||
} |
||||
|
||||
public void setRes(String res) { |
||||
this.res = res; |
||||
} |
||||
|
||||
public String getResourceName() { |
||||
return resourceName; |
||||
} |
||||
|
||||
public void setResourceName(String resourceName) { |
||||
this.resourceName = resourceName; |
||||
} |
||||
} |
@ -0,0 +1,26 @@
|
||||
package org.apache.dolphinscheduler.spi.task;/* |
||||
* 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. |
||||
*/ |
||||
|
||||
import org.slf4j.Logger; |
||||
|
||||
public interface TaskChannel { |
||||
|
||||
void cancelApplication(boolean status); |
||||
|
||||
AbstractTask createTask(TaskRequest taskRequest,Logger logger); |
||||
|
||||
} |
@ -0,0 +1,25 @@
|
||||
/* |
||||
* 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.spi.task; |
||||
|
||||
import org.apache.dolphinscheduler.spi.common.UiChannelFactory; |
||||
|
||||
public interface TaskChannelFactory extends UiChannelFactory { |
||||
|
||||
TaskChannel create(); |
||||
} |
@ -0,0 +1,78 @@
|
||||
/* |
||||
* 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.spi.task; |
||||
|
||||
public class TaskConstants { |
||||
|
||||
private TaskConstants() { |
||||
throw new IllegalStateException("Utility class"); |
||||
} |
||||
|
||||
public static final String APPLICATION_REGEX = "application_\\d+_\\d+"; |
||||
|
||||
/** |
||||
* string false |
||||
*/ |
||||
public static final String STRING_FALSE = "false"; |
||||
|
||||
/** |
||||
* exit code kill |
||||
*/ |
||||
public static final int EXIT_CODE_KILL = 137; |
||||
public static final String PID = "pid"; |
||||
|
||||
/** |
||||
* comma , |
||||
*/ |
||||
public static final String COMMA = ","; |
||||
|
||||
/** |
||||
* sleep time |
||||
*/ |
||||
public static final int SLEEP_TIME_MILLIS = 1000; |
||||
|
||||
/** |
||||
* exit code failure |
||||
*/ |
||||
public static final int EXIT_CODE_FAILURE = -1; |
||||
|
||||
/** |
||||
* exit code success |
||||
*/ |
||||
public static final int EXIT_CODE_SUCCESS = 0; |
||||
|
||||
public static final String SH = "sh"; |
||||
|
||||
/** |
||||
* default log cache rows num,output when reach the number |
||||
*/ |
||||
public static final int DEFAULT_LOG_ROWS_NUM = 4 * 16; |
||||
|
||||
/** |
||||
* log flush interval?output when reach the interval |
||||
*/ |
||||
public static final int DEFAULT_LOG_FLUSH_INTERVAL = 1000; |
||||
|
||||
/** |
||||
* pstree, get pud and sub pid |
||||
*/ |
||||
public static final String PSTREE = "pstree"; |
||||
|
||||
public static final String RWXR_XR_X = "rwxr-xr-x"; |
||||
|
||||
} |
@ -0,0 +1,427 @@
|
||||
/* |
||||
* 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.spi.task; |
||||
|
||||
import java.util.Date; |
||||
import java.util.Map; |
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat; |
||||
|
||||
public class TaskRequest { |
||||
|
||||
|
||||
|
||||
/** |
||||
* task id |
||||
*/ |
||||
private int taskInstanceId; |
||||
|
||||
/** |
||||
* task name |
||||
*/ |
||||
private String taskName; |
||||
|
||||
/** |
||||
* task first submit time. |
||||
*/ |
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
||||
private Date firstSubmitTime; |
||||
|
||||
/** |
||||
* task start time |
||||
*/ |
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
||||
private Date startTime; |
||||
|
||||
/** |
||||
* task type |
||||
*/ |
||||
private String taskType; |
||||
|
||||
/** |
||||
* host |
||||
*/ |
||||
private String host; |
||||
|
||||
/** |
||||
* task execute path |
||||
*/ |
||||
private String executePath; |
||||
|
||||
/** |
||||
* log path |
||||
*/ |
||||
private String logPath; |
||||
|
||||
/** |
||||
* task json |
||||
*/ |
||||
private String taskJson; |
||||
|
||||
/** |
||||
* processId |
||||
*/ |
||||
private int processId; |
||||
|
||||
/** |
||||
* appIds |
||||
*/ |
||||
private String appIds; |
||||
|
||||
/** |
||||
* process instance id |
||||
*/ |
||||
private int processInstanceId; |
||||
|
||||
|
||||
/** |
||||
* process instance schedule time |
||||
*/ |
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") |
||||
private Date scheduleTime; |
||||
|
||||
/** |
||||
* process instance global parameters |
||||
*/ |
||||
private String globalParams; |
||||
|
||||
|
||||
/** |
||||
* execute user id |
||||
*/ |
||||
private int executorId; |
||||
|
||||
|
||||
/** |
||||
* command type if complement |
||||
*/ |
||||
private int cmdTypeIfComplement; |
||||
|
||||
|
||||
/** |
||||
* tenant code |
||||
*/ |
||||
private String tenantCode; |
||||
|
||||
/** |
||||
* task queue |
||||
*/ |
||||
private String queue; |
||||
|
||||
|
||||
/** |
||||
* process define id |
||||
*/ |
||||
private int processDefineId; |
||||
|
||||
/** |
||||
* project id |
||||
*/ |
||||
private int projectId; |
||||
|
||||
/** |
||||
* taskParams |
||||
*/ |
||||
private String taskParams; |
||||
|
||||
/** |
||||
* envFile |
||||
*/ |
||||
private String envFile; |
||||
|
||||
/** |
||||
* definedParams |
||||
*/ |
||||
private Map<String, String> definedParams; |
||||
|
||||
/** |
||||
* task AppId |
||||
*/ |
||||
private String taskAppId; |
||||
|
||||
/** |
||||
* task timeout strategy |
||||
*/ |
||||
private int taskTimeoutStrategy; |
||||
|
||||
/** |
||||
* task timeout |
||||
*/ |
||||
private int taskTimeout; |
||||
|
||||
/** |
||||
* worker group |
||||
*/ |
||||
private String workerGroup; |
||||
|
||||
/** |
||||
* delay execution time. |
||||
*/ |
||||
private int delayTime; |
||||
|
||||
|
||||
|
||||
/** |
||||
* resources full name and tenant code |
||||
*/ |
||||
private Map<String, String> resources; |
||||
|
||||
|
||||
private Map<String, Property> paramsMap; |
||||
|
||||
public Map<String, String> getResources() { |
||||
return resources; |
||||
} |
||||
|
||||
public void setResources(Map<String, String> resources) { |
||||
this.resources = resources; |
||||
} |
||||
|
||||
public Map<String, Property> getParamsMap() { |
||||
return paramsMap; |
||||
} |
||||
|
||||
public void setParamsMap(Map<String, Property> paramsMap) { |
||||
this.paramsMap = paramsMap; |
||||
} |
||||
|
||||
public int getTaskInstanceId() { |
||||
return taskInstanceId; |
||||
} |
||||
|
||||
public void setTaskInstanceId(int taskInstanceId) { |
||||
this.taskInstanceId = taskInstanceId; |
||||
} |
||||
|
||||
public String getTaskName() { |
||||
return taskName; |
||||
} |
||||
|
||||
public void setTaskName(String taskName) { |
||||
this.taskName = taskName; |
||||
} |
||||
|
||||
public Date getFirstSubmitTime() { |
||||
return firstSubmitTime; |
||||
} |
||||
|
||||
public void setFirstSubmitTime(Date firstSubmitTime) { |
||||
this.firstSubmitTime = firstSubmitTime; |
||||
} |
||||
|
||||
public Date getStartTime() { |
||||
return startTime; |
||||
} |
||||
|
||||
public void setStartTime(Date startTime) { |
||||
this.startTime = startTime; |
||||
} |
||||
|
||||
public String getTaskType() { |
||||
return taskType; |
||||
} |
||||
|
||||
public void setTaskType(String taskType) { |
||||
this.taskType = taskType; |
||||
} |
||||
|
||||
public String getHost() { |
||||
return host; |
||||
} |
||||
|
||||
public void setHost(String host) { |
||||
this.host = host; |
||||
} |
||||
|
||||
public String getExecutePath() { |
||||
return executePath; |
||||
} |
||||
|
||||
public void setExecutePath(String executePath) { |
||||
this.executePath = executePath; |
||||
} |
||||
|
||||
public String getLogPath() { |
||||
return logPath; |
||||
} |
||||
|
||||
public void setLogPath(String logPath) { |
||||
this.logPath = logPath; |
||||
} |
||||
|
||||
public String getTaskJson() { |
||||
return taskJson; |
||||
} |
||||
|
||||
public void setTaskJson(String taskJson) { |
||||
this.taskJson = taskJson; |
||||
} |
||||
|
||||
public int getProcessId() { |
||||
return processId; |
||||
} |
||||
|
||||
public void setProcessId(int processId) { |
||||
this.processId = processId; |
||||
} |
||||
|
||||
public String getAppIds() { |
||||
return appIds; |
||||
} |
||||
|
||||
public void setAppIds(String appIds) { |
||||
this.appIds = appIds; |
||||
} |
||||
|
||||
public int getProcessInstanceId() { |
||||
return processInstanceId; |
||||
} |
||||
|
||||
public void setProcessInstanceId(int processInstanceId) { |
||||
this.processInstanceId = processInstanceId; |
||||
} |
||||
|
||||
public Date getScheduleTime() { |
||||
return scheduleTime; |
||||
} |
||||
|
||||
public void setScheduleTime(Date scheduleTime) { |
||||
this.scheduleTime = scheduleTime; |
||||
} |
||||
|
||||
public String getGlobalParams() { |
||||
return globalParams; |
||||
} |
||||
|
||||
public void setGlobalParams(String globalParams) { |
||||
this.globalParams = globalParams; |
||||
} |
||||
|
||||
public int getExecutorId() { |
||||
return executorId; |
||||
} |
||||
|
||||
public void setExecutorId(int executorId) { |
||||
this.executorId = executorId; |
||||
} |
||||
|
||||
public int getCmdTypeIfComplement() { |
||||
return cmdTypeIfComplement; |
||||
} |
||||
|
||||
public void setCmdTypeIfComplement(int cmdTypeIfComplement) { |
||||
this.cmdTypeIfComplement = cmdTypeIfComplement; |
||||
} |
||||
|
||||
public String getTenantCode() { |
||||
return tenantCode; |
||||
} |
||||
|
||||
public void setTenantCode(String tenantCode) { |
||||
this.tenantCode = tenantCode; |
||||
} |
||||
|
||||
public String getQueue() { |
||||
return queue; |
||||
} |
||||
|
||||
public void setQueue(String queue) { |
||||
this.queue = queue; |
||||
} |
||||
|
||||
public int getProcessDefineId() { |
||||
return processDefineId; |
||||
} |
||||
|
||||
public void setProcessDefineId(int processDefineId) { |
||||
this.processDefineId = processDefineId; |
||||
} |
||||
|
||||
public int getProjectId() { |
||||
return projectId; |
||||
} |
||||
|
||||
public void setProjectId(int projectId) { |
||||
this.projectId = projectId; |
||||
} |
||||
|
||||
public String getTaskParams() { |
||||
return taskParams; |
||||
} |
||||
|
||||
public void setTaskParams(String taskParams) { |
||||
this.taskParams = taskParams; |
||||
} |
||||
|
||||
public String getEnvFile() { |
||||
return envFile; |
||||
} |
||||
|
||||
public void setEnvFile(String envFile) { |
||||
this.envFile = envFile; |
||||
} |
||||
|
||||
public Map<String, String> getDefinedParams() { |
||||
return definedParams; |
||||
} |
||||
|
||||
public void setDefinedParams(Map<String, String> definedParams) { |
||||
this.definedParams = definedParams; |
||||
} |
||||
|
||||
public String getTaskAppId() { |
||||
return taskAppId; |
||||
} |
||||
|
||||
public void setTaskAppId(String taskAppId) { |
||||
this.taskAppId = taskAppId; |
||||
} |
||||
|
||||
public int getTaskTimeoutStrategy() { |
||||
return taskTimeoutStrategy; |
||||
} |
||||
|
||||
public void setTaskTimeoutStrategy(int taskTimeoutStrategy) { |
||||
this.taskTimeoutStrategy = taskTimeoutStrategy; |
||||
} |
||||
|
||||
public int getTaskTimeout() { |
||||
return taskTimeout; |
||||
} |
||||
|
||||
public void setTaskTimeout(int taskTimeout) { |
||||
this.taskTimeout = taskTimeout; |
||||
} |
||||
|
||||
public String getWorkerGroup() { |
||||
return workerGroup; |
||||
} |
||||
|
||||
public void setWorkerGroup(String workerGroup) { |
||||
this.workerGroup = workerGroup; |
||||
} |
||||
|
||||
public int getDelayTime() { |
||||
return delayTime; |
||||
} |
||||
|
||||
public void setDelayTime(int delayTime) { |
||||
this.delayTime = delayTime; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!-- |
||||
~ 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. |
||||
--> |
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<parent> |
||||
<artifactId>dolphinscheduler-task-plugin</artifactId> |
||||
<groupId>org.apache.dolphinscheduler</groupId> |
||||
<version>1.3.6-SNAPSHOT</version> |
||||
</parent> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
|
||||
<artifactId>dolphinscheduler-task-api</artifactId> |
||||
|
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>org.apache.dolphinscheduler</groupId> |
||||
<artifactId>dolphinscheduler-spi</artifactId> |
||||
<scope>provided</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>commons-io</groupId> |
||||
<artifactId>commons-io</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>com.google.guava</groupId> |
||||
<artifactId>guava</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.slf4j</groupId> |
||||
<artifactId>slf4j-api</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>ch.qos.logback</groupId> |
||||
<artifactId>logback-classic</artifactId> |
||||
</dependency> |
||||
</dependencies> |
||||
</project> |
@ -0,0 +1,508 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.api; |
||||
|
||||
import static org.apache.dolphinscheduler.spi.task.TaskConstants.EXIT_CODE_FAILURE; |
||||
import static org.apache.dolphinscheduler.spi.task.TaskConstants.EXIT_CODE_KILL; |
||||
import static org.apache.dolphinscheduler.spi.task.TaskConstants.SH; |
||||
|
||||
import org.apache.dolphinscheduler.spi.task.TaskConstants; |
||||
import org.apache.dolphinscheduler.spi.task.TaskRequest; |
||||
import org.apache.dolphinscheduler.spi.utils.StringUtils; |
||||
|
||||
import java.io.BufferedReader; |
||||
import java.io.File; |
||||
import java.io.FileInputStream; |
||||
import java.io.IOException; |
||||
import java.io.InputStreamReader; |
||||
import java.lang.reflect.Field; |
||||
import java.nio.charset.StandardCharsets; |
||||
import java.util.ArrayList; |
||||
import java.util.Collections; |
||||
import java.util.LinkedList; |
||||
import java.util.List; |
||||
import java.util.concurrent.ExecutorService; |
||||
import java.util.concurrent.TimeUnit; |
||||
import java.util.function.Consumer; |
||||
import java.util.regex.Matcher; |
||||
import java.util.regex.Pattern; |
||||
|
||||
import org.slf4j.Logger; |
||||
|
||||
/** |
||||
* abstract command executor |
||||
*/ |
||||
public abstract class AbstractCommandExecutor { |
||||
/** |
||||
* rules for extracting application ID |
||||
*/ |
||||
protected static final Pattern APPLICATION_REGEX = Pattern.compile(TaskConstants.APPLICATION_REGEX); |
||||
|
||||
protected StringBuilder varPool = new StringBuilder(); |
||||
/** |
||||
* process |
||||
*/ |
||||
private Process process; |
||||
|
||||
/** |
||||
* log handler |
||||
*/ |
||||
protected Consumer<List<String>> logHandler; |
||||
|
||||
/** |
||||
* logger |
||||
*/ |
||||
protected Logger logger; |
||||
|
||||
/** |
||||
* log list |
||||
*/ |
||||
protected List<String> logBuffer; |
||||
|
||||
protected boolean logOutputIsSuccess = false; |
||||
|
||||
/* |
||||
* SHELL result string |
||||
*/ |
||||
protected String taskResultString; |
||||
|
||||
/** |
||||
* taskRequest |
||||
*/ |
||||
protected TaskRequest taskRequest; |
||||
|
||||
public AbstractCommandExecutor(Consumer<List<String>> logHandler, |
||||
TaskRequest taskRequest, |
||||
Logger logger) { |
||||
this.logHandler = logHandler; |
||||
this.taskRequest = taskRequest; |
||||
this.logger = logger; |
||||
this.logBuffer = Collections.synchronizedList(new ArrayList<>()); |
||||
} |
||||
|
||||
public AbstractCommandExecutor(List<String> logBuffer) { |
||||
this.logBuffer = logBuffer; |
||||
} |
||||
|
||||
/** |
||||
* build process |
||||
* |
||||
* @param commandFile command file |
||||
* @throws IOException IO Exception |
||||
*/ |
||||
private void buildProcess(String commandFile) throws IOException { |
||||
// setting up user to run commands
|
||||
List<String> command = new LinkedList<>(); |
||||
|
||||
//init process builder
|
||||
ProcessBuilder processBuilder = new ProcessBuilder(); |
||||
// setting up a working directory
|
||||
processBuilder.directory(new File(taskRequest.getExecutePath())); |
||||
// merge error information to standard output stream
|
||||
processBuilder.redirectErrorStream(true); |
||||
|
||||
// setting up user to run commands
|
||||
command.add("sudo"); |
||||
command.add("-u"); |
||||
command.add(taskRequest.getTenantCode()); |
||||
command.add(SH); |
||||
command.addAll(Collections.emptyList()); |
||||
command.add(commandFile); |
||||
|
||||
// setting commands
|
||||
processBuilder.command(command); |
||||
process = processBuilder.start(); |
||||
|
||||
// print command
|
||||
printCommand(command); |
||||
} |
||||
|
||||
public TaskResponse run(String execCommand) throws IOException, InterruptedException { |
||||
TaskResponse result = new TaskResponse(); |
||||
int taskInstanceId = taskRequest.getTaskInstanceId(); |
||||
if (null == TaskExecutionContextCacheManager.getByTaskInstanceId(taskInstanceId)) { |
||||
result.setExitStatusCode(EXIT_CODE_KILL); |
||||
return result; |
||||
} |
||||
if (StringUtils.isEmpty(execCommand)) { |
||||
TaskExecutionContextCacheManager.removeByTaskInstanceId(taskInstanceId); |
||||
return result; |
||||
} |
||||
|
||||
String commandFilePath = buildCommandFilePath(); |
||||
|
||||
// create command file if not exists
|
||||
createCommandFileIfNotExists(execCommand, commandFilePath); |
||||
|
||||
//build process
|
||||
buildProcess(commandFilePath); |
||||
|
||||
// parse process output
|
||||
parseProcessOutput(process); |
||||
|
||||
int processId = getProcessId(process); |
||||
|
||||
result.setProcessId(processId); |
||||
|
||||
// cache processId
|
||||
taskRequest.setProcessId(processId); |
||||
boolean updateTaskExecutionContextStatus = TaskExecutionContextCacheManager.updateTaskExecutionContext(taskRequest); |
||||
if (Boolean.FALSE.equals(updateTaskExecutionContextStatus)) { |
||||
ProcessUtils.kill(taskRequest); |
||||
result.setStatus(TaskRunStatus.FAIL_AND_NEED_KILL); |
||||
result.setExitStatusCode(EXIT_CODE_KILL); |
||||
return result; |
||||
} |
||||
// print process id
|
||||
logger.info("process start, process id is: {}", processId); |
||||
|
||||
// if timeout occurs, exit directly
|
||||
long remainTime = getRemainTime(); |
||||
|
||||
// waiting for the run to finish
|
||||
boolean status = process.waitFor(remainTime, TimeUnit.SECONDS); |
||||
logger.info("process has exited, execute path:{}, processId:{} ,exitStatusCode:{}", |
||||
taskRequest.getExecutePath(), |
||||
processId |
||||
, result.getExitStatusCode()); |
||||
|
||||
// if SHELL task exit
|
||||
if (status) { |
||||
// set appIds
|
||||
List<String> appIds = getAppIds(taskRequest.getLogPath()); |
||||
result.setAppIds(String.join(TaskConstants.COMMA, appIds)); |
||||
|
||||
// SHELL task state
|
||||
result.setExitStatusCode(process.exitValue()); |
||||
|
||||
} else { |
||||
logger.error("process has failure , exitStatusCode : {} , ready to kill ...", result.getExitStatusCode()); |
||||
ProcessUtils.kill(taskRequest); |
||||
result.setStatus(TaskRunStatus.FAIL_AND_NEED_KILL); |
||||
result.setExitStatusCode(EXIT_CODE_FAILURE); |
||||
} |
||||
|
||||
return result; |
||||
|
||||
} |
||||
|
||||
public String getVarPool() { |
||||
return varPool.toString(); |
||||
} |
||||
|
||||
/** |
||||
* cancel application |
||||
* |
||||
* @throws Exception exception |
||||
*/ |
||||
public void cancelApplication() throws Exception { |
||||
if (process == null) { |
||||
return; |
||||
} |
||||
|
||||
// clear log
|
||||
clear(); |
||||
|
||||
int processId = getProcessId(process); |
||||
|
||||
logger.info("cancel process: {}", processId); |
||||
|
||||
// kill , waiting for completion
|
||||
boolean killed = softKill(processId); |
||||
|
||||
if (!killed) { |
||||
// hard kill
|
||||
hardKill(processId); |
||||
|
||||
// destory
|
||||
process.destroy(); |
||||
|
||||
process = null; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* soft kill |
||||
* |
||||
* @param processId process id |
||||
* @return process is alive |
||||
* @throws InterruptedException interrupted exception |
||||
*/ |
||||
private boolean softKill(int processId) { |
||||
|
||||
if (processId != 0 && process.isAlive()) { |
||||
try { |
||||
// sudo -u user command to run command
|
||||
String cmd = String.format("kill %d", processId); |
||||
cmd = OSUtils.getSudoCmd(taskRequest.getTenantCode(), cmd); |
||||
logger.info("soft kill task:{}, process id:{}, cmd:{}", taskRequest.getTaskAppId(), processId, cmd); |
||||
|
||||
Runtime.getRuntime().exec(cmd); |
||||
} catch (IOException e) { |
||||
logger.info("kill attempt failed", e); |
||||
} |
||||
} |
||||
|
||||
return process.isAlive(); |
||||
} |
||||
|
||||
/** |
||||
* hard kill |
||||
* |
||||
* @param processId process id |
||||
*/ |
||||
private void hardKill(int processId) { |
||||
if (processId != 0 && process.isAlive()) { |
||||
try { |
||||
String cmd = String.format("kill -9 %d", processId); |
||||
cmd = OSUtils.getSudoCmd(taskRequest.getTenantCode(), cmd); |
||||
logger.info("hard kill task:{}, process id:{}, cmd:{}", taskRequest.getTaskAppId(), processId, cmd); |
||||
|
||||
Runtime.getRuntime().exec(cmd); |
||||
} catch (IOException e) { |
||||
logger.error("kill attempt failed ", e); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* print command |
||||
* |
||||
* @param commands process builder |
||||
*/ |
||||
private void printCommand(List<String> commands) { |
||||
String cmdStr; |
||||
|
||||
try { |
||||
cmdStr = ProcessUtils.buildCommandStr(commands); |
||||
logger.info("task run command:\n{}", cmdStr); |
||||
} catch (Exception e) { |
||||
logger.error(e.getMessage(), e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* clear |
||||
*/ |
||||
private void clear() { |
||||
|
||||
List<String> markerList = new ArrayList<>(); |
||||
markerList.add(ch.qos.logback.classic.ClassicConstants.FINALIZE_SESSION_MARKER.toString()); |
||||
|
||||
if (!logBuffer.isEmpty()) { |
||||
// log handle
|
||||
logHandler.accept(logBuffer); |
||||
logBuffer.clear(); |
||||
} |
||||
logHandler.accept(markerList); |
||||
} |
||||
|
||||
/** |
||||
* get the standard output of the process |
||||
* |
||||
* @param process process |
||||
*/ |
||||
private void parseProcessOutput(Process process) { |
||||
String threadLoggerInfoName = String.format(LoggerUtils.TASK_LOGGER_THREAD_NAME + "-%s", taskRequest.getTaskAppId()); |
||||
ExecutorService getOutputLogService = ThreadUtils.newDaemonSingleThreadExecutor(threadLoggerInfoName + "-" + "getOutputLogService"); |
||||
getOutputLogService.submit(() -> { |
||||
try (BufferedReader inReader = new BufferedReader(new InputStreamReader(process.getInputStream()))) { |
||||
String line; |
||||
logBuffer.add("welcome to use bigdata scheduling system..."); |
||||
while ((line = inReader.readLine()) != null) { |
||||
if (line.startsWith("${setValue(")) { |
||||
varPool.append(line, "${setValue(".length(), line.length() - 2); |
||||
varPool.append("$VarPool$"); |
||||
} else { |
||||
logBuffer.add(line); |
||||
taskResultString = line; |
||||
} |
||||
} |
||||
logOutputIsSuccess = true; |
||||
} catch (Exception e) { |
||||
logger.error(e.getMessage(), e); |
||||
logOutputIsSuccess = true; |
||||
} |
||||
}); |
||||
|
||||
getOutputLogService.shutdown(); |
||||
|
||||
ExecutorService parseProcessOutputExecutorService = ThreadUtils.newDaemonSingleThreadExecutor(threadLoggerInfoName); |
||||
parseProcessOutputExecutorService.submit(() -> { |
||||
try { |
||||
long lastFlushTime = System.currentTimeMillis(); |
||||
while (logBuffer.size() > 0 || !logOutputIsSuccess) { |
||||
if (logBuffer.size() > 0) { |
||||
lastFlushTime = flush(lastFlushTime); |
||||
} else { |
||||
Thread.sleep(TaskConstants.DEFAULT_LOG_FLUSH_INTERVAL); |
||||
} |
||||
} |
||||
} catch (Exception e) { |
||||
logger.error(e.getMessage(), e); |
||||
} finally { |
||||
clear(); |
||||
} |
||||
}); |
||||
parseProcessOutputExecutorService.shutdown(); |
||||
} |
||||
|
||||
public int getProcessId() { |
||||
return getProcessId(process); |
||||
} |
||||
|
||||
/** |
||||
* get app links |
||||
* |
||||
* @param logPath log path |
||||
* @return app id list |
||||
*/ |
||||
private List<String> getAppIds(String logPath) { |
||||
List<String> logs = convertFile2List(logPath); |
||||
|
||||
List<String> appIds = new ArrayList<>(); |
||||
/** |
||||
* analysis log?get submited yarn application id |
||||
*/ |
||||
for (String log : logs) { |
||||
String appId = findAppId(log); |
||||
if (StringUtils.isNotEmpty(appId) && !appIds.contains(appId)) { |
||||
logger.info("find app id: {}", appId); |
||||
appIds.add(appId); |
||||
} |
||||
} |
||||
return appIds; |
||||
} |
||||
|
||||
/** |
||||
* convert file to list |
||||
* |
||||
* @param filename file name |
||||
* @return line list |
||||
*/ |
||||
private List<String> convertFile2List(String filename) { |
||||
List lineList = new ArrayList<String>(100); |
||||
File file = new File(filename); |
||||
|
||||
if (!file.exists()) { |
||||
return lineList; |
||||
} |
||||
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filename), StandardCharsets.UTF_8))) { |
||||
String line; |
||||
while ((line = br.readLine()) != null) { |
||||
lineList.add(line); |
||||
} |
||||
} catch (Exception e) { |
||||
logger.error(String.format("read file: %s failed : ", filename), e); |
||||
} |
||||
|
||||
return lineList; |
||||
} |
||||
|
||||
/** |
||||
* find app id |
||||
* |
||||
* @param line line |
||||
* @return appid |
||||
*/ |
||||
private String findAppId(String line) { |
||||
Matcher matcher = APPLICATION_REGEX.matcher(line); |
||||
if (matcher.find()) { |
||||
return matcher.group(); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* get remain time(s) |
||||
* |
||||
* @return remain time |
||||
*/ |
||||
private long getRemainTime() { |
||||
long usedTime = (System.currentTimeMillis() - taskRequest.getStartTime().getTime()) / 1000; |
||||
long remainTime = taskRequest.getTaskTimeout() - usedTime; |
||||
|
||||
if (remainTime < 0) { |
||||
throw new RuntimeException("task execution time out"); |
||||
} |
||||
|
||||
return remainTime; |
||||
} |
||||
|
||||
/** |
||||
* get process id |
||||
* |
||||
* @param process process |
||||
* @return process id |
||||
*/ |
||||
private int getProcessId(Process process) { |
||||
int processId = 0; |
||||
|
||||
try { |
||||
Field f = process.getClass().getDeclaredField(TaskConstants.PID); |
||||
f.setAccessible(true); |
||||
|
||||
processId = f.getInt(process); |
||||
} catch (Throwable e) { |
||||
logger.error(e.getMessage(), e); |
||||
} |
||||
|
||||
return processId; |
||||
} |
||||
|
||||
/** |
||||
* when log buffer siz or flush time reach condition , then flush |
||||
* |
||||
* @param lastFlushTime last flush time |
||||
* @return last flush time |
||||
*/ |
||||
private long flush(long lastFlushTime) { |
||||
long now = System.currentTimeMillis(); |
||||
|
||||
/** |
||||
* when log buffer siz or flush time reach condition , then flush |
||||
*/ |
||||
if (logBuffer.size() >= TaskConstants.DEFAULT_LOG_ROWS_NUM || now - lastFlushTime > TaskConstants.DEFAULT_LOG_FLUSH_INTERVAL) { |
||||
lastFlushTime = now; |
||||
/** log handle */ |
||||
logHandler.accept(logBuffer); |
||||
|
||||
logBuffer.clear(); |
||||
} |
||||
return lastFlushTime; |
||||
} |
||||
|
||||
protected List<String> commandOptions() { |
||||
return Collections.emptyList(); |
||||
} |
||||
|
||||
protected abstract String buildCommandFilePath(); |
||||
|
||||
protected abstract String commandInterpreter(); |
||||
|
||||
protected abstract void createCommandFileIfNotExists(String execCommand, String commandFile) throws IOException; |
||||
|
||||
public String getTaskResultString() { |
||||
return taskResultString; |
||||
} |
||||
|
||||
public void setTaskResultString(String taskResultString) { |
||||
this.taskResultString = taskResultString; |
||||
} |
||||
} |
@ -0,0 +1,360 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.api; |
||||
|
||||
import java.io.BufferedReader; |
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
import java.io.InputStreamReader; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
import java.util.Timer; |
||||
import java.util.TimerTask; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
import java.util.concurrent.atomic.AtomicBoolean; |
||||
|
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
/** |
||||
* A base class for running a Unix command. |
||||
* |
||||
* <code>AbstractShell</code> can be used to run unix commands like <code>du</code> or |
||||
* <code>df</code>. It also offers facilities to gate commands by |
||||
* time-intervals. |
||||
*/ |
||||
public abstract class AbstractShell { |
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AbstractShell.class); |
||||
|
||||
/** |
||||
* Time after which the executing script would be timedout |
||||
*/ |
||||
protected long timeOutInterval = 0L; |
||||
/** |
||||
* If or not script timed out |
||||
*/ |
||||
private AtomicBoolean timedOut; |
||||
|
||||
/** |
||||
* refresh interval in msec |
||||
*/ |
||||
private long interval; |
||||
|
||||
/** |
||||
* last time the command was performed |
||||
*/ |
||||
private long lastTime; |
||||
|
||||
/** |
||||
* env for the command execution |
||||
*/ |
||||
private Map<String, String> environment; |
||||
|
||||
private File dir; |
||||
|
||||
/** |
||||
* sub process used to execute the command |
||||
*/ |
||||
private Process process; |
||||
private int exitCode; |
||||
|
||||
/** |
||||
* If or not script finished executing |
||||
*/ |
||||
private AtomicBoolean completed; |
||||
|
||||
AbstractShell() { |
||||
this(0L); |
||||
} |
||||
|
||||
/** |
||||
* @param interval the minimum duration to wait before re-executing the |
||||
* command. |
||||
*/ |
||||
AbstractShell(long interval) { |
||||
this.interval = interval; |
||||
this.lastTime = (interval < 0) ? 0 : -interval; |
||||
} |
||||
|
||||
/** |
||||
* set the environment for the command |
||||
* |
||||
* @param env Mapping of environment variables |
||||
*/ |
||||
protected void setEnvironment(Map<String, String> env) { |
||||
this.environment = env; |
||||
} |
||||
|
||||
/** |
||||
* set the working directory |
||||
* |
||||
* @param dir The directory where the command would be executed |
||||
*/ |
||||
protected void setWorkingDirectory(File dir) { |
||||
this.dir = dir; |
||||
} |
||||
|
||||
/** |
||||
* check to see if a command needs to be executed and execute if needed |
||||
* |
||||
* @throws IOException errors |
||||
*/ |
||||
protected void run() throws IOException { |
||||
if (lastTime + interval > System.currentTimeMillis()) { |
||||
return; |
||||
} |
||||
// reset for next run
|
||||
exitCode = 0; |
||||
runCommand(); |
||||
} |
||||
|
||||
/** |
||||
* Run a command actual work |
||||
*/ |
||||
private void runCommand() throws IOException { |
||||
ProcessBuilder builder = new ProcessBuilder(getExecString()); |
||||
Timer timeOutTimer = null; |
||||
ShellTimeoutTimerTask timeoutTimerTask; |
||||
timedOut = new AtomicBoolean(false); |
||||
completed = new AtomicBoolean(false); |
||||
|
||||
if (environment != null) { |
||||
builder.environment().putAll(this.environment); |
||||
} |
||||
if (dir != null) { |
||||
builder.directory(this.dir); |
||||
} |
||||
|
||||
process = builder.start(); |
||||
ProcessContainer.putProcess(process); |
||||
|
||||
if (timeOutInterval > 0) { |
||||
timeOutTimer = new Timer(); |
||||
timeoutTimerTask = new ShellTimeoutTimerTask( |
||||
this); |
||||
//One time scheduling.
|
||||
timeOutTimer.schedule(timeoutTimerTask, timeOutInterval); |
||||
} |
||||
final BufferedReader errReader = |
||||
new BufferedReader( |
||||
new InputStreamReader(process.getErrorStream())); |
||||
BufferedReader inReader = |
||||
new BufferedReader( |
||||
new InputStreamReader(process.getInputStream())); |
||||
final StringBuilder errMsg = new StringBuilder(); |
||||
|
||||
// read error and input streams as this would free up the buffers
|
||||
// free the error stream buffer
|
||||
Thread errThread = new Thread() { |
||||
@Override |
||||
public void run() { |
||||
try { |
||||
String line = errReader.readLine(); |
||||
while ((line != null) && !isInterrupted()) { |
||||
errMsg.append(line); |
||||
errMsg.append(System.getProperty("line.separator")); |
||||
line = errReader.readLine(); |
||||
} |
||||
} catch (IOException ioe) { |
||||
logger.warn("Error reading the error stream", ioe); |
||||
} |
||||
} |
||||
}; |
||||
Thread inThread = new Thread() { |
||||
@Override |
||||
public void run() { |
||||
try { |
||||
parseExecResult(inReader); |
||||
} catch (IOException ioe) { |
||||
logger.warn("Error reading the in stream", ioe); |
||||
} |
||||
super.run(); |
||||
} |
||||
}; |
||||
try { |
||||
errThread.start(); |
||||
inThread.start(); |
||||
} catch (IllegalStateException e) { |
||||
logger.error(" read error and input streams start error", e); |
||||
} |
||||
try { |
||||
// parse the output
|
||||
exitCode = process.waitFor(); |
||||
try { |
||||
// make sure that the error and in thread exits
|
||||
errThread.join(); |
||||
inThread.join(); |
||||
} catch (InterruptedException ie) { |
||||
logger.warn("Interrupted while reading the error and in stream", ie); |
||||
} |
||||
completed.compareAndSet(false, true); |
||||
//the timeout thread handling
|
||||
//taken care in finally block
|
||||
if (exitCode != 0 || errMsg.length() > 0) { |
||||
throw new ExitCodeException(exitCode, errMsg.toString()); |
||||
} |
||||
} catch (InterruptedException ie) { |
||||
throw new IOException(ie.toString()); |
||||
} finally { |
||||
if ((timeOutTimer != null) && !timedOut.get()) { |
||||
timeOutTimer.cancel(); |
||||
} |
||||
// close the input stream
|
||||
try { |
||||
inReader.close(); |
||||
} catch (IOException ioe) { |
||||
logger.warn("Error while closing the input stream", ioe); |
||||
} |
||||
if (!completed.get()) { |
||||
errThread.interrupt(); |
||||
} |
||||
try { |
||||
errReader.close(); |
||||
} catch (IOException ioe) { |
||||
logger.warn("Error while closing the error stream", ioe); |
||||
} |
||||
ProcessContainer.removeProcess(process); |
||||
process.destroy(); |
||||
lastTime = System.currentTimeMillis(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @return an array containing the command name and its parameters |
||||
*/ |
||||
protected abstract String[] getExecString(); |
||||
|
||||
/** |
||||
* Parse the execution result |
||||
* |
||||
* @param lines lines |
||||
* @throws IOException errors |
||||
*/ |
||||
protected abstract void parseExecResult(BufferedReader lines) |
||||
throws IOException; |
||||
|
||||
/** |
||||
* get the current sub-process executing the given command |
||||
* |
||||
* @return process executing the command |
||||
*/ |
||||
public Process getProcess() { |
||||
return process; |
||||
} |
||||
|
||||
/** |
||||
* get the exit code |
||||
* |
||||
* @return the exit code of the process |
||||
*/ |
||||
public int getExitCode() { |
||||
return exitCode; |
||||
} |
||||
|
||||
/** |
||||
* Set if the command has timed out. |
||||
*/ |
||||
private void setTimedOut() { |
||||
this.timedOut.set(true); |
||||
} |
||||
|
||||
/** |
||||
* Timer which is used to timeout scripts spawned off by shell. |
||||
*/ |
||||
private static class ShellTimeoutTimerTask extends TimerTask { |
||||
|
||||
private AbstractShell shell; |
||||
|
||||
public ShellTimeoutTimerTask(AbstractShell shell) { |
||||
this.shell = shell; |
||||
} |
||||
|
||||
@Override |
||||
public void run() { |
||||
Process p = shell.getProcess(); |
||||
try { |
||||
p.exitValue(); |
||||
} catch (Exception e) { |
||||
//Process has not terminated.
|
||||
//So check if it has completed
|
||||
//if not just destroy it.
|
||||
if (p != null && !shell.completed.get()) { |
||||
shell.setTimedOut(); |
||||
p.destroy(); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* This is an IOException with exit code added. |
||||
*/ |
||||
public static class ExitCodeException extends IOException { |
||||
private final int exitCode; |
||||
|
||||
public ExitCodeException(int exitCode, String message) { |
||||
super(message); |
||||
this.exitCode = exitCode; |
||||
} |
||||
|
||||
public int getExitCode() { |
||||
return exitCode; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* process manage container |
||||
*/ |
||||
public static class ProcessContainer extends ConcurrentHashMap<Integer, Process> { |
||||
private static final ProcessContainer container = new ProcessContainer(); |
||||
|
||||
private ProcessContainer() { |
||||
super(); |
||||
} |
||||
|
||||
public static final ProcessContainer getInstance() { |
||||
return container; |
||||
} |
||||
|
||||
public static void putProcess(Process process) { |
||||
getInstance().put(process.hashCode(), process); |
||||
} |
||||
|
||||
public static int processSize() { |
||||
return getInstance().size(); |
||||
} |
||||
|
||||
public static void removeProcess(Process process) { |
||||
getInstance().remove(process.hashCode()); |
||||
} |
||||
|
||||
public static void destroyAllProcess() { |
||||
Set<Entry<Integer, Process>> set = getInstance().entrySet(); |
||||
for (Entry<Integer, Process> entry : set) { |
||||
try { |
||||
entry.getValue().destroy(); |
||||
} catch (Exception e) { |
||||
logger.error("Destroy All Processes error", e); |
||||
} |
||||
} |
||||
|
||||
logger.info("close " + set.size() + " executing process tasks"); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,93 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.api; |
||||
|
||||
import org.apache.dolphinscheduler.spi.task.AbstractTask; |
||||
import org.apache.dolphinscheduler.spi.task.TaskRequest; |
||||
|
||||
import org.slf4j.Logger; |
||||
|
||||
/** |
||||
* abstract yarn task |
||||
*/ |
||||
public abstract class AbstractYarnTask extends AbstractTask { |
||||
/** |
||||
* process task |
||||
*/ |
||||
private ShellCommandExecutor shellCommandExecutor; |
||||
|
||||
/** |
||||
* Abstract Yarn Task |
||||
* |
||||
* @param taskRequest taskRequest |
||||
* @param logger logger |
||||
*/ |
||||
public AbstractYarnTask(TaskRequest taskRequest, Logger logger) { |
||||
super(taskRequest, logger); |
||||
this.shellCommandExecutor = new ShellCommandExecutor(this::logHandle, |
||||
taskRequest, |
||||
logger); |
||||
} |
||||
|
||||
@Override |
||||
public void handle() throws Exception { |
||||
try { |
||||
// SHELL task exit code
|
||||
TaskResponse response = shellCommandExecutor.run(getCommand()); |
||||
setExitStatusCode(response.getExitStatusCode()); |
||||
setAppIds(response.getAppIds()); |
||||
setProcessId(response.getProcessId()); |
||||
} catch (Exception e) { |
||||
logger.error("yarn process failure", e); |
||||
exitStatusCode = -1; |
||||
throw e; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* cancel application |
||||
* |
||||
* @param status status |
||||
* @throws Exception exception |
||||
*/ |
||||
@Override |
||||
public void cancelApplication(boolean status) throws Exception { |
||||
cancel = true; |
||||
// cancel process
|
||||
|
||||
//todo 交给上层处理
|
||||
shellCommandExecutor.cancelApplication(); |
||||
// TaskInstance taskInstance = processService.findTaskInstanceById(taskExecutionContext.getTaskInstanceId());
|
||||
// if (status && taskInstance != null){
|
||||
// ProcessUtils.killYarnJob(taskExecutionContext);
|
||||
// }
|
||||
} |
||||
|
||||
/** |
||||
* create command |
||||
* |
||||
* @return String |
||||
* @throws Exception exception |
||||
*/ |
||||
protected abstract String getCommand(); |
||||
|
||||
/** |
||||
* set main jar name |
||||
*/ |
||||
protected abstract void setMainJarName(); |
||||
} |
@ -0,0 +1,30 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.api; |
||||
|
||||
public class ArgsUtils { |
||||
|
||||
private ArgsUtils() throws IllegalStateException { |
||||
throw new IllegalStateException("Utility class"); |
||||
} |
||||
|
||||
public static String escape(String arg) { |
||||
return arg.replace(" ", "\\ ").replace("\"", "\\\"").replace("'", "\\'"); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,123 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.api; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.Optional; |
||||
import java.util.regex.Matcher; |
||||
import java.util.regex.Pattern; |
||||
|
||||
import org.slf4j.Logger; |
||||
|
||||
/** |
||||
* logger utils |
||||
*/ |
||||
public class LoggerUtils { |
||||
|
||||
private static final String APPLICATION_REGEX_NAME = "application_\\d+_\\d+"; |
||||
|
||||
private LoggerUtils() { |
||||
throw new UnsupportedOperationException("Construct LoggerUtils"); |
||||
} |
||||
|
||||
/** |
||||
* rules for extracting application ID |
||||
*/ |
||||
private static final Pattern APPLICATION_REGEX = Pattern.compile(APPLICATION_REGEX_NAME); |
||||
|
||||
/** |
||||
* Task Logger's prefix |
||||
*/ |
||||
public static final String TASK_LOGGER_INFO_PREFIX = "TASK"; |
||||
|
||||
/** |
||||
* Task Logger Thread's name |
||||
*/ |
||||
public static final String TASK_LOGGER_THREAD_NAME = "TaskLogInfo"; |
||||
|
||||
/** |
||||
* Task Logger Thread's name |
||||
*/ |
||||
public static final String TASK_APPID_LOG_FORMAT = "[taskAppId="; |
||||
|
||||
/** |
||||
* build job id |
||||
* |
||||
* @param affix Task Logger's prefix |
||||
* @param processDefId process define id |
||||
* @param processInstId process instance id |
||||
* @param taskId task id |
||||
* @return task id format |
||||
*/ |
||||
public static String buildTaskId(String affix, |
||||
int processDefId, |
||||
int processInstId, |
||||
int taskId) { |
||||
// - [taskAppId=TASK_79_4084_15210]
|
||||
return String.format(" - %s%s-%s-%s-%s]", TASK_APPID_LOG_FORMAT, affix, |
||||
processDefId, |
||||
processInstId, |
||||
taskId); |
||||
} |
||||
|
||||
/** |
||||
* processing log |
||||
* get yarn application id list |
||||
* |
||||
* @param log log content |
||||
* @param logger logger |
||||
* @return app id list |
||||
*/ |
||||
public static List<String> getAppIds(String log, Logger logger) { |
||||
|
||||
List<String> appIds = new ArrayList<>(); |
||||
|
||||
Matcher matcher = APPLICATION_REGEX.matcher(log); |
||||
|
||||
// analyse logs to get all submit yarn application id
|
||||
while (matcher.find()) { |
||||
String appId = matcher.group(); |
||||
if (!appIds.contains(appId)) { |
||||
logger.info("find app id: {}", appId); |
||||
appIds.add(appId); |
||||
} |
||||
} |
||||
return appIds; |
||||
} |
||||
|
||||
public static void logError(Optional<Logger> optionalLogger |
||||
, String error) { |
||||
optionalLogger.ifPresent((Logger logger) -> logger.error(error)); |
||||
} |
||||
|
||||
public static void logError(Optional<Logger> optionalLogger |
||||
, Throwable e) { |
||||
optionalLogger.ifPresent((Logger logger) -> logger.error(e.getMessage(), e)); |
||||
} |
||||
|
||||
public static void logError(Optional<Logger> optionalLogger |
||||
, String error, Throwable e) { |
||||
optionalLogger.ifPresent((Logger logger) -> logger.error(error, e)); |
||||
} |
||||
|
||||
public static void logInfo(Optional<Logger> optionalLogger |
||||
, String info) { |
||||
optionalLogger.ifPresent((Logger logger) -> logger.info(info)); |
||||
} |
||||
} |
@ -0,0 +1,90 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.api; |
||||
|
||||
import org.apache.dolphinscheduler.spi.utils.StringUtils; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.StringTokenizer; |
||||
|
||||
public class OSUtils { |
||||
|
||||
private OSUtils() { |
||||
throw new IllegalStateException("Utility class"); |
||||
} |
||||
|
||||
/** |
||||
* get sudo command |
||||
* |
||||
* @param tenantCode tenantCode |
||||
* @param command command |
||||
* @return result of sudo execute command |
||||
*/ |
||||
public static String getSudoCmd(String tenantCode, String command) { |
||||
return StringUtils.isEmpty(tenantCode) ? command : "sudo -u " + tenantCode + " " + command; |
||||
} |
||||
|
||||
/** |
||||
* whether is macOS |
||||
* |
||||
* @return true if mac |
||||
*/ |
||||
public static boolean isMacOS() { |
||||
return getOSName().startsWith("Mac"); |
||||
} |
||||
|
||||
/** |
||||
* whether is windows |
||||
* |
||||
* @return true if windows |
||||
*/ |
||||
public static boolean isWindows() { |
||||
return getOSName().startsWith("Windows"); |
||||
} |
||||
|
||||
/** |
||||
* Execute the corresponding command of Linux or Windows |
||||
* |
||||
* @param command command |
||||
* @return result of execute command |
||||
* @throws IOException errors |
||||
*/ |
||||
public static String exeCmd(String command) throws IOException { |
||||
StringTokenizer st = new StringTokenizer(command); |
||||
String[] cmdArray = new String[st.countTokens()]; |
||||
for (int i = 0; st.hasMoreTokens(); i++) { |
||||
cmdArray[i] = st.nextToken(); |
||||
} |
||||
return exeShell(cmdArray); |
||||
} |
||||
|
||||
/** |
||||
* Execute the shell |
||||
* |
||||
* @param command command |
||||
* @return result of execute the shell |
||||
* @throws IOException errors |
||||
*/ |
||||
public static String exeShell(String[] command) throws IOException { |
||||
return ShellExecutor.execCommand(command); |
||||
} |
||||
|
||||
public static String getOSName() { |
||||
return System.getProperty("os.name"); |
||||
} |
||||
} |
@ -0,0 +1,335 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.api; |
||||
|
||||
import org.apache.dolphinscheduler.spi.task.TaskConstants; |
||||
import org.apache.dolphinscheduler.spi.task.TaskRequest; |
||||
|
||||
import java.io.File; |
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
import java.util.regex.Matcher; |
||||
import java.util.regex.Pattern; |
||||
|
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
public class ProcessUtils { |
||||
|
||||
private ProcessUtils() { |
||||
throw new IllegalStateException("Utility class"); |
||||
} |
||||
|
||||
/** |
||||
* logger |
||||
*/ |
||||
private static final Logger logger = LoggerFactory.getLogger(ProcessUtils.class); |
||||
|
||||
/** |
||||
* Initialization regularization, solve the problem of pre-compilation performance, |
||||
* avoid the thread safety problem of multi-thread operation |
||||
*/ |
||||
private static final Pattern MACPATTERN = Pattern.compile("-[+|-]-\\s(\\d+)"); |
||||
|
||||
/** |
||||
* Expression of PID recognition in Windows scene |
||||
*/ |
||||
private static final Pattern WINDOWSATTERN = Pattern.compile("(\\d+)"); |
||||
|
||||
private static final String LOCAL_PROCESS_EXEC = "jdk.lang.Process.allowAmbiguousCommands"; |
||||
|
||||
/** |
||||
* verification cmd bat. |
||||
*/ |
||||
private static final int VERIFICATION_CMD_BAT = 0; |
||||
|
||||
/** |
||||
* verification legacy. |
||||
*/ |
||||
private static final int VERIFICATION_LEGACY = 2; |
||||
|
||||
/** |
||||
* escape verification. |
||||
*/ |
||||
private static final char[][] ESCAPE_VERIFICATION = {{' ', '\t', '<', '>', '&', '|', '^'}, {' ', '\t', '<', '>'}, {' ', '\t'}}; |
||||
|
||||
/** |
||||
* verification win32. |
||||
*/ |
||||
private static final int VERIFICATION_WIN32 = 1; |
||||
|
||||
/** |
||||
* Lazy Pattern. |
||||
*/ |
||||
private static class LazyPattern { |
||||
/** |
||||
* Escape-support version: |
||||
* "(\")((?:\\\\\\1|.)+?)\\1|([^\\s\"]+)"; |
||||
*/ |
||||
private static final Pattern PATTERN = Pattern.compile("[^\\s\"]+|\"[^\"]*\""); |
||||
} |
||||
|
||||
/** |
||||
* build command line characters. |
||||
* |
||||
* @param commandList command list |
||||
* @return command |
||||
*/ |
||||
public static String buildCommandStr(List<String> commandList) { |
||||
String cmdstr; |
||||
String[] cmd = commandList.toArray(new String[0]); |
||||
SecurityManager security = System.getSecurityManager(); |
||||
boolean allowAmbiguousCommands = isAllowAmbiguousCommands(security); |
||||
if (allowAmbiguousCommands) { |
||||
|
||||
String executablePath = new File(cmd[0]).getPath(); |
||||
|
||||
if (needsEscaping(VERIFICATION_LEGACY, executablePath)) { |
||||
executablePath = quoteString(executablePath); |
||||
} |
||||
|
||||
cmdstr = createCommandLine( |
||||
VERIFICATION_LEGACY, executablePath, cmd); |
||||
} else { |
||||
String executablePath; |
||||
try { |
||||
executablePath = getExecutablePath(cmd[0]); |
||||
} catch (IllegalArgumentException e) { |
||||
|
||||
StringBuilder join = new StringBuilder(); |
||||
for (String s : cmd) { |
||||
join.append(s).append(' '); |
||||
} |
||||
|
||||
cmd = getTokensFromCommand(join.toString()); |
||||
executablePath = getExecutablePath(cmd[0]); |
||||
|
||||
// Check new executable name once more
|
||||
if (security != null) { |
||||
security.checkExec(executablePath); |
||||
} |
||||
} |
||||
|
||||
cmdstr = createCommandLine( |
||||
|
||||
isShellFile(executablePath) ? VERIFICATION_CMD_BAT : VERIFICATION_WIN32, quoteString(executablePath), cmd); |
||||
} |
||||
return cmdstr; |
||||
} |
||||
|
||||
/** |
||||
* whether is shell file. |
||||
* |
||||
* @param executablePath executable path |
||||
* @return true if endsWith .CMD or .BAT |
||||
*/ |
||||
private static boolean isShellFile(String executablePath) { |
||||
String upPath = executablePath.toUpperCase(); |
||||
return (upPath.endsWith(".CMD") || upPath.endsWith(".BAT")); |
||||
} |
||||
|
||||
/** |
||||
* create command line. |
||||
* |
||||
* @param verificationType verification type |
||||
* @param executablePath executable path |
||||
* @param cmd cmd |
||||
* @return command line |
||||
*/ |
||||
private static String createCommandLine(int verificationType, final String executablePath, final String[] cmd) { |
||||
StringBuilder cmdbuf = new StringBuilder(80); |
||||
|
||||
cmdbuf.append(executablePath); |
||||
|
||||
for (int i = 1; i < cmd.length; ++i) { |
||||
cmdbuf.append(' '); |
||||
String s = cmd[i]; |
||||
if (needsEscaping(verificationType, s)) { |
||||
cmdbuf.append('"').append(s); |
||||
|
||||
if ((verificationType != VERIFICATION_CMD_BAT) && s.endsWith("\\")) { |
||||
cmdbuf.append('\\'); |
||||
} |
||||
cmdbuf.append('"'); |
||||
} else { |
||||
cmdbuf.append(s); |
||||
} |
||||
} |
||||
return cmdbuf.toString(); |
||||
} |
||||
|
||||
/** |
||||
* check is allow ambiguous commands |
||||
* |
||||
* @param security security manager |
||||
* @return allow ambiguous command flag |
||||
*/ |
||||
private static boolean isAllowAmbiguousCommands(SecurityManager security) { |
||||
boolean allowAmbiguousCommands = false; |
||||
if (security == null) { |
||||
allowAmbiguousCommands = true; |
||||
String value = System.getProperty(LOCAL_PROCESS_EXEC); |
||||
if (value != null) { |
||||
allowAmbiguousCommands = !TaskConstants.STRING_FALSE.equalsIgnoreCase(value); |
||||
} |
||||
} |
||||
return allowAmbiguousCommands; |
||||
} |
||||
|
||||
/** |
||||
* whether needs escaping. |
||||
* |
||||
* @param verificationType verification type |
||||
* @param arg arg |
||||
* @return boolean |
||||
*/ |
||||
private static boolean needsEscaping(int verificationType, String arg) { |
||||
|
||||
boolean argIsQuoted = isQuoted((verificationType == VERIFICATION_CMD_BAT), arg, "Argument has embedded quote, use the explicit CMD.EXE call."); |
||||
|
||||
if (!argIsQuoted) { |
||||
char[] testEscape = ESCAPE_VERIFICATION[verificationType]; |
||||
for (char c : testEscape) { |
||||
if (arg.indexOf(c) >= 0) { |
||||
return true; |
||||
} |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* whether is quoted. |
||||
* |
||||
* @param noQuotesInside no quotes inside |
||||
* @param arg arg |
||||
* @param errorMessage error message |
||||
* @return boolean |
||||
*/ |
||||
private static boolean isQuoted(boolean noQuotesInside, String arg, String errorMessage) { |
||||
int lastPos = arg.length() - 1; |
||||
if (lastPos >= 1 && arg.charAt(0) == '"' && arg.charAt(lastPos) == '"') { |
||||
// The argument has already been quoted.
|
||||
if (noQuotesInside && arg.indexOf('"', 1) != lastPos) { |
||||
// There is ["] inside.
|
||||
throw new IllegalArgumentException(errorMessage); |
||||
} |
||||
return true; |
||||
} |
||||
if (noQuotesInside && arg.indexOf('"') >= 0) { |
||||
// There is ["] inside.
|
||||
throw new IllegalArgumentException(errorMessage); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* quote string. |
||||
* |
||||
* @param arg argument |
||||
* @return format arg |
||||
*/ |
||||
private static String quoteString(String arg) { |
||||
return '"' + arg + '"'; |
||||
} |
||||
|
||||
/** |
||||
* get executable path. |
||||
* |
||||
* @param path path |
||||
* @return executable path |
||||
*/ |
||||
private static String getExecutablePath(String path) { |
||||
boolean pathIsQuoted = isQuoted(true, path, "Executable name has embedded quote, split the arguments"); |
||||
|
||||
File fileToRun = new File(pathIsQuoted ? path.substring(1, path.length() - 1) : path); |
||||
return fileToRun.getPath(); |
||||
} |
||||
|
||||
/** |
||||
* get tokens from command. |
||||
* |
||||
* @param command command |
||||
* @return token string array |
||||
*/ |
||||
private static String[] getTokensFromCommand(String command) { |
||||
ArrayList<String> matchList = new ArrayList<>(8); |
||||
Matcher regexMatcher = LazyPattern.PATTERN.matcher(command); |
||||
while (regexMatcher.find()) { |
||||
matchList.add(regexMatcher.group()); |
||||
} |
||||
return matchList.toArray(new String[0]); |
||||
} |
||||
|
||||
/** |
||||
* kill tasks according to different task types. |
||||
*/ |
||||
public static void kill(TaskRequest request) { |
||||
try { |
||||
int processId = request.getProcessId(); |
||||
if (processId == 0) { |
||||
logger.error("process kill failed, process id :{}, task id:{}", |
||||
processId, request.getTaskInstanceId()); |
||||
return; |
||||
} |
||||
|
||||
String cmd = String.format("kill -9 %s", getPidsStr(processId)); |
||||
cmd = OSUtils.getSudoCmd(request.getTenantCode(), cmd); |
||||
logger.info("process id:{}, cmd:{}", processId, cmd); |
||||
|
||||
OSUtils.exeCmd(cmd); |
||||
|
||||
// find log and kill yarn job
|
||||
// killYarnJob(request);
|
||||
|
||||
} catch (Exception e) { |
||||
logger.error("kill task failed", e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* get pids str. |
||||
* |
||||
* @param processId process id |
||||
* @return pids pid String |
||||
* @throws Exception exception |
||||
*/ |
||||
public static String getPidsStr(int processId) throws Exception { |
||||
StringBuilder sb = new StringBuilder(); |
||||
Matcher mat = null; |
||||
// pstree pid get sub pids
|
||||
if (OSUtils.isMacOS()) { |
||||
String pids = OSUtils.exeCmd(String.format("%s -sp %d", TaskConstants.PSTREE, processId)); |
||||
if (null != pids) { |
||||
mat = MACPATTERN.matcher(pids); |
||||
} |
||||
} else { |
||||
String pids = OSUtils.exeCmd(String.format("%s -p %d", TaskConstants.PSTREE, processId)); |
||||
mat = WINDOWSATTERN.matcher(pids); |
||||
} |
||||
|
||||
if (null != mat) { |
||||
while (mat.find()) { |
||||
sb.append(mat.group(1)).append(" "); |
||||
} |
||||
} |
||||
|
||||
return sb.toString().trim(); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,125 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.api; |
||||
|
||||
import org.apache.dolphinscheduler.spi.task.TaskRequest; |
||||
|
||||
import org.apache.commons.io.FileUtils; |
||||
|
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
import java.nio.charset.StandardCharsets; |
||||
import java.nio.file.Files; |
||||
import java.nio.file.Paths; |
||||
import java.util.List; |
||||
import java.util.function.Consumer; |
||||
|
||||
import org.slf4j.Logger; |
||||
|
||||
/** |
||||
* shell command executor |
||||
*/ |
||||
public class ShellCommandExecutor extends AbstractCommandExecutor { |
||||
|
||||
/** |
||||
* For Unix-like, using sh |
||||
*/ |
||||
private static final String SH = "sh"; |
||||
|
||||
/** |
||||
* For Windows, using cmd.exe |
||||
*/ |
||||
private static final String CMD = "cmd.exe"; |
||||
|
||||
/** |
||||
* constructor |
||||
* |
||||
* @param logHandler logHandler |
||||
* @param taskRequest taskRequest |
||||
* @param logger logger |
||||
*/ |
||||
public ShellCommandExecutor(Consumer<List<String>> logHandler, |
||||
TaskRequest taskRequest, |
||||
Logger logger) { |
||||
super(logHandler, taskRequest, logger); |
||||
} |
||||
|
||||
public ShellCommandExecutor(List<String> logBuffer) { |
||||
super(logBuffer); |
||||
} |
||||
|
||||
@Override |
||||
protected String buildCommandFilePath() { |
||||
// command file
|
||||
return String.format("%s/%s.%s" |
||||
, taskRequest.getExecutePath() |
||||
, taskRequest.getTaskAppId() |
||||
, OSUtils.isWindows() ? "bat" : "command"); |
||||
} |
||||
|
||||
/** |
||||
* get command type |
||||
* |
||||
* @return command type |
||||
*/ |
||||
@Override |
||||
protected String commandInterpreter() { |
||||
return OSUtils.isWindows() ? CMD : SH; |
||||
} |
||||
|
||||
/** |
||||
* create command file if not exists |
||||
* |
||||
* @param execCommand exec command |
||||
* @param commandFile command file |
||||
* @throws IOException io exception |
||||
*/ |
||||
@Override |
||||
protected void createCommandFileIfNotExists(String execCommand, String commandFile) throws IOException { |
||||
logger.info("tenantCode user:{}, task dir:{}", taskRequest.getTenantCode(), |
||||
taskRequest.getTaskAppId()); |
||||
|
||||
// create if non existence
|
||||
if (!Files.exists(Paths.get(commandFile))) { |
||||
logger.info("create command file:{}", commandFile); |
||||
|
||||
StringBuilder sb = new StringBuilder(); |
||||
if (OSUtils.isWindows()) { |
||||
sb.append("@echo off\n"); |
||||
sb.append("cd /d %~dp0\n"); |
||||
if (taskRequest.getEnvFile() != null) { |
||||
sb.append("call ").append(taskRequest.getEnvFile()).append("\n"); |
||||
} |
||||
} else { |
||||
sb.append("#!/bin/sh\n"); |
||||
sb.append("BASEDIR=$(cd `dirname $0`; pwd)\n"); |
||||
sb.append("cd $BASEDIR\n"); |
||||
if (taskRequest.getEnvFile() != null) { |
||||
sb.append("source ").append(taskRequest.getEnvFile()).append("\n"); |
||||
} |
||||
} |
||||
|
||||
sb.append(execCommand); |
||||
logger.info("command : {}", sb); |
||||
|
||||
// write data to file
|
||||
FileUtils.writeStringToFile(new File(commandFile), sb.toString(), StandardCharsets.UTF_8); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,179 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.api; |
||||
|
||||
import java.io.BufferedReader; |
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* shell command executor. |
||||
* |
||||
* <code>ShellExecutor</code> should be used in cases where the output |
||||
* of the command needs no explicit parsing and where the command, working |
||||
* directory and the environment remains unchanged. The output of the command |
||||
* is stored as-is and is expected to be small. |
||||
*/ |
||||
public class ShellExecutor extends AbstractShell { |
||||
|
||||
private String[] command; |
||||
private StringBuilder output; |
||||
|
||||
public ShellExecutor(String... execString) { |
||||
this(execString, null); |
||||
} |
||||
|
||||
public ShellExecutor(String[] execString, File dir) { |
||||
this(execString, dir, null); |
||||
} |
||||
|
||||
public ShellExecutor(String[] execString, File dir, |
||||
Map<String, String> env) { |
||||
this(execString, dir, env, 0L); |
||||
} |
||||
|
||||
/** |
||||
* Create a new instance of the ShellExecutor to execute a command. |
||||
* |
||||
* @param execString The command to execute with arguments |
||||
* @param dir If not-null, specifies the directory which should be set |
||||
* as the current working directory for the command. |
||||
* If null, the current working directory is not modified. |
||||
* @param env If not-null, environment of the command will include the |
||||
* key-value pairs specified in the map. If null, the current |
||||
* environment is not modified. |
||||
* @param timeout Specifies the time in milliseconds, after which the |
||||
* command will be killed and the status marked as timedout. |
||||
* If 0, the command will not be timed out. |
||||
*/ |
||||
public ShellExecutor(String[] execString, File dir, |
||||
Map<String, String> env, long timeout) { |
||||
command = execString.clone(); |
||||
if (dir != null) { |
||||
setWorkingDirectory(dir); |
||||
} |
||||
if (env != null) { |
||||
setEnvironment(env); |
||||
} |
||||
timeOutInterval = timeout; |
||||
} |
||||
|
||||
/** |
||||
* Static method to execute a shell command. |
||||
* Covers most of the simple cases without requiring the user to implement |
||||
* the <code>AbstractShell</code> interface. |
||||
* |
||||
* @param cmd shell command to execute. |
||||
* @return the output of the executed command. |
||||
* @throws IOException errors |
||||
*/ |
||||
public static String execCommand(String... cmd) throws IOException { |
||||
return execCommand(null, cmd, 0L); |
||||
} |
||||
|
||||
/** |
||||
* Static method to execute a shell command. |
||||
* Covers most of the simple cases without requiring the user to implement |
||||
* the <code>AbstractShell</code> interface. |
||||
* |
||||
* @param env the map of environment key=value |
||||
* @param cmd shell command to execute. |
||||
* @param timeout time in milliseconds after which script should be marked timeout |
||||
* @return the output of the executed command. |
||||
* @throws IOException errors |
||||
*/ |
||||
public static String execCommand(Map<String, String> env, String[] cmd, |
||||
long timeout) throws IOException { |
||||
ShellExecutor exec = new ShellExecutor(cmd, null, env, |
||||
timeout); |
||||
exec.execute(); |
||||
return exec.getOutput(); |
||||
} |
||||
|
||||
/** |
||||
* Static method to execute a shell command. |
||||
* Covers most of the simple cases without requiring the user to implement |
||||
* the <code>AbstractShell</code> interface. |
||||
* |
||||
* @param env the map of environment key=value |
||||
* @param cmd shell command to execute. |
||||
* @return the output of the executed command. |
||||
* @throws IOException errors |
||||
*/ |
||||
public static String execCommand(Map<String, String> env, String... cmd) |
||||
throws IOException { |
||||
return execCommand(env, cmd, 0L); |
||||
} |
||||
|
||||
/** |
||||
* Execute the shell command |
||||
* |
||||
* @throws IOException errors |
||||
*/ |
||||
public void execute() throws IOException { |
||||
this.run(); |
||||
} |
||||
|
||||
@Override |
||||
protected String[] getExecString() { |
||||
return command; |
||||
} |
||||
|
||||
@Override |
||||
protected void parseExecResult(BufferedReader lines) throws IOException { |
||||
output = new StringBuilder(); |
||||
char[] buf = new char[1024]; |
||||
int nRead; |
||||
String line = ""; |
||||
while ((nRead = lines.read(buf, 0, buf.length)) > 0) { |
||||
line = new String(buf, 0, nRead); |
||||
output.append(line); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @return the output of the shell command |
||||
*/ |
||||
public String getOutput() { |
||||
return (output == null) ? "" : output.toString(); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Returns the commands of this instance. |
||||
* Arguments with spaces in are presented with quotes round; other |
||||
* arguments are presented raw |
||||
* |
||||
* @return a string representation of the object |
||||
*/ |
||||
@Override |
||||
public String toString() { |
||||
StringBuilder builder = new StringBuilder(); |
||||
String[] args = getExecString(); |
||||
for (String s : args) { |
||||
if (s.indexOf(' ') >= 0) { |
||||
builder.append('"').append(s).append('"'); |
||||
} else { |
||||
builder.append(s); |
||||
} |
||||
builder.append(' '); |
||||
} |
||||
return builder.toString(); |
||||
} |
||||
} |
@ -0,0 +1,35 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.api; |
||||
|
||||
public class TaskException extends RuntimeException { |
||||
|
||||
private static final long serialVersionUID = 8155449302457294758L; |
||||
|
||||
public TaskException() { |
||||
super(); |
||||
} |
||||
|
||||
public TaskException(String msg, Throwable cause) { |
||||
super(msg, cause); |
||||
} |
||||
|
||||
public TaskException(String msg) { |
||||
super(msg); |
||||
} |
||||
} |
@ -0,0 +1,69 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.api; |
||||
|
||||
import org.apache.dolphinscheduler.spi.task.TaskRequest; |
||||
|
||||
import java.util.Map; |
||||
import java.util.concurrent.ConcurrentHashMap; |
||||
|
||||
public class TaskExecutionContextCacheManager { |
||||
|
||||
private TaskExecutionContextCacheManager() { |
||||
throw new IllegalStateException("Utility class"); |
||||
} |
||||
|
||||
/** |
||||
* taskInstance cache |
||||
*/ |
||||
private static Map<Integer, TaskRequest> taskRequestContextCache = new ConcurrentHashMap<>(); |
||||
|
||||
/** |
||||
* get taskInstance by taskInstance id |
||||
* |
||||
* @param taskInstanceId taskInstanceId |
||||
* @return taskInstance |
||||
*/ |
||||
|
||||
public static TaskRequest getByTaskInstanceId(Integer taskInstanceId) { |
||||
return taskRequestContextCache.get(taskInstanceId); |
||||
} |
||||
|
||||
/** |
||||
* cache taskInstance |
||||
* |
||||
* @param request request |
||||
*/ |
||||
public static void cacheTaskExecutionContext(TaskRequest request) { |
||||
taskRequestContextCache.put(request.getTaskInstanceId(), request); |
||||
} |
||||
|
||||
/** |
||||
* remove taskInstance by taskInstanceId |
||||
* |
||||
* @param taskInstanceId taskInstanceId |
||||
*/ |
||||
public static void removeByTaskInstanceId(Integer taskInstanceId) { |
||||
taskRequestContextCache.remove(taskInstanceId); |
||||
} |
||||
|
||||
public static boolean updateTaskExecutionContext(TaskRequest request) { |
||||
taskRequestContextCache.computeIfPresent(request.getTaskInstanceId(), (k, v) -> request); |
||||
return taskRequestContextCache.containsKey(request.getTaskInstanceId()); |
||||
} |
||||
} |
@ -0,0 +1,124 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.api; |
||||
|
||||
public class TaskResponse { |
||||
|
||||
/** |
||||
* varPool string |
||||
*/ |
||||
private String varPool; |
||||
|
||||
/** |
||||
* SHELL process pid |
||||
*/ |
||||
private int processId; |
||||
|
||||
/** |
||||
* SHELL result string |
||||
*/ |
||||
private String resultString; |
||||
|
||||
/** |
||||
* other resource manager appId , for example : YARN etc |
||||
*/ |
||||
private String appIds; |
||||
|
||||
/** |
||||
* process |
||||
*/ |
||||
private Process process; |
||||
|
||||
|
||||
|
||||
/** |
||||
* cancel |
||||
*/ |
||||
private volatile boolean cancel = false; |
||||
|
||||
/** |
||||
* exit code |
||||
*/ |
||||
private volatile int exitStatusCode = -1; |
||||
|
||||
private TaskRunStatus status; |
||||
|
||||
public String getVarPool() { |
||||
return varPool; |
||||
} |
||||
|
||||
public void setVarPool(String varPool) { |
||||
this.varPool = varPool; |
||||
} |
||||
|
||||
public int getProcessId() { |
||||
return processId; |
||||
} |
||||
|
||||
public void setProcessId(int processId) { |
||||
this.processId = processId; |
||||
} |
||||
|
||||
public String getResultString() { |
||||
return resultString; |
||||
} |
||||
|
||||
public void setResultString(String resultString) { |
||||
this.resultString = resultString; |
||||
} |
||||
|
||||
public String getAppIds() { |
||||
return appIds; |
||||
} |
||||
|
||||
public void setAppIds(String appIds) { |
||||
this.appIds = appIds; |
||||
} |
||||
|
||||
public boolean isCancel() { |
||||
return cancel; |
||||
} |
||||
|
||||
public void setCancel(boolean cancel) { |
||||
this.cancel = cancel; |
||||
} |
||||
|
||||
public int getExitStatusCode() { |
||||
return exitStatusCode; |
||||
} |
||||
|
||||
public void setExitStatusCode(int exitStatusCode) { |
||||
this.exitStatusCode = exitStatusCode; |
||||
} |
||||
|
||||
public Process getProcess() { |
||||
return process; |
||||
} |
||||
|
||||
public void setProcess(Process process) { |
||||
this.process = process; |
||||
} |
||||
|
||||
public TaskRunStatus getStatus() { |
||||
return status; |
||||
} |
||||
|
||||
public void setStatus(TaskRunStatus status) { |
||||
this.status = status; |
||||
} |
||||
} |
@ -0,0 +1,26 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.api; |
||||
|
||||
public enum TaskRunStatus { |
||||
|
||||
SUCCESS, |
||||
FAIL_AND_NEED_KILL, |
||||
FAIL; |
||||
|
||||
} |
@ -0,0 +1,257 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.api; |
||||
|
||||
import java.lang.management.ManagementFactory; |
||||
import java.lang.management.ThreadInfo; |
||||
import java.lang.management.ThreadMXBean; |
||||
import java.util.concurrent.ExecutorService; |
||||
import java.util.concurrent.Executors; |
||||
import java.util.concurrent.LinkedBlockingQueue; |
||||
import java.util.concurrent.ScheduledExecutorService; |
||||
import java.util.concurrent.ScheduledThreadPoolExecutor; |
||||
import java.util.concurrent.ThreadFactory; |
||||
import java.util.concurrent.ThreadPoolExecutor; |
||||
import java.util.concurrent.TimeUnit; |
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder; |
||||
|
||||
/** |
||||
* thread utils |
||||
*/ |
||||
public class ThreadUtils { |
||||
|
||||
private ThreadUtils() { |
||||
throw new IllegalStateException("Utility class"); |
||||
} |
||||
|
||||
private static final ThreadMXBean threadBean = ManagementFactory.getThreadMXBean(); |
||||
private static final int STACK_DEPTH = 20; |
||||
|
||||
/** |
||||
* Wrapper over newCachedThreadPool. Thread names are formatted as prefix-ID, where ID is a |
||||
* unique, sequentially assigned integer. |
||||
* |
||||
* @param prefix prefix |
||||
* @return ThreadPoolExecutor |
||||
*/ |
||||
public static ThreadPoolExecutor newDaemonCachedThreadPool(String prefix) { |
||||
ThreadFactory threadFactory = namedThreadFactory(prefix); |
||||
return ((ThreadPoolExecutor) Executors.newCachedThreadPool(threadFactory)); |
||||
} |
||||
|
||||
/** |
||||
* Create a thread factory that names threads with a prefix and also sets the threads to daemon. |
||||
* |
||||
* @param prefix prefix |
||||
* @return ThreadFactory |
||||
*/ |
||||
private static ThreadFactory namedThreadFactory(String prefix) { |
||||
return new ThreadFactoryBuilder().setDaemon(true).setNameFormat(prefix + "-%d").build(); |
||||
} |
||||
|
||||
/** |
||||
* Create a cached thread pool whose max number of threads is `maxThreadNumber`. Thread names |
||||
* are formatted as prefix-ID, where ID is a unique, sequentially assigned integer. |
||||
* |
||||
* @param prefix prefix |
||||
* @param maxThreadNumber maxThreadNumber |
||||
* @param keepAliveSeconds keepAliveSeconds |
||||
* @return ThreadPoolExecutor |
||||
*/ |
||||
public static ThreadPoolExecutor newDaemonCachedThreadPool(String prefix, |
||||
int maxThreadNumber, |
||||
int keepAliveSeconds) { |
||||
ThreadFactory threadFactory = namedThreadFactory(prefix); |
||||
ThreadPoolExecutor threadPool = new ThreadPoolExecutor( |
||||
// corePoolSize: the max number of threads to create before queuing the tasks
|
||||
maxThreadNumber, |
||||
// maximumPoolSize: because we use LinkedBlockingDeque, this one is not used
|
||||
maxThreadNumber, |
||||
keepAliveSeconds, |
||||
TimeUnit.SECONDS, |
||||
new LinkedBlockingQueue<>(), |
||||
threadFactory); |
||||
threadPool.allowCoreThreadTimeOut(true); |
||||
return threadPool; |
||||
} |
||||
|
||||
/** |
||||
* Wrapper over newFixedThreadPool. Thread names are formatted as prefix-ID, where ID is a |
||||
* unique, sequentially assigned integer. |
||||
* |
||||
* @param nThreads nThreads |
||||
* @param prefix prefix |
||||
* @return ThreadPoolExecutor |
||||
*/ |
||||
public static ThreadPoolExecutor newDaemonFixedThreadPool(int nThreads, String prefix) { |
||||
ThreadFactory threadFactory = namedThreadFactory(prefix); |
||||
return ((ThreadPoolExecutor) Executors.newFixedThreadPool(nThreads, threadFactory)); |
||||
} |
||||
|
||||
/** |
||||
* Wrapper over newSingleThreadExecutor. |
||||
* |
||||
* @param threadName threadName |
||||
* @return ExecutorService |
||||
*/ |
||||
public static ExecutorService newDaemonSingleThreadExecutor(String threadName) { |
||||
ThreadFactory threadFactory = new ThreadFactoryBuilder() |
||||
.setDaemon(true) |
||||
.setNameFormat(threadName) |
||||
.build(); |
||||
return Executors.newSingleThreadExecutor(threadFactory); |
||||
} |
||||
|
||||
/** |
||||
* Wrapper over newDaemonFixedThreadExecutor. |
||||
* |
||||
* @param threadName threadName |
||||
* @param threadsNum threadsNum |
||||
* @return ExecutorService |
||||
*/ |
||||
public static ExecutorService newDaemonFixedThreadExecutor(String threadName, int threadsNum) { |
||||
ThreadFactory threadFactory = new ThreadFactoryBuilder() |
||||
.setDaemon(true) |
||||
.setNameFormat(threadName) |
||||
.build(); |
||||
return Executors.newFixedThreadPool(threadsNum, threadFactory); |
||||
} |
||||
|
||||
/** |
||||
* Wrapper over ScheduledThreadPoolExecutor |
||||
* |
||||
* @param threadName threadName |
||||
* @param corePoolSize corePoolSize |
||||
* @return ScheduledExecutorService |
||||
*/ |
||||
public static ScheduledExecutorService newDaemonThreadScheduledExecutor(String threadName, int corePoolSize) { |
||||
return newThreadScheduledExecutor(threadName, corePoolSize, true); |
||||
} |
||||
|
||||
/** |
||||
* Wrapper over ScheduledThreadPoolExecutor |
||||
* |
||||
* @param threadName threadName |
||||
* @param corePoolSize corePoolSize |
||||
* @param isDaemon isDaemon |
||||
* @return ScheduledThreadPoolExecutor |
||||
*/ |
||||
public static ScheduledExecutorService newThreadScheduledExecutor(String threadName, int corePoolSize, boolean isDaemon) { |
||||
ThreadFactory threadFactory = new ThreadFactoryBuilder() |
||||
.setDaemon(isDaemon) |
||||
.setNameFormat(threadName) |
||||
.build(); |
||||
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(corePoolSize, threadFactory); |
||||
// By default, a cancelled task is not automatically removed from the work queue until its delay
|
||||
// elapses. We have to enable it manually.
|
||||
executor.setRemoveOnCancelPolicy(true); |
||||
return executor; |
||||
} |
||||
|
||||
/** |
||||
* get thread info |
||||
* |
||||
* @param t t |
||||
* @return thread info |
||||
*/ |
||||
public static ThreadInfo getThreadInfo(Thread t) { |
||||
long tid = t.getId(); |
||||
return threadBean.getThreadInfo(tid, STACK_DEPTH); |
||||
} |
||||
|
||||
/** |
||||
* Format the given ThreadInfo object as a String. |
||||
* |
||||
* @param threadInfo threadInfo |
||||
* @param indent indent |
||||
* @return threadInfo |
||||
*/ |
||||
public static String formatThreadInfo(ThreadInfo threadInfo, String indent) { |
||||
StringBuilder sb = new StringBuilder(); |
||||
appendThreadInfo(sb, threadInfo, indent); |
||||
return sb.toString(); |
||||
} |
||||
|
||||
/** |
||||
* Print all of the thread's information and stack traces. |
||||
* |
||||
* @param sb StringBuilder |
||||
* @param info ThreadInfo |
||||
* @param indent indent |
||||
*/ |
||||
public static void appendThreadInfo(StringBuilder sb, |
||||
ThreadInfo info, |
||||
String indent) { |
||||
boolean contention = threadBean.isThreadContentionMonitoringEnabled(); |
||||
|
||||
if (info == null) { |
||||
sb.append(indent).append("Inactive (perhaps exited while monitoring was done)\n"); |
||||
return; |
||||
} |
||||
String taskName = getTaskName(info.getThreadId(), info.getThreadName()); |
||||
sb.append(indent).append("Thread ").append(taskName).append(":\n"); |
||||
|
||||
Thread.State state = info.getThreadState(); |
||||
sb.append(indent).append(" State: ").append(state).append("\n"); |
||||
sb.append(indent).append(" Blocked count: ").append(info.getBlockedCount()).append("\n"); |
||||
sb.append(indent).append(" Waited count: ").append(info.getWaitedCount()).append("\n"); |
||||
if (contention) { |
||||
sb.append(indent).append(" Blocked time: ").append(info.getBlockedTime()).append("\n"); |
||||
sb.append(indent).append(" Waited time: ").append(info.getWaitedTime()).append("\n"); |
||||
} |
||||
if (state == Thread.State.WAITING) { |
||||
sb.append(indent).append(" Waiting on ").append(info.getLockName()).append("\n"); |
||||
} else if (state == Thread.State.BLOCKED) { |
||||
sb.append(indent).append(" Blocked on ").append(info.getLockName()).append("\n"); |
||||
sb.append(indent).append(" Blocked by ").append( |
||||
getTaskName(info.getLockOwnerId(), info.getLockOwnerName())).append("\n"); |
||||
} |
||||
sb.append(indent).append(" Stack:").append("\n"); |
||||
for (StackTraceElement frame : info.getStackTrace()) { |
||||
sb.append(indent).append(" ").append(frame.toString()).append("\n"); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* getTaskName |
||||
* |
||||
* @param id id |
||||
* @param name name |
||||
* @return task name |
||||
*/ |
||||
private static String getTaskName(long id, String name) { |
||||
if (name == null) { |
||||
return Long.toString(id); |
||||
} |
||||
return id + " (" + name + ")"; |
||||
} |
||||
|
||||
/** |
||||
* sleep |
||||
* |
||||
* @param millis millis |
||||
*/ |
||||
public static void sleep(final long millis) { |
||||
try { |
||||
Thread.sleep(millis); |
||||
} catch (final InterruptedException ignore) { |
||||
Thread.currentThread().interrupt(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,22 @@
|
||||
package org.apache.dolphinscheduler.task.plugin.api;/* |
||||
* 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. |
||||
*/ |
||||
|
||||
public class TaskTest { |
||||
|
||||
|
||||
|
||||
} |
@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!-- |
||||
~ 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. |
||||
--> |
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<parent> |
||||
<artifactId>dolphinscheduler-task-plugin</artifactId> |
||||
<groupId>org.apache.dolphinscheduler</groupId> |
||||
<version>1.3.6-SNAPSHOT</version> |
||||
</parent> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
|
||||
<artifactId>dolphinscheduler-task-flink</artifactId> |
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>org.apache.dolphinscheduler</groupId> |
||||
<artifactId>dolphinscheduler-spi</artifactId> |
||||
<scope>provided</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.apache.dolphinscheduler</groupId> |
||||
<artifactId>dolphinscheduler-task-api</artifactId> |
||||
<version>${project.version}</version> |
||||
</dependency> |
||||
</dependencies> |
||||
|
||||
</project> |
@ -0,0 +1,136 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.flink; |
||||
|
||||
import org.apache.dolphinscheduler.plugin.task.api.ArgsUtils; |
||||
import org.apache.dolphinscheduler.spi.task.ResourceInfo; |
||||
import org.apache.dolphinscheduler.spi.utils.StringUtils; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* flink args utils |
||||
*/ |
||||
public class FlinkArgsUtils { |
||||
|
||||
private FlinkArgsUtils() { |
||||
throw new IllegalStateException("Utility class"); |
||||
} |
||||
|
||||
private static final String LOCAL_DEPLOY_MODE = "local"; |
||||
private static final String FLINK_VERSION_BEFORE_1_10 = "<1.10"; |
||||
|
||||
/** |
||||
* build args |
||||
* |
||||
* @param param flink parameters |
||||
* @return argument list |
||||
*/ |
||||
public static List<String> buildArgs(FlinkParameters param) { |
||||
List<String> args = new ArrayList<>(); |
||||
|
||||
String deployMode = "cluster"; |
||||
String tmpDeployMode = param.getDeployMode(); |
||||
if (StringUtils.isNotEmpty(tmpDeployMode)) { |
||||
deployMode = tmpDeployMode; |
||||
} |
||||
String others = param.getOthers(); |
||||
if (!LOCAL_DEPLOY_MODE.equals(deployMode)) { |
||||
args.add(FlinkConstants.FLINK_RUN_MODE); //-m
|
||||
|
||||
args.add(FlinkConstants.FLINK_YARN_CLUSTER); //yarn-cluster
|
||||
|
||||
int slot = param.getSlot(); |
||||
if (slot > 0) { |
||||
args.add(FlinkConstants.FLINK_YARN_SLOT); |
||||
args.add(String.format("%d", slot)); //-ys
|
||||
} |
||||
|
||||
String appName = param.getAppName(); |
||||
if (StringUtils.isNotEmpty(appName)) { //-ynm
|
||||
args.add(FlinkConstants.FLINK_APP_NAME); |
||||
args.add(ArgsUtils.escape(appName)); |
||||
} |
||||
|
||||
// judge flink version, the parameter -yn has removed from flink 1.10
|
||||
String flinkVersion = param.getFlinkVersion(); |
||||
if (flinkVersion == null || FLINK_VERSION_BEFORE_1_10.equals(flinkVersion)) { |
||||
int taskManager = param.getTaskManager(); |
||||
if (taskManager > 0) { //-yn
|
||||
args.add(FlinkConstants.FLINK_TASK_MANAGE); |
||||
args.add(String.format("%d", taskManager)); |
||||
} |
||||
} |
||||
String jobManagerMemory = param.getJobManagerMemory(); |
||||
if (StringUtils.isNotEmpty(jobManagerMemory)) { |
||||
args.add(FlinkConstants.FLINK_JOB_MANAGE_MEM); |
||||
args.add(jobManagerMemory); //-yjm
|
||||
} |
||||
|
||||
String taskManagerMemory = param.getTaskManagerMemory(); |
||||
if (StringUtils.isNotEmpty(taskManagerMemory)) { // -ytm
|
||||
args.add(FlinkConstants.FLINK_TASK_MANAGE_MEM); |
||||
args.add(taskManagerMemory); |
||||
} |
||||
|
||||
if (StringUtils.isEmpty(others) || !others.contains(FlinkConstants.FLINK_QUEUE)) { |
||||
String queue = param.getQueue(); |
||||
if (StringUtils.isNotEmpty(queue)) { // -yqu
|
||||
args.add(FlinkConstants.FLINK_QUEUE); |
||||
args.add(queue); |
||||
} |
||||
} |
||||
} |
||||
|
||||
int parallelism = param.getParallelism(); |
||||
if (parallelism > 0) { |
||||
args.add(FlinkConstants.FLINK_PARALLELISM); |
||||
args.add(String.format("%d", parallelism)); // -p
|
||||
} |
||||
|
||||
// If the job is submitted in attached mode, perform a best-effort cluster shutdown when the CLI is terminated abruptly
|
||||
// The task status will be synchronized with the cluster job status
|
||||
args.add(FlinkConstants.FLINK_SHUTDOWN_ON_ATTACHED_EXIT); // -sae
|
||||
|
||||
// -s -yqu -yat -yD -D
|
||||
if (StringUtils.isNotEmpty(others)) { |
||||
args.add(others); |
||||
} |
||||
|
||||
ProgramType programType = param.getProgramType(); |
||||
String mainClass = param.getMainClass(); |
||||
if (programType != null && programType != ProgramType.PYTHON && StringUtils.isNotEmpty(mainClass)) { |
||||
args.add(FlinkConstants.FLINK_MAIN_CLASS); //-c
|
||||
args.add(param.getMainClass()); //main class
|
||||
} |
||||
|
||||
ResourceInfo mainJar = param.getMainJar(); |
||||
if (mainJar != null) { |
||||
args.add(mainJar.getRes()); |
||||
} |
||||
|
||||
String mainArgs = param.getMainArgs(); |
||||
if (StringUtils.isNotEmpty(mainArgs)) { |
||||
args.add(mainArgs); |
||||
} |
||||
|
||||
return args; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,42 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.flink; |
||||
|
||||
public class FlinkConstants { |
||||
|
||||
private FlinkConstants() { |
||||
throw new IllegalStateException("Utility class"); |
||||
} |
||||
|
||||
/** |
||||
* flink |
||||
*/ |
||||
public static final String FLINK_YARN_CLUSTER = "yarn-cluster"; |
||||
public static final String FLINK_RUN_MODE = "-m"; |
||||
public static final String FLINK_YARN_SLOT = "-ys"; |
||||
public static final String FLINK_APP_NAME = "-ynm"; |
||||
public static final String FLINK_QUEUE = "-yqu"; |
||||
public static final String FLINK_TASK_MANAGE = "-yn"; |
||||
|
||||
public static final String FLINK_JOB_MANAGE_MEM = "-yjm"; |
||||
public static final String FLINK_TASK_MANAGE_MEM = "-ytm"; |
||||
public static final String FLINK_MAIN_CLASS = "-c"; |
||||
public static final String FLINK_PARALLELISM = "-p"; |
||||
public static final String FLINK_SHUTDOWN_ON_ATTACHED_EXIT = "-sae"; |
||||
|
||||
} |
@ -0,0 +1,240 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.flink; |
||||
|
||||
import org.apache.dolphinscheduler.spi.task.AbstractParameters; |
||||
import org.apache.dolphinscheduler.spi.task.ResourceInfo; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* flink parameters |
||||
*/ |
||||
public class FlinkParameters extends AbstractParameters { |
||||
|
||||
/** |
||||
* major jar |
||||
*/ |
||||
private ResourceInfo mainJar; |
||||
|
||||
/** |
||||
* major class
|
||||
*/ |
||||
private String mainClass; |
||||
|
||||
/** |
||||
* deploy mode yarn-cluster yarn-local |
||||
*/ |
||||
private String deployMode; |
||||
|
||||
/** |
||||
* arguments |
||||
*/ |
||||
private String mainArgs; |
||||
|
||||
/** |
||||
* slot count |
||||
*/ |
||||
private int slot; |
||||
|
||||
/** |
||||
* parallelism |
||||
*/ |
||||
private int parallelism; |
||||
|
||||
/** |
||||
* yarn application name |
||||
*/ |
||||
private String appName; |
||||
|
||||
/** |
||||
* taskManager count |
||||
*/ |
||||
private int taskManager; |
||||
|
||||
/** |
||||
* job manager memory |
||||
*/ |
||||
private String jobManagerMemory; |
||||
|
||||
/** |
||||
* task manager memory |
||||
*/ |
||||
private String taskManagerMemory; |
||||
|
||||
/** |
||||
* resource list |
||||
*/ |
||||
private List<ResourceInfo> resourceList = new ArrayList<>(); |
||||
|
||||
/** |
||||
* The YARN queue to submit to |
||||
*/ |
||||
private String queue; |
||||
|
||||
/** |
||||
* other arguments |
||||
*/ |
||||
private String others; |
||||
|
||||
/** |
||||
* flink version |
||||
*/ |
||||
private String flinkVersion; |
||||
|
||||
/** |
||||
* program type |
||||
* 0 JAVA,1 SCALA,2 PYTHON |
||||
*/ |
||||
private ProgramType programType; |
||||
|
||||
public ResourceInfo getMainJar() { |
||||
return mainJar; |
||||
} |
||||
|
||||
public void setMainJar(ResourceInfo mainJar) { |
||||
this.mainJar = mainJar; |
||||
} |
||||
|
||||
public String getMainClass() { |
||||
return mainClass; |
||||
} |
||||
|
||||
public void setMainClass(String mainClass) { |
||||
this.mainClass = mainClass; |
||||
} |
||||
|
||||
public String getDeployMode() { |
||||
return deployMode; |
||||
} |
||||
|
||||
public void setDeployMode(String deployMode) { |
||||
this.deployMode = deployMode; |
||||
} |
||||
|
||||
public String getMainArgs() { |
||||
return mainArgs; |
||||
} |
||||
|
||||
public void setMainArgs(String mainArgs) { |
||||
this.mainArgs = mainArgs; |
||||
} |
||||
|
||||
public int getSlot() { |
||||
return slot; |
||||
} |
||||
|
||||
public void setSlot(int slot) { |
||||
this.slot = slot; |
||||
} |
||||
|
||||
public int getParallelism() { |
||||
return parallelism; |
||||
} |
||||
|
||||
public void setParallelism(int parallelism) { |
||||
this.parallelism = parallelism; |
||||
} |
||||
|
||||
public String getAppName() { |
||||
return appName; |
||||
} |
||||
|
||||
public void setAppName(String appName) { |
||||
this.appName = appName; |
||||
} |
||||
|
||||
public int getTaskManager() { |
||||
return taskManager; |
||||
} |
||||
|
||||
public void setTaskManager(int taskManager) { |
||||
this.taskManager = taskManager; |
||||
} |
||||
|
||||
public String getJobManagerMemory() { |
||||
return jobManagerMemory; |
||||
} |
||||
|
||||
public void setJobManagerMemory(String jobManagerMemory) { |
||||
this.jobManagerMemory = jobManagerMemory; |
||||
} |
||||
|
||||
public String getTaskManagerMemory() { |
||||
return taskManagerMemory; |
||||
} |
||||
|
||||
public void setTaskManagerMemory(String taskManagerMemory) { |
||||
this.taskManagerMemory = taskManagerMemory; |
||||
} |
||||
|
||||
public String getQueue() { |
||||
return queue; |
||||
} |
||||
|
||||
public void setQueue(String queue) { |
||||
this.queue = queue; |
||||
} |
||||
|
||||
public List<ResourceInfo> getResourceList() { |
||||
return resourceList; |
||||
} |
||||
|
||||
public void setResourceList(List<ResourceInfo> resourceList) { |
||||
this.resourceList = resourceList; |
||||
} |
||||
|
||||
public String getOthers() { |
||||
return others; |
||||
} |
||||
|
||||
public void setOthers(String others) { |
||||
this.others = others; |
||||
} |
||||
|
||||
public ProgramType getProgramType() { |
||||
return programType; |
||||
} |
||||
|
||||
public void setProgramType(ProgramType programType) { |
||||
this.programType = programType; |
||||
} |
||||
|
||||
public String getFlinkVersion() { |
||||
return flinkVersion; |
||||
} |
||||
|
||||
public void setFlinkVersion(String flinkVersion) { |
||||
this.flinkVersion = flinkVersion; |
||||
} |
||||
|
||||
@Override |
||||
public boolean checkParameters() { |
||||
return mainJar != null && programType != null; |
||||
} |
||||
|
||||
@Override |
||||
public List<ResourceInfo> getResourceFilesList() { |
||||
if (mainJar != null && !resourceList.contains(mainJar)) { |
||||
resourceList.add(mainJar); |
||||
} |
||||
return resourceList; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,123 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.flink; |
||||
|
||||
import org.apache.dolphinscheduler.plugin.task.api.AbstractYarnTask; |
||||
import org.apache.dolphinscheduler.plugin.task.api.TaskException; |
||||
import org.apache.dolphinscheduler.spi.task.AbstractParameters; |
||||
import org.apache.dolphinscheduler.spi.task.ResourceInfo; |
||||
import org.apache.dolphinscheduler.spi.task.TaskRequest; |
||||
import org.apache.dolphinscheduler.spi.utils.JSONUtils; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import org.slf4j.Logger; |
||||
|
||||
public class FlinkTask extends AbstractYarnTask { |
||||
|
||||
|
||||
/** |
||||
* flink command |
||||
* usage: flink run [OPTIONS] <jar-file> <arguments> |
||||
*/ |
||||
private static final String FLINK_COMMAND = "flink"; |
||||
private static final String FLINK_RUN = "run"; |
||||
|
||||
/** |
||||
* flink parameters |
||||
*/ |
||||
private FlinkParameters flinkParameters; |
||||
|
||||
private String command; |
||||
|
||||
|
||||
private TaskRequest flinkRequest; |
||||
|
||||
public FlinkTask(TaskRequest taskRequest, Logger logger) { |
||||
super(taskRequest, logger); |
||||
this.flinkRequest = taskRequest; |
||||
} |
||||
|
||||
@Override |
||||
public String getPreScript() { |
||||
|
||||
// flink run [OPTIONS] <jar-file> <arguments>
|
||||
List<String> args = new ArrayList<>(); |
||||
|
||||
args.add(FLINK_COMMAND); |
||||
args.add(FLINK_RUN); |
||||
logger.info("flink task args : {}", args); |
||||
// other parameters
|
||||
args.addAll(FlinkArgsUtils.buildArgs(flinkParameters)); |
||||
return String.join(" ", args); |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void setCommand(String command) { |
||||
this.command = command; |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void init() { |
||||
|
||||
logger.info("flink task params {}", flinkRequest.getTaskParams()); |
||||
|
||||
flinkParameters = JSONUtils.parseObject(flinkRequest.getTaskParams(), FlinkParameters.class); |
||||
|
||||
if (!flinkParameters.checkParameters()) { |
||||
throw new TaskException("flink task params is not valid"); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* create command |
||||
* |
||||
* @return command |
||||
*/ |
||||
@Override |
||||
protected String getCommand() { |
||||
|
||||
return command; |
||||
} |
||||
|
||||
@Override |
||||
protected void setMainJarName() { |
||||
// main jar
|
||||
ResourceInfo mainJar = flinkParameters.getMainJar(); |
||||
if (mainJar != null) { |
||||
int resourceId = mainJar.getId(); |
||||
String resourceName; |
||||
if (resourceId == 0) { |
||||
resourceName = mainJar.getRes(); |
||||
} else { |
||||
//when update resource maybe has error ,也许也可以交给上层去做控制 需要看资源是否可以抽象为共性 目前来讲我认为是可以的
|
||||
resourceName = mainJar.getResourceName().replaceFirst("/", ""); |
||||
} |
||||
mainJar.setRes(resourceName); |
||||
flinkParameters.setMainJar(mainJar); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public AbstractParameters getParameters() { |
||||
return flinkParameters; |
||||
} |
||||
} |
@ -0,0 +1,35 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.flink; |
||||
|
||||
import org.apache.dolphinscheduler.spi.task.TaskChannel; |
||||
import org.apache.dolphinscheduler.spi.task.TaskRequest; |
||||
|
||||
import org.slf4j.Logger; |
||||
|
||||
public class FlinkTaskChannel implements TaskChannel { |
||||
@Override |
||||
public void cancelApplication(boolean status) { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public FlinkTask createTask(TaskRequest taskRequest, Logger logger) { |
||||
return new FlinkTask(taskRequest, logger); |
||||
} |
||||
} |
@ -0,0 +1,41 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.flink; |
||||
|
||||
import org.apache.dolphinscheduler.spi.params.base.PluginParams; |
||||
import org.apache.dolphinscheduler.spi.task.TaskChannel; |
||||
import org.apache.dolphinscheduler.spi.task.TaskChannelFactory; |
||||
|
||||
import java.util.List; |
||||
|
||||
public class FlinkTaskChannelFactory implements TaskChannelFactory { |
||||
@Override |
||||
public TaskChannel create() { |
||||
return new FlinkTaskChannel(); |
||||
} |
||||
|
||||
@Override |
||||
public String getName() { |
||||
return "Flink"; |
||||
} |
||||
|
||||
@Override |
||||
public List<PluginParams> getParams() { |
||||
return null; |
||||
} |
||||
} |
@ -0,0 +1,30 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.flink; |
||||
|
||||
/** |
||||
* support program types |
||||
*/ |
||||
public enum ProgramType { |
||||
/** |
||||
* 0 JAVA,1 SCALA,2 PYTHON |
||||
*/ |
||||
JAVA, |
||||
SCALA, |
||||
PYTHON |
||||
} |
@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!-- |
||||
~ 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. |
||||
--> |
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<parent> |
||||
<artifactId>dolphinscheduler-task-plugin</artifactId> |
||||
<groupId>org.apache.dolphinscheduler</groupId> |
||||
<version>1.3.6-SNAPSHOT</version> |
||||
</parent> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
|
||||
<artifactId>dolphinscheduler-task-python</artifactId> |
||||
|
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>org.apache.dolphinscheduler</groupId> |
||||
<artifactId>dolphinscheduler-spi</artifactId> |
||||
<scope>provided</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.apache.dolphinscheduler</groupId> |
||||
<artifactId>dolphinscheduler-task-api</artifactId> |
||||
<version>${project.version}</version> |
||||
</dependency> |
||||
</dependencies> |
||||
|
||||
|
||||
</project> |
@ -0,0 +1,172 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.python; |
||||
|
||||
import org.apache.dolphinscheduler.plugin.task.api.AbstractCommandExecutor; |
||||
import org.apache.dolphinscheduler.spi.task.TaskRequest; |
||||
import org.apache.dolphinscheduler.spi.utils.StringUtils; |
||||
|
||||
import org.apache.commons.io.FileUtils; |
||||
|
||||
import java.io.BufferedReader; |
||||
import java.io.File; |
||||
import java.io.FileInputStream; |
||||
import java.io.IOException; |
||||
import java.io.InputStreamReader; |
||||
import java.nio.charset.StandardCharsets; |
||||
import java.nio.file.Files; |
||||
import java.nio.file.Paths; |
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
import java.util.function.Consumer; |
||||
|
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
/** |
||||
* python command executor |
||||
*/ |
||||
public class PythonCommandExecutor extends AbstractCommandExecutor { |
||||
|
||||
/** |
||||
* logger |
||||
*/ |
||||
private static final Logger logger = LoggerFactory.getLogger(PythonCommandExecutor.class); |
||||
|
||||
/** |
||||
* python |
||||
*/ |
||||
public static final String PYTHON = "python"; |
||||
|
||||
/** |
||||
* constructor |
||||
* |
||||
* @param logHandler log handler |
||||
* @param taskRequest TaskRequest |
||||
* @param logger logger |
||||
*/ |
||||
public PythonCommandExecutor(Consumer<List<String>> logHandler, |
||||
TaskRequest taskRequest, |
||||
Logger logger) { |
||||
super(logHandler, taskRequest, logger); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* build command file path |
||||
* |
||||
* @return command file path |
||||
*/ |
||||
@Override |
||||
protected String buildCommandFilePath() { |
||||
return String.format("%s/py_%s.command", taskRequest.getExecutePath(), taskRequest.getTaskAppId()); |
||||
} |
||||
|
||||
/** |
||||
* create command file if not exists |
||||
* |
||||
* @param execCommand exec command |
||||
* @param commandFile command file |
||||
* @throws IOException io exception |
||||
*/ |
||||
@Override |
||||
protected void createCommandFileIfNotExists(String execCommand, String commandFile) throws IOException { |
||||
logger.info("tenantCode :{}, task dir:{}", taskRequest.getTenantCode(), taskRequest.getExecutePath()); |
||||
|
||||
if (!Files.exists(Paths.get(commandFile))) { |
||||
logger.info("generate command file:{}", commandFile); |
||||
|
||||
StringBuilder sb = new StringBuilder(); |
||||
sb.append("#-*- encoding=utf8 -*-\n"); |
||||
|
||||
sb.append("\n\n"); |
||||
sb.append(execCommand); |
||||
logger.info(sb.toString()); |
||||
|
||||
// write data to file
|
||||
FileUtils.writeStringToFile(new File(commandFile), |
||||
sb.toString(), |
||||
StandardCharsets.UTF_8); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* get command options |
||||
* |
||||
* @return command options list |
||||
*/ |
||||
@Override |
||||
protected List<String> commandOptions() { |
||||
// unbuffered binary stdout and stderr
|
||||
return Collections.singletonList("-u"); |
||||
} |
||||
|
||||
/** |
||||
* get python home |
||||
* |
||||
* @return python home |
||||
*/ |
||||
@Override |
||||
protected String commandInterpreter() { |
||||
String pythonHome = getPythonHome(taskRequest.getEnvFile()); |
||||
if (StringUtils.isEmpty(pythonHome)) { |
||||
return PYTHON; |
||||
} |
||||
return pythonHome; |
||||
} |
||||
|
||||
/** |
||||
* get the absolute path of the Python command |
||||
* note : |
||||
* common.properties |
||||
* PYTHON_HOME configured under common.properties is Python absolute path, not PYTHON_HOME itself |
||||
* <p> |
||||
* for example : |
||||
* your PYTHON_HOM is /opt/python3.7/ |
||||
* you must set PYTHON_HOME is /opt/python3.7/python under nder common.properties |
||||
* dolphinscheduler.env.path file. |
||||
* |
||||
* @param envPath env path |
||||
* @return python home |
||||
*/ |
||||
private static String getPythonHome(String envPath) { |
||||
// BufferedReader br = null;
|
||||
StringBuilder sb = new StringBuilder(); |
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(envPath)));) { |
||||
String line; |
||||
while ((line = br.readLine()) != null) { |
||||
if (line.contains(PythonConstants.PYTHON_HOME)) { |
||||
sb.append(line); |
||||
break; |
||||
} |
||||
} |
||||
String result = sb.toString(); |
||||
if (StringUtils.isEmpty(result)) { |
||||
return null; |
||||
} |
||||
String[] arrs = result.split(PythonConstants.EQUAL_SIGN); |
||||
if (arrs.length == 2) { |
||||
return arrs[1]; |
||||
} |
||||
} catch (IOException e) { |
||||
logger.error("read file failure", e); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,35 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.python; |
||||
|
||||
public class PythonConstants { |
||||
|
||||
private PythonConstants() { |
||||
throw new IllegalStateException("Utility class"); |
||||
} |
||||
|
||||
/** |
||||
* python home |
||||
*/ |
||||
public static final String PYTHON_HOME = "PYTHON_HOME"; |
||||
|
||||
/** |
||||
* EQUAL SIGN |
||||
*/ |
||||
public static final String EQUAL_SIGN = "="; |
||||
} |
@ -0,0 +1,61 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.python; |
||||
|
||||
import org.apache.dolphinscheduler.spi.task.AbstractParameters; |
||||
import org.apache.dolphinscheduler.spi.task.ResourceInfo; |
||||
|
||||
import java.util.List; |
||||
|
||||
public class PythonParameters extends AbstractParameters { |
||||
/** |
||||
* origin python script |
||||
*/ |
||||
private String rawScript; |
||||
|
||||
/** |
||||
* resource list |
||||
*/ |
||||
private List<ResourceInfo> resourceList; |
||||
|
||||
public String getRawScript() { |
||||
return rawScript; |
||||
} |
||||
|
||||
public void setRawScript(String rawScript) { |
||||
this.rawScript = rawScript; |
||||
} |
||||
|
||||
public List<ResourceInfo> getResourceList() { |
||||
return resourceList; |
||||
} |
||||
|
||||
public void setResourceList(List<ResourceInfo> resourceList) { |
||||
this.resourceList = resourceList; |
||||
} |
||||
|
||||
@Override |
||||
public boolean checkParameters() { |
||||
return rawScript != null && !rawScript.isEmpty(); |
||||
} |
||||
|
||||
@Override |
||||
public List<ResourceInfo> getResourceFilesList() { |
||||
return this.resourceList; |
||||
} |
||||
} |
@ -0,0 +1,157 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.python; |
||||
|
||||
import org.apache.dolphinscheduler.plugin.task.api.TaskException; |
||||
import org.apache.dolphinscheduler.plugin.task.api.TaskResponse; |
||||
import org.apache.dolphinscheduler.spi.task.AbstractParameters; |
||||
import org.apache.dolphinscheduler.spi.task.AbstractTask; |
||||
import org.apache.dolphinscheduler.spi.task.TaskConstants; |
||||
import org.apache.dolphinscheduler.spi.task.TaskRequest; |
||||
import org.apache.dolphinscheduler.spi.utils.JSONUtils; |
||||
|
||||
import org.slf4j.Logger; |
||||
|
||||
/** |
||||
* python task |
||||
*/ |
||||
public class PythonTask extends AbstractTask { |
||||
|
||||
/** |
||||
* python parameters |
||||
*/ |
||||
private PythonParameters pythonParameters; |
||||
|
||||
/** |
||||
* task dir |
||||
*/ |
||||
private String taskDir; |
||||
|
||||
/** |
||||
* python command executor |
||||
*/ |
||||
private PythonCommandExecutor pythonCommandExecutor; |
||||
|
||||
private TaskRequest taskRequest; |
||||
|
||||
|
||||
private String command; |
||||
|
||||
/** |
||||
* constructor |
||||
* |
||||
* @param taskRequest taskRequest |
||||
* @param logger logger |
||||
*/ |
||||
public PythonTask(TaskRequest taskRequest, Logger logger) { |
||||
super(taskRequest, logger); |
||||
this.taskRequest = taskRequest; |
||||
|
||||
this.pythonCommandExecutor = new PythonCommandExecutor(this::logHandle, |
||||
taskRequest, |
||||
logger); |
||||
} |
||||
|
||||
@Override |
||||
public void init() { |
||||
logger.info("python task params {}", taskRequest.getTaskParams()); |
||||
|
||||
pythonParameters = JSONUtils.parseObject(taskRequest.getTaskParams(), PythonParameters.class); |
||||
|
||||
if (!pythonParameters.checkParameters()) { |
||||
throw new TaskException("python task params is not valid"); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public String getPreScript() { |
||||
String rawPythonScript = pythonParameters.getRawScript().replaceAll("\\r\\n", "\n"); |
||||
try { |
||||
rawPythonScript = convertPythonScriptPlaceholders(rawPythonScript); |
||||
} catch (StringIndexOutOfBoundsException e) { |
||||
logger.error("setShareVar field format error, raw python script : {}", rawPythonScript); |
||||
} |
||||
return rawPythonScript; |
||||
} |
||||
|
||||
@Override |
||||
public void setCommand(String command) { |
||||
this.command = command; |
||||
} |
||||
|
||||
@Override |
||||
public void handle() throws Exception { |
||||
try { |
||||
// construct process
|
||||
TaskResponse taskResponse = pythonCommandExecutor.run(command); |
||||
|
||||
setExitStatusCode(taskResponse.getExitStatusCode()); |
||||
setAppIds(taskResponse.getAppIds()); |
||||
setProcessId(taskResponse.getProcessId()); |
||||
setVarPool(pythonCommandExecutor.getVarPool()); |
||||
} catch (Exception e) { |
||||
logger.error("python task failure", e); |
||||
setExitStatusCode(TaskConstants.EXIT_CODE_FAILURE); |
||||
throw new TaskException("run python task error",e); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void cancelApplication(boolean cancelApplication) throws Exception { |
||||
// cancel process
|
||||
pythonCommandExecutor.cancelApplication(); |
||||
} |
||||
|
||||
@Override |
||||
public AbstractParameters getParameters() { |
||||
return pythonParameters; |
||||
} |
||||
|
||||
/** |
||||
* convertPythonScriptPlaceholders |
||||
* |
||||
* @param rawScript rawScript |
||||
* @return String |
||||
* @throws StringIndexOutOfBoundsException StringIndexOutOfBoundsException |
||||
*/ |
||||
private static String convertPythonScriptPlaceholders(String rawScript) throws StringIndexOutOfBoundsException { |
||||
int len = "${setShareVar(${".length(); |
||||
int scriptStart = 0; |
||||
while ((scriptStart = rawScript.indexOf("${setShareVar(${", scriptStart)) != -1) { |
||||
int start = -1; |
||||
int end = rawScript.indexOf('}', scriptStart + len); |
||||
String prop = rawScript.substring(scriptStart + len, end); |
||||
|
||||
start = rawScript.indexOf(',', end); |
||||
end = rawScript.indexOf(')', start); |
||||
|
||||
String value = rawScript.substring(start + 1, end); |
||||
|
||||
start = rawScript.indexOf('}', start) + 1; |
||||
end = rawScript.length(); |
||||
|
||||
String replaceScript = String.format("print(\"${{setValue({},{})}}\".format(\"%s\",%s))", prop, value); |
||||
|
||||
rawScript = rawScript.substring(0, scriptStart) + replaceScript + rawScript.substring(start, end); |
||||
|
||||
scriptStart += replaceScript.length(); |
||||
} |
||||
return rawScript; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,35 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.python; |
||||
|
||||
import org.apache.dolphinscheduler.spi.task.TaskChannel; |
||||
import org.apache.dolphinscheduler.spi.task.TaskRequest; |
||||
|
||||
import org.slf4j.Logger; |
||||
|
||||
public class PythonTaskChannel implements TaskChannel { |
||||
@Override |
||||
public void cancelApplication(boolean status) { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public PythonTask createTask(TaskRequest taskRequest, Logger logger) { |
||||
return new PythonTask(taskRequest, logger); |
||||
} |
||||
} |
@ -0,0 +1,39 @@
|
||||
package org.apache.dolphinscheduler.plugin.task.python;/* |
||||
* 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. |
||||
*/ |
||||
|
||||
import org.apache.dolphinscheduler.spi.params.base.PluginParams; |
||||
import org.apache.dolphinscheduler.spi.task.TaskChannel; |
||||
import org.apache.dolphinscheduler.spi.task.TaskChannelFactory; |
||||
|
||||
import java.util.List; |
||||
|
||||
public class PythonTaskChannelFactory implements TaskChannelFactory { |
||||
@Override |
||||
public TaskChannel create() { |
||||
return new PythonTaskChannel(); |
||||
} |
||||
|
||||
@Override |
||||
public String getName() { |
||||
return "Python"; |
||||
} |
||||
|
||||
@Override |
||||
public List<PluginParams> getParams() { |
||||
return null; |
||||
} |
||||
} |
@ -0,0 +1,46 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!-- |
||||
~ 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. |
||||
--> |
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<parent> |
||||
<artifactId>dolphinscheduler-task-plugin</artifactId> |
||||
<groupId>org.apache.dolphinscheduler</groupId> |
||||
<version>1.3.6-SNAPSHOT</version> |
||||
</parent> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
|
||||
<artifactId>dolphinscheduler-task-shell</artifactId> |
||||
|
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>org.apache.dolphinscheduler</groupId> |
||||
<artifactId>dolphinscheduler-spi</artifactId> |
||||
<scope>provided</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.apache.dolphinscheduler</groupId> |
||||
<artifactId>dolphinscheduler-task-api</artifactId> |
||||
<version>${project.version}</version> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.slf4j</groupId> |
||||
<artifactId>slf4j-api</artifactId> |
||||
</dependency> |
||||
</dependencies> |
||||
</project> |
@ -0,0 +1,62 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.shell; |
||||
|
||||
import org.apache.dolphinscheduler.spi.task.AbstractParameters; |
||||
import org.apache.dolphinscheduler.spi.task.ResourceInfo; |
||||
|
||||
import java.util.List; |
||||
|
||||
public class ShellParameters extends AbstractParameters { |
||||
|
||||
/** |
||||
* shell script |
||||
*/ |
||||
private String rawScript; |
||||
|
||||
/** |
||||
* resource list |
||||
*/ |
||||
private List<ResourceInfo> resourceList; |
||||
|
||||
public String getRawScript() { |
||||
return rawScript; |
||||
} |
||||
|
||||
public void setRawScript(String rawScript) { |
||||
this.rawScript = rawScript; |
||||
} |
||||
|
||||
public List<ResourceInfo> getResourceList() { |
||||
return resourceList; |
||||
} |
||||
|
||||
public void setResourceList(List<ResourceInfo> resourceList) { |
||||
this.resourceList = resourceList; |
||||
} |
||||
|
||||
@Override |
||||
public boolean checkParameters() { |
||||
return rawScript != null && !rawScript.isEmpty(); |
||||
} |
||||
|
||||
@Override |
||||
public List<ResourceInfo> getResourceFilesList() { |
||||
return resourceList; |
||||
} |
||||
} |
@ -0,0 +1,178 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.shell; |
||||
|
||||
import org.apache.dolphinscheduler.plugin.task.api.OSUtils; |
||||
import org.apache.dolphinscheduler.plugin.task.api.ShellCommandExecutor; |
||||
import org.apache.dolphinscheduler.plugin.task.api.TaskException; |
||||
import org.apache.dolphinscheduler.plugin.task.api.TaskResponse; |
||||
import org.apache.dolphinscheduler.spi.task.AbstractParameters; |
||||
import org.apache.dolphinscheduler.spi.task.AbstractTask; |
||||
import org.apache.dolphinscheduler.spi.task.Direct; |
||||
import org.apache.dolphinscheduler.spi.task.Property; |
||||
import org.apache.dolphinscheduler.spi.task.TaskConstants; |
||||
import org.apache.dolphinscheduler.spi.task.TaskRequest; |
||||
import org.apache.dolphinscheduler.spi.utils.JSONUtils; |
||||
|
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
import java.nio.file.Files; |
||||
import java.nio.file.Path; |
||||
import java.nio.file.StandardOpenOption; |
||||
import java.nio.file.attribute.FileAttribute; |
||||
import java.nio.file.attribute.PosixFilePermission; |
||||
import java.nio.file.attribute.PosixFilePermissions; |
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
|
||||
import org.slf4j.Logger; |
||||
|
||||
/** |
||||
* shell task |
||||
*/ |
||||
public class ShellTask extends AbstractTask { |
||||
|
||||
/** |
||||
* shell parameters |
||||
*/ |
||||
private ShellParameters shellParameters; |
||||
|
||||
/** |
||||
* shell command executor |
||||
*/ |
||||
private ShellCommandExecutor shellCommandExecutor; |
||||
|
||||
/** |
||||
* taskExecutionContext |
||||
*/ |
||||
private TaskRequest taskRequest; |
||||
|
||||
private String command; |
||||
|
||||
/** |
||||
* constructor |
||||
* |
||||
* @param taskRequest taskRequest |
||||
* @param logger logger |
||||
*/ |
||||
public ShellTask(TaskRequest taskRequest, Logger logger) { |
||||
super(taskRequest, logger); |
||||
|
||||
this.taskRequest = taskRequest; |
||||
this.shellCommandExecutor = new ShellCommandExecutor(this::logHandle, |
||||
taskRequest, |
||||
logger); |
||||
} |
||||
|
||||
@Override |
||||
public void init() { |
||||
logger.info("shell task params {}", taskRequest.getTaskParams()); |
||||
|
||||
shellParameters = JSONUtils.parseObject(taskRequest.getTaskParams(), ShellParameters.class); |
||||
|
||||
assert shellParameters != null; |
||||
if (!shellParameters.checkParameters()) { |
||||
throw new RuntimeException("shell task params is not valid"); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void handle() { |
||||
try { |
||||
// construct process
|
||||
TaskResponse response = shellCommandExecutor.run(command); |
||||
setExitStatusCode(response.getExitStatusCode()); |
||||
setAppIds(response.getAppIds()); |
||||
setProcessId(response.getProcessId()); |
||||
setResult(shellCommandExecutor.getTaskResultString()); |
||||
} catch (Exception e) { |
||||
logger.error("shell task error", e); |
||||
setExitStatusCode(TaskConstants.EXIT_CODE_FAILURE); |
||||
throw new TaskException("shell task error", e); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void cancelApplication(boolean cancelApplication) throws Exception { |
||||
// cancel process
|
||||
shellCommandExecutor.cancelApplication(); |
||||
} |
||||
|
||||
@Override |
||||
public String getPreScript() { |
||||
return shellParameters.getRawScript().replaceAll("\\r\\n", "\n"); |
||||
} |
||||
|
||||
/** |
||||
* set command |
||||
* |
||||
* @throws IOException exception |
||||
*/ |
||||
@Override |
||||
public void setCommand(String command) throws IOException { |
||||
// generate scripts
|
||||
String fileName = String.format("%s/%s_node.%s", |
||||
taskRequest.getExecutePath(), |
||||
taskRequest.getTaskAppId(), OSUtils.isWindows() ? "bat" : "sh"); |
||||
|
||||
Path path = new File(fileName).toPath(); |
||||
|
||||
if (Files.exists(path)) { |
||||
this.command = fileName; |
||||
return; |
||||
} |
||||
this.command = command; |
||||
shellParameters.setRawScript(command); |
||||
|
||||
logger.info("raw script : {}", shellParameters.getRawScript()); |
||||
logger.info("task execute path : {}", taskRequest.getExecutePath()); |
||||
|
||||
Set<PosixFilePermission> perms = PosixFilePermissions.fromString(TaskConstants.RWXR_XR_X); |
||||
FileAttribute<Set<PosixFilePermission>> attr = PosixFilePermissions.asFileAttribute(perms); |
||||
|
||||
if (OSUtils.isWindows()) { |
||||
Files.createFile(path); |
||||
} else { |
||||
Files.createFile(path, attr); |
||||
} |
||||
|
||||
Files.write(path, shellParameters.getRawScript().getBytes(), StandardOpenOption.APPEND); |
||||
this.command = fileName; |
||||
} |
||||
|
||||
@Override |
||||
public AbstractParameters getParameters() { |
||||
return shellParameters; |
||||
} |
||||
|
||||
public void setResult(String result) { |
||||
Map<String, Property> localParams = shellParameters.getLocalParametersMap(); |
||||
List<Map<String, String>> outProperties = new ArrayList<>(); |
||||
Map<String, String> p = new HashMap<>(); |
||||
localParams.forEach((k, v) -> { |
||||
if (v.getDirect() == Direct.OUT) { |
||||
p.put(k, result); |
||||
} |
||||
}); |
||||
outProperties.add(p); |
||||
resultString = JSONUtils.toJsonString(outProperties); |
||||
} |
||||
} |
@ -0,0 +1,41 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.shell; |
||||
|
||||
import org.apache.dolphinscheduler.spi.task.TaskChannel; |
||||
import org.apache.dolphinscheduler.spi.task.TaskRequest; |
||||
|
||||
import org.slf4j.Logger; |
||||
|
||||
public class ShellTaskChannel implements TaskChannel { |
||||
/** |
||||
* shell parameters |
||||
*/ |
||||
private ShellParameters shellParameters; |
||||
|
||||
@Override |
||||
public void cancelApplication(boolean status) { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public ShellTask createTask(TaskRequest taskRequest, Logger logger) { |
||||
return new ShellTask(taskRequest, logger); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,41 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.shell; |
||||
|
||||
import org.apache.dolphinscheduler.spi.params.base.PluginParams; |
||||
import org.apache.dolphinscheduler.spi.task.TaskChannel; |
||||
import org.apache.dolphinscheduler.spi.task.TaskChannelFactory; |
||||
|
||||
import java.util.List; |
||||
|
||||
public class ShellTaskChannelFactory implements TaskChannelFactory { |
||||
@Override |
||||
public TaskChannel create() { |
||||
return new ShellTaskChannel(); |
||||
} |
||||
|
||||
@Override |
||||
public String getName() { |
||||
return "Shell"; |
||||
} |
||||
|
||||
@Override |
||||
public List<PluginParams> getParams() { |
||||
return null; |
||||
} |
||||
} |
@ -0,0 +1,31 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.shell; |
||||
|
||||
import org.apache.dolphinscheduler.spi.DolphinSchedulerPlugin; |
||||
import org.apache.dolphinscheduler.spi.task.TaskChannelFactory; |
||||
|
||||
import com.google.common.collect.ImmutableList; |
||||
|
||||
public class ShellTaskPlugin implements DolphinSchedulerPlugin { |
||||
|
||||
@Override |
||||
public Iterable<TaskChannelFactory> getTaskChannelFactorys() { |
||||
return ImmutableList.of(new ShellTaskChannelFactory()); |
||||
} |
||||
} |
@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!-- |
||||
~ 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. |
||||
--> |
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<parent> |
||||
<artifactId>dolphinscheduler-task-plugin</artifactId> |
||||
<groupId>org.apache.dolphinscheduler</groupId> |
||||
<version>1.3.6-SNAPSHOT</version> |
||||
</parent> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
<artifactId>dolphinscheduler-task-spark</artifactId> |
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>org.apache.dolphinscheduler</groupId> |
||||
<artifactId>dolphinscheduler-spi</artifactId> |
||||
<scope>provided</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.apache.dolphinscheduler</groupId> |
||||
<artifactId>dolphinscheduler-task-api</artifactId> |
||||
<version>${project.version}</version> |
||||
</dependency> |
||||
</dependencies> |
||||
|
||||
</project> |
@ -0,0 +1,31 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.spark; |
||||
|
||||
/** |
||||
* support program types |
||||
*/ |
||||
public enum ProgramType { |
||||
|
||||
/** |
||||
* 0 JAVA,1 SCALA,2 PYTHON |
||||
*/ |
||||
JAVA, |
||||
SCALA, |
||||
PYTHON |
||||
} |
@ -0,0 +1,129 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.spark; |
||||
|
||||
import org.apache.dolphinscheduler.plugin.task.api.ArgsUtils; |
||||
import org.apache.dolphinscheduler.spi.task.ResourceInfo; |
||||
import org.apache.dolphinscheduler.spi.utils.StringUtils; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* spark args utils |
||||
*/ |
||||
public class SparkArgsUtils { |
||||
|
||||
private static final String SPARK_CLUSTER = "cluster"; |
||||
|
||||
private static final String SPARK_LOCAL = "local"; |
||||
|
||||
private static final String SPARK_ON_YARN = "yarn"; |
||||
|
||||
private SparkArgsUtils() { |
||||
throw new IllegalStateException("Utility class"); |
||||
} |
||||
|
||||
/** |
||||
* build args |
||||
* |
||||
* @param param param |
||||
* @return argument list |
||||
*/ |
||||
public static List<String> buildArgs(SparkParameters param) { |
||||
List<String> args = new ArrayList<>(); |
||||
args.add(SparkConstants.MASTER); |
||||
|
||||
String deployMode = StringUtils.isNotEmpty(param.getDeployMode()) ? param.getDeployMode() : SPARK_CLUSTER; |
||||
if (!SPARK_LOCAL.equals(deployMode)) { |
||||
args.add(SPARK_ON_YARN); |
||||
args.add(SparkConstants.DEPLOY_MODE); |
||||
} |
||||
args.add(deployMode); |
||||
|
||||
ProgramType programType = param.getProgramType(); |
||||
String mainClass = param.getMainClass(); |
||||
if (programType != null && programType != ProgramType.PYTHON && StringUtils.isNotEmpty(mainClass)) { |
||||
args.add(SparkConstants.MAIN_CLASS); |
||||
args.add(mainClass); |
||||
} |
||||
|
||||
int driverCores = param.getDriverCores(); |
||||
if (driverCores > 0) { |
||||
args.add(SparkConstants.DRIVER_CORES); |
||||
args.add(String.format("%d", driverCores)); |
||||
} |
||||
|
||||
String driverMemory = param.getDriverMemory(); |
||||
if (StringUtils.isNotEmpty(driverMemory)) { |
||||
args.add(SparkConstants.DRIVER_MEMORY); |
||||
args.add(driverMemory); |
||||
} |
||||
|
||||
int numExecutors = param.getNumExecutors(); |
||||
if (numExecutors > 0) { |
||||
args.add(SparkConstants.NUM_EXECUTORS); |
||||
args.add(String.format("%d", numExecutors)); |
||||
} |
||||
|
||||
int executorCores = param.getExecutorCores(); |
||||
if (executorCores > 0) { |
||||
args.add(SparkConstants.EXECUTOR_CORES); |
||||
args.add(String.format("%d", executorCores)); |
||||
} |
||||
|
||||
String executorMemory = param.getExecutorMemory(); |
||||
if (StringUtils.isNotEmpty(executorMemory)) { |
||||
args.add(SparkConstants.EXECUTOR_MEMORY); |
||||
args.add(executorMemory); |
||||
} |
||||
|
||||
String appName = param.getAppName(); |
||||
if (StringUtils.isNotEmpty(appName)) { |
||||
args.add(SparkConstants.SPARK_NAME); |
||||
args.add(ArgsUtils.escape(appName)); |
||||
} |
||||
|
||||
String others = param.getOthers(); |
||||
if (!SPARK_LOCAL.equals(deployMode) && (StringUtils.isEmpty(others) || !others.contains(SparkConstants.SPARK_QUEUE))) { |
||||
String queue = param.getQueue(); |
||||
if (StringUtils.isNotEmpty(queue)) { |
||||
args.add(SparkConstants.SPARK_QUEUE); |
||||
args.add(queue); |
||||
} |
||||
} |
||||
|
||||
// --conf --files --jars --packages
|
||||
if (StringUtils.isNotEmpty(others)) { |
||||
args.add(others); |
||||
} |
||||
|
||||
ResourceInfo mainJar = param.getMainJar(); |
||||
if (mainJar != null) { |
||||
args.add(mainJar.getRes()); |
||||
} |
||||
|
||||
String mainArgs = param.getMainArgs(); |
||||
if (StringUtils.isNotEmpty(mainArgs)) { |
||||
args.add(mainArgs); |
||||
} |
||||
|
||||
return args; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,73 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.spark; |
||||
|
||||
public class SparkConstants { |
||||
|
||||
private SparkConstants() { |
||||
throw new IllegalStateException("Utility class"); |
||||
} |
||||
|
||||
/** |
||||
* --class CLASS_NAME |
||||
*/ |
||||
public static final String MAIN_CLASS = "--class"; |
||||
|
||||
/** |
||||
* --name NAME |
||||
*/ |
||||
public static final String SPARK_NAME = "--name"; |
||||
|
||||
/** |
||||
* --queue QUEUE |
||||
*/ |
||||
public static final String SPARK_QUEUE = "--queue"; |
||||
|
||||
public static final String DEPLOY_MODE = "--deploy-mode"; |
||||
|
||||
/** |
||||
* --driver-cores NUM |
||||
*/ |
||||
public static final String DRIVER_CORES = "--driver-cores"; |
||||
|
||||
/** |
||||
* --driver-memory MEM |
||||
*/ |
||||
public static final String DRIVER_MEMORY = "--driver-memory"; |
||||
|
||||
/** |
||||
* master |
||||
*/ |
||||
public static final String MASTER = "--master"; |
||||
|
||||
/** |
||||
* --num-executors NUM |
||||
*/ |
||||
public static final String NUM_EXECUTORS = "--num-executors"; |
||||
|
||||
/** |
||||
* --executor-cores NUM |
||||
*/ |
||||
public static final String EXECUTOR_CORES = "--executor-cores"; |
||||
|
||||
/** |
||||
* --executor-memory MEM |
||||
*/ |
||||
public static final String EXECUTOR_MEMORY = "--executor-memory"; |
||||
|
||||
} |
@ -0,0 +1,241 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.spark; |
||||
|
||||
import org.apache.dolphinscheduler.spi.task.AbstractParameters; |
||||
import org.apache.dolphinscheduler.spi.task.ResourceInfo; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* spark parameters |
||||
*/ |
||||
public class SparkParameters extends AbstractParameters { |
||||
|
||||
/** |
||||
* main jar |
||||
*/ |
||||
private ResourceInfo mainJar; |
||||
|
||||
/** |
||||
* main class
|
||||
*/ |
||||
private String mainClass; |
||||
|
||||
/** |
||||
* deploy mode |
||||
*/ |
||||
private String deployMode; |
||||
|
||||
/** |
||||
* arguments |
||||
*/ |
||||
private String mainArgs; |
||||
|
||||
/** |
||||
* driver-cores Number of cores used by the driver, only in cluster mode |
||||
*/ |
||||
private int driverCores; |
||||
|
||||
/** |
||||
* driver-memory Memory for driver |
||||
*/ |
||||
|
||||
private String driverMemory; |
||||
|
||||
/** |
||||
* num-executors Number of executors to launch |
||||
*/ |
||||
private int numExecutors; |
||||
|
||||
/** |
||||
* executor-cores Number of cores per executor |
||||
*/ |
||||
private int executorCores; |
||||
|
||||
/** |
||||
* Memory per executor |
||||
*/ |
||||
private String executorMemory; |
||||
|
||||
/** |
||||
* app name |
||||
*/ |
||||
private String appName; |
||||
|
||||
/** |
||||
* The YARN queue to submit to |
||||
*/ |
||||
private String queue; |
||||
|
||||
/** |
||||
* other arguments |
||||
*/ |
||||
private String others; |
||||
|
||||
/** |
||||
* program type |
||||
* 0 JAVA,1 SCALA,2 PYTHON |
||||
*/ |
||||
private ProgramType programType; |
||||
|
||||
/** |
||||
* spark version |
||||
*/ |
||||
private String sparkVersion; |
||||
|
||||
/** |
||||
* resource list |
||||
*/ |
||||
private List<ResourceInfo> resourceList = new ArrayList<>(); |
||||
|
||||
public ResourceInfo getMainJar() { |
||||
return mainJar; |
||||
} |
||||
|
||||
public void setMainJar(ResourceInfo mainJar) { |
||||
this.mainJar = mainJar; |
||||
} |
||||
|
||||
public String getMainClass() { |
||||
return mainClass; |
||||
} |
||||
|
||||
public void setMainClass(String mainClass) { |
||||
this.mainClass = mainClass; |
||||
} |
||||
|
||||
public String getDeployMode() { |
||||
return deployMode; |
||||
} |
||||
|
||||
public void setDeployMode(String deployMode) { |
||||
this.deployMode = deployMode; |
||||
} |
||||
|
||||
public String getMainArgs() { |
||||
return mainArgs; |
||||
} |
||||
|
||||
public void setMainArgs(String mainArgs) { |
||||
this.mainArgs = mainArgs; |
||||
} |
||||
|
||||
public int getDriverCores() { |
||||
return driverCores; |
||||
} |
||||
|
||||
public void setDriverCores(int driverCores) { |
||||
this.driverCores = driverCores; |
||||
} |
||||
|
||||
public String getDriverMemory() { |
||||
return driverMemory; |
||||
} |
||||
|
||||
public void setDriverMemory(String driverMemory) { |
||||
this.driverMemory = driverMemory; |
||||
} |
||||
|
||||
public int getNumExecutors() { |
||||
return numExecutors; |
||||
} |
||||
|
||||
public void setNumExecutors(int numExecutors) { |
||||
this.numExecutors = numExecutors; |
||||
} |
||||
|
||||
public int getExecutorCores() { |
||||
return executorCores; |
||||
} |
||||
|
||||
public void setExecutorCores(int executorCores) { |
||||
this.executorCores = executorCores; |
||||
} |
||||
|
||||
public String getExecutorMemory() { |
||||
return executorMemory; |
||||
} |
||||
|
||||
public void setExecutorMemory(String executorMemory) { |
||||
this.executorMemory = executorMemory; |
||||
} |
||||
|
||||
public String getAppName() { |
||||
return appName; |
||||
} |
||||
|
||||
public void setAppName(String appName) { |
||||
this.appName = appName; |
||||
} |
||||
|
||||
public String getQueue() { |
||||
return queue; |
||||
} |
||||
|
||||
public void setQueue(String queue) { |
||||
this.queue = queue; |
||||
} |
||||
|
||||
public String getOthers() { |
||||
return others; |
||||
} |
||||
|
||||
public void setOthers(String others) { |
||||
this.others = others; |
||||
} |
||||
|
||||
public List<ResourceInfo> getResourceList() { |
||||
return resourceList; |
||||
} |
||||
|
||||
public void setResourceList(List<ResourceInfo> resourceList) { |
||||
this.resourceList = resourceList; |
||||
} |
||||
|
||||
public ProgramType getProgramType() { |
||||
return programType; |
||||
} |
||||
|
||||
public void setProgramType(ProgramType programType) { |
||||
this.programType = programType; |
||||
} |
||||
|
||||
public String getSparkVersion() { |
||||
return sparkVersion; |
||||
} |
||||
|
||||
public void setSparkVersion(String sparkVersion) { |
||||
this.sparkVersion = sparkVersion; |
||||
} |
||||
|
||||
@Override |
||||
public boolean checkParameters() { |
||||
return mainJar != null && programType != null; |
||||
} |
||||
|
||||
@Override |
||||
public List<ResourceInfo> getResourceFilesList() { |
||||
if (mainJar != null && !resourceList.contains(mainJar)) { |
||||
resourceList.add(mainJar); |
||||
} |
||||
return resourceList; |
||||
} |
||||
|
||||
} |
@ -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.plugin.task.spark; |
||||
|
||||
import org.apache.dolphinscheduler.plugin.task.api.AbstractYarnTask; |
||||
import org.apache.dolphinscheduler.spi.task.AbstractParameters; |
||||
import org.apache.dolphinscheduler.spi.task.ResourceInfo; |
||||
import org.apache.dolphinscheduler.spi.task.TaskRequest; |
||||
import org.apache.dolphinscheduler.spi.utils.JSONUtils; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
import org.slf4j.Logger; |
||||
|
||||
public class SparkTask extends AbstractYarnTask { |
||||
|
||||
|
||||
/** |
||||
* spark1 command |
||||
* usage: spark-submit [options] <app jar | python file> [app arguments] |
||||
*/ |
||||
private static final String SPARK1_COMMAND = "${SPARK_HOME1}/bin/spark-submit"; |
||||
|
||||
/** |
||||
* spark2 command |
||||
* usage: spark-submit [options] <app jar | python file> [app arguments] |
||||
*/ |
||||
private static final String SPARK2_COMMAND = "${SPARK_HOME2}/bin/spark-submit"; |
||||
|
||||
/** |
||||
* spark parameters |
||||
*/ |
||||
private SparkParameters sparkParameters; |
||||
|
||||
/** |
||||
* taskExecutionContext |
||||
*/ |
||||
private TaskRequest taskRequest; |
||||
|
||||
public SparkTask(TaskRequest taskRequest, Logger logger) { |
||||
super(taskRequest, logger); |
||||
this.taskRequest = taskRequest; |
||||
} |
||||
|
||||
@Override |
||||
public void init() { |
||||
|
||||
logger.info("spark task params {}", taskRequest.getTaskParams()); |
||||
|
||||
sparkParameters = JSONUtils.parseObject(taskRequest.getTaskParams(), SparkParameters.class); |
||||
|
||||
if (null == sparkParameters) { |
||||
logger.error("Spark params is null"); |
||||
return; |
||||
} |
||||
|
||||
if (!sparkParameters.checkParameters()) { |
||||
throw new RuntimeException("spark task params is not valid"); |
||||
} |
||||
sparkParameters.setQueue(taskRequest.getQueue()); |
||||
setMainJarName(); |
||||
} |
||||
|
||||
@Override |
||||
public String getPreScript() { |
||||
// spark-submit [options] <app jar | python file> [app arguments]
|
||||
List<String> args = new ArrayList<>(); |
||||
|
||||
// spark version
|
||||
String sparkCommand = SPARK2_COMMAND; |
||||
|
||||
if (SparkVersion.SPARK1.name().equals(sparkParameters.getSparkVersion())) { |
||||
sparkCommand = SPARK1_COMMAND; |
||||
} |
||||
|
||||
args.add(sparkCommand); |
||||
|
||||
// other parameters
|
||||
args.addAll(SparkArgsUtils.buildArgs(sparkParameters)); |
||||
return String.join(" ", args); |
||||
} |
||||
|
||||
private String command; |
||||
|
||||
@Override |
||||
public void setCommand(String command) { |
||||
logger.info("spark task command: {}", command); |
||||
this.command = command; |
||||
} |
||||
|
||||
/** |
||||
* get command |
||||
* |
||||
* @return command |
||||
*/ |
||||
@Override |
||||
protected String getCommand() { |
||||
return command; |
||||
} |
||||
|
||||
@Override |
||||
protected void setMainJarName() { |
||||
// main jar
|
||||
ResourceInfo mainJar = sparkParameters.getMainJar(); |
||||
|
||||
if (null == mainJar) { |
||||
throw new RuntimeException("Spark task jar params is null"); |
||||
} |
||||
|
||||
int resourceId = mainJar.getId(); |
||||
String resourceName; |
||||
if (resourceId == 0) { |
||||
resourceName = mainJar.getRes(); |
||||
} else { |
||||
//fixme when update resource maybe has error ,也许也可以交给上层去做控制 需要看资源是否可以抽象为共性 目前来讲我认为是可以的
|
||||
resourceName = mainJar.getResourceName().replaceFirst("/", ""); |
||||
} |
||||
mainJar.setRes(resourceName); |
||||
sparkParameters.setMainJar(mainJar); |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public AbstractParameters getParameters() { |
||||
return sparkParameters; |
||||
} |
||||
} |
@ -0,0 +1,44 @@
|
||||
/* |
||||
* Licensed to the Apache Software Foundation (ASF) under one or more |
||||
* contributor license agreements. See the NOTICE file distributed with |
||||
* this work for additional information regarding copyright ownership. |
||||
* The ASF licenses this file to You under the Apache License, Version 2.0 |
||||
* (the "License"); you may not use this file except in compliance with |
||||
* the License. You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package org.apache.dolphinscheduler.plugin.task.spark; |
||||
|
||||
public enum SparkVersion { |
||||
|
||||
/** |
||||
* 0 SPARK1 |
||||
* 1 SPARK2 |
||||
*/ |
||||
SPARK1(0, "SPARK1"), |
||||
SPARK2(1, "SPARK2"); |
||||
|
||||
SparkVersion(int code, String descp) { |
||||
this.code = code; |
||||
this.descp = descp; |
||||
} |
||||
|
||||
private final int code; |
||||
private final String descp; |
||||
|
||||
public int getCode() { |
||||
return code; |
||||
} |
||||
|
||||
public String getDescp() { |
||||
return descp; |
||||
} |
||||
} |
@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!-- |
||||
~ 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. |
||||
--> |
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<parent> |
||||
<artifactId>dolphinscheduler</artifactId> |
||||
<groupId>org.apache.dolphinscheduler</groupId> |
||||
<version>1.3.6-SNAPSHOT</version> |
||||
</parent> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
|
||||
<artifactId>dolphinscheduler-task-plugin</artifactId> |
||||
<packaging>pom</packaging> |
||||
|
||||
<modules> |
||||
<module>dolphinscheduler-task-shell</module> |
||||
<module>dolphinscheduler-task-api</module> |
||||
<module>dolphinscheduler-task-flink</module> |
||||
<module>dolphinscheduler-task-python</module> |
||||
<module>dolphinscheduler-task-spark</module> |
||||
</modules> |
||||
|
||||
|
||||
</project> |
Loading…
Reference in new issue