mirror of https://github.com/jumpserver/jumpserver
完成web批量命令执行
parent
104ee779e7
commit
1f26e49fb8
|
@ -24,7 +24,7 @@ if django.get_version() != '1.6':
|
|||
from django.contrib.sessions.models import Session
|
||||
from jumpserver.api import ServerError, User, Asset, PermRole, AssetGroup, get_object, mkdir, get_asset_info, get_role
|
||||
from jumpserver.api import logger, Log, TtyLog, get_role_key, CRYPTOR, bash, get_tmp_dir
|
||||
from jperm.perm_api import gen_resource, get_group_asset_perm, get_group_user_perm, user_have_perm
|
||||
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 jperm.ansible_api import Command, MyRunner
|
||||
from jlog.log_api import escapeString
|
||||
|
|
|
@ -8,6 +8,7 @@ urlpatterns = patterns('',
|
|||
(r'^skin_config/$', 'jumpserver.views.skin_config'),
|
||||
(r'^login/$', 'jumpserver.views.Login'),
|
||||
(r'^logout/$', 'jumpserver.views.Logout'),
|
||||
(r'^exec_cmd/$', 'jumpserver.views.exec_cmd'),
|
||||
(r'^file/upload/$', 'jumpserver.views.upload'),
|
||||
(r'^file/download/$', 'jumpserver.views.download'),
|
||||
(r'^setting', 'jumpserver.views.setting'),
|
||||
|
|
|
@ -360,3 +360,8 @@ def download(request):
|
|||
return render_to_response('download.html', locals(), context_instance=RequestContext(request))
|
||||
|
||||
|
||||
@login_required(login_url='/login')
|
||||
def exec_cmd(request):
|
||||
role_name = request.GET.get('role_name')
|
||||
web_terminal_uri = 'ws://%s/exec?role=%s' % (WEB_SOCKET_HOST, role_name)
|
||||
return my_render('exec_cmd.html', locals(), request)
|
||||
|
|
|
@ -23,8 +23,8 @@ from tornado.options import define, options
|
|||
from pyinotify import WatchManager, Notifier, ProcessEvent, IN_DELETE, IN_CREATE, IN_MODIFY, AsyncNotifier
|
||||
import select
|
||||
|
||||
from connect import Tty, User, Asset, PermRole, logger, get_object
|
||||
from connect import TtyLog, Log, Session, user_have_perm
|
||||
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
|
||||
|
||||
try:
|
||||
import simplejson as json
|
||||
|
@ -67,22 +67,6 @@ def require_auth(role='user'):
|
|||
except AttributeError:
|
||||
pass
|
||||
logger.warning('Websocket: Request auth failed.')
|
||||
# asset_id = int(request.get_argument('id', 9999))
|
||||
# print asset_id
|
||||
# asset = Asset.objects.filter(id=asset_id)
|
||||
# if asset:
|
||||
# asset = asset[0]
|
||||
# request.asset = asset
|
||||
# else:
|
||||
# request.close()
|
||||
#
|
||||
# if user:
|
||||
# user = user[0]
|
||||
# request.user = user
|
||||
#
|
||||
# else:
|
||||
# print("No session user.")
|
||||
# request.close()
|
||||
return _deco2
|
||||
return _deco
|
||||
|
||||
|
@ -138,6 +122,7 @@ class Application(tornado.web.Application):
|
|||
(r'/monitor', MonitorHandler),
|
||||
(r'/terminal', WebTerminalHandler),
|
||||
(r'/kill', WebTerminalKillHandler),
|
||||
(r'/exec', ExecHandler),
|
||||
]
|
||||
|
||||
setting = {
|
||||
|
@ -225,6 +210,61 @@ class WebTerminalKillHandler(tornado.web.RequestHandler):
|
|||
logger.debug('Websocket: web terminal client num: %s' % len(WebTerminalHandler.clients))
|
||||
|
||||
|
||||
class ExecHandler(tornado.websocket.WebSocketHandler):
|
||||
clients = []
|
||||
tasks = []
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.id = 0
|
||||
self.user = None
|
||||
self.role = None
|
||||
self.cmd = None
|
||||
self.assets = []
|
||||
self.perm = {}
|
||||
super(ExecHandler, self).__init__(*args, **kwargs)
|
||||
|
||||
def check_origin(self, origin):
|
||||
return True
|
||||
|
||||
@require_auth('user')
|
||||
def open(self):
|
||||
logger.debug('Websocket: Open exec request')
|
||||
role_name = self.get_argument('role', 'dev')
|
||||
self.role = get_object(PermRole, name=role_name)
|
||||
self.perm = get_group_user_perm(self.user)
|
||||
roles = self.perm.get('role').keys()
|
||||
if self.role not in roles:
|
||||
self.write_message('No perm that role %s' % role_name)
|
||||
self.close()
|
||||
self.assets = self.perm.get('role').get(self.role).get('asset')
|
||||
res = gen_resource({'user': self.user, 'asset': self.assets, 'role': self.role})
|
||||
logger.debug('Web执行命令res: %s' % res)
|
||||
self.cmd = Command(res)
|
||||
message = '有权限的主机:' + ', '.join([asset.hostname for asset in self.assets])
|
||||
self.write_message(message)
|
||||
|
||||
def on_message(self, message):
|
||||
data = json.loads(message)
|
||||
pattern = data.get('pattern', '')
|
||||
command = data.get('command', '')
|
||||
asset_name_str = '匹配主机: '
|
||||
if pattern and command:
|
||||
for inv in self.cmd.inventory.get_hosts(pattern=pattern):
|
||||
asset_name_str += '\n%s' % inv.name
|
||||
self.write_message(asset_name_str)
|
||||
self.write_message('<span style="color: yellow">Ansible> %s</span>\n\n' % command)
|
||||
result = self.cmd.run(module_name='shell', command=command, pattern=pattern)
|
||||
for k, v in result.items():
|
||||
for host, output in v.items():
|
||||
if k == 'ok':
|
||||
header = "<span style='color: green'>[ %s => %s]</span>\n" % (host, 'Ok')
|
||||
else:
|
||||
header = "<span style='color: red'>[ %s => %s]</span>\n" % (host, 'failed')
|
||||
self.write_message(header)
|
||||
self.write_message(output)
|
||||
self.write_message('\n\n')
|
||||
|
||||
|
||||
class WebTerminalHandler(tornado.websocket.WebSocketHandler):
|
||||
clients = []
|
||||
tasks = []
|
||||
|
|
|
@ -148,6 +148,7 @@
|
|||
<a value="/jasset/asset_edit_batch/" type="button" class="btn btn-sm btn-warning iframe">修改</a>
|
||||
<input type="button" id="asset_update" class="btn btn-info btn-sm" name="update_button" value="更新"/>
|
||||
<input type="button" id="asset_update_all" class="btn btn-primary btn-sm" name="update_button" value="更新全部"/>
|
||||
<input type="button" id="exec_cmd" class="btn btn-sm btn-danger" name="exec_cmd" value="执行命令"/>
|
||||
</div>
|
||||
{% include 'paginator.html' %}
|
||||
</div>
|
||||
|
@ -175,6 +176,46 @@
|
|||
}
|
||||
});
|
||||
|
||||
$('#exec_cmd').click(function(){
|
||||
var url='/jlog/get_role_name/?id={{ user.id }}';
|
||||
var href = $(this).attr('href');
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: url,
|
||||
data: {},
|
||||
success: function(data){
|
||||
var dataArray = data.split(',');
|
||||
if (dataArray.length == 1 && data != 'error'){
|
||||
var title = 'Jumpserver Exec Terminal';
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: title,
|
||||
maxmin: true,
|
||||
shade: false,
|
||||
area: ['628px', '452px'],
|
||||
content: new_url+data
|
||||
});
|
||||
//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');
|
||||
} else if (dataArray.length == '1' && data == 'error'){
|
||||
layer.alert('没有授权角色')
|
||||
} else {
|
||||
aUrl = '';
|
||||
$.each(dataArray, function(index, value){
|
||||
aUrl += '<a onclick="windowOpen(this); return false" class="btn btn-xs btn-primary newa" href=' + new_url + value + ' value=' + hostname + '>' + value + '</a> '
|
||||
});
|
||||
layer.alert(aUrl, {
|
||||
skin: 'layui-layer-molv',
|
||||
title: '多个角色,请选择一个连接',
|
||||
shade: false,
|
||||
closeBtn: 0
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
return false
|
||||
|
||||
});
|
||||
|
||||
$('.conn').click(function(){
|
||||
var url='/jlog/get_role_name/?id=' + $(this).attr('value');
|
||||
var href = $(this).attr('href');
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<title>Jumpserver | 开源跳板机系统</title>
|
||||
|
||||
<link rel="shortcut icon" href="/static/img/facio.ico" type="image/x-icon">
|
||||
{% include 'link_css.html' %}
|
||||
{% include 'head_script.html' %}
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="wrapper">
|
||||
<div class="col-lg-12">
|
||||
<div class="ibox float-e-margins">
|
||||
<div class="ibox-title">
|
||||
<h5> 实时监控 </h5>
|
||||
</div>
|
||||
|
||||
<div class="ibox-content blank-panel" id="content" style="background-color: #0b0b0b; color: #006621; height: 500px; padding: 20px;">
|
||||
你好<br>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
{% block self_footer_js %}
|
||||
<script>
|
||||
function monitor(){
|
||||
var wsUri = 'ws://j:8080/send';
|
||||
var ws = new WebSocket(wsUri);
|
||||
ws.onopen = function(evt){
|
||||
$('#content').append('Connect websocket success' + '<br />');
|
||||
ws.send('Start')
|
||||
};
|
||||
|
||||
ws.onmessage = function(evt){
|
||||
console.log(evt.data);
|
||||
$('#content').append(evt.data.replace(/\n|\r|(\r\n)|(\u0085)|(\u2028)|(\u2029)/g, '<br>'));
|
||||
};
|
||||
|
||||
ws.onclose = function(evt){
|
||||
$('#content').append('Disconnect with websocket')
|
||||
}
|
||||
}
|
||||
|
||||
monitor();
|
||||
</script>
|
||||
{% endblock %}
|
||||
</html>
|
Loading…
Reference in New Issue