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

This commit is contained in:
CaptainB 2022-05-09 11:42:23 +08:00 committed by 刘瑞斌
parent 9e170f9254
commit 810652fc98
6 changed files with 253 additions and 30 deletions

View File

@ -16,7 +16,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.*;

View File

@ -87,7 +87,7 @@
<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" :label="$t('test_resource_pool.type')">
<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>
@ -114,12 +114,38 @@
</el-row>
<el-row>
<el-col>
<el-form-item label="Namespace"
:rules="requiredRules">
<el-form-item label="Namespace" :rules="requiredRules">
<template v-slot:label>
Namespace
<el-popover
placement="bottom"
width="450"
trigger="hover">
<div>
<strong>{{ $t('test_resource_pool.k8s_sa_tips') }}</strong><br>
<el-link type="primary" @click="downloadYaml(item, 'sa')">sa.yaml</el-link>
</div>
<div style="padding-top: 20px">
<strong>{{ $t('test_resource_pool.k8s_deploy_type_tips') }}</strong><br>
<el-link type="primary" @click="downloadYaml(item, 'DaemonSet')">daemonset.yaml</el-link>
&nbsp;
<el-link type="primary" @click="downloadYaml(item, 'Deployment')">deployment.yaml</el-link>
</div>
<i class="el-icon-info" slot="reference"></i>
</el-popover>
</template>
<el-input v-model="item.namespace" type="text"/>
</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>
<el-form-item label="API Image">
@ -146,13 +172,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 +268,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 +308,14 @@ export default {
updatePool: {
testName: '',
haveTestUsePool: false
}
},
apiImage: '',
apiImageTag: '',
};
},
activated() {
this.initTableData();
this.getApiImageTag();
},
methods: {
initTableData() {
@ -316,6 +339,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 +390,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 === 'apiImage') {
continue;
}
if (info[key] != '0' && !info[key]) {
@ -383,15 +407,7 @@ 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;
},
buildPagePath(path) {
@ -417,6 +433,9 @@ 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';
delete configuration.nodeSelector;
resources.push(configuration);
});
}
@ -549,15 +568,37 @@ 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, deployType) {
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(deployType, item.deployName, item.namespace, apiImage);
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", deployType.toLowerCase() + ".yaml")
downloadAnchorNode.click();
downloadAnchorNode.remove();
},
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,171 @@
const daemonSet = `apiVersion: apps/v1
kind: DaemonSet
metadata:
labels:
app: ms-node-controller
name: {name}
namespace: {namespace}
spec:
selector:
matchLabels:
app: ms-node-controller
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:
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:
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) {
if (type === 'Deployment') {
return deployment
.replace('{name}', name)
.replace('{namespace}', namespace)
.replace('{image}', image);
}
if (type === 'DaemonSet') {
return daemonSet
.replace('{name}', name)
.replace('{namespace}', namespace)
.replace('{image}', image);
}
if (type === 'sa') {
return sa.replace('{namespace}', namespace);
}
}

View File

@ -2454,6 +2454,10 @@ export default {
usage: 'Usage',
backend_listener: 'Backend Listener',
batch_add_resource_tips: 'Format: IP, Port, Monitor, maximum concurrent number<br/>such as: 192.168.1.52,8082,9100,500',
k8s_sa_tips: 'Permissions required to use the K8S resource pool',
k8s_sa_download_tips: 'Download SA executable file',
k8s_deploy_type_tips: 'A DaemonSet or Deployment needs to be deployed to perform interface testing',
k8s_deploy_download_tips: 'Download the YAML executable file',
},
system_parameter_setting: {
mailbox_service_settings: 'Mailbox Settings',

View File

@ -2458,6 +2458,10 @@ export default {
usage: '用途',
backend_listener: '后置监听器',
batch_add_resource_tips: '格式IP,Port,Monitor,最大并发数<br/>如192.168.1.52,8082,9100,500',
k8s_sa_tips: '使用K8S资源池需要的权限',
k8s_sa_download_tips: '下载SA执行文件',
k8s_deploy_type_tips: '执行接口测试需要部署 DaemonSet 或 Deployment',
k8s_deploy_download_tips: '下载YAML执行文件',
},
system_parameter_setting: {
mailbox_service_settings: '邮件设置',

View File

@ -2457,6 +2457,10 @@ export default {
usage: '用途',
backend_listener: '後置監聽器',
batch_add_resource_tips: '格式IP,Port,Monitor,最大並發數<br/>如192.168.1.52,8082,9100,500',
k8s_sa_tips: '使用K8S資源池需要的權限',
k8s_sa_download_tips: '下載SA執行文件',
k8s_deploy_type_tips: '執行接口測試需要部署 DaemonSet 或 Deployment',
k8s_deploy_download_tips: '下載YAML執行文件',
},
system_parameter_setting: {
mailbox_service_settings: '郵件設置',