pull/6/head
halcyon 2015-02-09 19:02:25 +08:00
parent 433974d77d
commit c84f124511
21 changed files with 732 additions and 139 deletions

View File

@ -143,9 +143,6 @@ def log_record(username, host):
log_file_path = os.path.join(today_connect_log_dir, log_filename)
pid = os.getpid()
user = get_object(User, username=username)
asset = get_object(Asset, ip=host)
if not os.path.isdir(today_connect_log_dir):
try:
os.makedirs(today_connect_log_dir)
@ -158,7 +155,7 @@ def log_record(username, host):
except IOError:
raise ServerError('Create logfile failed, Please modify %s permission.' % today_connect_log_dir)
log = Log(user=user, asset=asset, log_path=log_file_path, start_time=datetime.now(), pid=pid)
log = Log(user=username, host=host, log_path=log_file_path, start_time=datetime.now(), pid=pid)
log.save()
return log_file, log
@ -203,6 +200,7 @@ def posix_shell(chan, username, host):
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
log_file.close()
log.is_finished = True
log.log_finished = False
log.end_time = datetime.now()
log.save()

View File

@ -7,13 +7,14 @@ urlpatterns = patterns('',
url(r'^host_add/$', add_host),
url(r"^host_add_multi/$", add_host_multi),
url(r'^host_list/$', list_host),
url(r'^search/$', host_search),
url(r"^(\d+.\d+.\d+.\d+)/$", jlist_ip),
url(r'^idc_add/$', add_idc),
url(r'^idc_list/$', list_idc),
url(r'^idc_detail/(\d+)$', detail_idc),
url(r'^idc_del/(\d+)/$', del_idc),
url(r'^group_add/$', add_group),
url(r'^group_edit/(\d+)/$', edit_group),
url(r'^group_edit/$', edit_group),
url(r'^group_list/$', list_group),
url(r'^group_detail/(\d+)/$', detail_group),
url(r'^group_del_host/(\w+)/$', group_del_host),

View File

@ -1,13 +1,15 @@
# coding:utf-8
from django.db.models import Q
from django.http import HttpResponseRedirect
from django.template import RequestContext
from django.shortcuts import render_to_response
from django.core.paginator import Paginator, EmptyPage
from django.core.paginator import Paginator, EmptyPage, InvalidPage
from models import IDC, Asset, BisGroup
from juser.models import UserGroup
from connect import PyCrypt, KEY
from jumpserver.views import jasset_group_add, jasset_host_edit
from jumpserver.views import jasset_group_add, jasset_host_edit, pages
cryptor = PyCrypt(KEY)
@ -86,13 +88,13 @@ def add_host_multi(request):
for host in multi_hosts:
if host == '':
break
j_ip, j_port, j_type, j_idc, j_groups, j_user_group, j_active, j_comment = host.split()
j_ip, j_port, j_type, j_idc, j_groups, j_active, j_comment = host.split()
j_type = login_types[j_type]
j_groups = j_groups.split(',')
for group in j_groups:
g = group.strip('[]').encode('utf-8').strip()
j_group.append(g)
print j_group,type(j_group)
if Asset.objects.filter(ip=str(j_ip)):
emg = u'该IP %s 已存在!' %j_ip
return render_to_response('jasset/host_add_multi.html', locals(), context_instance=RequestContext(request))
@ -141,7 +143,6 @@ def list_host(request):
header_title, path1, path2 = u'查看主机 | List Host', u'资产管理', u'查看主机'
login_types = {'L': 'LDAP', 'S': 'SSH_KEY', 'P': 'PASSWORD', 'M': 'MAP'}
posts = contact_list = Asset.objects.all().order_by('ip')
print posts
p = paginator = Paginator(contact_list, 20)
try:
page = int(request.GET.get('page', '1'))
@ -285,9 +286,10 @@ def list_group(request):
return render_to_response('jasset/group_list.html', locals(), context_instance=RequestContext(request))
def edit_group(request, offset):
def edit_group(request):
header_title, path1, path2 = u'编辑主机组 | Edit Group', u'资产管理', u'编辑主机组'
group = BisGroup.objects.get(id=offset)
group_id = request.GET.get('id')
group = BisGroup.objects.get(id=group_id)
all = Asset.objects.all()
eposts = contact_list = Asset.objects.filter(bis_group=group).order_by('ip')
posts = [g for g in all if g not in eposts]
@ -296,13 +298,13 @@ def edit_group(request, offset):
j_hosts = request.POST.getlist('j_hosts')
j_comment = request.POST.get('j_comment')
group = BisGroup.objects.get(name=j_group)
group.asset_set.clear()
for host in j_hosts:
g = Asset.objects.get(id=host)
group.asset_set.add(g)
BisGroup.objects.filter(id=group_id).update(name=j_group, comment=j_comment)
smg = u'主机组%s修改成功' %j_group
return HttpResponseRedirect('/jasset/group_detail/%s' %offset)
return HttpResponseRedirect('/jasset/group_detail/%s' % group_id)
return render_to_response('jasset/group_add.html', locals(), context_instance=RequestContext(request))
@ -371,5 +373,17 @@ def group_del(request, offset):
return HttpResponseRedirect('/jasset/group_list/')
def host_search(request):
keyword = request.GET.get('keyword')
login_types = {'L': 'LDAP', 'S': 'SSH_KEY', 'P': 'PASSWORD', 'M': 'MAP'}
posts = Asset.objects.filter(Q(ip__contains=keyword) | Q(idc__name__contains=keyword) |
Q(bis_group__name__contains=keyword) | Q(comment__contains=keyword)).distinct().order_by('ip')
print posts
contact_list, p, contacts = pages(posts, request)
print contact_list, p, contacts
return render_to_response('jasset/host_search.html', locals(), context_instance=RequestContext(request))
def test(request):
return render_to_response('jasset/test.html', locals())

View File

@ -1,16 +1,14 @@
from django.db import models
from juser.models import User
from jasset.models import Asset
class Log(models.Model):
user = models.ForeignKey(User)
asset = models.ForeignKey(Asset)
user = models.CharField(max_length=20, null=True)
host = models.CharField(max_length=20, null=True)
log_path = models.CharField(max_length=100)
start_time = models.DateTimeField(null=True)
pid = models.IntegerField(max_length=10)
is_finished = models.BooleanField(default=False)
log_finished = models.BooleanField(default=False)
end_time = models.DateTimeField(null=True)
def __unicode__(self):

View File

@ -3,7 +3,10 @@ from django.conf.urls import patterns, include, url
from jlog.views import *
urlpatterns = patterns('',
url(r'^$', jlog_list),
url(r'^log_list/(\w+)/$', jlog_list),
url(r'^log_kill/(\d+)', jlog_kill),
)
url(r'^$', log_list_online),
url(r'^log_list/online/$', log_list_online),
url(r'^log_list/offline/$', log_list_offline),
url(r'^log_kill/(\d+)', log_kill),
url(r'^history/$', log_history),
url(r'^search/$', log_search),
)

View File

@ -2,30 +2,68 @@
import os
import ConfigParser
from datetime import datetime
from django.db.models import Q
from django.http import HttpResponse
from django.http import HttpResponseRedirect
from django.template import RequestContext
from django.shortcuts import render_to_response
from django.core.paginator import Paginator, EmptyPage
from connect import BASE_DIR
from jlog.models import Log
from jumpserver.views import pages
CONF = ConfigParser.ConfigParser()
CONF.read('%s/jumpserver.conf' % BASE_DIR)
def jlog_list(request, offset='online'):
header_title, path1, path2 = u'查看日志 | Log List.', u'查看日志', u'日志列表'
def log_list_online(request):
header_title, path1, path2 = u'查看日志 | Log List.', u'查看日志', u'在线用户'
web_socket_host = CONF.get('websocket', 'web_socket_host')
online = Log.objects.filter(is_finished=0)
offline = Log.objects.filter(is_finished=1)
posts = Log.objects.filter(is_finished=0).order_by('-start_time')
contact_list, p, contacts = pages(posts, request)
return render_to_response('jlog/log_list.html', locals())
return render_to_response('jlog/log_online.html', locals())
def jlog_kill(request, offset):
def log_list_offline(request):
header_title, path1, path2 = u'查看日志 | Log List.', u'查看日志', u'历史记录'
web_socket_host = CONF.get('websocket', 'web_socket_host')
posts = Log.objects.filter(is_finished=1).order_by('-start_time')
contact_list, p, contacts = pages(posts, request)
return render_to_response('jlog/log_offline.html', locals())
def log_kill(request, offset):
pid = offset
if pid:
os.kill(int(pid), 9)
Log.objects.filter(pid=pid).update(is_finished=1, end_time=datetime.now())
return HttpResponseRedirect('jlog/log_list.html', locals())
return HttpResponseRedirect('jlog/log_offline.html', locals())
def log_history(request):
if request.method == 'GET':
id = request.GET.get('id', 0)
log = Log.objects.get(id=int(id))
if log:
log_his = "%s.his" % log.log_path
if os.path.isfile(log_his):
f = open(log_his)
content = f.read()
return HttpResponse(content)
def log_search(request):
keyword = request.GET.get('keyword')
env = request.GET.get('env')
if env == 'online':
posts = contact_list = Log.objects.filter(Q(user__contains=keyword) | Q(host__contains=keyword)) \
.filter(is_finished=0).order_by('-start_time')
contact_list, p, contacts = pages(posts, request)
elif env == 'offline':
posts = contact_list = Log.objects.filter(Q(user__contains=keyword) | Q(host__contains=keyword)) \
.filter(is_finished=1).order_by('-start_time')
contact_list, p, contacts = pages(posts, request)
return render_to_response('jlog/log_search.html', locals())

View File

@ -101,5 +101,9 @@ def filter_private(group):
for g in group:
if not pattern.match(g.name):
agroup.append(g)
agroup.remove(p)
try:
agroup.remove(p)
except ValueError:
pass
return agroup

View File

@ -2,12 +2,11 @@
import hashlib
from django.http import HttpResponse
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect
from django.core.paginator import Paginator, EmptyPage, InvalidPage
from juser.models import User
from connect import PyCrypt, KEY
from jasset.models import Asset, BisGroup, IDC
@ -45,7 +44,6 @@ def jasset_host_edit(j_id, j_ip, j_idc, j_port, j_type, j_group, j_active, j_com
print j_idc
print
a = Asset.objects.get(id=j_id)
print '123'
if j_type == 'M':
a.ip = j_ip
a.port = j_port
@ -67,6 +65,22 @@ def jasset_host_edit(j_id, j_ip, j_idc, j_port, j_type, j_group, j_active, j_com
a.save()
def pages(posts, r):
contact_list = posts
p = paginator = Paginator(contact_list, 10)
try:
page = int(r.GET.get('page', '1'))
except ValueError:
page = 1
try:
contacts = paginator.page(page)
except (EmptyPage, InvalidPage):
contacts = paginator.page(paginator.num_pages)
return contact_list, p, contacts
def login(request):
"""登录界面"""
if request.session.get('username'):

View File

@ -2,11 +2,10 @@
#coding: utf-8
import os
import sys
import time
import psutil
from datetime import datetime
cur_dir = os.path.dirname(__file__)
sys.path.append('%s/webroot/AutoSa/' % cur_dir)
os.environ['DJANGO_SETTINGS_MODULE'] = 'jumpserver.settings'
import django
@ -14,28 +13,24 @@ django.setup()
from jlog.models import Log
def log_hanler(pid):
log = Log.objects.filter(id=pid)
def log_hanler(id):
log = Log.objects.get(id=id)
if log:
log = log[0]
filename = log.logfile
filename = log.log_path
if os.path.isfile(filename):
ret1 = os.system('cat %s | grep "DateTime" > %s.his' % (filename, filename))
ret2 = os.system('cat %s | grep "\[.*@.*\][\$\#]" >> %s.his' % (filename, filename))
ret3 = os.system('cat %s | grep "EndTime" >> %s.his' % (filename, filename))
if (ret1 + ret2 + ret3) == 0:
print 'Handler %s ok.' % filename
log.log_finished = True
log.save()
def set_finish(id):
logs = Log.objects.filter(id=id, finish=0)
if logs:
structtime_start = time.localtime()
timestamp_end = int(time.mktime(structtime_start))
log = logs[0]
log.finish = 1
log.end_time = timestamp_end
log.save()
log = Log.objects.filter(id=id)
if log:
log.update(is_finished=1, end_time=datetime.now())
def kill_pid(pid):
@ -45,52 +40,37 @@ def kill_pid(pid):
pass
def pid_exist(pid):
pid_dir = "/proc/%s" % pid
if os.path.isdir(pid_dir):
return True
else:
return False
def del_pid(pid_id):
pid = Pid.objects.filter(id=pid_id)
if pid:
pid[0].delete()
def get_pids():
pids = []
pids_obj = Pid.objects.all()
for pid_obj in pids_obj:
pids.append((pid_obj.id, pid_obj.ppid, pid_obj.cpid, pid_obj.pid, pid_obj.start_time))
return pids
pids1, pids2 = [], []
pids1_obj = Log.objects.filter(is_finished=0)
pids2_obj = Log.objects.filter(is_finished=1, log_finished=0)
for pid_obj in pids1_obj:
pids1.append((pid_obj.id, pid_obj.pid, pid_obj.log_path, pid_obj.is_finished, pid_obj.log_finished, pid_obj.start_time))
for pid_obj in pids2_obj:
pids2.append(pid_obj.id)
return pids1, pids2
def run():
for pid_id, ppid, cpid, pid, start_time in get_pids():
if pid_exist(cpid):
if pid_exist(ppid):
structtime_start = time.localtime()
timestamp_end = int(time.mktime(structtime_start))
if timestamp_end - start_time > 7200:
kill_pid(ppid)
kill_pid(cpid)
del_pid(pid_id)
set_finish(pid)
log_hanler(pid)
else:
kill_pid(cpid)
del_pid(pid_id)
set_finish(pid)
log_hanler(pid)
else:
del_pid(pid_id)
set_finish(pid)
log_hanler(pid)
pids1, pids2 = get_pids()
for pid_id in pids2:
log_hanler(pid_id)
for pid_id, pid, log_path, is_finished, log_finished, start_time in pids1:
print pid_id, start_time, type(start_time)
try:
file_time = int(os.stat(log_path).st_ctime)
now_time = int(time.time())
if now_time - file_time > 18000:
if psutil.pid_exists(pid):
kill_pid(pid)
set_finish(pid_id)
log_hanler(pid_id)
except OSError:
pass
if __name__ == '__main__':
while True:
run()
time.sleep(0.5)
time.sleep(5)

View File

@ -90,16 +90,4 @@ function selectAll(){
}
function move(from, to) {
$("#"+from+" option").each(function(){
if ( $(this).prop("selected") == true ) {
$("#"+to).append(this);
}
});
}
function move_all(from, to){
$("#"+from).children().each(function(){
$("#"+to).append(this);
});
}

View File

@ -24,7 +24,7 @@
{% endif %}
<form id="assetForm" method="post" class="form-horizontal">
<div class="form-group"><label class="col-sm-2 control-label"> 主机组名 </label>
<div class="col-sm-8"><input type="text" value="{{ group.name }}" placeholder="网站" name="j_group" class="form-control"></div>
<div class="col-sm-8" name="group_id" value="{{ post.id }}"><input type="text" value="{{ group.name }}" placeholder="网站" name="j_group" class="form-control"></div>
</div>
<div class="hr-line-dashed"></div>

View File

@ -92,21 +92,21 @@
<div class="col-sm-8">
<select id="j_group" name="j_group" class="form-control m-b" multiple size="10">
{% for g in egroup %}
<option type="checkbox" value="{{ g.name }}">{{ g.name }} --- {{ g.comment }}</option>
<option type="checkbox" value="{{ g.name }}">{{ g.name }} {% if g.comment %} --- {{ g.comment }} {% endif %}</option>
{% endfor %}
</select>
</div>
</div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<label for="j_group" class="col-sm-2 control-label"> 所属用户组<span class="red-fonts">*</span> </label>
<div class="col-sm-8">
{% for g in eusergroup %}
<label class="checkbox-inline"><input type="checkbox" id="j_usergroup" value="{{ g }}" name="j_usergroup"> {{ g }} </label>
{% endfor %}
</div>
</div>
<!--<div class="hr-line-dashed"></div>-->
<!--<div class="form-group">-->
<!--<label for="j_group" class="col-sm-2 control-label"> 所属用户组<span class="red-fonts">*</span> </label>-->
<!--<div class="col-sm-8">-->
<!--{% for g in eusergroup %}-->
<!--<label class="checkbox-inline"><input type="checkbox" id="j_usergroup" value="{{ g }}" name="j_usergroup"> {{ g }} </label>-->
<!--{% endfor %}-->
<!--</div>-->
<!--</div>-->
<div class="hr-line-dashed"></div>
<div class="form-group"><label class="col-sm-2 control-label"> 是否激活<span class="red-fonts">*</span> </label>

View File

@ -44,7 +44,7 @@
{% endif %}
<h4>按照文本框内主机信息格式填写, 多台主机回车换行</h4>
<form id="assetMulti" method="post" class="form-horizontal">
<div><textarea id="j_multi" name="j_multi" type="text" placeholder="192.168.1.1 22 LDAP 北京联通 [网站,数据库] admin 1 网站服务器" class="form-control" style="width:700px;height:500px"></textarea></div>
<div><textarea id="j_multi" name="j_multi" type="text" placeholder="192.168.1.1 22 LDAP 北京联通 [网站,数据库] 1 网站服务器" class="form-control" style="width:700px;height:500px"></textarea></div>
<div class="hr-line-dashed"></div>
<div class="form-group">
<div class="col-sm-4 col-sm-offset-4">

View File

@ -29,8 +29,19 @@
</div>
<div class="ibox-content">
<div class="">
<a target="_blank" href="/jasset/host_add" class="btn btn-sm btn-primary "> 添加 </a>
<div>
<a target="_blank" href="/jasset/host_add" class="btn btn-sm btn-primary "> 添加 </a>
<form id="search_form" method="get" action="" class="pull-right mail-search">
<div class="input-group">
<input type="text" class="form-control input-sm" id="search_input" name="keyword" placeholder="Search">
<input type="text" style="display: none">
<div class="input-group-btn">
<button id='search_btn' type="button" class="btn btn-sm btn-primary" onclick="host_search()">
Search
</button>
</div>
</div>
</form>
</div>
<form id="contents_form" name="contents_form">
@ -125,27 +136,46 @@
}
}
function del(form) {
var checkboxes = document.getElementById(form);
var id_list = {};
var j = 0;
for (var i = 0; i < checkboxes.elements.length; i++) {
if (checkboxes.elements[i].type == "checkbox" && checkboxes.elements[i].checked == true && checkboxes.elements[i].value != "checkall") {
id_list[j] = checkboxes.elements[i].value;
j++;
}
}
if (confirm("确定删除")) {
$.ajax({
type: "POST",
url: "/jasset/host_del/multi/",
data: {"id_list": id_list, "len_list": j},
success: function (data) {
window.open("/jasset/host_list/", "_self");
}
});
function del(form) {
var checkboxes = document.getElementById(form);
var id_list = {};
var j = 0;
for (var i = 0; i < checkboxes.elements.length; i++) {
if (checkboxes.elements[i].type == "checkbox" && checkboxes.elements[i].checked == true && checkboxes.elements[i].value != "checkall") {
id_list[j] = checkboxes.elements[i].value;
j++;
}
}
if (confirm("确定删除")) {
$.ajax({
type: "POST",
url: "/jasset/host_del/multi/",
data: {"id_list": id_list, "len_list": j},
success: function (data) {
window.open("/jasset/host_list/", "_self");
}
});
}
}
function host_search(){
$.ajax({
type: "GET",
url: "/jasset/search/",
data: $("#search_form").serialize(),
success: function (data) {
$("#contents_form").html(data);
}
});
}
$("#search_input").keydown(function(e){
if(e.keyCode==13){
host_search()
}
})
</script>
{% endblock %}

View File

@ -0,0 +1,64 @@
{% load mytags %}
<table class="table table-striped table-bordered table-hover " id="editable" name="editable">
<thead>
<tr>
<th class="text-center"><input id="checkall" type="checkbox" class="i-checks" name="checkall" value="checkall" data-editable='false' onclick="check_all('contents_form')"></th>
<th class="text-center" name="j_ip"> IP地址 </th>
<th class="text-center"> 端口号 </th>
<th class="text-center" name="j_type"> 登录方式 </th>
<th class="text-center" name="j_idc"> 所属IDC </th>
<th class="text-center"> 所属业务组 </th>
<th class="text-center"> 是否激活 </th>
<th class="text-center" name="j_time"> 添加时间 </th>
<th class="text-center" name="j_comment"> 备注 </th>
<th class="text-center"> 操作 </th>
</tr>
</thead>
<tbody>
{% for post in contacts.object_list %}
<tr class="gradeX">
<td class="text-center" name="j_id" value="{{ post.id }}" data-editable='false'><input name="id" value="{{ post.id }}" type="checkbox" class="i-checks"></td>
<td class="text-center" name="j_ip"> {{ post.ip }} </td>
<td class="text-center" name="j_port"> {{ post.port }} </td>
<td class="text-center" name="j_type"> {{ login_types|get_item:post.login_type }} </td>
<td class="text-center" name="j_idc"> {{ post.idc.name }} </td>
<td class="text-center" name="j_group">{% for group in post.bis_group.all|filter_private %} {{ group }} {% endfor %}</td>
<td class="text-center" name="j_active"> {{ post.is_active|bool2str }} </td>
<td class="text-center"> {{ post.date_added|date:"Y-m-d H:i:s" }} </td>
<td class="text-center" name="j_comment"> {{ post.comment }} </td>
<td class="text-center" data-editable='false'>
<a href="/jasset/{{ post.ip }}/" class="iframe btn btn-xs btn-primary">详情</a>
<a href="/jasset/host_edit/{{ post.id }}" class="btn btn-xs btn-info">编辑</a>
<a href="/jasset/host_del/{{ post.id }}" class="btn btn-xs btn-danger">删除</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="row">
<div class="col-sm-6">
<input type="button" id="del_button" class="btn btn-danger btn-sm" name="del_button" value="删除" onclick="del('contents_form')" />
<input type="button" id="alter_button" class="btn btn-warning btn-sm" name="alter_button" value="修改" onclick="alter('contents_form')" />
</div>
<div class="col-sm-6">
<div class="dataTables_paginate paging_simple_numbers" id="editable_paginate">
<ul class="pagination" style="margin-top: 0; float: right">
{% if contacts.has_previous %}
<li><a href="?page={{ contacts.previous_page_number }}">&laquo;</a></li>
{% endif %}
{% for page in p.page_range %}
{% ifequal offset1 page %}
<li class="active"><a href="?page={{ page }}" title="第{{ page }}页">{{ page }}</a></li>
{% else %}
<li><a href="?page={{ page }}" title="第{{ page }}页">{{ page }}</a></li>
{% endifequal %}
{% endfor %}
{% if contacts.has_next %}
<li><a href="?page={{ contacts.next_page_number }}">&raquo;</a></li>
{% endif %}
</ul>
</div>
</div>
</div>

View File

@ -0,0 +1,179 @@
{% extends 'base.html' %}
{% block content %}
{% include 'nav_cat_bar.html' %}
<style>
.bootstrap-dialog-body {
background-color: rgba(0, 0, 0, 0);
}
.bootstrap-dialog-message {
background-color: rgba(0, 0, 0, 0);
}
.modal-content {
background-color: rgba(0, 0, 0, 0.6);
}
.modal-dialog {
background-color: rgba(0, 0, 0, 0);
width: 800px;
}
.modal-body {
background-color: rgba(0, 0, 0, 0);
}
.modal-header {
background-color: #FFFFFF;
}
.bootstrap-dialog-message {
color: #00FF00;
}
</style>
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-12">
<div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title">
<h5> 用户日志详细信息列表 </h5>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<ul class="dropdown-menu dropdown-user">
<li><a href="#">未启用 1</a>
</li>
<li><a href="#">未启用 2</a>
</li>
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<div class="panel-options">
<ul class="nav nav-tabs">
<li><a href="/jlog/log_list/online/" class="text-center"><i class="fa fa-laptop"></i> 在线 </a></li>
<li class="active"><a href="/jlog/log_list/offline/" class="text-center"><i class="fa fa-bar-chart-o"></i> 历史记录 </a></li>
<li style="float: right">
<form id="search_form" method="get" action="" class="pull-right mail-search">
<div class="input-group">
<input type="text" class="form-control input-sm" id="search_input" name="keyword" placeholder="Search">
<input type="text" style="display: none">
<div class="input-group-btn">
<button id='search_btn' type="button" class="btn btn-sm btn-primary" onclick="log_search()">
Search
</button>
</div>
</div>
</form>
</li>
</ul>
</div>
<br/>
<div class="tab-content">
<table class="table table-striped table-bordered table-hover ">
<thead>
<tr>
<th class="text-center"> 用户名 </th>
<th class="text-center"> 登录主机 </th>
<th class="text-center"> 命令统计 </th>
<th class="text-center"> 登录时间 </th>
<th class="text-center"> 结束时间 </th>
</tr>
</thead>
<tbody>
{% for post in contacts.object_list %}
<tr class="gradeX">
<td class="text-center" id="username"> {{ post.user }} </td>
<td class="text-center" id="ip"> {{ post.host }} </td>
<td class="text-center"><a href="/jlog/history/?id={{ post.id }}" class="log_command"> 命令统计 </td>
<td class="text-center" id="start_time"> {{ post.start_time|date:"Y-m-d H:i:s"}} </td>
<td class="text-center" id="end_time"> {{ post.end_time|date:"Y-m-d H:i:s" }} </td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="row">
<div class="col-sm-6 col-sm-offset-6">
<div class="dataTables_paginate paging_simple_numbers" id="editable_paginate">
<ul class="pagination" style="margin-top: 0; float: right">
{% if contacts.has_previous %}
<li><a href="?page={{ contacts.previous_page_number }}">&laquo;</a></li>
{% endif %}
{% for page in p.page_range %}
{% ifequal offset1 page %}
<li class="active"><a href="?page={{ page }}" title="第{{ page }}页">{{ page }}</a></li>
{% else %}
<li><a href="?page={{ page }}" title="第{{ page }}页">{{ page }}</a></li>
{% endifequal %}
{% endfor %}
{% if contacts.has_next %}
<li><a href="?page={{ contacts.next_page_number }}">&raquo;</a></li>
{% endif %}
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="http://{{ web_socket_host }}/socket.io/socket.io.js"></script>
<script>
$('.log_command').on('click',function(){
var url = $(this).attr('href');
var username = $('#username')[0].innerText;
var ip = $('#ip')[0].innerText;
var start_time = $('#start_time')[0].innerText;
var end_time = $('#end_time')[0].innerText;
var div_username = ' 登录用户名: '+'<span class="text-info">'+username+'' + '</span>';
var div_ip = ' 登录主机: '+'<span class="text-info">' + ip + '</span>';
var div_time = ' 开始时间: ' + '<span class="text-info">'+start_time +'</span>' + ' 结束时间: ' +'<span class="text-info">' + end_time + '</span'
var title = 'JumpServer命令统计 '+ div_username + div_ip + div_time
$.ajax({url:url,success:function(data){
BootstrapDialog.show({title: title, message:data});
}});
return false;
})
globalConfig = {
SOCKET_HOST: "{{ web_socket_host }}"
}
function cut(num){
var g_url = "/jlog/log_kill/"+num;
console.log(g_url);
$.ajax({
type: "GET",
url: g_url,
success: window.open("/jlog/","_self")
});
}
function log_search(){
$.ajax({
type: "GET",
url: "/jlog/search/?env=offline",
data: $("#search_form").serialize(),
success: function (data) {
$(".tab-content").html(data);
}
});
}
$("#search_input").keydown(function(e){
if(e.keyCode==13){
log_search()
}
})
</script>
{% endblock %}

View File

@ -0,0 +1,218 @@
{% extends 'base.html' %}
{% block content %}
{% include 'nav_cat_bar.html' %}
<style>
.bootstrap-dialog-body {
background-color: rgba(0, 0, 0, 0);
}
.bootstrap-dialog-message {
background-color: rgba(0, 0, 0, 0);
}
.modal-content {
background-color: rgba(0, 0, 0, 0.6);
}
.modal-dialog {
background-color: rgba(0, 0, 0, 0);
width: 800px;
}
.modal-body {
background-color: rgba(0, 0, 0, 0);
}
.modal-header {
background-color: #FFFFFF;
}
</style>
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-lg-12">
<div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title">
<h5> 用户日志详细信息列表 </h5>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<ul class="dropdown-menu dropdown-user">
<li><a href="#">未启用 1</a>
</li>
<li><a href="#">未启用 2</a>
</li>
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<div class="panel-options">
<ul class="nav nav-tabs">
<li class="active"><a href="/jlog/log_list/online/" class="text-center"><i class="fa fa-laptop"></i> 在线 </a></li>
<li><a href="/jlog/log_list/offline/" class="text-center"><i class="fa fa-bar-chart-o"></i> 历史记录 </a></li>
<li style="float: right">
<form id="search_form" method="get" action="" class="pull-right mail-search">
<div class="input-group">
<input type="text" class="form-control input-sm" id="search_input" name="keyword" placeholder="Search">
<input type="text" style="display: none">
<div class="input-group-btn">
<button id='search_btn' type="button" class="btn btn-sm btn-primary" onclick="log_search()">
Search
</button>
</div>
</div>
</form>
</li>
</ul>
</div>
<br/>
<div class="tab-content">
<table class="table table-striped table-bordered table-hover ">
<thead>
<tr>
<th class="text-center"> 用户名 </th>
<th class="text-center"> 登录主机 </th>
<th class="text-center"> 实时监控 </th>
<th class="text-center"> 阻断 </th>
<th class="text-center"> 登录时间 </th>
<th class="text-center"> 结束时间 </th>
</tr>
</thead>
<tbody>
{% for post in contacts.object_list %}
<tr class="gradeX">
<td id="username" class="text-center"> {{ post.user }} </td>
<td id="ip" class="text-center"> {{ post.host }} </td>
<td class="text-center"><a class="monitor" filename="{{ post.log_path }}"> 监控 </a></td>
<td class="text-center"><input type="button" id="cut" class="btn btn-danger btn-xs" name="cut" value="阻断" onclick='cut("{{ post.pid }}")' /></td>
<td class="text-center"> {{ post.start_time|date:"Y-m-d H:i:s" }} </td>
<td class="text-center"> {{ post.end_time|date:"Y-m-d H:i:s" }} </td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="row">
<div class="col-sm-6 col-sm-offset-6">
<div class="dataTables_paginate paging_simple_numbers" id="editable_paginate">
<ul class="pagination" style="margin-top: 0; float: right">
{% if contacts.has_previous %}
<li><a href="?page={{ contacts.previous_page_number }}">&laquo;</a></li>
{% endif %}
{% for page in p.page_range %}
{% ifequal offset1 page %}
<li class="active"><a href="?page={{ page }}" title="第{{ page }}页">{{ page }}</a></li>
{% else %}
<li><a href="?page={{ page }}" title="第{{ page }}页">{{ page }}</a></li>
{% endifequal %}
{% endfor %}
{% if contacts.has_next %}
<li><a href="?page={{ contacts.next_page_number }}">&raquo;</a></li>
{% endif %}
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="http://{{ web_socket_host }}/socket.io/socket.io.js"></script>
<script>
$.fn.webSocket = function(opt){
var st = {};
st = $.extend(st,opt);
var message = {};
var $this = $(this);
var genUid = function(){
return new Date().getTime()+""+Math.floor(Math.random()*899+100);
};
var init = function(e){
var socket = io.connect('ws://'+globalConfig.SOCKET_HOST);
var node = $(e.target);
message.id = genUid();
message.filename = node.attr('filename');
var username = $('#username')[0].innerText;
var ip = $('#ip')[0].innerText;
BootstrapDialog.show({message:function(){
var escapeString = function (html){
var elem = document.createElement('div')
var txt = document.createTextNode(html)
elem.appendChild(txt)
return elem.innerHTML;
}
var tag = $('<div id="log" style="height: 500px;overflow: auto;background-color: rgba(0, 0, 0, 0);"></div>');
//告诉服务器端有用户登录
socket.emit('login', {userid:message.id, filename:message.filename});
socket.on('message',function(obj){
//去除log中的颜色控制字符
var regx = /\x1B\[([0-9]{1,3}((;[0-9]{1,3})*)?)?[m|K]/g;
// tag.append('<p>'+escapeString(obj.content.replace(regx,''))+'</p>');
tag.append('<p>'+escapeString(obj.content)+'</p>');
tag.animate({ scrollTop: tag[0].scrollHeight}, 1);
});
tag[0].style.color = "#00FF00";
return tag[0];
} ,
title:'Jumpserver实时监控 '+' 登录用户名: '+'<span class="text-info">'+username+'</span>'+' 登录主机: '+'<span class="text-info">'+ip,
onhide:function(){
socket.emit('disconnect');
}});
}
$this.on("click",function(e){
init(e);
return false;
});
}
$('.log_command').on('click',function(){
var url = $(this).attr('href');
$.ajax({url:url,success:function(data){
BootstrapDialog.show({title:'命令统计',message:data});
}});
return false;
})
globalConfig = {
SOCKET_HOST: "{{ web_socket_host }}"
}
$(".monitor").webSocket()
function log_search(){
console.log('hell0')
$.ajax({
type: "GET",
url: "/jlog/search/?env=online",
data: $("#search_form").serialize(),
success: function (data) {
$(".tab-content").html(data);
}
});
}
$("#search_input").keydown(function(e){
if(e.keyCode==13){
log_search()
}
})
function cut(num){
var g_url = "/jlog/log_kill/"+num;
console.log(g_url);
$.ajax({
type: "GET",
url: g_url,
success: window.open("/jlog/","_self")
});
}
</script>
{% endblock %}

View File

@ -0,0 +1,47 @@
<div class="tab-content">
<table class="table table-striped table-bordered table-hover ">
<thead>
<tr>
<th class="text-center"> 用户名 </th>
<th class="text-center"> 登录主机 </th>
<th class="text-center"> 命令统计 </th>
<th class="text-center"> 登录时间 </th>
<th class="text-center"> 结束时间 </th>
</tr>
</thead>
<tbody>
{% for post in contacts.object_list %}
<tr class="gradeX">
<td class="text-center" id="username"> {{ post.user }} </td>
<td class="text-center" id="ip"> {{ post.host }} </td>
<td class="text-center"><a href="/jlog/history/?id={{ post.id }}" class="log_command"> 命令统计 </td>
<td class="text-center" id="start_time"> {{ post.start_time|date:"Y-m-d H:i:s"}} </td>
<td class="text-center" id="end_time"> {{ post.end_time|date:"Y-m-d H:i:s" }} </td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="row">
<div class="col-sm-6 col-sm-offset-6">
<div class="dataTables_paginate paging_simple_numbers" id="editable_paginate">
<ul class="pagination" style="margin-top: 0; float: right">
{% if contacts.has_previous %}
<li><a href="?page={{ contacts.previous_page_number }}">&laquo;</a></li>
{% endif %}
{% for page in p.page_range %}
{% ifequal offset1 page %}
<li class="active"><a href="?page={{ page }}" title="第{{ page }}页">{{ page }}</a></li>
{% else %}
<li><a href="?page={{ page }}" title="第{{ page }}页">{{ page }}</a></li>
{% endifequal %}
{% endfor %}
{% if contacts.has_next %}
<li><a href="?page={{ contacts.next_page_number }}">&raquo;</a></li>
{% endif %}
</ul>
</div>
</div>
</div>

View File

@ -24,7 +24,7 @@
<a href="mailbox.html"><i class="fa fa-cube"></i> <span class="nav-label">资产管理</span><span class="fa arrow"></span></a>
<ul class="nav nav-second-level">
<li id="host_add"><a href="/jasset/host_add/">添加资产</a></li>
<li id="host_list"><a href="/jasset/host_list/">查看资产&nbsp&nbsp<span class="label label-warning">16/18</span></a></li>
<li id="host_list"><a href="/jasset/host_list/">查看资产&nbsp&nbsp</span><span class="label label-info pull-right">16/18</span></a></li>
<li id="group_add"><a href="/jasset/group_add/">添加IDC|主机组</a></li>
<li id="group_list"><a href="/jasset/group_list/">查看IDC|主机组</a></li>
</ul>
@ -39,7 +39,7 @@
<li id="jlog">
<a href="#"><i class="fa fa-files-o"></i> <span class="nav-label">日志审计</span><span class="fa arrow"></span></a>
<ul class="nav nav-second-level">
<li id="log_list"><a href="/jlog/">查看日志</a></li>
<li id="log_list"><a href="/jlog/log_list/online/">查看日志</a></li>
<li id="log_detail"><a href="/jlog/log_detail/">日志分析</a></li>
</ul>
</li>

View File

@ -3,7 +3,7 @@
<h2>{{ header_title }}</h2>
<ol class="breadcrumb">
<li>
<a href="/">Home</a>
<a href="/">仪表盘</a>
</li>
<li>
<a>{{ path1 }}</a>

17
websocket/.bin/node-tail Executable file
View File

@ -0,0 +1,17 @@
#!/usr/bin/env node
var program = require('commander');
nodetail = require('../src/node-tail.js');
var options = {};
program
.usage('[options] file...')
.option('-p, --port <port>', 'custom port');
program.parse(process.argv);
nodetail.run({
port: program.port,
file: program.args[0]
});