Skip to content
Snippets Groups Projects
Select Git revision
  • a3dabf0a1ab447440c80d4032dbca0cf05db6f7d
  • master default protected
  • handle-cookies
  • add-docker
4 results

redirect.class.php

Blame
  • deploy_app.sh 12.40 KiB
    #!/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
    # 2021-07-08  v0.5  <axel.hahn@iml.unibe.ch>  added function "runas"
    # 2021-11-01  v0.6  <axel.hahn@iml.unibe.ch>  save config diffs
    # 2021-11-02  v0.7  <axel.hahn@iml.unibe.ch>  delete logs keping N files
    # 2022-11-24  v0.8  <axel.hahn@iml.unibe.ch>  tar -xzf without dot as 2nd param
    # 2022-11-25  v0.9  <axel.hahn@iml.unibe.ch>  support custom phase + file per project
    # ======================================================================
    
    
    # ----------------------------------------------------------------------
    # CONFIG
    # ----------------------------------------------------------------------
    cd $( dirname $0 )
    selfdir=$( /bin/pwd )
    _version=0.9
    
    tmpdir=/var/tmp/imldeployment_packages
    logdir=/var/log/imldeployment-client
    
    # keep last N logs per project
    typeset -i iKeep=10
    
    wait=0
    # wait=1
    
    # export variables that will be set in getfile config or project
    export IMLCI_PROJECT=TODO
    export IMLCI_PHASE=TODO
    export cfgdiff=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."
    
        local localfile
        if [ -n "$IMLCI_FILE" ]; then
            localfile="${IMLCI_PROJECT}__${IMLCI_FILE}"
        else
            IMLCI_FILE="${IMLCI_PROJECT}.tgz"
            localfile="${IMLCI_FILE}"
        fi
    
        downloadfile="${tmpdir}/${localfile}"
        downloadtmp="${tmpdir}/${localfile}.tmp"
        cfgdiff="${tmpdir}/${localfile}_cfgdiff.txt"
        test -f "${cfgdiff}" && rm -f "${cfgdiff}"
    }
    
    # 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
    }
    
    # run a command as another posix user (even if it does not have a shell)
    # to be used in taskas_*install.sh
    #
    # example:
    # runas www-data "./hooks/ondeploy"
    #
    # param  string  username
    # param  string  command to execute. Needs to be quoted.
    # param  string  optional: shell (default: /bin/sh)
    function runas(){
        local _user=$1
        local _cmd=$2
        local _shell=$3
        test -z "$_shell" && _shell=/bin/sh
    
        su $_user -s $_shell -c "$_cmd"
    }
    
    # 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(){
        local dlparams
        skipmessage="SKIP: no newer download file. You can use parameter -f to force reinstall."
    
        # ----------------------------------------------------------------------
        header "Set profile [$1]"
        setprofile $1
    
    
        # ----------------------------------------------------------------------
        header "Download ${IML} ${IMLCI_PROJECT}.tgz"
        typeset -i local isupdate=$defaultupdate
        
        # getfile.sh reads phase from its cfg file - we need to add it as parameter
        test -n "${IMLCI_PHASE}" && dlparams="$dlparams -e ${IMLCI_PHASE}"
    
        # set the filename to fetch
        test -n "$IMLCI_FILE" || dlparams="$dlparams -f ${IMLCI_PROJECT}.tgz"
        test -n "$IMLCI_FILE" && dlparams="$dlparams -f $IMLCI_FILE"
    
        ${selfdir}/bin/getfile.sh ${dlparams} -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
        ls -1 * >/dev/null 2>&1
        if [ $? -ne 0 ]; then
            echo "INFO: target directory is empty."
            isupdate=$isupdate+1
        fi
    
    
        # ----------------------------------------------------------------------
        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} in $( 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
                # . is ${installdir}
                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"
        hasfilechange=0
        grep . $cfgdiff && hasfilechange=1
        if [ $hasfilechange -eq 1 ]; then
            echo "INFO: a config file was created or changed."
        else
            echo SKIP: No config file was changed.
        fi
        
        if [ $isupdate -ne 0 -o $hasfilechange -eq 1 ]; then
            run_task "${profiledir}/tasks_postchange.sh"
        fi
    
        cd $( dirname $0 )
    
    }
    
    # delete old logfiles keeping the last N files
    # param  string  name of project
    function logdelete(){
        local sProfile=$1
    
        header "DELETE LOGS ${logdir}/${sProfile}__* ... keep $iKeep"
        # order files by time 
        typeset -i local _iFiles=$( ls -1t ${logdir}/${sProfile}__*.log | wc -l )
        typeset -i local _iStart=$iKeep+1
    
        if [ $_iFiles -gt $iKeep ]; then
            ls -1t ${logdir}/${sProfile}__*.log | sed -n "${_iStart},${_iFiles}p" | while read mylogfile
            do
                echo -n "deleting "
                ls -l "${mylogfile}" && rm -f "${mylogfile}" 
            done
        else
            echo SKIP: deletion ... less than $iKeep files found 
        fi
    }
    
    # ----------------------------------------------------------------------
    # MAIN
    # ----------------------------------------------------------------------
    
    
    cd $( dirname $0 )
    
    action="deploy"
    typeset -i defaultupdate=0
    
    echo "_______________________________________________________________________________
    
     IML - DEPLOYMENT CLIENT
     DOCS: https://os-docs.iml.unibe.ch/imldeployment-client/                 _____
    _________________________________________________________________________/ v$_version
    "
    
    
    while getopts 'hfl' arg; do
      case ${arg} in
        h) 
            echo "HELP:"
            echo "  Loads 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 "  Optionally it cleans up the target directory."
            echo "  Runs 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 "OPTIONS:"
            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
    
    test -d "${logdir}" || mkdir -p "${logdir}"
    for myprofile in $allprofiles
    do
        ( deploy $myprofile; logdelete $myprofile ) 2>&1 | tee ${logdir}/${myprofile}__$(date +%Y-%m-%d__%H%M%S).log
        profile=
    done
    
    rc=$?
    profile=
    header "All done."
    echo exiting with statuscode $rc
    exit $rc
    
    
    
    # ----------------------------------------------------------------------
    header "DONE :-)"
    
    
    # ----------------------------------------------------------------------