#!/usr/bin/env bash # ====================================================================== # # DEPLOYMENT POC CLIENT # # ---------------------------------------------------------------------- # 2021-04-19 v0.1 <axel.hahn@iml.unibe.ch> initial version # 2021-05-09 v0.2 <axel.hahn@iml.unibe.ch> chown includes dot files # 2021-05-14 v0.3 <axel.hahn@iml.unibe.ch> add params (list, force, help) # 2021-05-27 v0.4 <axel.hahn@iml.unibe.ch> FIX first install # ====================================================================== # ---------------------------------------------------------------------- # CONFIG # ---------------------------------------------------------------------- cd $( dirname $0 ) selfdir=$( /bin/pwd ) tmpdir=/var/tmp/imldeployment_packages wait=0 # wait=1 # export variables that will be set in getfile config or project export IMLCI_PROJECT=TODO export IMLCI_PHASE=TODO # ---------------------------------------------------------------------- # FUNCTIONS # ---------------------------------------------------------------------- # get a list profiles by searching a config.sh # no param function getprofiles(){ find ${selfdir}/profiles/ -name "config.sh" | rev | cut -f 2 -d "/" | rev } # set a profile, load it, verify required parameters # param string name of a subdir in ./profiles/ function setprofile(){ profile=$1 # source config for software download - as default. . ${selfdir}/bin/getfile.sh.cfg # my install dir installdir= # fileowner appowner= profiledir=${selfdir}/profiles/${profile} . ${profiledir}/config.sh || exit 11 echo "[${profiledir}/config.sh] was loaded." if [ -z "$installdir" -o -z "${IMLCI_PHASE}" -o -z "${IMLCI_PROJECT}" ]; then echo "to be defined in ${profiledir}/config.sh:" echo "installdir = $installdir" echo "These variables must be set in bin/getfile.sh.cfg or in [profile]/config.sh:" echo "IMLCI_PHASE = $IMLCI_PHASE" echo "IMLCI_PROJECT = $IMLCI_PROJECT" exit 12 fi echo "OK, profile [${profile}] was set." downloadfile="${tmpdir}/${IMLCI_PROJECT}.tgz" downloadtmp="${tmpdir}/${IMLCI_PROJECT}.tgz.tmp" } # output a colored infoline with date and given message # param string message text function header(){ local COLOR="\033[34m" local NO_COLOR="\033[0m" echo echo -en "${COLOR}" echo ______________________________________________________________________ echo -n ">>>>>>>>>> $(date) " test ! -z "$profile" && echo -n "${profile} :: " echo -n "$*" echo -en "${NO_COLOR}" if [ "$wait" = "1" ]; then echo -n " RETURN"; read dummy; fi echo } # execute a task/ hook - if the given task script exists and has executable # persmissions; if not it is not an error # param string filename function run_task(){ local taskscript=$1 if [ -x "${taskscript}" ]; then echo "INFO: starting script ${taskscript}..." . "${taskscript}" || exit 10 else test -f "${taskscript}" && ( echo "SKIP: task script ${taskscript} is not executable." ; ls -l "${taskscript}") test -f "${taskscript}" || echo "SKIP: task script ${taskscript} does not exist." fi } function deploy(){ skipmessage="SKIP: no newer download file. You can use parameter -f to fore reinstall." # ---------------------------------------------------------------------- header "Set profile [$1]" setprofile $1 # ---------------------------------------------------------------------- header "Download ${IMLCI_PROJECT}.tgz" typeset -i local isupdate=$defaultupdate ${selfdir}/bin/getfile.sh -f ${IMLCI_PROJECT}.tgz -o ${downloadtmp} if [ $? -ne 0 ]; then echo Download failed. echo Repeating request with debug param -d to get the error... # added sleep to repeat the request with another hashed secret sleep 2 ${selfdir}/bin/getfile.sh -d -f ${IMLCI_PROJECT}.tgz -o ${downloadtmp} exit 1 fi # ---------------------------------------------------------------------- header "Detect if download is newer than last download." if [ -f ${downloadfile} ]; then # ls -l "${downloadfile}" "${downloadtmp}" diff "${downloadfile}" "${downloadtmp}" if [ $? -eq 0 ]; then echo "INFO: the downloaded file is the same like last download." rm -f "${downloadtmp}" else echo "OK: donwload contains an update." isupdate=$isupdate+1 mv "${downloadtmp}" "${downloadfile}" fi else echo "INFO: last download not available - first install or a forced update." isupdate=$isupdate+1 mv "${downloadtmp}" "${downloadfile}" fi ls -l "${downloadfile}" # ---------------------------------------------------------------------- header "Switch into install dir ${installdir} ..." test -d "${installdir}" || mkdir -p "${installdir}" cd ${installdir} || exit 2 # ---------------------------------------------------------------------- header "PRE tasks" # what you could do here: # - enable maintenance flag # - stop service # - cleanup directory ... up to remove all current files test $isupdate -eq 0 && echo $skipmessage test $isupdate -eq 0 || run_task "${profiledir}/tasks_preinstall.sh" # ---------------------------------------------------------------------- header "PRE tasks II - cleanup" if [ $isupdate -eq 0 ]; then echo $skipmessage else test "$cleanup_preview" -eq "1" || echo "SKIP: preview of cleanup is disabled." test "$cleanup_preview" -eq "1" && "${selfdir}/bin/preinstall_cleanup.sh" "${installdir}" "${downloadfile}" test "$cleanup_force" -eq "1" || echo "SKIP: cleanup files is disabled." test "$cleanup_force" -eq "1" && "${selfdir}/bin/preinstall_cleanup.sh" "${installdir}" "${downloadfile}" "force" fi # ---------------------------------------------------------------------- header "Extract ${downloadfile} $( pwd )" test $isupdate -eq 0 && echo $skipmessage test $isupdate -eq 0 || tar -xzf "${downloadfile}" . || exit 3 ls -l # ---------------------------------------------------------------------- # header "Remove download archive ${IMLCI_PROJECT}.tgz" # echo rm -f ${IMLCI_PROJECT}.tgz # ---------------------------------------------------------------------- header "Update config files" echo "Showing replacements:" ; grep '@replace\[' hooks/templates/* run_task "${profiledir}/tasks_config.sh" # ---------------------------------------------------------------------- header "Set file owner [${appowner}]" if [ $isupdate -eq 0 ]; then echo $skipmessage else if [ ! -z "${appowner}" ]; then sudo chown -R $appowner * .* || exit 5 ls -la else echo "SKIP: variable appowner was not set" fi fi # ---------------------------------------------------------------------- header "POST tasks" # what you could do here: # - start current deploy scripts # - apply database updates # - set permissions # - start service # - remove maintenance flag # - send success message as email/ slack/ [another fancy tool] test $isupdate -eq 0 && echo $skipmessage test $isupdate -eq 0 || run_task "${profiledir}/tasks_postinstall.sh" cd $( dirname $0 ) } # ---------------------------------------------------------------------- # MAIN # ---------------------------------------------------------------------- cd $( dirname $0 ) action="deploy" typeset -i defaultupdate=0 echo echo echo "<<<<<<<<<<##########| IML - DEPLOYMENT SCRIPT |##########>>>>>>>>>>" echo while getopts 'hfl' arg; do case ${arg} in h) echo "HELP" echo "Load one or more profiles profile to deploy an application." echo "If the download file is not newer then it does not extract files and does not" echo "run pre and post hooks - it updates the config files only and sets the owner." echo echo "Syntax:" echo " $( basename $0 ) [OPTION] [PROFILE(S)]" echo echo "Optioms:" echo " -h | show this help and exit" echo " -f | force full installation even if the download file is not newer" echo " -l | list exiting profile names" echo echo "Profile(s):" echo " Set one or more valid profile names. By default it loops over all profiles." echo " This prameter limits the execution to the given profiles." echo " Use option -l to get a list of profiles." echo exit 0 ;; f) echo "FORCE update" defaultupdate=1 shift 1 ;; l) echo "LIST of existing profiles:" getprofiles echo exit 0 ;; ?) echo "Invalid option: -${OPTARG}." exit 2 ;; esac done if [ $# -eq 0 ]; then header "looping over all profiles" getprofiles echo allprofiles=$( getprofiles ) else allprofiles="$*" fi for myprofile in $allprofiles do deploy $myprofile profile= done rc=$? profile= header "All done." echo exiting with statuscode $rc exit $rc # ---------------------------------------------------------------------- header "DONE :-)" # ----------------------------------------------------------------------