Hello,

regarding the backups of the gnuhealth-control command I modified this bash script in a way that backups are differentiated into attachments, database & environment. Before a potential commit I would work on restore & tests but before doing this I would like to see what you think about it.


Problems I see in the current state:

- All files & database are processed twice because there is filesystem+database+filesystem&database

- All python & tryton modules are copied every time

- It fails if the database is not on the same system

- Restore can not be combined with changing the environment

- systemd .service file is not part of the backup

- It is not working for differing config file locations


Hopefully I could solve those problems with the new approach. It should at least work for installations following the wikibooks documentation, using the zypper package and modifications like my ansible scripts which are based on the wikibooks documentation and keep the .gnuhealthrc at $HOME but put config files at other locations.


The usage would be:

./gnuhealth-control backup_attachments --backdir <...> --datadir <...>

./gnuhealth-control backup_database --backdir <...> --database <...>

./gnuhealth-control backup_environment --backdir <...> --database <...>

Where ā€œ./ā€ should be skipped on openSUSE package installation and "su gnuhealth" + "cdutil" should be executed before if using the vanilla installation


Besides I’m also interested in backup approaches people are using apart from using gnuhealth-control if someone likes to share. I thought of using rsnapshot (with SSH) for the attachments folder and doing the database backup as postgres user or with sudo in order to include config files as well.


Best

Gerald

On 31.03.22 15:12, Gerald Wiese wrote:
URL:
   <https://savannah.gnu.org/task/?16142>

                  Summary: improve gnuhealth-control backup & restore
                  Project: GNU Health
             Submitted by: gerald_wiese
             Submitted on: Thu 31 Mar 2022 01:12:50 PM UTC
          Should Start On: Thu 31 Mar 2022 12:00:00 AM UTC
    Should be Finished on: Sun 01 May 2022 12:00:00 AM UTC
                 Category: None
                 Priority: 5 - Normal
                   Status: In Progress
                  Privacy: Public
         Percent Complete: 0%
              Assigned to: None
              Open/Closed: Open
                  Release: None
          Discussion Lock: Any
                   Module: health

     _______________________________________________________

Details:

How to improve backups & restore in gnuhealth-control command?

Backup application for restore:
     - attachments
     - config files
     - systemd service file
     - .gnuhealthrc bash environment
     - list of activated modules
Backup application for debugging if restore fails:
     - OS version
     - GH version
     - Tryton version
     - pip freeze

Backup PostgreSQL: A dump is saved but a backup as postgres/root could be more
appropriate in order to save config files as well that are not world-readable

Any further thoughts on this?




     _______________________________________________________

Reply to this item at:

   <https://savannah.gnu.org/task/?16142>

_______________________________________________
   Message sent via Savannah
   https://savannah.gnu.org/
#!/usr/bin/env bash

# gnuhealth-control
# The GNU Health control center

##############################################################################
#
#    GNU Health: The Free Health and Hospital Information System
#    Copyright (C) 2008-2022 Luis Falcon <[email protected]>
#    Copyright (C) 2011-2022 GNU Solidario <[email protected]>
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

VERSION="4.0.2"

TRYTON_URL="https://downloads-cdn.tryton.org";
GNUHEALTH_URL="https://ftp.gnu.org/gnu/health";
TRANSLATE_URL="https://hosted.weblate.org";

TRYTON_MODULES="account account_invoice account_product company country \
    currency party product stock stock_lot purchase account_invoice_stock \
    stock_supply purchase_request"

UPDATE_DOWNLOAD_DIR="$HOME/.gnuhealth_update"

BACKUP_TEMP_DIR="$HOME/.backup_temp"

PATCH_TRYTON=0

TRYTON_PATCHES=""

BSDTAR="bsdtar"

usage()
{
    cat << EOF

This is GNU Health control center ${VERSION}

usage: `basename $0` command [options]

Command:

  version             : Show version
  update              : Download and install the patches
  backup_attachments  : Backup the attachments folder
  backup_database     : Backup the database
  backup_environment  : Backup the environment including config files, versions 
of GNU Health, Tryton and OS & pip freeze
  instpydeps          : Install or update the latest dependencies
  getlang             : Get and install / update the language pack code
  status              : Show environment and GNU Health Tryton server status

Options:

 --backdir  : destination directory for the backup files
 --dry-run  : Check, download and preview, but don't actually update process
 --database : database name to use with the backup_database command
 --datadir  : directory containing attachments to backup

EOF
    exit 0
}

help()
{
    cat << EOF
    The GNU Health Control Center (gnuhealth-control) is the main tool for
    administrative tasks of the GNU Health environment.

    It can perform backups and updates of the instance

    Updates
    -------

    When gnuhealth-control is invoked with the update command,
    it will update GNU Health components within the same major number
    The following components will be checked and updated if necessary

        - Trytond : Tryton server version
        - GNU Health patchsets

    This will be valid for version with the same major and minor numbers, for 
example
    2.8.x will look for the latest tryton updates and GNU Health updates
    associated to that release.

    GNU Health Control is available for release 2.8 and newer.
    You can get the latest version of GNU Health update at GNU
    ftp://ftp.gnu.org/gnu/health


EOF
    usage
    exit 0
}

message()
{
    local UTC="$(date -u +'%Y-%m-%d %H:%M:%S')"

    case $1 in
      ERROR ) echo -e "\e[00;31m${UTC} [ERROR] $2\e[00m";;
      WARNING ) echo -e "\e[0;33m${UTC} [WARNING] $2\e[m" ;;
      INFO ) echo -e "\e[0;36m${UTC} [INFO] $2\e[m" ;;
    esac
}

get_current_values()
{
    # Bail out if no GNU Health profile exists
    if [ -f $HOME/.gnuhealthrc ]; then
      GNUHEALTHRC_PATH=$HOME/.gnuhealthrc
      message "INFO" "Found gnuhealthrc at $GNUHEALTHRC_PATH"
    elif [ -f /etc/tryton/gnuhealthrc ]; then
      GNUHEALTHRC_PATH=/etc/tryton/gnuhealthrc
      message "INFO" "Found gnuhealthrc at $GNUHEALTHRC_PATH"
    else
      message "ERROR" "Could not find gnuhealthrc in $HOME/.gnuhealthrc or 
/etc/tryton/gnuhealthrc"
      bailout
    fi

    source $GNUHEALTHRC_PATH

    # Stop if it can not find the GNU Health version
    if [ -z "$GNUHEALTH_VERSION" ]
    then
        message "ERROR" "Could not find the GNU Health version env. variable"
        bailout
    fi

    # Stop if current GNU Health version < 3.0.0
    local raw_ver=`echo $GNUHEALTH_VERSION | tr -d '.'`
    if [ $raw_ver -lt 300 ]
    then
        message "ERROR" "GNU Health version must be at least 3.0"
        bailout
    fi

    message "INFO" "Environment variables"
    message "INFO" "GNUHEALTH_VERSION = ${GNUHEALTH_VERSION}"
    message "INFO" "TRYTON VERSION = ${TRYTON_VERSION}"

}

do_backup_attachments()
{
    local BACKDATE=`date -u +%Y-%m-%d_%H%M%S`
    local LOCKFILE="$HOME/.gnuhealth_backup_attachments.lock"
    local INFOFILE="$HOME/gnuhealth_backup_attachments.log"
    local BACKDIR=""
    local DATADIR=""

    shift # Remove the command and deal only with the options

    if [ $# -ne 4 ]; then
        echo -e "Usage : gnuhealth-control backup --backdir <directory> 
--datadir <directory>"
        exit
    fi

    for option in "$@"
    do
      case $option in
          --backdir ) BACKDIR=$2;;
          --datadir ) DATADIR=$2 ;;
      esac
      shift
    done

    if [ -f $LOCKFILE ]; then
        message "ERROR" "Backup in progress or stale lock file found ..." | tee 
-a $INFOFILE
        bailout
    fi

    if [ ! -e ${BACKDIR} ]; then
        message "INFO" "Backup directory does not exist yet; creating it." | 
tee -a $INFOFILE
        mkdir -p $BACKDIR || bailout
    fi

    echo $$ > $LOCKFILE

    # Backup start
    message "INFO" "Compressing GNU Health attachments directory" | tee -a 
$INFOFILE

    cd $DATADIR
    tar -cvzf $BACKDIR/gnuhealth_attachments_$BACKDATE.tar.gz * || bailout

    message "INFO" "Backup of Attachments Successful" | tee -a $INFOFILE

    #Remove lock file
    rm $LOCKFILE

}

do_backup_database()
{
  local BACKDATE=`date -u +%Y-%m-%d_%H%M%S`
  local LOCKFILE="$HOME/.gnuhealth_backup_database.lock"
  local INFOFILE="$HOME/gnuhealth_backup_database.log"
  local BACKDIR=""
  local DB=""

  shift

  if [ $# -ne 4 ]; then
      echo -e "Usage : gnuhealth-control backup_database --backdir <directory> 
--database <dbname>"
      exit
  fi

  for option in "$@"
  do
    case $option in
        --backdir ) BACKDIR=$2;;
        --database ) DB=$2 ;;
    esac
    shift
  done

  if [ -f $LOCKFILE ]
  then
      message "ERROR" "Backup in progress or stale lock file found ..." | tee 
-a $INFOFILE
      bailout
  fi


  if [ ! -e ${BACKDIR} ]; then
      message "INFO" "Backup directory does not exist yet; creating it." | tee 
-a $INFOFILE
      mkdir -p $BACKDIR || bailout
  fi

  echo $$ > $LOCKFILE

  # Backup start

  message "INFO" "START Database Backup" | tee -a $INFOFILE

  pg_dump -Fc $DB > $BACKDIR/backup\_$DB\_$BACKDATE.dump || bailout

  message "INFO" "Backup of Database Successful" | tee -a $INFOFILE

  #Remove lock file
  rm $LOCKFILE
}

do_backup_environment()
{
  get_current_values

  local BACKDATE=`date -u +%Y-%m-%d_%H%M%S`
  local LOCKFILE="$HOME/.gnuhealth_backup_environment.lock"
  local INFOFILE="$HOME/gnuhealth_backup_environment.log"
  local BACKDIR=""
  local DB=""

  shift

  if [ $# -ne 4 ]; then
      echo -e "Usage : gnuhealth-control backup_environment --backdir 
<directory> --database <dbname>"
      exit
  fi

  for option in "$@"
  do
    case $option in
        --backdir ) BACKDIR=$2;;
        --database ) DB=$2 ;;
    esac
    shift
  done

  if [ -f $LOCKFILE ]
  then
      message "ERROR" "Backup in progress or stale lock file found ..." | tee 
-a $INFOFILE
      bailout
  fi

  if [ ! -e ${BACKDIR} ]; then
      message "INFO" "Backup directory does not exist yet; creating it." | tee 
-a $INFOFILE
      mkdir -p $BACKDIR || bailout
  fi

  if [ -d $BACKUP_TEMP_DIR ]; then
      message "ERROR" "Update download directory exists. Bailing out"
      bailout
  fi

  mkdir -p $BACKUP_TEMP_DIR
  cd $BACKUP_TEMP_DIR

  # Get trytond-console commands' path
  if command -v trytond-console; then
    TRYTOND_CONSOLE_PATH=`command -v trytond-console`
    message "INFO" "Found trytond-console at $TRYTOND_CONSOLE_PATH"
  elif [ -f 
$HOME/gnuhealth/tryton/server/trytond-$TRYTON_VERSION/bin/trytond-console ]; 
then
    
TRYTOND_CONSOLE_PATH=$HOME/gnuhealth/tryton/server/trytond-$TRYTON_VERSION/bin/trytond-console
    message "INFO" "Found trytond-console at $TRYTOND_CONSOLE_PATH"
  else
    message "ERROR" "Could not find trytond-console as system command or in 
${$HOME/gnuhealth/tryton/server/trytond-$TRYTON_VERSION/bin/}"
    exit
    # bailout
  fi

  # Look for path of trytond config
  if [ "$TRYTOND_CONFIG" != "" ] && [ -f $TRYTOND_CONFIG ] ; then
    message "INFO" "Found trytond config at $TRYTOND_CONFIG"
  elif [ -f /etc/tryton/trytond.conf ]; then
    TRYTOND_CONFIG=/etc/tryton/trytond.conf
    message "INFO" "Found trytond config at $TRYTOND_CONFIG"
  else
    message "ERROR" "Could not find trytond.conf as environment variable 
TRYTOND_CONFIG or at /etc/tryton/trytond.conf"
    exit
    # bailout
  fi

  echo $$ > $LOCKFILE

  # Backup start

  message "INFO" "START Environment Backup" | tee -a $INFOFILE

  $TRYTOND_CONSOLE_PATH -d $DB -c $TRYTOND_CONFIG > trytond_modules.txt << EOF
Module = pool.get('ir.module')
modules = Module.search([('state', '=', 'activated')])
for module in modules:
  print(module.name)
EOF

  pip3 freeze > pip_environment.txt
  cat /etc/os-release > os_version.txt
  echo $GNUHEALTH_VERSION > gnuhealth_version.txt
  echo $TRYTON_VERSION > trytond_version.txt

  cp $GNUHEALTHRC_PATH gnuhealthrc
  cp $TRYTOND_CONFIG .
  cp `dirname $TRYTOND_CONFIG`/gnuhealth_log.conf . || cp `dirname 
$TRYTOND_CONFIG`/trytond_log.conf . || message "WARNING" "Did not find log 
config"

  SYSTEMD_GNUHEALTH=`systemctl show -p FragmentPath gnuhealth`
  cp ${SYSTEMD_GNUHEALTH:13} .

  echo $TRYTOND_CONFIG > config_path.txt
  echo $GNUHEALTHRC_PATH > gnuhealthrc_path.txt
  echo ${SYSTEMD_GNUHEALTH:13} > systemd_path.txt

  tar -cvzf $BACKDIR/gnuhealth_environment_$BACKDATE.tar.gz .

  cd ..
  rm -rf $BACKUP_TEMP_DIR

  message "INFO" "Backup of Environment Successful" | tee -a $INFOFILE

  #Remove lock file
  rm $LOCKFILE
}

check_status()
{
    TRYTOND_PIDS=`pgrep -f "^.*python.*trytond.*$"`
    if [ $? = 0 ]
    then
        message "INFO" "GNU Health / Tryton instance(s) with PID(s) :"
        echo $TRYTOND_PIDS
    else
        message "INFO" "No GNU Health instance seems to be running"
    fi

}

check_download_dir()
{
    if [ -d $UPDATE_DOWNLOAD_DIR ]; then
        message "ERROR" "Update download directory exists. Bailing out"
        bailout
    fi
}

check_updates()
{
    source $HOME/.gnuhealthrc
    UTIL_DIR="${GNUHEALTH_DIR}/tryton/server/util"

    local TRYTOND_PATCHLEVEL=`echo ${TRYTON_VERSION} | cut -d'.' -f3`

    TRYTON_MAJOR_MINOR=`echo $TRYTON_VERSION | cut -d'.' -f1-2`

    GNUHEALTH_MAJOR_MINOR=`echo $GNUHEALTH_VERSION | cut -d'.' -f1-2`
    GNUHEALTH_PATCHSET=`echo $GNUHEALTH_VERSION | cut -d'.' -f3`

    GCONTROL_PATCHSET=`echo $VERSION | cut -d'.' -f3`

    NEED_UPDATE_GCONTROL=0
    NEED_UPDATE_TRYTOND=0
    NEED_UPDATE_MODULES=0
    NEED_UPDATE_PATCHSETS=0
    NEED_PATCH_TRYTON=0
    MOD_UPDATES=""
    NEED_DELETE=0
    TO_DELETE=""

    message "INFO" "GNUHEALTH-CONTROL VERSION : ${VERSION}"

    # Retrieve the latest control center that is compatible with the current 
GNU Health version
    LATEST_GHCONTROL=`wget --quiet -O - ${GNUHEALTH_URL} | egrep -o 
gnuhealth-control-${GNUHEALTH_MAJOR_MINOR}.[0-9\.]+.tar.gz | sort -V | tail -1`
    local LATEST_GHCONTROL_PATCHSET=`echo ${LATEST_GHCONTROL} | cut -d'.' -f3`
    local GHCONTROL_PATCHSET=`echo $VERSION | cut -d'.' -f3`

    if (test ${LATEST_GHCONTROL}); then
        if (( ${GHCONTROL_PATCHSET} < ${LATEST_GHCONTROL_PATCHSET} )); then
            message "WARNING" "Current version ${VERSION} is outdated. A new 
version (${LATEST_GHCONTROL}) is available"
            NEED_UPDATE_GCONTROL=1
        else
            message "INFO" "GNU Health control center is at the latest version 
${VERSION}"
        fi
    else
        message "ERROR" "Error on getting the latest GNU Health Control Verion. 
Maybe a development release"
    fi

    message "INFO" "TRYTON SERVER : Checking latest patchlevel"

    LATEST_TRYTOND=`wget --quiet -O - ${TRYTON_URL}/${TRYTON_MAJOR_MINOR} | 
egrep -o trytond-${TRYTON_MAJOR_MINOR}.[0-9\.]+.tar.gz | sort -V | tail -1`
    local LATEST_TRYTOND_PATCHLEVEL=`echo ${LATEST_TRYTOND} | cut -d'.' -f3`

    # Check latest tryton server against local version
    if (( ${TRYTOND_PATCHLEVEL} < ${LATEST_TRYTOND_PATCHLEVEL} )); then
        message "WARNING" "TRYTON SERVER patchlevel ${TRYTOND_PATCHLEVEL} is 
outdated ! A newer version is available (${LATEST_TRYTOND})"
        NEED_DELETE=1
        TO_DELETE="${TO_DELETE} 
${GNUHEALTH_DIR}/tryton/server/trytond-${TRYTON_MAJOR_MINOR}.${TRYTOND_PATCHLEVEL}"
        NEED_UPDATE_TRYTOND=1
    else
        message "INFO" "TRYTON SERVER patchlevel ${TRYTOND_PATCHLEVEL} is at 
the latest version"
    fi

    # Check latest tryton modules against local version
    cd ${GNUHEALTH_DIR}/tryton/server/modules

    for MODULE in ${TRYTON_MODULES}; do
        MOD=`ls -1d trytond_${MODULE}-*`
        message "INFO" "Checking MODULE ${MOD}"
        MODNAME=`echo $MOD | cut -d'-' -f1`
        MODULE_PATCHLEVEL=`echo $MOD | sed  's/^.*\.\([[:digit:]]*\)$/\1/'`
        LATEST_MODULE=`wget --quiet -O - ${TRYTON_URL}/${TRYTON_MAJOR_MINOR} | 
egrep -o ${MODNAME}-${TRYTON_MAJOR_MINOR}.[0-9\.]+.tar.gz | sort -V | tail -1`
        LATEST_MODULE_PATCHLEVEL=`echo ${LATEST_MODULE} | cut -d'.' -f3`
        if (( ${MODULE_PATCHLEVEL} < ${LATEST_MODULE_PATCHLEVEL} )); then
            message "WARNING" "${MODNAME} patchlevel ${MODULE_PATCHLEVEL} is 
outdated ! A newer version is available (${LATEST_MODULE})"
            NEED_UPDATE_MODULES=1
            MOD_UPDATES="${MOD_UPDATES} ${LATEST_MODULE}"
            NEED_DELETE=1
            TO_DELETE="${TO_DELETE} 
${GNUHEALTH_DIR}/tryton/server/modules/${MODNAME}-${TRYTON_MAJOR_MINOR}.${MODULE_PATCHLEVEL}"
        else
            message "INFO" "${MODNAME} patchlevel ${MODULE_PATCHLEVEL} is at 
the latest version"
        fi
    done

    # Check latest GNU HEALTH PATCHSETS against local version
    message "INFO" "GNU HEALTH KERNEL : Checking latest PATCHSETS"

    PATCHSETS_NUM=`wget --quiet -O - ${GNUHEALTH_URL}/ | egrep -o 
gnuhealth_patchset-${GNUHEALTH_MAJOR_MINOR}\.[0-9\.]+.tar.gz | uniq | wc -l | 
tr -d ' '`

    if (( ${PATCHSETS_NUM} > 0 )); then
        message "INFO" "Number of Patchsets for this version : ${PATCHSETS_NUM}"

        LATEST_GNUHEALTH=`wget --quiet -O - ${GNUHEALTH_URL}/ | egrep -o 
gnuhealth_patchset-${GNUHEALTH_MAJOR_MINOR}\.[0-9\.]+.tar.gz | sort -V | tail 
-1`
        LATEST_GNUHEALTH_PATCHSET=`echo ${LATEST_GNUHEALTH} | cut -d'.' -f3`

        if (( ${GNUHEALTH_PATCHSET} < ${LATEST_GNUHEALTH_PATCHSET} )); then
            message "WARNING" "GNU HEALTH patchset ${GNUHEALTH_PATCHSET} is 
outdated ! A newer version is available (${LATEST_GNUHEALTH})"
            NEED_UPDATE_PATCHSETS=1
            let PSET=GNUHEALTH_PATCHSET+1
            for n in `seq $PSET $LATEST_GNUHEALTH_PATCHSET`
            do
                PATCHSETS="$PATCHSETS 
gnuhealth_patchset-${GNUHEALTH_MAJOR_MINOR}.$n.tar.gz"
            done

        else
            message "INFO" "GNU HEALTH patchset ${GNUHEALTH_PATCHSET} is at the 
latest version"
        fi

    else
        message "INFO" "** NO GNU HEALTH PATCHSETS FOUND FOR THIS VERSION **"
    fi

    # CHECK SECURITY ADVISORIES AND OTHER PATCHES NOT PRESENT IN THE STANDARD 
TRYTON KERNEL

    if (( ${PATCH_TRYTON} == 1 )); then
        message "INFO" "Checking Security Advisories and other patches not 
present in the standard tryton kernel"

            for n in ${TRYTON_PATCHES}
            do
                message "INFO" "Downloading patch for Tryton server : ${n}"
                wget --quiet --directory-prefix=${UPDATE_DOWNLOAD_DIR}/ 
${GNUHEALTH_URL}/security/${n} || message "ERROR" "Could not get patch"
                message "INFO" "Checking elegibility of the patch"
                cd ${GNUHEALTH_DIR}/tryton/server/trytond-${TRYTON_VERSION}*
                patch --dry-run --silent -N -p1 < ${UPDATE_DOWNLOAD_DIR}/${n}
                if [ $? -eq 0 ]; then
                    message "WARNING" "Patch ${n} needs to be applied"
                    NEED_PATCH_TRYTON=1
                else
                    message "INFO" "Patch ${n} already applied or not elegible"
                fi

            done
    else
        message "WARNING" "PATCHING STANDARD TRYTON IS DISABLED. NO EXTRA 
SECURITY PATCHES OR FUNCTIONALITY WILL BE APPLIED"
    fi
}

install_updates()
{
    if [ $NEED_UPDATE_GCONTROL -eq 1 ]; then
        message "INFO" "Downloading ${LATEST_GHCONTROL} ..."
        wget --quiet --directory-prefix=${UPDATE_DOWNLOAD_DIR}/ 
${GNUHEALTH_URL}/${LATEST_GHCONTROL} || bailout
        message "INFO" "Uncompressing ${LATEST_GHCONTROL} ..."
        tar -xzf ${UPDATE_DOWNLOAD_DIR}/${LATEST_GHCONTROL} --directory 
${UTIL_DIR}|| bailout
        message "INFO" "Sucessfully installed ${LATEST_GHCONTROL} "
        message "INFO" "Removing temporary download directory "
        rm -rf ${UPDATE_DOWNLOAD_DIR} || bailout
        message "INFO" "Please restart now the update with the new control 
center"
        exit 0

    fi

    if [ $NEED_UPDATE_TRYTOND -eq 1 ]; then
        message "INFO" "Downloading TRYTON SERVER $LATEST_TRYTOND"
        wget --quiet --directory-prefix=${UPDATE_DOWNLOAD_DIR}/trytond 
${TRYTON_URL}/${TRYTON_MAJOR_MINOR}/${LATEST_TRYTOND} || bailout
        message "INFO" "--> Uncompressing TRYTON SERVER $LATEST_TRYTOND"
        tar -xzf ${UPDATE_DOWNLOAD_DIR}/trytond/${LATEST_TRYTOND} --directory 
${GNUHEALTH_DIR}/tryton/server || bailout
    fi

    if [ $NEED_UPDATE_MODULES -eq 1 ]; then
        for mod in ${MOD_UPDATES}
        do
            message "INFO" "Downloading $mod"
            wget --quiet --directory-prefix=${UPDATE_DOWNLOAD_DIR}/modules 
${TRYTON_URL}/${TRYTON_MAJOR_MINOR}/${mod} || bailout
            message "INFO" "--> Uncompressing ${mod}"
            tar -xzf ${UPDATE_DOWNLOAD_DIR}/modules/${mod} --directory 
${GNUHEALTH_DIR}/tryton/server/modules || bailout
        done
    fi

    if [ $NEED_UPDATE_PATCHSETS -eq 1 ]; then
        for patchset in ${PATCHSETS}
        do
            message "INFO" "Downloading $patchset"
            wget --quiet --directory-prefix=${UPDATE_DOWNLOAD_DIR}/patchsets 
${GNUHEALTH_URL}/${patchset} || bailout
            message "INFO" "--> Applying PATCHSET $patchset"
            tar -xzf ${UPDATE_DOWNLOAD_DIR}/patchsets/${patchset} --directory 
${HOME} || bailout
        done
    fi

    # APPLY SECURITY ADVISORIES AND OTHER PATCHES NOT PRESENT IN THE STANDARD 
TRYTON KERNEL

    if (( ${PATCH_TRYTON} == 1 )); then
        if (( ${NEED_PATCH_TRYTON} == 1 )); then
            message "INFO" "APPLY SECURITY ADVISORIES AND OTHER PATCHES NOT 
PRESENT IN THE STANDARD TRYTON KERNEL"
            for n in ${TRYTON_PATCHES}
            do
                message "INFO" "Checking elegibility of the patch"
                cd ${GNUHEALTH_DIR}/tryton/server/trytond-${TRYTON_VERSION}

                patch --dry-run --silent -N -p1 < ${UPDATE_DOWNLOAD_DIR}/${n}
                if [ $? -eq 0 ]; then
                    message "WARNING" "Applying patch ${n} to Tryton kernel"
                    patch -p1 < ${UPDATE_DOWNLOAD_DIR}/${n} || bailout
                    message "INFO" "Tryton kernel sucessfully patched"
                else
                    message "INFO" "Patch ${n} already applied or not elegible"
                fi
            done
        fi
    else
        message "WARNING" "PATCHING STANDARD TRYTON IS DISABLED. NO EXTRA 
SECURITY PATCHES OR FUNCTIONALITY WILL BE APPLIED"
    fi

}

remove_old()
{
    if [ ${NEED_DELETE} -eq 1 ]; then
        message "WARNING" "Removing obsolete kernel and/or modules : 
${TO_DELETE}"
        rm -rf ${TO_DELETE}
    fi
}

relink_mods()
{
    source $HOME/.gnuhealthrc

    if [ ${NEED_DELETE} -eq 1 ]; then
        for mod in ${TRYTON_MODULES}; do
            local modname=`ls -1d trytond_${mod}-*`
            message "INFO" "Relinking : ${mod}"
            ln -sf ${GNUHEALTH_DIR}/tryton/server/modules/${modname} 
${GNUHEALTH_DIR}/tryton/server/${TRYTOND}/trytond/modules/${mod} || bailout
        done

        message "INFO" "Relinking GNU Health modules ..."
        local HEALTH_MODS=`cd ${GNUHEALTH_DIR}/tryton/server/modules; ls -1d 
health*`
        for mod in ${HEALTH_MODS}; do
            message "INFO" "--> Relinking : ${mod}"
            ln -sf ${GNUHEALTH_DIR}/tryton/server/modules/${mod} 
${GNUHEALTH_DIR}/tryton/server/${TRYTOND}/trytond/modules/ || bailout
        done

        message "INFO" "Relinking local modules and customizations ..."

        local LOCAL_MODS=`cd ${GNUHEALTH_DIR}/tryton/server/modules/local; ls 
-A`
        for mod in ${LOCAL_MODS}; do
            message "INFO" "--> Relinking : ${mod}"
            ln -sf ${GNUHEALTH_DIR}/tryton/server/modules/local/${mod} 
${GNUHEALTH_DIR}/tryton/server/${TRYTOND}/trytond/modules/ || bailout
        done

    fi
}

do_update()
{
    if [ $# -gt 1 ];then
        if [ $2 != "--dry-run" ];then
        message "ERROR" "Unrecognized update option"
        bailout
        fi
    fi

    check_download_dir
    get_current_values
    check_updates
    if [ $# -gt 1 ];then
        if [ $2 == "--dry-run" ];then
            cleanup
            exit 0
        fi
    fi
    install_updates
    remove_old
    relink_mods
    cleanup
}

getlang() {
    if [ $# -eq 1 ]; then
        usage
    fi

    local lang_to_install=$2
    local lang_file=${lang_to_install}.zip
    source $HOME/.gnuhealthrc || bailout
    local lang_download_dir=$(mktemp -d /tmp/gnuhealth-XXXX)

    message "INFO" "Going to modules directory..."

    cd ${GNUHEALTH_DIR}/tryton/server/modules || bailout
    message "INFO" "Retrieving language pack file for ${lang_to_install}"
    wget 
${TRANSLATE_URL}/download-language/${lang_to_install}/gnu-health/?format=zip -O 
${lang_download_dir}/${lang_file} || bailout
    message "INFO" "Installing / Updating language files for ${lang_to_install} 
..."

    ${BSDTAR} --strip-components 3 -xzf ${lang_download_dir}/${lang_file} || 
bailout
    message "INFO" "Language pack ${lang_to_install} sucessfully installed / 
updated"
    message "INFO" "You now need to update the database modules"
    message "INFO" "Removing temporary directories"
    rm -rf ${lang_download_dir}
    cd
}

install_python_dependencies() {
    message "INFO" "Updating Python dependencies..."

    # PIP names on Debian/Arch Linux based distros:
    local PIP_NAMES="pip pip3 pip-python"
    PIP_NAME=""
    for NAME in ${PIP_NAMES}; do
        if [[ $(which ${NAME} 2>/dev/null) ]]; then
            PIP_NAME=${NAME}
            break
        fi
    done

    if [[ ! ${PIP_NAME} ]]; then
        message "ERROR" "PIP command not found. Please install it or check your 
PATH variable."
        bailout
    fi


    local PIP_CMD=$(which $PIP_NAME)
    local PIP_VERSION="$(${PIP_CMD} --version | awk '{print $2}')"

    local PIP_ARGS="install --upgrade --user"

    # Python packages
    local PIP_LXML="lxml"
    local PIP_RELATORIO="relatorio"
    local PIP_WRAPT="wrapt"
    local PIP_WERKZEUG="werkzeug<2"
    local PIP_DATEUTIL="python-dateutil"
    local PIP_PSYCOPG2="psycopg2-binary"
    local PIP_PYTZ="pytz"
    local PIP_LDAP="python-ldap"
    local PIP_VOBJECT="vobject"
    local PIP_QRCODE="qrcode"
    local PIP_PYBARCODE="python-barcode"
    local PIP_SIX="six"
    local PIP_PILLOW="Pillow"
    local PIP_CALDAV="caldav"
    local PIP_POLIB="polib"
    local PIP_SQL="python-sql"
    local PIP_STDNUM="python-stdnum"
    local PIP_SIMPLEEVAL="simpleeval"
    local PIP_CONFIGPARSER="configparser"
    local PIP_WEBDAV3="pywebdav3-gnuhealth"
    local PIP_BCRYPT="bcrypt"
    local PIP_NUMPY="numpy"
    local PIP_UNOCONV="unoconv"
    local PIP_MAGIC="python-magic"
    local PIP_BEREN="beren==0.7.0"
    local PIP_PENDULUM="pendulum"
    local PIP_MATPLOTLIB="matplotlib"
    local PIP_PASSLIB="passlib"
    local PIP_PYCOUNTRY="pycountry==20.7.3"
    local PIP_PROGRESSBAR="progressbar==2.2"
    local PIP_DEFUSEDXML="defusedxml"


    # Operating System specific package selection
    # Skip PYTHON-LDAP installation since it tries to install / compile it 
system-wide

    message "WARNING" "Skipping local PYTHON-LDAP installation. Please refer to 
the Wikibook to install it"

    local PIP_PKGS="$PIP_NUMPY $PIP_PYTZ $PIP_WRAPT $PIP_WERKZEUG $PIP_SIX 
$PIP_LXML $PIP_RELATORIO $PIP_DATEUTIL $PIP_PSYCOPG2 $PIP_VOBJECT \
        $PIP_QRCODE $PIP_PYBARCODE $PIP_PILLOW $PIP_CALDAV $PIP_POLIB $PIP_SQL 
$PIP_STDNUM $PIP_SIMPLEEVAL $PIP_CONFIGPARSER \
        $PIP_WEBDAV3 $PIP_BCRYPT $PIP_UNOCONV $PIP_MAGIC $PIP_PASSLIB 
$PIP_BEREN $PIP_PENDULUM $PIP_MATPLOTLIB $PIP_PASSLIB $PIP_PYCOUNTRY \
        $PIP_PROGRESSBAR $PIP_DEFUSEDXML"

    message "INFO" "Installing python dependencies with pip-${PIP_VERSION} ..."

    for PKG in ${PIP_PKGS}; do
        message " >> ${PKG}"
        ${PIP_CMD} ${PIP_ARGS} ${PKG} || bailout
        message " >> OK"
    done
}

bailout() {
    message "ERROR" "Bailing out !"
    message "ERROR" "Removing lock files and temporary directories"
    rm -f $LOCKFILE
    rm -rf ${LANG_DOWNLOAD_DIR}
    exit 1
}

cleanup()
{
    # Delete temporary download directory
    rm -rf ${UPDATE_DOWNLOAD_DIR} || bailout
    exit 0
}

parse_command_line()
{
    if [ $# -eq 0 ]; then
        usage
    fi

    case $1 in
        version) echo $VERSION;;
        backup_attachments) do_backup_attachments $@;;
        backup_database) do_backup_database $@;;
        backup_environment) do_backup_environment $@;;
        update) do_update $@;;
        status) check_status;;
        getlang) getlang $@;;
        instpydeps)  install_python_dependencies $@;;
        help) help;;
        *) echo $1: Unrecognized command; exit 1;;
    esac
}

parse_command_line $@

Reply via email to