从FTP服务器下载文件部署更新linux服务器上的服务

作为软件测试人员,经常要发布开发的集成包。本来嘛,更新个服务,没什么大不了。但是集成包打出来,要更新的服务有9个(分别部署在三台服务器上),并且以后还会增加。如果手动更新,每次更新时间都得20分钟以上,长此以往,非常浪费时间。

更新流程背景

1、从一台可用FTP连接的服务器上,下载集成人员集成好的最新包。
2、解压下载的集成包,解压后,生成9个程序包,每个程序包是以.tar.gz格式压缩。
3、将9个包,分别上传至对应服务器(3台linux服务器)
4、关闭服务器上的服务,并备份未更新前的服务程序
5、解压上传的.tar.gz文件至指定目录
6、替换加压后文件中的一个conf文件夹中的配置
7、启动服务。

脚本编写

从FTP服务器下载文件

python 内置ftplib库,可以方便的通过FTP连接服务器

FTP连接

def ftp_connect(host, port, username, password, encoding="UTF-8"):
    """Connect server via FTP.
    If connect sucessfully, return ftp object, else return False!"""
    try:
        ftp = FTP()
        ftp.set_debuglevel(0)   #打开调试级别2,显示详细信息;0为关闭调试信息 
        ftp.set_pasv(0)#0主动模式 1 #被动模式
        ftp.encoding = encoding
        ftp.connect(host, port)
        ftp.login(username, password)   #登录,如果匿名登录则用空串代替即可 
        return ftp
    except Exception as e:
        print("Connect FTP Error!")
        print("Error:", str(e))
        return False

定义一个函数,传参分别是服务器IP,端口,用户名,密码,编码。

FTP文件下载

def ftp_download():
    """Download file via ftp connection!
    Get the latest file from the dir file_path["DB/Middle"][0],
    Save the file to the dir file_path["DB/Middle"][1]."""
    file_path = {"DB":["/省略.../DB", "D:/FTP/DB/"], "Middle":["/省略.../Middle", "D:/FTP/Middle/"]}
    ftp = ftp_connect()
    if ftp:
        for each in file_path:
            ftp.cwd("/") #改变路径
            try:
                ftp.cwd(file_path[each][0]) #改变路径
            except:
                print("There is no such [%s] directory!" % file_path[each][0])
                continue
            #ftp.dir()
            #print ftp.getwelcome()#显示ftp服务器欢迎信息 
            #ftp.cwd('xxx/xxx/') #选择操作目录

            del_dir(file_path[each][1], isfile=True) #删除当前目录的解压后的文件夹
            bufsize = 1024 
            file_name = ftp.nlst()[-1] #取当前路径的文件名列表(按时间顺序排序)
            try:
                file_handler = open(file_path[each][1] + file_name,'wb').write #以写模式在本地打开文件
            except:
                print("There is no such [%s] directory!" % file_path[each][1])
                continue
            try:
                print("[%s] will be downloaded!" % file_name)
                ftp.retrbinary('RETR %s' % os.path.basename(file_name),file_handler,bufsize)#接收服务器上文件并写入本地文件 
                #ftp.set_debuglevel(0) 
                #file_handler.close()
                print("[%s] downloads completed!" % file_name)
            except Exception as e:
                print("Download file[%s] Error!" % file_name)
                print("Error:", str(e))
        ftp.quit()

介绍一下file_path变量:

file_path = {"DB":["/省略.../DB", "D:/FTP/DB/"], "Middle":["/省略.../Middle", "D:/FTP/Middle/"]}
file_path["DB"][0]是FTP服务器上下载的需要执行的sql文件
file_path["DB"][1]是FTP服务器上下载的需要执行的sql文件存放于本地磁盘的路径
file_path["Middle"][0]是FTP服务器上下载的中台程序包(解压后会产生9个.tar.gz包)
file_path["Middle"][1]是FTP服务器上下载的中台程序包存放于本地磁盘的路径

del_dir()是自定义的函数,主要作用是删除当前目录下的所有文件或者文件夹。具体实现如下:

def del_dir(path, isdir=True, isfile=False):
    """Delete files or directories!
    The files or directories whether would be deleted pointing to isdir/isfile is true or false.
    If true, then will be deleted"""
    os.chdir(path)
    for each in os.listdir():
        if os.path.isdir(each):
            if isdir:
                shutil.rmtree(each)
                print("The dir[%s] was removed!" % each)
        else:
            if isfile:
                os.remove(each)
                print("The file[%s] was removed!" % each)

此处还用到解压.rar文件,需要安装rarfile库。
解压方法如下:

def un_rar(path):
    """Extract rar file!
    Argue path is the dir, file is the one which will be extract!"""
    try:
        os.chdir(path)
        for each in os.listdir():
            if os.path.isfile(each):#当前目录只有一个文件
                file = each
        rar = rarfile.RarFile(file) 
        os.mkdir(file[:-4]) #创建rar文件解压后的存放路径
        rar.extractall(file[:-4]) #解压文件到指定路径
        print("Un_rar file[%s] Successfully!" % file)
    except Exception as e:
        print("Un_rar file[%s] failed!" % file)
        print("Error:", str(e))
    finally:
        rar.close()

SSH连接

python支持ssh连接的库还是比较多的,此处选择paramiko库(关于windows安装paramiko库,我在上一篇文章中做了记录,可供大家参考)

def ssh_connect(host="192.168.226.131", port=22, username="root", password="chenkang0818", encoding="UTF-8"):
    """Connect to server via SSH.
    If connect successfully return ssh object, else return False."""
    try:
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())   #这行代码的作用是允许连接不在know_hosts文件中的主机。
        ssh.connect(host, port=port, username=username, password=password)
        return ssh
    except Exception as e:
        print("SSH Connect Error!")
        print("Error:", e)
        return False

SSH连接linux服务器上传文件

连接服务器成功后,接下来就是上传文件。使用sftp.put(file_1,file_2)命令,如果服务器存在file_2,那么该文件会被替换,如果没有则直接拷贝至服务器。

def ssh_upload():
    """A ssh upload fuction!"""
    for ip in SERVER_INFO:
        ssh = ssh_connect(host=ip, port=SERVER_INFO[ip]["port"], username=SERVER_INFO[ip]["username"], password=SERVER_INFO[ip]["password"]) #以ssh形式连接服务器
        if not ssh: #如果连接不成功,则跳过
            print("Connect server[%s] failed!" % ip)
            continue
        call_command(ssh, "cd middle; ./middle_stop")   #连接上服务器后,执行关闭服务脚本
        print("Preparing for starting...............")
        sftp = ssh.open_sftp()  #打开一个sftp形式连接服务器
        os.chdir(SERVER_INFO[ip]["get_path"])
        try:
            if len((lambda count=0:[ count+1 for each in os.listdir() if os.path.isdir(each)])()) == 1:  #防止middle文件夹中含有多个解压文件夹,确保上传服务器的文件是最新的
                for each in os.listdir():
                    if os.path.isdir(each):
                        local_get_path = os.path.join(os.getcwd(), each) #合并路径
                        print("Uploading file on the server [%s]" % (ip))
                        for file in SERVER_INFO[ip]["get_file"]:
                            local_get_file = os.path.join(local_get_path, file) #合并路径
                            sftp.put(local_get_file, "/home/hundsun/middle/" + file) #将本地文件上传至服务器
                            print("Up file[%s] successfully!" % file)
                        call_command(ssh, "cd middle; ./middle_start") #当前服务器所有tar文件替换完毕后,执行启动脚本
        except Exception as e:
            print("Upload file[%s] failed!" % file)
            print("Error:", str(e))
        finally:
            sftp.close()
            ssh.close()

说明:

SERVER_INFO是定义的一个字典,其格式为:
SERVER_INFO = {"xx.xx.xx.xx":{"port":22, "username":"root", "password":"xxxxxx", "get_path":"D:/FTP/Middle/", 
                                     "get_file":["xx1.tar.gz", 
                                                  "xx2.tar.gz",
                                                  "xx3.tar.gz"],
                                     "save_path":"/home/省略.../"}}

其中get_path是指:要上传服务器的程序包(.tar.gz文件)的本地路径get_file的是指:需要上传至服务器更新的程序包
save_path是指:上传至linux服务器的路径

os.path.join(get_path, get_file)是要上传的程序包的整个路径

call_command()是自定义函数,主要是运行服务器上启动,停止服务的脚本。定义如下:

def call_command(ssh, cmd):
    stdin,stdout,stderr = ssh.exec_command(cmd)
    print("-------------------return result--------------------")
    for each in stdout.readlines():
        print(each)
    print("----------------------Error-------------------------")
    for each in stderr.readlines():
        print(each)

这里着重说一下paramiko的exec_command(cmd)方法。
开始的时候我产生一个误区,以为:先执行ssh.exec_command(“cd /home/abc/efg”),shh就会定位在/home/abc/efg,其实不是这样的。
通过paramiko建立ssh连接,会默认定位于/home/当前用户的路径。
如果你想先cd /home/abc/efg,而后执行/home/abc/efg路径下的脚本./stop.sh则应该这样:ssh.exec_command(“cd /home/abc/efg; ./stop.sh”)

运行程序

以下是运行程序方法:

spend_time()(ftp_down)
un_rar("D:/FTP/Middle/")
un_rar("D:/FTP/DB/")
spend_time()(ssh_upload)

为了查看各个过程花费的时长,做了个时间统计。前面说手动操作是20分钟以上,那么当然想看看程序能为我们节省下多少时间。
spend_time()函数定义如下:

def spend_time():
    """Calculate calling a fuctionthe how longs it will spend. """
    time1 = time.time()
    def wrapper(func):
        func()
        time2 = time.time()
        return print(time2-time1)
    return wrapper

涉及库

以下是支撑该脚本运行的库

from ftplib import FTP 
import os, time
import paramiko
import rarfile
import shutil
import pymysql

windows安装paramiko库我上篇文章提过。
windows安装rarfile安装可用pip命令。安装完毕之后,找到windows下rar安装路径,将Unrar.exe放在python的环境变量中即可。
以下是windows 64位Unrar.exe程序包。
链接:http://pan.baidu.com/s/1hsJmZbe 密码:ee6h

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值