通过Git WebHooks+脚本实现自动更新发布代码之Shell脚本(二)

依据前文《通过Git WebHooks+脚本实现自动更新发布代码》的解决方案编写的shell脚本,此脚本专门用于更新补丁文件,例如对项目中的文件实现增(add)、删(remove)、改(update),并且执行相关的命令,如清除缓存、重启服务等。

此Shell脚本目前设计成在本地执行,目前不适合分布式执行的情况。也就是说,此脚本最好与项目在同一个机器上,这个缺陷已经标注在脚本中了,参见脚本中的多个TODO。

脚本完成的工作:

  • 检查配置文件合规性
  • 备份与恢复
  • 增删改文件
  • 执行命令
  • 失败回滚

除上述完成的功能外,因为不同的项目其用到的命令或所需要执行的操作以及检查成功与否大有不同,因此其他的功能需要可以继续往上添加,需要的可以自行修改此脚本。此脚本仅作参考之用,欢迎提出改进意见、批评指正。

此脚本可以略做修改,与前文《通过Git WebHooks+脚本实现自动更新发布代码之shell脚本》提到的部署脚本一起联用。后期改进请关注github

脚本如下:

#!/usr/bin/env bash

# Public header
# =============================================================================================================================

# Check that we are root ... so non-root users stop here
[  `id -u` -eq  "0" ] ||  exit 4

# resolve links - $0 may be a symbolic link
PRG="$0"

while [ -h "$PRG" ]; do
  ls=`ls -ld "$PRG"`
  link=`expr "$ls" : ‘.*-> \(.*\)$‘`
  if expr "$link" : ‘/.*‘ > /dev/null; then
    PRG="$link"
  else
    PRG=`dirname "$PRG"`/"$link"
  fi
done

# Get standard environment variables
PRGDIR=`dirname "$PRG"`

# echo color function
function cecho {
    # Usage:
    # cecho -red sometext     #Error, Failed
    # cecho -green sometext   # Success
    # cecho -yellow sometext  # Warning
    # cecho -blue sometext    # Debug
    # cecho -white sometext   # info
    # cecho -n                # new line
    # end

    while [ "$1" ]; do
        case "$1" in
            -normal)        color="\033[00m" ;;
# -black)         color="\033[30;01m" ;;
-red)           color="\033[31;01m" ;;
-green)         color="\033[32;01m" ;;
-yellow)        color="\033[33;01m" ;;
-blue)          color="\033[34;01m" ;;
# -magenta)       color="\033[35;01m" ;;
# -cyan)          color="\033[36;01m" ;;
-white)         color="\033[37;01m" ;;
-n)             one_line=1;   shift ; continue ;;
*)              echo -n "$1"; shift ; continue ;;
esac

shift
echo -en "$color"
echo -en "$1"
echo -en "\033[00m"
shift

done
if [ ! $one_line ]; then
        echo
fi
}
# end echo color function

# echo color function, smarter
function echo_r () {
    #Error, Failed
    [ $# -ne 1 ] && return 0
    echo -e "\033[31m$1\033[0m"
}
function echo_g () {
    # Success
    [ $# -ne 1 ] && return 0
    echo -e "\033[32m$1\033[0m"
}
function echo_y () {
    # Warning
    [ $# -ne 1 ] && return 0
    echo -e "\033[33m$1\033[0m"
}
function echo_b () {    # Debug
    [ $# -ne 1 ] && return 0
    echo -e "\033[34m$1\033[0m"
}
# end echo color function, smarter

WORKDIR=$PRGDIR
# end public header
# =============================================================================================================================

# begin customization for special case
# project directory to waiting for update
config_project_dir=example_projects
# resources directory which contain config file and update files
config_resources_dir=example_resources
config_config_file=$config_resources_dir/config_update.conf
config_backup_dir=example_backup_dir
# log options
config_this_logfile=$WORKDIR/.update_backup.log
# end

function check_dependencies(){
    echo_b "Checking dependencies for update procedure. "

    if [ -z $config_project_dir ]; then
        echo_r "Error: config_project_dir is undefined! "
        exit 1
    fi

    if [ ! -d $config_resources_dir ]; then
        echo_r "Error: config_resources_dir is undefined! "
    fi

    if [ -z $config_config_file ]; then
        echo_r "Error: config_config_file is undefined! "
        exit 1
    fi

    left_disk_space=`df $config_backup_dir | tail -n1 | awk ‘{print $(NF -2)}‘`
    # set 2097152 to project directory size
    if [ -z $config_project_dir -o ! -d $config_project_dir ]; then
        project_file_space_usage=$(du -s /root | awk ‘{print $1}‘)
        required_size=$(expr $project_file_space_usage \* 2)
    fi
    if [[ $left_disk_space -lt $required_size ]]; then
        echo_r "Disk space of $config_backup_dir is smaller than $required_size. "
        exit 1
    fi

    echo_g "All required dependencies check pass! "

}

function test_self(){
    # How to use this function:
    # First execute "$0 test_self", then execute "$0 update"

    echo_b "Test purpose begin. "

    # clean old test example
    echo_b "Clean old test example. "
    [ -d $WORKDIR/example_projects ] && rm -rf $WORKDIR/example_projects
    [ -d $WORKDIR/example_resources ] && rm -rf $WORKDIR/example_resources
    [ -d $WORKDIR/example_backup_dir ] && rm -rf $WORKDIR/example_backup_dir

    # make an example project directory
    if [ -z $config_project_dir -o ! -d $config_project_dir ]; then
        echo_b "Making an example project directory. "
        mkdir $WORKDIR/example_projects
        config_project_dir=example_projects
        # Padding example_projects directory
        touch $config_project_dir/example_filename
        mkdir $config_project_dir/example_directory
    fi

    # make an example resources directory
    if [ -z $config_resources_dir -o ! -d $config_resources_dir ]; then
        echo_b "Making an example resources directory. "
        mkdir  $WORKDIR/example_resources
        config_resources_dir=$WORKDIR/example_resources
    fi

    # make an example config_update.conf
    if [ -z $config_config_file -o ! -f $config_config_file ]; then
        echo_b "Making an example config_update.conf file. "
        touch $config_resources_dir/config_update.conf
        config_config_file=$config_resources_dir/config_update.conf
    # Padding config_update.conf file
    cat >$config_config_file <<eof
file    filename1          add
file    filename2          remove
file    filename3          update
file    filename4          add
config  cleancachea             enable
config  cleancacheb             disable
config  restartservicea         enable
config  restartserviceb         disable
target  192.168.1.241           ssh
target  192.168.1.242           ssh
eof
    files=`awk -F ‘[ ]+‘ ‘/^file/ { print $2 }‘ $config_config_file`
    echo_b "Making an example files(patches) refer to $config_config_file. "
    for names in $files; do
        [ ! -f $config_resources_dir/$names ] && touch $config_resources_dir/$names
    done
    fi

    # TODO
    # test network and ssh for remote call

    # make an example backup directory
    if [ -z $config_backup_dir -o ! -d $config_backup_dir ]; then
        echo_b "Making an example backup directory"
        mkdir $WORKDIR/example_backup_dir
        config_backup_dir=$WORKDIR/example_backup_dir
    fi

    echo_g "Test purpose is finished and successfully! "
}

#function parse_config_file(){
#    # unbanned action
#    files=`awk -F ‘[ ]+‘ ‘/^file/ { print $2 }‘ $config_config_file`
#    configs=`awk -F ‘[ ]+‘ ‘/^config/ { print $2 }‘ $config_config_file`
#}

function do_cp(){
    SOURCE=$1
#    echo "var: $SOURCE"
#    echo "result: $(dirname $SOURCE | grep ^\/ | awk ‘{print substr($1,1,1)}‘ )"
#    exit 0
    if test "$(dirname $SOURCE | grep ^\/ | awk ‘{print substr($1,1,1)}‘)" == ""; then
        echo_b "Execute copy action. "
        DEST=$config_project_dir/$SOURCE
        \cp $SOURCE $DEST
    else
        echo_y "Self test purpose found! But we can do this action! "
        [ ! -d $config_project_dir/$(dirname $SOURCE) ] && mkdir -p $config_project_dir/$(dirname $SOURCE)
        \cp $SOURCE $config_project_dir/$(dirname $SOURCE)
    fi
}
function do_remove(){
    FILE=$1
    if test "$(dirname $SOURCE | awk -F ‘/‘ ‘{print $1}‘)" == ""; then
        rm -rf $config_project_dir/$FILE
    else
        echo_y "Self test purpose found! This can NOT do remove action on self test purpose, skipping..."
        return
    fi

}

# TODO
# for remote call
#function do_remote_cp(){}
#function fo_remote_remove(){}

function file_operation(){
    echo_b "Begin files operations"
    files=`awk -F ‘[ ]+‘ ‘/^file/ { print $2 }‘ $config_config_file`
    for names in $files; do
        if grep $names $config_config_file | grep add >/dev/null 2>&1 ; then
            # do_cp
            do_cp $names
        elif grep $names $config_config_file | grep update >/dev/null 2>&1 ;then
            # do_cp
            do_cp $names
        elif grep $names $config_config_file | grep remove >/dev/null 2>&1 ;then
            # do_remove
            do_remove $names
        else
            exit 1
        fi
    done
    echo_g "Files operations finished successfully! "
}

# TODO
# no example here, please refer to your real production environment
#function do_clean_cache(){}
#function do_restart_service(){}

function service_operation(){
    echo_b "Begin services operations"
    configs=`awk -F ‘[ ]+‘ ‘/^config/ { print $2 }‘ $config_config_file`
    for names in $configs; do
        if grep $names $config_config_file | grep cleancache | grep enable >/dev/null 2>&1 ; then
            # do_clean_cache
            echo do_clean_cache $names
        elif grep $names $config_config_file | grep cleancache | grep disable >/dev/null 2>&1 ; then
            # echo a warning
            echo_y "Warning: disable action is NOT recommended, $names skipped."
        elif grep $names $config_config_file | grep restartservice | grep enable >/dev/null 2>&1 ; then
            # do_restart_service
            echo do_restart_service $names
        elif grep $names $config_config_file | grep restartservice | grep disable >/dev/null 2>&1 ; then
            # echo a warning
            echo_y "Warning: disable action is NOT recommended, $names skipped."
        else
            echo $names
            echo_r "Error: Wrong config file $config_config_file, please check it. "
            exit 1
        fi
    done
    echo_g "Services operations finished successfully! "
}

function check_remote_server_status(){
    # TODO
    # for remote call
    echo

}

function backup(){
    echo_b "Backup files before update"
#    backup_filename=backup_$(date +%F_%H_%M_%S).tgz
    backup_filename=backup_$(date +%Y_%m_%d_%H_%M_%S).tgz
    tar --create --gzip --absolute-names --file=$config_backup_dir/$backup_filename $config_project_dir
    if [ $? -eq 0 ]; then
        echo_g "Backup files before update finished and successfully! "
        echo "restore_least_file=$config_backup_dir/$backup_filename" > $config_this_logfile
    else
        echo_r "Error: Backup files before update failed! Please alter to administrator. "
        exit 1
    fi

}

function restore(){
    echo_b "Restore files for rollback"
    if [ -f $config_this_logfile ]; then
        . $config_this_logfile
    fi
    restore_least_file=${restore_least_file:-1}
    if [ -s $restore_least_file ]; then
        tar -C $config_project_dir/.. -zxf $restore_least_file
        if [ $? -eq 0 ]; then
            echo_g "Restore files finished and successfully! "
        else
            echo_r "Restore files failed! Please alter to administrator. "
            exit 1
        fi
    else
        echo_r "Can NOT find backup files in $config_backup_dir, backup once indeed? "
        exit 1
    fi

}

# TODO
# for remote call
# function remote_backup(){}
# function remote_restore(){}

function rollback(){
    echo_b "rollback after update failed"
    $0 restore

    echo_g "rollback finished and successfully! "
}

function update_status(){
    # TODO
    # no example here, please refer to your real production environment
    # check if update success or failure
    echo update_status
    # if failure, do rollback action
        # service_operation
}

function update(){
    # TODO
    # thinking carefully with all exit status, which is not good for automatic update 
    check_dependencies
    backup
    file_operation
    service_operation
    update_status
}

function destroy() {
    # echo a warning message
    echo_y "Warning: This action will destroy all this project, and this is unrecoverable! "
    answer="n"
    echo_y "Do you want to destroy this project? "
    read -p "(Default no,if you want please input: y ,if not please press the enter button):" answer
    case "$answer" in
        y|Y|Yes|YES|yes|yES|yEs|YeS|yeS )
        # delete all file expect for this script self
        # find: warning: Unix filenames usually don‘t contain slashes (though pathnames do).  That means that ‘-name `./deploy.sh‘‘ will probably evaluate to false all the time on this system.  You might find the ‘-wholename‘ test more useful, or perhaps ‘-samefile‘.  Alternatively, if you are using GNU grep, you could use ‘find ... -print0 | grep -FzZ `./deploy.sh‘‘.
            # echo $WORKDIR/
            #find -L $WORKDIR -type f ! -name "$(basename $0)" -exec ls --color=auto -al {} \;
            # find -L . -type f ! -name "deploy.sh" -exec ls --color=auto -al {} \;
            # find -L . -type d -exec ls --color=auto -al {} \;
            # find -L ./ -maxdepth 1 ! -name "deploy.sh" ! -wholename "./"
        # ls | grep -v "fielname" |xargs rm -rf
        find -L $WORKDIR -maxdepth 1 ! -name "$(basename $0)" ! -wholename "$WORKDIR"  -exec rm -rf {} \;
        if [ $? -eq 0 ];then
            echo_g "Destory this project successfully! Now will exit with status 0. "
            exit 0
        else
            echo_r "Error: something go wrong! Please check or alter to Admin user! "
            exit 1
        fi
        ;;
        n|N|No|NO|no|nO)
        echo_g "destroy action is cancel"
        exit 0
        ;;
        *)
        echo_r "Are you kidding me? You are a bad kid! "
        exit 1
        ;;
    esac

}

case $1 in
    update)
        update
        ;;
    backup)
        backup
        ;;
    restore)
        restore
        ;;
    rollback)
        rollback
        ;;
    destroy)
        destroy
        ;;
    help|*)
        echo "Usage: $0 {update|backup|restore|rollback|destroy} with $0 itself"
        exit 1
        ;;
esac

# This is not essential with ‘case .. esac‘ handled no args excutions
# replace "exit 0" with ":"
#exit 0
:

tag: 自动更新shell脚本,自动化部署脚本,Shell部署脚本,脚本实现自动更新和回滚,自动化部署shell脚本实例

--end--

时间: 2024-07-30 23:58:08

通过Git WebHooks+脚本实现自动更新发布代码之Shell脚本(二)的相关文章

通过Git WebHooks+脚本实现自动更新发布代码之shell脚本

前文讲述了<通过Git WebHooks+脚本实现自动更新发布代码>,里面提供了一种自动更新发布代码的脚本编写思路.本文的脚本与前文中的思路不太不同.本脚本以capistrano中的一些思想和理念为依据,用简单好理解的shell脚本实现capistrano原本实现的自动化部署部分. 脚本的一些特点和功能: 解决脚本的符号链接问题,准确获取脚本工作目录(从tomcat脚本中学到): 颜色显示,不同级别的信息用不同的颜色显示(共两种方案,前一种从一位不知名的国外工程师处得到,后一种从lnmp1.2

通过Git WebHooks+脚本实现自动更新发布代码

需求: 写一个自动化部署脚本,能根据git push动作自动更新发布代码(补丁文件(或更新文件,以下简称补丁)) 解决方案: 通过git webhooks.python脚本.Linux Shell脚本完成,所有动作均自动完成,人工部分仅限于发布补丁文件之前 git webhooks实现触发执行脚本 python脚本用于接收git webhooks的post数据并根据这些数据判断是否执行shell脚本 Linux Shell脚本用于实现部署.备份.回滚等操作 具体步骤(方案实现): 实现原理: 用

Shell学习之路和我发布过的Shell脚本博文

Shell学习之路 目录 Shell学习之路[第一篇]:别名,管道,用户配置文件,变量,read Shell学习之路[第二篇]:条件测试,运算符,选择结构,for循环结构 Shell学习之路[第三篇]:While循环,C-for循环,Until循环,case分支结构,流程控制语句 Shell学习之路[第四篇]:函数,数组,变量替换 Shell学习之路[第五篇]:多线程脚本 Shell学习之路[第六篇]:Trap信号捕捉命令介绍与Shell结合实战讲解 Shell学习之路[第七篇]:Linux下d

基于mysqldump编写自动全备增备的shell脚本

基于mysqldump编写自动全备增备的shell脚本 在线上MySQL数据库备份分为全备和增备,而xtrabackup备份已经支持了增量备份了,但是mysqldump就不支持增量备份,所以我们需要写一个shell脚本对于mysqldump来自动全备和增备. 一下脚本要求我们做一个全备的策略,然后如何做增量备份,自动完成每天执行增量备份,每个星期天执行全备.备份完删除二进制文件,减低磁盘压力. [[email protected] ~]# cat mysqlback.sh #!/bin/bash

Java代码调用Shell脚本并传入参数实现DB2数据库表导出到文件

本文通过Java代码调用Shell脚本并传入参数实现DB2数据库表导出到文件,代码如下: import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.LineNumberReader; import java.util.HashMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import

织梦DEDE后台定时分时段自动更新发布文章插件

定时审核插件使用说明 一.立信CPA培训注册会计师考试网站 以超级管理员身份登录后台,依次选择[核心]à [定时审核管理],输入定时审核的时间段,如下图所示: 功能说明: 1. 可以设置若干时间段,在这些时间段内,每天自动审核和生成指定篇数的未审核文章,每个时间段每天只会更新一次. 2. 自动更新网站首页和需要更新的栏目页,需要更新的栏目页是有新文章生成的栏目,没有新文章更新的栏目不会更新,提高了更新的性能. 3. 可以按照栏目或者总数更新文章.按照栏目更新文章,每个栏目更新指定篇数文章.按照总

git自动更新网站代码

1.实现过程在linux上安装git服务.创建源版本库.从源版本库克隆得到网站目录,然后利用git中的hooks机制,在git push推送代码到源版本库的时候,触发编写的shell脚本,更新网站目录下的代码. 2.安装git服务 [[email protected] ~]# cd /usr/local/src[[email protected] src]# wget https://mirrors.edge.kernel.org/pub/software/scm/git/git-2.15.2.

jenkins git公有仓库与私有仓库发布代码

1 发布php代码 - jenkins已经搭建完成,现在开始来做一个php发布代码的任务 - 在发布php代码时先看看是否有两个插件 在系统管理-管理插件- 已安装插件- 检查是否有"Git plugin"和"Publish Over SSH"两个插件,如果没有,则需点击"可选插件",找到它并安装 [[email protected] jenkins]# systemctl restart jenkins //重启服务 - 需要生成一对密钥对用来

一个自动安装LNMP的简洁Shell脚本

此脚本在生产服务器上使用了一年多,本脚本崇尚简单唯美,只需要一个脚本就可以在任何一台有网络的服务器上自动配置LNMP.本脚本会在脚本执行目录下,建packages目录用于存放LNMP所需要的软件.大家安装完可以删除该目录. 使用方法:1.把shell脚本的内容保存为nginx_php2.root权限下运行:chmod u+x nginx_php; ./nginx_php init; ./nginx_php ins_mysql-server; ./nginx_php ins_mysql-clien