zoukankan      html  css  js  c++  java
  • 对webssh实现命令回放功能

    想要实现webssh的命令记录功能需要一个前端的组件 asciinema

    django服务端代码

     1 class WebSSH(WebsocketConsumer):
     2     message = {'status': 0, 'message': None}
     3     """
     4     status:
     5         0: ssh 连接正常, websocket 正常
     6         1: 发生未知错误, 关闭 ssh 和 websocket 连接
     7 
     8     message:
     9         status 为 1 时, message 为具体的错误信息
    10         status 为 0 时, message 为 ssh 返回的数据, 前端页面将获取 ssh 返回的数据并写入终端页面
    11     """
    12 
    13     def connect(self):
    14         try:
    15             self.accept()
    16             logger.info('open connet service ssh')
    17 
    18             query_string = self.scope['query_string']
    19             logger.info(query_string)
    20             connet_argv = QueryDict(query_string=query_string, encoding='utf-8')
    21             logger.info(connet_argv)
    22             serverid = connet_argv.get('unique')
    23             width = connet_argv.get('width')
    24             height = connet_argv.get('height')
    25             appid = connet_argv.get('appid','')
    26             execuserid = connet_argv.get('execuserid','')
    27 
    28             width = int(width)
    29             height = int(height)
    30 
    31             service = models.ServiceModel.objects.get(id=serverid)
    32 
    33             host = service.ipaddress
    34             port = str(service.port)
    35             user = system_config.log_user
    36             logger.info('{} {} {} {} {}'.format(serverid,height,serverid,host,user))
    37             self.ssh = SSH(websocker=self, message=self.message)
    38             self.execuserid = execuserid
    39             self.serverid = serverid
    40 
    41 
    42             self.ssh.connect(
    43                 host=host,
    44                 user=user,
    45                 port=port,
    46                 pty_width=width,
    47                 pty_height=height
    48             )
    49             if appid:
    50                 app = models.ApplicationModel.objects.get(id=appid)
    51                 self.ssh.shell('/home/{}/showlog.sh {}
    '.format(user,app.tomcatname))
    52 
    53         except Exception as e:
    54             logger.info(e)
    55             self.message['status'] = 1
    56             self.message['message'] = str(e)
    57             message = json.dumps(self.message)
    58             self.send(message)
    59             self.close()
    60 
    61     def disconnect(self, close_code):
    62         try:
    63             self.ssh.close()
    64         except:
    65             pass
    66 
    67     def receive(self, text_data=None, bytes_data=None):
    68         data = json.loads(text_data)
    69         if type(data) == dict:
    70             status = data['status']
    71             if status == 0:
    72                 data = data['data']
    73                 self.ssh.shell(data,self) #这里执行命令的时候把对象本身传进去(用了channels和xterm.js通过websocket实现的webssh是一个字符一个字符发送的,在parimako这个模块中做了一系列的命令组装,组成一个完整的shell命令)
    74 
    75             else:
    76                 cols = data['cols']
    77                 rows = data['rows']
    78                 self.ssh.resize_pty(cols=cols, rows=rows)
    79 
    80     def savecommend(self,commend):   #这里是保存命令的方法
    81         servicecommit = ServiceCommitModel()
    82         servicecommit.service_id = self.serverid
    83         servicecommit.user_id = self.execuserid
    84         json_commend = json.dumps(commend)
    85         servicecommit.commitname = json_commend[1:-1]
    86         servicecommit.save()
    87         logger.info(json_commend)
     1 import paramiko
     2 from threading import Thread
     3 from libs.ansible_libs.tools import get_key_obj
     4 import socket
     5 import json
     6 import logging
     7 
     8 
     9 class SSH:
    10     def __init__(self, websocker, message):
    11         self.websocker = websocker
    12         self.message = message
    13 
    14     def connect(self, host, user, password=None, pkey=None, port=22, timeout=120,
    15                 term='xterm', pty_width=80, pty_height=24):
    16         try:
    17             ssh_client = paramiko.SSHClient()
    18             ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    19 
    20             if password:
    21                 ssh_client.connect(username=user, password=password, hostname=host, port=port, timeout=timeout)
    22             else:
    23                 ssh_client.connect(username=user, hostname=host, port=port, timeout=timeout)
    24 
    25             transport = ssh_client.get_transport()
    26             self.channel = transport.open_session()
    27             self.channel.get_pty(term=term, width=pty_width, height=pty_height)
    28             self.channel.invoke_shell()
    29 
    30             for i in range(2):
    31                 recv = self.channel.recv(1024).decode('utf-8')
    32                 self.message['status'] = 0
    33                 self.message['message'] = recv
    34                 message = json.dumps(self.message)
    35                 self.websocker.send(message)
    36 
    37         except socket.timeout as e:
    38             self.message['status'] = 1
    39             self.message['message'] = 'ssh 连接超时'
    40             message = json.dumps(self.message)
    41             logging.info('connet server timeout')
    42             self.websocker.send(message)
    43             self.websocker.close()
    44         except Exception as e:
    45             self.message['status'] = 1
    46             self.message['message'] = str(e)
    47             message = json.dumps(self.message)
    48             logging.info('connet server custom')
    49             self.websocker.send(message)
    50             self.websocker.close()
    51 
    52     def resize_pty(self, cols, rows):
    53         self.channel.resize_pty(width=cols, height=rows)
    54 
    55 
    56     def django_to_ssh(self, data):
    57         try:
    58             self.channel.send(data)
    59             return
    60         except:
    61             self.close()
    62 
    63     def websocket_to_django(self,httpobj):
    64         try:
    65             while True:
    66                 data = self.channel.recv(1024).decode('utf-8')
    67                 if not len(data):
    68                     return
    69                 self.message['status'] = 0
    70                 self.message['message'] = data
    71                 message = json.dumps(self.message)  
    72                 self.websocker.send(message)
    73                 print(data)
    74                 try:
    75                     if httpobj:
    76                         httpobj.savecommend(str(data))  在这里做命令记录,把命令保存到数据库
    77                 except Exception as e:
    78                     print(e)
    79                 # httpobj.savecommend(data)
    80         except Exception as e:
    81             print(e)
    82             self.close()
    83 
    84     def close(self):
    85         self.message['status'] = 1
    86         self.message['message'] = '关闭连接'
    87         message = json.dumps(self.message)
    88         self.websocker.send(message)
    89         self.channel.close()
    90         self.websocker.close()
    91 
    92     def shell(self, data, httpobj=None):
    93         Thread(target=self.django_to_ssh, args=(data,)).start()
    94         Thread(target=self.websocket_to_django, args=(httpobj,)).start()  #这里是返回到前端的线程,在这个线程中做命令的记录

    当需要查看命令回放的时候

     1 class CommandData(LoginRequiredMixin,View):
     2     def get(self,request):
     3         '''
     4         获取用户选择的参数以返回视频文件
     5         :param request:
     6         :return:
     7         '''
     8         serverid = request.GET.get('sid')
     9         end_time = request.GET.get('end_time')
    10         start_time = request.GET.get('start_time')
    11         userid = request.GET.get('uid')
    12         servers = ServiceModel.objects.all()
    13         users = User.objects.all()
    14         datas = ServiceCommitModel.objects.filter(date__gte=start_time,date__lte=end_time,service_id=serverid,user_id=userid).values('commitname')
    15         # fileurl = '/home/PyObject/static/image/demo/demo.json'
    16         fileurl = '/opt/object/static/image/demo/demo.json'
    17         datalist = list()
    18         playindex = 0
    19         with open(fileurl,'wb') as f:
    20             f.write(bytes('{"version": 2, "width": 1500, "height": 1000, "timestamp": 1559530296, "env": {"SHELL": "/bin/bash", "TERM": "xterm-256color"}}
    ',encoding='utf-8')) #这里是asciinema需要的文件头
    21             for data in datas:
    22                 playindex += 0.4  #设置播放速度
    23 
    24                 commitname = data['commitname']
    25 
    26                 linestr = '[{}, "o", "{}"]
    '.format(playindex,commitname) #把命令写入到asciiname文件里面(必须按照这种格式)
    27                 # print(type(commitname),print(commitname))
    28                 f.write(bytes(linestr,encoding='utf-8')) 以二进制格式写入
    29             # datalist.append(data['commitname'])
    30         # print(json.dumps(datalist))
    31         # return JsonResponse({
    32         #     'datas': json.dumps(datalist)
    33         # })
    34         player = 'ok'
    35         return render(request,'command/playbackcommend.html',locals()) 返回页面

    前端网页:

    在html中导入asciinema的js和css文件

    <div class="row">
        {% if player %}
             <asciinema-player src="{% static 'image/demo/demo.json' %}" cols="260" rows="40"></asciinema-player>
        {% endif %}
    </div>

    这样就实现了webssh的命令回放功能

  • 相关阅读:
    MySQL-EXPLAIN执行计划字段解释
    MySQL-EXPLAIN执行计划Extra解释
    HTTP与HTTPS的区别
    【面试】Java中sleep和wait的区别
    Nginx之前后端分离(入门)
    玩程序 之 一 . 字符串处理工具(可通过C#脚本扩展)
    C#实现下载功能,可用于软件自动更新
    对c#剪切板Clipboard占用的问题一点解决方法
    C# 制作 仪表
    C#使用自定义字体(从文件获取)
  • 原文地址:https://www.cnblogs.com/arrow-kejin/p/11439721.html
Copyright © 2011-2022 走看看