feat(性能测试): 资源池增加cpu以及是否有任务执行的显示
--story=1013023 --user=宋天阳 【通用功能】选择资源池运行时支持查看资源池的使用状态以及各节点CPU使用率 https://www.tapd.cn/55049933/s/1424391
This commit is contained in:
parent
09e7e0b247
commit
d76e854e14
|
@ -1,6 +1,10 @@
|
|||
import { get } from 'metersphere-frontend/src/plugins/request';
|
||||
import {get, post} from 'metersphere-frontend/src/plugins/request';
|
||||
|
||||
export function getTestResourcePools() {
|
||||
let url = '/testresourcepool/list/quota/valid';
|
||||
return get(url);
|
||||
}
|
||||
|
||||
export function getNodeOperationInfo(request) {
|
||||
return post(`/prometheus/query/node-operation-info`, request)
|
||||
}
|
||||
|
|
|
@ -64,6 +64,11 @@
|
|||
:label="item.name"
|
||||
:disabled="!item.api"
|
||||
:value="item.id">
|
||||
<template v-slot>
|
||||
<node-operation-label
|
||||
:nodeName="item.name"
|
||||
:node-operation-info="nodeInfo(item.id)"/>
|
||||
</template>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
|
@ -83,19 +88,20 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { apiScenarioEnvMap } from '@/api/scenario';
|
||||
import {apiScenarioEnvMap} from '@/api/scenario';
|
||||
import MsDialogFooter from 'metersphere-frontend/src/components/MsDialogFooter';
|
||||
import { ENV_TYPE } from 'metersphere-frontend/src/utils/constants';
|
||||
import { strMapToObj } from 'metersphere-frontend/src/utils';
|
||||
import { getOwnerProjects, getProjectConfig } from '@/api/project';
|
||||
import { getTestResourcePools } from '@/api/test-resource-pool';
|
||||
import { getCurrentProjectID } from 'metersphere-frontend/src/utils/token';
|
||||
import {ENV_TYPE} from 'metersphere-frontend/src/utils/constants';
|
||||
import {strMapToObj} from 'metersphere-frontend/src/utils';
|
||||
import {getOwnerProjects, getProjectConfig} from '@/api/project';
|
||||
import {getNodeOperationInfo, getTestResourcePools} from '@/api/test-resource-pool';
|
||||
import {getCurrentProjectID} from 'metersphere-frontend/src/utils/token';
|
||||
import EnvSelectPopover from '@/business/automation/scenario/EnvSelectPopover';
|
||||
import { getApiCaseEnvironments } from '@/api/api-test-case';
|
||||
import {getApiCaseEnvironments} from '@/api/api-test-case';
|
||||
import NodeOperationLabel from "metersphere-frontend/src/components/node/NodeOperationLabel";
|
||||
|
||||
export default {
|
||||
name: 'ApiRunMode',
|
||||
components: { MsDialogFooter, EnvSelectPopover },
|
||||
components: {MsDialogFooter, EnvSelectPopover, NodeOperationLabel},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
|
@ -116,6 +122,7 @@ export default {
|
|||
projectList: [],
|
||||
projectIds: new Set(),
|
||||
caseIdEnvNameMap: {},
|
||||
nodeOperationInfo: {},
|
||||
};
|
||||
},
|
||||
props: {
|
||||
|
@ -127,6 +134,26 @@ export default {
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
nodeInfo(nodeId) {
|
||||
return this.nodeOperationInfo[nodeId];
|
||||
},
|
||||
selectNodeOperation() {
|
||||
let nodeOperationInfoRequest = {nodeIds: []};
|
||||
this.resourcePools.forEach(item => {
|
||||
nodeOperationInfoRequest.nodeIds.push(item.id);
|
||||
});
|
||||
|
||||
getNodeOperationInfo(nodeOperationInfoRequest)
|
||||
.then(response => {
|
||||
this.parseNodeOperationStatus(response.data);
|
||||
});
|
||||
},
|
||||
parseNodeOperationStatus(nodeOperationData) {
|
||||
this.nodeOperationInfo = {};
|
||||
nodeOperationData.forEach(item => {
|
||||
this.nodeOperationInfo[item.id] = item;
|
||||
});
|
||||
},
|
||||
open() {
|
||||
this.runModeVisible = true;
|
||||
this.getResourcePools();
|
||||
|
@ -173,6 +200,7 @@ export default {
|
|||
getResourcePools() {
|
||||
this.result = getTestResourcePools().then((response) => {
|
||||
this.resourcePools = response.data;
|
||||
this.selectNodeOperation();
|
||||
this.getProjectApplication();
|
||||
});
|
||||
},
|
||||
|
|
|
@ -20,6 +20,10 @@ const message = {
|
|||
trash: "Trash",
|
||||
yes: "yes",
|
||||
no: "no",
|
||||
running: "Running",
|
||||
idle: "idle",
|
||||
running_status: "Running Status",
|
||||
cpu_usage: "CPU Usage",
|
||||
expand_all: "Expand all",
|
||||
close_all: "Close all",
|
||||
example: "Demo",
|
||||
|
|
|
@ -20,6 +20,10 @@ const message = {
|
|||
trash: "回收站",
|
||||
yes: "是",
|
||||
no: "否",
|
||||
running: "运行中",
|
||||
idle: "空闲",
|
||||
running_status: "运行状态",
|
||||
cpu_usage: "CPU 使用率",
|
||||
expand_all: "一键展开",
|
||||
close_all: "一键收起",
|
||||
example: "示例",
|
||||
|
|
|
@ -20,6 +20,10 @@ const message = {
|
|||
trash: "回收站",
|
||||
yes: "是",
|
||||
no: "否",
|
||||
running: "運行中",
|
||||
idle: "空閑",
|
||||
running_status: "運行狀態",
|
||||
cpu_usage: "CPU 使用率",
|
||||
expand_all: "一鍵展開",
|
||||
close_all: "一鍵收起",
|
||||
example: "示例",
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package io.metersphere.controller;
|
||||
|
||||
import io.metersphere.dto.ResourcePoolOperationInfo;
|
||||
import io.metersphere.request.NodeOperationSelectRequest;
|
||||
import io.metersphere.service.PrometheusService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/prometheus")
|
||||
public class PrometheusController {
|
||||
|
||||
@Resource
|
||||
private PrometheusService prometheusService;
|
||||
|
||||
@PostMapping("/query/node-operation-info")
|
||||
public List<ResourcePoolOperationInfo> queryMetric(@RequestBody NodeOperationSelectRequest request) {
|
||||
return prometheusService.queryNodeOperationInfo(request);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package io.metersphere.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
public class ResourcePoolOperationInfo {
|
||||
private String id;
|
||||
private String cpuUsage;
|
||||
private int runningTask = 0;
|
||||
Map<String, NodeOperationInfo> nodeOperationInfos = new HashMap<>();
|
||||
|
||||
public void addNodeOperationInfo(String taskResourceId, String ip, String port, String cpuUsage, int runningTask) {
|
||||
NodeOperationInfo nodeOperationInfo = new NodeOperationInfo();
|
||||
nodeOperationInfo.setIp(ip);
|
||||
nodeOperationInfo.setPort(port);
|
||||
nodeOperationInfo.setCpuUsage(cpuUsage);
|
||||
nodeOperationInfo.setRunningTask(runningTask);
|
||||
nodeOperationInfos.put(taskResourceId, nodeOperationInfo);
|
||||
|
||||
this.cpuUsage = cpuUsage;
|
||||
this.runningTask += runningTask;
|
||||
|
||||
if (nodeOperationInfos.size() > 1) {
|
||||
//多节点的情况下暂不处理CPU使用率
|
||||
this.cpuUsage = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
class NodeOperationInfo {
|
||||
private String ip;
|
||||
private String port;
|
||||
private String cpuUsage;
|
||||
private int runningTask;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package io.metersphere.request;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class NodeOperationSelectRequest {
|
||||
private List<String> nodeIds;
|
||||
}
|
|
@ -14,13 +14,13 @@ import io.metersphere.log.vo.DetailColumn;
|
|||
import io.metersphere.log.vo.OperatingLogDetails;
|
||||
import io.metersphere.log.vo.system.SystemReference;
|
||||
import io.metersphere.request.resourcepool.QueryResourcePoolRequest;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.beanutils.BeanUtils;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -37,18 +37,18 @@ public class BaseTestResourcePoolService {
|
|||
@Resource
|
||||
private TestResourceMapper testResourceMapper;
|
||||
|
||||
public List<TestResourcePoolDTO> listResourcePools(QueryResourcePoolRequest request) {
|
||||
|
||||
public List<TestResourcePoolDTO> listResourcePoolById(List<String> testResourcePoolId) {
|
||||
TestResourcePoolExample example = new TestResourcePoolExample();
|
||||
TestResourcePoolExample.Criteria criteria = example.createCriteria();
|
||||
if (StringUtils.isNotBlank(request.getName())) {
|
||||
criteria.andNameLike(StringUtils.wrapIfMissing(request.getName(), "%"));
|
||||
}
|
||||
if (StringUtils.isNotBlank(request.getStatus())) {
|
||||
criteria.andStatusEqualTo(request.getStatus());
|
||||
}
|
||||
criteria.andIdIn(testResourcePoolId).andTypeEqualTo("NODE");
|
||||
criteria.andStatusNotEqualTo(DELETE.name());
|
||||
example.setOrderByClause("update_time desc");
|
||||
|
||||
List<TestResourcePool> testResourcePools = testResourcePoolMapper.selectByExample(example);
|
||||
return this.generateTestResourcePoolDTO(testResourcePools);
|
||||
}
|
||||
|
||||
private List<TestResourcePoolDTO> generateTestResourcePoolDTO(List<TestResourcePool> testResourcePools) {
|
||||
List<TestResourcePoolDTO> testResourcePoolDTOS = new ArrayList<>();
|
||||
testResourcePools.forEach(pool -> {
|
||||
TestResourceExample example2 = new TestResourceExample();
|
||||
|
@ -67,6 +67,21 @@ public class BaseTestResourcePoolService {
|
|||
return testResourcePoolDTOS;
|
||||
}
|
||||
|
||||
public List<TestResourcePoolDTO> listResourcePools(QueryResourcePoolRequest request) {
|
||||
TestResourcePoolExample example = new TestResourcePoolExample();
|
||||
TestResourcePoolExample.Criteria criteria = example.createCriteria();
|
||||
if (StringUtils.isNotBlank(request.getName())) {
|
||||
criteria.andNameLike(StringUtils.wrapIfMissing(request.getName(), "%"));
|
||||
}
|
||||
if (StringUtils.isNotBlank(request.getStatus())) {
|
||||
criteria.andStatusEqualTo(request.getStatus());
|
||||
}
|
||||
criteria.andStatusNotEqualTo(DELETE.name());
|
||||
example.setOrderByClause("update_time desc");
|
||||
List<TestResourcePool> testResourcePools = testResourcePoolMapper.selectByExample(example);
|
||||
return this.generateTestResourcePoolDTO(testResourcePools);
|
||||
}
|
||||
|
||||
|
||||
public TestResourcePool getResourcePool(String resourcePoolId) {
|
||||
return testResourcePoolMapper.selectByPrimaryKey(resourcePoolId);
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
package io.metersphere.service;
|
||||
|
||||
|
||||
import io.metersphere.base.domain.TestResource;
|
||||
import io.metersphere.commons.constants.ParamConstants;
|
||||
import io.metersphere.commons.utils.CodingUtil;
|
||||
import io.metersphere.commons.utils.JSON;
|
||||
import io.metersphere.commons.utils.LogUtil;
|
||||
import io.metersphere.dto.ResourcePoolOperationInfo;
|
||||
import io.metersphere.dto.TestResourcePoolDTO;
|
||||
import io.metersphere.request.NodeOperationSelectRequest;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.net.URL;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public class PrometheusService {
|
||||
|
||||
@Resource
|
||||
private SystemParameterService systemParameterService;
|
||||
@Resource
|
||||
private RestTemplate restTemplate;
|
||||
@Resource
|
||||
private BaseTestResourcePoolService baseTestResourcePoolService;
|
||||
|
||||
public List<ResourcePoolOperationInfo> queryNodeOperationInfo(NodeOperationSelectRequest request) {
|
||||
if (CollectionUtils.isEmpty(request.getNodeIds())) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
String host = systemParameterService.getValue(ParamConstants.BASE.PROMETHEUS_HOST.getValue());
|
||||
String prometheusHost = StringUtils.isNotBlank(host) ? host : "http://ms-prometheus:9090";
|
||||
List<TestResourcePoolDTO> testResourcePoolDTOS = baseTestResourcePoolService.listResourcePoolById(request.getNodeIds());
|
||||
return this.queryNodeOperationInfoByPrometheus(prometheusHost, testResourcePoolDTOS);
|
||||
}
|
||||
|
||||
private List<ResourcePoolOperationInfo> queryNodeOperationInfoByPrometheus(String host, List<TestResourcePoolDTO> testResourcePoolDTOS) {
|
||||
|
||||
List<ResourcePoolOperationInfo> returnList = new ArrayList<>();
|
||||
|
||||
HttpHeaders headers;
|
||||
try {
|
||||
headers = new HttpHeaders();
|
||||
headers.add("Content-Type", "application/x-www-form-urlencoded");
|
||||
// 如果prometheus开启了认证,需要在请求头中添加认证信息
|
||||
if (host.contains("@")) {
|
||||
URL url = new URL(host);
|
||||
// 获取认证信息部分
|
||||
String userInfo = url.getUserInfo();
|
||||
headers.add("Authorization", "Basic " + CodingUtil.base64Encoding(userInfo));
|
||||
host = host.replace(userInfo + "@", "");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtil.error("Get prometheus header fail.");
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
return returnList;
|
||||
}
|
||||
|
||||
DecimalFormat decimalFormat = new DecimalFormat("#0.00");
|
||||
decimalFormat.setMinimumFractionDigits(2);
|
||||
decimalFormat.setMaximumFractionDigits(2);
|
||||
|
||||
for (TestResourcePoolDTO testResourcePoolDTO : testResourcePoolDTOS) {
|
||||
ResourcePoolOperationInfo nodeOperationInfo = new ResourcePoolOperationInfo();
|
||||
nodeOperationInfo.setId(testResourcePoolDTO.getId());
|
||||
|
||||
boolean queryCpuUsage = true;
|
||||
if (testResourcePoolDTO.getResources().size() > 1) {
|
||||
queryCpuUsage = false;
|
||||
}
|
||||
|
||||
String cpuUsage = null;
|
||||
int runningTask = 0;
|
||||
|
||||
for (TestResource testResource : testResourcePoolDTO.getResources()) {
|
||||
String config = testResource.getConfiguration();
|
||||
if (StringUtils.isNotBlank(config)) {
|
||||
Map<String, Object> configMap = JSON.parseObject(config, Map.class);
|
||||
String ip = String.valueOf(configMap.get("ip"));
|
||||
String port = String.valueOf(configMap.get("port"));
|
||||
String nodeId = ip + ":" + port;
|
||||
if (queryCpuUsage) {
|
||||
String cpuUsageQL = this.generatePromQL(new String[]{"system_cpu_usage"}, nodeId);
|
||||
LogUtil.debug(host + "/api/v1/query?query=" + cpuUsageQL);
|
||||
String cpuUsageDouble = this.runPromQL(headers, host, cpuUsageQL);
|
||||
cpuUsage = decimalFormat.format(Double.parseDouble(cpuUsageDouble) * 100) + "%";
|
||||
}
|
||||
|
||||
// 查询任务数
|
||||
List<String> taskSeriesNames = new ArrayList<>() {{
|
||||
this.add("running_tasks_load_count");
|
||||
this.add("running_tasks_api_count");
|
||||
}};
|
||||
String taskCountQL = this.generatePromQL(taskSeriesNames.toArray(new String[0]), nodeId);
|
||||
String result = this.runPromQL(headers, host, taskCountQL);
|
||||
if (StringUtils.isNotBlank(result)) {
|
||||
runningTask += Integer.parseInt(result);
|
||||
}
|
||||
nodeOperationInfo.addNodeOperationInfo(String.valueOf(configMap.get("id")), ip, port, cpuUsage, runningTask);
|
||||
}
|
||||
}
|
||||
if (MapUtils.isNotEmpty(nodeOperationInfo.getNodeOperationInfos())) {
|
||||
returnList.add(nodeOperationInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return returnList;
|
||||
}
|
||||
|
||||
private String generatePromQL(String[] series, String nodeId) {
|
||||
StringBuilder promQL = new StringBuilder();
|
||||
for (int i = 0; i < series.length; i++) {
|
||||
String seriesName = series[i];
|
||||
if (i > 0) {
|
||||
promQL.append("+");
|
||||
}
|
||||
promQL.append(seriesName);
|
||||
promQL.append("{");
|
||||
promQL.append("instance=\"");
|
||||
promQL.append(nodeId);
|
||||
promQL.append("\"}");
|
||||
}
|
||||
return promQL.toString();
|
||||
}
|
||||
|
||||
private String runPromQL(HttpHeaders headers, String host, String promQL) {
|
||||
try {
|
||||
MultiValueMap<String, Object> postParameters = new LinkedMultiValueMap<>();
|
||||
postParameters.add("query", promQL);
|
||||
HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(postParameters, headers);
|
||||
return this.parseResultValue(restTemplate.postForObject(host + "/api/v1/query", httpEntity, Map.class));
|
||||
} catch (Exception e) {
|
||||
LogUtil.error("query prometheus metric fail.");
|
||||
LogUtil.error(e.getMessage(), e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String parseResultValue(Map response) {
|
||||
String value = null;
|
||||
if (response != null && StringUtils.equals((String) response.get("status"), "success")) {
|
||||
Map data = (Map) response.get("data");
|
||||
List result = (List) data.get("result");
|
||||
|
||||
if (CollectionUtils.isNotEmpty(result)) {
|
||||
Map resultObject = (Map) result.get(0);
|
||||
List valueMetrics = (List) resultObject.get("value");
|
||||
if (CollectionUtils.isNotEmpty(valueMetrics)) {
|
||||
value = valueMetrics.get(1).toString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
|
@ -237,3 +237,7 @@ export function exportScenarioJmx(condition) {
|
|||
export function searchScenarioList(goPage, pageSize, condition) {
|
||||
return post(`/api/automation/list/${goPage}/${pageSize}`, condition)
|
||||
}
|
||||
|
||||
export function getNodeOperationInfo(request) {
|
||||
return post(`/prometheus/query/node-operation-info`, request)
|
||||
}
|
||||
|
|
|
@ -11,6 +11,11 @@
|
|||
:label="item.name"
|
||||
:disabled="!item.performance"
|
||||
:value="item.id">
|
||||
<template v-slot>
|
||||
<node-operation-label
|
||||
:nodeName="item.name"
|
||||
:node-operation-info="nodeInfo(item.id)"/>
|
||||
</template>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
@ -219,22 +224,62 @@
|
|||
:value="index">
|
||||
</el-option>
|
||||
</el-select>
|
||||
<div style="margin-left: 5px;float: right">
|
||||
<el-tag size="mini" v-if="nodeTaskCount(resourceNodes[threadGroup.resourceNodeIndex])===0"
|
||||
style="color:#E5594B;background-color: #FFFFFF;border-color: #E5594B;margin-left: 5px;margin-right: 5px">
|
||||
{{ $t("commons.idle") }}
|
||||
</el-tag>
|
||||
<el-tag size="mini" v-else-if="nodeTaskCount(resourceNodes[threadGroup.resourceNodeIndex])>0"
|
||||
style="color:#89DB7E;background-color: #FFFFFF;border-color: #89DB7E;margin-left: 5px;margin-right: 5px">
|
||||
{{ $t("commons.running") }}
|
||||
</el-tag>
|
||||
|
||||
<span v-if="nodeTaskCount(resourceNodes[threadGroup.resourceNodeIndex]) !== -1">
|
||||
{{
|
||||
" " + $t("commons.cpu_usage") + " " + nodeCpuUsage(resourceNodes[threadGroup.resourceNodeIndex])
|
||||
}}
|
||||
</span>
|
||||
|
||||
</div>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div v-else>
|
||||
<el-table class="adjust-table" :data="threadGroup.resourceNodes" :max-height="200">
|
||||
<el-table-column type="index" width="50"/>
|
||||
<el-table-column prop="ip" label="IP"/>
|
||||
<el-table-column prop="runStatus" :label="$t('commons.running_status')">
|
||||
<template v-slot:default="{row}">
|
||||
<el-tag size="mini" v-if="nodeTaskCount(row)===0"
|
||||
style="color:#E5594B;background-color: #FFFFFF;border-color: #E5594B;margin-left: 5px;margin-right: 5px">
|
||||
{{ $t("commons.idle") }}
|
||||
</el-tag>
|
||||
<el-tag size="mini" v-else-if="nodeTaskCount(row)>0"
|
||||
style="color:#89DB7E;background-color: #FFFFFF;border-color: #89DB7E;margin-left: 5px;margin-right: 5px">
|
||||
{{ $t("commons.running") }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="maxConcurrency" :label="$t('test_resource_pool.max_threads')"/>
|
||||
<el-table-column prop="ratio" :label="$t('test_track.home.percentage')">
|
||||
<el-table-column prop="ratio" :label="$t('test_track.home.percentage')" width="120px">
|
||||
<template v-slot:default="{row}">
|
||||
<el-input-number size="mini" v-model="row.ratio"
|
||||
v-if="rampUpTimeVisible"
|
||||
@change="customNodeChange(threadGroup)"
|
||||
style="width: 100px"
|
||||
:min="0" :step=".1" controls-position="right"
|
||||
:max="1"></el-input-number>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="cpuUsage" :label="$t('commons.cpu_usage')">
|
||||
<template v-slot:default="{row}">
|
||||
{{ nodeCpuUsage(row) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="refresh" width="50px">
|
||||
<template v-slot:header>
|
||||
<el-button icon="el-icon-refresh" size="mini" @click="refreshNodeOperation" circle></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -252,8 +297,9 @@
|
|||
|
||||
<script>
|
||||
import MsChart from "metersphere-frontend/src/components/chart/MsChart";
|
||||
import NodeOperationLabel from "metersphere-frontend/src/components/node/NodeOperationLabel";
|
||||
import {findThreadGroup} from "../../../business/test/model/ThreadGroup";
|
||||
import {getJmxContent, getLoadConfig, getResourcePools} from "../../../api/performance";
|
||||
import {getJmxContent, getLoadConfig, getNodeOperationInfo, getResourcePools} from "../../../api/performance";
|
||||
|
||||
const HANDLER = "handler";
|
||||
const THREAD_GROUP_TYPE = "tgType";
|
||||
|
@ -288,7 +334,7 @@ const hexToRgb = function (hex) {
|
|||
|
||||
export default {
|
||||
name: "PerformancePressureConfig",
|
||||
components: {MsChart},
|
||||
components: {MsChart, NodeOperationLabel},
|
||||
props: {
|
||||
test: {
|
||||
type: Object
|
||||
|
@ -333,6 +379,7 @@ export default {
|
|||
autoStop: false,
|
||||
autoStopDelay: 30,
|
||||
rampUpTimeVisible: true,
|
||||
nodeOperationInfo: {},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -344,7 +391,7 @@ export default {
|
|||
{value: 'stoptest', label: this.$t('load_test.stoptest')},
|
||||
{value: 'stoptestnow', label: this.$t('load_test.stoptestnow')},
|
||||
];
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (this.testId) {
|
||||
|
@ -395,6 +442,36 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
refreshNodeOperation() {
|
||||
let nodeOperationInfoRequest = {nodeIds: []};
|
||||
this.resourcePools.forEach(item => {
|
||||
nodeOperationInfoRequest.nodeIds.push(item.id);
|
||||
});
|
||||
|
||||
getNodeOperationInfo(nodeOperationInfoRequest)
|
||||
.then(response => {
|
||||
this.parseNodeOperationStatus(response.data);
|
||||
});
|
||||
},
|
||||
nodeCpuUsage(row) {
|
||||
let nodeInfo = this.nodeOperationInfo[this.resourcePool];
|
||||
if (nodeInfo) {
|
||||
return this.nodeOperationInfo[this.resourcePool].nodeOperationInfos[row.id].cpuUsage;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
},
|
||||
nodeTaskCount(row) {
|
||||
let nodeInfo = this.nodeOperationInfo[this.resourcePool];
|
||||
if (nodeInfo) {
|
||||
return this.nodeOperationInfo[this.resourcePool].nodeOperationInfos[row.id].runningTask;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
},
|
||||
nodeInfo(nodeId) {
|
||||
return this.nodeOperationInfo[nodeId];
|
||||
},
|
||||
getResourcePools() {
|
||||
getResourcePools(this.isShare)
|
||||
.then(response => {
|
||||
|
@ -408,9 +485,24 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
let nodeOperationInfoRequest = {nodeIds: []};
|
||||
this.resourcePools.forEach(item => {
|
||||
nodeOperationInfoRequest.nodeIds.push(item.id);
|
||||
});
|
||||
|
||||
getNodeOperationInfo(nodeOperationInfoRequest)
|
||||
.then(response => {
|
||||
this.parseNodeOperationStatus(response.data);
|
||||
});
|
||||
this.resourcePoolChange();
|
||||
});
|
||||
},
|
||||
parseNodeOperationStatus(nodeOperationData) {
|
||||
this.nodeOperationInfo = {};
|
||||
nodeOperationData.forEach(item => {
|
||||
this.nodeOperationInfo[item.id] = item;
|
||||
});
|
||||
},
|
||||
getLoadConfig() {
|
||||
this.result.loading = true;
|
||||
getLoadConfig(this.testId, this.reportId, this.isShare)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import {get, post} from "metersphere-frontend/src/plugins/request"
|
||||
import {hasLicense} from "metersphere-frontend/src/utils/permission";
|
||||
import {getCurrentProjectID} from "metersphere-frontend/src/utils/token";
|
||||
|
||||
export function getProject(id) {
|
||||
|
@ -38,6 +37,10 @@ export function getProjectConfig(projectId, type) {
|
|||
return get(url);
|
||||
}
|
||||
|
||||
export function getNodeOperationInfo(request) {
|
||||
return post(`/prometheus/query/node-operation-info`, request)
|
||||
}
|
||||
|
||||
export function apiTestReRun(condition) {
|
||||
return post('/api/test/exec/rerun', condition);
|
||||
}
|
||||
|
|
|
@ -73,6 +73,11 @@
|
|||
:label="item.name"
|
||||
:value="item.id"
|
||||
>
|
||||
<template v-slot>
|
||||
<node-operation-label
|
||||
:nodeName="item.name"
|
||||
:node-operation-info="nodeInfo(item.id)"/>
|
||||
</template>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</div>
|
||||
|
@ -155,25 +160,19 @@
|
|||
|
||||
<script>
|
||||
import MsDialogFooter from "metersphere-frontend/src/components/MsDialogFooter";
|
||||
import { strMapToObj } from "metersphere-frontend/src/utils";
|
||||
import {strMapToObj} from "metersphere-frontend/src/utils";
|
||||
import MsTag from "metersphere-frontend/src/components/MsTag";
|
||||
import { ENV_TYPE } from "metersphere-frontend/src/utils/constants";
|
||||
import {
|
||||
getCurrentProjectID,
|
||||
getOwnerProjects,
|
||||
} from "@/business/utils/sdk-utils";
|
||||
import { getQuotaValidResourcePools } from "@/api/remote/resource-pool";
|
||||
import {ENV_TYPE} from "metersphere-frontend/src/utils/constants";
|
||||
import {getCurrentProjectID, getOwnerProjects,} from "@/business/utils/sdk-utils";
|
||||
import {getQuotaValidResourcePools} from "@/api/remote/resource-pool";
|
||||
import EnvGroupPopover from "@/business/plan/env/EnvGroupPopover";
|
||||
import { getApiCaseEnv } from "@/api/remote/plan/test-plan-api-case";
|
||||
import {
|
||||
getApiScenarioEnv,
|
||||
getPlanCaseEnv,
|
||||
getPlanCaseProjectIds,
|
||||
} from "@/api/remote/plan/test-plan";
|
||||
import {getApiCaseEnv} from "@/api/remote/plan/test-plan-api-case";
|
||||
import {getApiScenarioEnv, getPlanCaseEnv, getPlanCaseProjectIds,} from "@/api/remote/plan/test-plan";
|
||||
import EnvGroupWithOption from "../env/EnvGroupWithOption";
|
||||
import EnvironmentGroup from "@/business/plan/env/EnvironmentGroupList";
|
||||
import EnvSelectPopover from "@/business/plan/env/EnvSelectPopover";
|
||||
import { getProjectConfig } from "@/api/project";
|
||||
import {getNodeOperationInfo, getProjectConfig} from "@/api/project";
|
||||
import NodeOperationLabel from "metersphere-frontend/src/components/node/NodeOperationLabel";
|
||||
|
||||
export default {
|
||||
name: "MsTestPlanRunModeWithEnv",
|
||||
|
@ -184,6 +183,7 @@ export default {
|
|||
EnvGroupWithOption,
|
||||
EnvironmentGroup,
|
||||
EnvSelectPopover,
|
||||
NodeOperationLabel,
|
||||
},
|
||||
computed: {
|
||||
ENV_TYPE() {
|
||||
|
@ -229,6 +229,7 @@ export default {
|
|||
},
|
||||
],
|
||||
value: "confirmAndRun",
|
||||
nodeOperationInfo: {},
|
||||
browsers: [
|
||||
{
|
||||
label: this.$t("chrome"),
|
||||
|
@ -263,6 +264,26 @@ export default {
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
nodeInfo(nodeId) {
|
||||
return this.nodeOperationInfo[nodeId];
|
||||
},
|
||||
selectNodeOperation() {
|
||||
let nodeOperationInfoRequest = {nodeIds: []};
|
||||
this.resourcePools.forEach(item => {
|
||||
nodeOperationInfoRequest.nodeIds.push(item.id);
|
||||
});
|
||||
|
||||
getNodeOperationInfo(nodeOperationInfoRequest)
|
||||
.then(response => {
|
||||
this.parseNodeOperationStatus(response.data);
|
||||
});
|
||||
},
|
||||
parseNodeOperationStatus(nodeOperationData) {
|
||||
this.nodeOperationInfo = {};
|
||||
nodeOperationData.forEach(item => {
|
||||
this.nodeOperationInfo[item.id] = item;
|
||||
});
|
||||
},
|
||||
open(testType, runModeConfig) {
|
||||
this.defaultEnvMap = {};
|
||||
if (this.type === "plan") {
|
||||
|
@ -350,6 +371,7 @@ export default {
|
|||
getResourcePools() {
|
||||
getQuotaValidResourcePools().then((response) => {
|
||||
this.resourcePools = response.data;
|
||||
this.selectNodeOperation();
|
||||
this.getProjectApplication();
|
||||
});
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue