一、流程
通過前端上傳要發佈的壓縮包,邏輯端獲取後將壓縮包分發到遠程服務器上,並執行遠程服務器上使用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)
效果圖
更新歷史
使用基於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壓縮包的步驟