From 810652fc988f89f20b0e776274ee67963c6c71e9 Mon Sep 17 00:00:00 2001 From: CaptainB Date: Mon, 9 May 2022 11:42:23 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E8=B5=84=E6=BA=90=E6=B1=A0?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=E6=8E=A5=E5=8F=A3=E6=B5=8B=E8=AF=95=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/SystemParameterController.java | 1 - .../settings/system/TestResourcePool.vue | 99 +++++++--- .../settings/system/test-resource-pool.js | 171 ++++++++++++++++++ frontend/src/i18n/en-US.js | 4 + frontend/src/i18n/zh-CN.js | 4 + frontend/src/i18n/zh-TW.js | 4 + 6 files changed, 253 insertions(+), 30 deletions(-) create mode 100644 frontend/src/business/components/settings/system/test-resource-pool.js diff --git a/backend/src/main/java/io/metersphere/controller/SystemParameterController.java b/backend/src/main/java/io/metersphere/controller/SystemParameterController.java index 5224a05eab..ff2f61071a 100644 --- a/backend/src/main/java/io/metersphere/controller/SystemParameterController.java +++ b/backend/src/main/java/io/metersphere/controller/SystemParameterController.java @@ -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.*; diff --git a/frontend/src/business/components/settings/system/TestResourcePool.vue b/frontend/src/business/components/settings/system/TestResourcePool.vue index 9f5548441a..41ba74b135 100644 --- a/frontend/src/business/components/settings/system/TestResourcePool.vue +++ b/frontend/src/business/components/settings/system/TestResourcePool.vue @@ -87,7 +87,7 @@ - + Node @@ -114,12 +114,38 @@ - + + + + + + + + + @@ -146,13 +172,6 @@ - - - - - - - @@ -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); + }); } } }; diff --git a/frontend/src/business/components/settings/system/test-resource-pool.js b/frontend/src/business/components/settings/system/test-resource-pool.js new file mode 100644 index 0000000000..e1f23b79a8 --- /dev/null +++ b/frontend/src/business/components/settings/system/test-resource-pool.js @@ -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); + } +} + diff --git a/frontend/src/i18n/en-US.js b/frontend/src/i18n/en-US.js index 0191af49b3..9a61931166 100644 --- a/frontend/src/i18n/en-US.js +++ b/frontend/src/i18n/en-US.js @@ -2454,6 +2454,10 @@ export default { usage: 'Usage', backend_listener: 'Backend Listener', batch_add_resource_tips: 'Format: IP, Port, Monitor, maximum concurrent number
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', diff --git a/frontend/src/i18n/zh-CN.js b/frontend/src/i18n/zh-CN.js index fc48e2b742..3228c9b983 100644 --- a/frontend/src/i18n/zh-CN.js +++ b/frontend/src/i18n/zh-CN.js @@ -2458,6 +2458,10 @@ export default { usage: '用途', backend_listener: '后置监听器', batch_add_resource_tips: '格式:IP,Port,Monitor,最大并发数
如: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: '邮件设置', diff --git a/frontend/src/i18n/zh-TW.js b/frontend/src/i18n/zh-TW.js index 3d0c141918..83bddc61ed 100644 --- a/frontend/src/i18n/zh-TW.js +++ b/frontend/src/i18n/zh-TW.js @@ -2457,6 +2457,10 @@ export default { usage: '用途', backend_listener: '後置監聽器', batch_add_resource_tips: '格式:IP,Port,Monitor,最大並發數
如: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: '郵件設置',