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

View File

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

View File

@ -1,13 +1,15 @@
# coding:utf-8 # coding:utf-8
from django.db.models import Q
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.template import RequestContext from django.template import RequestContext
from django.shortcuts import render_to_response 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 models import IDC, Asset, BisGroup
from juser.models import UserGroup from juser.models import UserGroup
from connect import PyCrypt, KEY 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) cryptor = PyCrypt(KEY)
@ -86,13 +88,13 @@ def add_host_multi(request):
for host in multi_hosts: for host in multi_hosts:
if host == '': if host == '':
break 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_type = login_types[j_type]
j_groups = j_groups.split(',') j_groups = j_groups.split(',')
for group in j_groups: for group in j_groups:
g = group.strip('[]').encode('utf-8').strip() g = group.strip('[]').encode('utf-8').strip()
j_group.append(g) j_group.append(g)
print j_group,type(j_group)
if Asset.objects.filter(ip=str(j_ip)): if Asset.objects.filter(ip=str(j_ip)):
emg = u'该IP %s 已存在!' %j_ip emg = u'该IP %s 已存在!' %j_ip
return render_to_response('jasset/host_add_multi.html', locals(), context_instance=RequestContext(request)) 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'查看主机' header_title, path1, path2 = u'查看主机 | List Host', u'资产管理', u'查看主机'
login_types = {'L': 'LDAP', 'S': 'SSH_KEY', 'P': 'PASSWORD', 'M': 'MAP'} login_types = {'L': 'LDAP', 'S': 'SSH_KEY', 'P': 'PASSWORD', 'M': 'MAP'}
posts = contact_list = Asset.objects.all().order_by('ip') posts = contact_list = Asset.objects.all().order_by('ip')
print posts
p = paginator = Paginator(contact_list, 20) p = paginator = Paginator(contact_list, 20)
try: try:
page = int(request.GET.get('page', '1')) 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)) 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'编辑主机组' 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() all = Asset.objects.all()
eposts = contact_list = Asset.objects.filter(bis_group=group).order_by('ip') eposts = contact_list = Asset.objects.filter(bis_group=group).order_by('ip')
posts = [g for g in all if g not in eposts] 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_hosts = request.POST.getlist('j_hosts')
j_comment = request.POST.get('j_comment') j_comment = request.POST.get('j_comment')
group = BisGroup.objects.get(name=j_group)
group.asset_set.clear() group.asset_set.clear()
for host in j_hosts: for host in j_hosts:
g = Asset.objects.get(id=host) g = Asset.objects.get(id=host)
group.asset_set.add(g) group.asset_set.add(g)
BisGroup.objects.filter(id=group_id).update(name=j_group, comment=j_comment)
smg = u'主机组%s修改成功' %j_group 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)) 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/') 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): def test(request):
return render_to_response('jasset/test.html', locals()) return render_to_response('jasset/test.html', locals())

View File

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

View File

@ -3,7 +3,10 @@ from django.conf.urls import patterns, include, url
from jlog.views import * from jlog.views import *
urlpatterns = patterns('', urlpatterns = patterns('',
url(r'^$', jlog_list), url(r'^$', log_list_online),
url(r'^log_list/(\w+)/$', jlog_list), url(r'^log_list/online/$', log_list_online),
url(r'^log_kill/(\d+)', jlog_kill), 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 os
import ConfigParser import ConfigParser
from datetime import datetime from datetime import datetime
from django.db.models import Q
from django.http import HttpResponse
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.template import RequestContext
from django.shortcuts import render_to_response from django.shortcuts import render_to_response
from django.core.paginator import Paginator, EmptyPage
from connect import BASE_DIR from connect import BASE_DIR
from jlog.models import Log from jlog.models import Log
from jumpserver.views import pages
CONF = ConfigParser.ConfigParser() CONF = ConfigParser.ConfigParser()
CONF.read('%s/jumpserver.conf' % BASE_DIR) CONF.read('%s/jumpserver.conf' % BASE_DIR)
def jlog_list(request, offset='online'): def log_list_online(request):
header_title, path1, path2 = u'查看日志 | Log List.', u'查看日志', u'日志列表' header_title, path1, path2 = u'查看日志 | Log List.', u'查看日志', u'在线用户'
web_socket_host = CONF.get('websocket', 'web_socket_host') web_socket_host = CONF.get('websocket', 'web_socket_host')
online = Log.objects.filter(is_finished=0) posts = Log.objects.filter(is_finished=0).order_by('-start_time')
offline = Log.objects.filter(is_finished=1) 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 pid = offset
if pid: if pid:
os.kill(int(pid), 9) os.kill(int(pid), 9)
Log.objects.filter(pid=pid).update(is_finished=1, end_time=datetime.now()) 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: for g in group:
if not pattern.match(g.name): if not pattern.match(g.name):
agroup.append(g) agroup.append(g)
try:
agroup.remove(p) agroup.remove(p)
except ValueError:
pass
return agroup return agroup

View File

@ -2,12 +2,11 @@
import hashlib import hashlib
from django.http import HttpResponse
from django.shortcuts import render_to_response from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.core.paginator import Paginator, EmptyPage, InvalidPage
from juser.models import User from juser.models import User
from connect import PyCrypt, KEY
from jasset.models import Asset, BisGroup, IDC 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 j_idc
print print
a = Asset.objects.get(id=j_id) a = Asset.objects.get(id=j_id)
print '123'
if j_type == 'M': if j_type == 'M':
a.ip = j_ip a.ip = j_ip
a.port = j_port 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() 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): def login(request):
"""登录界面""" """登录界面"""
if request.session.get('username'): if request.session.get('username'):

View File

@ -2,11 +2,10 @@
#coding: utf-8 #coding: utf-8
import os import os
import sys
import time 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' os.environ['DJANGO_SETTINGS_MODULE'] = 'jumpserver.settings'
import django import django
@ -14,28 +13,24 @@ django.setup()
from jlog.models import Log from jlog.models import Log
def log_hanler(pid): def log_hanler(id):
log = Log.objects.filter(id=pid) log = Log.objects.get(id=id)
if log: if log:
log = log[0] filename = log.log_path
filename = log.logfile
if os.path.isfile(filename): if os.path.isfile(filename):
ret1 = os.system('cat %s | grep "DateTime" > %s.his' % (filename, filename)) ret1 = os.system('cat %s | grep "DateTime" > %s.his' % (filename, filename))
ret2 = os.system('cat %s | grep "\[.*@.*\][\$\#]" >> %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)) ret3 = os.system('cat %s | grep "EndTime" >> %s.his' % (filename, filename))
if (ret1 + ret2 + ret3) == 0: if (ret1 + ret2 + ret3) == 0:
print 'Handler %s ok.' % filename print 'Handler %s ok.' % filename
log.log_finished = True
log.save()
def set_finish(id): def set_finish(id):
logs = Log.objects.filter(id=id, finish=0) log = Log.objects.filter(id=id)
if logs: if log:
structtime_start = time.localtime() log.update(is_finished=1, end_time=datetime.now())
timestamp_end = int(time.mktime(structtime_start))
log = logs[0]
log.finish = 1
log.end_time = timestamp_end
log.save()
def kill_pid(pid): def kill_pid(pid):
@ -45,52 +40,37 @@ def kill_pid(pid):
pass 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(): def get_pids():
pids = [] pids1, pids2 = [], []
pids_obj = Pid.objects.all() pids1_obj = Log.objects.filter(is_finished=0)
for pid_obj in pids_obj: pids2_obj = Log.objects.filter(is_finished=1, log_finished=0)
pids.append((pid_obj.id, pid_obj.ppid, pid_obj.cpid, pid_obj.pid, pid_obj.start_time)) for pid_obj in pids1_obj:
return pids 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(): def run():
for pid_id, ppid, cpid, pid, start_time in get_pids(): pids1, pids2 = get_pids()
if pid_exist(cpid): for pid_id in pids2:
if pid_exist(ppid): log_hanler(pid_id)
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)
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__': if __name__ == '__main__':
while True: while True:
run() 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 %} {% endif %}
<form id="assetForm" method="post" class="form-horizontal"> <form id="assetForm" method="post" class="form-horizontal">
<div class="form-group"><label class="col-sm-2 control-label"> 主机组名 </label> <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>
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>

View File

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

View File

@ -44,7 +44,7 @@
{% endif %} {% endif %}
<h4>按照文本框内主机信息格式填写, 多台主机回车换行</h4> <h4>按照文本框内主机信息格式填写, 多台主机回车换行</h4>
<form id="assetMulti" method="post" class="form-horizontal"> <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="hr-line-dashed"></div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-4 col-sm-offset-4"> <div class="col-sm-4 col-sm-offset-4">

View File

@ -29,8 +29,19 @@
</div> </div>
<div class="ibox-content"> <div class="ibox-content">
<div class=""> <div>
<a target="_blank" href="/jasset/host_add" class="btn btn-sm btn-primary "> 添加 </a> <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> </div>
<form id="contents_form" name="contents_form"> <form id="contents_form" name="contents_form">
@ -146,6 +157,25 @@
}); });
} }
} }
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> </script>
{% endblock %} {% 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> <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"> <ul class="nav nav-second-level">
<li id="host_add"><a href="/jasset/host_add/">添加资产</a></li> <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_add"><a href="/jasset/group_add/">添加IDC|主机组</a></li>
<li id="group_list"><a href="/jasset/group_list/">查看IDC|主机组</a></li> <li id="group_list"><a href="/jasset/group_list/">查看IDC|主机组</a></li>
</ul> </ul>
@ -39,7 +39,7 @@
<li id="jlog"> <li id="jlog">
<a href="#"><i class="fa fa-files-o"></i> <span class="nav-label">日志审计</span><span class="fa arrow"></span></a> <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"> <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> <li id="log_detail"><a href="/jlog/log_detail/">日志分析</a></li>
</ul> </ul>
</li> </li>

View File

@ -3,7 +3,7 @@
<h2>{{ header_title }}</h2> <h2>{{ header_title }}</h2>
<ol class="breadcrumb"> <ol class="breadcrumb">
<li> <li>
<a href="/">Home</a> <a href="/">仪表盘</a>
</li> </li>
<li> <li>
<a>{{ path1 }}</a> <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]
});