mirror of https://github.com/openspug/spug
parent
b8fbb0e8eb
commit
b42b12aa88
|
@ -13,6 +13,7 @@ urlpatterns = [
|
|||
path('extend/', ExtendView.as_view()),
|
||||
path('group/', GroupView.as_view()),
|
||||
path('import/', post_import),
|
||||
path('export/', post_export),
|
||||
path('import/cloud/', cloud_import),
|
||||
path('import/region/', get_regions),
|
||||
path('parse/', post_parse),
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# Released under the AGPL-3.0 License.
|
||||
from django.views.generic import View
|
||||
from django.db.models import F
|
||||
from django.http.response import HttpResponseBadRequest
|
||||
from django.http.response import HttpResponseBadRequest, HttpResponse
|
||||
from libs import json_response, JsonParser, Argument, AttrDict, auth
|
||||
from apps.setting.utils import AppSetting
|
||||
from apps.account.utils import get_host_perms
|
||||
|
@ -14,10 +14,11 @@ from apps.schedule.models import Task
|
|||
from apps.monitor.models import Detection
|
||||
from libs.ssh import SSH, AuthenticationException
|
||||
from paramiko.ssh_exception import BadAuthenticationType
|
||||
from openpyxl import load_workbook
|
||||
from openpyxl import load_workbook, Workbook
|
||||
from threading import Thread
|
||||
import socket
|
||||
import uuid
|
||||
import json
|
||||
|
||||
|
||||
class HostView(View):
|
||||
|
@ -110,13 +111,16 @@ class HostView(View):
|
|||
deploy = Deploy.objects.filter(host_ids__regex=regex) \
|
||||
.annotate(app_name=F('app__name'), env_name=F('env__name')).first()
|
||||
if deploy:
|
||||
return json_response(error=f'应用【{deploy.app_name}】在【{deploy.env_name}】的发布配置关联了该主机,请解除关联后再尝试删除该主机')
|
||||
return json_response(
|
||||
error=f'应用【{deploy.app_name}】在【{deploy.env_name}】的发布配置关联了该主机,请解除关联后再尝试删除该主机')
|
||||
task = Task.objects.filter(targets__regex=regex).first()
|
||||
if task:
|
||||
return json_response(error=f'任务计划中的任务【{task.name}】关联了该主机,请解除关联后再尝试删除该主机')
|
||||
return json_response(
|
||||
error=f'任务计划中的任务【{task.name}】关联了该主机,请解除关联后再尝试删除该主机')
|
||||
detection = Detection.objects.filter(type__in=('3', '4'), targets__regex=regex).first()
|
||||
if detection:
|
||||
return json_response(error=f'监控中心的任务【{detection.name}】关联了该主机,请解除关联后再尝试删除该主机')
|
||||
return json_response(
|
||||
error=f'监控中心的任务【{detection.name}】关联了该主机,请解除关联后再尝试删除该主机')
|
||||
Host.objects.filter(id__in=host_ids).delete()
|
||||
return json_response(error=error)
|
||||
|
||||
|
@ -161,6 +165,37 @@ def post_import(request):
|
|||
return json_response({'summary': summary, 'token': token, 'hosts': {x.id: {'name': x.name} for x in hosts}})
|
||||
|
||||
|
||||
@auth('host.host.view')
|
||||
def post_export(request):
|
||||
hosts = Host.objects.select_related('hostextend')
|
||||
if not request.user.is_supper:
|
||||
hosts = hosts.filter(id__in=get_host_perms(request.user))
|
||||
wb = Workbook()
|
||||
ws = wb.active
|
||||
ws.append(('主机名称', 'SSH地址', 'SSH端口', 'SSH用户', 'SSH密码', '备注信息', '实例ID', '操作系统', 'CPU核心数', '内存GB', '磁盘GB', '内网IP'
|
||||
'公网IP', '实例计费方式', '网络计费方式', '创建时间', '到期时间'))
|
||||
for item in hosts:
|
||||
data = [item.name, item.hostname, item.port, item.username, '', item.desc]
|
||||
if hasattr(item, 'hostextend'):
|
||||
data.extend([
|
||||
item.hostextend.instance_id,
|
||||
item.hostextend.os_name,
|
||||
item.hostextend.cpu,
|
||||
item.hostextend.memory,
|
||||
','.join(str(x) for x in json.loads(item.hostextend.disk)),
|
||||
','.join(json.loads(item.hostextend.private_ip_address)),
|
||||
','.join(json.loads(item.hostextend.public_ip_address)),
|
||||
item.hostextend.get_instance_charge_type_display(),
|
||||
item.hostextend.get_internet_charge_type_display(),
|
||||
item.hostextend.created_time,
|
||||
item.hostextend.expired_time
|
||||
])
|
||||
ws.append(data)
|
||||
response = HttpResponse(content_type='application/octet-stream')
|
||||
wb.save(response)
|
||||
return response
|
||||
|
||||
|
||||
@auth('host.host.add')
|
||||
def post_parse(request):
|
||||
file = request.FILES['file']
|
||||
|
|
|
@ -86,7 +86,7 @@ export function trimFixed(data, bit) {
|
|||
}
|
||||
|
||||
// 日期
|
||||
export function human_date(date) {
|
||||
export function humanDate(date) {
|
||||
const now = date || new Date();
|
||||
let month = now.getMonth() + 1;
|
||||
let day = now.getDate();
|
||||
|
@ -94,7 +94,7 @@ export function human_date(date) {
|
|||
}
|
||||
|
||||
// 时间
|
||||
export function human_time(date) {
|
||||
export function humanTime(date) {
|
||||
const now = date || new Date();
|
||||
const hour = now.getHours() < 10 ? '0' + now.getHours() : now.getHours();
|
||||
const minute = now.getMinutes() < 10 ? '0' + now.getMinutes() : now.getMinutes();
|
||||
|
@ -102,8 +102,8 @@ export function human_time(date) {
|
|||
return `${hour}:${minute}:${second}`
|
||||
}
|
||||
|
||||
export function human_datetime(date) {
|
||||
return `${human_date(date)} ${human_time(date)}`
|
||||
export function humanDatetime(date) {
|
||||
return `${humanDate(date)} ${humanTime(date)}`
|
||||
}
|
||||
|
||||
// 生成唯一id
|
||||
|
@ -113,3 +113,15 @@ export function uniqueId() {
|
|||
return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16)
|
||||
});
|
||||
}
|
||||
|
||||
export function blobToExcel(data, filename) {
|
||||
const blob = new Blob([data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'});
|
||||
const link = document.createElement('a');
|
||||
link.href = URL.createObjectURL(blob);
|
||||
link.download = filename;
|
||||
document.body.appendChild(link);
|
||||
const evt = document.createEvent("MouseEvents");
|
||||
evt.initEvent("click", false, false);
|
||||
link.dispatchEvent(evt);
|
||||
document.body.removeChild(link);
|
||||
}
|
|
@ -3,17 +3,19 @@
|
|||
* Copyright (c) <spug.dev@gmail.com>
|
||||
* Released under the AGPL-3.0 License.
|
||||
*/
|
||||
import React from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
import { Table, Modal, Dropdown, Button, Menu, Avatar, Tooltip, Space, Tag, Radio, Input, message } from 'antd';
|
||||
import { PlusOutlined, DownOutlined, SyncOutlined, FormOutlined } from '@ant-design/icons';
|
||||
import { PlusOutlined, DownOutlined, SyncOutlined, FormOutlined, ExportOutlined } from '@ant-design/icons';
|
||||
import { Action, TableCard, AuthButton, AuthFragment } from 'components';
|
||||
import IPAddress from './IPAddress';
|
||||
import { http, hasPermission } from 'libs';
|
||||
import { http, hasPermission, blobToExcel, humanDate } from 'libs';
|
||||
import store from './store';
|
||||
import icons from './icons';
|
||||
|
||||
function ComTable() {
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
function handleDelete(text) {
|
||||
Modal.confirm({
|
||||
title: '删除确认',
|
||||
|
@ -38,6 +40,13 @@ function ComTable() {
|
|||
}
|
||||
}
|
||||
|
||||
function handleExport() {
|
||||
setLoading(true)
|
||||
http.post('/api/host/export/', {ids: store.dataSource.map(x => x.id)}, {responseType: 'blob', timeout: 60000})
|
||||
.then(res => blobToExcel(res.data, `${humanDate()}_主机列表.xlsx`))
|
||||
.finally(() => setLoading(false))
|
||||
}
|
||||
|
||||
return (
|
||||
<TableCard
|
||||
tKey="hi"
|
||||
|
@ -80,6 +89,12 @@ function ComTable() {
|
|||
<Button type="primary" icon={<PlusOutlined/>}>新建 <DownOutlined/></Button>
|
||||
</Dropdown>
|
||||
</AuthFragment>,
|
||||
<AuthButton
|
||||
auth="host.host.view"
|
||||
type="primary"
|
||||
loading={loading}
|
||||
icon={<ExportOutlined/>}
|
||||
onClick={handleExport}>导出</AuthButton>,
|
||||
<AuthButton
|
||||
auth="host.host.add"
|
||||
type="primary"
|
||||
|
|
Loading…
Reference in New Issue