文件打包、上传与校验我们时常做一些文件包分发的工作,实施步骤一般是先压缩打包,
再批量上传至目标服务器,最后做一致性校验。
本案例通过put()方法实现文件的上传,通过对比本地与远程主机文件的md5,最终实现文件一致性校验。
详细源码如下:
#!/usr/bin/env python
#_*_coding:utf-8 _*_
__author__ = 'gaogd'

from fabric.api import *
from fabric.context_managers import *
from fabric.contrib.console import confirm


env.user='root'
env.hosts=['192.168.23.140','192.168.23.141']
env.password='xxx@xxx'


@task
@runs_once
def tar_task(): #本地打包任务函数,只限执行一次
    with lcd("/tmp"):
        local("tar -czf access.tar.gz access.log")

@task
def put_task(): #上传文件任务函数
    run("mkdir -p /tmp/test/")
    with cd("/tmp/test/"):
        with settings(warn_only=True): #put(上传)出现异常时继续执行,非终止
            result = put("/tmp/access.tar.gz","/tmp/test/access.tar.gz")
    if result.failed and not confirm("put file failed,Continue[Y/N]?"):
        abort("Aborting file put task!") #出现异常时,确认用户是否继续,(Y继续)

@task
def check_task(): #校验文件任务函数
    with settings(warn_only=True):
        #本地local命令需要配置capture=True才能捕获返回值
        lmd5=local("md5sum /tmp/access.tar.gz",capture=True).split(' ')[0]
        rmd5=run("md5sum /tmp/test/access.tar.gz").split(' ')[0]

    if lmd5==rmd5: #对比本地及远程文件md5信息
        print "OK"
    else:
        print "ERROR"

    print 'lmd5:',lmd5
    print 'rmd5:',rmd5



########################################################
部署LNMP业务服务环境
业务上线之前最关键的一项任务便是环境部署,往往一个业务涉及多种应用环境,
比如Web、DB、PROXY、CACHE等,本示例通过env.roledefs定义不同主机角色,
再使用“@roles('webservers')”修饰符绑定到对应的任务函数,
实现不同角色主机的部署差异,详细源码如下:


#!/usr/bin/env python
#_*_coding:utf-8 _*_
__author__ = 'gaogd'

from fabric.colors import *
from fabric.api import *

env.user = 'root'

env.roledefs = {  # 定义业务角色分组
    'webservers': ['192.168.1.21', '192.168.1.22'],
    'dbservers': ['192.168.1.23']
}

env.passwords = {
    'root@192.168.1.21:22': 'SJk348ygd',
    'root@192.168.1.22:22': 'KSh458j4f',
    'root@192.168.1.23:22': 'KSdu43598'
}

@roles('webservers')  # webtask任务函数引用'webservers'角色修饰符
def webtask():  # 部署nginx php php-fpm等环境
    print yellow("Install nginx php php-fpm...")
    with settings(warn_only=True):  ##出现异常时继续执行,非终止
        run("yum -y install nginx")
        run("yum -y install php-fpm php-mysql php-mbstring php-xml phpmcrypt php-gd")
        run("chkconfig --levels 235 php-fpm on")
        run("chkconfig --levels 235 nginx on")


@roles('dbservers')  # dbtask任务函数引用'dbservers'角色修饰符
def dbtask():  # 部署mysql环境
    print yellow("Install Mysql...")
    with settings(warn_only=True):  ##出现异常时继续执行,非终止
        run("yum -y install mysql mysql-server")
        run("chkconfig --levels 235 mysqld on")


@roles('webservers','dbservers')  # publictask任务函数同时引用两个角色修饰符
def publictask():  # 部署公共类环境,如epel、ntp等
    print yellow("Install epel ntp...")
    with settings(warn_only=True):
        run("rpm -Uvh http://dl.fedoraproject.org/pub/epel/6/x86_64/epelrelease-6-8.noarch.rpm")
        run("yum -y install ntp")


def deploy():
    execute(publictask)
    execute(webtask)
    execute(dbtask)



生产环境代码包发布管理
程序生产环境的发布是业务上线最后一个环节,
要求具备源码打包、发布、切换、回滚、版本管理等功能,本示例实现了这一整套流程功能,
其中版本切换与回滚使用了Linux下的软链接实现。详细源码如下:
#!/usr/bin/env python
#_*_coding:utf-8 _*_
__author__ = 'gaogd'

from fabric.api import *
from fabric.colors import *
from fabric.context_managers import *
from fabric.contrib.console import confirm
import time
env.user='root'
env.hosts=['192.168.1.21','192.168.1.22']
env.password='LKs934jh3'

env.project_dev_source = '/data/dev/Lwebadmin/'     #开发机项目主目录
env.project_tar_source = '/data/dev/releases/'      #开发机项目压缩包存储目录
env.project_pack_name = 'release'                   #项目压缩包名前缀,文件名为release.tar.gz

env.deploy_project_root = '/data/www/Lwebadmin/'    #项目生产环境主目录
env.deploy_release_dir = 'releases'                 #项目发布目录,位于主目录下面 /data/www/Lwebadmin/releases
env.deploy_current_dir = 'current'                  #对外服务的当前版本软链接 /data/www/Lwebadmin/current
env.deploy_version=time.strftime("%Y%m%d")+"v2"     #版本号

@runs_once
def input_versionid(): #获得用户输入的版本号,以便做版本回滚操作
    return prompt("please input project rollback version ID:",default="")

@task
@runs_once
def tar_source(): #打包本地项目主目录,并将压缩包存储到本地压缩包目录
    print yellow("Creating source package...")
    with lcd(env.project_dev_source):  # cd /data/dev/Lwebadmin/
        local("tar -czf %s.tar.gz ." % (env.project_tar_source +env.project_pack_name))
        ## cd /data/dev/Lwebadmin/
        ##  tar -zcf   /data/dev/releases/release.tar.gz  .
    print green("Creating source package success!")

@task
def put_package(): #上传任务函数
    print yellow("Start put package...")
    with settings(warn_only=True):
        with cd(env.deploy_project_root+env.deploy_release_dir):   ## cd  /data/www/Lwebadmin/releases
            run("mkdir %s" % (env.deploy_version)) #创建版本目录   mkdir time.strftime("%Y%m%d")+"v2"
            env.deploy_full_path=env.deploy_project_root + env.deploy_release_dir+"/"+env.deploy_version
            ##env.deploy_full_path = "/data/www/Lwebadmin/releases/20160111v2 "


    with settings(warn_only=True): #上传项目压缩包至此目录
        result = put(env.project_tar_source + env.project_pack_name+".tar.gz",env.deploy_full_path)
        ## scp /data/dev/releases/release.tar.gz   root@192.168.10.11:/data/www/Lwebadmin/releases/20160111v2
        if result.failed and not ("put file failed,Continue[Y/N]?"):
            abort("Aborting file put task!")
        with cd(env.deploy_full_path): #成功解压后删除压缩包 cd /data/www/Lwebadmin/releases/20160111v2
            run("tar -zxvf %s.tar.gz" % (env.project_pack_name))
            ## tar -zxvf  /data/www/Lwebadmin/releases/20160111v2/release.tar.gz
            run("rm -rf %s.tar.gz" % (env.project_pack_name))
            ## rm -rf   /data/www/Lwebadmin/releases/20160111v2/release.tar.gz

    print green("Put & untar package success!")


@task
def make_symlink(): #为当前版本目录做软链接
    print yellow("update current symlink")
    env.deploy_full_path=env.deploy_project_root + env.deploy_release_dir+"/"+env.deploy_version
    ## env.deploy_full_path =  '/data/www/Lwebadmin/' releases  20160111v2
    with settings(warn_only=True): #删除软链接,重新创建并指定软链源目录,新版本生效
        run("rm -rf %s" % (env.deploy_project_root +env.deploy_current_dir))
        ##  rm -rf /data/www/Lwebadmin/current
        run("ln -s %s %s" % (env.deploy_full_path,env.deploy_project_root + env.deploy_current_dir))
        ## ln -s /data/www/Lwebadmin/releases/20160111v2  /data/www/Lwebadmin/current
        print green("make symlink success!")


@task
def rollback(): #版本回滚任务函数
    print yellow("rollback project version")
    versionid= input_versionid() #获得用户输入的回滚版本号
    if versionid=='':
        abort("Project version ID error,abort!")

    env.deploy_full_path=env.deploy_project_root + env.deploy_release_dir+"/"+versionid
    ## env.deploy_full_path =  '/data/www/Lwebadmin/'releases/20160111v2(输入的版本号)
    run("rm -f %s" % env.deploy_project_root + env.deploy_current_dir)
    ##删除软链接,   rm -rf /data/www/Lwebadmin/current
    run("ln -s %s %s" % (env.deploy_full_path,env.deploy_project_root +env.deploy_current_dir))
    ##ln -s /data/www/Lwebadmin/releases/20160111v2(输入的版本号)   /data/www/Lwebadmin/current
    ## 重新创建并指定软链源目录,新版本生效
    print green("rollback success!")


@task
def go(): #自动化程序版本发布入口函数
    tar_source()
    put_package()
    make_symlink()