[AWS] S3 から資材をダウンロードしてデプロイする

#!/bin/bash
##########################################################################################
#
# [USAGE]
#
#   deploy.sh [name] -f
#     name : S3 Bucket の RELEASEフォルダ直下のフォルダ名
#     -f   : デプロイの強制
#
# [自動デプロイの使用例]
#
#   - root 権限で実行する。
#   - crontab に登録して、1時間に1回実行する。( -f は指定しない )
#
# [S3 Bucket Tree]
#
#   S3 Bucket                                            : S3 Bucket
#        +--- RELEASE                                    : リリース資材の格納場所
#                  +--- [name]                           : deploy.sh の [name] で指定するフォルダ
#                          +--- deploy.list              : サーバ上のデプロイ手順を指示する設定ファイル。
#                          +--- dummy.conf               : 配布資材
#                          +--- v1                       : 配布資材
#                          |     +--- dummy.sh           : 配布資材
#                          +--- [hostname].deploy.log    : デプロイ実行後に格納されるログファイル。(*1)
#
#   (*1) ログファイルが存在する場合は、デプロイ済みとして処理を中止する。ただし、-f が指定された場合は強制する。
#        -f を指定しない場合に、デプロイしたい場合は、このログファイルを削除しておくこと
#
# [deploy.list]
#
#  ex.)
#  #2018-01-19 12:00
#  time= anytime
#  cmnd= echo "stop service"
#  cmnd= hostname
#  copy= dummy.conf,  /root/workspace, root:root, 644
#  copy= v1/dummy.sh, /root/workspace, root:root, 644
#  cmnd= echo "start service"
#  cmnd= hostname
#
#  - 1行目から順番に処理する。
#  - 1カラム目が "#" はコメント行
#  - time= は、デプロイ時間(24h形式)を記載する。anytimeにすると、次回の実行時が対象。
#  - cmnd= は、コマンドを記載する。
#  - copy= は、配布資材を記載する。CSV形式。
#    <配布ファイル名>,<サーバ上の配置先ディレクトリ>,<オーナ(user:group)>,<パーミション>
#
##########################################################################################

TMP_DIR=/tmp
TMP_RELEASE_DIR=/tmp/release
LOG_LOCAL=${TMP_DIR}/deploy.log
DEPLOY_LIST=${TMP_RELEASE_DIR}/deploy.list
FORCE=0
AWS_RETRY_MAX=5
AWS_RETRY_INTERVAL=2

if [ $# -eq 0 ]; then
  echo "[USAGE] `basename $0` [name]"
  exit 1
fi
if [ $# -eq 2 -a "$2" = "-f" ]; then
  FORCE=1
fi

DOWNLOAD_SRC="s3://blue21.dev.local/RELEASE/$1"
LOG_UPLOAD="${DOWNLOAD_SRC}/_`hostname`.deploy.log"

#-----------------------
# aws retry
#-----------------------
function aws_retry
{
  argv="$*"
  i=0
  while [ 1 ]
  do
      eval "aws ${argv}"
      if [ $? -ne 0 ]; then
          i=$((i+1))
          if [ $i -eq $((AWS_RETRY_MAX+1)) ]; then
              break
          fi
          echo "aws retry $i times waiting ..."
          sleep ${AWS_RETRY_INTERVAL}
          continue
      fi
      return 0
  done
  return 1
}

#-----------------------
# time=
#-----------------------
function deploy_time
{
  now=`date '+%Y-%m-%d %H:00'`
  deploy_time=`egrep 'time=' ${DEPLOY_LIST} | cut -d= -f2 | sed -e 's/^  *//' | sed -e 's/*  $//'`
  if [ "anytime" != "$deploy_time" ]; then
    if [ "$now" != "$deploy_time" ]; then
      echo "deploy time is no match."
      exit 0
    fi
  fi
}

#-----------------------
# copy=
#-----------------------
function deploy_copy
{
  w_src_path=`echo "$1"| awk -F, '{printf("%s",$1)}'| tr -d " "`
  w_src_file=`basename $w_src_path`
  w_dst_dir=`echo "$1"| awk -F, '{printf("%s",$2)}'| tr -d " "`
  w_dst_path=$w_dst_dir/$w_src_file
  w_owner=`echo "$1"| awk -F, '{printf("%s",$3)}'| tr -d " "`
  w_mode=`echo "$1"| awk -F, '{printf("%s",$4)}'| tr -d " "`

  echo "--------------------- copy."

  if [ ! -f ${TMP_RELEASE_DIR}/$w_src_path ]; then
    echo "not found file: ${TMP_RELEASE_DIR}/$w_src_path"
    continue
  fi
  if [ ! -d ${w_dst_dir} ]; then
    echo "not found dir: $w_dst_dir"
    continue
  fi

  /bin/cp ${TMP_RELEASE_DIR}/$w_src_path $w_dst_path
  chown $w_owner $w_dst_path
  chmod $w_mode $w_dst_path

  ls -l ${w_dst_path}
}

#-----------------------
# cmnd=
#-----------------------
function deploy_cmnd
{
  echo "--------------------- cmnd."
  echo "# $1"
  eval $1
  sleep 1
}

########################
# MAIN
########################

exec > >(tee ${LOG_LOCAL}) 2>&1

echo "--------------------- `date '+%Y-%m-%d %H:%M:%S'` - START"

# DOWNLOAD DEPLOY FILES

echo "--------------------- S3 Bucket/RELEASE LIST."
echo "${DOWNLOAD_SRC}/"
aws_retry s3 ls ${DOWNLOAD_SRC}/ > ${TMP_DIR}/deploy.s3.list
if [ $? -ne 0 ]; then
  echo "not found bucket. ${DOWNLOAD_SRC}/"
  exit 1
fi
cat ${TMP_DIR}/deploy.s3.list

echo "--------------------- S3 Bucket/RELEASE LOG CHECK."
logname="`basename ${LOG_UPLOAD}`"
egrep " $logname$" ${TMP_DIR}/deploy.s3.list
if [ $? -eq 0 -a $FORCE -eq 0 ]; then
  echo "alredy release. found ${LOG_UPLOAD}"
  rm -f ${TMP_DIR}/deploy.s3.list
  exit 0
fi
rm -f ${TMP_DIR}/deploy.s3.list

echo "--------------------- S3 Bucket/RELEASE DOWNLOAD."
rm -fr ${TMP_RELEASE_DIR} > /dev/null 2>&1
mkdir -p ${TMP_RELEASE_DIR}
aws_retry s3 cp ${DOWNLOAD_SRC}/ ${TMP_RELEASE_DIR}/ --recursive
if [ $? -ne 0 ]; then
  exit 1
fi

# DEPLOY TIME CHECK
deploy_time

# DEPLOY RUN
while read line
do

  func=`echo "$line"| cut -d= -f1 | tr -d "\n"`
  data=`echo "$line"| cut -d= -f2 | sed -e 's/^  *//' | sed -e 's/  *$//' | tr -d "\n"`

  if [ "$func" = "copy" ]; then
    deploy_copy "$data"
  elif [ "$func" = "cmnd" ]; then
    deploy_cmnd "$data"
  else
    echo "error: $line"
  fi

done < <(egrep -v '^#|^time=|^$|^  *$' ${DEPLOY_LIST})

echo "--------------------- `date '+%Y-%m-%d %H:%M:%S'` - NORMAL END"

# UPLOAD DEPLOY LOG
aws_retry s3 cp ${LOG_LOCAL} ${LOG_UPLOAD}
rm -rf ${TMP_RELEASE_DIR} > /dev/null 2>&1

exit 0