使用python構建一個簡單的發佈系統

一、流程

  通過前端上傳要發佈的壓縮包,邏輯端獲取後將壓縮包分發到遠程服務器上,並執行遠程服務器上使用shell編寫的發佈腳本,實現代碼發佈。


二、前端文件上傳代碼

<form id="codeForm" method='post' action='/code/' class="form-horizontal nice-validator n-yellow" novalidate="novalidate" enctype='multipart/form-data'>
<div class="form-group">
    <label for="package" class="col-sm-2">需要上傳的包<span class="red-fonts">*</span></label>
    <br>
    <div class="col-sm-12">
	<input id="package" name="package" type="file" datatype='*'/><!-- 上傳時type爲file -->
     </div>
</div>
</form>


三、邏輯端

1、保存文件到指定位置

import os
fpath = '/usr/local/zip/'

file = request.files.get('package')                         # 獲取壓縮包
filename = secure_filename(file.filename)                   # 確保文件格式正確
if '.' in filename and filename.split('.',1)[1] == 'zip':   # 確保文件是*.zip格式
    where = os.path.join(fpath,filename)
    file.save(where)                                        # 保存爲where指定的路徑


2、將文件分發到遠程服務器,並執行遠程命令

app.config.from_object(RemoteHost)
hosts = []

for i in app.config:
    if re.findall('HOST.',i):                               # 正則匹配HOST.類型
        hosts.append(app.config.get(i))
        # hosts格式爲[['192.168.1.100', 22, 'root', '123456'],['192.168.1.101', 22, 'root', '123456'],...]

def trans(where,filename):
    ssh = paramiko.SSHClient()                              # 初始化ssh對象
    comm = '/root/test.sh '+where                           # 遠程服務器上要執行的命令
 
    for i in hosts:
        # 文件傳輸
        tus = (i[0],i[1])
        t = paramiko.Transport(tus)
        t.connect(username=i[2],password=i[3])
        sftp = paramiko.SFTPClient.from_transport(t)        # 初始化sftp對象
        sftp.put(where,'/tmp'+filename)                     # 傳輸到'/tmp'下
        t.close()
           
        # 執行遠程命令
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) # 允許連接不在know_hosts文件中的主機(可選項)
        ssh.connect(i[0],i[1],i[2],i[3],timeout=10)
        stdin,stdout,stderr = ssh.exec_command(comm)        # 執行遠程命令
        ssh.close()


四、數據端

將前端獲取的一些其他數據保存到數據庫

data = dict((k,v[0]) for k,v in dict(request.form).items()) # message, key, project
key = data.pop('key')
data['update_persion'] = session.get('name')                # 添加執行人
data['package'] = filename                                  # 添加上傳的包名
conditions = [ "%s='%s'" %  (k,v) for k,v in data.items()]
if key == 'abcde':                                          # 許可碼正確就執行操作
    try:  
        trans(where,filename)
        db.add('code',conditions)                           # 寫入數據庫
        return render_template('/code/code.html',result='更新成功!',role = role)
    except Exception, e:
        errmsg = '失敗信息 error: '+str(e)
        return render_template('/code/code.html',result=errmsg,role = role)
else:
    return render_template('/code/code.html',result='許可碼無效!',role = role)


效果圖

wKioL1gz72aR3fhsAABK27kRcDw286.png

更新歷史

wKioL1gz8APjVzwTAABPFmpHFAE501.png



使用基於python的pysvn模塊,直接通過svn更新代碼

def get_login(realm,username,may_save):
    return True,'test','123456',True           # svn用戶名:test ,密碼:123456

def svncheckout(url,where):
    client = pysvn.Client()
    client.callback_get_login = get_login      # 登錄svn
    try:
        client.checkout(url,where)             # 將代碼checkout到本地
    except Exception,e:
        print 'Error: {}'.format(e)


分發到遠程服務器的方法

1、通過遍歷所有的文件

def dirlist(where):  
    filelist =  os.listdir(where)  
  
    for filename in filelist:  
        filepath = os.path.join(where, filename)  
        if os.path.isdir(filepath):  
            dirlist(filepath)  
        else:  
            allfile.append(filepath)  
    return allfile


2、直接壓縮

def zip_dir(dirname,zipfilename):
    filelist = []
    if os.path.isfile(dirname):
        filelist.append(dirname)
    else :
        for root, dirs, files in os.walk(dirname):
            for name in files:
                filelist.append(os.path.join(root, name))
                
    zf = zipfile.ZipFile(zipfilename, "w", zipfile.zlib.DEFLATED)
    for tar in filelist:
        arcname = tar[len(dirname):]
        #print arcname
        zf.write(tar,arcname)
    zf.close()


使用zip方法傳輸的邏輯端處理方法

@app.route('/code/',methods=['GET','POST'])
@login_request.login_request
def code():
    role = session.get('role')
    if request.method=='GET':
        return render_template('/code/code.html',role=role)
    else:
        data = dict((k,v[0]) for k,v in dict(request.form).items()) # message, key, project
        print data
        key = data.pop('key')
        project = data['project']
        data['update_persion'] = session.get('name')
        conditions = [ "%s='%s'" %  (k,v) for k,v in data.items()]
        if key == 'abcde' and data['project']:
            try:
                localtime = time.strftime('-%Y-%m-%d-%H:%M:%S')
                project_name = project+localtime # 例如: 'ecg-2016-12-07-10:00:37'
                zip_name = project_name+'.zip'
                print zip_name
                svncheckout(url[project],path+project_name) # co 到 '/data/ecg-2016-12-07-10:00:37'
                os.chdir(path) # cd '/data'
                zip_dir(project_name,zip_name)
                for host in hosts:
                    trans(zip_name,path+zip_name,host)
                    exec_comm('/bin/bash /root/update.sh '+zip_name,host)     
                db.add('code',conditions)
                return json.dumps({'code':0,'result':'更新成功'})
            except Exception, e:
                errmsg = '失敗信息 error: '+str(e)
                return json.dumps({'code':1,'errmsg':errmsg})
        elif not data['project']:
            return json.dumps({'code':1,'errmsg':errmsg})
        else:
            errmsg = '許可碼無效!'
            return json.dumps({'code':1,'errmsg':errmsg})


前端效果圖

免去了上傳zip壓縮包的步驟

wKiom1hjTV6wiKQ-AAA5s1yAdTI356.jpg

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章