Skip to content

Commit

Permalink
perf: 对文件分发任务的源和目标使用同一批目标的情况做提醒交互 TencentBlueKing#147
Browse files Browse the repository at this point in the history
  • Loading branch information
hLinx committed Aug 3, 2021
1 parent 683ce7a commit f4d99e8
Show file tree
Hide file tree
Showing 6 changed files with 215 additions and 121 deletions.
4 changes: 3 additions & 1 deletion src/frontend/src/domain/model/task/task-file-step.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@

import _ from 'lodash';
import I18n from '@/i18n';
// import HostNode from '@model/host-node'
import TaskHostNodeModel from '@model/task-host-node';

const transferModeMap = {
Expand All @@ -35,6 +34,9 @@ const transferModeMap = {
};

export default class TaskFileStep {
static TYPE_SERVER = 1
static TYPE_LOCAL = 2
static TYPE_SOURCE = 3
constructor (payload = {}) {
this.timeout = payload.timeout;
this.uploadSpeedLimit = payload.uploadSpeedLimit || 0;
Expand Down
107 changes: 107 additions & 0 deletions src/frontend/src/utils/assist/business.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,110 @@ export const checkPublicScript = (route) => {
}
return false;
};

export const compareHost = (preHost, nextHost) => {
// 全都使用了主机变量
if (nextHost.variable && nextHost.variable === preHost.variable) {
return true;
}
// 服务文件主机手动添加
// 目标服务器主机使用主机变量
if (nextHost.variable) {
return false;
}
// 全都手动添加对比值
const {
ipList: preIPList,
topoNodeList: preNodeList,
dynamicGroupList: preGroupList,
} = preHost.hostNodeInfo;
const {
ipList: nextIPList,
topoNodeList: nextNodeList,
dynamicGroupList: nextGroupList,
} = nextHost.hostNodeInfo;
// 对比主机
if (preIPList.length !== nextIPList.length) {
return false;
}
const genHostKey = host => `${host.cloudAreaInfo.id}:${host.ip}`;
const preIPMap = preIPList.reduce((result, host) => {
result[genHostKey(host)] = true;
return result;
}, {});
// eslint-disable-next-line no-plusplus
for (let i = 0; i < nextIPList.length; i++) {
if (!preIPMap[genHostKey(nextIPList[i])]) {
return false;
}
}
// 对比节点
if (preNodeList.length !== nextNodeList.length) {
return false;
}
const genNodeKey = node => `#${node.id}#${node.type}`;
const taretNodeMap = preNodeList.reduce((result, node) => {
result[genNodeKey(node)] = true;
return result;
}, {});
// eslint-disable-next-line no-plusplus
for (let i = 0; i < nextNodeList.length; i++) {
if (!taretNodeMap[genNodeKey(nextNodeList[i])]) {
return false;
}
}
// 对比分组
if (preGroupList.length !== nextGroupList.length) {
return false;
}
const preGroupMap = preGroupList.reduce((result, groupId) => {
result[groupId] = true;
return result;
}, {});
// eslint-disable-next-line no-plusplus
for (let i = 0; i < nextGroupList.length; i++) {
if (!preGroupMap[nextGroupList[i]]) {
return false;
}
}
return true;
};

export const detectionSourceFileDupLocation = (fileSourceList) => {
const fileLocationMap = {};
const pathReg = /([^/]+\/?)\*?$/;
// 路径中以 * 结尾表示分发所有文件,可能和分发具体文件冲突
let hasDirAllFile = false;
let hasFile = false;
// eslint-disable-next-line no-plusplus
for (let i = 0; i < fileSourceList.length; i++) {
const currentFileSource = fileSourceList[i];
// eslint-disable-next-line no-plusplus
for (let j = 0; j < currentFileSource.fileLocation.length; j++) {
const currentFileLocation = currentFileSource.fileLocation[j];
// 分发所有文件
if (/\*$/.test(currentFileLocation)) {
hasDirAllFile = true;
if (hasFile) {
return true;
}
continue;
}
// 分发具体的文件
if (!/(\/|(\/\*))$/.test(currentFileLocation)) {
hasFile = true;
if (hasDirAllFile) {
return true;
}
}
const pathMatch = currentFileLocation.match(pathReg);
if (pathMatch) {
if (fileLocationMap[pathMatch[1]]) {
return true;
}
fileLocationMap[pathMatch[1]] = 1;
}
}
}
return false;
};
106 changes: 50 additions & 56 deletions src/frontend/src/views/fast-execution/distro-file/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,15 @@
} from 'vuex';
import I18n from '@/i18n';
import TaskExecuteService from '@service/task-execute';
import TaskStepModel from '@model/task/task-step';
import TaskHostNodeModel from '@model/task-host-node';
import JbForm from '@components/jb-form';
import CardLayout from '@components/task-step/file/card-layout';
import ItemFactory from '@components/task-step/file/item-factory';
import {
getScriptName,
compareHost,
detectionSourceFileDupLocation,
} from '@utils/assist';
import {
pushFileHistory,
Expand Down Expand Up @@ -347,71 +350,62 @@
},
});
}))
// 检测源文件的同名文件和目录
// 检测服务器源文件的主机和执行目标服务器主机相同
.then(() => new Promise((resolve, reject) => {
const fileLocationMap = {};
const pathReg = /([^/]+\/?)\*?$/;
let isDouble = false;
// 路径中以 * 结尾表示分发所有文件,可能和分发具体文件冲突
let hasDirAllFile = false;
let hasFile = false;
let sameHost = false;
// eslint-disable-next-line no-plusplus
for (let i = 0; i < this.formData.fileSourceList.length; i++) {
const currentFileSource = this.formData.fileSourceList[i];
// eslint-disable-next-line no-plusplus
for (let j = 0; j < currentFileSource.fileLocation.length; j++) {
const currentFileLocation = currentFileSource.fileLocation[j];
// 分发所有文件
if (/\*$/.test(currentFileLocation)) {
hasDirAllFile = true;
if (hasFile) {
isDouble = true;
break;
}
continue;
}
// 分发具体的文件
if (!/(\/|(\/\*))$/.test(currentFileLocation)) {
hasFile = true;
if (hasDirAllFile) {
isDouble = true;
break;
}
}
const pathMatch = currentFileLocation.match(pathReg);
if (pathMatch) {
if (fileLocationMap[pathMatch[1]]) {
isDouble = true;
break;
} else {
fileLocationMap[pathMatch[1]] = 1;
}
// 服务器源文件
if (currentFileSource.fileType === TaskStepModel.fileStep.TYPE_SERVER) {
if (compareHost(this.formData.server, currentFileSource.host)) {
sameHost = true;
break;
}
}
}

if (!isDouble) {
if (sameHost) {
this.$bkInfo({
title: I18n.t('execution.源和目标服务器相同'),
subTitle: I18n.t('execution.检测到文件传输源和目标服务器是同一批,若是单台建议使用本地 cp 方式效率会更高,请问你是否确定参数无误?'),
width: 500,
okText: I18n.t('execution.好的,我调整一下'),
cancelText: I18n.t('execution.是的,确定无误'),
confirmFn: () => {
reject(new Error('execute'));
},
cancelFn: () => {
resolve();
},
});
} else {
resolve();
}
}))
// 检测源文件的同名文件和目录
.then(() => new Promise((resolve, reject) => {
if (detectionSourceFileDupLocation(this.formData.fileSourceList)) {
// 有重名目录和文件
this.$bkInfo({
title: I18n.t('execution.源文件可能出现同名'),
subTitle: I18n.t('execution.多文件源传输场景下容易出现同名文件覆盖的问题,你可以在目标路径中使用 [源服务器IP] 的变量来尽可能规避风险。'),
okText: I18n.t('execution.好的,我调整一下'),
cancelText: I18n.t('execution.已知悉,确定执行'),
closeIcon: false,
width: 500,
confirmFn: () => {
// 聚焦到目标路径输入框
this.$refs.targetPath.$el.scrollIntoView();
this.$refs.targetPath.$el.querySelector('.bk-form-input').focus();
reject(new Error('transferMode change'));
},
cancelFn: () => {
resolve();
},
});
} else {
resolve();
return;
}
// 有重名目录和文件
this.$bkInfo({
title: I18n.t('execution.源文件可能出现同名'),
subTitle: I18n.t('execution.多文件源传输场景下容易出现同名文件覆盖的问题,你可以在目标路径中使用 [源服务器IP] 的变量来尽可能规避风险。'),
okText: I18n.t('execution.好的,我调整一下'),
cancelText: I18n.t('execution.已知悉,确定执行'),
closeIcon: false,
width: 500,
confirmFn: () => {
// 聚焦到目标路径输入框
this.$refs.targetPath.$el.scrollIntoView();
this.$refs.targetPath.$el.querySelector('.bk-form-input').focus();
reject(new Error('transferMode change'));
},
cancelFn: () => {
resolve();
},
});
}))
.then(() => {
const {
Expand Down
3 changes: 3 additions & 0 deletions src/frontend/src/views/fast-execution/local.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,8 @@ export default {
'多文件源传输场景下容易出现同名文件覆盖的问题,你可以在目标路径中使用 [源服务器IP] 的变量来尽可能规避风险。': 'Files may have the risk of overwriting with the same name in multi-file source, using built-in variable like [FILESRCIP] in the Dst. path to avoid risks as much as possible.',
'好的,我调整一下': 'Oops... Adjust Now',
'已知悉,确定执行': 'I\'m Sure, Keep Going',
源和目标服务器相同: '',
'检测到文件传输源和目标服务器是同一批,若是单台建议使用本地 cp 方式效率会更高,请问你是否确定参数无误?': '',
'是的,确定无误': '',
},
};
Loading

0 comments on commit f4d99e8

Please sign in to comment.