refactor: 资源池执行接口测试修改

This commit is contained in:
CaptainB 2022-05-09 11:42:23 +08:00 committed by 刘瑞斌
parent 353da01c67
commit 55a11cae5e
3 changed files with 275 additions and 30 deletions

View File

@ -6,6 +6,7 @@ import io.metersphere.base.domain.UserHeader;
import io.metersphere.commons.constants.OperLogConstants;
import io.metersphere.commons.constants.OperLogModule;
import io.metersphere.commons.constants.ParamConstants;
import io.metersphere.config.KafkaProperties;
import io.metersphere.controller.request.HeaderRequest;
import io.metersphere.dto.BaseSystemConfigDTO;
import io.metersphere.dto.SystemStatisticData;
@ -16,7 +17,6 @@ import io.metersphere.service.ProjectService;
import io.metersphere.service.SystemParameterService;
import io.metersphere.service.UserService;
import io.metersphere.service.WorkspaceService;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.*;
@ -37,6 +37,8 @@ public class SystemParameterController {
private WorkspaceService workspaceService;
@Resource
private ProjectService projectService;
@Resource
private KafkaProperties kafkaProperties;
@PostMapping("/edit/email")
@MsAuditLog(module = OperLogModule.SYSTEM_PARAMETER_SETTING, type = OperLogConstants.UPDATE, title = "邮件设置", beforeEvent = "#msClass.getMailLogDetails()", content = "#msClass.getMailLogDetails()", msClass = SystemParameterService.class)
@ -54,6 +56,11 @@ public class SystemParameterController {
return systemParameterService.getVersion();
}
@GetMapping("/kafka-servers")
public String getKafkaBootstrapServers() {
return kafkaProperties.getBootstrapServers();
}
@GetMapping("/theme")
public String getTheme() {
return systemParameterService.getValue("ui.theme");

View File

@ -87,7 +87,19 @@
<el-input v-model="form.gcAlgo"
placeholder="-XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:G1ReservePercent=20"/>
</el-form-item>
<el-form-item :label="$t('test_resource_pool.type')" prop="type">
<el-form-item prop="type">
<template v-slot:label>
{{ $t('test_resource_pool.type') }}
<el-popover
v-if="form.type === 'K8S'"
placement="bottom"
width="450"
title="使用K8S资源池需要的权限"
trigger="hover">
<el-link type="primary" @click="downloadYaml({deployType:'sa', deployName:'sa'})">sa.yaml</el-link>
<i class="el-icon-info" slot="reference"></i>
</el-popover>
</template>
<el-select v-model="form.type" :placeholder="$t('test_resource_pool.select_pool_type')"
@change="changeResourceType(form.type)">
<el-option key="NODE" value="NODE" label="Node">Node</el-option>
@ -113,12 +125,38 @@
</el-col>
</el-row>
<el-row>
<el-col>
<el-form-item label="Namespace"
:rules="requiredRules">
<el-col :span="12">
<el-form-item label="Namespace" :rules="requiredRules">
<el-input v-model="item.namespace" type="text"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item>
<template v-slot:label>
Deploy Type
<el-popover
placement="bottom"
width="450"
title="执行接口测试需要部署 DaemonSet 或 Deployment"
trigger="hover">
<el-link type="primary" @click="downloadYaml(item)">daemonset.yaml</el-link> &nbsp;
<el-link type="primary" @click="downloadYaml(item)">deployment.yaml</el-link>
<i class="el-icon-info" slot="reference"></i>
</el-popover>
</template>
<el-select v-model="item.deployType" style="width: 100%">
<el-option key="DaemonSet" value="DaemonSet" label="DaemonSet"/>
<el-option key="Deployment" value="Deployment" label="Deployment"/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col>
<el-form-item label="Deploy Name" :rules="requiredRules">
<el-input v-model="item.deployName"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col>
@ -146,13 +184,6 @@
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col>
<el-form-item label="nodeSelector">
<el-input v-model="item.nodeSelector" placeholder='{"disktype": "ssd",...}'/>
</el-form-item>
</el-col>
</el-row>
</div>
</div>
@ -249,6 +280,7 @@ import MsTableOperator from "../../common/components/MsTableOperator";
import MsDialogFooter from "../../common/components/MsDialogFooter";
import {listenGoBack, removeGoBackListener} from "@/common/js/utils";
import BatchAddResource from "@/business/components/settings/system/components/BatchAddResource";
import {getYaml} from "@/business/components/settings/system/test-resource-pool";
export default {
name: "MsTestResourcePool",
@ -288,11 +320,16 @@ export default {
updatePool: {
testName: '',
haveTestUsePool: false
}
},
apiImage: '',
kafkaBootstrapServers: '',
apiImageTag: '',
};
},
activated() {
this.initTableData();
this.getApiImageTag();
this.getKafkaBootstrapServers();
},
methods: {
initTableData() {
@ -316,6 +353,8 @@ export default {
info.token = '';
info.namespace = '';
info.podThreadLimit = 5000;
info.deployType = 'DaemonSet';
info.deployName = 'ms-node-controller';
}
info.maxConcurrency = 100;
this.infoList.push(info);
@ -365,12 +404,11 @@ export default {
if (this.infoList.length <= 0) {
return {validate: false, msg: this.$t('test_resource_pool.cannot_empty')};
}
let resourcePoolType = this.form.type;
let resultValidate = {validate: true, msg: this.$t('test_resource_pool.fill_the_data')};
this.infoList.forEach(info => {
for (let key in info) {
//
if (key === 'nodeSelector' || key === 'apiImage') {
if (key === 'deployName' || key === 'apiImage') {
continue;
}
if (info[key] != '0' && !info[key]) {
@ -383,13 +421,6 @@ export default {
resultValidate.validate = false;
return false;
}
if (resourcePoolType === 'K8S' && info.nodeSelector) {
let validate = this.isJsonString(info.nodeSelector);
if (!validate) {
resultValidate.validate = false;
resultValidate.msg = this.$t('test_resource_pool.node_selector_invalid');
}
}
});
return resultValidate;
@ -417,6 +448,8 @@ export default {
let configuration = JSON.parse(resource.configuration);
configuration.id = resource.id;
configuration.monitorPort = configuration.monitorPort || '9100';
configuration.deployType = configuration.deployType || 'DaemonSet';
configuration.deployName = configuration.deployName || 'ms-node-controller';
resources.push(configuration);
});
}
@ -549,15 +582,42 @@ export default {
this.result.loading = false;
});
},
isJsonString(str) {
try {
if (typeof JSON.parse(str) == "object") {
return true;
}
} catch (e) {
console.log('json invalid');
downloadYaml(item) {
if (!item.namespace) {
this.$error(this.$t('test_resource_pool.fill_the_data'));
return;
}
return false;
if (!item.deployName) {
this.$error(this.$t('test_resource_pool.fill_the_data'));
return;
}
let apiImage = 'registry.cn-qingdao.aliyuncs.com/metersphere/ms-node-controller:' + this.apiImageTag;
if (item.apiImage) {
apiImage = item.apiImage;
}
let yaml = getYaml(item.deployType, item.deployName, item.namespace, apiImage, this.kafkaBootstrapServers);
let blob = new Blob([yaml], {type: 'application/yaml'});
let url = URL.createObjectURL(blob);
let downloadAnchorNode = document.createElement('a')
downloadAnchorNode.setAttribute("href", url);
downloadAnchorNode.setAttribute("download", item.deployType.toLowerCase() + ".yaml")
downloadAnchorNode.click();
downloadAnchorNode.remove();
},
getKafkaBootstrapServers() {
this.$get('/system/kafka-servers', response => {
this.kafkaBootstrapServers = response.data;
})
},
getApiImageTag() {
this.$get('/system/version', response => {
if (!response.data) {
this.apiImageTag = 'dev';
return;
}
let i = response.data.lastIndexOf('-');
this.apiImageTag = response.data.substring(0, i);
});
}
}
};

View File

@ -0,0 +1,178 @@
const daemonSet = `apiVersion: apps/v1
kind: DaemonSet
metadata:
labels:
app: ms-node-controller
name: {name}
namespace: {namespace}
spec:
selector:
matchLabels:
app: ms-node-controller
replicas: 2
template:
metadata:
labels:
app: ms-node-controller
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- ms-node-controller
topologyKey: kubernetes.io/hostname
weight: 100
containers:
- env:
- name: KAFKA_BOOTSTRAP-SERVERS
value: {kafkaBootstrapServers}
image: {image}
imagePullPolicy: IfNotPresent
name: ms-node-controller
ports:
- containerPort: 8082
protocol: TCP
resources: {}
volumeMounts:
- mountPath: /opt/metersphere/logs
name: metersphere-logs
restartPolicy: Always
volumes:
- emptyDir: {}
name: metersphere-logs
`;
const deployment = `apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: ms-node-controller
name: {name}
namespace: {namespace}
spec:
selector:
matchLabels:
app: ms-node-controller
replicas: 2
template:
metadata:
labels:
app: ms-node-controller
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- ms-node-controller
topologyKey: kubernetes.io/hostname
weight: 100
containers:
- env:
- name: KAFKA_BOOTSTRAP-SERVERS
value: {kafkaBootstrapServers}
image: {image}
imagePullPolicy: IfNotPresent
name: ms-node-controller
ports:
- containerPort: 8082
protocol: TCP
resources: {}
volumeMounts:
- mountPath: /opt/metersphere/logs
name: metersphere-logs
restartPolicy: Always
volumes:
- emptyDir: {}
name: metersphere-logs
`;
const sa = `apiVersion: rbac.authorization.k8s.io/v1beta1
kind: Role
metadata:
name: metersphere
namespace: {namespace}
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- get
- watch
- list
- create
- update
- patch
- delete
- exec
- apiGroups:
- ""
resources:
- pods/exec
verbs:
- get
- create
- apiGroups:
- ""
resources:
- namespaces
verbs:
- get
- watch
- list
- apiGroups:
- apps
resources:
- daemonsets
verbs:
- get
- watch
- list
- create
- update
- patch
- delete
- apiGroups:
- batch
resources:
- jobs
verbs:
- get
- watch
- list
- create
- update
- patch
- delete
`
export function getYaml(type, name, namespace, image, kafkaBootstrapServers) {
if (type === 'Deployment') {
return deployment
.replace('{name}', name)
.replace('{namespace}', namespace)
.replace('{image}', image)
.replace('{kafkaBootstrapServers}', kafkaBootstrapServers);
}
if (type === 'DaemonSet') {
return daemonSet
.replace('{name}', name)
.replace('{namespace}', namespace)
.replace('{image}', image)
.replace('{kafkaBootstrapServers}', kafkaBootstrapServers);
}
if (type === 'sa') {
return sa.replace('{namespace}', namespace);
}
}