pull/26/head
广宏伟 2015-10-26 22:17:16 +08:00
parent 72a18d6abf
commit 9366003f7b
13 changed files with 379 additions and 312 deletions

View File

@ -19,7 +19,6 @@ if django.get_version() != '1.6':
django.setup() django.setup()
from jumpserver.api import ServerError, User, Asset, Jtty, get_object from jumpserver.api import ServerError, User, Asset, Jtty, get_object
from jumpserver.api import logger from jumpserver.api import logger
from jumpserver.api import BisGroup as AssetGroup
login_user = get_object(User, username=getpass.getuser()) login_user = get_object(User, username=getpass.getuser())
@ -98,76 +97,6 @@ def print_prompt():
print textwrap.dedent(msg) print textwrap.dedent(msg)
# def remote_exec_cmd(ip, port, username, password, cmd):
# try:
# time.sleep(5)
# ssh = paramiko.SSHClient()
# ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# ssh.connect(ip, port, username, password, timeout=5)
# stdin, stdout, stderr = ssh.exec_command("bash -l -c '%s'" % cmd)
# out = stdout.readlines()
# err = stderr.readlines()
# color_print('%s:' % ip, 'blue')
# for i in out:
# color_print(" " * 4 + i.strip(), 'green')
# for j in err:
# color_print(" " * 4 + j.strip(), 'red')
# ssh.close()
# except Exception as e:
# color_print(ip + ':', 'blue')
# color_print(str(e), 'red')
# def multi_remote_exec_cmd(hosts, username, cmd):
# pool = Pool(processes=5)
# for host in hosts:
# username, password, ip, port = get_connect_item(username, host)
# pool.apply_async(remote_exec_cmd, (ip, port, username, password, cmd))
# pool.close()
# pool.join()
# def exec_cmd_servers(username):
# color_print("You can choose in the following IP(s), Use glob or ips split by comma. q/Q to PreLayer.", 'green')
# user.get_asset_info(printable=True)
# while True:
# hosts = []
# inputs = raw_input('\033[1;32mip(s)>: \033[0m')
# if inputs in ['q', 'Q']:
# break
# get_hosts = login_user.get_asset_info().keys()
#
# if ',' in inputs:
# ips_input = inputs.split(',')
# for host in ips_input:
# if host in get_hosts:
# hosts.append(host)
# else:
# for host in get_hosts:
# if fnmatch.fnmatch(host, inputs):
# hosts.append(host.strip())
#
# if len(hosts) == 0:
# color_print("Check again, Not matched any ip!", 'red')
# continue
# else:
# print "You matched ip: %s" % hosts
# color_print("Input the Command , The command will be Execute on servers, q/Q to quit.", 'green')
# while True:
# cmd = raw_input('\033[1;32mCmd(s): \033[0m')
# if cmd in ['q', 'Q']:
# break
# exec_log_dir = os.path.join(log_dir, 'exec_cmds')
# if not os.path.isdir(exec_log_dir):
# os.mkdir(exec_log_dir)
# os.chmod(exec_log_dir, 0777)
# filename = "%s/%s.log" % (exec_log_dir, time.strftime('%Y%m%d'))
# f = open(filename, 'a')
# f.write("DateTime: %s User: %s Host: %s Cmds: %s\n" %
# (time.strftime('%Y/%m/%d %H:%M:%S'), username, hosts, cmd))
# multi_remote_exec_cmd(hosts, username, cmd)
def main(): def main():
""" """
he he he he

68
jlog/log_api.py Normal file
View File

@ -0,0 +1,68 @@
# coding: utf-8
from argparse import ArgumentParser, FileType
from contextlib import closing
from codecs import open as copen
from json import dumps
from math import ceil
from os.path import basename, dirname, exists, join
from struct import unpack
from subprocess import Popen
from sys import platform, prefix, stderr
from tempfile import NamedTemporaryFile
from jinja2 import FileSystemLoader, Template
from jinja2.environment import Environment
from jumpserver.api import BASE_DIR
DEFAULT_TEMPLATE = join(BASE_DIR, 'templates', 'jlog', 'static.jinja2')
def escapeString(string):
string = string.encode('unicode_escape').decode('utf-8')
string = string.replace("'", "\\'")
string = '\'' + string + '\''
return string
def getTiming(timef):
timing = None
with closing(timef):
timing = [l.strip().split(' ') for l in timef]
timing = [(int(ceil(float(r[0]) * 1000)), int(r[1])) for r in timing]
return timing
def scriptToJSON(scriptf, timing=None):
ret = []
with closing(scriptf):
scriptf.readline() # ignore first header line from script file
offset = 0
for t in timing:
data = escapeString(scriptf.read(t[1]))
offset += t[0]
ret.append((data, offset))
return dumps(ret)
def renderTemplate(script_path, time_file_path, dimensions=(24, 60), templatename=DEFAULT_TEMPLATE):
with copen(script_path, encoding='utf-8', errors='replace') as scriptf:
with open(time_file_path) as timef:
timing = getTiming(timef)
json = scriptToJSON(scriptf, timing)
fsl = FileSystemLoader(dirname(templatename), 'utf-8')
e = Environment()
e.loader = fsl
templatename = basename(templatename)
rendered = e.get_template(templatename).render(json=json,
dimensions=dimensions)
return rendered

View File

@ -5,12 +5,10 @@ class Log(models.Model):
user = models.CharField(max_length=20, null=True) user = models.CharField(max_length=20, null=True)
host = models.CharField(max_length=20, null=True) host = models.CharField(max_length=20, null=True)
remote_ip = models.CharField(max_length=100) remote_ip = models.CharField(max_length=100)
dept_name = models.CharField(max_length=20)
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)
handle_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

@ -5,7 +5,7 @@ from jlog.views import *
urlpatterns = patterns('', urlpatterns = patterns('',
url(r'^$', log_list), url(r'^$', log_list),
url(r'^log_list/(\w+)/$', log_list), url(r'^log_list/(\w+)/$', log_list),
url(r'^log_kill/', log_kill), # url(r'^log_kill/', log_kill),
url(r'^history/$', log_history), # url(r'^history/$', log_history),
url(r'^search/$', log_search), # url(r'^search/$', log_search),
) )

View File

@ -4,117 +4,103 @@ from django.template import RequestContext
from django.shortcuts import render_to_response from django.shortcuts import render_to_response
from jumpserver.api import * from jumpserver.api import *
from jasset.views import httperror
from django.http import HttpResponseNotFound from django.http import HttpResponseNotFound
CONF = ConfigParser() CONF = ConfigParser()
CONF.read('%s/jumpserver.conf' % BASE_DIR) CONF.read('%s/jumpserver.conf' % BASE_DIR)
from jlog.models import Log
# def get_user_info(request, offset):
# """ 获取用户信息及环境 """
# env_dic = {'online': 0, 'offline': 1}
# env = env_dic[offset]
# keyword = request.GET.get('keyword', '')
# user_info = get_session_user_info(request)
# user_id, username = user_info[0:2]
# dept_id, dept_name = user_info[3:5]
# ret = [request, keyword, env, username, dept_name]
#
# return ret
#
#
# def get_user_log(ret_list):
# """ 获取不同类型用户日志记录 """
# request, keyword, env, username, dept_name = ret_list
# post_all = Log.objects.filter(is_finished=env).order_by('-start_time')
# post_keyword_all = Log.objects.filter(Q(user__contains=keyword) |
# Q(host__contains=keyword)) \
# .filter(is_finished=env).order_by('-start_time')
#
# if keyword:
# posts = post_keyword_all
# else:
# posts = post_all
#
# return posts
def get_user_info(request, offset):
""" 获取用户信息及环境 """
env_dic = {'online': 0, 'offline': 1}
env = env_dic[offset]
keyword = request.GET.get('keyword', '')
user_info = get_session_user_info(request)
user_id, username = user_info[0:2]
dept_id, dept_name = user_info[3:5]
ret = [request, keyword, env, username, dept_name]
return ret
def get_user_log(ret_list):
""" 获取不同类型用户日志记录 """
request, keyword, env, username, dept_name = ret_list
post_all = Log.objects.filter(is_finished=env).order_by('-start_time')
post_keyword_all = Log.objects.filter(Q(user__contains=keyword) |
Q(host__contains=keyword)) \
.filter(is_finished=env).order_by('-start_time')
if is_super_user(request):
if keyword:
posts = post_keyword_all
else:
posts = post_all
elif is_group_admin(request):
if keyword:
posts = post_keyword_all.filter(dept_name=dept_name)
else:
posts = post_all.filter(dept_name=dept_name)
elif is_common_user(request):
if keyword:
posts = post_keyword_all.filter(user=username)
else:
posts = post_all.filter(user=username)
return posts
@require_login
def log_list(request, offset): def log_list(request, offset):
""" 显示日志 """ """ 显示日志 """
header_title, path1, path2 = u'查看日志', u'查看日志', u'在线用户' header_title, path1, path2 = u'查看日志', u'查看日志', u'在线用户'
keyword = request.GET.get('keyword', '') keyword = request.GET.get('keyword', '')
web_socket_host = CONF.get('websocket', 'web_socket_host') web_socket_host = CONF.get('websocket', 'web_socket_host')
posts = get_user_log(get_user_info(request, offset)) # posts = get_user_log(get_user_info(request, offset))
if offset == 'online':
posts = Log.objects.filter(is_finished=False).order_by('-start_time')
else:
posts = Log.objects.filter(is_finished=True).order_by('-start_time')
contact_list, p, contacts, page_range, current_page, show_first, show_end = pages(posts, request) contact_list, p, contacts, page_range, current_page, show_first, show_end = pages(posts, request)
return render_to_response('jlog/log_%s.html' % offset, locals(), context_instance=RequestContext(request)) return render_to_response('jlog/log_%s.html' % offset, locals(), context_instance=RequestContext(request))
#
@require_admin # def log_kill(request):
def log_kill(request): # """ 杀掉connect进程 """
""" 杀掉connect进程 """ # pid = request.GET.get('id', '')
pid = request.GET.get('id', '') # log = Log.objects.filter(pid=pid)
log = Log.objects.filter(pid=pid) # if log:
if log: # log = log[0]
log = log[0] # dept_name = log.dept_name
dept_name = log.dept_name # deptname = get_session_user_info(request)[4]
deptname = get_session_user_info(request)[4] # if is_group_admin(request) and dept_name != deptname:
if is_group_admin(request) and dept_name != deptname: # return httperror(request, u'Kill失败, 您无权操作!')
return httperror(request, u'Kill失败, 您无权操作!') # try:
try: # os.kill(int(pid), 9)
os.kill(int(pid), 9) # except OSError:
except OSError: # pass
pass # Log.objects.filter(pid=pid).update(is_finished=1, end_time=datetime.datetime.now())
Log.objects.filter(pid=pid).update(is_finished=1, end_time=datetime.datetime.now()) # return render_to_response('jlog/log_offline.html', locals(), context_instance=RequestContext(request))
return render_to_response('jlog/log_offline.html', locals(), context_instance=RequestContext(request)) # else:
else: # return HttpResponseNotFound(u'没有此进程!')
return HttpResponseNotFound(u'没有此进程!') #
#
# def log_history(request):
@require_login # """ 命令历史记录 """
def log_history(request): # log_id = request.GET.get('id', 0)
""" 命令历史记录 """ # log = Log.objects.filter(id=int(log_id))
log_id = request.GET.get('id', 0) # if log:
log = Log.objects.filter(id=int(log_id)) # log = log[0]
if log: # dept_name = log.dept_name
log = log[0] # deptname = get_session_user_info(request)[4]
dept_name = log.dept_name # if is_group_admin(request) and dept_name != deptname:
deptname = get_session_user_info(request)[4] # return httperror(request, '查看失败, 您无权查看!')
if is_group_admin(request) and dept_name != deptname: #
return httperror(request, '查看失败, 您无权查看!') # elif is_common_user(request):
# return httperror(request, '查看失败, 您无权查看!')
elif is_common_user(request): #
return httperror(request, '查看失败, 您无权查看!') # log_his = "%s.his" % log.log_path
# if os.path.isfile(log_his):
log_his = "%s.his" % log.log_path # f = open(log_his)
if os.path.isfile(log_his): # content = f.read()
f = open(log_his) # return HttpResponse(content)
content = f.read() # else:
return HttpResponse(content) # return httperror(request, '无日志记录, 请查看日志处理脚本是否开启!')
else: #
return httperror(request, '无日志记录, 请查看日志处理脚本是否开启!') #
# def log_search(request):
# """ 日志搜索 """
@require_login # offset = request.GET.get('env', '')
def log_search(request): # keyword = request.GET.get('keyword', '')
""" 日志搜索 """ # posts = get_user_log(get_user_info(request, offset))
offset = request.GET.get('env', '') # contact_list, p, contacts, page_range, current_page, show_first, show_end = pages(posts, request)
keyword = request.GET.get('keyword', '') # return render_to_response('jlog/log_search.html', locals(), context_instance=RequestContext(request))
posts = get_user_log(get_user_info(request, offset))
contact_list, p, contacts, page_range, current_page, show_first, show_end = pages(posts, request)
return render_to_response('jlog/log_search.html', locals(), context_instance=RequestContext(request))

View File

@ -12,6 +12,7 @@ import random
import subprocess import subprocess
import paramiko import paramiko
import struct, fcntl, signal,socket, select, fnmatch import struct, fcntl, signal,socket, select, fnmatch
import re
from django.core.paginator import Paginator, EmptyPage, InvalidPage from django.core.paginator import Paginator, EmptyPage, InvalidPage
from django.http import HttpResponse, Http404 from django.http import HttpResponse, Http404
@ -69,75 +70,6 @@ def set_log(level):
return logger_f return logger_f
# class LDAPMgmt():
# """
# LDAP class for add, select, del, update
# LDAP 管理类,增删改查
# """
# def __init__(self,
# host_url,
# base_dn,
# root_cn,
# root_pw):
# self.ldap_host = host_url
# self.ldap_base_dn = base_dn
# self.conn = ldap.initialize(host_url)
# self.conn.set_option(ldap.OPT_REFERRALS, 0)
# self.conn.protocol_version = ldap.VERSION3
# self.conn.simple_bind_s(root_cn, root_pw)
#
# def list(self, filter, scope=ldap.SCOPE_SUBTREE, attr=None):
# """
# query
# 查询
# """
# result = {}
# try:
# ldap_result = self.conn.search_s(self.ldap_base_dn, scope, filter, attr)
# for entry in ldap_result:
# name, data = entry
# for k, v in data.items():
# print '%s: %s' % (k, v)
# result[k] = v
# return result
# except ldap.LDAPError, e:
# print e
#
# def add(self, dn, attrs):
# """
# add
# 添加
# """
# try:
# ldif = modlist.addModlist(attrs)
# self.conn.add_s(dn, ldif)
# except ldap.LDAPError, e:
# print e
#
# def modify(self, dn, attrs):
# """
# modify
# 更改
# """
# try:
# attr_s = []
# for k, v in attrs.items():
# attr_s.append((2, k, v))
# self.conn.modify_s(dn, attr_s)
# except ldap.LDAPError, e:
# print e
#
# def delete(self, dn):
# """
# delete
# 删除
# """
# try:
# self.conn.delete_s(dn)
# except ldap.LDAPError, e:
# print e
def page_list_return(total, current=1): def page_list_return(total, current=1):
""" """
page page
@ -181,17 +113,46 @@ def pages(post_objects, request):
return post_objects, paginator, page_objects, page_range, current_page, show_first, show_end return post_objects, paginator, page_objects, page_range, current_page, show_first, show_end
def remove_control_char(str_r):
"""
处理日志特殊字符
"""
control_char = re.compile(r"""
\x1b[ #%()*+\-.\/]. |
\r | #匹配 回车符(CR)
(?:\x1b\[|\x9b) [ -?]* [@-~] | #匹配 控制顺序描述符(CSI)... Cmd
(?:\x1b\]|\x9d) .*? (?:\x1b\\|[\a\x9c]) | \x07 | #匹配 操作系统指令(OSC)...终止符或振铃符(ST|BEL)
(?:\x1b[P^_]|[\x90\x9e\x9f]) .*? (?:\x1b\\|\x9c) | #匹配 设备控制串或私讯或应用程序命令(DCS|PM|APC)...终止符(ST)
\x1b. #匹配 转义过后的字符
[\x80-\x9f] #匹配 所有控制字符
""", re.X)
backspace = re.compile(r"[^\b][\b]")
line_filtered = control_char.sub('', str_r.rstrip())
while backspace.search(line_filtered):
line_filtered = backspace.sub('', line_filtered)
return line_filtered
def newline_code_in(strings):
for i in ['\r', '\r\n', '\n']:
if i in strings:
#print "new line"
return True
return False
class Jtty(object): class Jtty(object):
""" """
A virtual tty class A virtual tty class
一个虚拟终端类实现连接ssh和记录日志 一个虚拟终端类实现连接ssh和记录日志
""" """
def __init__(self, user, asset): def __init__(self, username, ip):
self.chan = None self.chan = None
self.username = user.username self.username = username
self.ip = asset.ip self.ip = ip
self.user = user # self.user = user
self.asset = asset # self.asset = asset
@staticmethod @staticmethod
def get_win_size(): def get_win_size():
@ -227,11 +188,8 @@ class Jtty(object):
timestamp_start = int(time.time()) timestamp_start = int(time.time())
date_start = time.strftime('%Y%m%d', time.localtime(timestamp_start)) date_start = time.strftime('%Y%m%d', time.localtime(timestamp_start))
time_start = time.strftime('%H%M%S', time.localtime(timestamp_start)) time_start = time.strftime('%H%M%S', time.localtime(timestamp_start))
log_filename = '%s_%s_%s.log' % (self.username, self.ip, time_start)
today_connect_log_dir = os.path.join(tty_log_dir, date_start) today_connect_log_dir = os.path.join(tty_log_dir, date_start)
log_file_path = os.path.join(today_connect_log_dir, log_filename) log_file_path = os.path.join(today_connect_log_dir, '%s_%s_%s' % (self.username, self.ip, time_start))
dept_name = self.user.dept.name
pid = os.getpid() pid = os.getpid()
pts = os.popen("ps axu | grep %s | grep -v grep | awk '{ print $7 }'" % pid).read().strip() pts = os.popen("ps axu | grep %s | grep -v grep | awk '{ print $7 }'" % pid).read().strip()
ip_list = os.popen("who | grep %s | awk '{ print $5 }'" % pts).read().strip('()\n') ip_list = os.popen("who | grep %s | awk '{ print $5 }'" % pts).read().strip('()\n')
@ -242,23 +200,29 @@ class Jtty(object):
raise ServerError('Create %s failed, Please modify %s permission.' % (today_connect_log_dir, tty_log_dir)) raise ServerError('Create %s failed, Please modify %s permission.' % (today_connect_log_dir, tty_log_dir))
try: try:
log_file = open(log_file_path, 'a') log_file_f = open(log_file_path + '.log', 'a')
log_time_f = open(log_file_path + '.time', 'a')
log_res_f = open(log_file_path + '.res', 'a')
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=self.username, host=self.ip, remote_ip=ip_list, dept_name=dept_name, log = Log(user=self.username, host=self.ip, remote_ip=ip_list,
log_path=log_file_path, start_time=datetime.datetime.now(), pid=pid) log_path=log_file_path, start_time=datetime.datetime.now(), pid=pid)
log_file.write('Start time is %s\n' % datetime.datetime.now()) log_file_f.write('Start time is %s\n' % datetime.datetime.now())
log.save() log.save()
return log_file, log return log_file_f, log_time_f, log_res_f, log
def posix_shell(self): def posix_shell(self):
""" """
Use paramiko channel connect server interactive. Use paramiko channel connect server interactive.
使用paramiko模块的channel连接后端进入交互式 使用paramiko模块的channel连接后端进入交互式
""" """
log_file, log = self.log_record() log_file_f, log_time_f, log_res_f, log = self.log_record()
old_tty = termios.tcgetattr(sys.stdin) old_tty = termios.tcgetattr(sys.stdin)
pre_timestamp = time.time()
input_r = ''
input_mode = False
try: try:
tty.setraw(sys.stdin.fileno()) tty.setraw(sys.stdin.fileno())
tty.setcbreak(sys.stdin.fileno()) tty.setcbreak(sys.stdin.fileno())
@ -277,23 +241,40 @@ class Jtty(object):
break break
sys.stdout.write(x) sys.stdout.write(x)
sys.stdout.flush() sys.stdout.flush()
log_file.write(x) log_file_f.write(x)
log_file.flush() now_timestamp = time.time()
log_time_f.write('%s %s\n' % (round(now_timestamp-pre_timestamp, 4), len(x)))
pre_timestamp = now_timestamp
log_file_f.flush()
log_time_f.flush()
if input_mode and not newline_code_in(x):
input_r += x
except socket.timeout: except socket.timeout:
pass pass
if sys.stdin in r: if sys.stdin in r:
x = os.read(sys.stdin.fileno(), 1) x = os.read(sys.stdin.fileno(), 1)
if not input_mode:
input_mode = True
if str(x) in ['\r', '\n', '\r\n']:
input_r = remove_control_char(input_r)
log_res_f.write('%s: %s\n' % (datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), input_r))
log_res_f.flush()
input_r = ''
input_mode = False
if len(x) == 0: if len(x) == 0:
break break
self.chan.send(x) self.chan.send(x)
finally: finally:
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty) termios.tcsetattr(sys.stdin, termios.TCSADRAIN, old_tty)
log_file.write('End time is %s' % datetime.datetime.now()) log_file_f.write('End time is %s' % datetime.datetime.now())
log_file.close() log_file_f.close()
log.is_finished = True log.is_finished = True
log.handle_finished = False
log.end_time = datetime.datetime.now() log.end_time = datetime.datetime.now()
log.save() log.save()
@ -302,27 +283,15 @@ class Jtty(object):
get args for connect: ip, port, username, passwd get args for connect: ip, port, username, passwd
获取连接需要的参数也就是服务ip, 端口, 用户账号和密码 获取连接需要的参数也就是服务ip, 端口, 用户账号和密码
""" """
if not self.asset.is_active: # if not self.asset.is_active:
raise ServerError('该主机被禁用 Host %s is not active.' % self.ip) # raise ServerError('该主机被禁用 Host %s is not active.' % self.ip)
#
# if not self.user.is_active:
# raise ServerError('该用户被禁用 User %s is not active.' % self.username)
if not self.user.is_active: # password = CRYPTOR.decrypt(self.])
raise ServerError('该用户被禁用 User %s is not active.' % self.username) # return self.username, password, self.ip, int(self.asset.port)
return 'root', 'redhat', '127.0.0.1', 22
login_type_dict = {
'L': self.user.ldap_pwd,
}
if self.asset.login_type in login_type_dict:
password = CRYPTOR.decrypt(login_type_dict[self.asset.login_type])
return self.username, password, self.ip, int(self.asset.port)
elif self.asset.login_type == 'M':
username = self.asset.username
password = CRYPTOR.decrypt(self.asset.password)
return username, password, self.ip, int(self.asset.port)
else:
raise ServerError('不支持的服务器登录方式 Login type is not in ["L", "M"]')
def get_connection(self): def get_connection(self):
""" """
@ -337,7 +306,7 @@ class Jtty(object):
ssh.load_system_host_keys() ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try: try:
ssh.connect(ip, port=port, username=username, password=password, compress=True) ssh.connect(ip, port=port, username=username, password=password)
except paramiko.ssh_exception.AuthenticationException, paramiko.ssh_exception.SSHException: except paramiko.ssh_exception.AuthenticationException, paramiko.ssh_exception.SSHException:
raise ServerError('认证错误 Authentication Error.') raise ServerError('认证错误 Authentication Error.')
except socket.error: except socket.error:
@ -351,7 +320,7 @@ class Jtty(object):
连接服务器 连接服务器
""" """
ps1 = "PS1='[\u@%s \W]\$ '\n" % self.ip ps1 = "PS1='[\u@%s \W]\$ '\n" % self.ip
login_msg = "clear;echo -e '\\033[32mLogin %s done. Enjoy it.\\033[0m'\n" % self.asset.ip login_msg = "clear;echo -e '\\033[32mLogin %s done. Enjoy it.\\033[0m'\n" % self.ip
# 发起ssh连接请求 Make a ssh connection # 发起ssh连接请求 Make a ssh connection
ssh = self.get_connection() ssh = self.get_connection()
@ -706,14 +675,5 @@ def my_render(template, data, request):
CRYPTOR = PyCrypt(KEY) CRYPTOR = PyCrypt(KEY)
# if LDAP_ENABLE:
# LDAP_HOST_URL = CONF.get('ldap', 'host_url')
# LDAP_BASE_DN = CONF.get('ldap', 'base_dn')
# LDAP_ROOT_DN = CONF.get('ldap', 'root_dn')
# LDAP_ROOT_PW = CONF.get('ldap', 'root_pw')
# ldap_conn = LDAPMgmt(LDAP_HOST_URL, LDAP_BASE_DN, LDAP_ROOT_DN, LDAP_ROOT_PW)
# else:
# ldap_conn = None
log_level = CONF.get('base', 'log') log_level = CONF.get('base', 'log')
logger = set_log(log_level) logger = set_log(log_level)

View File

@ -62,7 +62,7 @@ INSTALLED_APPS = (
'juser', 'juser',
'jasset', 'jasset',
'jperm', 'jperm',
# 'jlog', 'jlog',
) )
MIDDLEWARE_CLASSES = ( MIDDLEWARE_CLASSES = (

View File

@ -16,7 +16,7 @@ urlpatterns = patterns('',
(r'^error/$', 'jumpserver.views.httperror'), (r'^error/$', 'jumpserver.views.httperror'),
(r'^juser/', include('juser.urls')), (r'^juser/', include('juser.urls')),
(r'^jasset/', include('jasset.urls')), (r'^jasset/', include('jasset.urls')),
# (r'^jlog/', include('jlog.urls')), (r'^jlog/', include('jlog.urls')),
(r'^jperm/', include('jperm.urls')), (r'^jperm/', include('jperm.urls')),
(r'^node_auth/', 'jumpserver.views.node_auth'), (r'^node_auth/', 'jumpserver.views.node_auth'),

111
templates/jlog/base.jinja2 Normal file
View File

@ -0,0 +1,111 @@
<html>
<head>{% block head %}{% endblock %}
</head>
<body>
<input type="button" value="Play/Pause" onclick="pause(false);" />
<input type="button" value="Restart" onclick="restart(1);" />
<span id="beforeScrubberText"></span>
<input id="scrubber" type="range" value="0" min=0 max=100
onmousedown="pause(true);" onmouseup="scrub();" />
<span id="afterScrubberText"></span>
-5x <input id="speed" type="range" value="0" min=-5 max=5
onmouseup="setSpeed();" /> +5x
<script>
var data = {{ json }};
var toggle = true;
var totalTime = 0;
var TICK = 33;
var TIMESTEP = 33;
var time = 33;
var pos = 0;
var timer;
// Thanks http://stackoverflow.com/a/2998822
function zeroPad(num, size) {
var s = "0" + num;
return s.substr(s.length-size);
}
function scrub() {
setPercent = document.getElementById('scrubber').value;
time = (setPercent / 100) * totalTime;
restart(time);
}
function buildTimeString(millis) {
hours = zeroPad(Math.floor(millis / (1000 * 60 * 60)), 2);
millis -= hours * (1000 * 60 * 60)
minutes = zeroPad(Math.floor(millis / (1000 * 60)), 2);
millis -= minutes * (1000 * 60);
seconds = zeroPad(Math.floor(millis / 1000), 2);
return hours + ':' + minutes + ':' + seconds;
}
function advance() {
document.getElementById('scrubber').value =
Math.ceil((time / totalTime) * 100);
timestr = buildTimeString(time);
document.getElementById("beforeScrubberText").innerHTML =
timestr;
for (; pos < data.length; pos++) {
if (data[pos][1] <= time) {
term.write(eval(data[pos][0]));
} else {
break;
}
}
if (pos >= data.length) {
clearInterval(timer);
}
time += TIMESTEP;
}
function pause(test) {
if (!toggle && test) {
return;
}
if (toggle) {
clearInterval(timer);
toggle = !toggle;
} else {
timer = setInterval(advance, TICK);
toggle = !toggle;
}
}
function setSpeed() {
speed = document.getElementById('speed').value;
if (speed == 0) {
TIMESTEP = TICK;
} else if (speed < 0) {
TIMESTEP = TICK / -speed;
} else {
TIMESTEP = TICK * speed;
}
}
function restart(millis) {
clearInterval(timer);
term.reset();
time = millis;
pos = 0;
toggle = true;
timer = setInterval(advance, TICK);
}
var term = new Terminal({
cols: {{ dimensions[1] }},
rows: {{ dimensions[0] }},
screenKeys: true
});
totalTime = data[data.length - 1][1];
timestr = buildTimeString(totalTime);
document.getElementById("afterScrubberText").innerHTML = timestr;
term.open(document.body);
timer = setInterval(advance, TICK);
</script>
</body>
</html>

View File

@ -0,0 +1,11 @@
{% extends "base.jinja2" %}
{% block head %}
<script src='term.js'></script>
<link href='http://fonts.googleapis.com/css?family=Ubuntu+Mono' rel='stylesheet' type='text/css'>
<style>
body {
font-family: 'Ubuntu Mono', Courier, monospace;
font-size: 14pt;
}
</style>
{% endblock %}

View File

@ -39,12 +39,6 @@
<a class="dropdown-toggle" data-toggle="dropdown" href="#"> <a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i> <i class="fa fa-wrench"></i>
</a> </a>
<ul class="dropdown-menu dropdown-user">
<li><a href="#">未启用 1</a>
</li>
<li><a href="#">未启用 2</a>
</li>
</ul>
<a class="close-link"> <a class="close-link">
<i class="fa fa-times"></i> <i class="fa fa-times"></i>
</a> </a>
@ -77,12 +71,12 @@
<thead> <thead>
<tr> <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"> 来源IP </th> <th class="text-center"> 来源IP </th>
{% ifnotequal session_role_id 0 %} {% ifnotequal session_role_id 0 %}
<th class="text-center"> 命令统计 </th> <th class="text-center"> 命令统计 </th>
{% endifnotequal %} {% endifnotequal %}
<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>
@ -92,12 +86,12 @@
{% for post in contacts.object_list %} {% for post in contacts.object_list %}
<tr class="gradeX"> <tr class="gradeX">
<td class="text-center" id="username"> {{ post.user }} </td> <td class="text-center" id="username"> {{ post.user }} </td>
<td class="text-center" id="dept"> {{ post.dept_name }} </td>
<td class="text-center" id="ip"> {{ post.host }} </td> <td class="text-center" id="ip"> {{ post.host }} </td>
<td class="text-center" id="remote_ip"> {{ post.remote_ip }} </td> <td class="text-center" id="remote_ip"> {{ post.remote_ip }} </td>
{% ifnotequal session_role_id 0 %} {% ifnotequal session_role_id 0 %}
<td class="text-center"><a href="/jlog/history/?id={{ post.id }}" class="log_command"> 命令统计 </td> <td class="text-center"><a href="/jlog/history/?id={{ post.id }}" class="log_command"> 命令统计 </td>
{% endifnotequal %} {% endifnotequal %}
<td class="text-center"><a href="/jlog/record/?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="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> <td class="text-center" id="end_time"> {{ post.end_time|date:"Y-m-d H:i:s" }} </td>
</tr> </tr>

View File

@ -39,12 +39,6 @@
<a class="dropdown-toggle" data-toggle="dropdown" href="#"> <a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i> <i class="fa fa-wrench"></i>
</a> </a>
<ul class="dropdown-menu dropdown-user">
<li><a href="#">未启用 1</a>
</li>
<li><a href="#">未启用 2</a>
</li>
</ul>
<a class="close-link"> <a class="close-link">
<i class="fa fa-times"></i> <i class="fa fa-times"></i>
</a> </a>
@ -77,7 +71,6 @@
<thead> <thead>
<tr> <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"> 来源IP </th> <th class="text-center"> 来源IP </th>
{% ifnotequal session_role_id 0 %} {% ifnotequal session_role_id 0 %}
@ -92,7 +85,6 @@
{% for post in contacts.object_list %} {% for post in contacts.object_list %}
<tr class="gradeX"> <tr class="gradeX">
<td id="username" class="text-center"> {{ post.user }} </td> <td id="username" class="text-center"> {{ post.user }} </td>
<td id="deptname" class="text-center"> {{ post.dept_name }} </td>
<td id="ip" class="text-center"> {{ post.host }} </td> <td id="ip" class="text-center"> {{ post.host }} </td>
<td id="remote_ip" class="text-center"> {{ post.remote_ip }} </td> <td id="remote_ip" class="text-center"> {{ post.remote_ip }} </td>
{% ifnotequal session_role_id 0 %} {% ifnotequal session_role_id 0 %}

File diff suppressed because one or more lines are too long