• Web堡垒机


    前言:

    如何向Leader体现出运维人员的工作价值?工单!如何自动记录下他们的操作,堡垒机!我看了网上有说 GateOne是一款开源的堡垒机解决方案,但是部署上之后发现了一个痛点, 我如何在不使用 公钥、私钥的前提下,基于web shh 实现 点击按钮进行一键登录--------》使用xshell一样使用Linux ------》退出之后记录操作日志,我可以修改GateOne的源码!但感觉自己实力不足,所以当下我想利用Django+websocket+paramiko+gevent.....能否zzzzzz实现?

    一、WebSocket配合terms.js 

    terms.js是在前端模拟ssh终端的开源框架

    把terms.js和websocket框架的回调函数

    onmessage()

    socket.onclose()

    onclose()

    send()

    结合起来!

    {% extends "arya/layout.html" %}
    {% block out_js %}
        <script src="/static/pligin/datatables/jquery.dataTables.min.js"></script>
        <script src="/static/pligin/datatables/dataTables.bootstrap.min.js"></script>
        <script src="/static/pligin/term.js"></script>
        <script src="/static/iron_ssh.js"></script>  <!---引入打开WebSocke的JavaScript代码  IronSSHClient类-->
    {% endblock %}
    {% block content %}
        <div class="table-responsive">
            <div id="page-content">
                <div class="panel col-lg-9">
                    <div class="panel-heading">
                        <h3 class="panel-title">主机列表</h3>
                    </div>
                    <div class="panel-body">
                        <div class="table-responsive">
                            <table id="host_table" class="table table-hover table-bordered table-striped">
                                <thead>
                                <tr>
                                    <th>IDC</th>
                                    <th>Hostname</th>
                                    <th>IP</th>
                                    <th>Port</th>
                                    <th>Username</th>
                                    <th>操作</th>
                                </tr>
                                </thead>
                                <tbody id="hostlist">
                                {% for host in hosts %}
                                    <tr>
                                        <td>{{ host.host.idc }}</td>
                                        <td>{{ host.host.hostname }}</td>
                                        <td>{{ host.host.ip_addr }}</td>
                                        <td>{{ host.host.port }}</td>
                                        <td>{{ host.host_user.username }}</td>
                                        <td>
                                            <button onclick="open_websocket({{ host.pk }},this)" type="button"
                                                    class="btn btn-success">连接
                                            </button>
                                        </td>
                                    </tr>
                                {% endfor %}
                                </tbody>
                            </table>
                        </div>
    
                    </div>
                </div>
    
            </div>
        </div>
        <div id="term">
    
        </div>
        <div hidden="hidden" id="disconnect">
            <button type="button" class="btn btn-danger" id="close_connect" onclick="close_ssh_termial()">关闭连接</button>
        </div>
    {% endblock %}
    {% block in_js %}
        <script>
            /* Datatables是一款jquery表格插件。它是一个高度灵活的工具,可以将任何HTML表格添加高级的交互功能。 */
            function set_tables() {
                $('#host_table').DataTable({
                    "paging": true, <!-- 允许分页 -->
                    "lengthChange": true, <!-- 允许改变每页显示的行数 -->
                    "searching": true, <!-- 允许内容搜索 -->
                    "ordering": true, <!-- 允许排序 -->
                    "info": true, <!-- 显示信息 -->
                    "autoWidth": true
                });
            }
    
            set_tables();
            CUURENT_WEB_SOCKEY='';
            function open_terminal(options) {
                $('#page-content').hide(); //点击连接按钮隐藏表格
                $('#disconnect').show();
                var client = new IronSSHClient();  //这里相当于执行了iron_ssh.js中的代码
                CUURENT_WEB_SOCKEY=client;
                var term = new Terminal(
                    {
                        cols: 80,
                        rows: 24,
                        handler: function (key) {
                            client.send(key);
                        },
                        screenKeys: true,
                        useStyle: true,
                        cursorBlink: true
                    });
                term.open(); //打开ssh终端
                $('.terminal').detach().appendTo('#term'); //把ssh终端放入 #term div标签中
                term.write('开始连接......');
                client.connect( //调用connect连接方法,把option的方法扩展了传进去
                    $.extend(options,
                        {
                            onError: function (error) {
                                term.write('错误: ' + error + '
    ');
                            },
                            onConnect: function () {
                                term.write('
    ');
                            },
                            onClose: function () {
                                client.close_web_soket();
                                term.write('对方断开了连接.......');
    
    {#                            close_ssh_termial() //关闭ssh命令 终端#}
    
                            }, //term.destroy();
                            onData: function (data) {
                                term.write(data);
                            }
                        }
                    )
                );
    
            }
    
            function open_websocket(pk, self) { //点击连接按钮创建web_ssh 通道
                var options = {host_id: pk};
                open_terminal(options)//打开1个模块ssh的终端
            }
    
            function close_ssh_termial() {//关闭ssh命令终端
                CUURENT_WEB_SOCKEY.close_web_soket();
                $('#term').empty();
                $('#page-content').show(); //点击连接按钮隐藏表格
                $('#disconnect').hide();
    
    
            }
    
        </script>
    
    
    
    
    {% endblock %}
    模板语言

    ---------------------------------------------------

    //定义1个js的原型
    function IronSSHClient() {
    }
    
    //增加生成URL的方法
    IronSSHClient.prototype._generateURL = function (options) {
        if (window.location.protocol == 'https:'){
            var protocol = 'wss://';
        }
        else {
            var protocol = 'ws://';
        }
        // ws://192.168.1.108:8000/host/3/
        var url = protocol + window.location.host + '/audit/host/'+ encodeURIComponent(options.host_id) + '/';
        return url;
    };
    
    //连接websocket
    IronSSHClient.prototype.connect = function (options) {
        var server_socket = this._generateURL(options);
        if (window.WebSocket) {
            this._web_socket = new WebSocket(server_socket) //创建1个websocket对象
        }
        else if (window.MozWebSocket) {
            this._web_socket = new new MozWebSocket(server_socket) //如果是火狐浏览器使用这种方式:创建1个websocket对象
        }
        else {
            options.onError('当前浏览器不支持WebSocket'); //如果用户的浏览器不支持 websocket
            return
        }
    
        this._web_socket.onopen = function () {  //连接建立时触发
            options.onConnect();
        };
    
        this._web_socket.onmessage = function (event) {  //客户端接收服务端数据时触发(event)
            var data = JSON.parse(event.data.toString());
            // console.log(data);
            if (data.error !== undefined) { //如果发过来的错误信息
                options.onError(data.error);//执行opetion中的error方法
            }
            else {                        //正常数据
                options.onData(data.data);
            }
    
        };
        this._web_socket.onclose = function (event) {  //关闭websocket的方法
            options.onClose();
    
    
    
        };
    
    };
    
    
    //websocket 发送数据
    IronSSHClient.prototype.send = function (data) {  //websocket发送数据的方法
        this._web_socket.send(JSON.stringify({'data':data})); //注意O,我发得可是字典!!
    
    };
    
    IronSSHClient.prototype.close_web_soket = function (data) {  //websocket发送数据的方法
        this._web_socket.close();
    
    };
    
    // web_socket_client = new IronSSHClient();
    iron_ssh.js

    二、Django+dwebsocket

    @accept_websocket
    def connect_host(request,user_bind_host_id):
        # print(request.environ)
        try:
            if request.is_websocket():
                while True:
                        message = request.websocket.wait()#一直等待前端发生数据过来!!
                        if message:
                            request.websocket.send(message)
    Django接收websocket请求

    三、paramiko交互式

    import paramiko
    import time
    
    trans = paramiko.Transport(('172.17.10.113', 22))  # 【坑1】 如果你使用 paramiko.SSHClient() cd后会回到连接的初始状态
    trans.start_client()
    # 用户名密码方式
    trans.auth_password(username='root', password='xxxxxx123')
    # 打开一个通道
    channel = trans.open_session()
    channel.settimeout(7200)
    # 获取一个终端
    channel.get_pty()
    # 激活器
    channel.invoke_shell()
    
    while True:
        cmd = input('--------->        ').strip()
        channel.send(cmd + '
    ')
        time.sleep(0.2)
        rst = channel.recv(1024)
        rst = rst.decode('utf-8')
        print(rst)
        # 通过命令执行提示符来判断命令是否执行完成
        if 'yes/no' in rst:
            channel.send('yes
    ')  # 【坑3】 如果你使用绝对路径,则会在home路径建立文件夹导致与预期不符
            time.sleep(0.5)
            ret = channel.recv(1024)
            ret = ret.decode('utf-8')
            print(ret)
            break
    
    channel.close()
    trans.close()
    paramiko交互式

     四、WebSocket+Paramiko交互式(同步)

    import json,time,paramiko
    from . import models
    from dwebsocket.decorators import accept_websocket
    from django.shortcuts import render,HttpResponse,redirect
    
    def hosts_list(request):
        current_user=models.UserInfo.objects.get(username=request.session.get('username'))
        current_audit__user =models.Account.objects.filter(user=current_user).first()
        if current_user:
            hosts=current_audit__user.host_user_binds.all()
        return render(request,'hosts_list.html',locals())
    
    
    @accept_websocket
    def connect_host(request,user_bind_host_id):
        # print(request.environ)
        try:
            if request.is_websocket(): #来了1个WebSocket创建1个SSHSocket,在它们两个开始同步 对话
                ssh_socket = paramiko.Transport(('172.17.10.113', 22))
                ssh_socket.start_client()
                ssh_socket.auth_password(username='root', password='xxxxxx123')
                channel = ssh_socket.open_session()
                channel.get_pty()
                channel.invoke_shell()
                while True:
                        message = request.websocket.wait()#一直等待前端发生数据过来!!
                        if len(message)>1:
                            cmd=json.loads(message)
                            #-------------------------------
                            channel.send(cmd['data'])
                            #---------------------------------
                            data = channel.recv(1024)
                            if len(data)>1:
                                request.websocket.send(json.dumps({'data': data.decode()}))  # 把前端发送的数据,返回前段的数据
                                # time.sleep(2)
        except Exception:
            print('客户端已经断开了连接!')
    同步堡垒机

     五、WebSocket+Paramiko交互式+Gevent模块(协程异步)

    本来打算使用Gevent模块开协程进行切换的,但是gevent的模块的from gevent import monkey;monkey.patch_all()Django项目中所有用到得库,还得换uwsgi,为避免牵一发而动全身的,我采用了保守的方式(线程)

    import paramiko
    import threading
    import json
    
    class Web_and_SSH(object):
        def __init__(self,host_user_bind_obj,websocket):
            self.host_user_bind_obj=host_user_bind_obj
            self.ip=self.host_user_bind_obj.host.ip_addr
            self.port=int(self.host_user_bind_obj.host.port)
            self.login_user=self.host_user_bind_obj. host_user.username
            self.password=self.host_user_bind_obj.host_user.password
            self.web_socket = websocket
            self.cmd_string = ''
    
        def open_shh_socket(self):
            try:
                # trans = paramiko.Transport(('172.17.10.113', 22))  # 【坑1】 如果你使用 paramiko.SSHClient() cd后会回到连接的初始状态
                # print(self.ip,)
                trans = paramiko.Transport((self.ip,self.port))  # 【坑1】 如果你使用 paramiko.SSHClient() cd后会回到连接的初始状态
                trans.start_client()
                # 用户名密码方式
                # print(self.login_user,self.password) #xxxxxx123
                trans.auth_password(username=self.login_user,password=self.password)
                # 打开一个通道
                channel = trans.open_session()
                # 获取一个终端
                channel.get_pty()
                channel.invoke_shell()
                self.ssh_socket=channel
                # print(self.ssh_socket)
            except Exception as e:
                print(e)
                self.web_socket.send(json.dumps({'error':str(e)},ensure_ascii=False))
                self.ssh_socket.close()
                raise
    
        def web_to_ssh(self):
            # print('--------------->')
            try:
                while True:
                    message= self.web_socket.wait()
                    if not message:
                        return
                    cmd = json.loads(message)
                    if 'data' in cmd:
                        self.ssh_socket.send(cmd['data'])
                        self.cmd_string += cmd['data']
            finally:
                self.close()
    
        def ssh_to_web(self):
            # print('<-------------------')
            try:
                while True:
                    data = self.ssh_socket.recv(1024)
                    if not data:
                        return
                    self.web_socket.send(json.dumps({'data':data.decode()}))
                    # print(self.cmd_string)
    
            finally:
                self.close()
    
        def _bridge(self):
            t1 = threading.Thread(target=self.web_to_ssh)
            t2 = threading.Thread(target=self.ssh_to_web)
            t1.start()
            t2.start()
            t1.join()
            t2.join()
        def shell(self):
            self.open_shh_socket()
            self._bridge()
            self.close()
    
    
        def close(self):
            self.ssh_socket.close()
    Bridge.py
    from audit import Bridge
    from . import models
    from dwebsocket.decorators import accept_websocket
    from django.shortcuts import render,HttpResponse,redirect
    
    def hosts_list(request):
        current_user=models.UserInfo.objects.get(username=request.session.get('username'))
        current_audit__user =models.Account.objects.filter(user=current_user).first()
        if current_user:
            hosts=current_audit__user.host_user_binds.all()
        return render(request,'hosts_list.html',locals())
    
    
    @accept_websocket
    def connect_host(request,user_bind_host_id):
            if request.is_websocket(): #来了1个WebSocket创建1个SSHSocket,在它们两个开始同步 对话
                user_bind_host_id=models.HostUserBind.objects.get(pk=user_bind_host_id)
                obj=Bridge.Web_and_SSH(user_bind_host_id,request.websocket)
                obj.open_shh_socket()
                obj.shell()
    视图

    六.用户行为日志+运维日志

    我在想怎么在使用了web socket的前提下 记录用户输入的command,这样做的痛点是使用了web socket协议之后 数据传输是 水流式的( 如果你执行了1个df命令,就会有d 、f 、 传输到后端),还要继续做数据处理,即便我拿到这些命令意义也不是很大;

    突然我放弃了,我不这么搞了,我要这么搞!

    我记录web socket响应给前端的数据,其实这样也可以把堡垒机用户所有操作记录下来而且较为详细; 

    用户行为日志

    用户操作日志

    from django.db import models
    from cmdb.models import UserInfo
    # Create your models here.
    
    
    class IDC(models.Model):
        name = models.CharField(max_length=64,unique=True)
        def __str__(self):
            return self.name
        class Meta:
            verbose_name_plural = "IDC机房"
    
    class Host(models.Model):
        """存储所有主机信息"""
        hostname = models.CharField(max_length=64,unique=True)
        ip_addr = models.GenericIPAddressField(unique=True)
        port = models.IntegerField(default=22)
        idc = models.ForeignKey("IDC")
        enabled = models.BooleanField(default=True)
        def __str__(self):
            return "%s-%s" %(self.hostname,self.ip_addr)
        class Meta:
            verbose_name_plural = "主机"
    
    class HostGroup(models.Model):
        """主机组"""
        name = models.CharField(max_length=64,unique=True)
        host_user_binds  = models.ManyToManyField("HostUserBind")
        def __str__(self):
            return self.name
        class Meta:
            verbose_name_plural = "主机组"
    
    
    class HostUser(models.Model):
        """存储远程主机的用户信息
        root 123
        root abc
        root sfsfs
        """
        auth_type_choices = ((0,'ssh-password'),(1,'ssh-key'))
        auth_type = models.SmallIntegerField(choices=auth_type_choices)
        username = models.CharField(max_length=32)
        password = models.CharField(blank=True,null=True,max_length=128)
    
        def __str__(self):
            return "%s-%s-%s" %(self.get_auth_type_display(),self.username,self.password)
    
        class Meta:
            unique_together = ('username','password')
            verbose_name_plural = "用户+密码表"
    
    
    class HostUserBind(models.Model):
        """绑定主机和用户"""
        host = models.ForeignKey("Host")
        host_user = models.ForeignKey("HostUser")
        def __str__(self):
            return "%s-%s" %(self.host,self.host_user)
    
        class Meta:
            unique_together = ('host','host_user')
            verbose_name_plural = "主机+用户+密码表"
    
    class SessionLog(models.Model):
        ''' 记录每个用户 每次操作的记录 '''
        account=models.ForeignKey('Account',verbose_name='执行任务的用户')
        host_user_bind=models.ForeignKey('HostUserBind',verbose_name='执行的任务所在服务器')
        operation_type_choices= ((0, '交互式操作'), (1, '批量操作'))
        operation_type=models.SmallIntegerField(choices=operation_type_choices,default=0,verbose_name='操作类型')
        start_date=models.CharField(max_length=255,verbose_name='开始时间')
        end_date=models.DateTimeField(auto_now_add=True,verbose_name='结束时间')
        is_work_order=models.BooleanField(default=False)
        def __str__(self):
            return '%s %s-%s-%s-%s'%(self.start_date,self.account,self.host_user_bind.host.ip_addr,self.host_user_bind.host_user.username,self.get_operation_type_display())
        class Meta:
            verbose_name_plural = '操作记录'
    
    class AuditLog(models.Model):
        """记录用户 每次操作执行的命令"""
        session = models.ForeignKey("SessionLog")
        cmd = models.TextField(verbose_name='执行了哪些命令')
        date = models.DateTimeField(auto_now_add=True)
        def __str__(self):
            return "%s-%s" %(self.session,self.cmd)
        class Meta:
            verbose_name_plural = '操作执行的命令'
    
    
    class Account(models.Model):
        """堡垒机账户
        user.account.host_user_bind
        """
        user = models.OneToOneField(UserInfo,verbose_name='运维平台用户')
        enabled = models.BooleanField(default=True,verbose_name='当前用户是否被禁用')
        host_user_binds = models.ManyToManyField("HostUserBind",blank=True,verbose_name='用户下的权限')
        host_groups = models.ManyToManyField("HostGroup",blank=True,verbose_name='用户下的权限组')
        def __str__(self):
            return "%s" %(self.user.username)
        class Meta:
            verbose_name_plural = '堡垒机用户'
    
    class CronTable(models.Model):
        '''主机的Cron 任务表'''
        host_user=models.ForeignKey('HostUserBind',verbose_name='1服务器+1用户+1cron+1行记录')
        task_name=models.CharField(max_length=255,verbose_name='任务名称',blank=True,null=True)
        task_tag= models.CharField(max_length=255, verbose_name='任务功能说明',blank=True, null=True)
        cron_expression = models.CharField(max_length=255, verbose_name='任务表达式', blank=True, null=True)
        available=models.BooleanField(verbose_name='当前cron任务是否可用')
        last_execute_available = models.BooleanField(default=True, verbose_name='上一次执行是否执行成功')
        last_execute_log = models.TextField(verbose_name='上次次执行日志', blank=True, null=True)
        next_execute_time = models.CharField(max_length=255, verbose_name='下次执行时间',blank=True, null=True)
        cron_execute=((0,'shell'),(1,'http-get'))
        pass1 = models.CharField(max_length=255,verbose_name='预留字段1',blank=True, null=True)
        pass2 = models.CharField(max_length=255,verbose_name='预留字段2',blank=True, null=True)
        # class Meta:
        #     verbose_name_plural = 'crontab表'
    models.py
    from django.conf.urls import url
    from . import views
    urlpatterns = [
        url(r'^hosts_list/$',views.hosts_list,name='hosts_list'),#/audit/hosts_list/
        #('host/<int:user_bind_host_id>/', views.connect  #(?P<n1>d+)/
        url(r'^host/(?P<user_bind_host_id>d+)/$',views.connect_host,name='connect_host'),#/audit/hosts_list/
        url(r'^user/activity/logs/$',views.activity_log, name='users_activity_log_url'),#/audit//user/operation/logs/
        url(r'^user/operation/logs/$',views.operation_log, name='users_operation_log_url')
       ]
    urls.py
    from audit import Bridge
    from . import models
    
    from dwebsocket.decorators import accept_websocket
    from django.shortcuts import render,HttpResponse,redirect
    
    def hosts_list(request):
        current_user=models.UserInfo.objects.get(username=request.session.get('username'))
        current_audit__user =models.Account.objects.filter(user=current_user).first()
        if current_user:
            hosts=current_audit__user.host_user_binds.all()
        return render(request,'hosts_list.html',locals())
    
    
    
    
    
    @accept_websocket
    def connect_host(request,user_bind_host_id):
            if request.is_websocket(): #来了1个WebSocket创建1个SSHSocket,django在它们2个之间, 协调异步对话
                user_bind_host_id=models.HostUserBind.objects.get(pk=user_bind_host_id)
                obj=Bridge.Web_and_SSH(user_bind_host_id,request.websocket,request,models)
                obj.open_shh_socket()
                obj.shell()
                obj.add_logs()
    
    
    def activity_log(request):#用户行为日志
        pk=request.GET.get('pk')
        host_user_bind_pk=pk
        SessionLogs=models.SessionLog.objects.filter(host_user_bind__pk=pk).order_by('-pk')
        return render(request,'activity_logs.html',locals())
    
    def operation_log(request):#用户操作日
        pk = request.GET.get('pk')
        host_user_bind_pk=request.GET.get('next')
        AuditLogs = models.AuditLog.objects.filter(session__pk=pk).order_by('-pk')
        return render(request,'operation_logs.html',locals())
    
    def generate_work_order(request):#运维日志生成工单
        return HttpResponse('ok')
    views.py

    ------------------------------------------------------------------

    {% extends "arya/layout.html" %}
    {% block out_js %}
        <script src="/static/pligin/datatables/jquery.dataTables.min.js"></script>
        <script src="/static/pligin/datatables/dataTables.bootstrap.min.js"></script>
        <script src="/static/pligin/term.js"></script>
        <script src="/static/iron_ssh.js"></script>  <!---引入打开WebSocke的JavaScript代码  IronSSHClient类-->
    {% endblock %}
    {% block content %}
        <div class="table-responsive">
    
            <div id="page-content">
                <div class="panel col-lg-9">
                    <div class="panel-heading">
                        <h3 class="panel-title">主机列表</h3>
                    </div>
                    <div class="panel-body">
                        <div class="table-responsive">
                            <table id="host_table" class="table table-hover table-bordered table-striped">
                                <thead>
                                <tr>
                                    <th>IDC</th>
                                    <th>Hostname</th>
                                    <th>IP</th>
                                    <th>Port</th>
                                    <th>Username</th>
                                    <th>操作</th>
                                </tr>
                                </thead>
                                <tbody id="hostlist">
                                {% for host in hosts %}
                                    <tr>
                                        <td>{{ host.host.idc }}</td>
                                        <td>{{ host.host.hostname }}</td>
                                        <td><a href="{% url 'users_activity_log_url'%}?pk={{ host.pk }}">{{ host.host.ip_addr }}</a> </td>
                                        <td>{{ host.host.port }}</td>
                                        <td>{{ host.host_user.username }}</td>
                                        <td>
                                            <button onclick="open_websocket({{ host.pk }},this)" type="button"
                                                    class="btn btn-success">连接
                                            </button>
                                        </td>
                                    </tr>
                                {% endfor %}
                                </tbody>
                            </table>
                        </div>
    
                    </div>
                </div>
    
            </div>
        </div>
        <div id="term">
    
        </div>
        <div hidden="hidden" id="disconnect">
            <button type="button" class="btn btn-danger" id="close_connect" onclick="close_ssh_termial()">关闭连接</button>
        </div>
    {% endblock %}
    {% block in_js %}
        <script>
            /* Datatables是一款jquery表格插件。它是一个高度灵活的工具,可以将任何HTML表格添加高级的交互功能。 */
            function set_tables() {
                $('#host_table').DataTable({
                    "paging": true, <!-- 允许分页 -->
                    "lengthChange": true, <!-- 允许改变每页显示的行数 -->
                    "searching": true, <!-- 允许内容搜索 -->
                    "ordering": true, <!-- 允许排序 -->
                    "info": true, <!-- 显示信息 -->
                    "autoWidth": true
                });
            }
    
            set_tables();
            CUURENT_WEB_SOCKEY='';
            function open_terminal(options) {
                $('#page-content').hide(); //点击连接按钮隐藏表格
                $('#disconnect').show();
                var client = new IronSSHClient();  //这里相当于执行了iron_ssh.js中的代码
                CUURENT_WEB_SOCKEY=client;
                var term = new Terminal(
                    {
                        cols: 80,
                        rows: 24,
                        handler: function (key) {
                            client.send(key);
                        },
                        screenKeys: true,
                        useStyle: true,
                        cursorBlink: true
                    });
                term.open(); //打开ssh终端
                $('.terminal').detach().appendTo('#term'); //把ssh终端放入 #term div标签中
                term.write('开始连接......');
                client.connect( //调用connect连接方法,把option的方法扩展了传进去
                    $.extend(options,
                        {
                            onError: function (error) {
                                term.write('错误: ' + error + '
    ');
                            },
                            onConnect: function () {
                                term.write('
    ');
                            },
                            onClose: function () {
                                client.close_web_soket();
                                term.write('对方断开了连接.......');
    
    {#                            close_ssh_termial() //关闭ssh命令 终端#}
    
                            }, //term.destroy();
                            onData: function (data) {
                                term.write(data);
                            }
                        }
                    )
                );
    
            }
    
            function open_websocket(pk, self) { //点击连接按钮创建web_ssh 通道
                var options = {host_id: pk};
                open_terminal(options)//打开1个模块ssh的终端
            }
    
            function close_ssh_termial() {//关闭ssh命令终端
                CUURENT_WEB_SOCKEY.close_web_soket();
                $('#term').empty();
                $('#page-content').show(); //点击连接按钮隐藏表格
                $('#disconnect').hide();
    
    
            }
    
        </script>
    
    
    
    
    {% endblock %}
    hosts_list.html
    {% extends "arya/layout.html" %}
    {% block out_js %}
        <script src="/static/pligin/datatables/jquery.dataTables.min.js"></script>
        <script src="/static/pligin/datatables/dataTables.bootstrap.min.js"></script>
    {% endblock %}
    {% block content %}
        <a class='btn btn-primary btn-sm' href="/audit/hosts_list/">返回</a>
        <div class="table-responsive">
            <div id="page-content">
                <div class="panel col-lg-9">
                    <div class="panel-heading">
                        <h3 class="panel-title">用户行为日志</h3>
                    </div>
                    <div class="panel-body">
                        <div class="table-responsive">
                            <table id="users_activity_log_show" class="table table-hover table-bordered table-striped">
                                <thead>
                                <tr>
                                    <th>开始时间</th>
                                    <th>结束时间</th>
                                    <th>运维用户</th>
                                    <th>方式</th>
                                    <th>登录</th>
                                    <th>服务器</th>
                                    <th>操作</th>
                                </tr>
                                </thead>
                                <tbody>
                                {% for log in SessionLogs %}
                                    <tr>
                                        <td>{{ log.start_date }}</td>
                                        <td>{{ log.end_date }}</td>
                                        <td> {{ log.account.user.username }}</td>
                                        <td> {{ log.get_operation_type_display }}</td>
                                        <td>{{ log.host_user_bind.host_user.username }}</td>
                                        <td>{{ log.host_user_bind.host.ip_addr }}</td>
                                        <td style="text-align: center">
                                            <a class='btn btn-primary btn-sm'
                                               href="{% url 'users_operation_log_url' %}?pk={{ log.pk }}&next={{ host_user_bind_pk }}">更多</a>
                                            {% if request.session.username == log.account.user.username %}
                                                <a class='btn btn-success btn-sm'
                                                   href="{% url 'users_operation_log_url' %}?pk={{ log.pk }}&next={{ host_user_bind_pk }}">工单</a>
                                                </td>
                                            {% endif %}
    
                                    </tr>
                                {% endfor %}
                                </tbody>
                            </table>
                        </div>
    
                    </div>
                </div>
    
            </div>
        </div>
    {% endblock %}
    
    {% block in_js %}
        <script>
            function set_tables() {
                $('#users_activity_log_show').DataTable({
                    "paging": true, <!-- 允许分页 -->
                    "lengthChange": true, <!-- 允许改变每页显示的行数 -->
                    "searching": true, <!-- 允许内容搜索 -->
                    "ordering": true, <!-- 允许排序 -->
                    "info": true, <!-- 显示信息 -->
                    "autoWidth": true
                });
            }
    
            set_tables()
        </script>
    
    {% endblock %}
    activity_logs.html
    {% extends "arya/layout.html" %}
    {% block content %}
        <a class='btn btn-primary btn-sm' href="{% url 'users_activity_log_url'%}?pk={{ host_user_bind_pk}}">返回</a>
        <div class="table-responsive">
            <div id="page-content">
                <div class="panel col-lg-9">
                    <div class="panel-heading">
                        <h3 class="panel-title">运维日志</h3>
                    </div>
                    {% for log in AuditLogs %}
                        <h3>{{ log.date }}</h3>
                        <pre style="background-color: black;color: white">
                         {{ log.cmd }}
                        </pre>
                    {% endfor %}
                </div>
    
            </div>
        </div>
    
    
    
    {% endblock %}
    operation_logs.html

    参考

    批量任务执行

    Django支持WebSocker协议

    Paramiko实现shell交互

  • 相关阅读:
    SVN 服务器 配置
    字符串写入到json文件
    关于Linux系统打开最大文件数量
    svn clearup svn cleanup failed–previous operation has not finished; run cleanup if it was int错误的解决办法
    原标题:北大最短毕业致辞,4分钟9次掌声!
    Mysql 基础操作命令
    Git 合并两个分支内容
    微信、QQ第三方登录授权时的问题总结
    PHP CI框架数据库常用操作
    Python 抓取数据存储到Mysql中
  • 原文地址:https://www.cnblogs.com/sss4/p/11016699.html
Copyright © 2020-2023  润新知