update_instance.sh 6.16 KB
update_instance() {
  #Read arguments and set variables
  coop=$1
  instance=$2
  repo=$3
  now=$4
  send_mails=$5
  ci_dir=$6
  ci_data_dir=$7
  if [[ ${repo} == "third-party" ]]; then
    user="django"
    service="django"
  elif [[ ${repo} == "Odoo" ]]; then
    user="odoo"
    service="odoo"
  else
    echo "Incorrect repo name : ${repo}"
    if ${send_mails}; then
      python3 "${ci_dir}/send_error_mail.py" "${coop} ${instance} ${repo} : incorrect repo name"
    fi
    exit 1
  fi
  if [[ "${instance}" == "prod" ]]; then
    target="${coop}_prod"
  else
    target="dev_cooperatic"
  fi

  #Move to repository directory, fetch all and make sure coop_prod branch exists
  cd /home/${user}/${repo}
  su ${user} -c "git fetch --all"
  branch_found_str=$( su ${user} -c "git ls-remote origin ${coop}_prod" ) #seems that git ls-remote is not "failing" so we need to check output
  if [ -z "${branch_found_str}" ]; then
    #branch prod does not exist, cannot go on
    echo "${coop} ${instance} ${repo}: branch ${coop}_prod does not exist"
    if ${send_mails}; then
      python3 "${ci_dir}/send_error_mail.py" "${coop} ${instance} ${repo} : branch ${coop}_prod does not exist"
    fi
    exit 1
  fi

  #Make sure config file exists if repo is third-party
  if [[ ${repo} == "third-party" ]]; then
    if ! test -f "coops_configurations/config_${coop}.py"; then
      echo "${coop} ${instance} ${repo}: coops_configurations/config_${coop}.py does not exists"
      if ${send_mails}; then
        python3 "${ci_dir}/send_error_mail.py" "${coop} ${instance} ${repo} : coops_configurations/config_${coop}.py does not exists"
      fi
      exit 1
    fi
  fi

  #Save filepaths of files that are going to be updated if repo is odoo
  if [[ ${repo} == "Odoo" ]]; then
    echo "git diff --name-only origin/${target}.."
    updated_filepaths="$( git diff --name-only origin/${target}.. )"
    echo "${updated_filepaths}"
  fi

  #Update code if needed
  new_commits="$( git log origin/${target}... )"
  if [ -z "${new_commits}" ]; then
    echo "${coop} ${instance} ${repo} : already up to date"
  else
    #Stop instance
    /etc/init.d/${service} stop
    #One could argue that git stash is risky on prod,
    #but it's way easier to go that way to get rid of template file changes generated on django service restart
    if ! su ${user} -c "git stash"; then
      #We can not finish the update : restart the system
      /etc/init.d/${service} start
      echo "${coop} ${instance} ${repo}: could not git stash"
      if ${send_mails}; then
        python3 "${ci_dir}/send_error_mail.py" "${coop} ${instance} ${repo} : could not git stash"
      fi
      exit 1
    fi
    #Make script robust to any branch change : switch to target !
    if ! su ${user} -c "git checkout ${target}"; then
      #We can not finish the update : restart the system
      #TODO : detect if we have stashed something on previous step to revert it (git stash pop)
      /etc/init.d/${service} start
      echo "${coop} ${instance} ${repo}: could not git checkout ${target}"
      if ${send_mails}; then
        python3 "${ci_dir}/send_error_mail.py" "${coop} ${instance} ${repo} : could not git checkout ${target}"
      fi
      exit 1
    fi
    #Pull
    if ! su ${user} -c "git pull"; then
      #We can not finish the update : restart the system
      #TODO : detect if we have stashed something on previous step to revert it (git stash pop)
      #TODO : undo previous git checkout if necessary
      echo "${coop} ${instance} ${repo}: could not git pull"
      if ${send_mails}; then
        python3 "${ci_dir}/send_error_mail.py" "${coop} ${instance} ${repo} : could not git pull"
      fi
      exit 1
    fi

    #Additionnal update actions

    #push tags to remember this prod update point (only on prod)
    if [[ "${instance}" == "prod" ]]; then
      #TODO : handle errors
      su ${user} -c "git tag -a ${coop}_${now} -m autotag"
      su ${user} -c "git push origin ${coop}_${now}"
    fi

    if [[ ${repo} == "third-party" ]]; then
      #Replace config file by proper one only if required
      if ! cmp "outils/config.py" "coops_configurations/config_${coop}.py"; then
        #Config files are different, go for it
        mv "outils/config.py" "${ci_data_dir}/ci_old_cfg_file_${now}.py"
        cp "coops_configurations/config_${coop}.py" "outils/config.py"
      else
        echo "config files are identical"
      fi
    fi

    if [[ ${repo} == "Odoo" ]]; then
      #Loop on updated_filenames, for each filename, look for the directory of __openerp__.py file
      #Ff found, just store the parent directory
      SAVEIFS=$IFS
      IFS=$'\n'
      if [[ ${updated_filepaths} == "" ]]; then
        updated_filepaths_array=()
      else
        read -rd '' -a updated_filepaths_array <<<"${updated_filepaths}"
      fi

      IFS='/'
      l=${#updated_filepaths_array[@]}

      declare -A modules #Modules to update
      modules_str=""

      for (( i=0; i<l; i++ ));
      do
        read -rd '' -a one_path_array <<<"${updated_filepaths_array[$i]}"
        j=0
        accu_path="${one_path_array[0]}"
        pathlen=${#one_path_array[@]}
        while [[ $j -lt ${pathlen} ]] && ! test -f "${accu_path}/__openerp__.py"; do
          ((j++))
          accu_path="${accu_path}/${one_path_array[j]}"
        done
        #Update key of modules if (we have found openerp.py (j<path) + module has not been added already),
        #so that we do not add twice same module in modules_str
        #and add module in modules_str
        if [[ $j -lt ${pathlen} ]] && [[ ! -v modules["${one_path_array[$j]}"] ]]; then
          modules["${one_path_array[$j]}"]=
          if [[ ${modules_str} == "" ]]; then
            modules_str="${one_path_array[$j]}"
          else
            modules_str="${modules_str},${one_path_array[$j]}"
          fi
        fi
      done

      IFS=$SAVEIFS

      echo "${modules_str}"

      restart_odoo_cmd="/home/odoo/Odoo/odoo/odoo.py -c /home/odoo/odoo-server.conf"
      if [[ -n "${modules_str}" ]]; then
        echo "restart odoo service with module update"
        su odoo -c "${restart_odoo_cmd} -u${modules_str} --stop-after-init"
      fi
    fi

    #Restart service
    echo "Starting ${service} service"
    /etc/init.d/${service} start
  fi
}