openFuyao is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details. */
import { containerRouterPrefix } from '@/common/constants';
import { Address4 } from 'ip-address';
* 处理params
*/
import Dayjs from 'dayjs';
import { filterStatusName } from '../utils/common';
import dayjs from 'dayjs';
export function solveParams(params) {
for (let key in params) {
if (params[key] === '') {
params[key] = null;
}
}
return params;
}
* antd表格按名字首字母顺序排序
*/
export function sorterFirstAlphabe(a = '--', b = '--') {
if (typeof a === 'number' && typeof b === 'number') {
return a - b;
}
return a.toString().localeCompare(b.toString());
}
* antd表格按时间顺序排序
*/
export function sortJobByTime(a, b) {
let firstTime = a.creationTimestamp ? a.creationTimestamp : '';
let endTime = b.creationTimestamp ? b.creationTimestamp : '';
return Dayjs(firstTime) - Dayjs(endTime);
}
* antd表格筛选项去重过滤
*/
export function filterRepeat(arr) {
const newArr = arr.filter((item, index, self) => {
return self.findIndex((obj) => obj.value === item.value) === index;
});
return newArr;
}
* 工作负载表格按名称升序
*/
export function sortWorkLoadByNameAscend(type, arr) {
arr.sort((a, b) => {
let nameA = a.name;
let nameB = b.name;
if (nameA < nameB) {
return -1;
}
if (nameA > nameB) {
return 1;
}
return 0;
});
}
* 工作负载表格按名称降序
*/
export function sortWorkLoadByNameDescend(type, arr) {
arr.sort((a, b) => {
let nameA = a.name;
let nameB = b.name;
if (nameA < nameB) {
return 1;
}
if (nameA > nameB) {
return -1;
}
return 0;
});
}
* 工作负载表格按时间降序
*/
export function sortWorkLoadByTimeDescend(type, arr) {
arr.sort((a, b) => {
let timeA = a.creationTimestamp;
let timeB = b.creationTimestamp;
if (timeA < timeB) {
return 1;
}
if (timeA > timeB) {
return -1;
}
return 0;
});
}
* 工作负载表格按时间升序
*/
export function sortWorkLoadByTimeAscend(type, arr) {
arr.sort((a, b) => {
let nameA = a.creationTimestamp;
let nameB = b.creationTimestamp;
if (nameA < nameB) {
return -1;
}
if (nameA > nameB) {
return 1;
}
return 0;
});
}
* 工作负载表格按命名空间升序
*/
export function sortWorkLoadByNamespaceAscend(type, arr) {
arr.sort((a, b) => {
let namespaceA = a.namespace;
let namespaceB = b.namespace;
if (namespaceA < namespaceB) {
return -1;
}
if (namespaceA > namespaceB) {
return 1;
}
return 0;
});
}
* 工作负载表格按命名空间降序
*/
export function sortWorkLoadByNamespaceDescend(type, arr) {
arr.sort((a, b) => {
let namespaceA = a.namespace;
let namespaceB = b.namespace;
if (namespaceA < namespaceB) {
return 1;
}
if (namespaceA > namespaceB) {
return -1;
}
return 0;
});
}
* 工作负载表格按属性升序
*/
export function sortWorkLoadByStatusAscend(type, arr) {
arr.sort((a, b) => {
let typeA = filterStatusName(a.colocationType);
let typeB = filterStatusName(b.colocationType);
if (typeA < typeB) {
return 1;
}
if (typeA > typeB) {
return -1;
}
return 0;
});
}
* 工作负载表格按属性降序
*/
export function sortWorkLoadByStatusDescend(type, arr) {
arr.sort((a, b) => {
let typeA = filterStatusName(a.colocationType);
let typeB = filterStatusName(b.colocationType);
if (typeA < typeB) {
return -1;
}
if (typeA > typeB) {
return 1;
}
return 0;
});
}
* 工作负载表格按所属混部节点升序
*/
export function sortWorkLoadByNodeAscend(type, arr) {
arr.sort((a, b) => {
let nodeA = a.hostIP;
let nodeB = b.hostIP;
if (nodeA < nodeB) {
return -1;
}
if (nodeA > nodeB) {
return 1;
}
return 0;
});
}
* 工作负载表格按所属混部节点降序
*/
export function sortWorkLoadByNodeDescend(type, arr) {
arr.sort((a, b) => {
let nodeA = a.hostIP;
let nodeB = b.hostIP;
if (nodeA < nodeB) {
return 1;
}
if (nodeA > nodeB) {
return -1;
}
return 0;
});
}
* 工作负载表格按ip升序
*/
export function sortWorkLoadByIpAscend(type, arr) {
arr.sort((a, b) => {
const [podIpA, ...resets] = a.podIPs;
const [podIpB, ...resets1] = b.podIPs;
if (podIpA < podIpB) {
return -1;
}
if (podIpA > podIpB) {
return 1;
}
return 0;
});
}
* 工作负载表格按ip降序
*/
export function sortWorkLoadByIpDescend(type, arr) {
arr.sort((a, b) => {
const [podIpA, ...resets] = a.podIPs;
const [podIpB, ...resets1] = b.podIPs;
if (podIpA < podIpB) {
return 1;
}
if (podIpA > podIpB) {
return -1;
}
return 0;
});
}
* 判断 daemonsets
*/
export function getDaemonSetStatus(statusObj) {
let status = 'Failed';
if (!statusObj) {
status === 'Failed';
return status;
}
if (statusObj.desiredNumberScheduled) {
if (statusObj.numberAvailable === statusObj.desiredNumberScheduled) {
status = 'Active';
} else {
if (statusObj.currentNumberScheduled !== statusObj.desiredNumberScheduled) {
status = 'Updating';
}
}
} else {
status = 'Failed';
}
return status;
}
* 增加判断状态工作负载
* // status
*/
export function getWorkloadStatusJudge(statusObj) {
let status = 'Failed';
if (!statusObj) {
status === 'Failed';
return status;
}
if (statusObj.replicas) {
if (statusObj.availableReplicas === statusObj.replicas) {
status = 'Active';
} else {
if (statusObj.updatedReplicas !== statusObj.replicas) {
status = 'Updating';
}
}
} else {
status = 'Failed';
}
return status;
}
export function sorterFirstAlphabet(a = '--', b = '--') {
if (typeof a === 'number' && typeof b === 'number') {
return a - b;
}
return a.toString().localeCompare(b.toString());
}
export function firstAlphabetUp(word) {
return word.charAt(0).toUpperCase() + word.slice(1);
}
export function skipSendMainMsg(event, key, url, history, isAddLocalPrefix = true) {
event ? event.preventDefault() : '';
window.parent.postMessage({
type: 'subToMainMsg',
data: key,
url: isAddLocalPrefix ? `/${containerRouterPrefix}${url}` : url,
isInsertMainPrefix: true,
});
window.__OPENFUYAO__ ? '' : history.push(url);
}
* 通过数量生成
*/
export function solveDataAreaNumPalette(num) {
let colorList = ['#43cbbb', '#F9a975', '#4B8BEA', '#B4A2FF', '#Eb96F5'];
const colLength = colorList.length;
try {
for (let range = 0; range < num - colLength; range++) {
let color = '';
color = `rgb( ${[
Math.round((window.crypto.getRandomValues(new Uint8Array(1))[0] / 256) * 255), // 替换math.random()
Math.round((window.crypto.getRandomValues(new Uint8Array(1))[0] / 256) * 255),
Math.round((window.crypto.getRandomValues(new Uint8Array(1))[0] / 256) * 255),
].join(',')})`;
while (colorList.some((i) => i === color)) {
color = `rgb( ${[
Math.round((window.crypto.getRandomValues(new Uint8Array(1))[0] / 256) * 255), // 替换math.random()
Math.round((window.crypto.getRandomValues(new Uint8Array(1))[0] / 256) * 255),
Math.round((window.crypto.getRandomValues(new Uint8Array(1))[0] / 256) * 255),
].join(',')})`;
}
colorList.push(color);
}
} catch (e) {
}
return colorList;
}
* 优化颜色
*/
export function solveDataAreaNumPalettePlus(num) {
const presetColors = ['#43CBBB', '#F9A975', '#4B8BEA', '#B4A2FF', '#Eb96F5'];
if (num <= presetColors.length) {
return presetColors.slice(0, num);
}
const colorSet = new Set(presetColors);
const result = [...presetColors];
const generateRandomRgb = () => {
const randomValue = () => Math.floor(Math.random() * 256);
return `rgb(${randomValue()}, ${randomValue()}, ${randomValue()})`;
};
const neededColors = num - presetColors.length;
const batchSize = Math.min(1000, neededColors);
let generated = 0;
while (generated < neededColors) {
const batch = [];
const currentBatchSize = Math.min(batchSize, neededColors - generated);
for (let i = 0; i < currentBatchSize * 1.2; i++) {
batch.push(generateRandomRgb());
}
const uniqueBatch = batch.filter((color) => !colorSet.has(color));
const addCount = Math.min(uniqueBatch.length, neededColors - generated);
for (let i = 0; i < addCount; i++) {
const color = uniqueBatch[i];
colorSet.add(color);
result.push(color);
generated++;
}
}
return result;
}
export function solveColorMap(mockData, colors) {
const groupedData = {};
mockData.forEach((item) => {
if (!groupedData[item.name]) {
groupedData[item.name] = [];
}
groupedData[item.name].push(item);
});
const series = Object.keys(groupedData).map((type, index) => ({
name: type,
color: colors[index % colors.length],
}));
return series;
}
const completeTimeSeries = (dataArray) => {
if (dataArray.length === 0) return [];
const timeToMinutes = (timeStr) => {
const [hours, minutes] = timeStr.split(':').map(Number);
return hours * 60 + minutes;
};
const minutesToTime = (totalMinutes) => {
const hours = Math.floor(totalMinutes / 60);
const mins = totalMinutes % 60;
return `${String(hours).padStart(2, '0')}:${String(mins).padStart(2, '0')}`;
};
const processedData = [];
const timeMap = new Map();
dataArray.forEach(([time, value]) => {
const minutes = timeToMinutes(time);
processedData.push(minutes);
timeMap.set(minutes, value);
});
if (processedData.length === 0) return [];
processedData.sort((a, b) => a - b);
const min = processedData[0];
const max = processedData[processedData.length - 1];
const interval = 1;
const allMinutes = new Set(processedData);
for (let m = min; m <= max; m += interval) {
allMinutes.add(m);
}
const sortedMinutes = Array.from(allMinutes).sort((a, b) => a - b);
return sortedMinutes.map((m) => [minutesToTime(m), timeMap.has(m) ? timeMap.get(m) : null]);
};
export function solveSeriesMap(mockData) {
const seriesMap = {};
mockData.forEach((item) => {
if (!seriesMap[item.name]) {
seriesMap[item.name] = [];
}
seriesMap[item.name].push([dayjs(item.timestamp * 1000).format('HH:mm'), item.value]);
});
const series = Object.keys(seriesMap).map((name) => ({
name,
type: 'line',
smooth: true,
symbol: 'none',
data: completeTimeSeries(seriesMap[name]),
lineStyle: {
width: 3,
},
connectNulls: false,
}));
return series;
}
const cpuMapping = {
clusterCpuTotal: '物理资源总量',
clusterMemoryTotal: '物理资源总量',
clusterNoncoloCpuUsage: '非混部Pod使用量',
clusterNoncoloMemoryUsage: '非混部Pod使用量',
clusterHlsCpuUsage: 'HLS级别Pod使用量',
clusterHlsMemoryUsage: 'HLS级别Pod使用量',
clusterLsCpuUsage: 'LS级别Pod使用量',
clusterLsMemoryUsage: 'LS级别Pod使用量',
clusterBeCpuUsage: 'BE级别Pod使用量',
clusterBeMemoryUsage: 'BE级别Pod使用量',
clusterBeCpuAllocatable: '超卖资源总量',
clusterBeMemoryAllocatable: '超卖资源总量',
clusterBeCpuRequest: '超卖资源已申请量',
clusterBeMemoryRequest: '超卖资源已申请量',
clusterHlsCpuRequest: 'HLS级别Pod资源申请量',
clusterHlsMemoryRequest: 'HLS级别Pod资源申请量',
clusterLsCpuRequest: 'LS级别Pod资源申请量',
clusterLsMemoryRequest: 'LS级别Pod资源申请量',
clusterNoncoloCpuRequest: '非混部Pod资源申请量',
clusterNoncoloMemoryRequest: '非混部Pod资源申请量',
};
const cpuMappingEn = {
clusterCpuTotal: 'Total Physical Resources',
clusterMemoryTotal: 'Total Physical Resources',
clusterNoncoloCpuUsage: 'Non-Colocation Pod Usage',
clusterNoncoloMemoryUsage: 'Non-Colocation Pod Usage',
clusterHlsCpuUsage: 'HLS-Level Pod Usage',
clusterHlsMemoryUsage: 'HLS-Level Pod Usage',
clusterLsCpuUsage: 'LS-Level Pod Usage',
clusterLsMemoryUsage: 'LS-Level Pod Usage',
clusterBeCpuUsage: 'BE-Level Pod Usage',
clusterBeMemoryUsage: 'BE-Level Pod Usage',
clusterBeCpuAllocatable: 'Total Oversold Resources',
clusterBeMemoryAllocatable: 'Total Oversold Resources',
clusterBeCpuRequest: 'Oversold Resources Requested',
clusterBeMemoryRequest: 'Oversold Resources Requested',
clusterHlsCpuRequest: 'HLS-Level Pod Resource Request',
clusterHlsMemoryRequest: 'HLS-Level Pod Resource Request',
clusterLsCpuRequest: 'LS-Level Pod Resource Request',
clusterLsMemoryRequest: 'LS-Level Pod Resource Request',
clusterNoncoloCpuRequest: 'Non-Colocation Pod Resource Request',
clusterNoncoloMemoryRequest: 'Non-Colocation Pod Resource Request',
};
const nodeMapping = {
nodeCpuTotal: '物理资源总量',
nodeMemoryTotal: '物理资源总量',
nodeNoncoloCpuUsage: '非混部Pod使用量',
nodeNoncoloMemoryUsage: '非混部Pod使用量',
nodeHlsCpuUsage: 'HLS级别Pod使用量',
nodeHlsMemoryUsage: 'HLS级别Pod使用量',
nodeLsCpuUsage: 'LS级别Pod使用量',
nodeLsMemoryUsage: 'LS级别Pod使用量',
nodeBeCpuUsage: 'BE级别Pod使用量',
nodeBeMemoryUsage: 'BE级别Pod使用量',
nodeBeCpuAllocatable: '超卖资源总量',
nodeBeMemoryAllocatable: '超卖资源总量',
nodeBeCpuRequest: '超卖资源已申请量',
nodeBeMemoryRequest: '超卖资源已申请量',
nodeHlsCpuRequest: 'HLS级别Pod资源申请量',
nodeHlsMemoryRequest: 'HLS级别Pod资源申请量',
nodeLsCpuRequest: 'LS级别Pod资源申请量',
nodeLsMemoryRequest: 'LS级别Pod资源申请量',
nodeNoncoloCpuRequest: '非混部Pod资源申请量',
nodeNoncoloMemoryRequest: '非混部Pod资源申请量',
};
const nodeMappingEn = {
nodeCpuTotal: 'Total Physical Resources',
nodeMemoryTotal: 'Total Physical Resources',
nodeNoncoloCpuUsage: 'Non-Colocation Pod Usage',
nodeNoncoloMemoryUsage: 'Non-Colocation Pod Usage',
nodeHlsCpuUsage: 'HLS-Level Pod Usage',
nodeHlsMemoryUsage: 'HLS-Level Pod Usage',
nodeLsCpuUsage: 'LS-Level Pod Usage',
nodeLsMemoryUsage: 'LS-Level Pod Usage',
nodeBeCpuUsage: 'BE-Level Pod Usage',
nodeBeMemoryUsage: 'BE-Level Pod Usage',
nodeBeCpuAllocatable: 'Total Oversold Resources',
nodeBeMemoryAllocatable: 'Total Oversold Resources',
nodeBeCpuRequest: 'Oversold Resources Requested',
nodeBeMemoryRequest: 'Oversold Resources Requested',
nodeHlsCpuRequest: 'HLS-Level Pod Resource Request',
nodeHlsMemoryRequest: 'HLS-Level Pod Resource Request',
nodeLsCpuRequest: 'LS-Level Pod Resource Request',
nodeLsMemoryRequest: 'LS-Level Pod Resource Request',
nodeNoncoloCpuRequest: 'Non-Colocation Pod Resource Request',
nodeNoncoloMemoryRequest: 'Non-Colocation Pod Resource Request',
};
const isEnLocale = () => (window.__OPENFUYAO_LOCALE__ || 'zh-CN') === 'en-US';
const getMetricNameMap = () => (isEnLocale() ? cpuMappingEn : cpuMapping);
const getNodeMetricNameMap = () => (isEnLocale() ? nodeMappingEn : nodeMapping);
const getPhysicalResourceTotalName = () => (isEnLocale() ? 'Total Physical Resources' : '物理资源总量');
const getGeneralResourceTotalName = () => (isEnLocale() ? 'Total General Resources' : '通用资源总量');
const nodeZhMap = {
nodeCpuTotal: 'cpuNodeUse',
nodeMemoryTotal: 'memoryNodeUse',
nodeNoncoloCpuUsage: 'cpuNodeUse',
nodeNoncoloMemoryUsage: 'memoryNodeUse',
nodeHlsCpuUsage: 'cpuNodeUse',
nodeHlsMemoryUsage: 'memoryNodeUse',
nodeLsCpuUsage: 'cpuNodeUse',
nodeLsMemoryUsage: 'memoryNodeUse',
nodeBeCpuUsage: 'cpuNodeUse',
nodeBeMemoryUsage: 'memoryNodeUse',
nodeBeCpuAllocatable: 'cpuNodeApply',
nodeBeMemoryAllocatable: 'memoryNodeApply',
nodeBeCpuRequest: 'cpuNodeApply',
nodeBeMemoryRequest: 'memoryNodeApply',
nodeHlsCpuRequest: 'normalNodeCpu',
nodeHlsMemoryRequest: 'normalNodeMemory',
nodeLsCpuRequest: 'normalNodeCpu',
nodeLsMemoryRequest: 'normalNodeMemory',
nodeNoncoloCpuRequest: 'normalNodeCpu',
nodeNoncoloMemoryRequest: 'normalNodeMemory',
};
const newZhMap = {
clusterCpuTotal: 'cpuUse',
clusterMemoryTotal: 'memoryUse',
clusterNoncoloCpuUsage: 'cpuUse',
clusterNoncoloMemoryUsage: 'memoryUse',
clusterHlsCpuUsage: 'cpuUse',
clusterHlsMemoryUsage: 'memoryUse',
clusterLsCpuUsage: 'cpuUse',
clusterLsMemoryUsage: 'memoryUse',
clusterBeCpuUsage: 'cpuUse',
clusterBeMemoryUsage: 'memoryUse',
clusterBeCpuAllocatable: 'cpuApply',
clusterBeMemoryAllocatable: 'memoryApply',
clusterBeCpuRequest: 'cpuApply',
clusterBeMemoryRequest: 'memoryApply',
clusterHlsCpuRequest: 'normalCpu',
clusterHlsMemoryRequest: 'normalMemory',
clusterLsCpuRequest: 'normalCpu',
clusterLsMemoryRequest: 'normalMemory',
clusterNoncoloCpuRequest: 'normalCpu',
clusterNoncoloMemoryRequest: 'normalMemory',
};
const backMetricName = (name) => {
let finallyName = getMetricNameMap()[convertObjectKeys(name)];
return finallyName;
};
const backNodeMetricName = (name) => {
let finallyName = getNodeMetricNameMap()[convertObjectKeys(name)];
return finallyName;
};
const formatNumber = (num) => {
return num % 1 === 0 ? num : parseFloat(num.toFixed(2));
};
const convertObjectKeys = (name) => name.replace(/_(?<line>[a-z])/g, (_, letter) => letter.toUpperCase());
export function solveEchartsClean(data) {
let clusterResult = {
cpuUse: [],
memoryUse: [],
cpuApply: [],
memoryApply: [],
normalCpu: [],
normalMemory: [],
};
data.map((item) => {
const metricName = backMetricName(item.metricName);
if (metricName) {
item.data.result.map((resultItem) => {
resultItem.values.map(([timestamp, value]) => {
clusterResult[newZhMap[convertObjectKeys(item.metricName)]].push({
name: metricName,
timestamp,
value: item.metricName.includes('memory') && value ? formatNumber(value / 1024 / 1024) : value,
});
});
});
}
});
clusterResult.normalCpu = [
...clusterResult.cpuUse
.filter((item) => item.name === getPhysicalResourceTotalName())
.map((item) => ({ ...item, name: getGeneralResourceTotalName() })),
...clusterResult.normalCpu,
];
clusterResult.normalMemory = [
...clusterResult.memoryUse
.filter((item) => item.name === getPhysicalResourceTotalName())
.map((item) => ({ ...item, name: getGeneralResourceTotalName() })),
...clusterResult.normalMemory,
];
return clusterResult;
}
export function solveEchartsNodeClean(data) {
let nodeResult = {
cpuNodeUse: [],
memoryNodeUse: [],
cpuNodeApply: [],
memoryNodeApply: [],
normalNodeCpu: [],
normalNodeMemory: [],
};
data.map((item) => {
const metricName = backNodeMetricName(item.metricName);
if (metricName) {
item.data.result.map((resultItem) => {
resultItem.values.map(([timestamp, value]) => {
nodeResult[nodeZhMap[convertObjectKeys(item.metricName)]].push({
name: `${resultItem.metric.instance}-${metricName}`,
timestamp,
value: item.metricName.includes('memory') && value ? formatNumber(value / 1024 / 1024) : value,
});
});
});
}
});
nodeResult.normalNodeCpu = [
...nodeResult.cpuNodeUse
.filter((item) => item.name.includes(getPhysicalResourceTotalName()))
.map((item) => ({
...item,
name: item.name.replace(getPhysicalResourceTotalName(), getGeneralResourceTotalName()),
})),
...nodeResult.normalNodeCpu,
];
nodeResult.normalNodeMemory = [
...nodeResult.memoryNodeUse
.filter((item) => item.name.includes(getPhysicalResourceTotalName()))
.map((item) => ({
...item,
name: item.name.replace(getPhysicalResourceTotalName(), getGeneralResourceTotalName()),
})),
...nodeResult.normalNodeMemory,
];
return nodeResult;
}
export function compareIPs(ipA, ipB) {
let addrA = '';
let addrB = '';
if (ipA && ipA.length) {
addrA = new Address4(ipA[0]);
}
if (ipB && ipB.length) {
addrB = new Address4(ipB[0]);
}
return addrA.bigInteger() - addrB.bigInteger();
}
export function forbiddenMsg(message, errorMsg) {
const isEn = isEnLocale();
if (errorMsg.response.data.message.includes('User') || errorMsg.response.data.message.includes('user')) {
return message.error(
isEn
? 'Operation failed, current user does not have permission. Please contact the administrator to add permissions!'
: '操作失败,当前用户没有操作权限,请联系管理员添加权限!',
);
} else {
return message.error(
isEn
? 'Request rejected by the server. Please consider modifying the request!'
: '请求被服务端拒绝,建议修改该请求!',
);
}
}