diff --git a/spug_api/apps/host/urls.py b/spug_api/apps/host/urls.py index b685216..c434677 100644 --- a/spug_api/apps/host/urls.py +++ b/spug_api/apps/host/urls.py @@ -7,4 +7,5 @@ from .views import * urlpatterns = [ path('', HostView.as_view()), + path('import/', post_import), ] diff --git a/spug_api/apps/host/views.py b/spug_api/apps/host/views.py index 9d98aef..329a740 100644 --- a/spug_api/apps/host/views.py +++ b/spug_api/apps/host/views.py @@ -10,7 +10,8 @@ from apps.app.models import Deploy from apps.schedule.models import Task from apps.monitor.models import Detection from libs.ssh import SSH, AuthenticationException -from libs import human_datetime +from libs import human_datetime, AttrDict +from openpyxl import load_workbook class HostView(View): @@ -69,6 +70,38 @@ class HostView(View): return json_response(error=error) +def post_import(request): + password = request.POST.get('password') + file = request.FILES['file'] + ws = load_workbook(file, read_only=True)['Sheet1'] + summary = {'invalid': [], 'skip': [], 'fail': [], 'success': []} + for i, row in enumerate(ws.rows): + if i == 0: # 第1行是表头 略过 + continue + if not all([row[x].value for x in range(5)]): + 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 + ) + if Host.objects.filter(hostname=data.hostname, port=data.port, username=data.username, + deleted_by_id__isnull=True).exists(): + summary['skip'].append(i) + continue + if valid_ssh(data.hostname, data.port, data.username, data.pop('password') or password) is False: + summary['fail'].append(i) + continue + Host.objects.create(created_by=request.user, **data) + summary['success'].append(i) + return json_response(summary) + + def valid_ssh(hostname, port, username, password): try: private_key = AppSetting.get('private_key') diff --git a/spug_api/requirements.txt b/spug_api/requirements.txt index 1532c93..4134d20 100644 --- a/spug_api/requirements.txt +++ b/spug_api/requirements.txt @@ -7,3 +7,4 @@ django-redis==4.10.0 requests==2.22.0 GitPython==3.0.8 python-ldap==3.2.0 +openpyxl==3.0.3 \ No newline at end of file diff --git a/spug_api/test.py b/spug_api/test.py new file mode 100644 index 0000000..eb51d2d --- /dev/null +++ b/spug_api/test.py @@ -0,0 +1,34 @@ +from email.message import EmailMessage +from email.utils import formataddr +import smtplib + + +class Mail: + def __init__(self, server, port, username, password, nickname=None): + self.host = server + self.port = port + self.user = username + self.password = password + self.nickname = nickname + + def _get_server(self): + print(self.host, self.port, self.user, self.password) + server = smtplib.SMTP_SSL(self.host, self.port) + server.login(self.user, self.password) + return server + + def send_text_mail(self, to_addrs, subject, body): + if isinstance(to_addrs, (list, tuple)): + to_addrs = ', '.join(to_addrs) + server = self._get_server() + msg = EmailMessage() + msg.set_content(body) + msg['Subject'] = subject + msg['From'] = formataddr((self.nickname, self.user)) if self.nickname else self.user + msg['To'] = to_addrs + server.send_message(msg) + server.quit() + +mail_service = {'server': 'smtp.163.com', 'port': '465', 'username': 'leiem1989@163.com', 'password': 'FOCCUIGOCTJGCBOB', 'nickname': 'spug'} +mail = Mail(**mail_service) +mail.send_text_mail({'live1989@foxmail.com'}, '恢复-官网检测', f'恢复-官网检测\r\n\r\n自动发送,请勿回复。') \ No newline at end of file diff --git a/spug_web/public/resource/主机导入模板.xlsx b/spug_web/public/resource/主机导入模板.xlsx new file mode 100644 index 0000000..1c3c1dd Binary files /dev/null and b/spug_web/public/resource/主机导入模板.xlsx differ diff --git a/spug_web/src/pages/host/Import.js b/spug_web/src/pages/host/Import.js new file mode 100644 index 0000000..0c5f718 --- /dev/null +++ b/spug_web/src/pages/host/Import.js @@ -0,0 +1,92 @@ +/** + * Copyright (c) OpenSpug Organization. https://github.com/openspug/spug + * Copyright (c) + * Released under the MIT License. + */ +import React from 'react'; +import { observer } from 'mobx-react'; +import { Modal, Form, Input, Upload, Icon, Button, Tooltip, Alert } from 'antd'; +import http from 'libs/http'; +import store from './store'; + +@observer +class ComImport extends React.Component { + constructor(props) { + super(props); + this.state = { + loading: false, + password: null, + fileList: [], + } + } + + handleSubmit = () => { + this.setState({loading: true}); + const formData = new FormData(); + formData.append('file', this.state.fileList[0]); + formData.append('password', this.state.password); + http.post('/api/host/import/', formData) + .then(res => { + Modal.info({ + title: '导入结果', + content:
+ {res.success.length} + {res['fail'].length > 0 && + {res['fail'].length} + } + {res['skip'].length > 0 && + {res['skip'].length} + } + {res['invalid'].length > 0 && + {res['invalid'].length} + } +
+ }) + }) + .finally(() => this.setState({loading: false})) + }; + + beforeUpload = (file) => { + this.setState({fileList: [file]}); + return false + }; + + render() { + return ( + store.importVisible = false} + confirmLoading={this.state.loading} + okButtonProps={{disabled: !this.state.fileList.length}} + onOk={this.handleSubmit}> + +
+ + 主机导入模板.xlsx + + + this.setState({password: e.target.value})} + placeholder="请输入默认主机密码"/> + + + + + + +
+
+ ) + } +} + +export default ComImport diff --git a/spug_web/src/pages/host/Table.js b/spug_web/src/pages/host/Table.js index 411c10d..b059b9d 100644 --- a/spug_web/src/pages/host/Table.js +++ b/spug_web/src/pages/host/Table.js @@ -8,6 +8,7 @@ import { observer } from 'mobx-react'; import { Table, Divider, Modal, message } from 'antd'; import { LinkButton } from 'components'; import ComForm from './Form'; +import ComImport from './Import'; import http from 'libs/http'; import store from './store'; @@ -85,6 +86,7 @@ class ComTable extends React.Component { {store.formVisible && } + {store.importVisible && } ) } diff --git a/spug_web/src/pages/host/index.js b/spug_web/src/pages/host/index.js index 5f13a3a..536745e 100644 --- a/spug_web/src/pages/host/index.js +++ b/spug_web/src/pages/host/index.js @@ -33,6 +33,8 @@ export default observer(function () { + diff --git a/spug_web/src/pages/host/store.js b/spug_web/src/pages/host/store.js index 9bb731c..88a4273 100644 --- a/spug_web/src/pages/host/store.js +++ b/spug_web/src/pages/host/store.js @@ -13,6 +13,7 @@ class Store { @observable idMap = {}; @observable isFetching = false; @observable formVisible = false; + @observable importVisible = false; @observable f_name; @observable f_zone;