代码分发脚本

kevin.Zhu 发布于:2013-3-5 12:25 分类:小喇叭  有 20 人浏览,获得评论 0 条  

#!/bin/bash
# Version: 1.1.0
# 代码分发:将测试机上待更新的代码分发到指定的生产节点中 zkf 2016-2-16
# version:1.0.1 2016-2-18 , 完善对备份操作的文件检测 增加帮助选项 版本列表选项
# version:1.0.2 2016-2-19 , 增加备份、分发的提示信息
# version:1.1.0 2016-2-19 19:24:19 , 合并了多个项目,使脚本可以完成多项目的分发任务
# 代码分发前会对需要更新的代码先做备份
# 每次分发会产生一个版本号,版本号从 1开始
# 版本号和对应的分发时间会生成日志文件
# 备份的代码会自动保存到 版本号-1的目录中(如当前版本号为1,则备份目录为 v0)

# ***************** 配置项,这里不需要定义 下方集中定义****************
#项目名称
proj_name=''

#需要分发的节点
hosts=('172.16.7.213' '172.16.18.237')
#hosts=('172.16.9.151')

#备份文件源(使用哪个节点的文件做备份)
bak_source_host='172.16.7.213'

#分发路径前缀,如果不为数组 则所有节点相同; 否则必须定义为数组且和节点数组一一对应
#2个及2个以上才定义成数组 (暂未实现)
#file_path_pre=('/mydata1/www/' '/mydata1/www/') 
file_path_pre='/mydata1/www/app186.sunyoupai.com/'

#分发文件列表
up_lst_file="/root/tool/publish_laba.lst"

#备份路径
bak_path="/root/tool/publish_bak/"

#版本记录文件 - 记录格式:版本号 分发时间
#如:   1 2016-2-17    ,表示: 版本为1 分发时间为2016-2-17
ver_file="/root/tool/publish.version"

#回退版本号, 只能回退到当前版本以前的版本
back_version=''



#v回退版本号 back_version 
opt_version=''
lst_version=''
while getopts "v:t:hl" arg ; do
    case $arg in
        v)
            opt_version=$OPTARG
            ;;
        t)
            proj_name=$OPTARG
            ;;
        h)
            echo "=================================== 帮助信息 ===================================" 
            echo "v:指定回退版本号,t:项目名称,l:列出版本号列表"
            exit
            ;;
        l)
            lst_version='ok'
            ;;
        ?)
            echo "存在未知参数, 有效参数为 v t hl" ; exit; 
            ;;
    esac
done

if [ -z "$proj_name" ]; then 
    echo "请指定项目名称" ; exit; 
fi

# **************************  此处集中定义所有配置  ********************
if [ "$proj_name" = "laba" ]; then 
    hosts=('172.16.7.213' '172.16.18.237')
    bak_source_host='172.16.7.213'
    file_path_pre='/mydata1/www/app186.sunyoupai.com/'
    up_lst_file="/root/tool/publish_laba.lst"
    bak_path="/root/tool/publish_bak/"
    ver_file="/root/tool/publish.version"
elif [ "$proj_name" = "laba" ]; then 
    hosts=('172.16.7.213' '172.16.18.237')
    bak_source_host='172.16.7.213'
    file_path_pre='/mydata1/www/app186.sunyoupai.com/'
    up_lst_file="/root/tool/publish_laba.lst"
    bak_path="/root/tool/publish_bak/"
    ver_file="/root/tool/publish.version"
else
    echo "未定义的项目名" ; exit; 
fi
#回退版本文件路径, 默认设置为当前备份路径
back_version_path="$bak_path"
back_version="$opt_version"
# **************************  此处集中定义所有配置 end  ********************

if [ -n "$lst_version" ]; then
    echo "版本记录:$ver_file"
    cat "$ver_file"
    echo
    echo "备份目录:$bak_path"
    ls -l "$bak_path" ; exit ;
fi


# ************************************************ 函数 ******************************************
#记录更新版本号
function fun_log_version() {
    ver_file=$1 
    back_ver=$2
    hosts=$3
    back_mark=''
    v_info=$(tail -n 1  "$ver_file" | awk '{print $1;}')
    if [ "$v_info" = "" ]; then   v_info=1 ; else  let "v_info = v_info + 1"; fi 
    tm=$(date +%Y-%m-%d_%H:%M)
    if [ -n "$back_ver" ]; then 
        back_mark="b${back_ver}"
    fi
    echo "$v_info    $tm    \"${hosts[@]}\"    $back_mark"    >>  $ver_file 
}

# 分发指定列表中的文件
function publish_lst() {
    uplst_file=$1 
    target_host=$2
    path_pre=$3
    ver_file=$4
    
    if [ ! -f "$uplst_file" ]; then
        echo "列表文件不存在"; exit; 
    fi
    
    up_lst=$(cat "$uplst_file") 
    if [ -z "$up_lst" ]; then
        echo "更新文件列表为空" ; exit; 
    fi
    
    if [ -z "$target_host" ]; then
        echo "目标主机不能为空"; exit; 
    fi
    
    echo "$up_lst" | while read fl; do  
        if [ ! -d  "${path_pre}${fl}" ]; then
            if [ -f "${path_pre}${fl}" ]; then
                rsync -aRzv  ${path_pre}${fl}  root@$target_host:${path_pre}${fl}
            else
                echo "文件不存在: ${path_pre}${fl}"
            fi
        fi
    done
}

# 备份指定列表中的文件到本地
function bak_lst() {
    uplst_file=$1 
    bak_path=$2
    path_pre=$3
    host=$4
    
    if [ ! -f "$uplst_file" ]; then
        echo "列表文件不存在,无法备份"; exit; 
    fi
    
    lst=$(cat "$uplst_file") 
    if [ -z "$lst" ]; then
        echo "文件列表为空, 程序退出" ; exit; 
    fi
    
    #创建备份目录
    if [ ! -d "$bak_path" ]; then 
        mkdir -p "$bak_path" 
    fi
    
    echo "===================================== 开始备份,备份源为:$host ======================================" 
    echo "$lst" | while read fl; do  
        local_path=$(dirname ${bak_path}${path_pre}${fl}) 
        if [ ! -d "$local_path" ]; then
            mkdir -p "$local_path" 
        fi
        
        if [ ! -d  "${path_pre}${fl}" ]; then
            rsync -aRzv root@$host:${path_pre}${fl}   ${bak_path}${path_pre}${fl}
        fi
    done
}

# ****************************************************  主程序 **********************************************
notice='';
#设置了back_version 则为回退操作 ,否则为分发
if [ -n "$back_version" ];then
    notice="回退至版本: $back_version"
    if [ -n "$back_version_path" ];then
        notice=${notice}", 回退路径设置为: $back_version_path"
    fi
else
    notice="更新列表文件设置为: $up_lst_file"
fi

echo '======================================='
echo $notice
echo '======================================='
echo
echo '是否开始操作?(y/n)' 
read doit
if [ "$doit" != 'y' ] ; then 
    echo '已取消' ; exit ;
fi

#检查版本文件是否存在
if [ ! -f "$ver_file" ]; then
    echo "找不到版本记录文件 $ver_file"; exit; 
fi

#当前版本
v_info=$(tail -n 1  "$ver_file" | awk '{print $1;}')

#版本回退操作(将备份的版本文件分发)
if [ -n "$back_version" ];then
    if [ -z "$v_info" ]; then 
        echo "没有可以回退的版本"; exit;
    else
        if [ "$back_version" -gt "$v_info" ] || [ "$back_version" -eq "$v_info" ]; then
            echo "回退版本只能小于当前版本, 当前版本号:$v_info" ; exit;
        fi
    fi
    back=${back_version_path}${back_version}'/'
    if [ ! -d "$back" ]; then
        echo "版本目录 $back 不存在" ; exit; 
    fi
    
    #回退
    echo '============= 开始回退 =============='
    echo "回退文件在:$back "
    for host in ${hosts[@]} ; do
        rsync -aRzv "$back"  root@$host:/
    done
    echo "============= 完成 =================="
    
    fun_log_version  $ver_file  $back_version  "${hosts[@]}"

#分发操作(将线上测试机的文件分发)
else

    if [ ! -d "$bak_path" ] ; then
        mkdir -p "$bak_path" 
    fi

    for host in ${hosts[@]} ; do
        #备份原文件
        if [ "$host" = "$bak_source_host" ]; then
            if [ "$v_info" = "" ]; then   
                v_info=1 ; 
                let "bak_v = v_info -1" ;
            else
                let "bak_v = v_info"  
            fi 
            
            #由版本号产生备份目录
            bak_dir="${bak_path}${bak_v}"
            
            #备份
            bak_lst  $up_lst_file   $bak_dir  $file_path_pre $host
        fi

        #更新文件
        echo "=========================== 开始分发至: $host ========================="
        publish_lst  $up_lst_file  $host  $file_path_pre  $ver_file 
    done
    
    #记录版本号
    fun_log_version $ver_file  -1  "${hosts[@]}" 

fi