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 + '\r\n');
                        },
                        onConnect: function () {
                            term.write('\r');
                        },
                        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 + '\r')
    time.sleep(0.2)
    rst = channel.recv(1024)
    rst = rst.decode('utf-8')
    print(rst)
    # 通過命令執行提示符來判斷命令是否執行完成
    if 'yes/no' in rst:
        channel.send('yes\r')  # 【坑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 、\r 傳輸到后端),還要繼續做數據處理,即便我拿到這些命令意義也不是很大;

突然我放棄了,我不這么搞了,我要這么搞!

我記錄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 + '\r\n');
                        },
                        onConnect: function () {
                            term.write('\r');
                        },
                        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交互

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM