用paramiko模块写的发版机


说明:为了安全,本文敏感信息如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脚本

点击(此处)折叠或打开

#-*-coding:utf-8-*-
import Crypto #paramiko模块依赖Crypto模块
import paramiko #paramiko模块是wnidows 远程linux机器用的模块
import os
import sys
import shutil #shutil模块下有copy文件夹的方法
import time #这里使用其休眠函数sleep
import subprocess
import glob



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


#定义函数用来合并svn
def MergeSVN(develop_svn,online_svn):
    with open('filelist.txt') as f:
        for index,line in enumerate(f,1): #1表示索引值从1开始
            line = line.replace('/trunk','') #替换路径
            line = line.replace('\n','') #把换行替换掉,\n是换行符的意思
            develop_svn_path=develop_svn + line #拼接路径
            online_svn_path = online_svn + line #拼接路径
            print "%d copying: %s ---> %s" % (index,develop_svn_path,online_svn_path)
            if not os.path.exists(os.path.dirname(online_svn_path)) : #如果目录不存在,就建立一个目录,注意exists方法返回的是布尔值,所以用Not进行否定
                os.mkdir(os.path.dirname(online_svn_path)) #建立目录
            shutil.copy(develop_svn_path,online_svn_path) #将develop_svn_path里面的代码拷贝到online_svn_path目录下
    print('\n') #输出一个换行
    print("合并SVN目录已完成,请手工通过ecplice编译代码".decode('utf-8').encode('gb2312'))
    print('\n') #输出一个换行
     
    


#定义函数用来远程备份代码--给北京的机器备份
def BackupCode(hostname,port,username,password):
    ssh = paramiko.SSHClient() #创建一个从客户端连接服务器端的对象,也就是类的实例化
    ssh.load_system_host_keys() #加载主机秘钥
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) #接受不在本地Known_host文件下的主机。否则ssh需要手工输入一次yes
    ssh.connect(hostname,port,username,password) #ssh连接
    
    stdin,stdout,stderr = ssh.exec_command(get_pty=False,command='dir=$(date +%Y%m%d%H%M%S) && \
                                             rsync -zrtopg --exclude geadPortrait/ \
                                           --exclude=idcard/ --exclude=temp/ --exclude=upload \
                                           --exclude=files --exclude=temporary_zip/ \
                                           /opt/apache-tomcat-8.0.27/webapps/ROOT /backup/tms/$dir') #执行远程机器的rsync命令进行备份,rsync命令没加-v参数,所以正常信息不会输出,只有报错才输出内容
    result = stdout.read() #内容输出
    error = stderr.read() #错误输出
    print result
    print error
    #判断是否有错误输出,没有就说备份成功,否则说备份失败
    if result.strip()=="" and error.strip()=="":
        print "%s 完美,备份成功,备份位置在远程机器的/backup目录下".decode('utf-8').encode('gb2312') % hostname
        print('\n')
    else:
        print "%s 不好了,备份失败了".decode('utf-8').encode('gb2312') % hostname
        print('\n')
    ssh.close() #记得关闭paramiko的ssh连接






#定义函数用来远程备份代码--给香港腾讯的机器备份
def BackupCode_HK_QQ(hostname,port,username,password):
    ssh = paramiko.SSHClient() #创建一个从客户端连接服务器端的对象,也就是类的实例化
    ssh.load_system_host_keys() #加载主机秘钥
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) #接受不在本地Known_host文件下的主机。否则ssh需要手工输入一次yes
    ssh.connect(hostname,port,username,password) #ssh连接
    stdin,stdout,stderr = ssh.exec_command(get_pty=False,command='dir=$(date +%Y%m%d%H%M%S) && \
                                            rsync -zrtopg --exclude geadPortrait/ \
                                           --exclude=idcard/ --exclude=temp/ --exclude=upload \
                                           --exclude=files --exclude=temporary_zip/ \
                                           /opt/tomcat-9090-tms/webapps/ROOT /backup/tms/$dir') #执行远程机器的rsync命令进行备份,rsync命令没加-v参数,所以正常信息不会输出,只有报错才输出内容
    result = stdout.read() #内容输出
    error = stderr.read() #错误输出
    print result
    print error
    #判断是否有错误输出,没有就说备份成功,否则说备份失败
    if result.strip()=="" and error.strip()=="":
        print "%s 完美,备份成功,备份位置在远程机器的/backup目录下".decode('utf-8').encode('gb2312') % hostname
        print('\n')
    else:
        print "%s 不好了,备份失败了".decode('utf-8').encode('gb2312') % hostname
        print('\n')
    ssh.close() #记得关闭paramiko的ssh连接


        

#定义函数用来远程执行发版动作
def Publish(hostname,port,username,password,local_base_path,remote_base_path):
    count = 0
    trans = paramiko.Transport(hostname,port) #建立paramiko的transport方式连接
    trans.connect(username=username,password=password) #建立连接
    sftp = paramiko.SFTPClient.from_transport(trans) #建立连接
    with open('filelist.txt','r') as f:
        for line in f:
            #本地路径预处理
            localpath_filename = line.replace('/trunk/src','WebRoot/WEB-INF/classes')
            localpath_filename = localpath_filename.replace('/trunk/WebRoot','WebRoot')
            localpath_filename = localpath_filename.replace('.java','.class')
            localpath_filename = localpath_filename.replace('\n','') #把换行替换掉
            #构造真正的父类本地路径
            localpath_filename = local_base_path + localpath_filename
            #构造真正的父类远程路径
            remotepath_filename = remote_base_path + localpath_filename.replace('online_svn/WebRoot/','')
            #拷贝父类到远程机器上
            print "%s is publishing: %s ---> %s " % (hostname,localpath_filename,remotepath_filename)
            try:
                sftp.listdir(os.path.dirname(remotepath_filename)) #加个错误处理,如果目录不存在,就建立一个目录
            except IOError:
                sftp.mkdir(os.path.dirname(remotepath_filename))
            sftp.put(localpath_filename,remotepath_filename)
            count += 1
            print "***********第%s个文件发版成功***************" % count
            #用glob模块寻找子类
            path_filename = os.path.split(localpath_filename) #split:返回一个二元组,包含文件的路径与文件名
            filename_splitext = os.path.splitext(path_filename[1]) #去掉文件扩展名
            localpath_subclassfilenames = glob.glob('%s/%s$*' % (path_filename[0],filename_splitext[0]))
            #把子类拷贝到远程机器的目录下
            for localpath_subclassfilename in localpath_subclassfilenames:
                localpath_subclassfilename = localpath_subclassfilename.replace('\\',r'/')
                remotepath_subclassfilename = remote_base_path + localpath_subclassfilename.replace('online_svn/WebRoot/','')
                print "%s is publishing: %s ---> %s " % (hostname,localpath_subclassfilename,remotepath_subclassfilename)
                sftp.put(localpath_subclassfilename,remotepath_subclassfilename)
                count += 1
                print "***********第%s个文件拷贝成功,注意该文件是子类哦^_^ *****************************************" % count
        print " %s机器发版完成!!!".decode('utf-8').encode('gb2312') % hostname
        print('\n')
    trans.close() #记得关闭paramiko的transport连接
                


#定义函数用来重启服务
def RestartService(hostname,port,username,password):
    ssh = paramiko.SSHClient() #创建一个从客户端连接服务器端的对象,也就是类的实例化
    ssh.load_system_host_keys() #加载主机秘钥
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) #接受不在本地Known_host文件下的主机。否则ssh需要手工输入一次yes
    ssh.connect(hostname,port,username,password) #ssh连接
    stdin,stdout,stderr = ssh.exec_command(get_pty=False,command='/usr/local/shell/restartservice.sh')
    result = stdout.read() #内容输出
    error = stderr.read() #错误输出
    print "%s 在重启服务...".decode('utf-8').encode('gb2312') % hostname
    print result
    print error
    print('\n')
    ssh.close() #记得关闭paramiko的ssh连接
    
  

#主程序
if __name__ == '__main__':
    #Update SVN
    while True:
        temp = str(raw_input('1) 请问你要Update SVN吗?[yes/no]:'.decode('utf-8').encode('gb2312')))
        tips = temp.strip().lower()
        if tips == 'yes':
            print "Now begin Update SVN..."
            UpdateSVN('develop_svn')
            break
        elif tips == 'no':
            break
    
    #合并svn
    while True:
        temp = str(raw_input('2) 请问你要把开发svn合并到生产svn里面吗?[yes/no]:'.decode('utf-8').encode('gb2312')))
        tips = temp.strip().lower()
        if tips == 'yes':
            print "Now begin Merge SVN..."
            MergeSVN('develop_svn','online_svn')
            break
        elif tips == 'no':
            break
        
    #备份远程机器上的代码
    while True:
        temp = str(raw_input('3)请问你要在发版前,备份一下远程服务器上的代码吗?[yes/no]:'.decode('utf-8').encode('gb2312')))
        tips = temp.strip().lower()
        if tips == 'yes':
            print "Now begin backup code..."
            BackupCode(hostname = '10.2.88.2',port = '22',username = 'tms',password = 'xxx')
            BackupCode(hostname = '10.2.88.3',port = '22',username = 'tms',password = 'xxx')
            BackupCode(hostname = '10.2.88.13',port = '22',username = 'tms',password = 'xxx')
            BackupCode(hostname = '10.2.88.14',port = '22',username = 'tms',password = 'xxx')
            BackupCode_HK_QQ(hostname = '10.144.89.252',port = '22',username = 'tms',password = 'xxx')
            break
        elif tips == 'no':
            break
    #提示是否eclipse编译代码
    while True:
        temp = str(raw_input('4) 提示:请问你手工通过eclse编译tms代码了吗[yes/no]:'))
        tips = temp.strip().lower()
        if tips == 'yes':
            break
        elif tips == 'no':
            break
    
    #预发版
    while True:
        temp = str(raw_input('5)请问你需要先单独在预发版机器10.2.88.3上测试一下子发版吗?[yes/no]:'.decode('utf-8').encode('gb2312')))
        tips = temp.strip().lower()
        if tips == 'yes':
            print "Now begin publish code..."
            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/')
            print "Now begin restart service..."
            RestartService(hostname = '10.2.88.3',port = '22',username = 'tms',password = 'tmsOo798')
            break
        elif tips == 'no':
            break

    #生产全发版
    while True:
        temp = str(raw_input('6)请问你要开始在所有正式服务器上进行发版吗,包括10.2.88.13/14/2/3,10.144.89.252?[yes/no]:'.decode('utf-8').encode('gb2312')))
        tips = temp.strip().lower()
        if tips == 'yes':
            print "Now begin publish code..."
            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/')
            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/')
            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/')
            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/')
            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/')

            break
        elif tips == 'no':
            break


    #重启服务
    while True:
        temp = str(raw_input('7)请问你要开始在所有正式服务器上重启服务吗,包括10.2.88.13/14/2/3,10.144.89.252?[yes/no]:'.decode('utf-8').encode('gb2312')))
        tips = temp.strip().lower()
        if tips == 'yes':
            print "Now begin restart service..."
            RestartService(hostname = '10.2.88.13',port = '22',username = 'tms',password = 'xxx')
            print "please wait 60s..."
            time.sleep(60)
            RestartService(hostname = '10.2.88.14',port = '22',username = 'tms',password = 'xxx')
            print "please wait 60s..."
            time.sleep(60)
            RestartService(hostname = '10.2.88.2',port = '22',username = 'tms',password = 'xxx')
            print "please wait 60s..."
            time.sleep(60)
            RestartService(hostname = '10.2.88.3',port = '22',username = 'tms',password = 'xxx')
            print "please wait 60s..."
            time.sleep(60)
            RestartService(hostname = '10.144.89.252',port = '22',username = 'tms',password = 'xxx')
            break
        elif tips == 'no':
            break

    #提示是否手工提交online_svn代码
    while True:
        temp = str(raw_input('8) 提示:请问你手工提交online_svn代码了吗?[yes/no]:'))
        tips = temp.strip().lower()
        if tips == 'yes':
            break
        elif tips == 'no':
            break

    #退出本程时要说的话
    print "\n"
    print "*" * 50
    print "亲,您的完版完成,记得测试业务是否正常哦!!!"
    print "*" * 50
    sys.exit()

        
#加入下面这句话,才能用windows双击运行python脚本,否则双击脚本会一闪而过
raw_input()


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/28916011/viewspace-2153244/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/28916011/viewspace-2153244/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值