3 Commits
v2.11 ... v2.15

Author SHA1 Message Date
RobbieHan
a36f8d74f6 cabinet 2019-01-25 14:34:42 +08:00
RobbieHan
cea6fa7cba celery&flower&supervisor 2019-01-18 16:50:05 +08:00
RobbieHan
eb10ffe9be device scan 2019-01-14 02:12:08 +08:00
12 changed files with 1039 additions and 6 deletions

56
apps/cmdb/tasks.py Normal file
View File

@@ -0,0 +1,56 @@
import time
import logging
from celery import shared_task
from celery_once import QueueOnce
from utils.sandbox_utils import SandboxScan, LoginExecution
from .models import DeviceScanInfo
info_logger = logging.getLogger('sandbox_info')
@shared_task(base=QueueOnce)
def scan_execution():
scan = SandboxScan()
execution = LoginExecution()
scan_type = execution.get_scan_type()
auth_type = execution.get_auth_type()
start_time = time.time()
if scan_type == 'basic_scan':
hosts = scan.basic_scan()
for host in hosts:
DeviceScanInfo.objects.update_or_create(
hostname=host,
)
else:
hosts = scan.os_scan()
login_hosts = [host for host in hosts if host['os'] in ['Linux', 'embedded']]
nologin_hosts = [host for host in hosts if host not in login_hosts]
for host in nologin_hosts:
DeviceScanInfo.objects.update_or_create(
hostname=host['host'],
defaults={
'os_type': host['os']
}
)
for host in login_hosts:
kwargs = {
'hostname': host['host'],
'username': execution.get_ssh_username(),
'port': execution.get_ssh_port(),
'password': execution.get_ssh_password(),
'private_key': execution.get_ssh_private_key()
}
defaults = execution.login_execution(auth_type=auth_type, **kwargs)
DeviceScanInfo.objects.update_or_create(
hostname=host['host'],
defaults=defaults
)
end_time = time.time()
msg = 'Scan task has been completed, execution time: %(time)s, %(num)s hosts are up.' % {
'time': end_time - start_time,
'num': len(hosts)
}
info_logger.info(msg)
return msg

View File

@@ -1,7 +1,7 @@
from django.urls import path
from .views import CmdbView
from . import views_code, views_scan
from . import views_code, views_scan, views_eam
app_name = 'cmdb'
@@ -14,4 +14,17 @@ urlpatterns = [
path('portal/code/delete/', views_code.CodeDeleteView.as_view(), name='portal-code-delete'),
path('portal/scan_config/', views_scan.ScanConfigView.as_view(), name='portal-scan_config'),
path('portal/device_scan/', views_scan.DeviceScanView.as_view(), name='portal-device_scan'),
path('portal/device_scan/list/', views_scan.DeviceScanListView.as_view(), name='portal-device_scan-list'),
path('portal/device_scan/detail/', views_scan.DeviceScanDetailView.as_view(), name='portal-device_scan-detail'),
path('portal/device_scan/delete/', views_scan.DeviceScanDeleteView.as_view(), name='portal-device_scan-delete'),
path('portal/device_scan/exec/', views_scan.DeviceScanExecView.as_view(), name='portal-device_scan-exec'),
path('portal/device_scan/inbound/', views_scan.DeviceScanInboundView.as_view(), name='portal-device_scan-inbound'),
path('eam/cabinet/', views_eam.CabinetView.as_view(), name='eam-cabinet'),
path('eam/cabinet/create/', views_eam.CabinetCreateView.as_view(), name='eam-cabinet-create'),
path('eam/cabinet/update/', views_eam.CabinetUpdateView.as_view(), name='eam-cabinet-update'),
path('eam/cabinet/list/', views_eam.CabinetListView.as_view(), name='eam-cabinet-list'),
path('eam/cabinet/delete/', views_eam.CabinetDeleteView.as_view(), name='eam-cabinet-delete'),
]

38
apps/cmdb/views_eam.py Normal file
View File

@@ -0,0 +1,38 @@
from django.views.generic import TemplateView
from system.mixin import LoginRequiredMixin
from custom import (BreadcrumbMixin, SandboxDeleteView,
SandboxListView, SandboxUpdateView, SandboxCreateView)
from .models import Cabinet
class CabinetView(LoginRequiredMixin, BreadcrumbMixin, TemplateView):
template_name = 'cmdb/cabinet.html'
class CabinetCreateView(SandboxCreateView):
model = Cabinet
fields = '__all__'
class CabinetUpdateView(SandboxUpdateView):
model = Cabinet
fields = '__all__'
class CabinetListView(SandboxListView):
model = Cabinet
fields = ['id', 'number', 'position', 'desc']
def get_filters(self):
data = self.request.GET
filters = {}
if 'number' in data and data['number']:
filters['number__icontains'] = data['number']
if 'position' in data and data['position']:
filters['position__icontains'] = data['position']
return filters
class CabinetDeleteView(SandboxDeleteView):
model = Cabinet

View File

@@ -6,15 +6,19 @@ import ast
import logging
from ruamel import yaml
from django.views.generic import View
from django.views.generic import View, TemplateView
from django.http import JsonResponse
from django.shortcuts import render
from django.shortcuts import render, get_object_or_404
from celery_once import AlreadyQueued
from system.mixin import LoginRequiredMixin
from custom import BreadcrumbMixin
from custom import BreadcrumbMixin, SandboxListView, SandboxDeleteView
from utils.sandbox_utils import ConfigFileMixin
from system.models import Menu
from .models import (DeviceScanInfo, ConnectionInfo, DeviceInfo,
ConnectionAbstract, DeviceAbstract)
from .tasks import scan_execution
error_logger = logging.getLogger('sandbox_error')
@@ -52,3 +56,63 @@ class ScanConfigView(LoginRequiredMixin, BreadcrumbMixin, ConfigFileMixin, View)
error_logger.error(e)
return JsonResponse(ret)
class DeviceScanView(LoginRequiredMixin, BreadcrumbMixin, TemplateView):
template_name = 'cmdb/device_scan.html'
class DeviceScanListView(SandboxListView):
model = DeviceScanInfo
fields = ['id', 'sys_hostname', 'hostname', 'mac_address', 'auth_type', 'status', 'os_type', 'device_type']
class DeviceScanDetailView(LoginRequiredMixin, View):
def get(self, request):
ret = Menu.get_menu_by_request_url(request.path_info)
if 'id' in request.GET and request.GET['id']:
device = get_object_or_404(DeviceScanInfo, pk=int(request.GET['id']))
ret['device'] = device
return render(request, 'cmdb/device_scan_detail.html', ret)
class DeviceScanDeleteView(SandboxDeleteView):
model = DeviceScanInfo
class DeviceScanExecView(LoginRequiredMixin, View):
def get(self, request):
ret = dict(status='fail')
try:
scan_execution.delay()
ret['status'] = 'success'
except AlreadyQueued:
ret['status'] = 'already_queued'
return JsonResponse(ret)
class DeviceScanInboundView(LoginRequiredMixin, View):
def post(self, request):
ret = dict(result=False)
login_succeed = list(DeviceScanInfo.objects.filter(status='succeed').values())
connection_fields = [field.name for field in ConnectionAbstract._meta.fields if field.name is not 'id']
device_fields = [field.name for field in DeviceAbstract._meta.fields if field.name is not 'id']
device_fields.append('hostname')
for host in login_succeed:
connection_defaults = {key: host[key] for key in host.keys() & connection_fields}
device_defaults = {key: host[key] for key in host.keys() & device_fields}
connection_info, _ = ConnectionInfo.objects.update_or_create(
hostname=host['hostname'],
defaults=connection_defaults
)
connection_id = int(getattr(connection_info, 'id'))
device_defaults['dev_connection'] = connection_id
device_defaults['changed_by_id'] = request.user.id
DeviceInfo.objects.update_or_create(
hostname=host['hostname'],
defaults=device_defaults
)
ret['result'] = True
return JsonResponse(ret)

View File

@@ -84,9 +84,9 @@ class SandboxMultipleObjectMixin:
filters = self.get_filters()
fields = self.get_fields()
if filters:
queryset = queryset.filter(**self.filters)
queryset = queryset.filter(**filters)
if fields:
queryset = queryset.values(*self.fields)
queryset = queryset.values(*fields)
record_filter_count = queryset.count()

View File

@@ -0,0 +1,5 @@
from __future__ import absolute_import, unicode_literals
from .celery import app as celery_app
__all__ = ('celery_app')

38
sandboxMP/celery.py Normal file
View File

@@ -0,0 +1,38 @@
from __future__ import absolute_import, unicode_literals
import os
from celery import Celery
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sandboxMP.settings')
app = Celery('sandbox')
app.config_from_object('django.conf:settings')
app.autodiscover_tasks()
BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/1'
CELERY_TIMEZONE = 'Asia/Shanghai'
CELERY_ENABLE_UTC = False
CELERYD_FORCE_EXECV = True
CELERYD_CONCURRENCY = 5
CELERY_ACKS_LATE = True
CELERYD_MAX_TASKS_PER_CHILD = 100
CELERYD_TASK_TIME_LIMIT = 60 * 5
app.conf.ONCE = {
'backend': 'celery_once.backends.Redis',
'settings': {
'url': 'redis://localhost:6379/2',
'default_timeout': 60 * 5
}
}

View File

@@ -13,6 +13,8 @@ https://docs.djangoproject.com/en/2.1/ref/settings/
import os
import sys
from .celery import *
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

276
templates/cmdb/cabinet.html Normal file
View File

@@ -0,0 +1,276 @@
{% extends "base-left.html" %}
{% load staticfiles %}
{% block css %}
<link rel="stylesheet" href="{% static 'plugins/datatables/jquery.dataTables.min.css' %}">
<link rel="stylesheet" href="{% static 'js/plugins/layer/skin/layer.css' %}">
<link rel="stylesheet" href="{% static 'plugins/select2/select2.min.css' %}">
{% endblock %}
{% block content %}
<!-- Main content -->
<section class="content">
<div id="devlist">
<div class="box box-primary" id="liebiao">
<div class="box-header">
<div class="btn-group pull-left">
<button type="button" id="btnRefresh" class="btn btn-default">
<i class="glyphicon glyphicon-repeat"></i>刷新
</button>
</div>
<div class="btn-group pull-left">&nbsp</div>
<div class="btn-group pull-left">
<button type="button" id="btnCreate" class="btn btn-default">
<i class="glyphicon glyphicon-plus"></i>新增
</button>
</div>
<div class="btn-group pull-left">&nbsp</div>
<div class="btn-group pull-left">
<button type="button" id="btnDelete" class="btn btn-default">
<i class="glyphicon glyphicon-trash"></i>删除
</button>
</div>
<div class="pull-right">
<form class="form-inline" id="queryForm">
<div class="form-group searchArea margin-r-5 margin-top-5">
<label>机柜编号</label>
<input type="text" name="number" class="form-control inputText" id="number">
</div>
<div class="form-group searchArea margin-r-5 margin-top-5">
<label>机柜位置</label>
<input type="text" name="position" class="form-control inputText" id="position">
</div>
<button type="button" id="btnSearch" class="btn btn-default">
<i class="glyphicon glyphicon-search"></i>查询
</button>
</form>
</div>
</div>
<div class="box-body">
<table id="dtbList" class="display" cellspacing="0" width="100%">
<thead>
<tr valign="middle">
<th><input type="checkbox" id="checkAll"></th>
<th>ID</th>
<th>机柜编号</th>
<th>机柜位置</th>
<th>备注信息</th>
<th>操作</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<br> <br>
</div>
</div>
</div>
</section>
<!-- /.content -->
{% endblock %}
{% block javascripts %}
<script src="{% static 'plugins/datatables/jquery.dataTables.min.js' %}"></script>
<script src="{% static 'plugins/datatables/dataTables.const-1.js' %}"></script>
<script src="{% static 'js/plugins/layer/layer.js' %}"></script>
<script src="{% static 'plugins/select2/select2.full.min.js' %}"></script>
<script type="text/javascript">
// 菜单选中高亮
$(function () {
$('#CMDB-EAM').addClass('active');
$('#CMDB-EAM-CABINET').addClass('active');
});
// datatables 初始化配置
var oDataTable = null;
$(function () {
oDataTable = initTable();
function initTable() {
var oTable = $('#dtbList').DataTable($.extend(true, {},
DATATABLES_CONSTANT.DATA_TABLES.SERVER_SIDE_OPTION,
{
ajax: {
"url": "{% url 'cmdb:eam-cabinet-list' %}",
"data": function (d) {
d.number = $("#number").val();
d.position = $("#position").val();
}
},
columns: [
DATATABLES_CONSTANT.DATA_TABLES.COLUMN.CHECKBOX,
{
data: "id",
width: "5%",
},
{
data: "number",
//width : "20%",
},
{
data: "position",
//width : "20%",
},
{
data: "desc",
//width : "20%",
},
{
data: "id",
width: "10%",
bSortable: "false",
render: function (data, type, row, meta) {
var ret = "";
var ret = "<button title='详情-修改' onclick='doUpdate("
+ data + ")'><i class='glyphicon glyphicon-pencil'></i></button>";
ret = ret + "<button title='删除' onclick='doDelete("
+ data + ")'><i class='glyphicon glyphicon-trash'></i></button>";
return ret;
}
}],
}));
return oTable;
}
});
// 刷新数据
$("#btnRefresh").click(function () {
oDataTable.ajax.reload();
});
//新建数据
$("#btnCreate").click(function () {
layer.open({
type: 2,
title: '新增',
shadeClose: false,
maxmin: true,
area: ['800px', '400px'],
content: "{% url 'cmdb:eam-cabinet-create' %}",
end: function () {
//关闭时做的事情
oDataTable.ajax.reload();
}
});
});
//修改数据
function doUpdate(id) {
layer.open({
type: 2,
title: '编辑',
shadeClose: false,
maxmin: true,
area: ['800px', '400px'],
content: ["{% url 'cmdb:eam-cabinet-update' %}" + '?id=' + id, 'no'],
end: function () {
oDataTable.ajax.reload();
}
});
}
//checkbox全选
$("#checkAll").on("click", function () {
if ($(this).prop("checked") === true) {
$("input[name='checkList']").prop("checked", $(this).prop("checked"));
$('#example tbody tr').addClass('selected');
} else {
$("input[name='checkList']").prop("checked", false);
$('#example tbody tr').removeClass('selected');
}
});
//批量删除
$("#btnDelete").click(function () {
if ($("input[name='checkList']:checked").length == 0) {
layer.msg("请选择要删除的记录");
return;
}
var arrId = new Array();
$("input[name='checkList']:checked").each(function () {
//alert($(this).val());
arrId.push($(this).val());
});
sId = arrId.join(',');
layer.alert('确定删除吗?', {
title: '提示'
, icon: 3 //0:感叹号 1对号 2差号 3问号 4小锁 5哭脸 6笑脸
, time: 0 //不自动关闭
, btn: ['YES', 'NO']
, yes: function (index) {
layer.close(index);
$.ajax({
type: "POST",
url: "{% url 'cmdb:eam-cabinet-delete' %}",
data: {"id": sId, csrfmiddlewaretoken: '{{ csrf_token }}'},
cache: false,
success: function (msg) {
if (msg.result) {
layer.alert("操作成功", {icon: 1});
oDataTable.ajax.reload();
} else {
//alert(msg.message);
layer.alert("操作失败", {icon: 2});
}
return;
}
});
}
});
});
//删除单个数据
function doDelete(id) {
layer.alert('确定删除吗?', {
title: '提示'
, icon: 3 //0:感叹号 1对号 2差号 3问号 4小锁 5哭脸 6笑脸
, time: 0 //不自动关闭
, btn: ['YES', 'NO']
, yes: function (index) {
layer.close(index);
$.ajax({
type: "POST",
url: "{% url 'cmdb:eam-cabinet-delete' %}",
data: {"id": id, csrfmiddlewaretoken: '{{ csrf_token }}'},
cache: false,
success: function (msg) {
if (msg.result) {
layer.alert('删除成功', {icon: 1});
oDataTable.ajax.reload();
} else {
//alert(msg.message);
layer.alert('删除失败', {icon: 2});
}
return;
}
});
}
});
}
//select2
$(function () {
//Initialize Select2 Elements
$(".select2").select2();
});
$("#btnSearch").click(function(){
oDataTable.ajax.reload();
});
</script>
{% endblock %}

View File

@@ -0,0 +1,99 @@
{% extends 'base-layer.html' %}
{% load staticfiles %}
{% block css %}
<link rel="stylesheet" href="{% static 'plugins/select2/select2.min.css' %}">
<!-- iCheck for checkboxes and radio inputs -->
{% endblock %}
{% block main %}
<div class="box box-danger">
<form class="form-horizontal" id="addForm" method="post">
<input type="hidden" name='id' value="{{ cabinet.id }}" />
{% csrf_token %}
<div class="box-body">
<fieldset>
<legend>
<h4>机柜信息</h4>
</legend>
<div class="form-group has-feedback">
<label class="col-sm-2 control-label">机柜编号</label>
<div class="col-sm-3">
<input class="form-control" name="number" type="text" value="{{ cabinet.number }}"/>
</div>
<label class="col-sm-2 control-label">机柜位置</label>
<div class="col-sm-3">
<input class="form-control" name="position" type="text" value="{{ cabinet.position }}"/>
</div>
</div>
<div class="form-group has-feedback">
<label class="col-sm-2 control-label">描述信息</label>
<div class="col-sm-8">
<input class="form-control" id="desc" name="desc" type="text" value="{{ cabinet.desc }}"/>
</div>
</div>
</fieldset>
</div>
<div class="box-footer ">
<div class="row span7 text-center ">
<button type="button" id="btnCancel" class="btn btn-default margin-right ">重置</button>
<button type="button" id="btnSave" class="btn btn-info margin-right ">保存</button>
</div>
</div>
</form>
</div>
{% endblock %}
{% block javascripts %}
<script src="{% static 'plugins/select2/select2.full.min.js' %}"></script>
<script type="text/javascript">
function getUrl() {
if ($("input[name='id']").val()) {
var url = "{% url 'cmdb:eam-cabinet-update' %}";
} else {
var url = "{% url 'cmdb:eam-cabinet-create' %}";
}
return url
}
$("#btnSave").click(function () {
var data = $("#addForm").serialize();
$.ajax({
type: $("#addForm").attr('method'),
url: getUrl(),
data: data,
cache: false,
success: function (msg) {
if (msg.result) {
layer.alert('数据保存成功!', {icon: 1}, function (index) {
parent.layer.closeAll(); //关闭所有弹窗
});
} else {
layer.alert(msg.error, {icon: 5});
//$('errorMessage').html(msg.message)
}
return;
}
});
});
/*点取消刷新新页面*/
$("#btnCancel").click(function () {
window.location.reload();
});
$(function () {
//Initialize Select2 Elements
$(".select2").select2();
});
</script>
{% endblock %}

View File

@@ -0,0 +1,329 @@
{% extends "base-left.html" %}
{% load staticfiles %}
{% block css %}
<link rel="stylesheet" href="{% static 'plugins/datatables/jquery.dataTables.min.css' %}">
<link rel="stylesheet" href="{% static 'js/plugins/layer/skin/layer.css' %}">
<link rel="stylesheet" href="{% static 'plugins/select2/select2.min.css' %}">
{% endblock %}
{% block content %}
<!-- Main content -->
<section class="content">
<div id="devlist">
<div class="box box-primary" id="liebiao">
<div class="box-header">
<div class="btn-group pull-left">
<button type="button" id="btnRefresh" class="btn btn-default">
<i class="glyphicon glyphicon-repeat"></i> 刷新
</button>
</div>
<div class="btn-group pull-left">&nbsp</div>
<div class="btn-group pull-left">
<button type="button" id="btnScan" class="btn btn-default" onclick="doScan()">
<i class="glyphicon glyphicon-search"></i> 执行扫描
</button>
</div>
<div class="btn-group pull-left">&nbsp</div>
<div class="btn-group pull-left">
<button type="button" id="btnInbound" class="btn btn-default" onclick="doInbound()">
<i class="glyphicon glyphicon-floppy-disk"></i> 执行入库
</button>
</div>
<div class="btn-group pull-left">&nbsp</div>
<div class="btn-group pull-left">
<button type="button" id="btnDelete" class="btn btn-default">
<i class="glyphicon glyphicon-trash"></i> 删除
</button>
</div>
</div>
<div class="box-body">
<table id="dtbList" class="display" cellspacing="0" width="100%">
<thead>
<tr valign="middle">
<th><input type="checkbox" id="checkAll"></th>
<th>ID</th>
<th>主机名</th>
<th>IP地址</th>
<th>MAC地址</th>
<th>认证类型</th>
<th>登陆状态</th>
<th>系统类型</th>
<th>设备类型</th>
<th>操作</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<br>
<small>点击执行入库可将扫描结果中登陆状态为成功succeed的设备数据导入正式设备管理数据库</small>
</div>
</div>
</div>
</section>
<!-- /.content -->
{% endblock %}
{% block javascripts %}
<script src="{% static 'plugins/datatables/jquery.dataTables.min.js' %}"></script>
<script src="{% static 'plugins/datatables/dataTables.const-1.js' %}"></script>
<script src="{% static 'js/plugins/layer/layer.js' %}"></script>
<script src="{% static 'plugins/select2/select2.full.min.js' %}"></script>
<script type="text/javascript">
// 菜单选中高亮
$(function () {
$('#CMDB-PORTAL').addClass('active');
$('#CDMB-PORTAL-DEVICE_SCAN').addClass('active');
});
// datatables 初始化配置
var oDataTable = null;
$(function () {
oDataTable = initTable();
function initTable() {
var oTable = $('#dtbList').DataTable($.extend(true, {},
DATATABLES_CONSTANT.DATA_TABLES.SERVER_SIDE_OPTION,
{
ajax: {
"url": "{% url 'cmdb:portal-device_scan-list' %}",
},
columns: [
DATATABLES_CONSTANT.DATA_TABLES.COLUMN.CHECKBOX,
{
data: "id",
width: "5%",
},
{
data: "sys_hostname",
//width : "20%",
},
{
data: "hostname",
//width : "20%",
},
{
data: "mac_address",
//width : "20%",
},
{
data: "auth_type",
//width : "20%",
},
{
data: "status",
render: function (data, type, row, meta) {
if (data == "succeed") {
var ret = "<button class='btn btn-info btn-xs'>成功</button>";
return ret;
}
if (data == "failed") {
var ret = "<button class='btn btn-danger btn-xs'>失败</button>";
return ret;
}
else {
var ret = "<button class='btn btn-default btn-xs'>未知</button>";
return ret;
}
}
},
{
data: "os_type",
//width : "20%",
},
{
data: "device_type",
//width : "20%",
},
{
data: "id",
width: "10%",
bSortable: "false",
render: function (data, type, row, meta) {
var ret = "";
var ret = "<button title='详情' onclick='doDetail("
+ data + ")'><i class='glyphicon glyphicon-list-alt'></i></button>";
ret = ret + "<button title='删除' onclick='doDelete("
+ data + ")'><i class='glyphicon glyphicon-trash'></i></button>";
return ret;
}
}],
}));
return oTable;
}
});
// 刷新数据
$("#btnRefresh").click(function () {
oDataTable.ajax.reload();
});
function doDetail(id){
window.location.href="/cmdb/portal/device_scan/detail/?id="+id;
}
//checkbox全选
$("#checkAll").on("click", function () {
if ($(this).prop("checked") === true) {
$("input[name='checkList']").prop("checked", $(this).prop("checked"));
$('#example tbody tr').addClass('selected');
} else {
$("input[name='checkList']").prop("checked", false);
$('#example tbody tr').removeClass('selected');
}
});
//批量删除
$("#btnDelete").click(function () {
if ($("input[name='checkList']:checked").length == 0) {
layer.msg("请选择要删除的记录");
return;
}
var arrId = new Array();
$("input[name='checkList']:checked").each(function () {
//alert($(this).val());
arrId.push($(this).val());
});
sId = arrId.join(',');
layer.alert('确定删除吗?', {
title: '提示'
, icon: 3 //0:感叹号 1对号 2差号 3问号 4小锁 5哭脸 6笑脸
, time: 0 //不自动关闭
, btn: ['YES', 'NO']
, yes: function (index) {
layer.close(index);
$.ajax({
type: "POST",
url: "{% url 'cmdb:portal-device_scan-delete' %}",
data: {"id": sId, csrfmiddlewaretoken: '{{ csrf_token }}'},
cache: false,
success: function (msg) {
if (msg.result) {
layer.alert("操作成功", {icon: 1});
oDataTable.ajax.reload();
} else {
//alert(msg.message);
layer.alert("操作失败", {icon: 2});
}
return;
}
});
}
});
});
//删除单个数据
function doDelete(id) {
layer.alert('确定删除吗?', {
title: '提示'
, icon: 3 //0:感叹号 1对号 2差号 3问号 4小锁 5哭脸 6笑脸
, time: 0 //不自动关闭
, btn: ['YES', 'NO']
, yes: function (index) {
layer.close(index);
$.ajax({
type: "POST",
url: "{% url 'cmdb:portal-device_scan-delete' %}",
data: {"id": id, csrfmiddlewaretoken: '{{ csrf_token }}'},
cache: false,
success: function (msg) {
if (msg.result) {
layer.alert('删除成功', {icon: 1});
oDataTable.ajax.reload();
} else {
//alert(msg.message);
layer.alert('删除失败', {icon: 2});
}
return;
}
});
}
});
}
//资产扫描
function doScan() {
layer.alert('确定开始扫描吗?', {
title: '提示'
, icon: 3 //0:感叹号 1对号 2差号 3问号 4小锁 5哭脸 6笑脸
, time: 0 //不自动关闭
, btn: ['YES', 'NO']
, yes: function (index) {
layer.close(index);
$.ajax({
type: "GET",
url: "{% url 'cmdb:portal-device_scan-exec' %}",
cache: false,
beforeSend:function(){
this.layerIndex = layer.load(2, {
shade: [0.1,'#fff']
});
},
success: function (msg) {
layer.closeAll('loading');
if (msg.status == 'success') {
layer.alert('扫描任务已下发', {icon: 1});
oDataTable.ajax.reload();
}
else if (msg.status == 'already_queued') {
layer.alert('当前已有扫描任务正在执行', {icon: 4});
oDataTable.ajax.reload();
}
else {
//alert(msg.message);
layer.alert('扫描失败', {icon: 2});
}
return;
}
});
}
});
}
function doInbound() {
layer.alert('确定将扫描结果导入设备管理库吗?', {
title: '提示'
, icon: 3
, time: 0
, btn: ['YES', 'NO']
, yes: function (index) {
layer.close(index);
$.ajax({
type: "POST",
url: "{% url 'cmdb:portal-device_scan-inbound' %}",
data: {csrfmiddlewaretoken: '{{ csrf_token }}'},
cache: false,
success: function (msg) {
if (msg.result) {
layer.alert('设备已入库', {icon: 1});
}
else {
//alert(msg.message);
layer.alert('设备入库失败', {icon: 2});
}
return;
}
});
}
});
}
</script>
{% endblock %}

View File

@@ -0,0 +1,113 @@
{% extends "base-left.html" %}
{% load staticfiles %}
{% block css %}
<link rel="stylesheet" href="{% static 'js/plugins/layer/skin/layer.css' %}">
{% endblock %}
{% block content %}
<!-- Main content -->
<section class="content">
<div class="row">
<div class="col-md-12">
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">设备详情</h3>
<div class="box-tools">
<button type="button" class="btn btn-box-tool" data-widget="collapse"><i
class="fa fa-minus"></i>
</button>
</div>
</div>
<div class="box-body no-padding">
<div class="btn-group pull-right margin">
<button type="button" class="btn btn-primary btn-xs margin-r-5" title="返回" id="btnReturn">
<i class="fa fa-undo"> 返回</i>
</button>
</div>
</div>
<div class="table-responsive mailbox-messages">
<table class="table" id="tbWorkList" style="white-space: nowrap;">
<tbody>
<tr class="info">
<td width="10%"><strong>主机名</strong></td>
<td class="text-left">{{ device.sys_hostname }}</td>
<td width="10%"><strong>SN编号</strong></td>
<td class="text-left">{{ device.sn_number }}</td>
</tr>
<tr>
<td><strong>SSH用户名</strong></td>
<td>{{ device.username }}</td>
<td><strong>SSH端口</strong></td>
<td>{{ device.port }}</td>
</tr>
<tr class="info">
<td><strong>认证类型</strong></td>
<td>{{ device.auth_type }}</td>
<td><strong>登陆状态</strong></td>
<td>{{ device.status }}</td>
</tr>
<tr>
<td><strong>IP地址</strong></td>
<td>{{ device.hostname }}</td>
<td><strong>MAC地址</strong></td>
<td>{{ device.mac_address }}</td>
</tr>
<tr class="info">
<td><strong>系统类型</strong></td>
<td>{{ device.os_type }}</td>
<td><strong>设备类型</strong></td>
<td>{{ device.device_type }}</td>
</tr>
<tr>
<td><strong>入库时间</strong></td>
<td>{{ device.add_time }}</td>
<td><strong>变更时间</strong></td>
<td>{{ device.modify_time }}</td>
</tr>
<tr class="info">
<td><strong>错误信息</strong></td>
<td colspan="3">{{ device.error_message }}</td>
</tr>
</tbody>
</table>
</div>
<br>
<div class="box-footer margin-b-10">
<small>该设备信息为自动扫描入库设备不提供修改功能可通过管理页面执行入库按钮将登陆状态为成功succeed的设备迁移到正式设备管理库</small>
</div>
<!-- /.box-footer -->
</div>
<!-- /.box-body -->
</div>
</div>
<!-- /.col -->
<!-- TO DO List -->
</section>
<!-- /.content -->
{% endblock %}
{% block javascripts %}
<script src="{% static 'js/plugins/layer/layer.js' %}"></script>
<script src="{% static 'plugins/masonry/masonry.js' %}"></script>
<script type="text/javascript">
$(function () {
$('#CMDB-PORTAL').addClass('active');
$('#CDMB-PORTAL-DEVICE_SCAN').addClass('active');
});
//返回
$("#btnReturn").click(function () {
history.back();
});
</script>
{% endblock %}