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
	
	 ibuler
						ibuler