用paramiko模組寫的發版機

czxin788發表於2018-04-23

說明:為了安全,本文敏感資訊如ip、使用者名稱密碼等做了轉換處理。

一、場景:每次發版時,都需要發版人一個一個檔案的往生產機上複製,這樣不僅費時,而且容易出錯,降低工程師的工作積極性。
二、解決方法:需用python指令碼寫一個發版機,自動發版。
三、指令碼實現的功能:自動合併develop_svn(開發svn)程式碼到online_svn(生產svn)下,自動備份遠端伺服器程式碼,手工透過ecplice編譯online_svn程式碼,然後自動把編譯後的class檔案根據filelist裡面的路徑複製到生產機,並自動重啟伺服器上的tomcat服務。
四、具體步驟:
1、開發提供類似如下svn檔案列表:
filelist.txt裡面的內容:
/trunk/src/ha/lalala/controller/BoardController.java
/trunk/src/ha/lalala/pda/PdaWaybillController.java
/trunk/WebRoot/jsp/productReview/list.jsp
2、建立develop_svn和online_svn目錄;



3、編寫faban.py指令碼

點選(此處)摺疊或開啟

  1. #-*-coding:utf-8-*-
  2. import Crypto #paramiko模組依賴Crypto模組
  3. import paramiko #paramiko模組是wnidows 遠端linux機器用的模組
  4. import os
  5. import sys
  6. import shutil #shutil模組下有copy資料夾的方法
  7. import time #這裡使用其休眠函式sleep
  8. import subprocess
  9. import glob



  10. #Update SVN
  11. def UpdateSVN(path):
  12.     p = subprocess.Popen(['svn','update',path],shell=True,stdout=subprocess.PIPE)
  13.     print p.stdout.readlines()
  14.     


  15. #定義函式用來合併svn
  16. def MergeSVN(develop_svn,online_svn):
  17.     with open('filelist.txt') as f:
  18.         for index,line in enumerate(f,1): #1表示索引值從1開始
  19.             line = line.replace('/trunk','') #替換路徑
  20.             line = line.replace('\n','') #把換行替換掉,\n是換行符的意思
  21.             develop_svn_path=develop_svn + line #拼接路徑
  22.             online_svn_path = online_svn + line #拼接路徑
  23.             print "%d copying: %s ---> %s" % (index,develop_svn_path,online_svn_path)
  24.             if not os.path.exists(os.path.dirname(online_svn_path)) : #如果目錄不存在,就建立一個目錄,注意exists方法返回的是布林值,所以用Not進行否定
  25.                 os.mkdir(os.path.dirname(online_svn_path)) #建立目錄
  26.             shutil.copy(develop_svn_path,online_svn_path) #將develop_svn_path裡面的程式碼複製到online_svn_path目錄下
  27.     print('\n') #輸出一個換行
  28.     print("合併SVN目錄已完成,請手工透過ecplice編譯程式碼".decode('utf-8').encode('gb2312'))
  29.     print('\n') #輸出一個換行
  30.      
  31.     


  32. #定義函式用來遠端備份程式碼--給北京的機器備份
  33. def BackupCode(hostname,port,username,password):
  34.     ssh = paramiko.SSHClient() #建立一個從客戶端連線伺服器端的物件,也就是類的例項化
  35.     ssh.load_system_host_keys() #載入主機秘鑰
  36.     ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) #接受不在本地Known_host檔案下的主機。否則ssh需要手工輸入一次yes
  37.     ssh.connect(hostname,port,username,password) #ssh連線
  38.     
  39.     stdin,stdout,stderr = ssh.exec_command(get_pty=False,command='dir=$(date +%Y%m%d%H%M%S) && \
  40.                                              rsync -zrtopg --exclude geadPortrait/ \
  41.                                            --exclude=idcard/ --exclude=temp/ --exclude=upload \
  42.                                            --exclude=files --exclude=temporary_zip/ \
  43.                                            /opt/apache-tomcat-8.0.27/webapps/ROOT /backup/tms/$dir') #執行遠端機器的rsync命令進行備份,rsync命令沒加-v引數,所以正常資訊不會輸出,只有報錯才輸出內容
  44.     result = stdout.read() #內容輸出
  45.     error = stderr.read() #錯誤輸出
  46.     print result
  47.     print error
  48.     #判斷是否有錯誤輸出,沒有就說備份成功,否則說備份失敗
  49.     if result.strip()=="" and error.strip()=="":
  50.         print "%s 完美,備份成功,備份位置在遠端機器的/backup目錄下".decode('utf-8').encode('gb2312') % hostname
  51.         print('\n')
  52.     else:
  53.         print "%s 不好了,備份失敗了".decode('utf-8').encode('gb2312') % hostname
  54.         print('\n')
  55.     ssh.close() #記得關閉paramiko的ssh連線






  56. #定義函式用來遠端備份程式碼--給香港騰訊的機器備份
  57. def BackupCode_HK_QQ(hostname,port,username,password):
  58.     ssh = paramiko.SSHClient() #建立一個從客戶端連線伺服器端的物件,也就是類的例項化
  59.     ssh.load_system_host_keys() #載入主機秘鑰
  60.     ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) #接受不在本地Known_host檔案下的主機。否則ssh需要手工輸入一次yes
  61.     ssh.connect(hostname,port,username,password) #ssh連線
  62.     stdin,stdout,stderr = ssh.exec_command(get_pty=False,command='dir=$(date +%Y%m%d%H%M%S) && \
  63.                                             rsync -zrtopg --exclude geadPortrait/ \
  64.                                            --exclude=idcard/ --exclude=temp/ --exclude=upload \
  65.                                            --exclude=files --exclude=temporary_zip/ \
  66.                                            /opt/tomcat-9090-tms/webapps/ROOT /backup/tms/$dir') #執行遠端機器的rsync命令進行備份,rsync命令沒加-v引數,所以正常資訊不會輸出,只有報錯才輸出內容
  67.     result = stdout.read() #內容輸出
  68.     error = stderr.read() #錯誤輸出
  69.     print result
  70.     print error
  71.     #判斷是否有錯誤輸出,沒有就說備份成功,否則說備份失敗
  72.     if result.strip()=="" and error.strip()=="":
  73.         print "%s 完美,備份成功,備份位置在遠端機器的/backup目錄下".decode('utf-8').encode('gb2312') % hostname
  74.         print('\n')
  75.     else:
  76.         print "%s 不好了,備份失敗了".decode('utf-8').encode('gb2312') % hostname
  77.         print('\n')
  78.     ssh.close() #記得關閉paramiko的ssh連線


  79.         

  80. #定義函式用來遠端執行發版動作
  81. def Publish(hostname,port,username,password,local_base_path,remote_base_path):
  82.     count = 0
  83.     trans = paramiko.Transport(hostname,port) #建立paramiko的transport方式連線
  84.     trans.connect(username=username,password=password) #建立連線
  85.     sftp = paramiko.SFTPClient.from_transport(trans) #建立連線
  86.     with open('filelist.txt','r') as f:
  87.         for line in f:
  88.             #本地路徑預處理
  89.             localpath_filename = line.replace('/trunk/src','WebRoot/WEB-INF/classes')
  90.             localpath_filename = localpath_filename.replace('/trunk/WebRoot','WebRoot')
  91.             localpath_filename = localpath_filename.replace('.java','.class')
  92.             localpath_filename = localpath_filename.replace('\n','') #把換行替換掉
  93.             #構造真正的父類本地路徑
  94.             localpath_filename = local_base_path + localpath_filename
  95.             #構造真正的父類遠端路徑
  96.             remotepath_filename = remote_base_path + localpath_filename.replace('online_svn/WebRoot/','')
  97.             #複製父類到遠端機器上
  98.             print "%s is publishing: %s ---> %s " % (hostname,localpath_filename,remotepath_filename)
  99.             try:
  100.                 sftp.listdir(os.path.dirname(remotepath_filename)) #加個錯誤處理,如果目錄不存在,就建立一個目錄
  101.             except IOError:
  102.                 sftp.mkdir(os.path.dirname(remotepath_filename))
  103.             sftp.put(localpath_filename,remotepath_filename)
  104.             count += 1
  105.             print "***********第%s個檔案發版成功***************" % count
  106.             #用glob模組尋找子類
  107.             path_filename = os.path.split(localpath_filename) #split:返回一個二元組,包含檔案的路徑與檔名
  108.             filename_splitext = os.path.splitext(path_filename[1]) #去掉副檔名
  109.             localpath_subclassfilenames = glob.glob('%s/%s$*' % (path_filename[0],filename_splitext[0]))
  110.             #把子類複製到遠端機器的目錄下
  111.             for localpath_subclassfilename in localpath_subclassfilenames:
  112.                 localpath_subclassfilename = localpath_subclassfilename.replace('\\',r'/')
  113.                 remotepath_subclassfilename = remote_base_path + localpath_subclassfilename.replace('online_svn/WebRoot/','')
  114.                 print "%s is publishing: %s ---> %s " % (hostname,localpath_subclassfilename,remotepath_subclassfilename)
  115.                 sftp.put(localpath_subclassfilename,remotepath_subclassfilename)
  116.                 count += 1
  117.                 print "***********第%s個檔案複製成功,注意該檔案是子類哦^_^ *****************************************" % count
  118.         print " %s機器發版完成!!!".decode('utf-8').encode('gb2312') % hostname
  119.         print('\n')
  120.     trans.close() #記得關閉paramiko的transport連線
  121.                 


  122. #定義函式用來重啟服務
  123. def RestartService(hostname,port,username,password):
  124.     ssh = paramiko.SSHClient() #建立一個從客戶端連線伺服器端的物件,也就是類的例項化
  125.     ssh.load_system_host_keys() #載入主機秘鑰
  126.     ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) #接受不在本地Known_host檔案下的主機。否則ssh需要手工輸入一次yes
  127.     ssh.connect(hostname,port,username,password) #ssh連線
  128.     stdin,stdout,stderr = ssh.exec_command(get_pty=False,command='/usr/local/shell/restartservice.sh')
  129.     result = stdout.read() #內容輸出
  130.     error = stderr.read() #錯誤輸出
  131.     print "%s 在重啟服務...".decode('utf-8').encode('gb2312') % hostname
  132.     print result
  133.     print error
  134.     print('\n')
  135.     ssh.close() #記得關閉paramiko的ssh連線
  136.     
  137.   

  138. #主程式
  139. if __name__ == '__main__':
  140.     #Update SVN
  141.     while True:
  142.         temp = str(raw_input('1) 請問你要Update SVN嗎?[yes/no]:'.decode('utf-8').encode('gb2312')))
  143.         tips = temp.strip().lower()
  144.         if tips == 'yes':
  145.             print "Now begin Update SVN..."
  146.             UpdateSVN('develop_svn')
  147.             break
  148.         elif tips == 'no':
  149.             break
  150.     
  151.     #合併svn
  152.     while True:
  153.         temp = str(raw_input('2) 請問你要把開發svn合併到生產svn裡面嗎?[yes/no]:'.decode('utf-8').encode('gb2312')))
  154.         tips = temp.strip().lower()
  155.         if tips == 'yes':
  156.             print "Now begin Merge SVN..."
  157.             MergeSVN('develop_svn','online_svn')
  158.             break
  159.         elif tips == 'no':
  160.             break
  161.         
  162.     #備份遠端機器上的程式碼
  163.     while True:
  164.         temp = str(raw_input('3)請問你要在發版前,備份一下遠端伺服器上的程式碼嗎?[yes/no]:'.decode('utf-8').encode('gb2312')))
  165.         tips = temp.strip().lower()
  166.         if tips == 'yes':
  167.             print "Now begin backup code..."
  168.             BackupCode(hostname = '10.2.88.2',port = '22',username = 'tms',password = 'xxx')
  169.             BackupCode(hostname = '10.2.88.3',port = '22',username = 'tms',password = 'xxx')
  170.             BackupCode(hostname = '10.2.88.13',port = '22',username = 'tms',password = 'xxx')
  171.             BackupCode(hostname = '10.2.88.14',port = '22',username = 'tms',password = 'xxx')
  172.             BackupCode_HK_QQ(hostname = '10.144.89.252',port = '22',username = 'tms',password = 'xxx')
  173.             break
  174.         elif tips == 'no':
  175.             break
  176.     #提示是否eclipse編譯程式碼
  177.     while True:
  178.         temp = str(raw_input('4) 提示:請問你手工透過eclse編譯tms程式碼了嗎[yes/no]:'))
  179.         tips = temp.strip().lower()
  180.         if tips == 'yes':
  181.             break
  182.         elif tips == 'no':
  183.             break
  184.     
  185.     #預發版
  186.     while True:
  187.         temp = str(raw_input('5)請問你需要先單獨在預發版機器10.2.88.3上測試一下子發版嗎?[yes/no]:'.decode('utf-8').encode('gb2312')))
  188.         tips = temp.strip().lower()
  189.         if tips == 'yes':
  190.             print "Now begin publish code..."
  191.             Publish(hostname='10.2.88.3',port='22',username='tms',password='tmsOo798',local_base_path='online_svn/',remote_base_path='/opt/apache-tomcat-8.0.27/webapps/ROOT/')
  192.             print "Now begin restart service..."
  193.             RestartService(hostname = '10.2.88.3',port = '22',username = 'tms',password = 'tmsOo798')
  194.             break
  195.         elif tips == 'no':
  196.             break

  197.     #生產全發版
  198.     while True:
  199.         temp = str(raw_input('6)請問你要開始在所有正式伺服器上進行發版嗎,包括10.2.88.13/14/2/3,10.144.89.252?[yes/no]:'.decode('utf-8').encode('gb2312')))
  200.         tips = temp.strip().lower()
  201.         if tips == 'yes':
  202.             print "Now begin publish code..."
  203.             Publish(hostname='10.2.88.13',port='22',username='tms',password='xxx',local_base_path='online_svn/',remote_base_path='/opt/apache-tomcat-8.0.27/webapps/ROOT/')
  204.             Publish(hostname='10.2.88.14',port='22',username='tms',password='xxx',local_base_path='online_svn/',remote_base_path='/opt/apache-tomcat-8.0.27/webapps/ROOT/')
  205.             Publish(hostname='10.2.88.2',port='22',username='tms',password='xxx',local_base_path='online_svn/',remote_base_path='/opt/apache-tomcat-8.0.27/webapps/ROOT/')
  206.             Publish(hostname='10.2.88.3',port='22',username='tms',password='xxx',local_base_path='online_svn/',remote_base_path='/opt/apache-tomcat-8.0.27/webapps/ROOT/')
  207.             Publish(hostname='10.144.89.252',port='22',username='tms',password='xxx',local_base_path='online_svn/',remote_base_path='/opt/tomcat-9090-tms/webapps/ROOT/')

  208.             break
  209.         elif tips == 'no':
  210.             break


  211.     #重啟服務
  212.     while True:
  213.         temp = str(raw_input('7)請問你要開始在所有正式伺服器上重啟服務嗎,包括10.2.88.13/14/2/3,10.144.89.252?[yes/no]:'.decode('utf-8').encode('gb2312')))
  214.         tips = temp.strip().lower()
  215.         if tips == 'yes':
  216.             print "Now begin restart service..."
  217.             RestartService(hostname = '10.2.88.13',port = '22',username = 'tms',password = 'xxx')
  218.             print "please wait 60s..."
  219.             time.sleep(60)
  220.             RestartService(hostname = '10.2.88.14',port = '22',username = 'tms',password = 'xxx')
  221.             print "please wait 60s..."
  222.             time.sleep(60)
  223.             RestartService(hostname = '10.2.88.2',port = '22',username = 'tms',password = 'xxx')
  224.             print "please wait 60s..."
  225.             time.sleep(60)
  226.             RestartService(hostname = '10.2.88.3',port = '22',username = 'tms',password = 'xxx')
  227.             print "please wait 60s..."
  228.             time.sleep(60)
  229.             RestartService(hostname = '10.144.89.252',port = '22',username = 'tms',password = 'xxx')
  230.             break
  231.         elif tips == 'no':
  232.             break

  233.     #提示是否手工提交online_svn程式碼
  234.     while True:
  235.         temp = str(raw_input('8) 提示:請問你手工提交online_svn程式碼了嗎?[yes/no]:'))
  236.         tips = temp.strip().lower()
  237.         if tips == 'yes':
  238.             break
  239.         elif tips == 'no':
  240.             break

  241.     #退出本程時要說的話
  242.     print "\n"
  243.     print "*" * 50
  244.     print "親,您的完版完成,記得測試業務是否正常哦!!!"
  245.     print "*" * 50
  246.     sys.exit()

  247.         
  248. #加入下面這句話,才能用windows雙擊執行python指令碼,否則雙擊指令碼會一閃而過
  249. raw_input()


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/28916011/viewspace-2153244/,如需轉載,請註明出處,否則將追究法律責任。

相關文章