mirror of https://github.com/jumpserver/jumpserver
Merge branch 'dev' of https://git.coding.net/jumpserver/jumpserver into dev
commit
0821e7cf41
|
@ -36,9 +36,10 @@ Web批量执行命令
|
||||||
### 文档
|
### 文档
|
||||||
|
|
||||||
* [访问wiki](https://github.com/ibuler/jumpserver/wiki)
|
* [访问wiki](https://github.com/ibuler/jumpserver/wiki)
|
||||||
* [快速安装](https://github.com/ibuler/jumpserver/wiki/快速安装)
|
* [快速安装](https://github.com/ibuler/jumpserver/wiki/Quickinstall)
|
||||||
* [名词解释](https://github.com/ibuler/jumpserver/wiki/名称解释)
|
* [名词解释](https://github.com/ibuler/jumpserver/wiki/Termexplain)
|
||||||
* [快速开始](https://github.com/ibuler/jumpserver/wiki/快速开始)
|
* [快速开始](https://github.com/ibuler/jumpserver/wiki/Quickstart)
|
||||||
|
* [FAQ](https://github.com/ibuler/jumpserver/wiki/FAQs)
|
||||||
|
|
||||||
### 特点
|
### 特点
|
||||||
|
|
||||||
|
|
13
connect.py
13
connect.py
|
@ -1,3 +1,4 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
@ -290,7 +291,7 @@ class Tty(object):
|
||||||
|
|
||||||
# 发起ssh连接请求 Make a ssh connection
|
# 发起ssh连接请求 Make a ssh connection
|
||||||
ssh = paramiko.SSHClient()
|
ssh = paramiko.SSHClient()
|
||||||
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:
|
||||||
role_key = connect_info.get('role_key')
|
role_key = connect_info.get('role_key')
|
||||||
|
@ -527,7 +528,7 @@ class Nav(object):
|
||||||
user_asset_search = user_asset_all
|
user_asset_search = user_asset_all
|
||||||
|
|
||||||
self.search_result = dict(zip(range(len(user_asset_search)), user_asset_search))
|
self.search_result = dict(zip(range(len(user_asset_search)), user_asset_search))
|
||||||
color_print('[%-3s] %-12s %-15s %-5s %-10s %s' % ('ID', u'主机名', 'IP', u'端口', u'系统用户', u'备注'), 'title')
|
color_print('[%-3s] %-12s %-15s %-5s %-10s %s' % ('ID', '主机名', 'IP', '端口', '系统用户', '备注'), 'title')
|
||||||
for index, asset in self.search_result.items():
|
for index, asset in self.search_result.items():
|
||||||
# 获取该资产信息
|
# 获取该资产信息
|
||||||
asset_info = get_asset_info(asset)
|
asset_info = get_asset_info(asset)
|
||||||
|
@ -684,7 +685,7 @@ class Nav(object):
|
||||||
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)
|
||||||
asset_name_str = ''
|
asset_name_str = ''
|
||||||
print "匹配用户:\n"
|
print "匹配主机:\n"
|
||||||
for inv in runner.inventory.get_hosts(pattern=pattern):
|
for inv in runner.inventory.get_hosts(pattern=pattern):
|
||||||
asset_name_str += '%s ' % inv.name
|
asset_name_str += '%s ' % inv.name
|
||||||
print ' %s' % inv.name
|
print ' %s' % inv.name
|
||||||
|
@ -734,7 +735,7 @@ def main():
|
||||||
主程序
|
主程序
|
||||||
"""
|
"""
|
||||||
if not login_user: # 判断用户是否存在
|
if not login_user: # 判断用户是否存在
|
||||||
color_print(u'没有该用户,或许你是以root运行的 No that user.', exits=True)
|
color_print('没有该用户,或许你是以root运行的 No that user.', exits=True)
|
||||||
|
|
||||||
gid_pattern = re.compile(r'^g\d+$')
|
gid_pattern = re.compile(r'^g\d+$')
|
||||||
nav = Nav(login_user)
|
nav = Nav(login_user)
|
||||||
|
@ -799,7 +800,9 @@ def main():
|
||||||
color_print('请输入正确ID', 'red')
|
color_print('请输入正确ID', 'red')
|
||||||
except ServerError, e:
|
except ServerError, e:
|
||||||
color_print(e, 'red')
|
color_print(e, 'red')
|
||||||
except IndexError:
|
except Exception, e:
|
||||||
|
color_print(e)
|
||||||
|
time.sleep(5)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
@ -109,7 +109,7 @@ class PreSetup(object):
|
||||||
|
|
||||||
def _test_db_conn(self):
|
def _test_db_conn(self):
|
||||||
try:
|
try:
|
||||||
MySQLdb.connect(host=self.db_host, port=self.db_port,
|
MySQLdb.connect(host=self.db_host, port=int(self.db_port),
|
||||||
user=self.db_user, passwd=self.db_pass, db=self.db)
|
user=self.db_user, passwd=self.db_pass, db=self.db)
|
||||||
color_print('连接数据库成功', 'green')
|
color_print('连接数据库成功', 'green')
|
||||||
return True
|
return True
|
||||||
|
@ -127,8 +127,11 @@ class PreSetup(object):
|
||||||
smtp.quit()
|
smtp.quit()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except (SMTPAuthenticationError, socket.timeout, socket.gaierror, SMTPSenderRefused, SMTPConnectError), e:
|
except Exception, e:
|
||||||
color_print(e, 'red')
|
color_print(e, 'red')
|
||||||
|
skip = raw_input('是否跳过(y/n) [n]? : ')
|
||||||
|
if skip == 'y':
|
||||||
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -147,7 +150,7 @@ class PreSetup(object):
|
||||||
bash('pip install -r requirements.txt')
|
bash('pip install -r requirements.txt')
|
||||||
|
|
||||||
def _input_ip(self):
|
def _input_ip(self):
|
||||||
ip = raw_input('\n请输入您服务器的IP地址,用户浏览器可以访问 [%s]: ' % get_ip_addr())
|
ip = raw_input('\n请输入您服务器的IP地址,用户浏览器可以访问 [%s]: ' % get_ip_addr()).strip()
|
||||||
self.ip = ip if ip else get_ip_addr()
|
self.ip = ip if ip else get_ip_addr()
|
||||||
|
|
||||||
def _input_mysql(self):
|
def _input_mysql(self):
|
||||||
|
@ -156,11 +159,11 @@ class PreSetup(object):
|
||||||
if mysql != 'n':
|
if mysql != 'n':
|
||||||
self._setup_mysql()
|
self._setup_mysql()
|
||||||
else:
|
else:
|
||||||
db_host = raw_input('请输入数据库服务器IP [127.0.0.1]: ')
|
db_host = raw_input('请输入数据库服务器IP [127.0.0.1]: ').strip()
|
||||||
db_port = int(raw_input('请输入数据库服务器端口 [3306]: '))
|
db_port = raw_input('请输入数据库服务器端口 [3306]: ').strip()
|
||||||
db_user = raw_input('请输入数据库服务器用户 [root]: ')
|
db_user = raw_input('请输入数据库服务器用户 [root]: ').strip()
|
||||||
db_pass = raw_input('请输入数据库服务器密码: ')
|
db_pass = raw_input('请输入数据库服务器密码: ').strip()
|
||||||
db = raw_input('请输入使用的数据库 [jumpserver]: ')
|
db = raw_input('请输入使用的数据库 [jumpserver]: ').strip()
|
||||||
|
|
||||||
if db_host: self.db_host = db_host
|
if db_host: self.db_host = db_host
|
||||||
if db_port: self.db_port = db_port
|
if db_port: self.db_port = db_port
|
||||||
|
|
|
@ -81,9 +81,9 @@ class Setup(object):
|
||||||
os.system('id %s &> /dev/null || useradd %s' % (self.admin_user, self.admin_user))
|
os.system('id %s &> /dev/null || useradd %s' % (self.admin_user, self.admin_user))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _cp_zzsh():
|
def _ensure_sh():
|
||||||
os.chdir(os.path.join(jms_dir, 'install'))
|
jshell = os.path.join(jms_dir, 'connect.py')
|
||||||
shutil.copy('zzjumpserver.sh', '/etc/profile.d/')
|
os.chmod(jshell, 0755)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _run_service():
|
def _run_service():
|
||||||
|
@ -97,7 +97,7 @@ class Setup(object):
|
||||||
self._sync_db()
|
self._sync_db()
|
||||||
self._input_admin()
|
self._input_admin()
|
||||||
self._create_admin()
|
self._create_admin()
|
||||||
self._cp_zzsh()
|
self._ensure_sh()
|
||||||
self._run_service()
|
self._run_service()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
if [ "$USER" == "admin" ] || [ "$USER" == "root" ] || [ "$USER" == "" ];then
|
|
||||||
echo ""
|
|
||||||
else
|
|
||||||
python /opt/jumpserver/connect.py
|
|
||||||
if [ $USER == 'guanghongwei' ];then
|
|
||||||
echo
|
|
||||||
else
|
|
||||||
exit 3
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
fi
|
|
|
@ -545,7 +545,7 @@ def perm_role_push(request):
|
||||||
if not failed_asset:
|
if not failed_asset:
|
||||||
msg = u'系统用户 %s 推送成功[ %s ]' % (role.name, ','.join(success_asset.keys()))
|
msg = u'系统用户 %s 推送成功[ %s ]' % (role.name, ','.join(success_asset.keys()))
|
||||||
else:
|
else:
|
||||||
error = u'系统用户 %s 推送失败 [ %s ], 推送成功 [ %s ]' % (role.name,
|
error = u'系统用户 %s 推送失败 [ %s ], 推送成功 [ %s ] 进入系统用户详情,查看失败原因' % (role.name,
|
||||||
','.join(failed_asset.keys()),
|
','.join(failed_asset.keys()),
|
||||||
','.join(success_asset.keys()))
|
','.join(success_asset.keys()))
|
||||||
return my_render('jperm/perm_role_push.html', locals(), request)
|
return my_render('jperm/perm_role_push.html', locals(), request)
|
||||||
|
|
|
@ -352,6 +352,10 @@ def exec_cmd(request):
|
||||||
def web_terminal(request):
|
def web_terminal(request):
|
||||||
asset_id = request.GET.get('id')
|
asset_id = request.GET.get('id')
|
||||||
role_name = request.GET.get('role')
|
role_name = request.GET.get('role')
|
||||||
|
asset = get_object(Asset, id=asset_id)
|
||||||
|
if asset:
|
||||||
|
print asset
|
||||||
|
hostname = asset.hostname
|
||||||
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())
|
||||||
|
|
||||||
|
|
|
@ -151,7 +151,8 @@ def server_add_user(username, password, ssh_key_pwd='', ssh_key_login_need=True)
|
||||||
add a system user in jumpserver
|
add a system user in jumpserver
|
||||||
在jumpserver服务器上添加一个用户
|
在jumpserver服务器上添加一个用户
|
||||||
"""
|
"""
|
||||||
bash("useradd '%s'; echo '%s'; echo '%s' | passwd --stdin '%s'" % (username, password, password, username))
|
bash("useradd -s %s/connect.py '%s'; echo '%s'; echo '%s' | passwd --stdin '%s'" %
|
||||||
|
(BASE_DIR, username, password, password, username))
|
||||||
if ssh_key_login_need:
|
if ssh_key_login_need:
|
||||||
gen_ssh_key(username, ssh_key_pwd)
|
gen_ssh_key(username, ssh_key_pwd)
|
||||||
|
|
||||||
|
|
|
@ -230,15 +230,14 @@ class ExecHandler(tornado.websocket.WebSocketHandler):
|
||||||
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', '')
|
self.command = data.get('command', '')
|
||||||
asset_name_str = ''
|
self.asset_name_str = ''
|
||||||
if pattern and command:
|
if pattern and self.command:
|
||||||
for inv in self.runner.inventory.get_hosts(pattern=pattern):
|
for inv in self.runner.inventory.get_hosts(pattern=pattern):
|
||||||
asset_name_str += '%s ' % inv.name
|
self.asset_name_str += '%s ' % inv.name
|
||||||
self.write_message('匹配主机: ' + asset_name_str)
|
self.write_message('匹配主机: ' + self.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' % self.command)
|
||||||
self.__class__.tasks.append(MyThread(target=self.run_cmd, args=(command, pattern)))
|
self.__class__.tasks.append(MyThread(target=self.run_cmd, args=(self.command, pattern)))
|
||||||
ExecLog(host=asset_name_str, cmd=command, user=self.user.username, remote_ip=self.remote_ip).save()
|
|
||||||
|
|
||||||
for t in self.__class__.tasks:
|
for t in self.__class__.tasks:
|
||||||
if t.is_alive():
|
if t.is_alive():
|
||||||
|
@ -251,11 +250,12 @@ class ExecHandler(tornado.websocket.WebSocketHandler):
|
||||||
|
|
||||||
def run_cmd(self, command, pattern):
|
def run_cmd(self, command, pattern):
|
||||||
self.runner.run('shell', command, pattern=pattern)
|
self.runner.run('shell', command, pattern=pattern)
|
||||||
|
ExecLog(host=self.asset_name_str, cmd=self.command, user=self.user.username,
|
||||||
|
remote_ip=self.remote_ip, result=self.runner.results).save()
|
||||||
newline_pattern = re.compile(r'\n')
|
newline_pattern = re.compile(r'\n')
|
||||||
for k, v in self.runner.results.items():
|
for k, v in self.runner.results.items():
|
||||||
for host, output in v.items():
|
for host, output in v.items():
|
||||||
output = newline_pattern.sub('<br />', output)
|
output = newline_pattern.sub('<br />', output)
|
||||||
logger.debug(output)
|
|
||||||
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')
|
||||||
else:
|
else:
|
||||||
|
@ -333,7 +333,13 @@ class WebTerminalHandler(tornado.websocket.WebSocketHandler):
|
||||||
data = json.loads(message)
|
data = json.loads(message)
|
||||||
if not data:
|
if not data:
|
||||||
return
|
return
|
||||||
if data.get('data'):
|
|
||||||
|
if 'resize' in data.get('data'):
|
||||||
|
self.channel.resize_pty(
|
||||||
|
data.get('data').get('resize').get('cols', 80),
|
||||||
|
data.get('data').get('resize').get('rows', 24)
|
||||||
|
)
|
||||||
|
elif data.get('data'):
|
||||||
self.term.input_mode = True
|
self.term.input_mode = True
|
||||||
if str(data['data']) in ['\r', '\n', '\r\n']:
|
if str(data['data']) in ['\r', '\n', '\r\n']:
|
||||||
if self.term.vim_flag:
|
if self.term.vim_flag:
|
||||||
|
@ -350,6 +356,8 @@ class WebTerminalHandler(tornado.websocket.WebSocketHandler):
|
||||||
self.term.data = ''
|
self.term.data = ''
|
||||||
self.term.input_mode = False
|
self.term.input_mode = False
|
||||||
self.channel.send(data['data'])
|
self.channel.send(data['data'])
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
def on_close(self):
|
def on_close(self):
|
||||||
logger.debug('Websocket: Close request')
|
logger.debug('Websocket: Close request')
|
||||||
|
|
|
@ -233,6 +233,7 @@
|
||||||
layer.alert('没有授权系统用户')
|
layer.alert('没有授权系统用户')
|
||||||
}
|
}
|
||||||
else if (dataArray.length == 1 && data != 'error' && navigator.platform == 'Win32'){
|
else if (dataArray.length == 1 && data != 'error' && navigator.platform == 'Win32'){
|
||||||
|
/*
|
||||||
var title = 'Jumpserver Web Terminal' + '<span class="text-info"> '+ hostname +'</span>';
|
var title = 'Jumpserver Web Terminal' + '<span class="text-info"> '+ hostname +'</span>';
|
||||||
layer.open({
|
layer.open({
|
||||||
type: 2,
|
type: 2,
|
||||||
|
@ -242,8 +243,10 @@
|
||||||
area: ['628px', '420px'],
|
area: ['628px', '420px'],
|
||||||
content: new_url+data
|
content: new_url+data
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
|
window.open(new_url+data, '', 'width=628px, height=420px')
|
||||||
} else if (dataArray.length == 1 && data != 'error'){
|
} else if (dataArray.length == 1 && data != 'error'){
|
||||||
layer.open({
|
/*layer.open({
|
||||||
type: 2,
|
type: 2,
|
||||||
title: title,
|
title: title,
|
||||||
maxmin: true,
|
maxmin: true,
|
||||||
|
@ -251,6 +254,9 @@
|
||||||
area: ['628px', '452px'],
|
area: ['628px', '452px'],
|
||||||
content: new_url+data
|
content: new_url+data
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
|
window.open(new_url+data, '', 'width=628px, height=440px')
|
||||||
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
aUrl = '';
|
aUrl = '';
|
||||||
|
@ -276,6 +282,7 @@
|
||||||
var hostname = $(a).attr('value');
|
var hostname = $(a).attr('value');
|
||||||
var title = 'Jumpserver Web Terminal - ' + '<span class="text-info"> '+ hostname +'</span>';
|
var title = 'Jumpserver Web Terminal - ' + '<span class="text-info"> '+ hostname +'</span>';
|
||||||
if (navigator.platform == 'Win32'){
|
if (navigator.platform == 'Win32'){
|
||||||
|
/*
|
||||||
layer.open({
|
layer.open({
|
||||||
type: 2,
|
type: 2,
|
||||||
title: title,
|
title: title,
|
||||||
|
@ -284,8 +291,11 @@
|
||||||
shade: false,
|
shade: false,
|
||||||
content: new_url
|
content: new_url
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
|
window.open(new_url, '', 'height=628px, width=420px')
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
/*
|
||||||
layer.open({
|
layer.open({
|
||||||
type: 2,
|
type: 2,
|
||||||
title: title,
|
title: title,
|
||||||
|
@ -294,6 +304,8 @@
|
||||||
shade: false,
|
shade: false,
|
||||||
content: new_url
|
content: new_url
|
||||||
});
|
});
|
||||||
|
*/
|
||||||
|
window.open(new_url, '', 'height=628px, width=452px')
|
||||||
}
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
|
@ -310,7 +322,6 @@
|
||||||
shade: false,
|
shade: false,
|
||||||
content: new_url
|
content: new_url
|
||||||
});
|
});
|
||||||
console.log(new_url);
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Jumpserver web terminal</title>
|
<title>Jumpserver Web Terminal: {{ hostname }}</title>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
|
@ -37,6 +37,8 @@
|
||||||
<script type="application/javascript" src="/static/js/term.js">
|
<script type="application/javascript" src="/static/js/term.js">
|
||||||
</script>
|
</script>
|
||||||
<script type="application/javascript">
|
<script type="application/javascript">
|
||||||
|
var rowHeight = 1;
|
||||||
|
var colWidth = 1;
|
||||||
function WSSHClient() {
|
function WSSHClient() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +103,22 @@
|
||||||
term.write(data);
|
term.write(data);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
rowHeight = 0.0 + 1.00 * $('.terminal').height() / 24 ;
|
||||||
|
colWidth = 0.0 + 1.00 * $('.terminal').width() / 80;
|
||||||
|
return {'term': term, 'client': client};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resize(){
|
||||||
|
$('.terminal').css('width', window.innerWidth-25);
|
||||||
|
console.log(window.innerWidth);
|
||||||
|
console.log(window.innerWidth-10);
|
||||||
|
var rows = Math.floor(window.innerHeight/rowHeight) - 1;
|
||||||
|
var cols = Math.floor(window.innerWidth/colWidth) - 1;
|
||||||
|
|
||||||
|
return {rows: rows, cols: cols};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type='application/javascript'>
|
<script type='application/javascript'>
|
||||||
|
@ -110,7 +127,17 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
$('#ssh').show();
|
$('#ssh').show();
|
||||||
openTerminal(options);
|
var term_client = openTerminal(options);
|
||||||
|
console.log(rowHeight);
|
||||||
|
|
||||||
|
window.onresize = function(){
|
||||||
|
var geom = resize();
|
||||||
|
console.log(geom);
|
||||||
|
term_client.term.resize(geom.cols, geom.rows);
|
||||||
|
term_client.client.send({'resize': {'roles': geom.rows, 'cols': geom.cols}});
|
||||||
|
$('#ssh').show();
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -204,7 +204,7 @@
|
||||||
{% if info.success %}
|
{% if info.success %}
|
||||||
<td class="text-center" style="color: #1ab394;" >{{ info.success | yesno:"成功,失败,未知" }} </td>
|
<td class="text-center" style="color: #1ab394;" >{{ info.success | yesno:"成功,失败,未知" }} </td>
|
||||||
{% else %}
|
{% else %}
|
||||||
<td class="text-center" style="color: #ec4758;cursor: help" title="{{ info.result }}" >{{ info.success | yesno:"成功,失败,未知" }} </td>
|
<td class="text-center push_failed" style="color: #ec4758;cursor: help" title="{{ info.result }}">{{ info.success | yesno:"成功,失败,未知" }} </td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<td class="text-center" ><a class="fa fa-times del" href="{% url 'role_recycle' %}?role_id={{ role.id }}&asset_id={{ asset.id }}" style="color: #ec4758;"></a></td>
|
<td class="text-center" ><a class="fa fa-times del" href="{% url 'role_recycle' %}?role_id={{ role.id }}&asset_id={{ asset.id }}" style="color: #ec4758;"></a></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -321,7 +321,16 @@
|
||||||
});
|
});
|
||||||
var url = '/jperm/role/push/?id={{ role.id }}&asset_id=' + check_array.join(',');
|
var url = '/jperm/role/push/?id={{ role.id }}&asset_id=' + check_array.join(',');
|
||||||
$(this).attr('href', url)
|
$(this).attr('href', url)
|
||||||
})
|
});
|
||||||
|
|
||||||
|
$('.push_failed').click(function() {
|
||||||
|
var fail_reason = $(this).attr('title');
|
||||||
|
layer.alert(fail_reason, {
|
||||||
|
skin: 'layui-layer-molv',
|
||||||
|
area: '500px'
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -67,7 +67,7 @@
|
||||||
<div class="col-sm-8">
|
<div class="col-sm-8">
|
||||||
<select name="asset" id="asset" data-placeholder="请选择资产" class="chosen-select form-control m-b" multiple tabindex="2">
|
<select name="asset" id="asset" data-placeholder="请选择资产" class="chosen-select form-control m-b" multiple tabindex="2">
|
||||||
{% for asset in assets %}
|
{% for asset in assets %}
|
||||||
<option value="{{ asset.id }}"{% if asset in rule.asset.all %} selected {% endif %}>{{ asset.ip }}</option>
|
<option value="{{ asset.id }}"{% if asset in rule.asset.all %} selected {% endif %}>{{ asset.hostname }}</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
<span class="help-block m-b-none">资产和资产组必选一个</span>
|
<span class="help-block m-b-none">资产和资产组必选一个</span>
|
||||||
|
|
|
@ -113,12 +113,12 @@ $('#userForm').validator({
|
||||||
|
|
||||||
$("document").ready(function() {
|
$("document").ready(function() {
|
||||||
$("#regen_ssh_key").click(function () {
|
$("#regen_ssh_key").click(function () {
|
||||||
alert('申请已提交,请等待,请勿重复提交');
|
layer.alert('申请已提交,请等待,请勿重复提交');
|
||||||
$.get(
|
$.get(
|
||||||
$(this).attr('value'),
|
$(this).attr('value'),
|
||||||
{},
|
{},
|
||||||
function(data){
|
function(data){
|
||||||
alert(data)
|
layer.alert(data)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue