zoukankan      html  css  js  c++  java
  • 简单分析实现运维利器---批量操作bashshell

    背景

    为了进一步完善自己写的小运维系统,今天就继续来补充一个批量操作bashshell,并记录操作用于审计!

     

    一、思路

    实现批量bashshell操作思路其实挺简单,同样是用到paramiko库,如果只写小脚本实现的可以参考我的另一篇文章Python

    搞定繁琐运维之批量执行Linux命令,如果运用在web应用上,则需要websocket的帮助。

    具体思路:

    .打开websocket通道2.打开ssh通道3.执行shell4.反馈执行结果.5.保存操作记录

    这个流程在Django运维系统基础功能之—web远程ssh终端这篇文章也讲述的很清楚。

    但是我在想,实现批量操作需不需要做到像web终端一样?所有数据都要返回?我的答案是否定的,因为我觉得,要实行批量操作的时候,一般都只是做配置、备份、部署应用等。

    因此只需要做到标准输入->标准输出或者错误输出即可。

     

    二、实现

    其实有上面的思路以及上述的两篇文章已经把细节讲的非常清楚了,在这里就不过多的阐述了,不清楚的可以看看上面提到的两篇文章,直接上代码供大家参考吧。

    def batch(request):
        global hostnum, hostip, hostport, hostuser, hostpass
        if request.session.get('login')==None:
            return redirect('/sys/login/')
        if not request.is_websocket():
            dataa = models.host.objects.all()
            hostlist = (request.POST.get(f'{data.hostaddress}') for data in dataa)
            hostnum = 0
            hostip = []
            hostport = []
            hostuser = []
            hostpass = []
            for data in dataa:
                host = request.POST.get(f'{data.hostaddress}')
                if host != None:
                    hostnum = hostnum + 1
                    hostip.append(host)
                    hostport.append(models.host.objects.get(hostaddress=host).hostport)
                    hostuser.append(models.host.objects.get(hostaddress=host).hostuser)
                    hostpass.append(models.host.objects.get(hostaddress=host).hostpass)
            return render(request,'html/batch.html',locals())
        else:
            if hostnum == 0 :
                nummessage = '没有选择主机.'
                request.websocket.send(nummessage.encode('utf-8'))
            else:
                wamessage = '等待主机连接ing...'
                request.websocket.send(wamessage.encode('utf-8'))
            a = []
            b = []
            c = []
            d = []
            for i in range(hostnum):
                a.append('client' + str(i))
                b.append('stdin' + str(i))
                c.append('stdout' + str(i))
                d.append('stderr' + str(i))
                a[i] = paramiko.SSHClient()  # 创建num个连接对象
                # client2 = paramiko.SSHClient()
                a[i].set_missing_host_key_policy(paramiko.AutoAddPolicy)  # 添加num个主机名及主机密钥到本地HostKeys对象
                # client2.set_missing_host_key_policy(paramiko.AutoAddPolicy)
                try:
                    a[i].connect(hostname=hostip[i], port=hostport[i], username=hostuser[i], password=hostpass[i])  # num个连接
                    # client2.connect(hostname=ip[1],port=port[1],username=username[1],password=password[1])
                    print(f'主机{hostip[i]}连接成功!')
                    message = f'主机{hostip[i]}连接成功!'
                    request.websocket.send(message.encode('utf-8'))
                except:
                    print(f'主机{hostip[i]}连接失败,请确认列表信息!')
                    message = f'主机{hostip[i]}连接失败,请确认列表信息!'
                    request.websocket.send(message.encode('utf-8'))
    
            for shell in request.websocket:
                addactionshell = models.batchaction()
                addactionshell.hostaddress = hostip
                addactionshell.username = request.session['username']
                addactionshell.actionshell = shell.decode('utf-8')
                addactionshell.starttime = time.strftime("%Y%m%d%H%M%S")
                addactionshell.save()
                for i in range(hostnum):
                    b[i], c[i], d[i] = a[i].exec_command(shell)  # num个对象执行e命令
                    # print(f'----------------------{hostip[i]}执行结果----------------------')
                    # print(c[i].read().decode('utf-8'))  # 打印正确输出
                    # print(d[i].read().decode('utf-8'))  # 打印错误输出
                    output = '-'*97 + f'{hostip[i]}执行结果' + '-'*90 + c[i].read().decode('utf-8')  + d[i].read().decode('utf-8')
                    request.websocket.send(output.encode('utf-8'))

     

    html页面:

    {% extends 'base.html' %}
    {% load static %}
    {% block title %}批量执行{% endblock %}
    {% block css %}
         <link rel="stylesheet" href="{% static 'adminlet-2.4.10/bower_components/datatables.net-bs/css/dataTables.bootstrap.css' %}">
        <link rel="stylesheet" href="{% static 'asciinemaplayer/asciinema-player.css' %}">
    {% endblock %}
    
    <!-- 顶部内容  -->
    {% block breadcrumb %}
        <!-- Content Header (Page header) -->
        <section class="content-header">
          <h1>批量执行</h1>
        </section>
    {% endblock %}
    
    <!-- 身体内容  -->
    {% block content %}
    <div class="col-md-4">
        <button type="button" style="float: left" class="btn btn-default" data-toggle="modal" data-target="#selecthost">选择主机</button>
    </div>
        <!-- Modal选择主机模态框 -->
    <div class="modal fade bs-example-modeal-sm" id="selecthost" tabindex="-1" role="dialog" aria-labelledby="selecthostLabel">
      <div class="modal-dialog modal-sm" role="document">
        <div class="modal-content">
          <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
            <h4 class="modal-title" id="selecthostlLabel">请选择主机</h4>
          </div>
    <form action="{% url 'batch' %}" method="post">
          {% csrf_token %}
          <div class="modal-body">
          <table class="table">
          <tbody>
                  {% for data in dataa %}
                      <tr>
                          <td>
                              <label class="checkbox-inline">
                                  <input type="checkbox" name="{{data.hostaddress}}" value="{{data.hostaddress}}">{{ data.hostaddress }}
                              </label>
                          </td>
                      </tr>
                {% endfor %}
          </tbody>
          </table>
    
          </div>
    
          <div class="modal-footer">
            <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
            <button type="submit" class="btn btn-primary" id="selhostip">确定</button>
          </div>
        </form>
        </div>
      </div>
    </div>
    <br><br>
    
        <!-- 批量连接box -->
        <div class="col-md-4">
    <div class="box box-info" >
            <div class="box-header with-border">
              <h3 class="box-title">执行的主机</h3>
            </div>
            <div class="box-body">
            <table>
                {% for i in hostlist  %}
                    {%  if i != None %}
                        <tr>
                            <td>{{i}}</td>
                        </tr>
                    {% endif %}
                {% endfor %}
            </table>
            </div>
                <div class="box-footer">
                   <a style="float: right" class="btn btn-success" id="conwebsocket">连接</a>
            </div>
          </div>
                              <label class="form-inline" >执行的命令:
                <input class="form-control" type="text" name="acshell" id="shell" value=''>
                <a class="btn btn-success" id="sendshell">确定</a><br>(只支持标准输入-标准输出-标准错误模式)
                        </label>
    </div>
    
    <div class="col-md-8">
    <div class="box box-info" >
            <div class="box-header with-border">
              <h3 class="box-title">执行结果</h3>
            </div>
            <div class="box-body" id="showmess">
    
            </div>
          </div>
    </div>
    
    
    {% endblock %}
    
    <!-- JS内容  -->
    {% block script %}
    <script src="{% static 'adminlet-2.4.10/bower_components/datatables.net/js/jquery.dataTables.min.js' %}"></script>
    <script src="{% static 'adminlet-2.4.10/bower_components/datatables.net-bs/js/dataTables.bootstrap.min.js' %}"></script>
        <script src="/static/xterm_/jquery.js"></script>
        <script type="text/javascript">
        $(function () {
            $('#conwebsocket').click(function () {
                if (window.s) {
                    window.s.close()
                }
                /*创建socket连接*/
                var socket = new WebSocket("ws://" + window.location.host + "{% url 'batch' %}");
                socket.onopen = function () {
                    console.log('WebSocket open');//成功连接上Websocket
                };
                socket.onmessage = function (mess) {
                    console.log('message: ' + mess.data);//打印出服务端返回过来的数据
                    $('#showmess').prepend('<p>' + mess.data + '</p>');
                };
                // Call onopen directly if socket is already open
                if (socket.readyState == WebSocket.OPEN) socket.onopen();
                window.s = socket;
            });
            $('#sendshell').click(function () {
                //如果未连接到websocket
                if (!window.s) {
                    $('#showmess').prepend('没有连接主机');
                } else {
                    window.s.send($('#shell').val());//通过websocket发送数据
                }
            });
            $('#close_websocket').click(function () {
                if (window.s) {
                    window.s.close();//关闭websocket
                    console.log('websocket已关闭');
                }
            });
    
        });
        </script>
    {% endblock %}

     

    models:

    class batchaction(models.Model):
        hostaddress = models.CharField(max_length=255)
        username = models.CharField(max_length=255)
        actionshell = models.CharField(max_length=255)
        starttime = models.CharField(max_length=255)

     

     

    审计html,在录像的页面基础上添加:

      <!-- datatable 批量操作审计-->
      <div class="box box-default">
    
        <div class="box-header with-border">
          <h3 class="box-title">批量操作列表</h3>
        </div>
    
        <div class="box-body">
    <table id="batchlist" class="display" style="100%">
                    <thead>
            <tr>
              <th>主机地址</th>
              <th>操作人</th>
              <th>执行shell</th>
              <th>开始时间</th>
            </tr>
            </thead>
            <tbody>
          {% for batchacction in batchactionlist %}
              <tr>
              <td>{{ batchacction.hostaddress }}</td>
              <td>{{ batchacction.username }}</td>
              <td>{{ batchacction.actionshell }}</td>
              <td>{{ batchacction.starttime }}</td>
              </tr>
            {% endfor %}
            </tbody>
    </table>
        </div>
      </div>

     

    最终效果:



     

    三、结束

    好啦,Django运维系统之—批量操作bashshell,并记录操作用于审计的功能做到这里就结束咯。下次看看再补充一个执行shell脚本的功能吧。

    执行shell脚本功能出来了好像上传文件的功能也差不多出来了哈哈…

  • 相关阅读:
    [项目管理]记一次外包过程遇到的“问题”以及“应对之道”
    [ZT]Web Standard and ASP.NET – Part1 XHTML Quick Start
    [前端技术]利用 try...catch 来跳出JQuery.each()
    [ZT]Use JQuery to adjust the iframe height
    [CSharp]复合格式化(Composite Formatting)
    [项目管理]关于项目的工期控制
    [CSharp]判断表达式为空的二元运算符
    MySoft.Data ORM组件之获取插入后的自增主键
    [前端技术]让iframe背景透明起来
    NSRunLoop
  • 原文地址:https://www.cnblogs.com/eflypro/p/14986557.html
Copyright © 2011-2022 走看看