This commit is contained in:
liqiang-fit2cloud 2023-01-30 13:53:47 +08:00
commit 1a378b3eab
14 changed files with 126 additions and 144 deletions

35
Jenkinsfile vendored
View File

@ -17,7 +17,6 @@ pipeline {
script {
REVISION = ""
BUILD_SDK = false
BUILD_PARENT = false
if (env.BRANCH_NAME.startsWith("v") ) {
REVISION = env.BRANCH_NAME.substring(1)
} else {
@ -26,30 +25,12 @@ pipeline {
if (params.buildSdk) {
BUILD_SDK = true
}
if (params.buildParent) {
BUILD_PARENT = true
}
if (params.frontendLink != null && !params.frontendLink.equals("")) {
env.FRONTEND_LINK = params.frontendLink
}
env.REVISION = "${REVISION}"
env.BUILD_SDK = "${BUILD_SDK}"
env.BUILD_PARENT = "${BUILD_PARENT}"
echo "REVISION=${REVISION}, BUILD_SDK=${BUILD_SDK}, BUILD_PARENT=${BUILD_PARENT}"
}
}
}
stage('POM') {
when { environment name: 'BUILD_PARENT', value: 'true' }
steps {
configFileProvider([configFile(fileId: 'metersphere-maven', targetLocation: 'settings.xml')]) {
sh '''#!/bin/bash -xe
export JAVA_HOME=/opt/jdk-17
export CLASSPATH=$JAVA_HOME/lib:$CLASSPATH
export PATH=$JAVA_HOME/bin:$PATH
java -version
./mvnw install -N -Drevision=${REVISION} --settings ./settings.xml
'''
echo "REVISION=${REVISION}, BUILD_SDK=${BUILD_SDK}"
}
}
}
@ -74,12 +55,7 @@ pipeline {
}
}
stage('Build/Test') {
when {
allOf {
environment name: 'BUILD_SDK', value: 'false';
environment name: 'BUILD_PARENT', value: 'false'
}
}
when { environment name: 'BUILD_SDK', value: 'false' }
steps {
configFileProvider([configFile(fileId: 'metersphere-maven', targetLocation: 'settings.xml')]) {
sh '''#!/bin/bash -xe
@ -107,12 +83,7 @@ pipeline {
}
}
stage('Docker build & push') {
when {
allOf {
environment name: 'BUILD_SDK', value: 'false';
environment name: 'BUILD_PARENT', value: 'false'
}
}
when { environment name: 'BUILD_SDK', value: 'false' }
steps {
script {
for (int i=0; i<10; i++) {

View File

@ -11,13 +11,11 @@ import io.metersphere.dto.JmeterRunRequestDTO;
import io.metersphere.service.RemakeReportService;
import io.metersphere.utils.LoggerUtil;
import io.metersphere.xpack.resourcepool.engine.provider.ClientCredential;
import okhttp3.Response;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Random;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class KubernetesApiExec {
@ -31,63 +29,49 @@ public class KubernetesApiExec {
if (CollectionUtils.isEmpty(nodePods)) {
MSException.throwException("Execution node not found");
}
Pod pod = nodePods.get(new Random().nextInt(nodePods.size()));
return pod;
return nodePods.get(new Random().nextInt(nodePods.size()));
}
public static ExecWatch newExecWatch(KubernetesClient client, String namespace, String podName, String command) {
public static ExecWatch newExecWatch(KubernetesClient client, String namespace, String podName, String command, JmeterRunRequestDTO runRequest) {
LoggerUtil.info("CURL 命令:【 " + command + "");
return client.pods().inNamespace(namespace).withName(podName)
.readingInput(System.in)
.writingOutput(System.out)
.writingError(System.err)
.withTTY()
.usingListener(new SimpleListener())
.usingListener(new SimpleListener(runRequest))
.exec("sh", "-c", command);
}
private static String getQuery(String content) {
Pattern regex = Pattern.compile("\\{([^}]*)\\}");
Matcher matcher = regex.matcher(content);
StringBuilder sql = new StringBuilder();
while (matcher.find()) {
sql.append(matcher.group(1) + ",");
}
if (sql.length() > 0) {
sql.deleteCharAt(sql.length() - 1);
}
return sql.toString();
}
private static class SimpleListener implements ExecListener {
private JmeterRunRequestDTO runRequest;
SimpleListener(JmeterRunRequestDTO runRequest) {
this.runRequest = runRequest;
}
@Override
public void onOpen() {
LoggerUtil.info("The shell will remain open for 10 seconds.");
LoggerUtil.info("K8s命令执行监听 onOpen ", runRequest.getReportId());
}
@Override
public void onFailure(Throwable t, Response response) {
// todo k8s 执行api变了
// List<String> value = response.request().url().queryParameterValues("command");
// if (CollectionUtils.isNotEmpty(value) && value.size() > 2 && value.get(2).startsWith("curl")) {
// String query = "{" + KubernetesApiExec.getQuery(value.get(2)) + "}";
// JmeterRunRequestDTO runRequest = JSON.parseObject(query, JmeterRunRequestDTO.class);
// if (runRequest != null) {
// RemakeReportService apiScenarioReportService = CommonBeanFactory.getBean(RemakeReportService.class);
// apiScenarioReportService.testEnded(runRequest, response.networkResponse().message());
// } else {
// MSException.throwException("K8S 节点执行错误:" + response.networkResponse().message());
// }
// } else {
// MSException.throwException("K8S 节点执行错误:" + response.networkResponse().message());
// }
// LoggerUtil.error("K8S 节点执行错误:" + JSON.toJSONString(value));
// LoggerUtil.error("K8S 节点执行错误:" + response.networkResponse());
LoggerUtil.info("进入K8s onFailure处理");
if (runRequest != null) {
LoggerUtil.info("请求参数:", JSON.toJSONString(runRequest));
RemakeReportService apiScenarioReportService = CommonBeanFactory.getBean(RemakeReportService.class);
apiScenarioReportService.testEnded(runRequest, StringUtils.join("K8s执行异常", t.getMessage()));
} else {
MSException.throwException("K8S 节点执行错误:" + t.getMessage());
}
LoggerUtil.error("K8S 节点执行错误:", t.getMessage());
}
@Override
public void onClose(int code, String reason) {
LoggerUtil.info("The shell will now close.");
LoggerUtil.info(code + "_" + reason, runRequest.getReportId());
LoggerUtil.info("K8s命令执行监听 onClose ", runRequest.getReportId());
}
}
}

View File

@ -6,11 +6,12 @@ import io.metersphere.api.dto.MsgDTO;
import io.metersphere.base.domain.TestResource;
import io.metersphere.commons.constants.ApiRunMode;
import io.metersphere.commons.constants.ExtendedParameter;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.commons.utils.JSON;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.commons.utils.WebSocketUtil;
import io.metersphere.dto.JmeterRunRequestDTO;
import io.metersphere.service.RemakeReportService;
import io.metersphere.utils.LoggerUtil;
import io.metersphere.xpack.resourcepool.engine.provider.ClientCredential;
import io.metersphere.xpack.resourcepool.engine.provider.KubernetesProvider;
@ -78,7 +79,7 @@ public class KubernetesTestEngine extends AbstractEngine {
command.append(StringUtils.SPACE).append("--max-time 120"); // 设置请求超时时间为120S
command.append(StringUtils.SPACE).append("--retry 3"); // 设置重试次数3次
command.append(StringUtils.SPACE).append("http://127.0.0.1:8082/jmeter/").append(path);
KubernetesApiExec.newExecWatch(client, clientCredential.getNamespace(), pod.getMetadata().getName(), command.toString());
KubernetesApiExec.newExecWatch(client, clientCredential.getNamespace(), pod.getMetadata().getName(), command.toString(), runRequest);
} catch (Exception e) {
MsgDTO dto = new MsgDTO();
dto.setExecEnd(false);
@ -88,13 +89,15 @@ public class KubernetesTestEngine extends AbstractEngine {
LoggerUtil.debug("send. " + runRequest.getReportId());
WebSocketUtil.sendMessageSingle(dto);
WebSocketUtil.onClose(runRequest.getReportId());
RemakeReportService remake = CommonBeanFactory.getBean(RemakeReportService.class);
remake.testEnded(runRequest, StringUtils.join("K8s执行异常", e.getMessage()));
LoggerUtil.error("当前报告:【" + runRequest.getReportId() + "】资源:【" + runRequest.getTestId() + "】CURL失败", e);
MSException.throwException(e);
}
}
@Override
public void stop() {
LoggerUtil.info("K8S执行STOP", runRequest.getReportId());
}
}

View File

@ -156,32 +156,17 @@ public class TestDataGenerator {
value = StringUtils.isNotBlank(v) ? v : value;
try {
if (object.has(FORMAT)) {
String propertyFormat = object.get(FORMAT).getAsString();
switch (propertyFormat) {
case "date-time":
value = DateTimeSource.getInstance().randomTimestamp(LocalDate.now()) + "";
break;
case "date":
value = DateTimeSource.getInstance().randomDate(LocalDate.now().getYear(), "yyyy-MM-dd");
break;
case "email":
value = InternetSource.getInstance().randomEmail(maxLength);
break;
case "hostname":
value = InternetSource.getInstance().randomDomain(maxLength);
break;
case "ipv4":
value = InternetSource.getInstance().randomPublicIpv4();
break;
case "ipv6":
value = InternetSource.getInstance().randomIpV6();
break;
case "uri":
value = InternetSource.getInstance().randomStaticUrl("jpg");
break;
}
}
if (object.has(PATTERN)) {
value = switch (object.get(FORMAT).getAsString()) {
case "date-time" -> DateTimeSource.getInstance().randomTimestamp(LocalDate.now()) + "";
case "date" -> DateTimeSource.getInstance().randomDate(LocalDate.now().getYear(), "yyyy-MM-dd");
case "email" -> InternetSource.getInstance().randomEmail(maxLength);
case "hostname" -> InternetSource.getInstance().randomDomain(maxLength);
case "ipv4" -> InternetSource.getInstance().randomPublicIpv4();
case "ipv6" -> InternetSource.getInstance().randomIpV6();
case "uri" -> InternetSource.getInstance().randomStaticUrl("jpg");
default -> value;
};
} else if (object.has(PATTERN)) {
String pattern = object.get(PATTERN).getAsString();
if (StringUtils.isNotEmpty(pattern)) {
Generex generex = new Generex(pattern);

View File

@ -13,6 +13,28 @@
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-server</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-conscrypt-server</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-server</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>

View File

@ -195,7 +195,7 @@
<groupId>org.tukaani</groupId>
</exclusion>
<exclusion>
<artifactId>springdoc-openapi-ui</artifactId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<groupId>org.springdoc</groupId>
</exclusion>
</exclusions>
@ -218,7 +218,7 @@
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-webflux-ui</artifactId>
<artifactId>springdoc-openapi-starter-webflux-ui</artifactId>
<version>${springdoc-openapi-ui.version}</version>
</dependency>

View File

@ -7,21 +7,23 @@ import parser from "cron-parser";
* @return True is expression is valid
*/
export function cronValidate(cronExpression ){
try {
parser.parseExpression(cronExpression);
} catch (e) {
return false;
}
if (!cronExpression) {
return false;
}
//alert("校验函数的开始!");
var cronParams = cronExpression.split(" ");
let cronParams = cronExpression.split(" ");
if (cronParams.length < 6 || cronParams.length > 7) {
return false;
}
let cronValue = cronExpression;
if(cronExpression.split(" ").length === 7){
cronValue = cronExpression.substring(0, cronExpression.lastIndexOf(" "));
}
try {
parser.parseExpression(cronValue);
} catch (e) {
return false;
}
//CronTrigger cronTrigger = new CronTrigger();
//cronTrigger.setCronExpression( cronExpression );
@ -81,15 +83,15 @@ function checkSecondsField(secondsField) {
function checkField(secondsField, minimal, maximal) {
if (secondsField.indexOf("-") > -1 ) {
var startValue = secondsField.substring(0, secondsField.indexOf( "-" ));
var endValue = secondsField.substring(secondsField.indexOf( "-" ) + 1);
let startValue = secondsField.substring(0, secondsField.indexOf( "-" ));
let endValue = secondsField.substring(secondsField.indexOf( "-" ) + 1);
if (!(checkIntValue(startValue, minimal, maximal, true) && checkIntValue(endValue, minimal, maximal, true))) {
return false;
}
try {
var startVal = parseInt(startValue, 10);
var endVal = parseInt(endValue, 10);
let startVal = parseInt(startValue, 10);
let endVal = parseInt(endValue, 10);
//return endVal > startVal;
return true;
} catch (e) {
@ -102,13 +104,13 @@ function checkField(secondsField, minimal, maximal) {
} else if (secondsField.indexOf( "*" ) != -1) {
return true;
} else {
return checkIntValue(secondsField, minimal, maximal);
return checkIntValue(secondsField, minimal, maximal,true);
}
}
function checkIntValue(value, minimal, maximal, checkExtremity) {
try {
var val = parseInt(value, 10);
let val = parseInt(value, 10);
//判断是否为整数
if (value == val) {
if (checkExtremity) {
@ -220,11 +222,11 @@ function checkYearField(yearField) {
function checkFieldWithLetter(value, letter, minimalBefore, maximalBefore,
minimalAfter, maximalAfter) {
var canBeAlone = false;
var canHaveIntBefore = false;
var canHaveIntAfter = false;
var mustHaveIntBefore = false;
var mustHaveIntAfter = false;
let canBeAlone = false;
let canHaveIntBefore = false;
let canHaveIntAfter = false;
let mustHaveIntBefore = false;
let mustHaveIntAfter = false;
if (letter == "L") {
canBeAlone = true;
@ -248,8 +250,8 @@ function checkFieldWithLetter(value, letter, minimalBefore, maximalBefore,
mustHaveIntAfter = true;
}
var beforeLetter = "";
var afterLetter = "";
let beforeLetter = "";
let afterLetter = "";
if (value.indexOf(letter) >= 0 ) {
beforeLetter = value.substring( 0, value.indexOf(letter));
@ -301,9 +303,9 @@ function checkFieldWithLetter(value, letter, minimalBefore, maximalBefore,
} */
function checkIncrementField(value, minimal, maximal) {
var start = value.substring(0, value.indexOf("/"));
let start = value.substring(0, value.indexOf("/"));
var increment = value.substring(value.indexOf("/") + 1);
let increment = value.substring(value.indexOf("/") + 1);
if (!("*" == start)) {
return checkIntValue(start, minimal, maximal, true) && checkIntValue(increment, minimal, maximal, false);
@ -315,16 +317,16 @@ function checkIncrementField(value, minimal, maximal) {
function checkListField(value, minimal, maximal ) {
var st = value.split(",");
let st = value.split(",");
var values = new Array(st.length);
let values = new Array(st.length);
for(var j = 0; j < st.length; j++) {
for(let j = 0; j < st.length; j++) {
values[j] = st[j];
}
for (var i= 0; i < values.length; i++) {
var currentValue = values[i];
for (let i= 0; i < values.length; i++) {
let currentValue = values[i];
if (!checkIntValue(currentValue, minimal, maximal, true)) {
return false;

View File

@ -90,7 +90,7 @@
<!-- openapi -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>${springdoc-openapi-ui.version}</version>
</dependency>
<dependency>

View File

@ -93,14 +93,14 @@
</when>
<when test="key == 'jira_key'">
AND p.platform = 'Jira'
AND p.jira_key IN
AND p.issue_config -> '$.jiraKey' IN
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>
</when>
<when test="key == 'zentao_id'">
AND p.platform = 'Zentao'
AND p.zentao_id IN
AND p.issue_config -> '$.zentaoId' IN
<foreach collection="values" item="value" separator="," open="(" close=")">
#{value}
</foreach>

View File

@ -2,6 +2,7 @@ package io.metersphere.service;
import io.metersphere.base.domain.Group;
import io.metersphere.base.domain.Project;
import io.metersphere.base.domain.ProjectExample;
import io.metersphere.base.domain.UserGroup;
import io.metersphere.base.mapper.ProjectMapper;
import io.metersphere.base.mapper.ext.BaseProjectMapper;
@ -34,6 +35,12 @@ public class BaseCheckPermissionService {
public Set<String> getUserRelatedProjectIds() {
if (SessionUtils.getUserId() != null && baseUserService.isSuperUser(SessionUtils.getUserId())) {
List<Project> projects = projectMapper.selectByExample(new ProjectExample());
if (CollectionUtils.isNotEmpty(projects)) {
return projects.stream().map(Project::getId).collect(Collectors.toSet());
}
}
UserDTO userDTO = baseUserService.getUserDTO(SessionUtils.getUserId());
List<String> groupIds = userDTO.getGroups()
.stream()
@ -78,6 +85,9 @@ public class BaseCheckPermissionService {
}
public void checkProjectOwner(String projectId) {
if (SessionUtils.getUserId() != null && baseUserService.isSuperUser(SessionUtils.getUserId())) {
return;
}
Set<String> projectIds = getUserRelatedProjectIds();
if (CollectionUtils.isEmpty(projectIds)) {
return;

12
pom.xml
View File

@ -6,7 +6,7 @@
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.1</version>
<version>3.0.2</version>
<relativePath/>
</parent>
@ -18,9 +18,9 @@
<description>MeterSphere</description>
<properties>
<revision>spring-boot-3.0</revision>
<revision>main</revision>
<java.version>17</java.version>
<spring-cloud.version>2022.0.0</spring-cloud.version>
<spring-cloud.version>2022.0.1</spring-cloud.version>
<dubbo.version>2.7.18</dubbo.version>
<platform-plugin-sdk.version>1.3.0</platform-plugin-sdk.version>
<shiro.version>1.11.0</shiro.version>
@ -33,9 +33,9 @@
<pagehelper.version>5.3.2</pagehelper.version>
<metersphere-jmeter-functions.version>1.5</metersphere-jmeter-functions.version>
<quartz-starter.version>1.0.7</quartz-starter.version>
<redisson-starter.version>3.19.0</redisson-starter.version>
<redisson-starter.version>3.19.1</redisson-starter.version>
<guice.version>5.1.0</guice.version>
<mybatis-starter.version>3.0.0</mybatis-starter.version>
<mybatis-starter.version>3.0.1</mybatis-starter.version>
<reflections.version>0.10.2</reflections.version>
<bcprov-jdk15on.version>1.70</bcprov-jdk15on.version>
<commons-io.version>2.11.0</commons-io.version>
@ -56,7 +56,7 @@
<json-lib.version>2.4</json-lib.version>
<json-schema-validator.version>2.2.14</json-schema-validator.version>
<xz.version>1.9</xz.version>
<springdoc-openapi-ui.version>1.6.13</springdoc-openapi-ui.version>
<springdoc-openapi-ui.version>2.0.2</springdoc-openapi-ui.version>
<flatten.version>1.2.7</flatten.version>
<jmeter.version>5.5</jmeter.version>
<codehaus-groovy.version>3.0.11</codehaus-groovy.version>

View File

@ -64,4 +64,9 @@ public class TestResourcePoolController {
return PageUtils.setPageInfo(page, testResourcePoolService.listResourcePools(request));
}
@GetMapping("/list/quota/ws/valid/{workspaceId}")
public List<TestResourcePoolDTO> listWsValidQuotaResourcePools(@PathVariable String workspaceId) {
return testResourcePoolService.listWsValidQuotaResourcePools(workspaceId);
}
}

View File

@ -47,13 +47,13 @@ export function getAllServiceIntegration() {
}
export function getFieldTemplateCaseOption(projectId) {
return get(`/project/field/template/case/option/${projectId}`);
return get(projectId ? `/project/field/template/case/option/${projectId}` : `/project/field/template/case/option`);
}
export function getFieldTemplateIssueOption(projectId) {
return get(`/project/field/template/issue/option/${projectId}`);
return get(projectId ? `/project/field/template/issue/option/${projectId}` : `/project/field/template/issue/option`);
}
export function getFieldTemplateApiOption(projectId) {
return get(`/project/field/template/api/option/${projectId}`);
return get(projectId ? `/project/field/template/api/option/${projectId}` : `/project/field/template/api/option`);
}

View File

@ -100,7 +100,7 @@ export default {
userResourceUrl: {
type: String,
default() {
return '/user/list/';
return '/user/list';
}
}
},