#!/bin/sh
#
# aryzhov@spasu.net
# install IBM's cluster-aware middleware into shared disks
#
# First, source the environmend and check if we aren't chrooted yet.
#
[ -z "$SID" ] && SID=/tmp/install_config
[ X$SubrIsRead = XYes ] || . $SID/Scripts/Misc/!Includes/Subroutines
[ X$VarsAreSet = XYes ] || SetJVars
SetRootOpts ; [ X$ROOT != X/ ] && exec Chroot_Script $0 $*

#
# Find the StartStopCheck script
# The $SC_INST_CONFIG_FILE variable, along with some other SC_* variables,
# is exported by SetSunClusterEnv() defined in Subroutines.
#
SC_STARTSTOPCHECK_SCRIPT=`dirname $SC_INST_CONFIG_FILE`/Scripts/StartStopCheck
[ -f $SC_STARTSTOPCHECK_SCRIPT ] || StartShell "Failed to find $SC_STARTSTOPCHECK_SCRIPT"

#
# Destination for Start/Stop/Check script whose full name will appear in
# Start/Stop/Check properties of almost all cluster resources,
# is refined in the text of sript itself. Source and eval it.
#
MyLocation=""
eval `grep '^MyLocation=/' $SC_STARTSTOPCHECK_SCRIPT`
[ x$MyLocation != x ] || StartShell "Failed to determine destination for $SC_STARTSTOPCHECK_SCRIPT"

echo "\n\n\n\n\t=== Configuring IBM Middleware prerequisites ===\n\n\n"

#
# IBM preferes to name the node roles "active/passive", unlike
# Sun, who preferes to name them primary/secondary.
# We shall use both, no confusion expected.
#
case x$SC_NODE_TYPE in
  xPRIMARY)   NODEROLE=active;;
  xSECONDARY) NODEROLE=passive;;
  *) "SC_NODE_TYPE not defined or wrong in cluster configuration"
      ;;
esac

#
# Directory structure for cluster-shared middleware objects is quite tricky.
# Some links cross one, some two directory levels.
# Some start under MQHA, sume in the underlying levels.
# Just be slow here. put StartShell here for debugging, copy-paste
# from the very beginning, and see how the variables look and what's and where
# is really created
#
MQHA_LINK=/MQHA
MQHA_REAL_DIR=/global/MQHA
STAGING_LINK=/opt/staging

DIRS="
  $MQHA_REAL_DIR/DB/db2inst1
  $MQHA_REAL_DIR/MW1/MGENPH1GM1
  $MQHA_REAL_DIR/MW1/MGENPH1BK1
  $MQHA_REAL_DIR/MW2/MGENPH1GM2
  $MQHA_REAL_DIR/MW2/MGENPH1BK2
"

#
# Mount points - the disk names are fake here so far,
# and will be replaced later as hadware gets discovered
#
# The order is important, as we shall substitute
# the disk_names in disk_size descending order,
# i.e. the largest disk will substitute the very first DDD entry
#
MO=logging,nosuid,forcedirectio
vfstab="
  /dev/dsk/DDDs1 /dev/rdsk/DDDs1 $MQHA_REAL_DIR/DB  ufs 3 no $MO
  /dev/dsk/DDDs1 /dev/rdsk/DDDs1 $MQHA_REAL_DIR/MW1 ufs 4 no $MO
  /dev/dsk/DDDs1 /dev/rdsk/DDDs1 $MQHA_REAL_DIR/MW2 ufs 4 no $MO
"

#
# Users
#
passwd="
  mqm:x:1005:100::/export/home/mqm:/bin/ksh
  wbiadmin:x:1117:100:MB User:/export/home/wbiadmin:/bin/ksh
  db2admin:x:1113:113::/export/home/db2admin:/usr/bin/ksh
  db2fenc1:x:1115:115::/export/home/db2fenc1:/usr/bin/sh
  db2inst1:x:1114:114::/export/home/db2inst1:/usr/bin/ksh
"

#
# We must keep wbiadmin's password hash here.
# The corresponding password for DB2 login is defined in IBM's
# middleware media/config directories within $JS_MEDIA_DIR/Packages/IBM
#
shadow="
  mqm:NoP:13377::::::
  wbiadmin:mfreGHLN8.2vc:13377::::::
  db2admin:NoP:13377::::::
  db2fenc1:NoP:13377::::::
  db2inst1:NoP:13377::::::
"

group="
  mqm::100:root,hollingl,acain
  dba::118:wbiadmin
  mqbrkrs::116:mqm,root,wbiadmin,db2inst1,db2fenc1,hollingl
  db2adm1::113:root,db2inst1,db2admin,wbiadmin
  db2fadm1::115:root,db2fenc1
  db2grp1::114:db2adm1,db2admin
"

#
# Add entries to real passwd, groups, shadow,
# and create the home directories.
# Remember, we are in chrooted environment here
#
for f in passwd shadow group ; do
  eval "echo \"\$$f\"" | egrep : | while read line ; do
    name=`echo $line | awk -F: '{print $1}'`
    egrep -s "^$name:" /etc/$f && continue
    echo $line >>/etc/$f
    [ $f = passwd ] && {
      homedir=`echo $line | awk -F: '{print $6}'`
      usergrp=`echo $line | awk -F: '{print $3":"$4}'`
      mkdir -p $homedir
      touch $homedir/.login $homedir/.profile
      chown -R $usergrp $homedir/.
    }
  done
done

#
# Add commands to "wbiadmin" user's shell profile
# to source some env info from "db2inst1" user's home.
# That's why we can not "chmod 700" all these apps homes.
#
WBIHOME=`awk -F: '$1=="wbiadmin" {print $6}' /etc/passwd`
[ x$WBIHOME = x ] && StartShell "No home dir for wbiadmin"
egrep -s mqsiprofile $WBIHOME/.profile 2>/dev/null || echo "#

  . /opt/IBM/mqsi/6.0/bin/mqsiprofile
  . ~db2inst1/sqllib/db2profile
  echo + Currently configured components are:
  mqsilist

#" >>$WBIHOME/.profile || StartShell "Failed to update $WBIHOME/.profile"

chown wbiadmin:mqm $WBIHOME/.profile

#
# Yeah, relax all those guys home dirs modes, otherwise they won't find each other.
#
for i in `echo "$passwd" | awk -F: '{print $6}'`; do
  cd $i || StartShell "Failed to chdir to $i"
  while [ `pwd` != / ]; do chmod u=rwx,go=rx . ..; cd ..; done
done

#
# Create the directory structure on local (non-shared) filesystems
#
cd /
ln -s $MQHA_REAL_DIR/. $MQHA_LINK || StartShell "Failed to create $MQHA_LINK symlink"
for i in $MQHA_REAL_DIR `echo "$vfstab" | awk '{print $3}'`; do
  mkdir -p $i || StartShell "\n\n\tCould not mkdir $i"
done

for i in $DIRS; do
  ln -s $i $MQHA_REAL_DIR/. || StartShell "\n\n\tFailed to create the sublink $i in $MQHA_REAL_DIR/."
done

#
# Find free (not mounted or allocated or metadevices) disks,
# add the vfstab entries and substitute the disk names
#
cp /etc/vfstab /etc/vfstab.pre-`basename $0`
echo "$vfstab" | expand | sed '/^ *$/d;s/^ *//' >>/etc/vfstab

touch /tmp/A.$$

for MP in `echo "$vfstab" | awk '{print $3}'`; do
  #
  # vfstab editing should be done on both nodes
  #
  FindFreeDisk  # Sets LargestDiskName and LargestDiskSize, defined in Subroutines
  MPE=`echo $MP | sed 's:/:\\\/:g'`
  printf "
    g/ $MPE /
    s/\/DDDs/\/${LargestDiskName}s/g
    w
    q
  " | expand | sed 's/^ *//;/^ *$/d' | ed -s /etc/vfstab

  #
  # We need some handshaking method between the nodes,
  # for a primary node to signal that she's done with accessing
  # the shared disks, so the secondary is allowed to mount them.
  #
  # For this, we reserve cylinder #0, and start our filesystems
  # from cylinder #1 only
  #
  # Cylinder 0, offset 8192 will contain the full path to mount pont
  # for a relevant filesystem, terminated with "@" as soon as
  # the primary node unmounts it
  #

  [ x$SC_NODE_TYPE = xPRIMARY ] && {
    #
    # Slice the disk that in this loop is the largest unused disk, using fmthard.
    # We only need Slice 1, and we want to start it from Cylinder 1 (not 0!) till the disk end.
    #
    CSZ=`prtvtoc /dev/rdsk/${LargestDiskName}s2 | awk '$3=="sectors/cylinder" {print $2}'`
    CCN=`expr \( $LargestDiskSize / $CSZ - 1 \) \* $CSZ`
    echo "

      0 0 00 0    0
      1 0 00 $CSZ $CCN
      2 5 01 0    $LargestDiskSize
      3 0 00 0    0
      4 0 00 0    0
      5 0 00 0    0
      6 0 00 0    0
      7 0 00 0    0

    " | sed '/^ *$/d' | fmthard -s - /dev/rdsk/${LargestDiskName}s2 || StartShell "Error formatting $LargestDiskName"
    #
    # Create a normal UFS filesystem on the disk just sliced.
    # It will turn global after reboot only, even though "global" option added to vfstab in this script.
    #
    echo y | newfs /dev/rdsk/${LargestDiskName}s1 || StartShell "Newfs of $LargestDiskName failed"

    #
    # To avoid confusion between character abd block devices, and line up at sector edge,
    # we use an intermediate file in /tmp/ for handshaking tokens.
    # First, test that disk is readable at all, then mark it.
    #
    dd if=/dev/rdsk/${LargestDiskName}s2 bs=1k skip=8 count=1 of=/tmp/A.$$ || StartShell "Failed to dd from $LargestDiskName"
    echo BusyBusyBusyBusyBusy@Busy | dd of=/tmp/A.$$
    while true; do echo BusyBusyBusyBusy@; done | dd of=/tmp/A.$$ bs=1 count=1024
    dd if=/tmp/A.$$ of=/dev/rdsk/${LargestDiskName}s2 bs=1k seek=8 count=1

    mount $MP || StartShell "Failed to mount $MP - check the changes in vfstab"
  }

  [ x$SC_NODE_TYPE = xSECONDARY ] && {
    #
    # Check the handshaking token (containing the mount point's path)
    # that must have been put on this disk by a primary node in the very end of this script
    # Wait if it's not there, or if "Busy" token is there. No timeouts, secondary will wait forever
    # if the primary never does his job.
    #
    MP_IN=BusyBusyBusy
    while [ x$MP_IN != x$MP ]; do
       sleep 300
       MP_IN=`dd if=/dev/rdsk/${LargestDiskName}s2 bs=1k skip=8 count=1 | strings | grep @ | head -1 | sed 's/@.*/'/`
       echo "`date`: Found hanshake label: $MP_IN, waiting for: $MP"
    done
    mount $MP || StartShell "Failed to mount $MP on $SC_NODE_TYPE node"
  }

done #/looping on shared mountpoints

echo "\n\n=== New vfstab entries:\n"
diff /etc/vfstab.pre-`basename $0` /etc/vfstab

[ x$SC_NODE_TYPE = xPRIMARY ] && {
  #
  # Create the directory structure
  #
  for i in $DIRS; do
    mkdir -p /$i/data /$i/log || StartShell "Failed to make subdirs under /$i"
  done
  chown -R mqm:mqm          $MQHA_REAL_DIR/M*/.  || StartShell "Failed to chown  subdirs in $MQHA_REAL_DIR"
  chmod -R u=rwx,og=rx      $MQHA_REAL_DIR/M*/.  || StartShell "Failed to chmod  subdirs in $MQHA_REAL_DIR"
  chown -R db2admin:db2grp1 $MQHA_REAL_DIR/D*/.  || StartShell "Failed to chown  subdirs in $MQHA_REAL_DIR"
  chmod -R ug=rwx,o=rx      $MQHA_REAL_DIR/D*/.  || StartShell "Failed to chmod  subdirs in $MQHA_REAL_DIR"

  #
  # Copy the StartStopCheck script over to the shared media
  # As we don't have a separate LUN for administration CFS,
  # the StartStopCheck script will live on a DB LUN
  #
  mkdir -p $MQHA_REAL_DIR/DB/SC/Scripts || StartShell "Failed to create $MQHA_REAL_DIR/DB/SC/Scripts"
  cp $SC_STARTSTOPCHECK_SCRIPT $MQHA_REAL_DIR/DB/SC/Scripts/. || StartShell "Failed to copy $SC_STARTSTOPCHECK_SCRIPT to the shared area"
  chmod +x $MyLocation
}

mkdir -p `dirname $MyLocation` || StartShell "Failed to create the parent directory for $MyLocation"
ln -s $MQHA_REAL_DIR/DB/SC/Scripts/`basename $SC_STARTSTOPCHECK_SCRIPT` $MyLocation || StartShell "Failed to link $MyLocation"

echo "\n\n=== Installing IBM Middleware components ===\n"

STAGING_DIR=$JS_PKGS_DIR/IBM_Middleware
[ -f $STAGING_DIR/config/system ] || StartShell "No $STAGING_DIR/config/system file"

cp /etc/system /etc/system.pre-`basename $0`
KPARAMS=`awk '$1=="set" {print $2}' $STAGING_DIR/config/system | cut -d= -f1`
#
# Remove the previous occurances of the same parameter settings
#
echo Cleaning up /etc/system...
for i in $KPARAMS; do
  echo "\tOverwriting $i"
  cp /etc/system /tmp/system.$$
  expand /tmp/system.$$ | egrep -iv "^ *set  *$i=|^ *set  *$i " >/etc/system
done
cat $STAGING_DIR/config/system >>/etc/system
ln -s $STAGING_DIR/. $STAGING_LINK || StartShell "Failed to link $STAGING_LINK"

#
# Copy the middleware install & configure scripts to local disks.
# We need /root directory for this
#
[ -d /root/. ] || mkdir /root || StartShell "Failed to chdir/create /root"

cd $STAGING_LINK/scripts || StartShell "No scripts directory in $STAGING_LINK"
echo "\n\n\n\t\t===  Syncing scripts  ===\n\n"; ./syncScripts.ksh
echo "\n\n\n\t\t===  Installing  WMQ  ===\n\n"; ./wmq_install.ksh
echo "\n\n\n\t\t===  Installing  WMB  ===\n\n"; ./wmb_install.ksh
echo "\n\n\n\t\t===  Installing  DB2  ===\n\n"; ./db2_server_install.ksh

#
SC_Append_Hosts
#
# For MW components to the DB at istallation time,
# we need a valid and active (up) IP address.
# The failover address is not available at installation time,
# so we set it to $SC_PRIMARY_NODE_ADDR for the installation time,
# and change back to a failover address as soon as middleware is shut down here.
#
[ x$SC_PRIMARY_NODE_ADDR != x ] || StartShell "Could not resolve $SC_PRIMARY_NODE_NAME via $SC_HOSTS_FILE"
NGDBNAME=ngdbnode
NGDBADDR=`awk '$0~/^[1-9][1-9.]*.*'$NGDBNAME'/ {print $1}' /etc/hosts`
[ x$NGDBADDR != x ] || StartShell "Could not resolve $NGDBNAME via /etc/hosts"
cp /etc/hosts /etc/hosts.pre-MW
printf "g/^$NGDBADDR.*$NGDBNAME/\ns/^$NGDBADDR/$SC_PRIMARY_NODE_ADDR/\nw\nq\n" | ed -s /etc/hosts
echo
diff /etc/hosts.pre-MW /etc/hosts

echo "\n\n=== Configuring the installed middleware for $NODEROLE node ===\n"

cd /root/. || StartShell "No /root/. directoty found"
echo "\n\n\n\t\t===  Configuring DB2  ===\n\n"; ./createDBenvironment.ksh  $NODEROLE
[ x$SC_NODE_TYPE = xSECONDARY ] && {
  #
  # IMPORTANT!!
  #
  # Since MQ and (maybe) MB config scripts from IBM make decision about node role,
  # not only based on ARG1, but also on the fact that /MQHA/* are present or not,
  # we must umount the $MQHA_REAL_DIR here for "passive" node.
  #
  # It has been previosly mounted, in order to satisfy DB2 config on "passive"
  # Lee Holingdale will eventually change the IBM install scripts to avoid this mess.
  #
  for MP in `echo "$vfstab" | awk '{print $3}'`; do
    /sbin/mount | awk '{print $1}' | grep "^$MP$" && { umount $MP || StartShell "Failed to umount $MP"; }
  done
}

echo "\n\n\n\t\t===  Configuring WMQ  ===\n\n";      ./createMQenvironment.ksh  $NODEROLE
echo "\n\n\n\t\t===  Configuring WMB  ===\n\n";      ./createMBenvironment.ksh  $NODEROLE
[  x$SC_NODE_TYPE = xPRIMARY ] && {
  echo "\n\n\n\t\t===  Creating MQ objects ===\n\n";   su - mqm ./createMQobjects.ksh
}


# # # # # # # # # # # # # # #
#
# We must install and configure Oracle here, as it also decides
# whether it's a primary or secondary node, depending on
# whether filesystems are mounted or not
#
echo "\n\n\t===== Installing Oracle Client =====\n"

PKGDIR=$JS_MEDIA_DIR/Packages/Oracle/10g/client
PKGLIST="
  Oracle-sparc-Solaris9
"

MakeAdminFile

for PKG in $PKGLIST; do
  pkginfo -d $PKGDIR $PKG | egrep -s $PKG || StartShell "Package $PKG not found in $PKGDIR"
  pkgadd -nM -a $PKGADMIN_FILE $ROOTOPTS -d $PKGDIR $PKG 2>&1 | grep "Installation of" || StartShell "Installation failed"
done

cd $STAGING_LINK/scripts || StartShell "No scripts directory in $STAGING_LINK"
echo "\n\n\n\t===  Configuring Oracle client  ===\n\n"; ./oracle_setup.ksh  $NODEROLE

#
# Source oracle config from the environ
#
set -x
[ -f $JS_HOST_ENV_FILE ] && . $JS_HOST_ENV_FILE
[ x$ORA_TNSNAMES_FILE != x ] && echo "$ORA_TNSNAMES_DATA" | egrep -is PORT && echo "$ORA_TNSNAMES_DATA" >$ORA_TNSNAMES_FILE
ORA_OWNER=`ls -ld \`dirname $ORA_TNSNAMES_FILE\` | awk '{print $3":"$4}'`
chown $ORA_OWNER $ORA_TNSNAMES_FILE || StartShell "Failed to chown $ORA_TNSNAMES_FILE to $ORA_OWNER"

WBIADMIN_HOME=`awk -F: '$1=="wbiadmin" {print $6}' /etc/passwd`
ORACLE_HOME=`echo $ORA_TNSNAMES_FILE | sed 's:/client/.*$:/client:'`
echo "###

  ORACLE_HOME=$ORACLE_HOME
  PATH=\$PATH:\$ORACLE_HOME/bin
  LD_LIBRARY_PATH=\$LD_LIBRARY_PATH:\$ORACLE_HOME/lib32

  export ORACLE_HOME
  export PATH
  export LD_LIBRARY_PATH

###" >>$WBIADMIN_HOME/.profile

db2inst1_home=`awk -F: '$1=="db2inst1" {print $6}' /etc/passwd`
[ x$db2inst1_home = x ] && StartShell "Wrong home for user db2inst1"

find /opt/IBM/. $db2inst1_home/. -type f | egrep '/db2ckpw$|/db2aud$' | xargs chown root || StartShell "Failed to chown"
find /opt/IBM/. $db2inst1_home/. -type f | egrep '/db2ckpw$|/db2aud$' | xargs chmod 4511 || StartShell "Failed to chmod"
find /opt/IBM/. $db2inst1_home/. -type f | egrep '/db2audit.cfg$'     | xargs chmod  644 || StartShell "Failed to chmod"
find /opt/IBM/. $db2inst1_home/.         | egrep '/db2flacc$'         | xargs chmod 2511 || StartShell "Failed to chmod"

set +x
#
# # # # # # # # # # # # # # #

echo "\n\n\n\t===  Waiting for MW components to complete the bootstrap ===\n"; sleep 15
echo "\n\n\n\t===  Stopping the MW components  ===\n\n"

RUNNING_MQBROKERS=`ps -eflo user,args | awk '$1=="wbiadmin" && $2~/bipservice/ {print $3}' | sort -u`
[ `echo $RUNNING_MQBROKERS | wc -w`  -gt 0 ] && su - wbiadmin -c "
  /bin/sh -c \"for m in `echo $RUNNING_MQBROKERS`; do mqsistop \\\$m; sleep 5; done\"
"

RUNNING_MQMGRS=`ps -eflo user,args | awk '$1=="mqm" && $3=="-m" {print $4}' | sort -u`
[ `echo $RUNNING_MQMGRS | wc -w`  -gt 0 ] && su - mqm -c "
  /bin/ksh -c \"
    cd
    . ./environment.ksh
    for m in `echo $RUNNING_MQMGRS`; do endmqm -w \\\$m; sleep 5; done
  \"
"

su - db2inst1 -c db2stop

echo "\n\n\n\t===  Waiting for MW components to complete the shutdown ===\n"; sleep 15
[ `ps -eflo user= | awk '$1!="root"' | wc -l` -gt 0 ] && StartShell "\n\n\n\t\tLeftover processes persist\n\n"

#
# Put the original NGDB address back to /etc/hosts
#
cp /etc/hosts /etc/hosts.post-MW
printf "g/^$SC_PRIMARY_NODE_ADDR.*$NGDBNAME/\ns/^$SC_PRIMARY_NODE_ADDR/$NGDBADDR/\nw\nq\n" | ed -s /etc/hosts
echo
diff /etc/hosts.post-MW /etc/hosts

echo === Unmounting shared filesystems ===
cd /
for MP in `echo "$vfstab" | awk '{print $3}'`; do
  /sbin/mount | awk '{print $1}' | grep "^$MP$" && { umount $MP || StartShell "Failed to umount $MP"; }
  [ x$SC_NODE_TYPE = xPRIMARY ] && {
    #
    # Release the disk and make it available for use by the secondary node,
    # putting the mountpoint path, instead of "BysyBusy..." token
    #
    CurrentDiskName=`awk '$3=="'$MP'" {print $1}' /etc/vfstab | awk -F/ '{print $NF}' | awk -Fs '{print $1}'`
    while true; do echo ${MP}@; done | dd of=/tmp/A.$$ bs=1 count=1024
    dd if=/tmp/A.$$ of=/dev/rdsk/${CurrentDiskName}s2 bs=1k seek=8 count=1
  }
done

