Commit 8f985ade authored by wangyong's avatar wangyong

Merge branch 'dev' of https://git.coding.net/jumpserver/jumpserver into dev

parents 9b7ef113 b5325fd0
...@@ -27,9 +27,11 @@ from jumpserver.api import logger, Log, TtyLog, get_role_key, CRYPTOR, bash, get ...@@ -27,9 +27,11 @@ from jumpserver.api import logger, Log, TtyLog, get_role_key, CRYPTOR, bash, get
from jperm.perm_api import gen_resource, get_group_asset_perm, get_group_user_perm, user_have_perm, PermRole from jperm.perm_api import gen_resource, get_group_asset_perm, get_group_user_perm, user_have_perm, PermRole
from jumpserver.settings import LOG_DIR from jumpserver.settings import LOG_DIR
from jperm.ansible_api import Command, MyRunner from jperm.ansible_api import Command, MyRunner
from jlog.log_api import escapeString # from jlog.log_api import escapeString
from jlog.models import ExecLog, FileLog
login_user = get_object(User, username=getpass.getuser()) login_user = get_object(User, username=getpass.getuser())
remote_ip = os.popen("who -m | awk '{ print $5 }'").read().strip('()\n')
try: try:
import termios import termios
...@@ -227,8 +229,6 @@ class Tty(object): ...@@ -227,8 +229,6 @@ class Tty(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_f = copen(log_file_path + '.log', mode='at', encoding='utf-8', errors='replace')
# log_time_f = copen(log_file_path + '.time', mode='at', encoding='utf-8', errors='replace')
log_file_f = open(log_file_path + '.log', 'a') log_file_f = open(log_file_path + '.log', 'a')
log_time_f = open(log_file_path + '.time', 'a') log_time_f = open(log_file_path + '.time', 'a')
except IOError: except IOError:
...@@ -237,13 +237,12 @@ class Tty(object): ...@@ -237,13 +237,12 @@ class Tty(object):
if self.login_type == 'ssh': # 如果是ssh连接过来,记录connect.py的pid,web terminal记录为日志的id if self.login_type == 'ssh': # 如果是ssh连接过来,记录connect.py的pid,web terminal记录为日志的id
pid = os.getpid() pid = os.getpid()
self.remote_ip = os.popen("who -m | awk '{ print $5 }'").read().strip('()\n') # 获取远端IP self.remote_ip = remote_ip # 获取远端IP
else: else:
pid = 0 pid = 0
log = Log(user=self.username, host=self.asset_name, remote_ip=self.remote_ip, login_type=self.login_type, log = Log(user=self.username, host=self.asset_name, remote_ip=self.remote_ip, login_type=self.login_type,
log_path=log_file_path, start_time=date_today, pid=pid) log_path=log_file_path, start_time=date_today, pid=pid)
log.save() log.save()
if self.login_type == 'web': if self.login_type == 'web':
log.pid = log.id log.pid = log.id
...@@ -421,9 +420,6 @@ class SshTty(Tty): ...@@ -421,9 +420,6 @@ class SshTty(Tty):
Connect server. Connect server.
连接服务器 连接服务器
""" """
ps1 = "PS1='[\u@%s \W]\$ '\n" % self.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()
...@@ -435,20 +431,6 @@ class SshTty(Tty): ...@@ -435,20 +431,6 @@ class SshTty(Tty):
signal.signal(signal.SIGWINCH, self.set_win_size) signal.signal(signal.SIGWINCH, self.set_win_size)
except: except:
pass pass
# 设置PS1并提示 Set PS1 and msg it
#channel.send(ps1)
#channel.send(login_msg)
# channel.send('echo ${SSH_TTY}\n')
# global SSH_TTY
# while not channel.recv_ready():
# time.sleep(1)
# tmp = channel.recv(1024)
#print 'ok'+tmp+'ok'
# SSH_TTY = re.search(r'(?<=/dev/).*', tmp).group().strip()
# SSH_TTY = ''
# channel.send('clear\n')
# Make ssh interactive tunnel
self.posix_shell() self.posix_shell()
# Shutdown channel socket # Shutdown channel socket
...@@ -468,16 +450,6 @@ class Nav(object): ...@@ -468,16 +450,6 @@ class Nav(object):
Print prompt Print prompt
打印提示导航 打印提示导航
""" """
msg = """\n\033[1;32m### Welcome To Use JumpServer, A Open Source System . ### \033[0m
1) Type \033[32mID\033[0m To Login.
2) Type \033[32m/\033[0m + \033[32mIP, Host Name, Host Alias or Comments \033[0mTo Search.
3) Type \033[32mP/p\033[0m To Print The Servers You Available.
4) Type \033[32mG/g\033[0m To Print The Server Groups You Available.
5) Type \033[32mG/g\033[0m\033[0m + \033[32mGroup ID\033[0m To Print The Server Group You Available.
6) Type \033[32mE/e\033[0m To Execute Command On Several Servers.
7) Type \033[32mQ/q\033[0m To Quit.
"""
msg = """\n\033[1;32m### 欢迎使用Jumpserver开源跳板机 ### \033[0m msg = """\n\033[1;32m### 欢迎使用Jumpserver开源跳板机 ### \033[0m
1) 输入 \033[32mID\033[0m 直接登录. 1) 输入 \033[32mID\033[0m 直接登录.
2) 输入 \033[32m/\033[0m + \033[32mIP, 主机名, 主机别名 or 备注 \033[0m搜索. 2) 输入 \033[32m/\033[0m + \033[32mIP, 主机名, 主机别名 or 备注 \033[0m搜索.
...@@ -542,35 +514,6 @@ class Nav(object): ...@@ -542,35 +514,6 @@ class Nav(object):
print '[%-3s] %-15s' % (asset_group.id, asset_group.name) print '[%-3s] %-15s' % (asset_group.id, asset_group.name)
print print
def get_exec_log(self, assets_name_str):
exec_log_dir = os.path.join(LOG_DIR, 'exec')
date_today = datetime.datetime.now()
date_start = date_today.strftime('%Y%m%d')
time_start = date_today.strftime('%H%M%S')
today_connect_log_dir = os.path.join(exec_log_dir, date_start)
log_file_path = os.path.join(today_connect_log_dir, '%s_%s' % (self.user.username, time_start))
try:
mkdir(os.path.dirname(today_connect_log_dir), mode=0777)
mkdir(today_connect_log_dir, mode=0777)
except OSError:
logger.debug('创建目录 %s 失败,请修改%s目录权限' % (today_connect_log_dir, exec_log_dir))
raise ServerError('Create %s failed, Please modify %s permission.' % (today_connect_log_dir, exec_log_dir))
try:
log_file_f = open(log_file_path + '.log', 'a')
log_file_f.write('Start at %s\r\n' % datetime.datetime.now())
log_time_f = open(log_file_path + '.time', 'a')
except IOError:
logger.debug('创建tty日志文件失败, 请修改目录%s权限' % today_connect_log_dir)
raise ServerError('Create logfile failed, Please modify %s permission.' % today_connect_log_dir)
remote_ip = os.popen("who -m | awk '{ print $5 }'").read().strip('()\n')
log = Log(user=self.user.username, host=assets_name_str, remote_ip=remote_ip, login_type='exec',
log_path=log_file_path, start_time=datetime.datetime.now(), pid=os.getpid())
log.save()
return log_file_f, log_time_f, log
def exec_cmd(self): def exec_cmd(self):
""" """
批量执行命令 批量执行命令
...@@ -578,8 +521,10 @@ class Nav(object): ...@@ -578,8 +521,10 @@ class Nav(object):
while True: while True:
if not self.user_perm: if not self.user_perm:
self.user_perm = get_group_user_perm(self.user) self.user_perm = get_group_user_perm(self.user)
print '\033[32m[%-2s] %-15s \033[0m' % ('ID', '角色')
roles = self.user_perm.get('role').keys() roles = self.user_perm.get('role').keys()
if len(roles) > 1: # 授权角色数大于1
print '\033[32m[%-2s] %-15s \033[0m' % ('ID', '角色')
role_check = dict(zip(range(len(roles)), roles)) role_check = dict(zip(range(len(roles)), roles))
for i, r in role_check.items(): for i, r in role_check.items():
...@@ -591,12 +536,16 @@ class Nav(object): ...@@ -591,12 +536,16 @@ class Nav(object):
role_id = raw_input("\033[1;32mRole>:\033[0m ").strip() role_id = raw_input("\033[1;32mRole>:\033[0m ").strip()
if role_id == 'q': if role_id == 'q':
break break
except (IndexError, ValueError):
color_print('错误输入')
else: else:
role = role_check[int(role_id)] role = role_check[int(role_id)]
assets = list(self.user_perm.get('role', {}).get(role).get('asset')) elif len(roles) == 1: # 授权角色数为1
role = roles[0]
assets = list(self.user_perm.get('role', {}).get(role).get('asset')) # 获取该用户,角色授权主机
print "该角色有权限的所有主机" print "该角色有权限的所有主机"
for asset in assets: for asset in assets:
print asset.hostname print ' %s' % asset.hostname
print print
print "请输入主机名、IP或ansile支持的pattern, q退出" print "请输入主机名、IP或ansile支持的pattern, q退出"
pattern = raw_input("\033[1;32mPattern>:\033[0m ").strip() pattern = raw_input("\033[1;32mPattern>:\033[0m ").strip()
...@@ -604,78 +553,43 @@ class Nav(object): ...@@ -604,78 +553,43 @@ class Nav(object):
break break
else: else:
res = gen_resource({'user': self.user, 'asset': assets, 'role': role}, perm=self.user_perm) res = gen_resource({'user': self.user, 'asset': assets, 'role': role}, perm=self.user_perm)
cmd = Command(res) runner = MyRunner(res)
logger.debug("批量执行res: %s" % res) logger.debug("批量执行res: %s" % res)
asset_name_str = '' asset_name_str = ''
for inv in cmd.inventory.get_hosts(pattern=pattern): print "匹配主机:"
print inv.name for inv in runner.inventory.get_hosts(pattern=pattern):
asset_name_str += inv.name print ' %s' % inv.name
asset_name_str += '%s ' % inv.name
print print
log_file_f, log_time_f, log = self.get_exec_log(asset_name_str)
pre_timestamp = time.time()
while True: while True:
print "请输入执行的命令, 按q退出" print "请输入执行的命令, 按q退出"
data = 'ansible> '
write_log(log_file_f, data)
now_timestamp = time.time()
write_log(log_time_f, '%s %s\n' % (round(now_timestamp-pre_timestamp, 4), len(data)))
pre_timestamp = now_timestamp
command = raw_input("\033[1;32mCmds>:\033[0m ").strip() command = raw_input("\033[1;32mCmds>:\033[0m ").strip()
data = '%s\r\n' % command
write_log(log_file_f, data)
now_timestamp = time.time()
write_log(log_time_f, '%s %s\n' % (round(now_timestamp-pre_timestamp, 4), len(data)))
pre_timestamp = now_timestamp
TtyLog(log=log, cmd=command, datetime=datetime.datetime.now()).save()
if command == 'q': if command == 'q':
log.is_finished = True
log.end_time = datetime.datetime.now()
log.save()
break break
result = cmd.run(module_name='shell', command=command, pattern=pattern) runner.run('shell', command, pattern=pattern)
for k, v in result.items(): ExecLog(host=asset_name_str, user=self.user.username, cmd=command, remote_ip=remote_ip,
result=runner.results).save()
for k, v in runner.results.items():
if k == 'ok': if k == 'ok':
for host, output in v.items(): for host, output in v.items():
header = color_print("%s => %s" % (host, 'Ok'), 'green') color_print("%s => %s" % (host, 'Ok'), 'green')
print output print output
output = re.sub(r'[\r\n]', '\r\n', output)
data = '%s\r\n%s\r\n' % (header, output)
now_timestamp = time.time()
write_log(log_file_f, data)
write_log(log_time_f, '%s %s\n' % (round(now_timestamp-pre_timestamp, 4), len(data)))
pre_timestamp = now_timestamp
print print
else: else:
for host, output in v.items(): for host, output in v.items():
header = color_print("%s => %s" % (host, k), 'red') color_print("%s => %s" % (host, k), 'red')
output = color_print(output, 'red') color_print(output, 'red')
output = re.sub(r'[\r\n]', '\r\n', output)
data = '%s\r\n%s\r\n' % (header, output)
now_timestamp = time.time()
write_log(log_file_f, data)
write_log(log_time_f, '%s %s\n' % (round(now_timestamp-pre_timestamp, 4), len(data)))
pre_timestamp = now_timestamp
print print
print "=" * 20 print "~o~ Task finished ~o~"
print print
except (IndexError, KeyError):
color_print('ID输入错误')
continue
except EOFError:
print
break
finally:
log.is_finished = True
log.end_time = datetime.datetime.now()
def upload(self): def upload(self):
while True: while True:
if not self.user_perm: if not self.user_perm:
self.user_perm = get_group_user_perm(self.user) self.user_perm = get_group_user_perm(self.user)
try: try:
print "进入批量上传模式"
print "请输入主机名、IP或ansile支持的pattern, q退出" print "请输入主机名、IP或ansile支持的pattern, q退出"
pattern = raw_input("\033[1;32mPattern>:\033[0m ").strip() pattern = raw_input("\033[1;32mPattern>:\033[0m ").strip()
if pattern == 'q': if pattern == 'q':
...@@ -684,33 +598,39 @@ class Nav(object): ...@@ -684,33 +598,39 @@ class Nav(object):
assets = self.user_perm.get('asset').keys() assets = self.user_perm.get('asset').keys()
res = gen_resource({'user': self.user, 'asset': assets}, perm=self.user_perm) res = gen_resource({'user': self.user, 'asset': assets}, perm=self.user_perm)
runner = MyRunner(res) runner = MyRunner(res)
logger.debug("Muti upload file res: %s" % res)
asset_name_str = '' asset_name_str = ''
print "匹配主机:\n"
for inv in runner.inventory.get_hosts(pattern=pattern): for inv in runner.inventory.get_hosts(pattern=pattern):
print inv.name print inv.name
asset_name_str += inv.name asset_name_str += '%s ' % inv.name
print
if not asset_name_str:
color_print('没有匹配主机')
continue
tmp_dir = get_tmp_dir() tmp_dir = get_tmp_dir()
logger.debug('Upload tmp dir: %s' % tmp_dir) logger.debug('Upload tmp dir: %s' % tmp_dir)
os.chdir(tmp_dir) os.chdir(tmp_dir)
bash('rz') bash('rz')
check_notempty = os.listdir(tmp_dir) filename_str = ' '.join(os.listdir(tmp_dir))
if not check_notempty: if not filename_str:
print color_print("上传文件为空") color_print("上传文件为空")
continue continue
logger.debug('上传文件: %s' % filename_str)
runner = MyRunner(res) runner = MyRunner(res)
runner.run('copy', module_args='src=%s dest=%s directory_mode' runner.run('copy', module_args='src=%s dest=%s directory_mode'
% (tmp_dir, tmp_dir), pattern=pattern) % (tmp_dir, tmp_dir), pattern=pattern)
ret = runner.get_result() ret = runner.results
logger.debug(ret) FileLog(user=self.user.name, host=asset_name_str, filename=filename_str,
remote_ip=remote_ip, type='upload', result=ret).save()
logger.debug('Upload file: %s' % ret)
if ret.get('failed'): if ret.get('failed'):
print ret
error = '上传目录: %s \n上传失败: [ %s ] \n上传成功 [ %s ]' % (tmp_dir, error = '上传目录: %s \n上传失败: [ %s ] \n上传成功 [ %s ]' % (tmp_dir,
', '.join(ret.get('failed').keys()), ', '.join(ret.get('failed').keys()),
', '.join(ret.get('ok'))) ', '.join(ret.get('ok').keys()))
color_print(error) color_print(error)
else: else:
msg = '上传目录: %s \n传送成功 [ %s ]' % (tmp_dir, ', '.join(ret.get('ok'))) msg = '上传目录: %s \n传送成功 [ %s ]' % (tmp_dir, ', '.join(ret.get('ok').keys()))
color_print(msg, 'green') color_print(msg, 'green')
print print
...@@ -731,30 +651,41 @@ class Nav(object): ...@@ -731,30 +651,41 @@ class Nav(object):
assets = self.user_perm.get('asset').keys() assets = self.user_perm.get('asset').keys()
res = gen_resource({'user': self.user, 'asset': assets}, perm=self.user_perm) res = gen_resource({'user': self.user, 'asset': assets}, perm=self.user_perm)
runner = MyRunner(res) runner = MyRunner(res)
logger.debug("Muti Muti file res: %s" % res) logger.debug("Muti download file res: %s" % res)
asset_name_str = ''
print "匹配用户:\n"
for inv in runner.inventory.get_hosts(pattern=pattern): for inv in runner.inventory.get_hosts(pattern=pattern):
print inv.name asset_name_str += '%s ' % inv.name
print ' %s' % inv.name
if not asset_name_str:
color_print('没有匹配主机')
continue
print print
while True:
tmp_dir = get_tmp_dir() tmp_dir = get_tmp_dir()
logger.debug('Download tmp dir: %s' % tmp_dir) logger.debug('Download tmp dir: %s' % tmp_dir)
while True:
print "请输入文件路径(不支持目录)" print "请输入文件路径(不支持目录)"
file_path = raw_input("\033[1;32mPath>:\033[0m ").strip() file_path = raw_input("\033[1;32mPath>:\033[0m ").strip()
if file_path == 'q': if file_path == 'q':
break break
runner.run('fetch', module_args='src=%s dest=%s' % (file_path, tmp_dir), pattern=pattern) runner.run('fetch', module_args='src=%s dest=%s' % (file_path, tmp_dir), pattern=pattern)
ret = runner.get_result() ret = runner.results
FileLog(user=self.user.name, host=asset_name_str, filename=file_path, type='download',
remote_ip=remote_ip, result=ret).save()
logger.debug('Download file result: %s' % ret)
os.chdir('/tmp') os.chdir('/tmp')
tmp_dir_name = os.path.basename(tmp_dir) tmp_dir_name = os.path.basename(tmp_dir)
bash('tar czf %s.tar.gz %s ' % (tmp_dir, tmp_dir_name)) if not os.listdir(tmp_dir):
color_print('下载全部失败')
continue
bash('tar czf %s.tar.gz %s && sz %s.tar.gz' % (tmp_dir, tmp_dir_name, tmp_dir))
if ret.get('failed'): if ret.get('failed'):
print ret error = '文件名称: %s \n下载失败: [ %s ] \n下载成功 [ %s ]' % \
error = '文件名称: %s 下载失败: [ %s ] \n下载成功 [ %s ]' % \ ('%s.tar.gz' % tmp_dir_name, ', '.join(ret.get('failed').keys()), ', '.join(ret.get('ok').keys()))
('%s.tar.gz' % tmp_dir_name, ', '.join(ret.get('failed').keys()), ', '.join(ret.get('ok')))
color_print(error) color_print(error)
else: else:
msg = '文件名称: %s 下载成功 [ %s ]' % ('%s.tar.gz' % tmp_dir_name, ', '.join(ret.get('ok'))) msg = '文件名称: %s \n下载成功 [ %s ]' % ('%s.tar.gz' % tmp_dir_name, ', '.join(ret.get('ok').keys()))
color_print(msg, 'green') color_print(msg, 'green')
print print
except IndexError: except IndexError:
......
...@@ -3,7 +3,7 @@ from django.db import models ...@@ -3,7 +3,7 @@ from django.db import models
class Log(models.Model): 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=200, null=True)
remote_ip = models.CharField(max_length=100) remote_ip = models.CharField(max_length=100)
login_type = models.CharField(max_length=100) login_type = models.CharField(max_length=100)
log_path = models.CharField(max_length=100) log_path = models.CharField(max_length=100)
...@@ -24,5 +24,26 @@ class Alert(models.Model): ...@@ -24,5 +24,26 @@ class Alert(models.Model):
class TtyLog(models.Model): class TtyLog(models.Model):
log = models.ForeignKey(Log) log = models.ForeignKey(Log)
datetime = models.DateTimeField() datetime = models.DateTimeField(auto_now=True)
cmd = models.CharField(max_length=200) cmd = models.CharField(max_length=200)
class ExecLog(models.Model):
user = models.CharField(max_length=100)
host = models.TextField()
cmd = models.TextField()
remote_ip = models.CharField(max_length=100)
result = models.TextField(default='')
datetime = models.DateTimeField(auto_now=True)
class FileLog(models.Model):
user = models.CharField(max_length=100)
host = models.TextField()
filename = models.TextField()
type = models.CharField(max_length=20)
remote_ip = models.CharField(max_length=100)
result = models.TextField(default='')
datetime = models.DateTimeField(auto_now=True)
...@@ -3,11 +3,11 @@ from django.conf.urls import patterns, include, url ...@@ -3,11 +3,11 @@ from django.conf.urls import patterns, include, url
from jlog.views import * from jlog.views import *
urlpatterns = patterns('', urlpatterns = patterns('',
url(r'^$', log_list), (r'^$', log_list),
url(r'^log_list/(\w+)/$', log_list), (r'^log_list/(\w+)/$', log_list),
url(r'^history/$', log_history), (r'^log_detail/(\w+)/$', log_detail),
url(r'^log_kill/', log_kill), (r'^history/$', log_history),
url(r'^record/$', log_record), (r'^log_kill/', log_kill),
url(r'^web_terminal/$', web_terminal), (r'^record/$', log_record),
(r'^web_terminal/$', web_terminal),
) )
\ No newline at end of file
...@@ -8,7 +8,7 @@ from jperm.perm_api import user_have_perm ...@@ -8,7 +8,7 @@ from jperm.perm_api import user_have_perm
from django.http import HttpResponseNotFound from django.http import HttpResponseNotFound
from jlog.log_api import renderTemplate from jlog.log_api import renderTemplate
from models import Log from jlog.models import Log, ExecLog, FileLog
from jumpserver.settings import WEB_SOCKET_HOST from jumpserver.settings import WEB_SOCKET_HOST
...@@ -21,9 +21,19 @@ def log_list(request, offset): ...@@ -21,9 +21,19 @@ def log_list(request, offset):
username_list = request.GET.getlist('username', []) username_list = request.GET.getlist('username', [])
host_list = request.GET.getlist('host', []) host_list = request.GET.getlist('host', [])
cmd = request.GET.get('cmd', '') cmd = request.GET.get('cmd', '')
print date_seven_day, date_now_str
if offset == 'online': if offset == 'online':
posts = Log.objects.filter(is_finished=False).order_by('-start_time') posts = Log.objects.filter(is_finished=False).order_by('-start_time')
elif offset == 'exec':
posts = ExecLog.objects.all().order_by('-id')
keyword = request.GET.get('keyword', '')
if keyword:
posts = posts.filter(Q(user__icontains=keyword)|Q(host__icontains=keyword)|Q(cmd__icontains=keyword))
elif offset == 'file':
posts = FileLog.objects.all().order_by('-id')
keyword = request.GET.get('keyword', '')
if keyword:
posts = posts.filter(Q(user__icontains=keyword)|Q(host__icontains=keyword)|Q(filename__icontains=keyword))
else: else:
posts = Log.objects.filter(is_finished=True).order_by('-start_time') posts = Log.objects.filter(is_finished=True).order_by('-start_time')
username_all = set([log.user for log in Log.objects.all()]) username_all = set([log.user for log in Log.objects.all()])
...@@ -57,6 +67,11 @@ def log_list(request, offset): ...@@ -57,6 +67,11 @@ def log_list(request, offset):
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_role('admin')
def log_detail(request):
return my_render('jlog/exec_detail.html', locals(), request)
@require_role('admin') @require_role('admin')
def log_kill(request): def log_kill(request):
""" 杀掉connect进程 """ """ 杀掉connect进程 """
...@@ -114,3 +129,21 @@ def web_terminal(request): ...@@ -114,3 +129,21 @@ def web_terminal(request):
web_terminal_uri = 'ws://%s/terminal?id=%s&role=%s' % (WEB_SOCKET_HOST, asset_id, role_name) web_terminal_uri = 'ws://%s/terminal?id=%s&role=%s' % (WEB_SOCKET_HOST, asset_id, role_name)
return render_to_response('jlog/web_terminal.html', locals()) return render_to_response('jlog/web_terminal.html', locals())
@require_role('admin')
def log_detail(request, offset):
log_id = request.GET.get('id')
if offset == 'exec':
log = get_object(ExecLog, id=log_id)
assets_hostname = log.host.split(' ')
result = eval(str(log.result))
return my_render('jlog/exec_detail.html', locals(), request)
elif offset == 'file':
log = get_object(FileLog, id=log_id)
assets_hostname = log.host.split(' ')
file_list = log.filename.split(' ')
try:
result = eval(str(log.result))
except (SyntaxError, NameError):
result = {}
return my_render('jlog/file_detail.html', locals(), request)
...@@ -117,9 +117,9 @@ class MyRunner(MyInventory): ...@@ -117,9 +117,9 @@ class MyRunner(MyInventory):
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(MyRunner, self).__init__(*args, **kwargs) super(MyRunner, self).__init__(*args, **kwargs)
self.results = {} self.results_raw = {}
def run(self, module_name, module_args='', timeout=10, forks=10, pattern='', def run(self, module_name='shell', module_args='', timeout=10, forks=10, pattern='',
sudo=False, sudo_user='root', sudo_pass=''): sudo=False, sudo_user='root', sudo_pass=''):
""" """
run module from andible ad-hoc. run module from andible ad-hoc.
...@@ -137,23 +137,29 @@ class MyRunner(MyInventory): ...@@ -137,23 +137,29 @@ class MyRunner(MyInventory):
become_user=sudo_user, become_user=sudo_user,
become_pass=sudo_pass become_pass=sudo_pass
) )
self.results = hoc.run() self.results_raw = hoc.run()
return self.results return self.results_raw
def get_result(self): @property
result = {'failed': {}, 'ok': []} def results(self):
dark = self.results.get('dark') """
contacted = self.results.get('contacted') {'failed': {'localhost': ''}, 'ok': {'jumpserver': ''}}
"""
result = {'failed': {}, 'ok': {}}
dark = self.results_raw.get('dark')
contacted = self.results_raw.get('contacted')
if dark: if dark:
for host, info in dark.items(): for host, info in dark.items():
result['failed'][host] = info.get('msg') result['failed'][host] = info.get('msg')
if contacted: if contacted:
for host, info in contacted.items(): for host, info in contacted.items():
if info.get('msg'): if info.get('failed'):
result['failed'][host] = info.get('msg') result['failed'][host] = info.get('msg') + info.get('stderr', '')
elif info.get('stderr'):
result['failed'][host] = info.get('stderr') + str(info.get('warnings'))
else: else:
result['ok'].append(host) result['ok'][host] = info.get('stdout')
return result return result
...@@ -163,9 +169,9 @@ class Command(MyInventory): ...@@ -163,9 +169,9 @@ class Command(MyInventory):
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(Command, self).__init__(*args, **kwargs) super(Command, self).__init__(*args, **kwargs)
self.results = {} self.results_raw = {}
def run(self, command, module_name="command", timeout=10, forks=10, pattern='*'): def run(self, command, module_name="command", timeout=10, forks=10, pattern=''):
""" """
run command from andible ad-hoc. run command from andible ad-hoc.
command : 必须是一个需要执行的命令字符串, 比如 command : 必须是一个需要执行的命令字符串, 比如
...@@ -183,25 +189,34 @@ class Command(MyInventory): ...@@ -183,25 +189,34 @@ class Command(MyInventory):
pattern=pattern, pattern=pattern,
forks=forks, forks=forks,
) )
self.results = hoc.run() self.results_raw = hoc.run()
ret = {} @property
def result(self):
result = {}
for k, v in self.results_raw.items():
if k == 'dark':
for host, info in v.items():
result[host] = {'dark': info.get('msg')}
elif k == 'contacted':
for host, info in v.items():
result[host] = {}
if info.get('stdout'):
result[host]['stdout'] = info.get('stdout')
elif info.get('stderr'):
result[host]['stderr'] = info.get('stderr')
return result
@property
def state(self):
result = {}
if self.stdout: if self.stdout:
data['ok'] = self.stdout result['ok'] = self.stdout
if self.stderr: if self.stderr:
data['err'] = self.stderr result['err'] = self.stderr
if self.dark: if self.dark:
data['dark'] = self.dark result['dark'] = self.dark
return result
return data
@property
def raw_results(self):
"""
get the ansible raw results.
"""
return self.results
@property @property
def exec_time(self): def exec_time(self):
...@@ -209,7 +224,7 @@ class Command(MyInventory): ...@@ -209,7 +224,7 @@ class Command(MyInventory):
get the command execute time. get the command execute time.
""" """
result = {} result = {}
all = self.results.get("contacted") all = self.results_raw.get("contacted")
for key, value in all.iteritems(): for key, value in all.iteritems():
result[key] = { result[key] = {
"start": value.get("start"), "start": value.get("start"),
...@@ -223,7 +238,7 @@ class Command(MyInventory): ...@@ -223,7 +238,7 @@ class Command(MyInventory):
get the comamnd standard output. get the comamnd standard output.
""" """
result = {} result = {}
all = self.results.get("contacted") all = self.results_raw.get("contacted")
for key, value in all.iteritems(): for key, value in all.iteritems():
result[key] = value.get("stdout") result[key] = value.get("stdout")
return result return result
...@@ -234,7 +249,7 @@ class Command(MyInventory): ...@@ -234,7 +249,7 @@ class Command(MyInventory):
get the command standard error. get the command standard error.
""" """
result = {} result = {}
all = self.results.get("contacted") all = self.results_raw.get("contacted")
for key, value in all.iteritems(): for key, value in all.iteritems():
if value.get("stderr") or value.get("warnings"): if value.get("stderr") or value.get("warnings"):
result[key] = { result[key] = {
...@@ -247,7 +262,7 @@ class Command(MyInventory): ...@@ -247,7 +262,7 @@ class Command(MyInventory):
""" """
get the dark results. get the dark results.
""" """
return self.results.get("dark") return self.results_raw.get("dark")
class Tasks(Command): class Tasks(Command):
......
...@@ -55,6 +55,6 @@ class PermPush(models.Model): ...@@ -55,6 +55,6 @@ class PermPush(models.Model):
is_public_key = models.BooleanField(default=False) is_public_key = models.BooleanField(default=False)
is_password = models.BooleanField(default=False) is_password = models.BooleanField(default=False)
success = models.BooleanField(default=False) success = models.BooleanField(default=False)
result = models.TextField() result = models.TextField(default='')
date_added = models.DateTimeField(auto_now=True) date_added = models.DateTimeField(auto_now=True)
...@@ -217,6 +217,7 @@ def gen_resource(ob, perm=None): ...@@ -217,6 +217,7 @@ def gen_resource(ob, perm=None):
for asset in ob: for asset in ob:
info = get_asset_info(asset) info = get_asset_info(asset)
res.append(info) res.append(info)
logger.debug('生成res: %s' % res)
return res return res
...@@ -295,9 +296,11 @@ def get_role_push_host(role): ...@@ -295,9 +296,11 @@ def get_role_push_host(role):
asset_all = Asset.objects.all() asset_all = Asset.objects.all()
asset_pushed = {} asset_pushed = {}
for push in pushs: for push in pushs:
print push.result
asset_pushed[push.asset] = {'success': push.success, 'key': push.is_public_key, 'password': push.is_password, asset_pushed[push.asset] = {'success': push.success, 'key': push.is_public_key, 'password': push.is_password,
'result': push.result} 'result': push.result}
asset_no_push = set(asset_all) - set(asset_pushed.keys()) asset_no_push = set(asset_all) - set(asset_pushed.keys())
print asset_no_push, asset_pushed
return asset_pushed, asset_no_push return asset_pushed, asset_no_push
......
...@@ -78,11 +78,11 @@ def perm_rule_add(request): ...@@ -78,11 +78,11 @@ def perm_rule_add(request):
if request.method == 'POST': if request.method == 'POST':
# 获取用户选择的 用户,用户组,资产,资产组,用户角色 # 获取用户选择的 用户,用户组,资产,资产组,用户角色
users_select = request.POST.getlist('user', []) users_select = request.POST.getlist('user', []) # 需要授权用户
user_groups_select = request.POST.getlist('usergroup', []) user_groups_select = request.POST.getlist('usergroup', []) # 需要授权用户组
assets_select = request.POST.getlist('asset', []) assets_select = request.POST.getlist('asset', []) # 需要授权资产
asset_groups_select = request.POST.getlist('assetgroup', []) asset_groups_select = request.POST.getlist('assetgroup', []) # 需要授权资产组
roles_select = request.POST.getlist('role', []) roles_select = request.POST.getlist('role', []) # 需要授权角色
rule_name = request.POST.get('rulename') rule_name = request.POST.get('rulename')
rule_comment = request.POST.get('rule_comment') rule_comment = request.POST.get('rule_comment')
...@@ -94,8 +94,10 @@ def perm_rule_add(request): ...@@ -94,8 +94,10 @@ def perm_rule_add(request):
# 获取需要授权的主机列表 # 获取需要授权的主机列表
assets_obj = [Asset.objects.get(id=asset_id) for asset_id in assets_select] assets_obj = [Asset.objects.get(id=asset_id) for asset_id in assets_select]
asset_groups_obj = [AssetGroup.objects.get(id=group_id) for group_id in asset_groups_select] asset_groups_obj = [AssetGroup.objects.get(id=group_id) for group_id in asset_groups_select]
group_assets_obj = [asset for asset in [group.asset_set.all() for group in asset_groups_obj]] group_assets_obj = []
calc_assets = set(group_assets_obj) | set(assets_obj) for asset_group in asset_groups_obj:
group_assets_obj.extend(list(asset_group.asset_set.all()))
calc_assets = set(group_assets_obj) | set(assets_obj) # 授权资产和资产组包含的资产
# 获取需要授权的用户列表 # 获取需要授权的用户列表
users_obj = [User.objects.get(id=user_id) for user_id in users_select] users_obj = [User.objects.get(id=user_id) for user_id in users_select]
...@@ -106,8 +108,9 @@ def perm_rule_add(request): ...@@ -106,8 +108,9 @@ def perm_rule_add(request):
# 获取授予的角色列表 # 获取授予的角色列表
roles_obj = [PermRole.objects.get(id=role_id) for role_id in roles_select] roles_obj = [PermRole.objects.get(id=role_id) for role_id in roles_select]
need_push_asset = set() need_push_asset = set()
for role in roles_obj: for role in roles_obj:
asset_no_push = get_role_push_host(role=role)[1] asset_no_push = get_role_push_host(role=role)[0] # 获取某角色已经推送的资产
need_push_asset.update(set(calc_assets) - set(asset_no_push)) need_push_asset.update(set(calc_assets) - set(asset_no_push))
if need_push_asset: if need_push_asset:
raise ServerError(u'没有推送角色 %s 的主机 %s' raise ServerError(u'没有推送角色 %s 的主机 %s'
...@@ -444,13 +447,14 @@ def perm_role_push(request): ...@@ -444,13 +447,14 @@ def perm_role_push(request):
if password_push or key_push: if password_push or key_push:
role_chosen_aliase = {} # {'dev': 'NETWORKING, SHUTDOWN'} role_chosen_aliase = {} # {'dev': 'NETWORKING, SHUTDOWN'}
sudo_alias = set([sudo for sudo in role.sudo.all()]) # set(sudo1, sudo2, sudo3) sudo_alias = set([sudo for sudo in role.sudo.all()]) # set(sudo1, sudo2, sudo3)
role_chosen_aliase[role.name] = ','.join(sudo.name for sudo in sudo_alias) if sudo_alias:
role_chosen_aliase[role.name] = ','.join(sudo.name for sudo in sudo_alias if sudo.name)
add_sudo_script = get_add_sudo_script(role_chosen_aliase, sudo_alias) add_sudo_script = get_add_sudo_script(role_chosen_aliase, sudo_alias)
ret['sudo'] = task.push_sudo_file(add_sudo_script) ret['sudo'] = task.push_sudo_file(add_sudo_script)
if ret['sudo'].get('msg'): if ret['sudo'].get('msg'):
ret_failed = ret['sudo'].get('msg') ret_failed = ret['sudo'].get('msg')
# os.remove(add_sudo_script) os.remove(add_sudo_script)
logger.debug('推送role结果: %s' % ret) logger.debug('推送role结果: %s' % ret)
logger.debug('推送role错误: %s' % ret_failed) logger.debug('推送role错误: %s' % ret_failed)
......
...@@ -96,7 +96,7 @@ def get_role_key(user, role): ...@@ -96,7 +96,7 @@ def get_role_key(user, role):
with open(os.path.join(role.key_path, 'id_rsa')) as fk: with open(os.path.join(role.key_path, 'id_rsa')) as fk:
with open(user_role_key_path, 'w') as fu: with open(user_role_key_path, 'w') as fu:
fu.write(fk.read()) fu.write(fk.read())
logger.debug("创建新的用户角色key %s" % user_role_key_path) logger.debug(u"创建新的用户角色key %s" % user_role_key_path)
chown(user_role_key_path, user.username) chown(user_role_key_path, user.username)
os.chmod(user_role_key_path, 0600) os.chmod(user_role_key_path, 0600)
return user_role_key_path return user_role_key_path
......
...@@ -15,7 +15,7 @@ from jumpserver.api import * ...@@ -15,7 +15,7 @@ from jumpserver.api import *
from jumpserver.models import Setting from jumpserver.models import Setting
from django.contrib.auth import authenticate, login, logout from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from jlog.models import Log from jlog.models import Log, FileLog
from jperm.perm_api import get_group_user_perm, gen_resource from jperm.perm_api import get_group_user_perm, gen_resource
from jasset.models import Asset, IDC from jasset.models import Asset, IDC
from jperm.ansible_api import MyRunner from jperm.ansible_api import MyRunner
...@@ -287,14 +287,14 @@ def setting(request): ...@@ -287,14 +287,14 @@ def setting(request):
def upload(request): def upload(request):
user = request.user user = request.user
assets = get_group_user_perm(user).get('asset').keys() assets = get_group_user_perm(user).get('asset').keys()
asset_select = [] asset_select = []
if request.method == 'POST': if request.method == 'POST':
remote_ip = request.META.get('REMOTE_ADDR')
asset_ids = request.POST.getlist('asset_ids', '') asset_ids = request.POST.getlist('asset_ids', '')
upload_files = request.FILES.getlist('file[]', None) upload_files = request.FILES.getlist('file[]', None)
date_now = datetime.datetime.now().strftime("%Y%m%d%H%M%S") date_now = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
upload_dir = get_tmp_dir() upload_dir = get_tmp_dir()
filenames = {} # file_dict = {}
for asset_id in asset_ids: for asset_id in asset_ids:
asset_select.append(get_object(Asset, id=asset_id)) asset_select.append(get_object(Asset, id=asset_id))
...@@ -302,9 +302,10 @@ def upload(request): ...@@ -302,9 +302,10 @@ def upload(request):
illegal_asset = set(asset_select).issubset(set(assets)) illegal_asset = set(asset_select).issubset(set(assets))
return HttpResponse('没有权限的服务器 %s' % ','.join([asset.hostname for asset in illegal_asset])) return HttpResponse('没有权限的服务器 %s' % ','.join([asset.hostname for asset in illegal_asset]))
for upload_file in upload_files: for upload_file in upload_files:
file_path = '%s/%s' % (upload_dir, upload_file.name) file_path = '%s/%s' % (upload_dir, upload_file.name)
filenames[upload_file.name] = file_path
with open(file_path, 'w') as f: with open(file_path, 'w') as f:
for chunk in upload_file.chunks(): for chunk in upload_file.chunks():
f.write(chunk) f.write(chunk)
...@@ -313,14 +314,17 @@ def upload(request): ...@@ -313,14 +314,17 @@ def upload(request):
runner = MyRunner(res) runner = MyRunner(res)
runner.run('copy', module_args='src=%s dest=%s directory_mode' runner.run('copy', module_args='src=%s dest=%s directory_mode'
% (upload_dir, upload_dir), pattern='*') % (upload_dir, upload_dir), pattern='*')
ret = runner.get_result() ret = runner.results
logger.debug(ret) logger.debug(ret)
FileLog(user=request.user.username, host=' '.join([asset.hostname for asset in asset_select]),
filename=' '.join([f.name for f in upload_files]), type='upload', remote_ip=remote_ip,
result=ret).save()
if ret.get('failed'): if ret.get('failed'):
error = '上传目录: %s <br> 上传失败: [ %s ] <br>上传成功 [ %s ]' % (upload_dir, error = '上传目录: %s <br> 上传失败: [ %s ] <br>上传成功 [ %s ]' % (upload_dir,
', '.join(ret.get('failed').keys()), ', '.join(ret.get('failed').keys()),
', '.join(ret.get('ok'))) ', '.join(ret.get('ok').keys()))
return HttpResponse(error, status=500) return HttpResponse(error, status=500)
msg = '上传目录: %s <br> 传送成功 [ %s ]' % (upload_dir, ', '.join(ret.get('ok'))) msg = '上传目录: %s <br> 传送成功 [ %s ]' % (upload_dir, ', '.join(ret.get('ok')).keys())
return HttpResponse(msg) return HttpResponse(msg)
return my_render('upload.html', locals(), request) return my_render('upload.html', locals(), request)
...@@ -329,9 +333,9 @@ def upload(request): ...@@ -329,9 +333,9 @@ def upload(request):
def download(request): def download(request):
user = request.user user = request.user
assets = get_group_user_perm(user).get('asset').keys() assets = get_group_user_perm(user).get('asset').keys()
asset_select = [] asset_select = []
if request.method == 'POST': if request.method == 'POST':
remote_ip = request.META.get('REMOTE_ADDR')
asset_ids = request.POST.getlist('asset_ids', '') asset_ids = request.POST.getlist('asset_ids', '')
file_path = request.POST.get('file_path') file_path = request.POST.get('file_path')
date_now = datetime.datetime.now().strftime("%Y%m%d%H%M%S") date_now = datetime.datetime.now().strftime("%Y%m%d%H%M%S")
...@@ -342,14 +346,17 @@ def download(request): ...@@ -342,14 +346,17 @@ def download(request):
if not set(asset_select).issubset(set(assets)): if not set(asset_select).issubset(set(assets)):
illegal_asset = set(asset_select).issubset(set(assets)) illegal_asset = set(asset_select).issubset(set(assets))
return HttpResponse('没有权限的服务器 %s' % ','.join([asset.hostname for asset in illegal_asset])) return HttpResponse('没有权限的服务器 %s' % ','.join([asset.hostname for asset in illegal_asset]))
res = gen_resource({'user': user, 'asset': asset_select}) res = gen_resource({'user': user, 'asset': asset_select})
runner = MyRunner(res) runner = MyRunner(res)
runner.run('fetch', module_args='src=%s dest=%s' % (file_path, upload_dir), pattern='*') runner.run('fetch', module_args='src=%s dest=%s' % (file_path, upload_dir), pattern='*')
logger.debug(runner.get_result()) FileLog(user=request.user.username, host=' '.join([asset.hostname for asset in asset_select]),
filename=file_path, type='download', remote_ip=remote_ip, result=runner.results).save()
logger.debug(runner.results)
os.chdir('/tmp') os.chdir('/tmp')
tmp_dir_name = os.path.basename(upload_dir) tmp_dir_name = os.path.basename(upload_dir)
tar_file = '%s.tar.gz' % upload_dir tar_file = '%s.tar.gz' % upload_dir
bash('tar czf %s %s && sz %s.tar.gz' % (tar_file, tmp_dir_name, upload_dir)) bash('tar czf %s %s' % (tar_file, tmp_dir_name))
f = open(tar_file) f = open(tar_file)
data = f.read() data = f.read()
f.close() f.close()
......
...@@ -8,7 +8,7 @@ import sys ...@@ -8,7 +8,7 @@ import sys
import os.path import os.path
import threading import threading
import datetime import datetime
import urllib import re
import tornado.ioloop import tornado.ioloop
import tornado.options import tornado.options
...@@ -24,7 +24,7 @@ from pyinotify import WatchManager, Notifier, ProcessEvent, IN_DELETE, IN_CREATE ...@@ -24,7 +24,7 @@ from pyinotify import WatchManager, Notifier, ProcessEvent, IN_DELETE, IN_CREATE
import select import select
from connect import Tty, User, Asset, PermRole, logger, get_object, PermRole, gen_resource from connect import Tty, User, Asset, PermRole, logger, get_object, PermRole, gen_resource
from connect import TtyLog, Log, Session, user_have_perm, get_group_user_perm, Command from connect import TtyLog, Log, Session, user_have_perm, get_group_user_perm, MyRunner, ExecLog
try: try:
import simplejson as json import simplejson as json
...@@ -218,9 +218,10 @@ class ExecHandler(tornado.websocket.WebSocketHandler): ...@@ -218,9 +218,10 @@ class ExecHandler(tornado.websocket.WebSocketHandler):
self.id = 0 self.id = 0
self.user = None self.user = None
self.role = None self.role = None
self.cmd = None self.runner = None
self.assets = [] self.assets = []
self.perm = {} self.perm = {}
self.remote_ip = ''
super(ExecHandler, self).__init__(*args, **kwargs) super(ExecHandler, self).__init__(*args, **kwargs)
def check_origin(self, origin): def check_origin(self, origin):
...@@ -230,6 +231,7 @@ class ExecHandler(tornado.websocket.WebSocketHandler): ...@@ -230,6 +231,7 @@ class ExecHandler(tornado.websocket.WebSocketHandler):
def open(self): def open(self):
logger.debug('Websocket: Open exec request') logger.debug('Websocket: Open exec request')
role_name = self.get_argument('role', 'sb') role_name = self.get_argument('role', 'sb')
self.remote_ip = self.request.remote_ip
logger.debug('Web执行命令: 请求角色 %s' % role_name) logger.debug('Web执行命令: 请求角色 %s' % role_name)
self.role = get_object(PermRole, name=role_name) self.role = get_object(PermRole, name=role_name)
self.perm = get_group_user_perm(self.user) self.perm = get_group_user_perm(self.user)
...@@ -238,24 +240,38 @@ class ExecHandler(tornado.websocket.WebSocketHandler): ...@@ -238,24 +240,38 @@ class ExecHandler(tornado.websocket.WebSocketHandler):
self.write_message('No perm that role %s' % role_name) self.write_message('No perm that role %s' % role_name)
self.close() self.close()
self.assets = self.perm.get('role').get(self.role).get('asset') self.assets = self.perm.get('role').get(self.role).get('asset')
res = gen_resource({'user': self.user, 'asset': self.assets, 'role': self.role}) res = gen_resource({'user': self.user, 'asset': self.assets, 'role': self.role})
logger.debug('Web执行命令res: %s' % res) self.runner = MyRunner(res)
self.cmd = Command(res) message = '有权限的主机: ' + ', '.join([asset.hostname for asset in self.assets])
message = '有权限的主机:' + ', '.join([asset.hostname for asset in self.assets]) self.__class__.clients.append(self)
self.write_message(message) self.write_message(message)
def on_message(self, message): def on_message(self, message):
data = json.loads(message) data = json.loads(message)
pattern = data.get('pattern', '') pattern = data.get('pattern', '')
command = data.get('command', '') command = data.get('command', '')
asset_name_str = '匹配主机: ' asset_name_str = ''
if pattern and command: if pattern and command:
for inv in self.cmd.inventory.get_hosts(pattern=pattern): for inv in self.runner.inventory.get_hosts(pattern=pattern):
asset_name_str += '\n%s' % inv.name asset_name_str += '%s ' % inv.name
self.write_message(asset_name_str) self.write_message('匹配主机: ' + asset_name_str)
self.write_message('<span style="color: yellow">Ansible> %s</span>\n\n' % command) self.write_message('<span style="color: yellow">Ansible> %s</span>\n\n' % command)
result = self.cmd.run(module_name='shell', command=command, pattern=pattern) self.__class__.tasks.append(MyThread(target=self.run_cmd, args=(command, pattern)))
for k, v in result.items(): ExecLog(host=asset_name_str, cmd=command, user=self.user.username, remote_ip=self.remote_ip).save()
for t in self.__class__.tasks:
if t.is_alive():
continue
try:
t.setDaemon(True)
t.start()
except RuntimeError:
pass
def run_cmd(self, command, pattern):
self.runner.run('shell', command, pattern=pattern)
for k, v in self.runner.results.items():
for host, output in v.items(): for host, output in v.items():
if k == 'ok': if k == 'ok':
header = "<span style='color: green'>[ %s => %s]</span>\n" % (host, 'Ok') header = "<span style='color: green'>[ %s => %s]</span>\n" % (host, 'Ok')
...@@ -263,8 +279,12 @@ class ExecHandler(tornado.websocket.WebSocketHandler): ...@@ -263,8 +279,12 @@ class ExecHandler(tornado.websocket.WebSocketHandler):
header = "<span style='color: red'>[ %s => %s]</span>\n" % (host, 'failed') header = "<span style='color: red'>[ %s => %s]</span>\n" % (host, 'failed')
self.write_message(header) self.write_message(header)
self.write_message(output) self.write_message(output)
self.write_message('\n~o~ Task finished ~o~\n') self.write_message('\n~o~ Task finished ~o~\n')
def on_close(self):
logger.debug('关闭web_exec请求')
class WebTerminalHandler(tornado.websocket.WebSocketHandler): class WebTerminalHandler(tornado.websocket.WebSocketHandler):
clients = [] clients = []
......
...@@ -2822,7 +2822,9 @@ body.body-small .footer.fixed { ...@@ -2822,7 +2822,9 @@ body.body-small .footer.fixed {
.table > thead > tr > td, .table > thead > tr > td,
.table > tbody > tr > td, .table > tbody > tr > td,
.table > tfoot > tr > td { .table > tfoot > tr > td {
border-top: 1px solid #e7eaec; /*border-top: 1px solid #e7eaec;*/
border-bottom: 1px solid #e7eaec;
border-top: none;
line-height: 1.42857; line-height: 1.42857;
padding: 8px; padding: 8px;
vertical-align: top; vertical-align: top;
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<div class="wrapper wrapper-content animated fadeIn"> <div class="wrapper wrapper-content animated fadeIn">
<div class="row"> <div class="row">
<div class="col-lg-12"> <div class="col-sm-12">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5>下载文件</h5> <h5>下载文件</h5>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<head> <head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=320, initial-scale=1"> <meta name="viewport" content="width=320, initial-scale=1">
<title>Chat</title> <title>Jumpserver Exec Terminal</title>
<style type="text/css"></style> <style type="text/css"></style>
</head> </head>
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<div class="wrapper wrapper-content"> <div class="wrapper wrapper-content">
<div class="row"> <div class="row">
<div class="col-lg-3"> <div class="col-sm-3">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<span class="label label-success pull-right">Users</span> <span class="label label-success pull-right">Users</span>
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-lg-3"> <div class="col-sm-3">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<span class="label label-info pull-right">Hosts</span> <span class="label label-info pull-right">Hosts</span>
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
</div> </div>
</div> </div>
<div class="col-lg-3"> <div class="col-sm-3">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<span class="label label-primary pull-right">Online</span> <span class="label label-primary pull-right">Online</span>
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
</div> </div>
</div> </div>
<div class="col-lg-3"> <div class="col-sm-3">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<span class="label label-danger pull-right">Connected</span> <span class="label label-danger pull-right">Connected</span>
...@@ -74,7 +74,7 @@ ...@@ -74,7 +74,7 @@
</ul> </ul>
</div> </div>
<div class="col-sm-7" id="top10" style="margin-left: -15px;height: 346px;padding: 15px 0 15px 0;"></div> <div class="col-sm-7" id="top10" style="margin-left: -15px;height: 346px;padding: 15px 0 15px 0;"></div>
<div class="col-lg-3 white-bg" id="top1" style="margin-left: -15px;height: 346px"> <div class="col-sm-3 white-bg" id="top1" style="margin-left: -15px;height: 346px">
<div class="statistic-box"> <div class="statistic-box">
<h4> <h4>
活跃用户资产占比 活跃用户资产占比
...@@ -83,13 +83,13 @@ ...@@ -83,13 +83,13 @@
以下图形分别描述一个月活跃用户和资产占所有用户主机的百分比 以下图形分别描述一个月活跃用户和资产占所有用户主机的百分比
</p> </p>
<div class="row text-center"> <div class="row text-center">
<div class="col-lg-6"> <div class="col-sm-6">
<div id="activeUser" style="width: 140px; height: 140px;"> <div id="activeUser" style="width: 140px; height: 140px;">
</div> </div>
<h5>用户</h5> <h5>用户</h5>
</div> </div>
<div class="col-lg-6"> <div class="col-sm-6">
<div id="activeAsset" style="width: 140px; height: 140px;"></div> <div id="activeAsset" style="width: 140px; height: 140px;"></div>
<h5>主机</h5> <h5>主机</h5>
</div> </div>
...@@ -103,7 +103,7 @@ ...@@ -103,7 +103,7 @@
<br/> <br/>
<div class="row"> <div class="row">
<div class="col-lg-4"> <div class="col-sm-4">
{# <div class="ibox float-e-margins">#} {# <div class="ibox float-e-margins">#}
{# <div class="ibox-title">#} {# <div class="ibox-title">#}
{# <h5>权限申请</h5>#} {# <h5>权限申请</h5>#}
...@@ -192,7 +192,7 @@ ...@@ -192,7 +192,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-lg-4"> <div class="col-sm-4">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5>最近十次登录</h5> <h5>最近十次登录</h5>
...@@ -258,7 +258,7 @@ ...@@ -258,7 +258,7 @@
</div> </div>
</div> </div>
<div class="col-lg-4"> <div class="col-sm-4">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5>一周Top10用户</h5> <h5>一周Top10用户</h5>
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<div class="wrapper wrapper-content" xmlns="http://www.w3.org/1999/html"> <div class="wrapper wrapper-content" xmlns="http://www.w3.org/1999/html">
<div class="row"> <div class="row">
<div class="col-sm-8"> <div class="col-sm-8">
<div class="col-lg-12"> <div class="col-sm-12">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5> 使用说明 </h5> <h5> 使用说明 </h5>
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-lg-12"> <div class="col-sm-12">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5>登录记录</h5> <h5>登录记录</h5>
...@@ -85,7 +85,7 @@ ...@@ -85,7 +85,7 @@
</div> </div>
</div> </div>
<div class="col-lg-4"> <div class="col-sm-4">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<span class="label label-primary"><b>{{ user.username }}</b></span> <span class="label label-primary"><b>{{ user.username }}</b></span>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
{% include 'nav_cat_bar.html' %} {% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title"> <div id="ibox-content" class="ibox-title">
<h5> 填写资产基本信息 </h5> <h5> 填写资产基本信息 </h5>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
</style> </style>
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title"> <div id="ibox-content" class="ibox-title">
<h5> 填写主机基本信息 </h5> <h5> 填写主机基本信息 </h5>
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
{% include 'nav_cat_bar.html' %} {% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-4"> <div class="col-sm-4">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<span class="text text-primary"><b>{{ asset.ip }}</b></span> <span class="text text-primary"><b>{{ asset.ip }}</b></span>
...@@ -167,7 +167,7 @@ ...@@ -167,7 +167,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-lg-4"> <div class="col-sm-4">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5>拥有权限的用户</h5> <h5>拥有权限的用户</h5>
...@@ -291,7 +291,7 @@ ...@@ -291,7 +291,7 @@
</div> </div>
</div> </div>
<div class="col-lg-4"> <div class="col-sm-4">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5>最近一周登录记录</h5> <h5>最近一周登录记录</h5>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
{% include 'nav_cat_bar.html' %} {% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title"> <div id="ibox-content" class="ibox-title">
<h5> 修改资产基本信息 </h5> <h5> 修改资产基本信息 </h5>
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
<body> <body>
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
{# <div class="ibox-title">#} {# <div class="ibox-title">#}
{# <h5 class="text-center"> 填写修改主机信息. </h5>#} {# <h5 class="text-center"> 填写修改主机信息. </h5>#}
......
...@@ -194,7 +194,7 @@ ...@@ -194,7 +194,7 @@
title: title, title: title,
maxmin: true, maxmin: true,
shade: false, shade: false,
area: ['800px', '700px'], area: ['800px', '600px'],
content: new_url+data+'&check_assets='+check_assets content: new_url+data+'&check_assets='+check_assets
}); });
//window.open(new_url + data, '', 'location=no, resizeable=no, height=410, width=625, top=89px, left=99px,toolbar=no,menubar=no,scrollbars=auto,status=no'); //window.open(new_url + data, '', 'location=no, resizeable=no, height=410, width=625, top=89px, left=99px,toolbar=no,menubar=no,scrollbars=auto,status=no');
...@@ -282,7 +282,7 @@ ...@@ -282,7 +282,7 @@
type: 2, type: 2,
title: title, title: title,
maxmin: true, maxmin: true,
area: ['800px', '700px'], area: ['800px', '600px'],
shade: false, shade: false,
content: new_url content: new_url
}); });
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title"> <div id="ibox-content" class="ibox-title">
<h5> 填写主机组基本信息 </h5> <h5> 填写主机组基本信息 </h5>
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title"> <div id="ibox-content" class="ibox-title">
<h5> 填写主机组基本信息 </h5> <h5> 填写主机组基本信息 </h5>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5> 主机组详细信息列表</h5> <h5> 主机组详细信息列表</h5>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
{% include 'nav_cat_bar.html' %} {% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title"> <div id="ibox-content" class="ibox-title">
<h5> 填写IDC基本信息 </h5> <h5> 填写IDC基本信息 </h5>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
{% include 'nav_cat_bar.html' %} {% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title"> <div id="ibox-content" class="ibox-title">
<h5> 填写IDC基本信息 </h5> <h5> 填写IDC基本信息 </h5>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5> IDC详细信息列表</h5> <h5> IDC详细信息列表</h5>
......
{% extends 'base.html' %}
{% load mytags %}
{% block content %}
{% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-sm-4">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span class="label label-primary"><b>{{ log.id }}</b></span>
<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">
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<div>
<div class="text-left">
<table class="table">
<tr>
<td class="text-navy">ID</td>
<td>{{ log.id }}</td>
</tr>
<tr>
<td class="text-navy">用户名</td>
<td>{{ log.user }}</td>
</tr>
<tr>
<td class="text-navy">来源IP</td>
<td>{{ log.remote_ip }}</td>
</tr>
<tr>
<td class="text-navy">日期</td>
<td>{{ log.datetime|date:"Y-m-d H:i:s" }}</td>
</tr>
<tr>
<td class="text-navy">主机</td>
<td>
<table class="table">
{% for asset_name in assets_hostname %}
{% if asset_name %}
<tr>
<td>{{ asset_name }}</td>
</tr>
{% endif %}
{% endfor %}
</table>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm-8">
<div class="ibox float-e-margins">
<div 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">
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content inspinia-timeline">
<div>
<div class="text-left">
<table class="table">
<tr>
<td class="text-navy">命令</td>
<td>{{ log.cmd }}</td>
</tr>
{% for result, info in result.items %}
{% for host, msg in info.items %}
{% ifequal result 'failed' %}
<tr>
<td class="text-navy" style="color: #ed5565">{{ host }}</td>
<td>{{ msg }}</td>
</tr>
{% else %}
<tr>
<td class="text-navy">{{ host }}</td>
<td>{{ msg }}</td>
</tr>
{% endifequal %}
{% endfor %}
{% endfor %}
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function(){
$('#show').click(function(){
$('#last').css('display', 'none');
$('#all').css('display', 'block');
})
})
</script>
{% endblock %}
\ No newline at end of file
{% extends 'base.html' %}
{% block self_head_css_js %}
<link href="/static/css/plugins/datepicker/datepicker3.css" rel="stylesheet">
<link href="/static/css/plugins/chosen/chosen.css" rel="stylesheet">
<script src="/static/js/plugins/chosen/chosen.jquery.js"></script>
{% endblock %}
{% block content %}
{% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-sm-10">
<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>
<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><a href="/jlog/log_list/offline/" class="text-center"><i class="fa fa-bar-chart-o"></i> 历史记录 </a></li>
<li class="active"><a href="/jlog/log_list/exec/" class="text-center"><i class="fa fa-bar-chart-o"></i> 命令记录 </a></li>
<li><a href="/jlog/log_list/file/" class="text-center"><i class="fa fa-bar-chart-o"></i> 上传下载 </a></li>
</ul>
</div>
<br/>
<div class="">
<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="keyword" name="keyword" value="{{ keyword }}" placeholder="Search">
<div class="input-group-btn">
<button id='search_btn' type="submit" class="btn btn-sm btn-primary">
-搜索-
</button>
</div>
</div>
</form>
</div>
<div class="tab-content">
<table class="table table-striped table-bordered table-hover ">
<thead>
<tr>
<th class="text-center"> ID </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"> 时间 </th>
<th class="text-center"> 详情 </th>
</tr>
</thead>
<tbody>
{% for post in contacts.object_list %}
<tr class="gradeX">
<td class="text-center"> {{ post.id }} </td>
<td class="text-center username"> {{ post.user }} </td>
<td class="text-center ip"> {{ post.host | truncatechars:30 }} </td>
<td class="text-center ip"> {{ post.cmd | truncatechars:30 }} </td>
<td class="text-center remote_ip"> {{ post.remote_ip }} </td>
<td class="text-center start_time"> {{ post.datetime|date:"Y-m-d H:i:s"}} </td>
<td class="text-center">
<a href="/jlog/log_detail/exec/?id={{ post.id }}" class="btn btn-xs btn-primary">详情</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="row">
<div class="col-sm-6">
</div>
{% include 'paginator.html' %}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
function log_search(){
$.ajax({
type: "GET",
url: "/jlog/search/?env=offline",
data: $("#search_form").serialize(),
success: function (data) {
$(".tab-content").html(data);
}
});
}
</script>
{% endblock %}
{% extends 'base.html' %}
{% block self_head_css_js %}
<link href="/static/css/plugins/datepicker/datepicker3.css" rel="stylesheet">
<link href="/static/css/plugins/chosen/chosen.css" rel="stylesheet">
<script src="/static/js/plugins/chosen/chosen.jquery.js"></script>
{% endblock %}
{% block content %}
{% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-sm-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>
<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><a href="/jlog/log_list/offline/" class="text-center"><i class="fa fa-bar-chart-o"></i> 历史记录 </a></li>
<li><a href="/jlog/log_list/exec/" class="text-center"><i class="fa fa-bar-chart-o"></i> 命令记录 </a></li>
<li class="active"><a href="/jlog/log_list/file/" class="text-center"><i class="fa fa-bar-chart-o"></i> 上传下载 </a></li>
</ul>
</div>
<br/>
<div class="">
<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="keyword" name="keyword" value="{{ keyword }}" placeholder="Search">
<div class="input-group-btn">
<button id='search_btn' type="submit" class="btn btn-sm btn-primary">
-搜索-
</button>
</div>
</div>
</form>
</div>
<div class="tab-content">
<table class="table table-striped table-bordered table-hover ">
<thead>
<tr>
<th class="text-center"> ID </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"> 时间 </th>
<th class="text-center"> 详情 </th>
</tr>
</thead>
<tbody>
{% for post in contacts.object_list %}
<tr class="gradeX">
<td class="text-center"> {{ post.id }} </td>
<td class="text-center"> {{ post.user }} </td>
<td class="text-center"> {{ post.host | truncatechars:30 }} </td>
<td class="text-center"> {{ post.filename | truncatechars:30 }} </td>
<td class="text-center"> {{ post.type }} </td>
<td class="text-center"> {{ post.remote_ip }} </td>
<td class="text-center"> {{ post.datetime|date:"Y-m-d H:i:s"}} </td>
<td class="text-center">
<a href="/jlog/log_detail/file/?id={{ post.id }}" class="btn btn-xs btn-primary">详情</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div class="row">
<div class="col-sm-6">
</div>
{% include 'paginator.html' %}
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
function log_search(){
$.ajax({
type: "GET",
url: "/jlog/search/?env=offline",
data: $("#search_form").serialize(),
success: function (data) {
$(".tab-content").html(data);
}
});
}
</script>
{% endblock %}
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-12"> <div class="col-sm-12">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title"> <div id="ibox-content" class="ibox-title">
<h5> 用户日志详细信息列表 </h5> <h5> 用户日志详细信息列表 </h5>
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-12"> <div class="col-sm-12">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title"> <div id="ibox-content" class="ibox-title">
<h5> 用户日志详细信息列表 </h5> <h5> 用户日志详细信息列表 </h5>
...@@ -54,6 +54,8 @@ ...@@ -54,6 +54,8 @@
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li><a href="/jlog/log_list/online/" class="text-center"><i class="fa fa-laptop"></i> 在线 </a></li> <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 class="active"><a href="/jlog/log_list/offline/" class="text-center"><i class="fa fa-bar-chart-o"></i> 历史记录 </a></li>
<li><a href="/jlog/log_list/exec/" class="text-center"><i class="fa fa-bar-chart-o"></i> 命令记录 </a></li>
<li><a href="/jlog/log_list/file/" class="text-center"><i class="fa fa-bar-chart-o"></i> 上传下载 </a></li>
</ul> </ul>
</div> </div>
<br/> <br/>
......
...@@ -47,7 +47,7 @@ ...@@ -47,7 +47,7 @@
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-12"> <div class="col-sm-12">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title"> <div id="ibox-content" class="ibox-title">
<h5> 用户日志详细信息列表 </h5> <h5> 用户日志详细信息列表 </h5>
...@@ -69,6 +69,8 @@ ...@@ -69,6 +69,8 @@
<ul class="nav nav-tabs"> <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 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><a href="/jlog/log_list/offline/" class="text-center"><i class="fa fa-bar-chart-o"></i> 历史记录 </a></li>
<li><a href="/jlog/log_list/exec/" class="text-center"><i class="fa fa-bar-chart-o"></i> 命令记录 </a></li>
<li><a href="/jlog/log_list/file/" class="text-center"><i class="fa fa-bar-chart-o"></i> 上传下载 </a></li>
</ul> </ul>
</div> </div>
<br/> <br/>
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-12"> <div class="col-sm-12">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div id="ibox-content" class="ibox-title"> <div id="ibox-content" class="ibox-title">
<h5> 用户{{ username }}日志详细信息列表 </h5> <h5> 用户{{ username }}日志详细信息列表 </h5>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5> {{ user_group.name }}授权修改</h5> <h5> {{ user_group.name }}授权修改</h5>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5> 查看小组</h5> <h5> 查看小组</h5>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5> 查看小组</h5> <h5> 查看小组</h5>
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
{% include 'nav_cat_bar.html' %} {% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5>填写基本信息</h5> <h5>填写基本信息</h5>
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
<div class="col-sm-4"> <div class="col-sm-4">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<span class="label label-primary"><b>授权规则</b></span> <span class="label label-primary"><b>{{ role.name }} - 授权规则</b></span>
<div class="ibox-tools"> <div class="ibox-tools">
<a class="collapse-link"> <a class="collapse-link">
<i class="fa fa-chevron-up"></i> <i class="fa fa-chevron-up"></i>
...@@ -54,7 +54,7 @@ ...@@ -54,7 +54,7 @@
<div class="col-sm-4"> <div class="col-sm-4">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<span class="label label-primary"><b>授权用户/用户组</b></span> <span class="label label-primary"><b>{{ role.name }} - 授权用户/用户组</b></span>
<div class="ibox-tools"> <div class="ibox-tools">
<a class="collapse-link"> <a class="collapse-link">
<i class="fa fa-chevron-up"></i> <i class="fa fa-chevron-up"></i>
...@@ -100,7 +100,7 @@ ...@@ -100,7 +100,7 @@
<div class="col-sm-4"> <div class="col-sm-4">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<span class="label label-primary"><b>授权主机/主机组</b></span> <span class="label label-primary"><b>{{ role.name }} - 授权主机/主机组</b></span>
<div class="ibox-tools"> <div class="ibox-tools">
<a class="collapse-link"> <a class="collapse-link">
<i class="fa fa-chevron-up"></i> <i class="fa fa-chevron-up"></i>
...@@ -148,7 +148,7 @@ ...@@ -148,7 +148,7 @@
<div class="col-sm-6"> <div class="col-sm-6">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<span class="label label-primary"><b>推送主机</b></span> <span class="label label-primary"><b>{{ role.name }} - 推送主机</b></span>
<div class="ibox-tools"> <div class="ibox-tools">
<a class="collapse-link"> <a class="collapse-link">
<i class="fa fa-chevron-up"></i> <i class="fa fa-chevron-up"></i>
...@@ -212,7 +212,7 @@ ...@@ -212,7 +212,7 @@
<div class="col-sm-4"> <div class="col-sm-4">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<span class="label label-danger"><b>未推送主机</b></span> <span class="label label-danger"><b>{{ role.name }} - 未推送主机</b></span>
<div class="ibox-tools"> <div class="ibox-tools">
<a class="collapse-link"> <a class="collapse-link">
<i class="fa fa-chevron-up"></i> <i class="fa fa-chevron-up"></i>
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
{% include 'nav_cat_bar.html' %} {% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5>填写基本信息</h5> <h5>填写基本信息</h5>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div> <div>
{% if error %} {% if error %}
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
{% include 'nav_cat_bar.html' %} {% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5>填写基本信息</h5> <h5>填写基本信息</h5>
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
{% include 'nav_cat_bar.html' %} {% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5>填写基本信息</h5> <h5>填写基本信息</h5>
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-4"> <div class="col-sm-4">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<span class="label label-primary"><b>{{ rule.name }}</b></span> <span class="label label-primary"><b>{{ rule.name }}</b></span>
...@@ -60,7 +60,7 @@ ...@@ -60,7 +60,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-lg-4"> <div class="col-sm-4">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<span class="label label-primary"><b>授权用户/用户组</b></span> <span class="label label-primary"><b>授权用户/用户组</b></span>
...@@ -106,7 +106,7 @@ ...@@ -106,7 +106,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-lg-4"> <div class="col-sm-4">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<span class="label label-primary"><b>授权主机/主机组</b></span> <span class="label label-primary"><b>授权主机/主机组</b></span>
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
{% include 'nav_cat_bar.html' %} {% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5>填写基本信息</h5> <h5>填写基本信息</h5>
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div> <div>
{% if error %} {% if error %}
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
{% include 'nav_cat_bar.html' %} {% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5>填写基本信息</h5> <h5>填写基本信息</h5>
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
{% include 'nav_cat_bar.html' %} {% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5>填写基本信息</h5> <h5>填写基本信息</h5>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div> <div>
{% if error %} {% if error %}
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
{% include 'nav_cat_bar.html' %} {% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="panel blank-panel"> <div class="panel blank-panel">
<div class="panel-heading"> <div class="panel-heading">
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-12"> <div class="col-sm-12">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="panel blank-panel"> <div class="panel blank-panel">
<div class="panel-heading"> <div class="panel-heading">
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
{% include 'nav_cat_bar.html' %} {% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5>编辑用户信息</h5> <h5>编辑用户信息</h5>
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
{% include 'nav_cat_bar.html' %} {% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5>填写基本信息</h5> <h5>填写基本信息</h5>
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-12"> <div class="col-sm-12">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5> 命令批量执行 </h5> <h5> 命令批量执行 </h5>
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
{% include 'nav_cat_bar.html' %} {% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5>填写基本信息</h5> <h5>填写基本信息</h5>
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
{% include 'nav_cat_bar.html' %} {% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-4"> <div class="col-sm-4">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<span class="label label-primary"><b>{{ user.name }}</b></span> <span class="label label-primary"><b>{{ user.name }}</b></span>
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-lg-4"> <div class="col-sm-4">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5>授权主机/组</h5> <h5>授权主机/组</h5>
...@@ -137,7 +137,7 @@ ...@@ -137,7 +137,7 @@
</div> </div>
</div> </div>
<div class="col-lg-4"> <div class="col-sm-4">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5>登录记录</h5> <h5>登录记录</h5>
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
{% include 'nav_cat_bar.html' %} {% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5>编辑用户信息</h5> <h5>编辑用户信息</h5>
...@@ -55,7 +55,7 @@ ...@@ -55,7 +55,7 @@
</div> </div>
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<div class="form-group"> <div class="form-group">
<label for="groups" class="col-lg-2 control-label">小组</label> <label for="groups" class="col-sm-2 control-label">小组</label>
<div class="col-sm-8"> <div class="col-sm-8">
<select id="groups" name="groups" class="form-control m-b" multiple size="12"> <select id="groups" name="groups" class="form-control m-b" multiple size="12">
{% for group in group_all %} {% for group in group_all %}
...@@ -70,7 +70,7 @@ ...@@ -70,7 +70,7 @@
</div> </div>
<div class="hr-line-dashed"></div> <div class="hr-line-dashed"></div>
<div class="form-group"> <div class="form-group">
<label for="role" class="col-lg-2 control-label">角色<span class="red-fonts">*</span></label> <label for="role" class="col-sm-2 control-label">角色<span class="red-fonts">*</span></label>
<div class="col-sm-8"> <div class="col-sm-8">
{% for r, role_name in user_role.items %} {% for r, role_name in user_role.items %}
<div class="col-sm-3"> <div class="col-sm-3">
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-12"> <div class="col-sm-12">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5> 查看用户 </h5> <h5> 查看用户 </h5>
......
...@@ -99,7 +99,7 @@ ...@@ -99,7 +99,7 @@
{# <div id="message"></div>#} {# <div id="message"></div>#}
{# </div>#} {# </div>#}
{# </div>#} {# </div>#}
<div class="col-lg-12"> <div class="col-sm-12">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title" style="border: solid"> <div class="ibox-title" style="border: solid">
<h5> 实时监控 </h5> <h5> 实时监控 </h5>
......
...@@ -27,19 +27,24 @@ ...@@ -27,19 +27,24 @@
<li class="rule perm_rule_add"> <li class="rule perm_rule_add">
<a href="/jperm/rule/">授权规则</a> <a href="/jperm/rule/">授权规则</a>
</li> </li>
<li class="role"> <li class="role">
<a href="/jperm/role/">系统角色</a> <a href="/jperm/role/">系统角色</a>
</li> </li>
<li class="sudo"> <li class="sudo">
<a href="/jperm/sudo/">Sudo命令</a> <a href="/jperm/sudo/">Sudo命令</a>
</li> </li>
</ul> </ul>
</li> </li>
<li id="jlog"> <li id="jlog">
<a href="/jlog/log_list/online/"><i class="fa fa-files-o"></i> <span class="nav-label">日志审计</span><span class="label label-info pull-right"></span></a> <a href="/jlog/log_list/online/"><i class="fa fa-files-o"></i> <span class="nav-label">日志审计</span><span class="label label-info pull-right"></span></a>
</li> </li>
<li id="file">
<a href="#"><i class="fa fa-download"></i> <span class="nav-label">上传下载</span><span class="fa arrow"></span></a>
<ul class="nav nav-second-level">
<li class="upload"><a href="/file/upload/">文件上传</a></li>
<li class="download"><a href="/file/download/">文件下载</a></li>
</ul>
</li>
<li id="setting"> <li id="setting">
<a href="/setting/"><i class="fa fa-gears"></i> <span class="nav-label">设置</span><span class="label label-info pull-right"></span></a> <a href="/setting/"><i class="fa fa-gears"></i> <span class="nav-label">设置</span><span class="label label-info pull-right"></span></a>
</li> </li>
......
<div class="row wrapper border-bottom white-bg page-heading"> <div class="row wrapper border-bottom white-bg page-heading">
<div class="col-lg-10"> <div class="col-sm-10">
<h2>{{ header_title }}</h2> <h2>{{ header_title }}</h2>
<ol class="breadcrumb"> <ol class="breadcrumb">
<li> <li>
...@@ -17,6 +17,6 @@ ...@@ -17,6 +17,6 @@
{% endif %} {% endif %}
</ol> </ol>
</div> </div>
<div class="col-lg-2"> <div class="col-sm-2">
</div> </div>
</div> </div>
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
{% include 'nav_cat_bar.html' %} {% include 'nav_cat_bar.html' %}
<div class="wrapper wrapper-content animated fadeInRight"> <div class="wrapper wrapper-content animated fadeInRight">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5> 项目设置 </h5> <h5> 项目设置 </h5>
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</style> </style>
<div class="wrapper wrapper-content animated fadeIn"> <div class="wrapper wrapper-content animated fadeIn">
<div class="row"> <div class="row">
<div class="col-lg-10"> <div class="col-sm-10">
<div class="ibox float-e-margins"> <div class="ibox float-e-margins">
<div class="ibox-title"> <div class="ibox-title">
<h5>上传文件</h5> <h5>上传文件</h5>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment