improve host import

pull/330/head
vapao 2021-04-28 11:48:03 +08:00
parent e0e791b01c
commit afe5d351ad
3 changed files with 45 additions and 22 deletions

View File

@ -14,7 +14,6 @@ from libs.ssh import SSH, AuthenticationException
from paramiko.ssh_exception import BadAuthenticationType
from libs import AttrDict
from openpyxl import load_workbook
import socket
class HostView(View):
@ -90,7 +89,7 @@ class HostView(View):
task = Task.objects.filter(targets__regex=fr'[^0-9]{form.id}[^0-9]').first()
if task:
return json_response(error=f'任务计划中的任务【{task.name}】关联了该主机,请解除关联后再尝试删除该主机')
detection = Detection.objects.filter(type__in=('3', '4'), addr=form.id).first()
detection = Detection.objects.filter(type__in=('3', '4'), targets__regex=fr'[^0-9]{form.id}[^0-9]').first()
if detection:
return json_response(error=f'监控中心的任务【{detection.name}】关联了该主机,请解除关联后再尝试删除该主机')
Host.objects.filter(pk=form.id).delete()
@ -99,6 +98,7 @@ class HostView(View):
def post_import(request):
password = request.POST.get('password')
group_id = request.POST.get('group_id')
file = request.FILES['file']
ws = load_workbook(file, read_only=True)['Sheet1']
summary = {'invalid': [], 'skip': [], 'repeat': [], 'success': []}
@ -109,13 +109,12 @@ def post_import(request):
summary['invalid'].append(i)
continue
data = AttrDict(
zone=row[0].value,
name=row[1].value,
hostname=row[2].value,
port=row[3].value,
username=row[4].value,
password=row[5].value,
desc=row[6].value
name=row[0].value,
hostname=row[1].value,
port=row[2].value,
username=row[3].value,
password=row[4].value,
desc=row[5].value
)
if Host.objects.filter(hostname=data.hostname, port=data.port, username=data.username).exists():
summary['skip'].append(i)
@ -130,6 +129,7 @@ def post_import(request):
except Exception:
pass
host = Host.objects.create(created_by=request.user, **data)
host.groups.add(group_id)
if request.user.role:
request.user.role.add_host_perm(host.id)
summary['success'].append(i)

View File

@ -6,7 +6,7 @@
import React, { useState } from 'react';
import { observer } from 'mobx-react';
import { UploadOutlined } from '@ant-design/icons';
import { Modal, Form, Input, Upload, Button, Tooltip, Alert } from 'antd';
import { Modal, Form, Input, Upload, Button, Tooltip, Alert, Cascader, message } from 'antd';
import http from 'libs/http';
import store from './store';
@ -14,11 +14,14 @@ export default observer(function () {
const [loading, setLoading] = useState(false);
const [password, setPassword] = useState('');
const [fileList, setFileList] = useState([]);
const [groupId, setGroupId] = useState([]);
function handleSubmit() {
if (groupId.length === 0) return message.error('请选择要导入的分组');
setLoading(true);
const formData = new FormData();
formData.append('file', fileList[0]);
formData.append('group_id', groupId[groupId.length - 1]);
if (password) formData.append('password', password);
http.post('/api/host/import/', formData, {timeout: 120000})
.then(res => {
@ -35,7 +38,11 @@ export default observer(function () {
{res['repeat'].length > 0 && <Form.Item style={{margin: 0, color: '#1890ff'}} label="重复主机名">
<Tooltip title={`相关行:${res['repeat'].join(', ')}`}>{res['repeat'].length}</Tooltip>
</Form.Item>}
</Form>
</Form>,
onOk: () => {
store.fetchRecords();
store.importVisible = false
}
})
})
.finally(() => setLoading(false))
@ -52,7 +59,6 @@ export default observer(function () {
return (
<Modal
visible
width={800}
maskClosable={false}
title="批量导入"
okText="导入"
@ -60,13 +66,23 @@ export default observer(function () {
confirmLoading={loading}
okButtonProps={{disabled: !fileList.length}}
onOk={handleSubmit}>
<Alert closable showIcon type="info" message={null}
style={{width: 600, margin: '0 auto 20px', color: '#31708f !important'}}
description="导入或输入的密码仅作首次验证使用,并不会存储密码。"/>
<Alert
showIcon
type="info"
style={{width: 365, margin: '0 auto 20px'}}
message="导入或输入的密码仅作首次验证使用,不会存储。"/>
<Form labelCol={{span: 6}} wrapperCol={{span: 14}}>
<Form.Item label="模板下载" help="请下载使用该模板填充数据后导入">
<a href="/resource/主机导入模板.xlsx">主机导入模板.xlsx</a>
</Form.Item>
<Form.Item required label="选择分组">
<Cascader
value={groupId}
onChange={setGroupId}
options={store.treeData}
fieldNames={{label: 'title'}}
placeholder="请选择"/>
</Form.Item>
<Form.Item label="默认密码" help="如果excel中密码为空则使用该密码">
<Input
value={password}
@ -74,11 +90,15 @@ export default observer(function () {
placeholder="请输入默认主机密码"/>
</Form.Item>
<Form.Item required label="导入数据">
<Upload name="file" accept=".xls, .xlsx" fileList={fileList} beforeUpload={() => false}
onChange={handleUpload}>
<Button>
<UploadOutlined/> 点击上传
</Button>
<Upload
name="file"
accept=".xls, .xlsx"
fileList={fileList}
beforeUpload={() => false}
onChange={handleUpload}>
{fileList.length === 0 && (
<Button><UploadOutlined/> 点击上传</Button>
)}
</Upload>
</Form.Item>
</Form>

View File

@ -6,6 +6,7 @@
import { observable, computed } from 'mobx';
import { message } from 'antd';
import http from 'libs/http';
import lds from 'lodash';
class Store {
counter = {};
@ -87,10 +88,11 @@ class Store {
refreshCounter = () => {
if (this.treeData.length && this.records.length) {
for (let item of this.treeData) {
const treeData = lds.cloneDeep(this.treeData);
for (let item of treeData) {
this._refreshCounter(item)
}
this.treeData = [...this.treeData]
this.treeData = treeData
}
}
@ -101,6 +103,7 @@ class Store {
item.all_host_ids = item.all_host_ids.concat(ids)
}
item.all_host_ids = Array.from(new Set(item.all_host_ids));
if (this.group.key === item.key) this.group = item;
return item.all_host_ids
}