#!/bin/bash
shopt -s compat31

[ -r /var/www/cgi-bin/getDbInfo.sh ] && . /var/www/cgi-bin/getDbInfo.sh
[ -r /var/www/shared/getDbInfo.sh ] && . /var/www/shared/getDbInfo.sh
[ -r /var/www/shared/getNetworkInfo.sh ] && . /var/www/shared/getNetworkInfo.sh


#variables
CMPMD5="useless"
SELFNAME=${0##*/}
BASE=`readlink -nf $0`
BASE=`dirname $BASE`
DIRNAME=`basename $BASE`
RPMDIR=$BASE/patchfile/rpm
USER=jboss
PASSWORD=$(getDbPassword | sed 's/.//;s/.$//')
HOSTNAME=`hostname`
LOCALIP=`grep $HOSTNAME /etc/hosts | head -n 1 | awk '{print \$1}'`
DB_HOST_NAME=$(getDbHost)

PROPERTY_FILE=$BASE/patch.properties
PR_LIST=$BASE/PR_List.txt
PATCH_VERSION=""
SPACE_VERSION=""
PRE_PATCH=""
POST_PATCH=""

function removeDuplicate(){
   TARGET=$1
   duplicatefiles=`/usr/bin/unzip -l $TARGET | sort | uniq -c -d | awk '{print \$5}'`
   for duplicate in $duplicatefiles
   do
      echo "find duplicate file $duplicate, start to delete it"
      /usr/bin/jar -xf $TARGET $duplicate
      while true; do
         /usr/bin/zip -d $TARGET $duplicate
         count=`/usr/bin/unzip -l $TARGET | grep $duplicate | wc -l`
         if [ $count -eq 0 ]; then
            break
         fi
      done
   done
   for duplicate in $duplicatefiles
   do
      /usr/bin/jar -uf $TARGET -C . $duplicate
      rm -rf $duplicate
   done
}

function patchJbossModule(){
   JMPSUBSYSTEM_DIR="/usr/local/jboss/modules/system/layers/base/net/juniper/jmp/cmp/subsystem/main"
   echo "--2-- patching jmpsubsystem file"
   if [ -e "$BASE/patchfile/subsystem/jmpsubsystem.jar" ];then
      cp -rf $BASE/patchfile/subsystem/jmpsubsystem.jar $JMPSUBSYSTEM_DIR
   fi
   if [ -e "$BASE/patchfile/subsystem/cems-interfaces.jar" ];then
      cp -rf $BASE/patchfile/subsystem/cems-interfaces.jar $JMPSUBSYSTEM_DIR
   fi
   rm -rf $JMPSUBSYSTEM_DIR/*.index
   echo "--2-- patching jmpsubsystem finished"
}

function patchJbossEar(){
   EAR_DIR="/usr/local/jboss/standalone/deployments/"
   mkdir -p $BASE/backupfile/ears
   earfiles=`find $EAR_DIR -name '*.ear'`
   for f in $earfiles
   do
      cp $f $BASE/backupfile/ears
   done
   
   patchlist=("cmp.ear|00" "cems.ear|01" "opennms.ear|021")
   #patchlist=("cmp.ear|00")
   for patch in ${patchlist[@]}
   do
      earname=`echo $patch | awk -F\| '{print $1}'`
      eardir=`echo $patch | awk -F\| '{print $2}'`
      if [ -d $BASE/patchfile/$earname ]; then
         echo "--1-- patching $earname file"
         removeDuplicate $EAR_DIR/$eardir/$earname
         filelist=`/usr/bin/find $BASE/patchfile/$earname/ -type f | awk -F"$earname/" '{print $2}'`
         for f in $filelist
         do
            echo "--1-- patching $earname $f"
            /usr/bin/jar -uf $EAR_DIR/$eardir/$earname -C $BASE/patchfile/$earname/ $f
         done
         chown jboss:jboss $EAR_DIR/$eardir/$earname
      fi
   done
   
   echo "--1-- patching other ear files"
   sh $BASE/scripts/patchEar.sh ALL > /dev/null
   
   rm -rf lib META-INF
   
   echo "--1-- patching ear files finished"
}

function patchSystem(){
   filelist=`/usr/bin/find $BASE/patchfile/system/ -type f | awk -F'patchfile/system' '{print $2}'`
   for f in $filelist
   do
      echo "--2-- patching $f"
      /bin/mkdir -p $BASE/backupfile$(dirname ${f})
      cp -f $f $BASE/backupfile$(dirname ${f})
      cp -f $BASE/patchfile/system${f} $f
   done
}

function patchScripts(){
   
   echo "-- patching scripts"
   # Backup the existing files
   cp -f /etc/httpd/conf/httpd.conf $BASE/patchfile/scripts/backup/
  
   # Replacing the existing files to the respective directory
   yes | cp -rf $BASE/patchfile/scripts/httpd.conf /etc/httpd/conf/

   # Copying the new file, change ownership and permission
   chmod 644 /etc/httpd/conf/httpd.conf

   /sbin/service httpd restart > /dev/null

   echo "-- patching scripts finished"

}


#ok-0,notok-1
function rpmisgoodtoupgrade(){
   ret=0
   rpm=$1
   rpmname=`rpm -qp $rpm --queryformat '%{NAME}' 2>/dev/null`
   rpmarch=`rpm -qp $rpm --queryformat '%{ARCH}' 2>/dev/null`
   newversion=`rpm -qp $rpm --queryformat '%{VERSION}.%{RELEASE}' 2>/dev/null`
   oldversion=`rpm -qa $rpmname --queryformat '%{VERSION}.%{RELEASE} %{ARCH}\n' | grep $rpmarch | awk '{print \$1}'`
   if [ "$oldversion"x == ""x ]; then
      echo "$rpmname does not installed"
   elif [ "$oldversion" \< "$newversion" ]; then
      echo "$rpmname.$rpmarch newVersion:$newversion > oldVersion:$oldversion"
   else
      #echo "$rpmname.$rpmarch does not need to upgrade"
      ret=1
   fi
   
   return $ret
}

function patchSoftware(){
   rpms=$1
   rpmops=$2
   headerrpm=${rpms[0]}
   
   rpmpath="$RPMDIR/$headerrpm"
   rpmisgoodtoupgrade $rpmpath
   if [ $? -eq 0 ]; then
      rpmstring=""
      for rpm in ${rpms[@]}
      do
         rpmstring="$rpmstring $RPMDIR/$rpm"
      done
      /bin/rpm -Uvh $2 $rpmstring
   else
      rpmname=`rpm -qp $rpmpath --queryformat '%{NAME}.%{ARCH}' 2>/dev/null`
      echo "Do not need to upgrade $rpmname"
   fi
}

function patchRPMS(){
   echo "start to upgrade rpms from $RPMDIR"
   rpmlist=`find $RPMDIR -name *.rpm`
   tmpfile=`mktemp`
   installedlist=`rpm -qa --queryformat '%{NAME}-%{VERSION}.%{RELEASE}.%{ARCH}\n' > $tmpfile`
   rpmstring=""
   for rpm in $rpmlist
   do
      nameVersion=`rpm -qp $rpm --queryformat '%{NAME}-%{VERSION}.%{RELEASE}.%{ARCH}' 2>/dev/null`
      rpminstalled=`grep $nameVersion $tmpfile`
      if [ "$rpminstalled"x == ""x ]; then
         #echo "rpm $rpm does not install"
         rpmstring="$rpmstring $rpm"
      else
         echo "rpm $rpm already installed"
      fi
   done
   
   rpm -Uvh $rpmstring 2>/dev/null
   unlink $tmpfile
}


function patchLocal(){ 
  
   if [ -e /etc/.$PATCH_VERSION ]; then
      echo "Patch $PATCH_VERSION already installed."
   else
      installHotPatch
   fi
}

function patchCluster(){ 
   hostlist=(`mysql -h$DB_HOST_NAME -u$USER -p$PASSWORD -sNe 'select ip from build_db.FABRIC_NODE' 2>/dev/null`)
   hostlength=${#hostlist[@]}
   
   if [ $hostlength -gt 1 ]; then
      adminpwd=""
      sameuser="y"
      read -ep "This is Cluster env, Do all nodes have same password for admin user?(y/n):" sameuser
      if [ $sameuser = 'y' ]; then
         read -esp "This is Cluster env, please enter password for admin user:" adminpwd
      elif [ ! $sameuser = 'n' ]; then
         echo "Input incorrect, exit!"
         exit 1
      fi
      
      for host in ${hostlist[@]}
      do
         if [ "$LOCALIP"x = "$host"x ]; then
            echo "start to patch local server $host"
            patchLocal
         else
            echo "start to patch remote server $host"
            if [ $sameuser = 'n' ]; then
               read -esp "Please enter password of admin user for node $host:" adminpwd
            fi
            host=`perl -e "use lib('/usr/nma/lib'); use NmaUtil; print NmaUtil::useEth1toSCP('$host');"`
            expect $BASE/scripts/scpExpect $adminpwd $BASE admin@$host:/home/admin
            expect $BASE/scripts/sshExpectSudo admin $adminpwd $host "sudo bash /home/admin/$DIRNAME/$SELFNAME LOCAL"
         fi
      done
   else
      patchLocal
   fi
}

function cleanupHotPatch(){
   rm -rf /etc/.$PATCH_VERSION
   if [ -e /home/admin/$DIRNAME/ ];then
      rm -rf /home/admin/$DIRNAME/
   fi
}

function installHotPatch() {
   echo "Install $PATCH_VERSION"
   echo "This may need 3-4 mins"
   echo "Stopping watchdog and JBOSS"
   
   /sbin/service jmp-watchdog stop
   
   /sbin/service jboss status
   if [ $? -eq "0" ] ; then /sbin/service jboss stop;  fi
   
   /sbin/service jboss-dc status
   if [ $? -eq "0" ] ; then /sbin/service jboss-dc stop;  fi
   
   if [ -n "$PRE_PATCH" ] && [ "$PRE_PATCH"x = "" ];then
      sh $BASE/$PRE_PATCH
   fi
   
   patchRPMS
   patchJbossEar
   patchJbossModule
   patchSystem
   patchScripts
   
   if [ -n "$POST_PATCH" ] && [ "$POST_PATCH"x != "" ];then
      sh $BASE/$POST_PATCH
   fi
   
   /sbin/service jmp-watchdog start
   
   createPatchFile
   
   echo "" >> /etc/.$PATCH_VERSION
   echo "The following rpms installed" >> /etc/.$PATCH_VERSION
   rpmlist=`find $RPMDIR -name *.rpm`
   for rpm in $rpmlist
   do
      basename $rpm >> /etc/.$PATCH_VERSION
   done
}

function parsePatchProperty() {
   if [ -f $PROPERTY_FILE ];then
      while IFS='=' read -r key value ; do
         length=${#key[@]}
         for (( i=0; i<${length}; i++ ));
         do
            # Patch version
            if [ "${key[$i]}" = "patch_version" ]; then
               if [ -n "${value[$i]}" ] && [ "${value[$i]}" != "" ];then
                  PATCH_VERSION="${value[$i]}"
               fi
            fi
            # Space Version
            if [ "${key[$i]}" = "space_version" ]; then
               if [ -n "${value[$i]}" ] && [ "${value[$i]}" != "" ];then
                  SPACE_VERSION="${value[$i]}"
               fi
            fi
            # Pre-Patch Script
            if [ "${key[$i]}" = "pre-patch" ]; then
               if [ -n "${value[$i]}" ] && [ "${value[$i]}" != "" ];then
                  PRE_PATCH="${value[$i]}"
               fi
            fi
            # Post-Patch Script
            if [ "${key[$i]}" = "post-patch" ]; then
               if [ -n "${value[$i]}" ] && [ "${value[$i]}" != "" ];then
                  POST_PATCH="${value[$i]}"
               fi
            fi
         done
      done < $PROPERTY_FILE
   else
      echo "Hot-Patch property file missed"
      exit 1
   fi
}

function createPatchFile() {
   touch /etc/.$PATCH_VERSION
   echo "$PATCH_VERSION" > /etc/.$PATCH_VERSION
   cat $PR_LIST >> /etc/.$PATCH_VERSION
}

function getYN() {
   # return y=0, n=1
   # input=prompt
   read -rsn1 -p "$1 [Y/N] "
   while true; do
      if [ "$REPLY" = "y" -o "$REPLY" = "Y" ]; then
         echo; echo
         return 0
      elif [ "$REPLY" = "n" -o "$REPLY" = "N" ]; then
         echo; echo
         return 1
      fi
      read -rsn1
   done
}

function validateHotPatch() {
   mainversion=`cat /etc/issue | head -1 | awk '{print $3}' | awk -F. '{print $1"."$2}'`
	if [ -e /etc/.$PATCH_VERSION ]; then
      echo "Patch $PATCH_VERSION already installed."
      cat /etc/.$PATCH_VERSION
      exit 1
    fi
    if [ "$mainversion"x != "$SPACE_VERSION"x ]; then
      echo "Patch $PATCH_VERSION can be only installed on $SPACE_VERSION"
      exit 1
   fi
}

parsePatchProperty
validateHotPatch

if [ $# -eq 1 ] && [ $1 = 'LOCAL' ]; then
   patchLocal
elif [ $# -eq 0 ]; then
   patchCluster
elif [ $# -eq 1 ] && [ $1 = 'CLUSTER' ]; then
   patchCluster
else
   echo "usage: patchme.sh [LOCAL|CLUSTER]"
fi
