Browse Source

[FEATURE][#841]Add HTTP components(添加HTTP组件) (#842)

* Add HTTP components(添加HTTP组件)

* HTTP组件的相关代码优化

* Repair HTTP Component Related Code Based on Optimized Recommendations
(基于优化建议的http组件相关代码修复)

* Repair HTTP connection leak problem
(修复http连接泄漏问题)
pull/2/head
黄聪 5 years ago committed by Baoqi Wu
parent
commit
6525440c94
  1. 30
      escheduler-common/src/main/java/cn/escheduler/common/enums/HttpCheckCondition.java
  2. 31
      escheduler-common/src/main/java/cn/escheduler/common/enums/HttpMethod.java
  3. 29
      escheduler-common/src/main/java/cn/escheduler/common/enums/HttpParametersType.java
  4. 3
      escheduler-common/src/main/java/cn/escheduler/common/enums/TaskType.java
  5. 125
      escheduler-common/src/main/java/cn/escheduler/common/process/HttpProperty.java
  6. 108
      escheduler-common/src/main/java/cn/escheduler/common/task/http/HttpParameters.java
  7. 3
      escheduler-common/src/main/java/cn/escheduler/common/utils/TaskParametersUtils.java
  8. 3
      escheduler-server/src/main/java/cn/escheduler/server/worker/task/TaskManager.java
  9. 270
      escheduler-server/src/main/java/cn/escheduler/server/worker/task/http/HttpTask.java
  10. 4
      escheduler-ui/src/js/conf/home/pages/dag/_source/config.js
  11. 3
      escheduler-ui/src/js/conf/home/pages/dag/_source/dag.scss
  12. 8
      escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/formModel.vue
  13. 18
      escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/_source/commcon.js
  14. 242
      escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/_source/httpParams.vue
  15. 191
      escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/http.vue
  16. BIN
      escheduler-ui/src/js/conf/home/pages/dag/img/toobar_HTTP.png
  17. 14
      escheduler-ui/src/js/module/i18n/locale/en_US.js
  18. 15
      escheduler-ui/src/js/module/i18n/locale/zh_CN.js

30
escheduler-common/src/main/java/cn/escheduler/common/enums/HttpCheckCondition.java

@ -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 cn.escheduler.common.enums;
/**
* http check condition
*/
public enum HttpCheckCondition {
/**
* 0 status_code_default:200
* 1 status_code_custom
* 2 body_contains
* 3 body_not_contains
*/
STATUS_CODE_DEFAULT,STATUS_CODE_CUSTOM, BODY_CONTAINS, BODY_NOT_CONTAINS
}

31
escheduler-common/src/main/java/cn/escheduler/common/enums/HttpMethod.java

@ -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 cn.escheduler.common.enums;
/**
* http method
*/
public enum HttpMethod {
/**
* 0 get
* 1 post
* 2 head
* 3 put
* 4 delete
*/
GET, POST, HEAD, PUT, DELETE
}

29
escheduler-common/src/main/java/cn/escheduler/common/enums/HttpParametersType.java

@ -0,0 +1,29 @@
/*
* 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 cn.escheduler.common.enums;
/**
* http parameters type
*/
public enum HttpParametersType {
/**
* 0 parameter;
* 1 body;
* 2 headers;
*/
PARAMETER,BODY,HEADERS
}

3
escheduler-common/src/main/java/cn/escheduler/common/enums/TaskType.java

@ -30,8 +30,9 @@ public enum TaskType {
* 6 PYTHON * 6 PYTHON
* 7 DEPENDENT * 7 DEPENDENT
* 8 FLINK * 8 FLINK
* 9 HTTP
*/ */
SHELL,SQL, SUB_PROCESS,PROCEDURE,MR,SPARK,PYTHON,DEPENDENT,FLINK; SHELL,SQL, SUB_PROCESS,PROCEDURE,MR,SPARK,PYTHON,DEPENDENT,FLINK,HTTP;
public static boolean typeIsNormalTask(String typeName) { public static boolean typeIsNormalTask(String typeName) {
TaskType taskType = TaskType.valueOf(typeName); TaskType taskType = TaskType.valueOf(typeName);

125
escheduler-common/src/main/java/cn/escheduler/common/process/HttpProperty.java

@ -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 cn.escheduler.common.process;
import cn.escheduler.common.enums.HttpParametersType;
import java.util.Objects;
public class HttpProperty {
/**
* key
*/
private String prop;
/**
* httpParametersType
*/
private HttpParametersType httpParametersType;
/**
* value
*/
private String value;
public HttpProperty() {
}
public HttpProperty(String prop, HttpParametersType httpParametersType, String value) {
this.prop = prop;
this.httpParametersType = httpParametersType;
this.value = value;
}
/**
* getter method
*
* @return the prop
* @see HttpProperty#prop
*/
public String getProp() {
return prop;
}
/**
* setter method
*
* @param prop the prop to set
* @see HttpProperty#prop
*/
public void setProp(String prop) {
this.prop = prop;
}
/**
* getter method
*
* @return the value
* @see HttpProperty#value
*/
public String getValue() {
return value;
}
/**
* setter method
*
* @param value the value to set
* @see HttpProperty#value
*/
public void setValue(String value) {
this.value = value;
}
public HttpParametersType getHttpParametersType() {
return httpParametersType;
}
public void setHttpParametersType(HttpParametersType httpParametersType) {
this.httpParametersType = httpParametersType;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
HttpProperty property = (HttpProperty) 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 "HttpProperty{" +
"prop='" + prop + '\'' +
", httpParametersType=" + httpParametersType +
", value='" + value + '\'' +
'}';
}
}

108
escheduler-common/src/main/java/cn/escheduler/common/task/http/HttpParameters.java

@ -0,0 +1,108 @@
/*
* 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 cn.escheduler.common.task.http;
import cn.escheduler.common.enums.HttpCheckCondition;
import cn.escheduler.common.enums.HttpMethod;
import cn.escheduler.common.process.HttpProperty;
import cn.escheduler.common.task.AbstractParameters;
import org.apache.commons.lang.StringUtils;
import java.util.ArrayList;
import java.util.List;
/**
* http parameter
*/
public class HttpParameters extends AbstractParameters {
/**
* url
*/
private String url;
/**
* httpMethod
*/
private HttpMethod httpMethod;
/**
* http params
*/
private List<HttpProperty> httpParams;
/**
* httpCheckCondition
*/
private HttpCheckCondition httpCheckCondition = HttpCheckCondition.STATUS_CODE_DEFAULT;
/**
* condition
*/
private String condition;
@Override
public boolean checkParameters() {
return StringUtils.isNotEmpty(url);
}
@Override
public List<String> getResourceFilesList() {
return new ArrayList<>();
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public HttpMethod getHttpMethod() {
return httpMethod;
}
public void setHttpMethod(HttpMethod httpMethod) {
this.httpMethod = httpMethod;
}
public List<HttpProperty> getHttpParams() {
return httpParams;
}
public void setHttpParams(List<HttpProperty> httpParams) {
this.httpParams = httpParams;
}
public HttpCheckCondition getHttpCheckCondition() {
return httpCheckCondition;
}
public void setHttpCheckCondition(HttpCheckCondition httpCheckCondition) {
this.httpCheckCondition = httpCheckCondition;
}
public String getCondition() {
return condition;
}
public void setCondition(String condition) {
this.condition = condition;
}
}

3
escheduler-common/src/main/java/cn/escheduler/common/utils/TaskParametersUtils.java

@ -20,6 +20,7 @@ import cn.escheduler.common.enums.TaskType;
import cn.escheduler.common.task.AbstractParameters; import cn.escheduler.common.task.AbstractParameters;
import cn.escheduler.common.task.dependent.DependentParameters; import cn.escheduler.common.task.dependent.DependentParameters;
import cn.escheduler.common.task.flink.FlinkParameters; import cn.escheduler.common.task.flink.FlinkParameters;
import cn.escheduler.common.task.http.HttpParameters;
import cn.escheduler.common.task.mr.MapreduceParameters; import cn.escheduler.common.task.mr.MapreduceParameters;
import cn.escheduler.common.task.procedure.ProcedureParameters; import cn.escheduler.common.task.procedure.ProcedureParameters;
import cn.escheduler.common.task.python.PythonParameters; import cn.escheduler.common.task.python.PythonParameters;
@ -66,6 +67,8 @@ public class TaskParametersUtils {
return JSONUtils.parseObject(parameter, DependentParameters.class); return JSONUtils.parseObject(parameter, DependentParameters.class);
case FLINK: case FLINK:
return JSONUtils.parseObject(parameter, FlinkParameters.class); return JSONUtils.parseObject(parameter, FlinkParameters.class);
case HTTP:
return JSONUtils.parseObject(parameter, HttpParameters.class);
default: default:
return null; return null;
} }

3
escheduler-server/src/main/java/cn/escheduler/server/worker/task/TaskManager.java

@ -20,6 +20,7 @@ package cn.escheduler.server.worker.task;
import cn.escheduler.common.enums.TaskType; import cn.escheduler.common.enums.TaskType;
import cn.escheduler.server.worker.task.dependent.DependentTask; import cn.escheduler.server.worker.task.dependent.DependentTask;
import cn.escheduler.server.worker.task.flink.FlinkTask; import cn.escheduler.server.worker.task.flink.FlinkTask;
import cn.escheduler.server.worker.task.http.HttpTask;
import cn.escheduler.server.worker.task.mr.MapReduceTask; import cn.escheduler.server.worker.task.mr.MapReduceTask;
import cn.escheduler.server.worker.task.processdure.ProcedureTask; import cn.escheduler.server.worker.task.processdure.ProcedureTask;
import cn.escheduler.server.worker.task.python.PythonTask; import cn.escheduler.server.worker.task.python.PythonTask;
@ -62,6 +63,8 @@ public class TaskManager {
return new PythonTask(props, logger); return new PythonTask(props, logger);
case DEPENDENT: case DEPENDENT:
return new DependentTask(props, logger); return new DependentTask(props, logger);
case HTTP:
return new HttpTask(props, logger);
default: default:
logger.error("unsupport task type: {}", taskType); logger.error("unsupport task type: {}", taskType);
throw new IllegalArgumentException("not support task type"); throw new IllegalArgumentException("not support task type");

270
escheduler-server/src/main/java/cn/escheduler/server/worker/task/http/HttpTask.java

@ -0,0 +1,270 @@
/*
* 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 cn.escheduler.server.worker.task.http;
import cn.escheduler.common.enums.HttpMethod;
import cn.escheduler.common.enums.HttpParametersType;
import cn.escheduler.common.process.HttpProperty;
import cn.escheduler.common.process.Property;
import cn.escheduler.common.task.AbstractParameters;
import cn.escheduler.common.task.http.HttpParameters;
import cn.escheduler.common.utils.Bytes;
import cn.escheduler.common.utils.DateUtils;
import cn.escheduler.common.utils.ParameterUtils;
import cn.escheduler.dao.DaoFactory;
import cn.escheduler.dao.ProcessDao;
import cn.escheduler.dao.model.ProcessInstance;
import cn.escheduler.server.utils.ParamUtils;
import cn.escheduler.server.worker.task.AbstractTask;
import cn.escheduler.server.worker.task.TaskProps;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.io.Charsets;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.ParseException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* http task
*/
public class HttpTask extends AbstractTask {
private HttpParameters httpParameters;
/**
* process database access
*/
private ProcessDao processDao;
/**
* Convert mill seconds to second unit
*/
protected static final int MAX_CONNECTION_MILLISECONDS = 60000;
protected static final String APPLICATION_JSON = "application/json";
protected String output;
public HttpTask(TaskProps props, Logger logger) {
super(props, logger);
this.processDao = DaoFactory.getDaoInstance(ProcessDao.class);
}
@Override
public void init() {
logger.info("http task params {}", taskProps.getTaskParams());
this.httpParameters = JSONObject.parseObject(taskProps.getTaskParams(), HttpParameters.class);
if (!httpParameters.checkParameters()) {
throw new RuntimeException("http task params is not valid");
}
}
@Override
public void handle() throws Exception {
String threadLoggerInfoName = String.format("TaskLogInfo-%s", taskProps.getTaskAppId());
Thread.currentThread().setName(threadLoggerInfoName);
long startTime = System.currentTimeMillis();
String statusCode = null;
String body = null;
try(CloseableHttpClient client = createHttpClient()) {
try(CloseableHttpResponse response = sendRequest(client)) {
statusCode = String.valueOf(getStatusCode(response));
body = getResponseBody(response);
exitStatusCode = validResponse(body, statusCode);
long costTime = System.currentTimeMillis() - startTime;
logger.info("startTime: {}, httpUrl: {}, httpMethod: {}, costTime : {}Millisecond, statusCode : {}, body : {}, log : {}",
DateUtils.format2Readable(startTime), httpParameters.getUrl(),httpParameters.getHttpMethod(), costTime, statusCode, body, output);
}catch (Exception e) {
appendMessage(e.toString());
exitStatusCode = -1;
logger.error("httpUrl[" + httpParameters.getUrl() + "] connection failed:"+output, e);
}
} catch (Exception e) {
appendMessage(e.toString());
exitStatusCode = -1;
logger.error("httpUrl[" + httpParameters.getUrl() + "] connection failed:"+output, e);
}
}
protected CloseableHttpResponse sendRequest(CloseableHttpClient client) throws IOException {
RequestBuilder builder = createRequestBuilder();
ProcessInstance processInstance = processDao.findProcessInstanceByTaskId(taskProps.getTaskInstId());
Map<String, Property> paramsMap = ParamUtils.convert(taskProps.getUserDefParamsMap(),
taskProps.getDefinedParams(),
httpParameters.getLocalParametersMap(),
processInstance.getCmdTypeIfComplement(),
processInstance.getScheduleTime());
List<HttpProperty> httpPropertyList = new ArrayList<>();
if(httpParameters.getHttpParams() != null && httpParameters.getHttpParams().size() > 0){
for (HttpProperty httpProperty: httpParameters.getHttpParams()) {
String jsonObject = JSONObject.toJSONString(httpProperty);
String params = ParameterUtils.convertParameterPlaceholders(jsonObject,ParamUtils.convert(paramsMap));
logger.info("http request params:{}",params);
httpPropertyList.add(JSONObject.parseObject(params,HttpProperty.class));
}
}
addRequestParams(builder,httpPropertyList);
HttpUriRequest request = builder.setUri(httpParameters.getUrl()).build();
setHeaders(request,httpPropertyList);
return client.execute(request);
}
protected String getResponseBody(CloseableHttpResponse httpResponse) throws ParseException, IOException {
if (httpResponse == null) {
return null;
}
HttpEntity entity = httpResponse.getEntity();
if (entity == null) {
return null;
}
String webPage = EntityUtils.toString(entity, Bytes.UTF8_ENCODING);
return webPage;
}
protected int getStatusCode(CloseableHttpResponse httpResponse) {
int status = httpResponse.getStatusLine().getStatusCode();
return status;
}
protected int validResponse(String body, String statusCode){
int exitStatusCode = 0;
switch (httpParameters.getHttpCheckCondition()) {
case BODY_CONTAINS:
if (StringUtils.isEmpty(body) || !body.contains(httpParameters.getCondition())) {
appendMessage(httpParameters.getUrl() + " doesn contain "
+ httpParameters.getCondition());
exitStatusCode = -1;
}
break;
case BODY_NOT_CONTAINS:
if (StringUtils.isEmpty(body) || body.contains(httpParameters.getCondition())) {
appendMessage(httpParameters.getUrl() + " contains "
+ httpParameters.getCondition());
exitStatusCode = -1;
}
break;
case STATUS_CODE_CUSTOM:
if (!statusCode.equals(httpParameters.getCondition())) {
appendMessage(httpParameters.getUrl() + " statuscode: " + statusCode + ", Must be: " + httpParameters.getCondition());
exitStatusCode = -1;
}
break;
default:
if (!"200".equals(statusCode)) {
appendMessage(httpParameters.getUrl() + " statuscode: " + statusCode + ", Must be: 200");
exitStatusCode = -1;
}
break;
}
return exitStatusCode;
}
public String getOutput() {
return output;
}
protected void appendMessage(String message) {
if (output == null) {
output = "";
}
if (message != null && !message.trim().isEmpty()) {
output += message;
}
}
protected void addRequestParams(RequestBuilder builder,List<HttpProperty> httpPropertyList) {
if(httpPropertyList != null && httpPropertyList.size() > 0){
JSONObject jsonParam = new JSONObject();
for (HttpProperty property: httpPropertyList){
if(property.getHttpParametersType() != null){
if (property.getHttpParametersType().equals(HttpParametersType.PARAMETER)){
builder.addParameter(property.getProp(), property.getValue());
}else if(property.getHttpParametersType().equals(HttpParametersType.BODY)){
jsonParam.put(property.getProp(), property.getValue());
}
}
}
StringEntity postingString = new StringEntity(jsonParam.toString(), Charsets.UTF_8);
postingString.setContentEncoding(Bytes.UTF8_ENCODING);
postingString.setContentType(APPLICATION_JSON);
builder.setEntity(postingString);
}
}
protected void setHeaders(HttpUriRequest request,List<HttpProperty> httpPropertyList) {
if(httpPropertyList != null && httpPropertyList.size() > 0){
for (HttpProperty property: httpPropertyList){
if(property.getHttpParametersType() != null) {
if (property.getHttpParametersType().equals(HttpParametersType.HEADERS)) {
request.addHeader(property.getProp(), property.getValue());
}
}
}
}
}
protected CloseableHttpClient createHttpClient() {
final RequestConfig requestConfig = requestConfig();
HttpClientBuilder httpClientBuilder;
httpClientBuilder = HttpClients.custom().setDefaultRequestConfig(requestConfig);
return httpClientBuilder.build();
}
private RequestConfig requestConfig() {
return RequestConfig.custom().setSocketTimeout(MAX_CONNECTION_MILLISECONDS).setConnectTimeout(MAX_CONNECTION_MILLISECONDS).build();
}
protected RequestBuilder createRequestBuilder() {
if (httpParameters.getHttpMethod().equals(HttpMethod.GET)) {
return RequestBuilder.get();
} else if (httpParameters.getHttpMethod().equals(HttpMethod.POST)) {
return RequestBuilder.post();
} else if (httpParameters.getHttpMethod().equals(HttpMethod.HEAD)) {
return RequestBuilder.head();
} else if (httpParameters.getHttpMethod().equals(HttpMethod.PUT)) {
return RequestBuilder.put();
} else if (httpParameters.getHttpMethod().equals(HttpMethod.DELETE)) {
return RequestBuilder.delete();
} else {
return null;
}
}
@Override
public AbstractParameters getParameters() {
return this.httpParameters;
}
}

4
escheduler-ui/src/js/conf/home/pages/dag/_source/config.js

@ -275,6 +275,10 @@ let tasksType = {
'DEPENDENT': { 'DEPENDENT': {
desc: 'DEPENDENT', desc: 'DEPENDENT',
color: '#2FBFD8' color: '#2FBFD8'
},
'HTTP': {
desc: 'HTTP',
color: '#E46F13'
} }
} }

3
escheduler-ui/src/js/conf/home/pages/dag/_source/dag.scss

@ -82,6 +82,9 @@
.icos-DEPENDENT { .icos-DEPENDENT {
background: url("../img/toolbar_DEPENDENT.png") no-repeat 50% 50%; background: url("../img/toolbar_DEPENDENT.png") no-repeat 50% 50%;
} }
.icos-HTTP {
background: url("../img/toobar_HTTP.png") no-repeat 50% 50%;
}
.toolbar { .toolbar {
width: 60px; width: 60px;
height: 100%; height: 100%;

8
escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/formModel.vue

@ -165,6 +165,12 @@
ref="DEPENDENT" ref="DEPENDENT"
:backfill-item="backfillItem"> :backfill-item="backfillItem">
</m-dependent> </m-dependent>
<m-http
v-if="taskType === 'HTTP'"
@on-params="_onParams"
ref="HTTP"
:backfill-item="backfillItem">
</m-http>
</div> </div>
</div> </div>
@ -189,6 +195,7 @@
import JSP from './../plugIn/jsPlumbHandle' import JSP from './../plugIn/jsPlumbHandle'
import mProcedure from './tasks/procedure' import mProcedure from './tasks/procedure'
import mDependent from './tasks/dependent' import mDependent from './tasks/dependent'
import mHttp from './tasks/http'
import mSubProcess from './tasks/sub_process' import mSubProcess from './tasks/sub_process'
import mSelectInput from './_source/selectInput' import mSelectInput from './_source/selectInput'
import mTimeoutAlarm from './_source/timeoutAlarm' import mTimeoutAlarm from './_source/timeoutAlarm'
@ -465,6 +472,7 @@
mFlink, mFlink,
mPython, mPython,
mDependent, mDependent,
mHttp,
mSelectInput, mSelectInput,
mTimeoutAlarm, mTimeoutAlarm,
mPriority, mPriority,

18
escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/_source/commcon.js

@ -202,10 +202,26 @@ const sqlTypeList = [
} }
] ]
const positionList = [
{
id: 'PARAMETER',
code: "Parameter"
},
{
id: 'BODY',
code: "Body"
},
{
id: 'HEADERS',
code: "Headers"
}
]
export { export {
cycleList, cycleList,
dateValueList, dateValueList,
typeList, typeList,
directList, directList,
sqlTypeList sqlTypeList,
positionList
} }

242
escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/_source/httpParams.vue

@ -0,0 +1,242 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
<template>
<div class="user-def-params-model">
<div class="select-listpp"
v-for="(item,$index) in httpParamsList"
:key="item.id"
@click="_getIndex($index)">
<x-input
:disabled="isDetails"
type="text"
v-model="httpParamsList[$index].prop"
:placeholder="$t('prop(required)')"
@on-blur="_verifProp()"
:style="inputStyle">
</x-input>
<x-select
@change="_handlePositionChanged"
v-model="httpParamsList[$index].httpParametersType"
:placeholder="$t('Http Parameters Position')"
:disabled="isDetails"
:style="inputStyle"
>
<x-option
v-for="position in positionList"
:key="position.code"
:value="position.id"
:label="position.code">
</x-option>
</x-select>
<x-input
:disabled="isDetails"
type="text"
v-model="httpParamsList[$index].value"
:placeholder="$t('value(required)')"
@on-blur="_handleValue()"
:style="inputStyle">
</x-input>
<span class="lt-add">
<a href="javascript:" style="color:red;" @click="!isDetails && _removeUdp($index)" >
<i class="iconfont" :class="_isDetails" data-toggle="tooltip" :title="$t('delete')" >&#xe611;</i>
</a>
</span>
<span class="add" v-if="$index === (httpParamsList.length - 1)">
<a href="javascript:" @click="!isDetails && _addUdp()" >
<i class="iconfont" :class="_isDetails" data-toggle="tooltip" :title="$t('Add')">&#xe636;</i>
</a>
</span>
</div>
<span class="add-dp" v-if="!httpParamsList.length">
<a href="javascript:" @click="!isDetails && _addUdp()" >
<i class="iconfont" :class="_isDetails" data-toggle="tooltip" :title="$t('Add')">&#xe636;</i>
</a>
</span>
</div>
</template>
<script>
import _ from 'lodash'
import i18n from '@/module/i18n'
import { positionList } from './commcon'
import disabledState from '@/module/mixin/disabledState'
export default {
name: 'http-params',
data () {
return {
// Increased data
httpParamsList: [],
// Current execution index
httpParamsIndex: null,
//
positionList:positionList
}
},
mixins: [disabledState],
props: {
udpList: Array,
// hide direct/type
hide: {
type: Boolean,
default: true
}
},
methods: {
/**
* Current index
*/
_getIndex (index) {
this.httpParamsIndex = index
},
/**
* 获取参数位置
*/
_handlePositionChanged () {
this._verifProp('value')
},
/**
* delete item
*/
_removeUdp (index) {
this.httpParamsList.splice(index, 1)
this._verifProp('value')
},
/**
* add
*/
_addUdp () {
this.httpParamsList.push({
prop: '',
httpParametersType: 'PARAMETER',
value: ''
})
},
/**
* blur verification
*/
_handleValue () {
this._verifValue('value')
},
/**
* Verify that the value exists or is empty
*/
_verifProp (type) {
let arr = []
let flag = true
_.map(this.httpParamsList, v => {
arr.push(v.prop)
if (!v.prop) {
flag = false
}
if(v.value === ''){
this.$message.warning(`${i18n.$t('value is empty')}`)
return false
}
})
if (!flag) {
if (!type) {
this.$message.warning(`${i18n.$t('prop is empty')}`)
}
return false
}
let newArr = _.cloneDeep(_.uniqWith(arr, _.isEqual))
if (newArr.length !== arr.length) {
if (!type) {
this.$message.warning(`${i18n.$t('prop is repeat')}`)
}
return false
}
this.$emit('on-http-params', _.cloneDeep(this.httpParamsList))
return true
},
_verifValue (type) {
let arr = []
let flag = true
_.map(this.httpParamsList, v => {
arr.push(v.value)
if (!v.value) {
flag = false
}
})
if (!flag) {
this.$message.warning(`${i18n.$t('value is empty')}`)
return false
}
this.$emit('on-http-params', _.cloneDeep(this.httpParamsList))
return true
}
},
watch: {
// Monitor data changes
udpList () {
this.httpParamsList = this.udpList
}
},
created () {
this.httpParamsList = this.udpList
},
computed: {
inputStyle () {
return "width:30%"
}
},
mounted () {
},
components: { }
}
</script>
<style lang="scss" rel="stylesheet/scss">
.user-def-params-model {
.select-listpp {
margin-bottom: 6px;
.lt-add {
padding-left: 4px;
a {
.iconfont {
font-size: 18px;
vertical-align: middle;
margin-bottom: -2px;
display: inline-block;
}
}
}
}
.add {
a {
color: #000;
.iconfont {
font-size: 18px;
vertical-align: middle;
display: inline-block;
margin-top: 1px;
}
}
}
.add-dp{
a {
color: #0097e0;
.iconfont {
font-size: 18px;
vertical-align: middle;
display: inline-block;
margin-top: 2px;
}
}
}
}
</style>

191
escheduler-ui/src/js/conf/home/pages/dag/_source/formModel/tasks/http.vue

@ -0,0 +1,191 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
<template>
<div class="http-model">
<m-list-box>
<div slot="text">{{$t('Http Url')}}</div>
<div slot="content">
<x-input
:autosize="{minRows:2}"
:disabled="isDetails"
type="textarea"
v-model="url"
:placeholder="$t('Please Enter Http Url')"
autocomplete="off">
</x-input>
</div>
</m-list-box>
<m-list-box>
<div slot="text">{{$t('Http Method')}}</div>
<div slot="content">
<x-select
style="width: 150px;"
v-model="httpMethod"
:disabled="isDetails">
<x-option
v-for="city in httpMethodList"
:key="city.code"
:value="city.code"
:label="city.code">
</x-option>
</x-select>
</div>
</m-list-box>
<m-list-box>
<div slot="text">{{$t('Http Parameters')}}</div>
<div slot="content">
<m-http-params
ref="refHttpParams"
@on-http-params="_onHttpParams"
:udp-list="httpParams"
:hide="false">
</m-http-params>
</div>
</m-list-box>
<m-list-box>
<div slot="text">{{$t('Http Check Condition')}}</div>
<div slot="content">
<x-select
style="width: 150px;"
v-model="httpCheckCondition"
:disabled="isDetails">
<x-option
v-for="city in httpCheckConditionList"
:key="city.code"
:value="city.code"
:label="city.value">
</x-option>
</x-select>
</div>
</m-list-box>
<m-list-box>
<div slot="text">{{$t('Http Condition')}}</div>
<div slot="content">
<x-input
:autosize="{minRows:2}"
:disabled="isDetails"
type="textarea"
v-model="condition"
:placeholder="$t('Please Enter Http Condition')"
autocomplete="off">
</x-input>
</div>
</m-list-box>
<m-list-box>
<div slot="text">{{$t('Custom Parameters')}}</div>
<div slot="content">
<m-local-params
ref="refLocalParams"
@on-local-params="_onLocalParams"
:udp-list="localParams"
:hide="false">
</m-local-params>
</div>
</m-list-box>
</div>
</template>
<script>
import _ from 'lodash'
import i18n from '@/module/i18n'
import mLocalParams from './_source/localParams'
import mHttpParams from './_source/httpParams'
import mListBox from './_source/listBox'
import disabledState from '@/module/mixin/disabledState'
export default {
name: 'http',
data () {
return {
url: '',
condition: '',
localParams: [],
httpParams: [],
httpMethod: 'GET',
httpMethodList: [{ code: 'GET' }, { code: 'POST' }, { code: 'HEAD' }, { code: 'PUT' }, { code: 'DELETE' }],
httpCheckCondition: 'STATUS_CODE_DEFAULT',
httpCheckConditionList: [{ code: 'STATUS_CODE_DEFAULT',value:'默认响应码200' }, { code: 'STATUS_CODE_CUSTOM',value:'自定义响应码' }, { code: 'BODY_CONTAINS',value:'内容包含' }, { code: 'BODY_NOT_CONTAINS',value:'内容不包含' }]
}
},
props: {
backfillItem: Object
},
mixins: [disabledState],
methods: {
/**
* return localParams
*/
_onLocalParams (a) {
this.localParams = a
},
_onHttpParams (a) {
this.httpParams = a
},
/**
* verification
*/
_verification () {
if (!this.url) {
this.$message.warning(`${i18n.$t('Please Enter Http Url')}`)
return false
}
// localParams Subcomponent verification
if (!this.$refs.refLocalParams._verifProp()) {
return false
}
if (!this.$refs.refHttpParams._verifProp()) {
return false
}
if (!this.$refs.refHttpParams._verifValue()) {
return false
}
// storage
this.$emit('on-params', {
localParams: this.localParams,
httpParams: this.httpParams,
url: this.url,
httpMethod: this.httpMethod,
httpCheckCondition: this.httpCheckCondition,
condition: this.condition
})
return true
}
},
watch: {
},
created () {
let o = this.backfillItem
// Non-null objects represent backfill
if (!_.isEmpty(o)) {
this.url = o.params.url || ''
this.httpMethod = o.params.httpMethod || 'GET'
this.httpCheckCondition = o.params.httpCheckCondition || 'DEFAULT'
this.condition = o.params.condition || ''
// backfill localParams
let localParams = o.params.localParams || []
if (localParams.length) {
this.localParams = localParams
}
let httpParams = o.params.httpParams || []
if (httpParams.length) {
this.httpParams = httpParams
}
}
},
mounted () {
},
components: { mLocalParams, mHttpParams, mListBox }
}
</script>

BIN
escheduler-ui/src/js/conf/home/pages/dag/img/toobar_HTTP.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 B

14
escheduler-ui/src/js/module/i18n/locale/en_US.js

@ -196,7 +196,9 @@ export default {
'Non Query': 'Non Query', 'Non Query': 'Non Query',
'prop(required)': 'prop(required)', 'prop(required)': 'prop(required)',
'value(optional)': 'value(optional)', 'value(optional)': 'value(optional)',
'value(required)': 'value(required)',
'prop is empty': 'prop is empty', 'prop is empty': 'prop is empty',
'value is empty': 'value is empty',
'prop is repeat': 'prop is repeat', 'prop is repeat': 'prop is repeat',
'Start Time': 'Start Time', 'Start Time': 'Start Time',
'End Time': 'End Time', 'End Time': 'End Time',
@ -475,5 +477,15 @@ export default {
'warning of timeout': 'warning of timeout', 'warning of timeout': 'warning of timeout',
'Next five execution times': 'Next five execution times', 'Next five execution times': 'Next five execution times',
'Execute time': 'Execute time', 'Execute time': 'Execute time',
'Complement range': 'Complement range' 'Complement range': 'Complement range',
'Http Url':'Http Url',
'Http Method':'Http Method',
'Http Parameters':'Http Parameters',
'Http Parameters Key':'Http Parameters Key',
'Http Parameters Position':'Http Parameters Position',
'Http Parameters Value':'Http Parameters Value',
'Http Check Condition':'Http Check Condition',
'Http Condition':'Http Condition',
'Please Enter Http Url': 'Please Enter Http Url(required)',
'Please Enter Http Condition': 'Please Enter Http Condition'
} }

15
escheduler-ui/src/js/module/i18n/locale/zh_CN.js

@ -196,7 +196,9 @@ export default {
'Non Query': '非查询', 'Non Query': '非查询',
'prop(required)': 'prop(必填)', 'prop(required)': 'prop(必填)',
'value(optional)': 'value(选填)', 'value(optional)': 'value(选填)',
'value(required)': 'value(必填)',
'prop is empty': 'prop不能为空', 'prop is empty': 'prop不能为空',
'value is empty': 'value不能为空',
'prop is repeat': 'prop中有重复', 'prop is repeat': 'prop中有重复',
'Start Time': '开始时间', 'Start Time': '开始时间',
'End Time': '结束时间', 'End Time': '结束时间',
@ -480,5 +482,16 @@ export default {
'slot':'slot数量', 'slot':'slot数量',
'taskManager':'taskManage数量', 'taskManager':'taskManage数量',
'jobManagerMemory':'jobManager内存数', 'jobManagerMemory':'jobManager内存数',
'taskManagerMemory':'taskManager内存数' 'taskManagerMemory':'taskManager内存数',
'Complement range': '补数范围',
'Http Url':'请求地址',
'Http Method':'请求类型',
'Http Parameters':'请求参数',
'Http Parameters Key':'参数名',
'Http Parameters Position':'参数位置',
'Http Parameters Value':'参数值',
'Http Check Condition':'校验条件',
'Http Condition':'校验内容',
'Please Enter Http Url': '请填写请求地址(必填)',
'Please Enter Http Condition': '请填写校验内容'
} }

Loading…
Cancel
Save