WEB化批量执行命令&文件上传

 

作者:wangxun

本文中将更进一步使用Tornado提供一个WEB界面,通过WEB界面操作即可实现批量命令执行、文件上传。

首先我们需要一个资料库来存放主机信息。本文中我们使用SQLite,我们建立一张表:myhost 表中创建四个栏位:ID、HOST、USER、PWD分别记录序号,主机名、主机登入用户名、登入密码。 SQL如下:

CREATE TABLE "myhost" (
"ID"  INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
"HOST"  TEXT(36),
"USER"  TEXT(36),
"PWD"  TEXT(36)
)

Python:

# -*- coding=utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
import tornado.web
import tornado.httpserver
import tornado.ioloop
import tornado.httpclient
import os.path,os,datetime
import threading
import sqlite3
import paramiko
import urllib
HTML = u""
def dbconn(sql):
    conn = sqlite3.connect("DB.db")
    conn.text_factory = str
    cur = conn.cursor()
    cur.execute(sql)
    conn.commit()
    result = cur.fetchall()
    cur.close()
    conn.close()
    return result
class ssh():
    def __init__(self,host,user,pwd,remotepath=None,localpath=None,cmd=None,TYPE=None,port=22):
        self.host = host                #Hostname
        self.user = user                #用户名
        self.pwd = pwd                  #密码
        self.remotepath = remotepath    #远程路径,上传&下载文件时需要提供此参数
        self.localpath =  localpath     #本地路径,上传&下载文件时需要提供此参数
        self.port = port                #ssh端口
        self.cmd = cmd                  #需要在远程主机执行的命令,执行命令时需要提供此参数
        self.type = TYPE                #sftp操作类型,允许的值有两个:upload和download

    def ssh(self):      #命令执行
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.connect(self.host,self.port,self.user,self.pwd,timeout=5)
        stdin, stdout, stderr = ssh.exec_command(self.cmd)
        return stdout.read()
        ssh.close()


    def sftp(self):     #文件上传下载
        t = paramiko.Transport((self.host,self.port))
        t.connect(username = self.user, password = self.pwd)
        sftp = paramiko.SFTPClient.from_transport(t)

        if self.type=='upload':
            sftp.put(self.localpath,self.remotepath)
        elif self.type=='download':
            sftp.get(self.remotepath, self.localpath)
        else:
            raise NameError('TYPE object is invalid!')
        t.close()
settings = {
    "static_path" : os.path.join(os.path.dirname(__file__), "static"),
    "template_path" : os.path.join(os.path.dirname(__file__), "templates"),
    "login_url": "/login",
    }

class main(tornado.web.RequestHandler):
    def get(self):
        SerList = dbconn("select ID,HOST from myhost")
        if SerList:
            SerList = [(i[0],i[1]) for i in SerList]
        else:
            SerList = []
        self.render("test.html",SerList = SerList)

    def post(self):
        global HTML
        cmd = self.get_argument('cmd',')
        argv = self.get_argument('argv',')
        TYPE = self.get_argument('TYPE',')
        filename = self.get_argument('localpath',')
        localpath = os.path.join(os.path.join(os.path.dirname(__file__),'files'),filename)
        remotepath = '%s/%s' % (self.get_argument('url','),filename)
        print remotepath,localpath
        HOST_LIST = dbconn("select HOST,USER,PWD from myhost WHERE int in (%s)" % argv[0:-1])
        for i in HOST_LIST:
            t = execute(host = i[0],user = i[1],pwd = i[2],cmd = cmd,TYPE = TYPE,remotepath=remotepath,localpath=localpath)
            t.start()
            t.join()
        result = HTML
        HTML = u'
        self.write(result)
class upload(tornado.web.RequestHandler):
    def post(self):
        upload_path=os.path.join(os.path.dirname(__file__),'files')
        file_metas=self.request.files['Filedata']
        filename=file_metas[0]['filename']
        filepath=os.path.join(upload_path,filename)
        with open(filepath,'wb') as up:
            up.write(file_metas[0]['body'])
        self.write('finished!')
class execute(threading.Thread):    #命令执行、文件上传下载任务并发执行。
    def __init__(self,host,user,pwd,cmd=None,TYPE='CMD',remotepath=None,localpath=None):
        threading.Thread.__init__(self)
        self.host = host
        self.user = user
        self.pwd = pwd
        self.cmd = cmd
        self.TYPE = TYPE
        self.remotepath = remotepath
        self.localpath = localpath
    def run(self):
        global HTML
        try:
            if self.TYPE=='CMD':
                result = ssh(host=self.host,user=self.user,pwd=self.pwd,cmd=self.cmd).ssh()
                if not result:result=u'
                HTML = HTML + self.host + u':<br />' + result.strip() + u"<br />"
            elif self.TYPE=='UP':
                result = ssh(host=self.host,user=self.user,pwd=self.pwd,TYPE='upload',remotepath=self.remotepath,localpath=self.localpath).sftp()
                HTML = HTML + self.host + u'  :Upload successfull!<br />'
            else:
                raise NameError('TYPE object is invalid!')
        except Exception as e:
            pass

App = tornado.web.Application([
    (r'/',main),
    (r'/upload',upload),
    ],**settings)
if __name__ == "__main__":
    http_server=tornado.httpserver.HTTPServer(App)
    http_server.listen(80)
    tornado.ioloop.IOLoop.instance().start()

HTML模板(需要Jquery&jquery.uploadify)

<!DOCTYPE html>
<html>
<head>
<link href="static/css/uploadify.css" rel="stylesheet">
  <script src="http://cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
  <script src="static/js/jquery.uploadify.min.js"></script>
  <script type="text/javascript">
        (document).ready(function()
        {("#upload").uploadify({
                'swf': 'static/js/uploadify.swf',
                'uploader': '/upload',
                'cancelImg': 'static/js/uploadify-cancel.png',
                'buttonText': '选择文件并上传',
                'queueID': 'fileQueue',
                'fileSizeLimit':'50MB',
                'simUploadLimit' : '100',
                'formData' : {'url':("#url").val()},
                'onUploadSuccess':function(file, data, response){
                    var argv='("#select2 option").each(function(){
                    argv += (this).val() + ',';
                    }).post("/",{argv:argv,
                                'TYPE':'UP',
                                'url':("#url").val(),
                                'localpath':file.name},function(HTML){("#result").html(HTML)})
                },
                'removeCompleted' : false,
                'auto': true,
                'multi': true
            });
        });  
    </script>
</head>
<body>

 <table>
 <tr>
 <td>
     <select multiple style="width:100px;height:200px" id="select1" >
        {% for i in SerList %}
            <option value="{{ i[0] }}">{{ i[1] }}</option>
        {% end %}
    </select>
 </td>
 <td>
     <button id="add">>|</button><br />
     <button id="alladd">>></button><br />
     <button id="move">|<</button><br />
     <button id="allmove"><<</button>
 </td>
 <td>
    <select multiple style="width:100px;height:200px" id="select2">
    </select>
 </td>
 </tr>
 <table>
 <input type="file" id="upload" />
 文件上传至:<input type="text" id="url" value="/tmp" />
 <div id="fileQueue"></div>
  執行命令: <input type="text" id="cmd" /> <button id="sub">提交</button><br />
 <br />

<div id="result"></div>
</body>

  <script>  
  ("#add").click(function(){
    varoptions = ("#select1 option:selected")options.appendTo("#select2")

    })
  ("#move").click(function(){
    varoptions = ("#select2 option:selected")options.appendTo("#select1")

    })
  ("#allmove").click(function(){
    varoptions = ("#select2 option")options.appendTo("#select1")
    })
  ("#alladd").click(function(){
    varoptions = ("#select1 option")options.appendTo("#select2")
    })
  ("#sub").click(function(){
    var argv='("#select2 option").each(function(){
    argv += (this).val() + ',';
    }).post("/",{argv:argv,cmd:("#cmd").val(),'TYPE':'CMD'},function(data){("#result").html(data)})
    })
  </script>
</html>