Browse Source
* [Feature][plugin] Add k8s task in task plugin * [Feature][plugin] fix dos and code problems * [Feature][plugin] refactor some code based on sonar * [Feature][UI] front-end for k8s task plugin * [Feature][plugin] delete some front files * [Feature][plugin] update document * Update docs/docs/zh/guide/task/k8s.md * Update docs/docs/en/guide/task/k8s.md * Update docs/docs/en/guide/task/k8s.md * Update docs/docs/en/guide/task/k8s.md * [Feature][UI] front-end change from review comments * [Feature][UI] replace get namespace list api * [Feature][plugin] change file name * Add kubernetes to zh task list Co-authored-by: hezhao2 <hezhao2@cisco.com> Co-authored-by: William Tong <weitong@cisco.com> Co-authored-by: Jiajie Zhong <zhongjiajie955@gmail.com>3.1.0-release
He Zhao
3 years ago
committed by
GitHub
42 changed files with 1733 additions and 21 deletions
@ -0,0 +1,44 @@
|
||||
# K8S Node |
||||
|
||||
## Overview |
||||
|
||||
K8S task type used to execute a batch task. In this task, the worker submits the task by using a k8s client. |
||||
|
||||
## Create Task |
||||
|
||||
- Click `Project -> Management-Project -> Name-Workflow Definition`, and click the `Create Workflow` button to enter the DAG editing page. |
||||
- Drag from the toolbar <img src="/img/tasks/icons/kubernetes.png" width="15"/> to the canvas. |
||||
|
||||
## Task Parameter |
||||
|
||||
- **Node name**: The node name in a workflow definition is unique. |
||||
- **Run flag**: Identifies whether this node schedules normally, if it does not need to execute, select the `prohibition execution`. |
||||
- **Descriptive information**: Describe the function of the node. |
||||
- **Task priority**: When the number of worker threads is insufficient, execute in the order of priority from high to low, and tasks with the same priority will execute in a first-in first-out order. |
||||
- **Worker grouping**: Assign tasks to the machines of the worker group to execute. If `Default` is selected, randomly select a worker machine for execution. |
||||
- **Environment Name**: Configure the environment name in which to run the task. |
||||
- **Times of failed retry attempts**: The number of times the task failed to resubmit. |
||||
- **Failed retry interval**: The time interval (unit minute) for resubmitting the task after a failed task. |
||||
- **Delayed execution time**: The time (unit minute) that a task delays in execution. |
||||
- **Timeout alarm**: Check the timeout alarm and timeout failure. When the task runs exceed the "timeout", an alarm email will send and the task execution will fail. |
||||
- **Namespace**::the namespace for running k8s task |
||||
- **Min CPU**:min CPU requirement for running k8s task |
||||
- **Min Memory**:min memory requirement for running k8s task |
||||
- **Image**:the registry url for image |
||||
- **Custom parameter**: It is a local user-defined parameter for K8S task, these params will pass to container as environment variables. |
||||
- **Predecessor task**: Selecting a predecessor task for the current task, will set the selected predecessor task as upstream of the current task. |
||||
## Task Example |
||||
|
||||
### Configure the K8S Environment in DolphinScheduler |
||||
|
||||
If you are using the K8S task type in a production environment, the K8S cluster environment is required. |
||||
|
||||
### Configure K8S Nodes |
||||
|
||||
Configure the required content according to the parameter descriptions above. |
||||
|
||||
![K8S](/img/tasks/demo/kubernetes-task-en.png) |
||||
|
||||
## Notice |
||||
|
||||
Task name contains only lowercase alphanumeric characters or '-' |
@ -0,0 +1,45 @@
|
||||
# Kubernetes |
||||
|
||||
## 综述 |
||||
|
||||
kubernetes任务类型,用于在kubernetes上执行一个短时和批处理的任务。worker最终会通过使用kubernetes client提交任务。 |
||||
|
||||
## 创建任务 |
||||
|
||||
- 点击项目管理-项目名称-工作流定义,点击"创建工作流"按钮,进入DAG编辑页面。 |
||||
- 工具栏中拖动 <img src="/img/tasks/icons/kubernetes.png" width="25"/> 到画板中,选择需要连接的数据源,即可完成创建。 |
||||
|
||||
## 任务参数 |
||||
|
||||
- 节点名称:设置任务的名称。一个工作流定义中的节点名称是唯一的。 |
||||
- 运行标志:标识这个节点是否能正常调度,如果不需要执行,可以打开禁止执行开关。 |
||||
- 描述:描述该节点的功能。 |
||||
- 任务优先级:worker 线程数不足时,根据优先级从高到低依次执行,优先级一样时根据先进先出原则执行。 |
||||
- Worker 分组:任务分配给 worker 组的机器执行,选择 Default 会随机选择一台 worker 机执行。 |
||||
- 环境名称:配置运行任务的环境。 |
||||
- 失败重试次数:任务失败重新提交的次数。 |
||||
- 失败重试间隔:任务失败重新提交任务的时间间隔,以分为单位。 |
||||
- 延迟执行时间:任务延迟执行的时间,以分为单位。 |
||||
- 超时警告:勾选超时警告、超时失败,当任务超过“超时时长”后,会发送告警邮件并且任务执行失败。 |
||||
- 命名空间:选择kubernetes集群上存在的命名空间 |
||||
- 最小CPU:任务在kubernetes上运行所需的最小CPU |
||||
- 最小内存:任务在kubernetes上运行所需的最小内存 |
||||
- 镜像:镜像地址 |
||||
- 自定义参数:kubernetes任务局部的用户自定义参数,自定义参数最终会通过环境变量形式存在于容器中,提供给kubernetes任务使用 |
||||
- 前置任务:在当前kubernetes任务之前需要执行的任务 |
||||
|
||||
## 任务样例 |
||||
|
||||
### 在 DolphinScheduler 中配置 kubernetes 集群环境 |
||||
|
||||
若生产环境中要是使用到 kubernetes 任务类型,则需要预先配置好所需的kubernetes集群环境 |
||||
|
||||
### 配置 kubernetes 任务节点 |
||||
|
||||
根据上述参数说明,配置所需的内容即可。 |
||||
|
||||
![kubernetes](/img/tasks/demo/kubernetes-task-en.png) |
||||
|
||||
## 注意事项 |
||||
|
||||
任务名字限制在小写字母、数字和-这三种字符之中 |
After Width: | Height: | Size: 475 KiB |
After Width: | Height: | Size: 1.4 KiB |
@ -0,0 +1,43 @@
|
||||
/* |
||||
* 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.Serializable; |
||||
|
||||
/** |
||||
* k8s Task ExecutionContext |
||||
*/ |
||||
|
||||
public class K8sTaskExecutionContext implements Serializable { |
||||
private String configYaml; |
||||
|
||||
public String getConfigYaml() { |
||||
return configYaml; |
||||
} |
||||
|
||||
public void setConfigYaml(String configYaml) { |
||||
this.configYaml = configYaml; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return "K8sTaskExecutionContext{" |
||||
+ "configYaml='" + configYaml + '\'' |
||||
+ '}'; |
||||
} |
||||
} |
@ -0,0 +1,74 @@
|
||||
/* |
||||
* 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.k8s; |
||||
|
||||
import org.apache.dolphinscheduler.plugin.task.api.AbstractTaskExecutor; |
||||
import org.apache.dolphinscheduler.plugin.task.api.TaskException; |
||||
import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext; |
||||
import org.apache.dolphinscheduler.plugin.task.api.k8s.impl.K8sTaskExecutor; |
||||
import org.apache.dolphinscheduler.plugin.task.api.model.TaskResponse; |
||||
|
||||
public abstract class AbstractK8sTask extends AbstractTaskExecutor { |
||||
/** |
||||
* process task |
||||
*/ |
||||
private AbstractK8sTaskExecutor abstractK8sTaskExecutor; |
||||
/** |
||||
* Abstract k8s Task |
||||
* |
||||
* @param taskRequest taskRequest |
||||
*/ |
||||
protected AbstractK8sTask(TaskExecutionContext taskRequest) { |
||||
super(taskRequest); |
||||
this.abstractK8sTaskExecutor = new K8sTaskExecutor(logger,taskRequest); |
||||
} |
||||
|
||||
@Override |
||||
public void handle() throws Exception { |
||||
try { |
||||
TaskResponse response = abstractK8sTaskExecutor.run(buildCommand()); |
||||
setExitStatusCode(response.getExitStatusCode()); |
||||
setAppIds(response.getAppIds()); |
||||
} catch (Exception e) { |
||||
exitStatusCode = -1; |
||||
throw new TaskException("k8s process failure",e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* cancel application |
||||
* |
||||
* @param status status |
||||
* @throws Exception exception |
||||
*/ |
||||
@Override |
||||
public void cancelApplication(boolean status) throws Exception { |
||||
cancel = true; |
||||
// cancel process
|
||||
abstractK8sTaskExecutor.cancelApplication(buildCommand()); |
||||
} |
||||
|
||||
/** |
||||
* create command |
||||
* |
||||
* @return String |
||||
* @throws Exception exception |
||||
*/ |
||||
protected abstract String buildCommand(); |
||||
|
||||
} |
@ -0,0 +1,63 @@
|
||||
/* |
||||
* 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.k8s; |
||||
|
||||
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.EXIT_CODE_FAILURE; |
||||
|
||||
import org.apache.dolphinscheduler.plugin.task.api.TaskException; |
||||
import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext; |
||||
import org.apache.dolphinscheduler.plugin.task.api.model.TaskResponse; |
||||
import org.apache.dolphinscheduler.plugin.task.api.utils.K8sUtils; |
||||
|
||||
import org.slf4j.Logger; |
||||
|
||||
public abstract class AbstractK8sTaskExecutor { |
||||
protected Logger logger; |
||||
protected TaskExecutionContext taskRequest; |
||||
protected K8sUtils k8sUtils; |
||||
protected StringBuilder logStringBuffer; |
||||
|
||||
protected AbstractK8sTaskExecutor(Logger logger, TaskExecutionContext taskRequest) { |
||||
this.logger = logger; |
||||
this.taskRequest = taskRequest; |
||||
this.k8sUtils = new K8sUtils(); |
||||
this.logStringBuffer = new StringBuilder(); |
||||
} |
||||
|
||||
public abstract TaskResponse run(String k8sParameterStr) throws Exception; |
||||
|
||||
public abstract void cancelApplication(String k8sParameterStr); |
||||
|
||||
public void waitTimeout(Boolean timeout) throws TaskException { |
||||
if (Boolean.TRUE.equals(timeout)) { |
||||
throw new TaskException("K8sTask is timeout"); |
||||
} |
||||
} |
||||
|
||||
public void flushLog(TaskResponse taskResponse) { |
||||
if (logStringBuffer.length() != 0 && taskResponse.getExitStatusCode() == EXIT_CODE_FAILURE) { |
||||
logger.error(logStringBuffer.toString()); |
||||
} else if (logStringBuffer.length() != 0) { |
||||
logger.info(logStringBuffer.toString()); |
||||
} |
||||
} |
||||
|
||||
public abstract void submitJob2k8s(String k8sParameterStr); |
||||
|
||||
public abstract void stopJobOnK8s(String k8sParameterStr); |
||||
} |
@ -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.k8s; |
||||
|
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* k8s task parameters |
||||
*/ |
||||
public class K8sTaskMainParameters { |
||||
|
||||
private String image; |
||||
private String namespaceName; |
||||
private String clusterName; |
||||
private double minCpuCores; |
||||
private double minMemorySpace; |
||||
private Map<String, String> paramsMap; |
||||
|
||||
public String getImage() { |
||||
return image; |
||||
} |
||||
|
||||
public void setImage(String image) { |
||||
this.image = image; |
||||
} |
||||
|
||||
public double getMinCpuCores() { |
||||
return minCpuCores; |
||||
} |
||||
|
||||
public void setMinCpuCores(double minCpuCores) { |
||||
this.minCpuCores = minCpuCores; |
||||
} |
||||
|
||||
public double getMinMemorySpace() { |
||||
return minMemorySpace; |
||||
} |
||||
|
||||
public void setMinMemorySpace(double minMemorySpace) { |
||||
this.minMemorySpace = minMemorySpace; |
||||
} |
||||
|
||||
public String getNamespaceName() { |
||||
return namespaceName; |
||||
} |
||||
|
||||
public void setNamespaceName(String namespaceName) { |
||||
this.namespaceName = namespaceName; |
||||
} |
||||
|
||||
public String getClusterName() { |
||||
return clusterName; |
||||
} |
||||
|
||||
public void setClusterName(String clusterName) { |
||||
this.clusterName = clusterName; |
||||
} |
||||
|
||||
public Map<String, String> getParamsMap() { |
||||
return paramsMap; |
||||
} |
||||
|
||||
public void setParamsMap(Map<String, String> paramsMap) { |
||||
this.paramsMap = paramsMap; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return "K8sTaskMainParameters{" |
||||
+ "image='" + image + '\'' |
||||
+ ", namespaceName='" + namespaceName + '\'' |
||||
+ ", clusterName='" + clusterName + '\'' |
||||
+ ", minCpuCores=" + minCpuCores |
||||
+ ", minMemorySpace=" + minMemorySpace |
||||
+ ", paramsMap=" + paramsMap |
||||
+ '}'; |
||||
} |
||||
} |
@ -0,0 +1,286 @@
|
||||
/* |
||||
* 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.k8s.impl; |
||||
|
||||
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.API_VERSION; |
||||
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.CPU; |
||||
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.EXIT_CODE_FAILURE; |
||||
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.EXIT_CODE_KILL; |
||||
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.EXIT_CODE_SUCCESS; |
||||
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.IMAGE_PULL_POLICY; |
||||
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.JOB_TTL_SECONDS; |
||||
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.LAYER_LABEL; |
||||
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.LAYER_LABEL_VALUE; |
||||
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.MEMORY; |
||||
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.MI; |
||||
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.NAME_LABEL; |
||||
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.RESTART_POLICY; |
||||
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.TASK_INSTANCE_ID; |
||||
|
||||
import org.apache.dolphinscheduler.plugin.task.api.K8sTaskExecutionContext; |
||||
import org.apache.dolphinscheduler.plugin.task.api.TaskConstants; |
||||
import org.apache.dolphinscheduler.plugin.task.api.TaskException; |
||||
import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext; |
||||
import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContextCacheManager; |
||||
import org.apache.dolphinscheduler.plugin.task.api.enums.TaskTimeoutStrategy; |
||||
import org.apache.dolphinscheduler.plugin.task.api.k8s.AbstractK8sTaskExecutor; |
||||
import org.apache.dolphinscheduler.plugin.task.api.k8s.K8sTaskMainParameters; |
||||
import org.apache.dolphinscheduler.plugin.task.api.model.TaskResponse; |
||||
import org.apache.dolphinscheduler.plugin.task.api.utils.MapUtils; |
||||
import org.apache.dolphinscheduler.spi.utils.JSONUtils; |
||||
import org.apache.dolphinscheduler.spi.utils.StringUtils; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.List; |
||||
import java.util.Locale; |
||||
import java.util.Map; |
||||
import java.util.concurrent.CountDownLatch; |
||||
import java.util.concurrent.TimeUnit; |
||||
|
||||
import org.slf4j.Logger; |
||||
|
||||
import io.fabric8.kubernetes.api.model.EnvVar; |
||||
import io.fabric8.kubernetes.api.model.Quantity; |
||||
import io.fabric8.kubernetes.api.model.ResourceRequirements; |
||||
import io.fabric8.kubernetes.api.model.batch.v1.Job; |
||||
import io.fabric8.kubernetes.api.model.batch.v1.JobBuilder; |
||||
import io.fabric8.kubernetes.api.model.batch.v1.JobStatus; |
||||
import io.fabric8.kubernetes.client.Watch; |
||||
import io.fabric8.kubernetes.client.Watcher; |
||||
import io.fabric8.kubernetes.client.WatcherException; |
||||
|
||||
/** |
||||
* K8sTaskExecutor used to submit k8s task to K8S |
||||
*/ |
||||
public class K8sTaskExecutor extends AbstractK8sTaskExecutor { |
||||
private Job job; |
||||
public K8sTaskExecutor(Logger logger, TaskExecutionContext taskRequest) { |
||||
super(logger,taskRequest); |
||||
} |
||||
|
||||
public Job buildK8sJob(K8sTaskMainParameters k8STaskMainParameters) { |
||||
String taskInstanceId = String.valueOf(taskRequest.getTaskInstanceId()); |
||||
String taskName = taskRequest.getTaskName().toLowerCase(Locale.ROOT); |
||||
String image = k8STaskMainParameters.getImage(); |
||||
String namespaceName = k8STaskMainParameters.getNamespaceName(); |
||||
Map<String, String> otherParams = k8STaskMainParameters.getParamsMap(); |
||||
Double podMem = k8STaskMainParameters.getMinMemorySpace(); |
||||
Double podCpu = k8STaskMainParameters.getMinCpuCores(); |
||||
Double limitPodMem = podMem * 2; |
||||
Double limitPodCpu = podCpu * 2; |
||||
int retryNum = 0; |
||||
String k8sJobName = String.format("%s-%s", taskName, taskInstanceId); |
||||
Map<String, Quantity> reqRes = new HashMap<>(); |
||||
reqRes.put(MEMORY, new Quantity(String.format("%s%s", podMem, MI))); |
||||
reqRes.put(CPU, new Quantity(String.valueOf(podCpu))); |
||||
Map<String, Quantity> limitRes = new HashMap<>(); |
||||
limitRes.put(MEMORY, new Quantity(String.format("%s%s", limitPodMem, MI))); |
||||
limitRes.put(CPU, new Quantity(String.valueOf(limitPodCpu))); |
||||
Map<String, String> labelMap = new HashMap<>(); |
||||
labelMap.put(LAYER_LABEL, LAYER_LABEL_VALUE); |
||||
labelMap.put(NAME_LABEL, k8sJobName); |
||||
EnvVar taskInstanceIdVar = new EnvVar(TASK_INSTANCE_ID, taskInstanceId, null); |
||||
List<EnvVar> envVars = new ArrayList<>(); |
||||
envVars.add(taskInstanceIdVar); |
||||
if (MapUtils.isNotEmpty(otherParams)) { |
||||
for (Map.Entry<String,String> entry : otherParams.entrySet()) { |
||||
String param = entry.getKey(); |
||||
String paramValue = entry.getValue(); |
||||
EnvVar envVar = new EnvVar(param, paramValue, null); |
||||
envVars.add(envVar); |
||||
} |
||||
} |
||||
return new JobBuilder() |
||||
.withApiVersion(API_VERSION) |
||||
.withNewMetadata() |
||||
.withName(k8sJobName) |
||||
.withLabels(labelMap) |
||||
.withNamespace(namespaceName) |
||||
.endMetadata() |
||||
.withNewSpec() |
||||
.withTtlSecondsAfterFinished(JOB_TTL_SECONDS) |
||||
.withNewTemplate() |
||||
.withNewSpec() |
||||
.addNewContainer() |
||||
.withName(k8sJobName) |
||||
.withImage(image) |
||||
.withImagePullPolicy(IMAGE_PULL_POLICY) |
||||
.withResources(new ResourceRequirements(limitRes, reqRes)) |
||||
.withEnv(envVars) |
||||
.endContainer() |
||||
.withRestartPolicy(RESTART_POLICY) |
||||
.endSpec() |
||||
.endTemplate() |
||||
.withBackoffLimit(retryNum) |
||||
.endSpec() |
||||
.build(); |
||||
} |
||||
|
||||
public void registerBatchJobWatcher(Job job, String taskInstanceId, TaskResponse taskResponse, K8sTaskMainParameters k8STaskMainParameters) { |
||||
CountDownLatch countDownLatch = new CountDownLatch(1); |
||||
Watcher<Job> watcher = new Watcher<Job>() { |
||||
@Override |
||||
public void eventReceived(Action action, Job job) { |
||||
if (action != Action.ADDED) { |
||||
int jobStatus = getK8sJobStatus(job); |
||||
setTaskStatus(jobStatus,taskInstanceId, taskResponse, k8STaskMainParameters); |
||||
countDownLatch.countDown(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void onClose(WatcherException e) { |
||||
logStringBuffer.append(String.format("[K8sJobExecutor-%s] fail in k8s: %s",job.getMetadata().getName(),e.getMessage())); |
||||
taskResponse.setExitStatusCode(EXIT_CODE_FAILURE); |
||||
countDownLatch.countDown(); |
||||
} |
||||
|
||||
@Override |
||||
public void onClose() { |
||||
logger.warn("Watch gracefully closed"); |
||||
} |
||||
}; |
||||
Watch watch = null; |
||||
try { |
||||
watch = k8sUtils.createBatchJobWatcher(job.getMetadata().getName(), watcher); |
||||
boolean timeoutFlag = taskRequest.getTaskTimeoutStrategy() == TaskTimeoutStrategy.FAILED |
||||
|| taskRequest.getTaskTimeoutStrategy() == TaskTimeoutStrategy.WARNFAILED; |
||||
if (timeoutFlag) { |
||||
Boolean timeout = !(countDownLatch.await(taskRequest.getTaskTimeout(), TimeUnit.SECONDS)); |
||||
waitTimeout(timeout); |
||||
} else { |
||||
countDownLatch.await(); |
||||
} |
||||
flushLog(taskResponse); |
||||
} catch (InterruptedException e) { |
||||
logger.error("job failed in k8s: {}",e.getMessage(), e); |
||||
Thread.currentThread().interrupt(); |
||||
taskResponse.setExitStatusCode(EXIT_CODE_FAILURE); |
||||
} catch (Exception e) { |
||||
logger.error("job failed in k8s: {}",e.getMessage(), e); |
||||
taskResponse.setExitStatusCode(EXIT_CODE_FAILURE); |
||||
} finally { |
||||
if (watch != null) { |
||||
watch.close(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public TaskResponse run(String k8sParameterStr) throws Exception { |
||||
TaskResponse result = new TaskResponse(); |
||||
int taskInstanceId = taskRequest.getTaskInstanceId(); |
||||
K8sTaskMainParameters k8STaskMainParameters = JSONUtils.parseObject(k8sParameterStr, K8sTaskMainParameters.class); |
||||
try { |
||||
if (null == TaskExecutionContextCacheManager.getByTaskInstanceId(taskInstanceId)) { |
||||
result.setExitStatusCode(EXIT_CODE_KILL); |
||||
return result; |
||||
} |
||||
if (StringUtils.isEmpty(k8sParameterStr)) { |
||||
TaskExecutionContextCacheManager.removeByTaskInstanceId(taskInstanceId); |
||||
return result; |
||||
} |
||||
K8sTaskExecutionContext k8sTaskExecutionContext = taskRequest.getK8sTaskExecutionContext(); |
||||
String configYaml = k8sTaskExecutionContext.getConfigYaml(); |
||||
k8sUtils.buildClient(configYaml); |
||||
submitJob2k8s(k8sParameterStr); |
||||
registerBatchJobWatcher(job, Integer.toString(taskInstanceId), result, k8STaskMainParameters); |
||||
} catch (Exception e) { |
||||
cancelApplication(k8sParameterStr); |
||||
result.setExitStatusCode(EXIT_CODE_FAILURE); |
||||
throw e; |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
@Override |
||||
public void cancelApplication(String k8sParameterStr) { |
||||
if (job != null) { |
||||
stopJobOnK8s(k8sParameterStr); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void submitJob2k8s(String k8sParameterStr) { |
||||
int taskInstanceId = taskRequest.getTaskInstanceId(); |
||||
String taskName = taskRequest.getTaskName().toLowerCase(Locale.ROOT); |
||||
K8sTaskMainParameters k8STaskMainParameters = JSONUtils.parseObject(k8sParameterStr, K8sTaskMainParameters.class); |
||||
try { |
||||
logger.info("[K8sJobExecutor-{}-{}] start to submit job", taskName, taskInstanceId); |
||||
job = buildK8sJob(k8STaskMainParameters); |
||||
stopJobOnK8s(k8sParameterStr); |
||||
String namespaceName = k8STaskMainParameters.getNamespaceName(); |
||||
k8sUtils.createJob(namespaceName, job); |
||||
logger.info("[K8sJobExecutor-{}-{}] submitted job successfully", taskName, taskInstanceId); |
||||
} catch (Exception e) { |
||||
logger.error("[K8sJobExecutor-{}-{}] fail to submit job", taskName, taskInstanceId); |
||||
throw new TaskException("K8sJobExecutor fail to submit job", e); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void stopJobOnK8s(String k8sParameterStr) { |
||||
K8sTaskMainParameters k8STaskMainParameters = JSONUtils.parseObject(k8sParameterStr, K8sTaskMainParameters.class); |
||||
String namespaceName = k8STaskMainParameters.getNamespaceName(); |
||||
String jobName = job.getMetadata().getName(); |
||||
try { |
||||
if (Boolean.TRUE.equals(k8sUtils.jobExist(jobName, namespaceName))) { |
||||
k8sUtils.deleteJob(jobName, namespaceName); |
||||
} |
||||
} catch (Exception e) { |
||||
logger.error("[K8sJobExecutor-{}] fail to stop job", jobName); |
||||
throw new TaskException("K8sJobExecutor fail to stop job", e); |
||||
} |
||||
} |
||||
|
||||
public int getK8sJobStatus(Job job) { |
||||
JobStatus jobStatus = job.getStatus(); |
||||
if (jobStatus.getSucceeded() != null && jobStatus.getSucceeded() == 1) { |
||||
return EXIT_CODE_SUCCESS; |
||||
} else if (jobStatus.getFailed() != null && jobStatus.getFailed() == 1) { |
||||
return EXIT_CODE_FAILURE; |
||||
} else { |
||||
return TaskConstants.RUNNING_CODE; |
||||
} |
||||
} |
||||
|
||||
public void setTaskStatus(int jobStatus,String taskInstanceId, TaskResponse taskResponse, K8sTaskMainParameters k8STaskMainParameters) { |
||||
if (jobStatus == EXIT_CODE_SUCCESS || jobStatus == EXIT_CODE_FAILURE) { |
||||
if (null == TaskExecutionContextCacheManager.getByTaskInstanceId(Integer.valueOf(taskInstanceId))) { |
||||
logStringBuffer.append(String.format("[K8sJobExecutor-%s] killed", job.getMetadata().getName())); |
||||
taskResponse.setExitStatusCode(EXIT_CODE_KILL); |
||||
} else if (jobStatus == EXIT_CODE_SUCCESS) { |
||||
logStringBuffer.append(String.format("[K8sJobExecutor-%s] succeed in k8s", job.getMetadata().getName())); |
||||
taskResponse.setExitStatusCode(EXIT_CODE_SUCCESS); |
||||
} else { |
||||
String errorMessage = k8sUtils.getPodLog(job.getMetadata().getName(), k8STaskMainParameters.getNamespaceName()); |
||||
logStringBuffer.append(String.format("[K8sJobExecutor-%s] fail in k8s: %s", job.getMetadata().getName(), errorMessage)); |
||||
taskResponse.setExitStatusCode(EXIT_CODE_FAILURE); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public Job getJob() { |
||||
return job; |
||||
} |
||||
|
||||
public void setJob(Job job) { |
||||
this.job = job; |
||||
} |
||||
} |
@ -0,0 +1,119 @@
|
||||
/* |
||||
* 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.utils; |
||||
|
||||
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.LOG_LINES; |
||||
|
||||
import org.apache.dolphinscheduler.plugin.task.api.TaskException; |
||||
|
||||
import java.util.List; |
||||
import java.util.Optional; |
||||
|
||||
import org.slf4j.Logger; |
||||
import org.slf4j.LoggerFactory; |
||||
|
||||
import io.fabric8.kubernetes.api.model.Pod; |
||||
import io.fabric8.kubernetes.api.model.batch.v1.Job; |
||||
import io.fabric8.kubernetes.api.model.batch.v1.JobList; |
||||
import io.fabric8.kubernetes.client.Config; |
||||
import io.fabric8.kubernetes.client.DefaultKubernetesClient; |
||||
import io.fabric8.kubernetes.client.KubernetesClient; |
||||
import io.fabric8.kubernetes.client.Watch; |
||||
import io.fabric8.kubernetes.client.Watcher; |
||||
|
||||
public class K8sUtils { |
||||
private static final Logger log = LoggerFactory.getLogger(K8sUtils.class); |
||||
private KubernetesClient client; |
||||
|
||||
public void createJob(String namespace, Job job) { |
||||
try { |
||||
client.batch().v1() |
||||
.jobs() |
||||
.inNamespace(namespace) |
||||
.create(job); |
||||
} catch (Exception e) { |
||||
throw new TaskException("fail to create job",e); |
||||
} |
||||
} |
||||
|
||||
public void deleteJob(String jobName, String namespace) { |
||||
try { |
||||
client.batch().v1() |
||||
.jobs() |
||||
.inNamespace(namespace) |
||||
.withName(jobName) |
||||
.delete(); |
||||
} catch (Exception e) { |
||||
throw new TaskException("fail to delete job",e); |
||||
} |
||||
} |
||||
|
||||
public Boolean jobExist(String jobName, String namespace) { |
||||
Optional<Job> result; |
||||
try { |
||||
JobList jobList = client.batch().v1().jobs().inNamespace(namespace).list(); |
||||
List<Job> jobs = jobList.getItems(); |
||||
result = jobs.stream() |
||||
.filter(job -> job.getMetadata().getName().equals(jobName)) |
||||
.findFirst(); |
||||
return result.isPresent(); |
||||
} catch (Exception e) { |
||||
throw new TaskException("fail to check job: ", e); |
||||
} |
||||
} |
||||
|
||||
public Watch createBatchJobWatcher(String jobName, Watcher<Job> watcher) { |
||||
try { |
||||
return client.batch().v1() |
||||
.jobs().withName(jobName).watch(watcher); |
||||
} catch (Exception e) { |
||||
throw new TaskException("fail to register batch job watcher",e); |
||||
} |
||||
} |
||||
|
||||
public String getPodLog(String jobName, String namespace) { |
||||
try { |
||||
List<Pod> podList = client.pods().inNamespace(namespace).list().getItems(); |
||||
String podName = null; |
||||
for (Pod pod : podList) { |
||||
podName = pod.getMetadata().getName(); |
||||
if (jobName.equals(podName.substring(0, pod.getMetadata().getName().lastIndexOf("-")))) { |
||||
break; |
||||
} |
||||
} |
||||
return client.pods().inNamespace(namespace) |
||||
.withName(podName) |
||||
.tailingLines(LOG_LINES) |
||||
.getLog(Boolean.TRUE); |
||||
} catch (Exception e) { |
||||
log.error("fail to getPodLog", e); |
||||
log.error("response bodies : {}", e.getMessage()); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
public void buildClient(String configYaml) { |
||||
try { |
||||
Config config = Config.fromKubeconfig(configYaml); |
||||
client = new DefaultKubernetesClient(config); |
||||
} catch (Exception e) { |
||||
throw new TaskException("fail to build k8s ApiClient",e); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,101 @@
|
||||
/* |
||||
* 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.k8s; |
||||
import io.fabric8.kubernetes.api.model.batch.v1.Job; |
||||
import io.fabric8.kubernetes.api.model.batch.v1.JobStatus; |
||||
|
||||
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.CLUSTER; |
||||
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.EXIT_CODE_KILL; |
||||
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.NAMESPACE_NAME; |
||||
import static org.hamcrest.Matchers.is; |
||||
|
||||
import org.apache.dolphinscheduler.plugin.task.api.TaskException; |
||||
import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext; |
||||
import org.apache.dolphinscheduler.plugin.task.api.k8s.impl.K8sTaskExecutor; |
||||
import org.apache.dolphinscheduler.plugin.task.api.model.TaskResponse; |
||||
import org.apache.dolphinscheduler.spi.utils.JSONUtils; |
||||
|
||||
import java.util.Map; |
||||
|
||||
import org.junit.Assert; |
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
|
||||
public class K8sTaskExecutorTest { |
||||
private K8sTaskExecutor k8sTaskExecutor = null; |
||||
private K8sTaskMainParameters k8sTaskMainParameters = null; |
||||
private final String image = "ds-dev"; |
||||
private final String namespace = "{\"name\":\"default\",\"cluster\":\"lab\"}"; |
||||
private final double minCpuCores = 2; |
||||
private final double minMemorySpace = 10; |
||||
private final int taskInstanceId = 1000; |
||||
private final String taskName = "k8s_task_test"; |
||||
private Job job; |
||||
@Before |
||||
public void before() { |
||||
TaskExecutionContext taskRequest = new TaskExecutionContext(); |
||||
taskRequest.setTaskInstanceId(taskInstanceId); |
||||
taskRequest.setTaskName(taskName); |
||||
Map<String,String> namespace = JSONUtils.toMap(this.namespace); |
||||
String namespaceName = namespace.get(NAMESPACE_NAME); |
||||
String clusterName = namespace.get(CLUSTER); |
||||
k8sTaskExecutor = new K8sTaskExecutor(null,taskRequest); |
||||
k8sTaskMainParameters = new K8sTaskMainParameters(); |
||||
k8sTaskMainParameters.setImage(image); |
||||
k8sTaskMainParameters.setNamespaceName(namespaceName); |
||||
k8sTaskMainParameters.setClusterName(clusterName); |
||||
k8sTaskMainParameters.setMinCpuCores(minCpuCores); |
||||
k8sTaskMainParameters.setMinMemorySpace(minMemorySpace); |
||||
job = k8sTaskExecutor.buildK8sJob(k8sTaskMainParameters); |
||||
} |
||||
@Test |
||||
public void testBuildK8sJobNormal() { |
||||
String jobStr = "Job(apiVersion=batch/v1, kind=Job, metadata=ObjectMeta(annotations=null, clusterName=null, creationTimestamp=null, deletionGracePeriodSeconds=null, deletionTimestamp=null, finalizers=[], generateName=null, generation=null, labels={k8s.cn/layer=batch, k8s.cn/name=k8s_task_test-1000}, managedFields=[], name=k8s_task_test-1000, namespace=default, ownerReferences=[], resourceVersion=null, selfLink=null, uid=null, additionalProperties={}), spec=JobSpec(activeDeadlineSeconds=null, backoffLimit=0, completionMode=null, completions=null, manualSelector=null, parallelism=null, selector=null, suspend=null, template=PodTemplateSpec(metadata=null, spec=PodSpec(activeDeadlineSeconds=null, affinity=null, automountServiceAccountToken=null, containers=[Container(args=[], command=[], env=[EnvVar(name=taskInstanceId, value=1000, valueFrom=null, additionalProperties={})], envFrom=[], image=ds-dev, imagePullPolicy=Always, lifecycle=null, livenessProbe=null, name=k8s_task_test-1000, ports=[], readinessProbe=null, resources=ResourceRequirements(limits={memory=20.0Mi, cpu=4.0}, requests={memory=10.0Mi, cpu=2.0}, additionalProperties={}), securityContext=null, startupProbe=null, stdin=null, stdinOnce=null, terminationMessagePath=null, terminationMessagePolicy=null, tty=null, volumeDevices=[], volumeMounts=[], workingDir=null, additionalProperties={})], dnsConfig=null, dnsPolicy=null, enableServiceLinks=null, ephemeralContainers=[], hostAliases=[], hostIPC=null, hostNetwork=null, hostPID=null, hostname=null, imagePullSecrets=[], initContainers=[], nodeName=null, nodeSelector=null, overhead=null, preemptionPolicy=null, priority=null, priorityClassName=null, readinessGates=[], restartPolicy=Never, runtimeClassName=null, schedulerName=null, securityContext=null, serviceAccount=null, serviceAccountName=null, setHostnameAsFQDN=null, shareProcessNamespace=null, subdomain=null, terminationGracePeriodSeconds=null, tolerations=[], topologySpreadConstraints=[], volumes=[], additionalProperties={}), additionalProperties={}), ttlSecondsAfterFinished=300, additionalProperties={}), status=null, additionalProperties={})"; |
||||
Assert.assertEquals(jobStr, job.toString()); |
||||
} |
||||
@Test |
||||
public void testGetJobNormal() { |
||||
k8sTaskExecutor.setJob(job); |
||||
String jobStr = "Job(apiVersion=batch/v1, kind=Job, metadata=ObjectMeta(annotations=null, clusterName=null, creationTimestamp=null, deletionGracePeriodSeconds=null, deletionTimestamp=null, finalizers=[], generateName=null, generation=null, labels={k8s.cn/layer=batch, k8s.cn/name=k8s_task_test-1000}, managedFields=[], name=k8s_task_test-1000, namespace=default, ownerReferences=[], resourceVersion=null, selfLink=null, uid=null, additionalProperties={}), spec=JobSpec(activeDeadlineSeconds=null, backoffLimit=0, completionMode=null, completions=null, manualSelector=null, parallelism=null, selector=null, suspend=null, template=PodTemplateSpec(metadata=null, spec=PodSpec(activeDeadlineSeconds=null, affinity=null, automountServiceAccountToken=null, containers=[Container(args=[], command=[], env=[EnvVar(name=taskInstanceId, value=1000, valueFrom=null, additionalProperties={})], envFrom=[], image=ds-dev, imagePullPolicy=Always, lifecycle=null, livenessProbe=null, name=k8s_task_test-1000, ports=[], readinessProbe=null, resources=ResourceRequirements(limits={memory=20.0Mi, cpu=4.0}, requests={memory=10.0Mi, cpu=2.0}, additionalProperties={}), securityContext=null, startupProbe=null, stdin=null, stdinOnce=null, terminationMessagePath=null, terminationMessagePolicy=null, tty=null, volumeDevices=[], volumeMounts=[], workingDir=null, additionalProperties={})], dnsConfig=null, dnsPolicy=null, enableServiceLinks=null, ephemeralContainers=[], hostAliases=[], hostIPC=null, hostNetwork=null, hostPID=null, hostname=null, imagePullSecrets=[], initContainers=[], nodeName=null, nodeSelector=null, overhead=null, preemptionPolicy=null, priority=null, priorityClassName=null, readinessGates=[], restartPolicy=Never, runtimeClassName=null, schedulerName=null, securityContext=null, serviceAccount=null, serviceAccountName=null, setHostnameAsFQDN=null, shareProcessNamespace=null, subdomain=null, terminationGracePeriodSeconds=null, tolerations=[], topologySpreadConstraints=[], volumes=[], additionalProperties={}), additionalProperties={}), ttlSecondsAfterFinished=300, additionalProperties={}), status=null, additionalProperties={})"; |
||||
Assert.assertEquals(jobStr,k8sTaskExecutor.getJob().toString()); |
||||
} |
||||
@Test |
||||
public void testGetK8sJobStatusNormal() { |
||||
JobStatus jobStatus = new JobStatus(); |
||||
jobStatus.setSucceeded(1); |
||||
job.setStatus(jobStatus); |
||||
Assert.assertEquals(0, Integer.compare(0,k8sTaskExecutor.getK8sJobStatus(job))); |
||||
} |
||||
@Test |
||||
public void testSetTaskStatusNormal() { |
||||
int jobStatus = 0; |
||||
TaskResponse taskResponse = new TaskResponse(); |
||||
K8sTaskMainParameters k8STaskMainParameters = new K8sTaskMainParameters(); |
||||
k8sTaskExecutor.setJob(job); |
||||
k8sTaskExecutor.setTaskStatus(jobStatus,String.valueOf(taskInstanceId),taskResponse,k8STaskMainParameters); |
||||
Assert.assertEquals(0, Integer.compare(EXIT_CODE_KILL,taskResponse.getExitStatusCode())); |
||||
} |
||||
@Test |
||||
public void testWaitTimeoutNormal() { |
||||
try { |
||||
k8sTaskExecutor.waitTimeout(true); |
||||
} catch (TaskException e) { |
||||
Assert.assertThat(e.getMessage(),is("K8sTask is timeout")); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,55 @@
|
||||
<?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>dev-SNAPSHOT</version> |
||||
</parent> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
|
||||
<artifactId>dolphinscheduler-task-k8s</artifactId> |
||||
<packaging>jar</packaging> |
||||
|
||||
<dependencies> |
||||
<dependency> |
||||
<groupId>org.apache.dolphinscheduler</groupId> |
||||
<artifactId>dolphinscheduler-datasource-all</artifactId> |
||||
</dependency> |
||||
|
||||
<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> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.apache.dolphinscheduler</groupId> |
||||
<artifactId>dolphinscheduler-datasource-api</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>com.fasterxml.jackson.core</groupId> |
||||
<artifactId>jackson-annotations</artifactId> |
||||
<scope>provided</scope> |
||||
</dependency> |
||||
|
||||
</dependencies> |
||||
</project> |
@ -0,0 +1,87 @@
|
||||
/* |
||||
* 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.k8s; |
||||
|
||||
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.CLUSTER; |
||||
import static org.apache.dolphinscheduler.plugin.task.api.TaskConstants.NAMESPACE_NAME; |
||||
|
||||
import org.apache.dolphinscheduler.plugin.task.api.TaskException; |
||||
import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext; |
||||
import org.apache.dolphinscheduler.plugin.task.api.k8s.AbstractK8sTask; |
||||
import org.apache.dolphinscheduler.plugin.task.api.k8s.K8sTaskMainParameters; |
||||
import org.apache.dolphinscheduler.plugin.task.api.model.Property; |
||||
import org.apache.dolphinscheduler.plugin.task.api.parameters.AbstractParameters; |
||||
import org.apache.dolphinscheduler.plugin.task.api.parser.ParamUtils; |
||||
import org.apache.dolphinscheduler.plugin.task.api.utils.MapUtils; |
||||
import org.apache.dolphinscheduler.spi.utils.JSONUtils; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
public class K8sTask extends AbstractK8sTask { |
||||
|
||||
/** |
||||
* taskExecutionContext |
||||
*/ |
||||
private final TaskExecutionContext taskExecutionContext; |
||||
|
||||
/** |
||||
* task parameters |
||||
*/ |
||||
private final K8sTaskParameters k8sTaskParameters; |
||||
|
||||
/** |
||||
* @param taskRequest taskRequest |
||||
*/ |
||||
public K8sTask(TaskExecutionContext taskRequest) { |
||||
super(taskRequest); |
||||
this.taskExecutionContext = taskRequest; |
||||
this.k8sTaskParameters = JSONUtils.parseObject(taskExecutionContext.getTaskParams(), K8sTaskParameters.class); |
||||
if (!k8sTaskParameters.checkParameters()) { |
||||
throw new TaskException("K8S task params is not valid"); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public AbstractParameters getParameters() { |
||||
return k8sTaskParameters; |
||||
} |
||||
|
||||
@Override |
||||
protected String buildCommand() { |
||||
K8sTaskMainParameters k8sTaskMainParameters = new K8sTaskMainParameters(); |
||||
Map<String, Property> paramsMap = ParamUtils.convert(taskExecutionContext,getParameters()); |
||||
if (MapUtils.isEmpty(paramsMap)) { |
||||
paramsMap = new HashMap<>(); |
||||
} |
||||
if (MapUtils.isNotEmpty(taskExecutionContext.getParamsMap())) { |
||||
paramsMap.putAll(taskExecutionContext.getParamsMap()); |
||||
} |
||||
Map<String,String> namespace = JSONUtils.toMap(k8sTaskParameters.getNamespace()); |
||||
String namespaceName = namespace.get(NAMESPACE_NAME); |
||||
String clusterName = namespace.get(CLUSTER); |
||||
k8sTaskMainParameters.setImage(k8sTaskParameters.getImage()); |
||||
k8sTaskMainParameters.setNamespaceName(namespaceName); |
||||
k8sTaskMainParameters.setClusterName(clusterName); |
||||
k8sTaskMainParameters.setMinCpuCores(k8sTaskParameters.getMinCpuCores()); |
||||
k8sTaskMainParameters.setMinMemorySpace(k8sTaskParameters.getMinMemorySpace()); |
||||
k8sTaskMainParameters.setParamsMap(ParamUtils.convert(paramsMap)); |
||||
return JSONUtils.toJsonString(k8sTaskMainParameters); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,49 @@
|
||||
/* |
||||
* 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.k8s; |
||||
|
||||
import org.apache.dolphinscheduler.plugin.task.api.AbstractTask; |
||||
import org.apache.dolphinscheduler.plugin.task.api.TaskChannel; |
||||
import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext; |
||||
import org.apache.dolphinscheduler.plugin.task.api.parameters.AbstractParameters; |
||||
import org.apache.dolphinscheduler.plugin.task.api.parameters.ParametersNode; |
||||
import org.apache.dolphinscheduler.plugin.task.api.parameters.resource.ResourceParametersHelper; |
||||
import org.apache.dolphinscheduler.spi.utils.JSONUtils; |
||||
|
||||
public class K8sTaskChannel implements TaskChannel { |
||||
@Override |
||||
public void cancelApplication(boolean status) { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public AbstractParameters parseParameters(ParametersNode parametersNode) { |
||||
return JSONUtils.parseObject(parametersNode.getTaskParams(), K8sTaskParameters.class); |
||||
} |
||||
|
||||
@Override |
||||
public ResourceParametersHelper getResources(String parameters) { |
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
public AbstractTask createTask(TaskExecutionContext taskRequest) { |
||||
return new K8sTask(taskRequest); |
||||
} |
||||
|
||||
} |
@ -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.k8s; |
||||
|
||||
import org.apache.dolphinscheduler.plugin.task.api.TaskChannel; |
||||
import org.apache.dolphinscheduler.plugin.task.api.TaskChannelFactory; |
||||
import org.apache.dolphinscheduler.spi.params.base.PluginParams; |
||||
|
||||
import java.util.List; |
||||
|
||||
import com.google.auto.service.AutoService; |
||||
|
||||
@AutoService(TaskChannelFactory.class) |
||||
public class K8sTaskChannelFactory implements TaskChannelFactory { |
||||
@Override |
||||
public String getName() { |
||||
return "K8S"; |
||||
} |
||||
|
||||
@Override |
||||
public List<PluginParams> getParams() { |
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
public TaskChannel create() { |
||||
return new K8sTaskChannel(); |
||||
} |
||||
} |
@ -0,0 +1,88 @@
|
||||
/* |
||||
* 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.k8s; |
||||
|
||||
import org.apache.dolphinscheduler.plugin.task.api.model.ResourceInfo; |
||||
import org.apache.dolphinscheduler.plugin.task.api.parameters.AbstractParameters; |
||||
import org.apache.dolphinscheduler.spi.utils.StringUtils; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* k8s task parameters |
||||
*/ |
||||
public class K8sTaskParameters extends AbstractParameters { |
||||
private String image; |
||||
private String namespace; |
||||
private double minCpuCores; |
||||
private double minMemorySpace; |
||||
|
||||
public String getImage() { |
||||
return image; |
||||
} |
||||
|
||||
public void setImage(String image) { |
||||
this.image = image; |
||||
} |
||||
|
||||
public String getNamespace() { |
||||
return namespace; |
||||
} |
||||
|
||||
public void setNamespace(String namespace) { |
||||
this.namespace = namespace; |
||||
} |
||||
|
||||
public double getMinCpuCores() { |
||||
return minCpuCores; |
||||
} |
||||
|
||||
public void setMinCpuCores(double minCpuCores) { |
||||
this.minCpuCores = minCpuCores; |
||||
} |
||||
|
||||
public double getMinMemorySpace() { |
||||
return minMemorySpace; |
||||
} |
||||
|
||||
public void setMinMemorySpace(double minMemorySpace) { |
||||
this.minMemorySpace = minMemorySpace; |
||||
} |
||||
|
||||
@Override |
||||
public boolean checkParameters() { |
||||
return StringUtils.isNotEmpty(image) && StringUtils.isNotEmpty(namespace) |
||||
; |
||||
} |
||||
|
||||
@Override |
||||
public List<ResourceInfo> getResourceFilesList() { |
||||
return new ArrayList<>(); |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return "K8sTaskParameters{" |
||||
+ "image='" + image + '\'' |
||||
+ ", namespace='" + namespace + '\'' |
||||
+ ", minCpuCores=" + minCpuCores |
||||
+ ", minMemorySpace=" + minMemorySpace |
||||
+ '}'; |
||||
} |
||||
} |
@ -0,0 +1,58 @@
|
||||
/* |
||||
* 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.k8s; |
||||
import org.junit.Assert; |
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
|
||||
public class K8sParametersTest { |
||||
private K8sTaskParameters k8sTaskParameters = null; |
||||
private final String image = "ds-dev"; |
||||
private final String namespace = "{\"name\":\"default\",\"cluster\":\"lab\"}"; |
||||
private final double minCpuCores = 2; |
||||
private final double minMemorySpace = 10; |
||||
|
||||
@Before |
||||
public void before() { |
||||
k8sTaskParameters = new K8sTaskParameters(); |
||||
k8sTaskParameters.setImage(image); |
||||
k8sTaskParameters.setNamespace(namespace); |
||||
k8sTaskParameters.setMinCpuCores(minCpuCores); |
||||
k8sTaskParameters.setMinMemorySpace(minMemorySpace); |
||||
} |
||||
|
||||
@Test |
||||
public void testCheckParameterNormal() { |
||||
Assert.assertTrue(k8sTaskParameters.checkParameters()); |
||||
} |
||||
|
||||
@Test |
||||
public void testGetResourceFilesListNormal() { |
||||
Assert.assertNotNull(k8sTaskParameters.getResourceFilesList()); |
||||
Assert.assertEquals(0, k8sTaskParameters.getResourceFilesList().size()); |
||||
} |
||||
|
||||
@Test |
||||
public void testK8sParameters() { |
||||
Assert.assertEquals(image, k8sTaskParameters.getImage()); |
||||
Assert.assertEquals(namespace, k8sTaskParameters.getNamespace()); |
||||
Assert.assertEquals(0, Double.compare(minCpuCores, k8sTaskParameters.getMinCpuCores())); |
||||
Assert.assertEquals(0,Double.compare(minMemorySpace, k8sTaskParameters.getMinMemorySpace())); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,85 @@
|
||||
/* |
||||
* 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.k8s; |
||||
|
||||
import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext; |
||||
import org.apache.dolphinscheduler.plugin.task.api.enums.DataType; |
||||
import org.apache.dolphinscheduler.plugin.task.api.enums.Direct; |
||||
import org.apache.dolphinscheduler.plugin.task.api.model.Property; |
||||
import org.apache.dolphinscheduler.spi.utils.JSONUtils; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
import org.junit.Assert; |
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
|
||||
public class K8sTaskTest { |
||||
private K8sTaskParameters k8sTaskParameters = null; |
||||
|
||||
private K8sTask k8sTask = null; |
||||
private final String image = "ds-dev"; |
||||
|
||||
private final String namespace = "{\"name\":\"default\",\"cluster\":\"lab\"}"; |
||||
|
||||
private final double minCpuCores = 2; |
||||
|
||||
private final double minMemorySpace = 10; |
||||
private final int taskInstanceId = 1000; |
||||
private final String taskName = "k8s_task_test"; |
||||
|
||||
private final String DAY = "day"; |
||||
private final String date = "20220507"; |
||||
@Before |
||||
public void before() { |
||||
k8sTaskParameters = new K8sTaskParameters(); |
||||
k8sTaskParameters.setImage(image); |
||||
k8sTaskParameters.setNamespace(namespace); |
||||
k8sTaskParameters.setMinCpuCores(minCpuCores); |
||||
k8sTaskParameters.setMinMemorySpace(minMemorySpace); |
||||
TaskExecutionContext taskRequest = new TaskExecutionContext(); |
||||
taskRequest.setTaskInstanceId(taskInstanceId); |
||||
taskRequest.setTaskName(taskName); |
||||
taskRequest.setTaskParams(JSONUtils.toJsonString(k8sTaskParameters)); |
||||
Property property = new Property(); |
||||
property.setProp(DAY); |
||||
property.setDirect(Direct.IN); |
||||
property.setType(DataType.VARCHAR); |
||||
property.setValue(date); |
||||
Map<String, Property> paramsMap = new HashMap<>(); |
||||
paramsMap.put(DAY,property); |
||||
taskRequest.setParamsMap(paramsMap); |
||||
k8sTask = new K8sTask(taskRequest); |
||||
} |
||||
|
||||
@Test |
||||
public void testBuildCommandNormal() { |
||||
String expectedStr = "{\"image\":\"ds-dev\",\"namespaceName\":\"default\",\"clusterName\":\"lab\",\"minCpuCores\":2.0,\"minMemorySpace\":10.0,\"paramsMap\":{\"day\":\"20220507\"}}"; |
||||
String commandStr = k8sTask.buildCommand(); |
||||
Assert.assertEquals(expectedStr, commandStr); |
||||
} |
||||
|
||||
@Test |
||||
public void testGetParametersNormal() { |
||||
String expectedStr = "K8sTaskParameters{image='ds-dev', namespace='{\"name\":\"default\",\"cluster\":\"lab\"}', minCpuCores=2.0, minMemorySpace=10.0}"; |
||||
String result = k8sTask.getParameters().toString(); |
||||
Assert.assertEquals(expectedStr, result); |
||||
} |
||||
|
||||
} |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.4 KiB |
@ -0,0 +1,58 @@
|
||||
/* |
||||
* 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 { useCustomParams, useNamespace } from '.' |
||||
import type { IJsonItem } from '../types' |
||||
import { useI18n } from 'vue-i18n' |
||||
|
||||
export function useK8s(model: { [field: string]: any }): IJsonItem[] { |
||||
const { t } = useI18n() |
||||
|
||||
return [ |
||||
useNamespace(), |
||||
{ |
||||
type: 'input-number', |
||||
field: 'minCpuCores', |
||||
span: 12, |
||||
name: t('project.node.min_cpu'), |
||||
slots: { |
||||
suffix: () => t('project.node.cores') |
||||
} |
||||
}, |
||||
{ |
||||
type: 'input-number', |
||||
field: 'minMemorySpace', |
||||
span: 12, |
||||
name: t('project.node.min_memory'), |
||||
slots: { |
||||
suffix: () => t('project.node.mb') |
||||
} |
||||
}, |
||||
{ |
||||
type: 'input', |
||||
field: 'image', |
||||
name: t('project.node.image'), |
||||
props: { |
||||
placeholder: t('project.node.image_tips') |
||||
}, |
||||
validate: { |
||||
trigger: ['input', 'blur'], |
||||
message: t('project.node.min_memory_tips') |
||||
} |
||||
}, |
||||
...useCustomParams({ model, field: 'localParams', isSimple: true }) |
||||
] |
||||
} |
@ -0,0 +1,71 @@
|
||||
/* |
||||
* 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 type { IJsonItem } from '../types' |
||||
import { useI18n } from 'vue-i18n' |
||||
import { onMounted, ref, VNodeChild } from 'vue' |
||||
import { getAllNamespaces } from '@/service/modules/k8s-namespace' |
||||
import { SelectOption } from 'naive-ui' |
||||
|
||||
export function useNamespace(): IJsonItem { |
||||
const { t } = useI18n() |
||||
|
||||
const options = ref([]) |
||||
const loading = ref(false) |
||||
|
||||
const getNamespaceList = async () => { |
||||
if (loading.value) return |
||||
loading.value = true |
||||
const totalList = await getAllNamespaces() |
||||
options.value = (totalList || []).map( |
||||
(item: { id: string; namespace: string; k8s: string }) => ({ |
||||
label: `${item.namespace}(${item.k8s})`, |
||||
value: JSON.stringify({ |
||||
name: item.namespace, |
||||
cluster: item.k8s |
||||
}) |
||||
}) |
||||
) |
||||
loading.value = false |
||||
} |
||||
|
||||
onMounted(() => { |
||||
getNamespaceList() |
||||
}) |
||||
|
||||
const renderLabel = (option: SelectOption): VNodeChild => { |
||||
if (option.type === 'group') return option.label as string |
||||
return [option.label as string] |
||||
} |
||||
|
||||
return { |
||||
type: 'select', |
||||
field: 'namespace', |
||||
name: t('project.node.namespace_cluster'), |
||||
props: { |
||||
loading, |
||||
'render-label': renderLabel |
||||
}, |
||||
options: [ |
||||
{ |
||||
type: 'group', |
||||
label: t('project.node.namespace_cluster'), |
||||
key: t('project.node.namespace_cluster'), |
||||
children: options as any |
||||
} |
||||
] |
||||
} |
||||
} |
@ -0,0 +1,81 @@
|
||||
/* |
||||
* 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 { reactive } from 'vue' |
||||
import * as Fields from '../fields/index' |
||||
import type { IJsonItem, INodeData } from '../types' |
||||
import { ITaskData } from '../types' |
||||
|
||||
export function useK8s({ |
||||
projectCode, |
||||
from = 0, |
||||
readonly, |
||||
data |
||||
}: { |
||||
projectCode: number |
||||
from?: number |
||||
readonly?: boolean |
||||
data?: ITaskData |
||||
}) { |
||||
const model = reactive({ |
||||
name: '', |
||||
taskType: 'K8S', |
||||
flag: 'YES', |
||||
description: '', |
||||
timeoutFlag: false, |
||||
localParams: [], |
||||
environmentCode: null, |
||||
failRetryInterval: 1, |
||||
failRetryTimes: 0, |
||||
workerGroup: 'default', |
||||
delayTime: 0, |
||||
timeout: 30 |
||||
} as INodeData) |
||||
|
||||
let extra: IJsonItem[] = [] |
||||
if (from === 1) { |
||||
extra = [ |
||||
Fields.useTaskType(model, readonly), |
||||
Fields.useProcessName({ |
||||
model, |
||||
projectCode, |
||||
isCreate: !data?.id, |
||||
from, |
||||
processName: data?.processName |
||||
}) |
||||
] |
||||
} |
||||
|
||||
return { |
||||
json: [ |
||||
Fields.useName(), |
||||
...extra, |
||||
Fields.useRunFlag(), |
||||
Fields.useDescription(), |
||||
Fields.useTaskPriority(), |
||||
Fields.useWorkerGroup(), |
||||
Fields.useEnvironmentName(model, !model.id), |
||||
...Fields.useTaskGroup(model, projectCode), |
||||
...Fields.useFailed(), |
||||
Fields.useDelayTime(model), |
||||
...Fields.useTimeoutAlarm(model), |
||||
...Fields.useK8s(model), |
||||
Fields.usePreTasks() |
||||
] as IJsonItem[], |
||||
model |
||||
} |
||||
} |
Loading…
Reference in new issue