1026 lines
40 KiB
Diff
1026 lines
40 KiB
Diff
From bba113a5899bb0b17916b2179e1f5594756dc58e Mon Sep 17 00:00:00 2001
|
||
From: Hu gang <18768366022@163.com>
|
||
Date: Wed, 13 Dec 2023 15:15:59 +0800
|
||
Subject: [PATCH] feat: add host management status, adaptation rollback tsak
|
||
|
||
---
|
||
src/api/assest.js | 1 +
|
||
src/api/leaks.js | 24 +--
|
||
src/config/router.config.js | 4 +
|
||
src/vendor/ant-design-pro/utils/request.js | 14 +-
|
||
src/views/assests/HostDetail.vue | 39 ++--
|
||
src/views/assests/HostManagement.vue | 82 ++++---
|
||
src/views/leaks/LeakTaskDetail.vue | 203 ++++++++++--------
|
||
src/views/leaks/LeakTaskList.vue | 4 +
|
||
src/views/leaks/TaskResultReport.vue | 76 +++++--
|
||
.../components/CreateRepairTaskDrawer.vue | 36 ++--
|
||
10 files changed, 277 insertions(+), 206 deletions(-)
|
||
|
||
diff --git a/src/api/assest.js b/src/api/assest.js
|
||
index a0f70ec..94015d3 100644
|
||
--- a/src/api/assest.js
|
||
+++ b/src/api/assest.js
|
||
@@ -55,6 +55,7 @@ export function hostList({tableInfo, ...parameter}) {
|
||
...parameter,
|
||
host_group_list: tableInfo.filters.host_group_name || [],
|
||
management,
|
||
+ search_key: tableInfo.filters.searchKey,
|
||
sort: tableInfo.sorter.field,
|
||
direction: directionMap[tableInfo.sorter.order],
|
||
page: tableInfo.pagination.current,
|
||
diff --git a/src/api/leaks.js b/src/api/leaks.js
|
||
index 8daf70d..c6f704b 100644
|
||
--- a/src/api/leaks.js
|
||
+++ b/src/api/leaks.js
|
||
@@ -44,15 +44,15 @@ const api = {
|
||
getRpmUnderCve: '/vulnerability/cve/packages/host/get', // 查询cve影响的rpm包的主机列表
|
||
getCvefixLeakRpm: '/vulnerability/task/cve/rpm/get', // 修复任务详情中cve列表的二级package
|
||
getCveRpmHostUnderLeak: '/vulnerability/task/cve/rpm/host/get', // 查询修复任务下的cve影响的rpm包的主机列表
|
||
- getCveListInFixDetail: '/vulnerability/task/cve-fix/info/get', // 新接口取代api.getCveUnderCveTask 获取修复任务详情下的cve列表
|
||
getRpmListInFixDetail: '/vulnerability/task/cve-fix/rpm/get', // 新接口取代api.getCvefixLeakRpm,获取修复任务详情下指定主机和任务下的rpm列表
|
||
getCveFixReport: '/vulnerability/task/cve-fix/result/get', // 新接口取代api.getCveTaskResult ,获取修复任务的报告
|
||
- getCveRollvackReport: ' /vulnerability/task/rollback/result/get', // 获取回滚任务报告
|
||
+ getCveRollvackReport: '/vulnerability/task/cve-rollback/result/get', // 获取回滚任务报告
|
||
generateHotPathRemoveTask: '/vulnerability/task/hotpatch-remove/generate', // 新接口取代api.generateRollbackTask ,生成热补丁移除任务
|
||
- getRpmListInRollbackDetail: '/vulnerability/task/rollback/rpm/get', // 获取回滚任务详情列表下的rpm信息
|
||
- getCveListInRollbackDetail: '/vulnerability/task/rollback/cve-info/get', // 获取回滚任务详情下的列表信息
|
||
+ getRpmListInRollbackDetail: '/vulnerability/task/cve-rollback/rpm/get', // 获取回滚任务详情列表下的rpm信息
|
||
generateRollbackTask: '/vulnerability/task/cve-rollback/generate', // 生成回滚任务
|
||
+ getCveListInRollbackDetail: '/vulnerability/task/cve-rollback/info/get', // 获取回滚任务详情下的列表信息
|
||
getCveHotpatchRemoveDetail: '/vulnerability/task/hotpatch-remove/info/get', // 获取热补丁移除任务详情
|
||
+ getCveListInFixDetail: '/vulnerability/task/cve-fix/info/get', // 新接口取代api.getCveUnderCveTask 获取修复任务详情下的cve列表
|
||
getHotpatchRemoveTaskReport: '/vulnerability/task/hotpatch-remove/result/get', // 获取热补丁移除任务报告
|
||
getAllHostInDetail: '/vulnerability/task/host/get' // 获取详情页面下所有的hostid
|
||
};
|
||
@@ -132,6 +132,7 @@ export function getCveListInRollbackDetail({tableInfo, ...params}) {
|
||
task_id: params.taskId,
|
||
direction: sorterMap[tableInfo.sorter.order],
|
||
filter: {
|
||
+ search_key: tableInfo.filters.searchKey,
|
||
status: tableInfo.filters.status
|
||
},
|
||
page: tableInfo.pagination.current,
|
||
@@ -140,7 +141,7 @@ export function getCveListInRollbackDetail({tableInfo, ...params}) {
|
||
});
|
||
}
|
||
|
||
-// 创建热补丁回退任务
|
||
+// 创建热补丁移除任务
|
||
export function generateHotPatchRemoveTask(params) {
|
||
return request({
|
||
url: api.generateHotPathRemoveTask,
|
||
@@ -196,6 +197,7 @@ export function getCveListInFixDetail({tableInfo, ...params}) {
|
||
task_id: params.taskId,
|
||
direction: sorterMap[tableInfo.sorter.order],
|
||
filter: {
|
||
+ search_key: tableInfo.filters.searchKey,
|
||
status: tableInfo.filters.status
|
||
},
|
||
page: tableInfo.pagination.current,
|
||
@@ -267,18 +269,6 @@ export function getCveFixRpm(parameters) {
|
||
});
|
||
}
|
||
|
||
-// export function generateRollbackTask(parameters) {
|
||
-// return request({
|
||
-// url: api.generateRollbackTask,
|
||
-// method: 'post',
|
||
-// data: {
|
||
-// task_name: parameters.task_name,
|
||
-// description: parameters.description,
|
||
-// info: parameters.info || []
|
||
-// }
|
||
-// });
|
||
-// }
|
||
-
|
||
export function getCveExport(parameter) {
|
||
return request({
|
||
url: api.getCveExport,
|
||
diff --git a/src/config/router.config.js b/src/config/router.config.js
|
||
index b92011f..5f1d4df 100644
|
||
--- a/src/config/router.config.js
|
||
+++ b/src/config/router.config.js
|
||
@@ -575,6 +575,10 @@ export const asyncRouterMap = [
|
||
breadcrumbName: routeMap.leaks.children.leakTaskView.children.leakTaskList.title,
|
||
path: routeMap.leaks.children.leakTaskView.children.leakTaskList.path
|
||
},
|
||
+ {
|
||
+ breadcrumbName: routeMap.leaks.children.leakTaskView.children.leakTaskDetail.title,
|
||
+ path: routeMap.leaks.children.leakTaskView.children.leakTaskDetail.path
|
||
+ },
|
||
{
|
||
breadcrumbName: routeMap.leaks.children.leakTaskView.children.taskResultReport.title,
|
||
path: routeMap.leaks.children.leakTaskView.children.taskResultReport.path
|
||
diff --git a/src/vendor/ant-design-pro/utils/request.js b/src/vendor/ant-design-pro/utils/request.js
|
||
index d9320d8..661bfd0 100644
|
||
--- a/src/vendor/ant-design-pro/utils/request.js
|
||
+++ b/src/vendor/ant-design-pro/utils/request.js
|
||
@@ -101,7 +101,7 @@ request.interceptors.response.use((response) => {
|
||
const code = response.data.code || response.status;
|
||
// 不处理所有2xx的状态码
|
||
if (!code.toString().match(/^2[0-9]{2,2}$/)) {
|
||
- let err = null;
|
||
+ // let err = null;
|
||
switch (code) {
|
||
case '1201':
|
||
if (!timestamp1 || timestamp1 + 1632252465 < new Date().getTime()) {
|
||
@@ -166,10 +166,14 @@ request.interceptors.response.use((response) => {
|
||
});
|
||
return retryRequest;
|
||
default:
|
||
- err = new Error(response.data.message);
|
||
- err.data = response.data.data;
|
||
- err.response = response.data;
|
||
- throw err;
|
||
+ notification.error({
|
||
+ message: response.data.label,
|
||
+ description: response.data.message
|
||
+ });
|
||
+ // err = new Error(response.data.message);
|
||
+ // err.data = response.data.data;
|
||
+ // err.response = response.data;
|
||
+ // throw err;
|
||
}
|
||
}
|
||
if (response.headers['content-type'] === 'application/octet-stream') {
|
||
diff --git a/src/views/assests/HostDetail.vue b/src/views/assests/HostDetail.vue
|
||
index 8286caf..6eadb05 100644
|
||
--- a/src/views/assests/HostDetail.vue
|
||
+++ b/src/views/assests/HostDetail.vue
|
||
@@ -49,38 +49,37 @@ export default {
|
||
};
|
||
},
|
||
methods: {
|
||
- fetchHostInfo(This) {
|
||
- const _this = This;
|
||
- This.basicHostInfoIsLoading = true;
|
||
- getHostDetail(This.hostId, true)
|
||
- .then(function (res) {
|
||
- _this.basicHostInfo = res.data.host_infos[0];
|
||
- _this.scene = This.basicHostInfo.scene;
|
||
+ fetchHostInfo() {
|
||
+ this.basicHostInfoIsLoading = true;
|
||
+ getHostDetail(Number(this.hostId), true)
|
||
+ .then((res) => {
|
||
+ this.basicHostInfo = res.data.host_infos[0];
|
||
+ this.scene = this.basicHostInfo.scene;
|
||
})
|
||
- .catch(function (err) {
|
||
- _this.$message.error(err.response.message);
|
||
+ .catch((err) => {
|
||
+ this.$message.error(err.response.message);
|
||
})
|
||
.finally(() => {
|
||
- _this.basicHostInfoIsLoading = false;
|
||
+ this.basicHostInfoIsLoading = false;
|
||
});
|
||
- This.basicInfoIsLoading = true;
|
||
- getHostDetail(This.hostId, false)
|
||
- .then(function (res) {
|
||
- _this.basicInfo = res.data.host_infos[0];
|
||
+ this.basicInfoIsLoading = true;
|
||
+ getHostDetail(Number(this.hostId), false)
|
||
+ .then((res) => {
|
||
+ this.basicInfo = res.data.host_infos[0];
|
||
})
|
||
- .catch(function (err) {
|
||
- _this.$message.error(err.response.message);
|
||
+ .catch((err) => {
|
||
+ this.$message.error(err.response.message);
|
||
})
|
||
.finally(() => {
|
||
- _this.basicInfoIsLoading = false;
|
||
+ this.basicInfoIsLoading = false;
|
||
});
|
||
},
|
||
reFetchHostInfo() {
|
||
- this.$options.methods.fetchHostInfo(this);
|
||
+ this.fetchHostInfo();
|
||
}
|
||
},
|
||
- mounted: function () {
|
||
- this.$options.methods.fetchHostInfo(this);
|
||
+ mounted() {
|
||
+ this.fetchHostInfo();
|
||
}
|
||
};
|
||
</script>
|
||
diff --git a/src/views/assests/HostManagement.vue b/src/views/assests/HostManagement.vue
|
||
index aaa86a8..77e0ed8 100644
|
||
--- a/src/views/assests/HostManagement.vue
|
||
+++ b/src/views/assests/HostManagement.vue
|
||
@@ -17,7 +17,8 @@
|
||
</a-alert>
|
||
</a-col>
|
||
<a-col>
|
||
- <a-button @click="handleReset">重置条件</a-button>
|
||
+ <!-- <a-button @click="handleReset">重置条件</a-button> -->
|
||
+ <a-input-search placeholder="按主机名或主机ip搜索" style="width: 200px" @search="handleSearch" />
|
||
</a-col>
|
||
</a-row>
|
||
</a-col>
|
||
@@ -59,26 +60,19 @@
|
||
>{{ hostName }}</router-link
|
||
>
|
||
<span slot="isManagement" slot-scope="isMana">{{ isMana ? '是' : '否' }}</span>
|
||
- <span slot="statusItem" slot-scope="status">{{ hostStatusMap[status] }}</span>
|
||
+ <span slot="statusItem" slot-scope="status">
|
||
+ <a-spin v-if="!status && status !== 0"></a-spin>
|
||
+ <span v-else>{{ hostStatusMap[status] }}</span>
|
||
+ </span>
|
||
<span slot="scene" slot-scope="scene">{{ scene ? (scene === 'normal' ? '通用' : scene) : '暂无' }}</span>
|
||
<span slot="action" slot-scope="record">
|
||
- <!-- <a @click="openDetail(record.host_id)">查看</a>
|
||
- ----后续增加-----
|
||
- <a-divider type="vertical" />
|
||
- <span>编辑</span>
|
||
- ----------------
|
||
- <a-divider type="vertical" /> -->
|
||
<router-link
|
||
:to="{path: `hosts-management/host-edit`, query: {hostId: record.host_id, pageType: 'edit'}}"
|
||
@click="editHost(record)"
|
||
- >编辑</router-link
|
||
- >
|
||
- <span> | </span>
|
||
- <a @click="deleteHost(record)">删除</a>
|
||
+ >编辑
|
||
+ </router-link>
|
||
+ <a @click="deleteHost(record)" class="delete-button"> 删除</a>
|
||
</span>
|
||
- <!-- <div slot="expandedRowRender" style="margin: 0">
|
||
- <host-terminal />
|
||
- </div> -->
|
||
</a-table>
|
||
</div>
|
||
</a-card>
|
||
@@ -94,7 +88,7 @@ import MyPageHeaderWrapper from '@/views/utils/MyPageHeaderWrapper';
|
||
import {getSelectedRow} from '@/views/utils/getSelectedRow';
|
||
import HostDetailDrawer from './components/HostDetailDrawer';
|
||
// import HostTerminal from '@/views/assests/components/HostTerminal';
|
||
-import {hostList, deleteHost, hostGroupList} from '@/api/assest';
|
||
+import {hostList, deleteHost, hostGroupList, getHostListWithStatus} from '@/api/assest';
|
||
|
||
const hostStatusMap = {
|
||
0: '在线',
|
||
@@ -214,6 +208,9 @@ export default {
|
||
}
|
||
},
|
||
methods: {
|
||
+ async getAllHostStatus() {
|
||
+ const res = await getHostListWithStatus();
|
||
+ },
|
||
handleTableChange(pagination, filters, sorter) {
|
||
// 存储翻页状态
|
||
this.pagination = pagination;
|
||
@@ -230,14 +227,13 @@ export default {
|
||
this.selectedRowsAll = getSelectedRow(selectedRowKeys, this.selectedRowsAll, this.tableData, 'host_id');
|
||
},
|
||
// 获取列表数据
|
||
- getHostList() {
|
||
- const _this = this;
|
||
+ async getHostList() {
|
||
this.tableIsLoading = true;
|
||
const pagination = this.pagination || {};
|
||
const filters = this.filters || {};
|
||
const sorter = this.sorter || {};
|
||
|
||
- hostList({
|
||
+ const hostListRes = await hostList({
|
||
tableInfo: {
|
||
pagination: {
|
||
current: pagination.current,
|
||
@@ -249,22 +245,28 @@ export default {
|
||
order: sorter.order
|
||
}
|
||
}
|
||
- })
|
||
- .then(function (res) {
|
||
- _this.tableData = res.data.host_infos || [];
|
||
- _this.pagination = {
|
||
- ..._this.pagination,
|
||
- current: pagination.current,
|
||
- pageSize: pagination.pageSize,
|
||
- total: res.data.total_count || (res.data.total_count === 0 ? 0 : pagination.total)
|
||
- };
|
||
- })
|
||
- .catch(function (err) {
|
||
- _this.$message.error(err.response.message);
|
||
- })
|
||
- .finally(function () {
|
||
- _this.tableIsLoading = false;
|
||
- });
|
||
+ });
|
||
+ if (hostListRes) {
|
||
+ this.tableData = hostListRes.data.host_infos || [];
|
||
+ this.pagination = {
|
||
+ ...this.pagination,
|
||
+ current: pagination.current,
|
||
+ pageSize: pagination.pageSize,
|
||
+ total: hostListRes.data.total_count || (hostListRes.data.total_count === 0 ? 0 : pagination.total)
|
||
+ };
|
||
+ const hostIdList = this.tableData.map((item) => item.host_id);
|
||
+ this.tableIsLoading = false;
|
||
+ const res = await getHostListWithStatus(hostIdList);
|
||
+ if (res) {
|
||
+ this.tableData.forEach((item) => {
|
||
+ const s = res.data.find((s) => item.host_id === s.host_id);
|
||
+ if (s) {
|
||
+ item.status = s.status;
|
||
+ }
|
||
+ });
|
||
+ this.tableData = JSON.parse(JSON.stringify(this.tableData));
|
||
+ }
|
||
+ }
|
||
},
|
||
editHost(record) {
|
||
this.$message.success('连接到主机' + record.host_ip);
|
||
@@ -384,6 +386,16 @@ export default {
|
||
duration: 5
|
||
});
|
||
},
|
||
+ handleSearch(text = '') {
|
||
+ this.pagination = defaultPagination;
|
||
+ this.sorter = null;
|
||
+ if (!this.filters) {
|
||
+ this.filters = {};
|
||
+ }
|
||
+ this.selectedRowKeys = [];
|
||
+ this.filters.searchKey = text !== '' ? text : undefined;
|
||
+ this.getHostList();
|
||
+ },
|
||
handleReset() {
|
||
this.pagination = defaultPagination;
|
||
this.sorter = null;
|
||
diff --git a/src/views/leaks/LeakTaskDetail.vue b/src/views/leaks/LeakTaskDetail.vue
|
||
index 27e919e..f7f7438 100644
|
||
--- a/src/views/leaks/LeakTaskDetail.vue
|
||
+++ b/src/views/leaks/LeakTaskDetail.vue
|
||
@@ -111,7 +111,9 @@
|
||
</a-row>
|
||
</a-col>
|
||
<a-col v-if="taskType === 'cve fix'">
|
||
- <a-button type="primary" @click="generateRollbackTask">生成回滚任务</a-button>
|
||
+ <a-button type="primary" @click="generateRollbackTask" :loading="isRollBackButtonLoading"
|
||
+ >生成回滚任务</a-button
|
||
+ >
|
||
</a-col>
|
||
</a-row>
|
||
<!-- 热补丁移除任务 -->
|
||
@@ -236,12 +238,13 @@ import {
|
||
getTaskProgress,
|
||
generateRollbackTask,
|
||
getCveProgressUnderCveTask,
|
||
- getAllHostInDetail
|
||
+ getAllHostInDetail,
|
||
+ getHostScanStatus
|
||
} from '@/api/leaks';
|
||
import configs from '@/config/defaultSettings';
|
||
|
||
const taskTypeMap = {
|
||
- 'cve fix': '漏洞修复',
|
||
+ 'cve fix': 'cve修复',
|
||
'repo set': 'REPO设置',
|
||
'cve rollback': 'cve回滚',
|
||
'hotpatch remove': '热补丁移除'
|
||
@@ -307,6 +310,8 @@ export default {
|
||
},
|
||
data() {
|
||
return {
|
||
+ // 生成回滚任务按钮是否loading
|
||
+ isRollBackButtonLoading: false,
|
||
expandedRowKeys: [],
|
||
rpmrecord: {},
|
||
propType: '',
|
||
@@ -379,7 +384,7 @@ export default {
|
||
{
|
||
dataIndex: 'host_name',
|
||
key: 'host_name',
|
||
- title: '主机',
|
||
+ title: '主机名',
|
||
scopedSlots: {customRender: 'hostName'}
|
||
},
|
||
{
|
||
@@ -391,7 +396,7 @@ export default {
|
||
{
|
||
dataIndex: 'cve_num',
|
||
key: 'cve_num',
|
||
- title: '修复的CVE',
|
||
+ title: 'CVE数量',
|
||
scopedSlots: {customRender: 'cveNum'}
|
||
},
|
||
{
|
||
@@ -405,26 +410,27 @@ export default {
|
||
{text: '修复成功', value: 'succeed'},
|
||
{text: '待修复', value: 'fail'},
|
||
{text: '运行中', value: 'running'},
|
||
- {text: '未知', value: 'None'}
|
||
+ {text: '未知', value: 'unknown'}
|
||
]
|
||
: [
|
||
{text: '回滚成功', value: 'succeed'},
|
||
{text: '待回滚', value: 'fail'},
|
||
{text: '运行中', value: 'running'},
|
||
- {text: '未知', value: 'None'}
|
||
+ {text: '未知', value: 'unknown'}
|
||
],
|
||
filteredValue: filters.status || null,
|
||
onFilter: (value, record) => record.status.includes(value)
|
||
}
|
||
];
|
||
},
|
||
+
|
||
repoColumns() {
|
||
let {filters} = this;
|
||
filters = filters || {};
|
||
return [
|
||
{
|
||
dataIndex: 'host_name',
|
||
- title: '主机名称',
|
||
+ title: '主机名',
|
||
scopedSlots: {customRender: 'host_name'}
|
||
},
|
||
{
|
||
@@ -452,27 +458,28 @@ export default {
|
||
},
|
||
// 展开后的列表列号
|
||
innerColumns() {
|
||
+ const {taskType} = this;
|
||
return [
|
||
{
|
||
dataIndex: 'installed_rpm',
|
||
key: 'installed_rpm',
|
||
- title: '受影响rpm'
|
||
+ title: taskType === 'cve fix' ? '受影响rpm' : '已安装rpm'
|
||
},
|
||
{
|
||
- dataIndex: 'available_rpm',
|
||
- key: 'available_rpm',
|
||
- title: '待安装rpm',
|
||
- scopedSlots: {customRender: 'available_rpm'}
|
||
+ dataIndex: taskType === 'cve fix' ? 'available_rpm' : 'target_rpm',
|
||
+ key: taskType === 'cve fix' ? 'available_rpm' : 'target_rpm',
|
||
+ title: taskType === 'cve fix' ? '待安装rpm' : '目标rpm',
|
||
+ scopedSlots: {customRender: 'rpm'}
|
||
},
|
||
{
|
||
dataIndex: 'cves',
|
||
key: 'cves',
|
||
- title: '修复cve'
|
||
+ title: 'CVE'
|
||
},
|
||
{
|
||
dataIndex: 'status',
|
||
key: 'rpm_status',
|
||
- title: '状态',
|
||
+ title: this.taskType === 'cve fix' ? '修复状态' : '回滚状态',
|
||
scopedSlots: {customRender: 'status'},
|
||
filter:
|
||
this.taskType === 'cve fix'
|
||
@@ -480,13 +487,13 @@ export default {
|
||
{text: '修复成功', value: 'succeed'},
|
||
{text: '待修复', value: 'fail'},
|
||
{text: '运行中', value: 'running'},
|
||
- {text: '未知', value: 'None'}
|
||
+ {text: '未知', value: 'unknown'}
|
||
]
|
||
: [
|
||
{text: '回滚成功', value: 'succeed'},
|
||
{text: '待回滚', value: 'fail'},
|
||
{text: '运行中', value: 'running'},
|
||
- {text: '未知', value: 'None'}
|
||
+ {text: '未知', value: 'unknown'}
|
||
]
|
||
}
|
||
];
|
||
@@ -563,50 +570,43 @@ export default {
|
||
clearInterval(this.jumpModalInterval);
|
||
this.isRollbackModelvisible = false;
|
||
this.$router.push({
|
||
- path: `/leaks/task/${this.taskType}/${this.rollbackTaskId}`,
|
||
+ path: `/leaks/task/cve rollback/${this.rollbackTaskId}`,
|
||
query: {
|
||
task_id: this.rollbackTaskId
|
||
}
|
||
});
|
||
+ this.expandedRowKeys = [];
|
||
+ this.taskType = 'cve rollback';
|
||
this.taskId = this.rollbackTaskId;
|
||
localStorage.setItem('taskId', this.taskId);
|
||
this.getInitalData();
|
||
},
|
||
async generateRollbackTask() {
|
||
+ this.isRollBackButtonLoading = true;
|
||
if (this.detail.statuses['running'] > 0) {
|
||
this.$warning({
|
||
title: '有任务正在运行,不能回滚。'
|
||
});
|
||
+ this.isRollBackButtonLoading = false;
|
||
return;
|
||
}
|
||
- this.$confirm({
|
||
- title: (
|
||
- <p>
|
||
- 回滚后无法恢复
|
||
- <br />
|
||
- 请确认回滚CVE修复任务:
|
||
- </p>
|
||
- ),
|
||
- icon: () => <a-icon type="exclamation-circle" />,
|
||
- onOk: async () => {
|
||
- const res = await generateRollbackTask(this.taskId);
|
||
- if (res) {
|
||
- this.rollbackTaskId = res.data.task_id;
|
||
- this.countDown = 5;
|
||
- this.isRollbackModelvisible = true;
|
||
- this.jumpModalInterval = setInterval(() => {
|
||
- this.countDown = this.countDown - 1;
|
||
- if (this.countDown === 0) {
|
||
- clearInterval(this.jumpModalInterval);
|
||
- this.isRollbackModelvisible = false;
|
||
- }
|
||
- }, 1000);
|
||
+ const res = await generateRollbackTask(this.taskId);
|
||
+ if (res) {
|
||
+ this.rollbackTaskId = res.data.task_id;
|
||
+ this.countDown = 5;
|
||
+ this.isRollbackModelvisible = true;
|
||
+ this.jumpModalInterval = setInterval(() => {
|
||
+ this.countDown = this.countDown - 1;
|
||
+ if (this.countDown === 0) {
|
||
+ clearInterval(this.jumpModalInterval);
|
||
+ this.isRollbackModelvisible = false;
|
||
}
|
||
- }
|
||
- });
|
||
+ }, 1000);
|
||
+ this.isRollBackButtonLoading = false;
|
||
+ } else {
|
||
+ }
|
||
},
|
||
dateFormat,
|
||
-
|
||
jumptoResult(value) {
|
||
this.$router.push({
|
||
path: `/leaks/task-report/${this.taskType}/${this.taskId}`,
|
||
@@ -633,7 +633,6 @@ export default {
|
||
});
|
||
return res || null;
|
||
},
|
||
-
|
||
// 展开详情列表
|
||
async expand(expanded, record) {
|
||
if (!expanded) return;
|
||
@@ -739,7 +738,7 @@ export default {
|
||
current: pagination.current,
|
||
pageSize: pagination.pageSize
|
||
},
|
||
- filters: filters,
|
||
+ filters,
|
||
sorter: {
|
||
field: sorter.field,
|
||
order: sorter.order
|
||
@@ -770,7 +769,7 @@ export default {
|
||
return res || null;
|
||
},
|
||
// 获取热补丁回退列表
|
||
- async getCveListWithHotpathRemove() {
|
||
+ async getCveListWithHotpathRemove(needScan = false) {
|
||
this.tableIsLoading = true;
|
||
const pagination = this.pagination || {};
|
||
const filters = this.filters || {};
|
||
@@ -800,12 +799,13 @@ export default {
|
||
this.tableIsLoading = false;
|
||
await this.updateCveProgress(
|
||
this.taskId,
|
||
- res.data.result.map((cve) => cve.cve_id)
|
||
+ res.data.result.map((cve) => cve.cve_id),
|
||
+ needScan
|
||
);
|
||
}
|
||
},
|
||
- // for cve task
|
||
- async getCveList() {
|
||
+ // 获取cve列表(修复,回滚)
|
||
+ async getCveList(needScan = false) {
|
||
this.tableIsLoading = true;
|
||
const res = this.taskType === 'cve fix' ? await this.getCveListWithFix() : await this.getCveListWithRollback();
|
||
if (res) {
|
||
@@ -814,34 +814,67 @@ export default {
|
||
rpms: []
|
||
}));
|
||
this.reportvisible = this.getReportVisible(res.data.result);
|
||
- this.expandedRowKeys = [];
|
||
+ // this.expandedRowKeys = [];
|
||
this.pagination = {
|
||
...this.pagination,
|
||
total: res.data.total_count || (res.data.total_count === 0 ? 0 : this.pagination.total)
|
||
};
|
||
- await this.updateHostProgress();
|
||
+ !this.reportvisible && (await this.updateHostProgress(needScan));
|
||
this.tableIsLoading = false;
|
||
}
|
||
},
|
||
// 修复,回滚任务running时刷新列表状态
|
||
- async updateHostProgress() {
|
||
+ async updateHostProgress(needScan = false) {
|
||
clearTimeout(this.CveScanStatueTimeout);
|
||
const res = this.taskType === 'cve fix' ? await this.getCveListWithFix() : await this.getCveListWithRollback();
|
||
const progressRes = res.data.result;
|
||
- this.tableData = progressRes.map((item) => ({
|
||
- ...item,
|
||
- rpms: []
|
||
- }));
|
||
+ progressRes.forEach((item) => {
|
||
+ const i = this.tableData.findIndex((t) => t.host_id === item.host_id);
|
||
+ if (i > -1 && this.tableData[i].status !== item.status) {
|
||
+ this.tableData[i].status = item.status;
|
||
+ if (this.expandedRowKeys.includes(this.tableData[i].host_id)) this.expand(true, this.tableData[i]);
|
||
+ }
|
||
+ });
|
||
+
|
||
const list = progressRes.filter((item) => item.status === 'running');
|
||
this.reportvisible = list.length === 0;
|
||
if (list.length > 0) {
|
||
this.CveScanStatueTimeout = setTimeout(() => {
|
||
- this.updateHostProgress();
|
||
+ this.updateHostProgress(needScan);
|
||
}, configs.taskProgressUpdateInterval);
|
||
+ } else {
|
||
+ needScan && (await this.sacnHostAfterExcute());
|
||
}
|
||
},
|
||
- // 更新热补丁回退的执行进度
|
||
- async updateCveProgress(taskId, cveList) {
|
||
+
|
||
+ // 在任务执行完成之后进行主机扫描
|
||
+ async sacnHostAfterExcute() {
|
||
+ const hostList = await this.getAllHostId();
|
||
+ const res = await getHostScanStatus({hostList});
|
||
+ if (!res) return;
|
||
+ const hostStatusList = res.data.result;
|
||
+ const needScanList = Object.keys(hostStatusList).map((h) => {
|
||
+ if (hostStatusList[h] !== 3 && hostList.includes(Number(h))) return Number(h);
|
||
+ });
|
||
+ this.scanLeakAfterExecuteTask(needScanList);
|
||
+ },
|
||
+ // 返回扫描状态的主机
|
||
+ getScanningHost(scanMap, hostList) {
|
||
+ const arr = [];
|
||
+ hostList.forEach((host) => {
|
||
+ if (scanMap[host.host_id] === 3) {
|
||
+ arr.push(host);
|
||
+ }
|
||
+ });
|
||
+ return arr;
|
||
+ },
|
||
+ /**
|
||
+ * 更新热补丁回退的执行进度
|
||
+ * @param {*} taskId 任务id
|
||
+ * @param {*} cveList cve 列表
|
||
+ * @param {*} needScan 是否需要扫描主机
|
||
+ */
|
||
+ async updateCveProgress(taskId, cveList, needScan = false) {
|
||
clearTimeout(this.CveScanStatueTimeout);
|
||
const processRes = await getCveProgressUnderCveTask({
|
||
taskId,
|
||
@@ -852,8 +885,10 @@ export default {
|
||
this.runningCveIds = this.getRunningCve(processRes.data.result);
|
||
if (this.runningCveIds.length > 0) {
|
||
this.CveScanStatueTimeout = setTimeout(() => {
|
||
- this.updateCveProgress(taskId, cveList);
|
||
+ this.updateCveProgress(taskId, cveList, needScan);
|
||
}, configs.taskProgressUpdateInterval);
|
||
+ } else {
|
||
+ needScan && (await this.sacnHostAfterExcute());
|
||
}
|
||
},
|
||
// 将查询到的cve进度更新到表格数据中,用于数据展示
|
||
@@ -954,26 +989,23 @@ export default {
|
||
title: `确定执行任务${this.detail.task_name}?`,
|
||
icon: () => <a-icon type="exclamation-circle" />,
|
||
okText: '执行',
|
||
- onOk: () => {
|
||
- return executeTask(this.taskId)
|
||
- .then((res) => {
|
||
- this.$message.success(res.message);
|
||
- this.scanLeakAfterExecuteTask();
|
||
- // 执行任务成功后刷新
|
||
- setTimeout(() => {
|
||
- this.getInitalData();
|
||
- this.expandedRowKeys = [];
|
||
- }, 3000);
|
||
- })
|
||
- .catch((err) => {
|
||
- this.$message.error(err.response.message);
|
||
- });
|
||
+ onOk: async () => {
|
||
+ const excuteRes = await executeTask(this.taskId);
|
||
+ if (excuteRes) {
|
||
+ // 获取详情任务所有处理的hostid列表
|
||
+ this.$message.success(excuteRes.message);
|
||
+ // 执行任务成功后刷新
|
||
+ setTimeout(() => {
|
||
+ this.getInitalData(true);
|
||
+ this.expandedRowKeys = [];
|
||
+ }, 3000);
|
||
+ }
|
||
}
|
||
});
|
||
},
|
||
- async scanLeakAfterExecuteTask() {
|
||
+ async scanLeakAfterExecuteTask(hostList) {
|
||
await scanHost({
|
||
- hostList: this.hostList,
|
||
+ hostList,
|
||
filter: null
|
||
});
|
||
},
|
||
@@ -981,7 +1013,7 @@ export default {
|
||
async getAllHostId() {
|
||
const res = await getAllHostInDetail(this.taskId);
|
||
if (res) {
|
||
- this.hostList = res.data;
|
||
+ return res.data;
|
||
}
|
||
},
|
||
showHostListUnderCve(type, record) {
|
||
@@ -992,16 +1024,17 @@ export default {
|
||
closeHostListUnderCve() {
|
||
this.hostListUnderCveVisible = false;
|
||
},
|
||
- getInitalData() {
|
||
+ /**
|
||
+ * isFresh 是第一次初始化还是后续的刷新数据
|
||
+ */
|
||
+ getInitalData(isFresh = false) {
|
||
this.getInfo();
|
||
- // 获取详情任务所有处理的hostid列表
|
||
- this.getAllHostId();
|
||
if (this.taskType === 'repo set') {
|
||
this.getHostList();
|
||
} else if (this.taskType === 'hotpatch remove') {
|
||
- this.getCveListWithHotpathRemove();
|
||
+ this.getCveListWithHotpathRemove(isFresh);
|
||
} else {
|
||
- this.getCveList();
|
||
+ this.getCveList(isFresh);
|
||
}
|
||
},
|
||
|
||
@@ -1023,9 +1056,9 @@ export default {
|
||
}
|
||
if (this.taskType === 'cve fix' || this.taskType === 'cve rollback') {
|
||
if (text !== '') {
|
||
- this.filters.host_name = text;
|
||
+ this.filters.searchKey = text;
|
||
} else {
|
||
- this.filters.host_name = undefined;
|
||
+ this.filters.searchKey = undefined;
|
||
}
|
||
this.getCveList();
|
||
} else {
|
||
@@ -1065,7 +1098,7 @@ export default {
|
||
localStorage.setItem('taskId', this.taskId);
|
||
},
|
||
mounted() {
|
||
- this.getInitalData();
|
||
+ this.getInitalData(false);
|
||
},
|
||
beforeDestroy() {
|
||
// 离开页面前,若当前存在轮询,清除轮询
|
||
diff --git a/src/views/leaks/LeakTaskList.vue b/src/views/leaks/LeakTaskList.vue
|
||
index be0ce82..08cb5e4 100644
|
||
--- a/src/views/leaks/LeakTaskList.vue
|
||
+++ b/src/views/leaks/LeakTaskList.vue
|
||
@@ -193,6 +193,10 @@ export default {
|
||
{
|
||
text: 'cve rollback',
|
||
value: 'cve rollback'
|
||
+ },
|
||
+ {
|
||
+ text: 'hotpatch remove',
|
||
+ value: 'hotpatch remove'
|
||
}
|
||
]
|
||
},
|
||
diff --git a/src/views/leaks/TaskResultReport.vue b/src/views/leaks/TaskResultReport.vue
|
||
index ca8d031..e702b06 100644
|
||
--- a/src/views/leaks/TaskResultReport.vue
|
||
+++ b/src/views/leaks/TaskResultReport.vue
|
||
@@ -1,4 +1,3 @@
|
||
-<!-- eslint-disable vue/max-attributes-per-line -->
|
||
<template>
|
||
<page-header-wrapper :breadcrumb="breadcrumb">
|
||
<a-card :bordered="false" class="aops-theme">
|
||
@@ -30,7 +29,7 @@
|
||
{{ cveStatusTextMap[resultItem.status] }}
|
||
</a-descriptions-item>
|
||
<a-descriptions-item label="状态" v-if="resultItem.task_type === 'cve rollback'">
|
||
- {{ rollStatusTextMap[resultItem.status] }}
|
||
+ {{ rollStatusTextMap[resultItem.task_result.result] }}
|
||
</a-descriptions-item>
|
||
<a-descriptions-item label="状态" v-if="resultItem.task_type === 'repo set'">
|
||
{{ repoStatusTextMap[resultItem.task_result.status] }}
|
||
@@ -39,8 +38,13 @@
|
||
{{ resultItem.task_result.repo }}
|
||
</a-descriptions-item>
|
||
</a-descriptions>
|
||
- <p class="reuslt-item-title">检查项:</p>
|
||
- <a-row>
|
||
+ <span class="reuslt-item-title">检查项:</span>
|
||
+ <span
|
||
+ v-if="resultItem.task_result.check_items && resultItem.task_result.check_items.length === 0"
|
||
+ style="margin-left: 10px"
|
||
+ >无</span
|
||
+ >
|
||
+ <a-row v-else>
|
||
<a-col span="8">
|
||
<a-descriptions :column="{sm: 1}" bordered size="small">
|
||
<a-descriptions-item
|
||
@@ -79,33 +83,31 @@
|
||
</div>
|
||
</div>
|
||
<!-- 回滚任务 -->
|
||
- <div v-if="taskType === 'cve rollback'" style="margin-left: 50px">
|
||
- <p class="reuslt-item-title" style="margin-top: 12px">RPM回滚情况:</p>
|
||
+ <div v-if="taskType === 'cve rollback'">
|
||
+ <p class="reuslt-item-title" style="margin-top: 12px">RPM回滚详情:</p>
|
||
<a-collapse v-if="resultItem.task_result.rpms.length !== 0" :bordered="false">
|
||
<a-collapse-panel
|
||
v-for="(rpm, rkidx) in resultItem.task_result.rpms"
|
||
:key="rkidx"
|
||
- :header="`${rpm.installed_rpm}`"
|
||
+ :header="`${rpm.cves}`"
|
||
>
|
||
- <div class="cve-item">
|
||
- <p class="reuslt-item-title">结果:</p>
|
||
- {{ rollStatusTextMap[rpm.result] }}
|
||
- </div>
|
||
- <div class="cve-item">
|
||
- <p class="reuslt-item-title" style="margin-top: 12px">Log:</p>
|
||
- <p class="result-log" v-html="logFormat(rpm.log)"></p>
|
||
- </div>
|
||
- <a-badge :status="statusResultValueMap[rpm.result]" slot="extra" />
|
||
+ <p>
|
||
+ <span class="title">已安装rpm:</span>
|
||
+ <span> {{ rpm.installed_rpm }}</span>
|
||
+ </p>
|
||
+ <p>
|
||
+ <span class="title">目标rpm:</span>
|
||
+ <span> {{ rpm.target_rpm }}</span>
|
||
+ </p>
|
||
+ <a-badge :status="statusResultValueMap[resultItem.task_result.result]" slot="extra" />
|
||
</a-collapse-panel>
|
||
</a-collapse>
|
||
- <div v-else class="cve-item">
|
||
- <p class="reuslt-item-title" style="margin-top: 12px">Log:</p>
|
||
- <p class="result-log">{{ resultItem.log }}</p>
|
||
- </div>
|
||
+ <p class="reuslt-item-title" style="margin-top: 16px">Log:</p>
|
||
+ <p class="result-log" v-html="logFormat(resultItem.task_result.log)"></p>
|
||
</div>
|
||
<!-- 热补丁移除任务 -->
|
||
<div v-if="taskType === 'hotpatch remove'" style="margin-left: 50px">
|
||
- <p class="reuslt-item-title" style="margin-top: 12px">CVE修复情况:</p>
|
||
+ <p class="reuslt-item-title" style="margin-top: 12px">热补丁移除情况:</p>
|
||
<a-collapse v-if="resultItem.task_result.cves.length !== 0" :bordered="false">
|
||
<a-collapse-panel
|
||
v-for="(cve, rkidx) in resultItem.task_result.cves"
|
||
@@ -113,7 +115,7 @@
|
||
:header="`${cve.cve_id}`"
|
||
>
|
||
<div class="cve-item">
|
||
- <p class="reuslt-item-title">结果: {{ statusResultTextMap[cve.result] }}</p>
|
||
+ <p class="reuslt-item-title">结果: {{ removeStatusResult[cve.result] }}</p>
|
||
</div>
|
||
<div class="cve-item">
|
||
<p class="reuslt-item-title" style="margin-top: 12px">Log:</p>
|
||
@@ -132,7 +134,16 @@
|
||
<p class="reuslt-item-title" style="margin-top: 16px">Log:</p>
|
||
<p class="result-log">{{ resultItem.task_result.log }}</p>
|
||
</div>
|
||
- <a-badge :status="statusValueMap[resultItem.status]" slot="extra" />
|
||
+ <a-badge
|
||
+ :status="
|
||
+ taskType === 'repo set'
|
||
+ ? statusValueMap[resultItem.task_result.status]
|
||
+ : taskType === 'cve fix' || taskType === 'hotpatch remove'
|
||
+ ? statusValueMap[resultItem.status]
|
||
+ : statusValueMap[resultItem.task_result.result]
|
||
+ "
|
||
+ slot="extra"
|
||
+ />
|
||
</a-collapse-panel>
|
||
</a-collapse>
|
||
</div>
|
||
@@ -188,6 +199,13 @@ const statusResultTextMap = {
|
||
unknown: '未知'
|
||
};
|
||
|
||
+const removeStatusResult = {
|
||
+ succeed: '移除成功',
|
||
+ fail: '待移除',
|
||
+ running: '运行中',
|
||
+ unknown: '未知'
|
||
+};
|
||
+
|
||
const statusResultValueMap = {
|
||
succeed: 'success',
|
||
unfixed: 'error',
|
||
@@ -210,6 +228,13 @@ export default {
|
||
props: {
|
||
routes,
|
||
itemRender: ({route, params, routes, paths, h}) => {
|
||
+ if (route.path === '/leaks/task/:taskType/:taskId') {
|
||
+ const path = {
|
||
+ path: `/leaks/task/${this.$route.query.taskType}/${this.$route.query.taskId}`,
|
||
+ query: {taskId: this.$route.query.taskId}
|
||
+ };
|
||
+ return <router-link to={path}>{route.breadcrumbName}</router-link>;
|
||
+ }
|
||
return <router-link to={route.path}>{route.breadcrumbName}</router-link>;
|
||
}
|
||
}
|
||
@@ -218,6 +243,7 @@ export default {
|
||
},
|
||
data() {
|
||
return {
|
||
+ removeStatusResult,
|
||
taskId: this.$route.query.taskId,
|
||
taskType: this.$route.query.taskType,
|
||
latestExecuteTime: this.$route.query.latestExecuteTime,
|
||
@@ -293,6 +319,10 @@ export default {
|
||
font-weight: 500;
|
||
color: rgba(0, 0, 0, 0.85);
|
||
}
|
||
+.title {
|
||
+ font-weight: bold;
|
||
+ margin-right: 5px;
|
||
+}
|
||
/deep/ .ant-descriptions-item {
|
||
.ant-descriptions-item-label {
|
||
font-weight: 500;
|
||
diff --git a/src/views/leaks/components/CreateRepairTaskDrawer.vue b/src/views/leaks/components/CreateRepairTaskDrawer.vue
|
||
index 5977bfb..b302439 100644
|
||
--- a/src/views/leaks/components/CreateRepairTaskDrawer.vue
|
||
+++ b/src/views/leaks/components/CreateRepairTaskDrawer.vue
|
||
@@ -4,7 +4,7 @@
|
||
{{ taskTypsbutton[taskType] }}
|
||
</a-button>
|
||
<a-drawer
|
||
- :title="`生成任务${taskType === 'repo set' ? ' 设置REPO' : ''}`"
|
||
+ :title="taskTypsbutton[taskType]"
|
||
closable
|
||
@close="handleCancel"
|
||
:get-container="false"
|
||
@@ -227,7 +227,7 @@ const taskTypsbutton = {
|
||
'cve fix': '生成修复任务',
|
||
'repo set': '设置REPO',
|
||
'cve rollback': '生成回滚任务',
|
||
- 'hotpatch remove': '热补丁移除'
|
||
+ 'hotpatch remove': '热补丁移除任务'
|
||
};
|
||
const taskTypsEnum = {
|
||
'cve fix': 'cve修复',
|
||
@@ -814,25 +814,19 @@ export default {
|
||
break;
|
||
} else {
|
||
// make request
|
||
- generateTask(params)
|
||
- .then((res) => {
|
||
- this.$message.success(res.message);
|
||
- if (excuteASAP) {
|
||
- const task = res.data.filter((item) => item.fix_way === 'hotpatch');
|
||
- this.handleExcuteASAP(task[0].task_id, res.data);
|
||
- } else {
|
||
- this.visible = false;
|
||
- this.handleGenerateSuccess(res.data, 'CVE修复', 'normal');
|
||
- }
|
||
- })
|
||
- .catch((err) => {
|
||
- this.$message.error(err.response.message);
|
||
- })
|
||
- .finally(() => {
|
||
- if (!excuteASAP) {
|
||
- this.submitLoading = false;
|
||
- }
|
||
- });
|
||
+ generateTask(params).then((res) => {
|
||
+ this.$message.success(res.message);
|
||
+ if (excuteASAP) {
|
||
+ // 如果同时存在冷热补丁两种任务,则选择热补丁任务立即执行,如果只有单个任务,则执行该任务
|
||
+ const task =
|
||
+ res.data.length > 1 ? res.data.filter((item) => item.fix_way === 'hotpatch') : res.data;
|
||
+ this.handleExcuteASAP(task[0].task_id, res.data);
|
||
+ } else {
|
||
+ this.visible = false;
|
||
+ this.handleGenerateSuccess(res.data, 'CVE修复', 'normal');
|
||
+ }
|
||
+ });
|
||
+ this.submitLoading = false;
|
||
break;
|
||
}
|
||
case 'repo set':
|
||
--
|
||
Gitee
|