ck1987 发表于 2018-8-17 10:06:53

Linux Shell脚本之远程自动化部署java maven项目

#!/bin/bash  

  
# Name: doDeploy.sh
  
#Execute this shell script to deploy Java projects built by Maven automatically on remote hosts.
  

  
# debug option
  
#_XTRACE_FUNCTIONS=$(set +o | grep xtrace)
  
#set -o xtrace
  

  
# define user friendly messages
  
header="
  
Function: Execute this shell script to deploy Java projects built by Maven automatically on remote hosts.
  
License: Open source software
  
"
  

  
# define variables
  
# Where to get source code
  
project_clone_depends_1=""
  
project_clone="ssh://git@xxx/xxx.git"
  
deploy_target_host_ip="xxx.xxx.xxx.xxx"
  
project_top_directory_to_target_host="/path/to/deploy/project"
  
docker_container_name=""
  
# Setting how many days do you want save old releases, default is 10 days
  
save_old_releases_for_days=10
  
# end define variables
  

  
# pretreatment
  
test -z ${project_clone_depends_1} || project_clone_target_depends_1="`echo ${project_clone_depends_1} | awk -F '[/.]+' '{ print $(NF-1)}'`"
  
project_clone_target="`echo ${project_clone} | awk -F '[/.]+' '{ print $(NF-1)}'`"
  
project_clone_repository_name=${project_clone_target}
  

  
# end pretreatment
  

  
# Public header
  
# =============================================================================================================================
  
# resolve links - $0 may be a symbolic link
  
# learn from apache-tomcat-6.x.xx/bin/catalina.sh
  
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, smarter, learn from lnmp.org lnmp install.sh
  
function echo_r (){
  
    # Color red: Error, Failed
  
    [ $# -ne 1 ] && return 1
  
    echo -e "\033[31m$1\033[0m"
  
}
  
function echo_g (){
  
    # Color green: Success
  
    [ $# -ne 1 ] && return 1
  
    echo -e "\033[32m$1\033[0m"
  
}
  
function echo_y (){
  
    # Color yellow: Warning
  
    [ $# -ne 1 ] && return 1
  
    echo -e "\033[33m$1\033[0m"
  
}
  
function echo_b (){
  
    # Color blue: Debug, friendly prompt
  
    [ $# -ne 1 ] && return 1
  
    echo -e "\033[34m$1\033[0m"
  
}
  
# end echo color function, smarter
  

  
#WORKDIR="`realpath ${WORKDIR}`"
  
WORKDIR="`readlink -f ${PRGDIR}`"
  

  
# end public header
  
# =============================================================================================================================
  

  
USER="`id -un`"
  
LOGNAME="$USER"
  
if [ $UID -ne 0 ]; then
  
    echo "WARNING: Running as a non-root user, \"$LOGNAME\". Functionality may be unavailable. Only root can use some commands or options"
  
fi
  

  
command_exists() {
  
    # which "$@" >/dev/null 2>&1
  
    command -v "$@" >/dev/null 2>&1
  
}
  

  
check_command_can_be_execute(){
  
    [ $# -ne 1 ] && return 1
  
    command_exists $1
  
}
  

  
check_network_connectivity(){
  
    echo_b "checking network connectivity ... "
  
    network_address_to_check=8.8.4.4
  
    stable_network_address_to_check=114.114.114.114
  
    ping_count=2
  
    ping -c ${ping_count} ${network_address_to_check} >/dev/null
  
    retval=$?
  
    if [ ${retval} -ne 0 ] ; then
  
      if ping -c ${ping_count} ${stable_network_address_to_check} >/dev/null;then
  
            echo_g "Network to $stable_network_address_to_check succeed! "
  
            echo_y "Note: network to $network_address_to_check failed once! maybe just some packages loss."
  
      elif ! ip route | grep default >/dev/null; then
  
            echo_r "Network is unreachable, gateway is not set."
  
            exit 1
  
      elif ! ping -c2 $(ip route | awk '/default/ {print $3}') >/dev/null; then
  
            echo_r "Network is unreachable, gateway is unreachable."
  
            exit 1
  
      else
  
            echo_r "Network is blocked! "
  
            exit 1
  
      fi
  
    elif [ ${retval} -eq 0 ]; then
  
      echo_g "Check network connectivity passed! "
  
    fi
  
}
  

  
check_name_resolve(){
  
    echo_b "checking DNS name resolve ... "
  
    target_name_to_resolve="github.com"
  
    stable_target_name_to_resolve="www.aliyun.com"
  
    ping_count=1
  
    if ! ping-c${ping_count} ${target_name_to_resolve} >/dev/null; then
  
      echo_y "Name lookup failed for $target_name_to_resolve with $ping_count times "
  
      if ping-c${ping_count} ${stable_target_name_to_resolve} >/dev/null; then
  
            echo_g "Name lookup success for $stable_target_name_to_resolve with $ping_count times "
  
      fi
  
      eval_md5sum_of_nameserver_config="`md5sum /etc/resolv.conf | awk '{ print $1 }'`"
  
      if test ${eval_md5sum_of_nameserver_config} = "674ea91675cdfac353bffbf49dc593c3"; then
  
            echo_y "Nameserver config file is validated, but name lookup failed for $target_name_to_resolve with $ping_count times"
  
            return 0
  
      fi
  
      [ -f /etc/resolv.conf ] && cp /etc/resolv.conf /etc/resolv.conf_$(date +%Y%m%d%H%M%S)~
  
      cat >/etc/resolv.conf>${WORKDIR}/git_$(date +%Y%m%d)_$$.log 2>&1
  
            # TODO(Guodong Ding) get branch names or revision numbers from VCS data
  

  
      cd ${project_clone_directory}
  
      git checkout ${branch} >>${WORKDIR}/git_$(date +%Y%m%d)_$$.log 2>&1
  
      cd ..
  
      echo_g "git clone from $project_clone_repository successfully! "
  
    else
  
      echo_b "git pull from $project_clone_repository"
  
      cd ${project_clone_directory}
  
      git pull >>${WORKDIR}/git_$(date +%Y%m%d)_$$.log 2>&1
  
      git checkout ${branch} >>${WORKDIR}/git_$(date +%Y%m%d)_$$.log 2>&1
  
      # TODO(Guodong Ding) get branch names or revision numbers from VCS data
  
      cd ..
  
      echo_g "git pull from $project_clone_repository successfully! "
  
    fi
  
    set +o errexit
  
}
  

  
function maven_build_project_deprecated(){
  
    set -o errexit
  
    echo_b "Do mvn build java project... "
  
    check_command_can_be_execute mvn
  
    [ $# -ge 1 ] && project_clone_repository="$1"
  
    project_clone_repository_name="`echo ${project_clone_repository} | awk -F '[/.]+' '{ print $(NF-1)}'`"
  
    project_clone_directory=${WORKDIR}/repository/${project_clone_repository_name}
  
    cd ${project_clone_directory}
  
    mvn install >>${WORKDIR}/mvn_build_$(date +%Y%m%d)_$$.log 2>&1
  
    mvn clean package >>${WORKDIR}/mvn_build_$(date +%Y%m%d)_$$.log 2>&1
  
    cd ..
  
    echo_g "Do mvn build java project finished with exit code 0! "
  
    set +o errexit
  
}
  

  
function maven_build_project(){
  
    echo_b "Do mvn build java project for `echo $1 | awk -F '[/.]+' '{ print $(NF-1)}'`... "
  
    check_command_can_be_execute mvn
  
    [ $# -ge 1 ] && project_clone_repository="$1"
  
    project_clone_repository_name="`echo ${project_clone_repository} | awk -F '[/.]+' '{ print $(NF-1)}'`"
  
    project_clone_directory=${WORKDIR}/repository/${project_clone_repository_name}
  

  
    cd ${project_clone_directory}
  
    mvn install >>${WORKDIR}/mvn_build_$(date +%Y%m%d)_$$.log 2>&1
  
    retval=$?
  
    if [ ${retval} -ne 0 ] ; then
  
      echo_r "mvn install failed! More details refer to ${WORKDIR}/mvn_build_$(date +%Y%m%d)_$$.log"
  
      exit 1
  
    else
  
      echo_g "mvn install for ${project_clone_repository_name} successfully! "
  
    fi
  

  
    mvn clean package >>${WORKDIR}/mvn_build_$(date +%Y%m%d)_$$.log 2>&1
  
    retval=$?
  
    if [ ${retval} -ne 0 ] ; then
  
      echo_r "mvn clean package for ${project_clone_repository_name} failed! More details refer to ${WORKDIR}/mvn_build_$(date +%Y%m%d)_$$.log"
  
      exit 1
  
    else
  
      echo_g "mvn clean package for ${project_clone_repository_name} successfully! "
  
    fi
  
    cd ..
  
    echo_g "Do mvn build java project finished for ${project_clone_repository_name} with exit code 0! "
  
}
  

  
function check_ssh_can_be_connect(){
  
    [ $# -ne 1 ] && return 1
  
    echo_b "Check if can ssh to remote host $1 ... "
  
    check_command_can_be_execute ssh || return 1
  
    ssh -i /etc/ssh/ssh_host_rsa_key -p 22 -oStrictHostKeyChecking=no root@$1 "uname -a >/dev/null 2>&1"
  
    retval=$?
  
    if [ ${retval} -ne 0 ] ; then
  
      echo_r "Check ssh to remote host $1 failed! "
  
      exit 1
  
    else
  
      echo_g "Check ssh to remote host $1 successfully! "
  
    fi
  
}
  

  
# ssh_execute_command_on_remote_host hostname command
  
function ssh_execute_command_on_remote_host(){
  
    [ $# -ne 2 ] && return 1
  
    ssh -i /etc/ssh/ssh_host_rsa_key -p 22 -oStrictHostKeyChecking=no root@$1 "$2" >>${WORKDIR}/ssh_command_$(date +%Y%m%d)_$$.log
  
    retval=$?
  
    if [ ${retval} -ne 0 ] ; then
  
      echo_r "ssh execute command on remote host $2 failed! More details refer to ${WORKDIR}/ssh_command_$(date +%Y%m%d)_$$.log"
  
      return 1
  
    else
  
      echo_g "ssh execute command on remote host $2 successfully! "
  
      return 0
  
    fi
  
}
  

  
function restart_docker_container(){
  
    echo_b "Restarting docker container..."
  
    [ $# -ne 1 ] && return 1
  
    # TODO(Guodong Ding) if we need restart more related docker container
  
    local docker_container_name=""
  
    test -n $1 && docker_container_name="$1"
  
    ssh_execute_command_on_remote_host "docker restart $docker_container_name"
  
    retval=$?
  
    if [ ${retval} -ne 0 ] ; then
  
      echo_r "restart docker container for$docker_container_name failed! "
  
      exit 1
  
    else
  
      echo_g "restart docker container for $docker_container_name successfully! "
  
      return 0
  
    fi
  
}
  

  
# scp_local_files_to_remote_host local_path remote_hostname remote_path
  
function scp_local_files_to_remote_host(){
  
    [ $# -ne 3 ] && return 1
  
    [ ! -d $1 -a ! -f $1 ] && return 1
  
    check_ssh_can_be_connect $2
  
    scp -i /etc/ssh/ssh_host_rsa_key -P 22 -oStrictHostKeyChecking=no -rp $1 root@$2:$3 >/dev/null 2>&1
  
    retval=$?
  
    if [ ${retval} -ne 0 ] ; then
  
      echo_r "scp local files to remote host failed! "
  
      exit 1
  
    else
  
      echo_g "scp local files to remote host successfully! "
  
    fi
  

  
}
  

  
# scp_remote_files_to_local_host remote_hostname remote_path local_path
  
function scp_remote_files_to_local_host(){
  
    [ $# -ne 3 ] && return 1
  
    check_ssh_can_be_connect $1
  
    scp -i /etc/ssh/ssh_host_rsa_key -P 22 -oStrictHostKeyChecking=no -rp root@$1:$2 $3 >/dev/null 2>&1
  
    retval=$?
  
    if [ ${retval} -ne 0 ] ; then
  
      echo_r "scp remote files to local host failed! "
  
      exit 1
  
    else
  
      echo_g "scp remote files to local host successfully! "
  
    fi
  
}
  

  
function backup_remote_host_config_files(){
  
    echo_b "backup remote host config files..."
  
    scp_remote_files_to_local_host ${deploy_target_host_ip} ${project_top_directory_to_target_host}/* ${WORKDIR}/backup
  
    # get config files
  
    [ "$(ls -A ${WORKDIR}/backup)" ] && find ${WORKDIR}/backup/. -type f ! -name . -a ! -name '*.xml*' -a ! -name '*.properties*' -exec rm -f -- '{}' \;
  
    # remove empty directory
  
    find ${WORKDIR}/backup/. -empty -type d -delete
  
    # TODO(Guodong Ding) improvements here
  
    echo_g "backup remote host config files finished."
  
}
  

  
function rollback_remote_host_config_files(){
  
    echo_b "rollback remote host config files..."
  
    #scp_local_files_to_remote_host ${WORKDIR}/backup ${deploy_target_host_ip} ${project_top_directory_to_target_host}
  
    saved_IFS=$IFS
  
    IFS=' '
  
    cd ${WORKDIR}/current
  
    for file in ${WORKDIR}/backup/*;do
  
      scp_local_files_to_remote_host ${file} ${deploy_target_host_ip} ${project_top_directory_to_target_host}
  
    done
  
    cd ${WORKDIR}
  
    IFS=${saved_IFS}
  
    # TODO(Guodong Ding) if save remote host config files
  
    # some ops
  

  
    # TODO(Guodong Ding) improvements here
  
    echo_g "rollback remote host config files finished."
  
}
  

  
function deploy() {
  
    [ -n "$header" ] && echo "$header"
  
    # check a directories lock, Note: this is redundant
  
    if [[ ! -f ${WORKDIR}/.lock ]]; then
  
      setDirectoryStructureOnLocalHost
  
    fi
  
    cleanOldReleases
  
    # do dependencies checking
  
    check_network_connectivity
  
    check_name_resolve
  
    checkOtherDependencies
  

  
    check_ssh_can_be_connect ${deploy_target_host_ip}
  

  
    # do core job
  
    # TODO(Guodong Ding) if we need a git_project_clone "$project_clone_depends_1" here using auto judgment statement
  
    test -z ${project_clone_depends_1} || git_project_clone "$project_clone_depends_1"
  
    git_project_clone "$project_clone"
  
    test -z ${project_clone_depends_1} || maven_build_project "$project_clone_depends_1"
  
    maven_build_project "$project_clone"
  
    cd ${WORKDIR}
  

  
    # links_target_directory_to_current
  
    # Make directory to release directory
  
    if test ! -d ${WORKDIR}/release -o ! -d ${WORKDIR}/share; then
  
      echo_r "capistrano directory structure is broken, make sure the file .capistrano_ds_lock is deleted before a new deploy! "
  
      exit 1
  
#      test -f ${WORKDIR}/.capistrano_ds_lock && \rm -rf${WORKDIR}/.capistrano_ds_lock
  
    fi
  
    new_release_just_created="$WORKDIR/release/$(date +%Y%m%d%H%M%S)"
  
    [ ! -d ${new_release_just_created} ] && mkdir ${new_release_just_created}
  
    [ -d ${WORKDIR}/repository/${project_clone_repository_name}/target/${project_clone_repository_name}/ ] && \
  
      \cp -rf ${WORKDIR}/repository/${project_clone_repository_name}/target/${project_clone_repository_name}/* ${new_release_just_created}
  
   # Make source code symbolic link to current
  
    ( [ -f ${WORKDIR}/current ] || [ -d ${WORKDIR}/current ] ) && rm -rf ${WORKDIR}/current
  
    ln -s ${new_release_just_created} ${WORKDIR}/current
  

  
    # backup remote host config files
  
    backup_remote_host_config_files
  

  
#    scp_local_files_to_remote_host ${WORKDIR}/current/ ${deploy_target_host_ip} ${project_top_directory_to_target_host}
  
    saved_IFS=$IFS
  
    IFS=' '
  
    cd ${WORKDIR}/current
  
    for file in ${WORKDIR}/current/*;do
  
      scp_local_files_to_remote_host ${file} ${deploy_target_host_ip} ${project_top_directory_to_target_host}
  
    done
  
    cd ${WORKDIR}
  
    IFS=${saved_IFS}
  

  
    # rollback remote host config files
  
    rollback_remote_host_config_files
  

  
    # Move conf and logs directives from release to share
  
    [ -d ${WORKDIR}/release/conf ] && mv ${WORKDIR}/release/conf ${WORKDIR}/share/conf
  
    [ -d ${WORKDIR}/release/logs ] && mv ${WORKDIR}/release/logs ${WORKDIR}/share/logs
  

  
    # Make conf and logs symbolic link to current
  
    [ -d ${WORKDIR}/share/conf ] && ln -s ${WORKDIR}/share/conf ${WORKDIR}/current/conf
  
    [ -d ${WORKDIR}/share/logs ] && ln -s ${WORKDIR}/share/logs ${WORKDIR}/current/logs
  

  
    # Start service or validate status
  
    if [[ -e ${WORKDIR}/current/bin/startup.sh ]]; then
  
      ${WORKDIR}/current/bin/startup.sh start
  
      RETVAL=$?
  
    else
  
      # TODO(Guodong Ding) external health check
  
      test -z ${docker_container_name} || restart_docker_container ${docker_container_name}
  
      RETVAL=$?
  
    fi
  

  
    # if started ok, then create a workable program to a file
  
    if [[ ${RETVAL} -eq 0 ]]; then
  
    # Note cat with eof must start at row 0, and with eof end only, such as no blank spaces, etc
  
    cat >${WORKDIR}/share/workable_program.log
页: [1]
查看完整版本: Linux Shell脚本之远程自动化部署java maven项目