else
retval=10
fi
#checking one hostid is enough
break;
fi
return $retval
}
#This function is used to kill the user to freeup a mountpoint
#that could be busy and then do the mount operation.
#freeup_busy_mountpoint_and_mount_fs(x, y, z)
# x = Logical volume group to be mounted.
# y = File System where the logical volume is to be mounted.
# z = Mount Options to be used for mount operation
#
function freeup_busy_mountpoint_and_mount_fs
{
typeset vol_to_mount
typeset mount_pt
typeset fs_mount_opt
vol_to_mount=$1
mount_pt=$2
shift 2
fs_mount_opt=$*
print "\tWARNING: Running fuser on ${mount_pt} to remove anyone using the busy mount point directly."
UM_COUNT=0
RET=1
# The control script exits, if the mount failed after
# retrying FS_MOUNT_RETRY_COUNT times.
while (( $UM_COUNT < $FS_MOUNT_RETRY_COUNT && $RET != 0 ))
do
(( UM_COUNT = $UM_COUNT + 1 ))
fuser -kuC ${mount_pt}
if (($UM_COUNT == $FS_MOUNT_RETRY_COUNT))
then
mount ${fs_mount_opt} ${vol_to_mount} ${mount_pt}
test_return 17
if (( $exit_value == 1 ))
then
RET=1
break
fi
else
mount ${fs_mount_opt} ${vol_to_mount} ${mount_pt}
(( RET = $? ))
sleep 1
fi
done
return $RET
}
function check_vxvm_vol_available
{
typeset volpath
volpath=$1
VOL=${volpath##*/}
TMP=${volpath%/*}
DG=${TMP##*/}
vol_kstate=$(vxprint -g $DG -F %kstate $VOL)
TMP=$?
if(( $TMP != 0 ))
then
print "\tERROR: Function check_vxvm_vol_available"
print "\tERROR: vxprint -g $DG -F %kstate $VOL"
print "\tERROR: Failed to get KSTATE for \"${volpath}\" See vxintro(1M) for EXIT CODE of $TMP."
exit_value=1
return 0
fi
if [[ $vol_kstate = "ENABLED" ]]
then
return 0
fi
print "$(date '+%b %e %X') - Node \"$(hostname)\": KSTATE for \"${volpath}\" is ${vol_kstate}."
return 1
}
# For each {file system/logical volume} pair, fsck the file system
# and mount it.
# If the mount point is busy and if FS_MOUNT_RETRY_COUNT = 0,
# mounting of the file system will fail and the control script
# will exit with an error.
#
function check_and_mount
{
integer NOT_READY=1
while (( $NOT_READY != 0 ))
do
NOT_READY=0
integer R=0
for I in ${LV[@]}
do
if [[ $(mount -p | awk '$1 == "'$I'"') = "" ]]
then
case $I in
*/dev/vx/dsk*)
check_vxvm_vol_available $I
if(( $? != 0 ))
then
NOT_READY=1
else
RLV[$R]=$(print $I | sed -e 's/dsk/rdsk/')
fi
;;
*)
RLV[$R]="${I%/*}/r${I##*/}"
;;
esac
(( R = $R + 1 ))
fi
done
if(( $NOT_READY != 0 ))
then
sleep 5
fi
done
# Verify that there is at least one file system to check.
if [[ "$exit_value" != 1 && ${RLV[@]} != "" ]]
then
print -n "$(date '+%b %e %X') - Node \"$(hostname)\": "
print "Checking filesystems:"
print ${LV[@]} | tr ' ' '\012' | sed -e 's/^/ /'
# Perform parallel fsck's for better performance.
# Limit the number of concurrent fsck's to CONCURRENT_FSCK_OPERATIONS
R=0
while (( R < ${#RLV
} ))
do
# Re-create file for storing background pids
> fsck_pids$$
j=0
while (( j < CONCURRENT_FSCK_OPERATIONS && R < ${#RLV
} ))
do
( case ${FS_TYPE[$R]} in
hfs) fsck -F ${FS_TYPE[$R]} ${FS_FSCK_OPT[$R]} -P ${RLV[$R]}
;;
vxfs) fsck -F ${FS_TYPE[$R]} ${FS_FSCK_OPT[$R]} -p -y ${RLV[$R]}
;;
unk*) fsck ${FS_FSCK_OPT[$R]} ${RLV[$R]}
;;
*) if [[ ${FS_TYPE[$R]} = "" ]]
then
fsck ${FS_FSCK_OPT[$R]} ${RLV[$R]}
else
fsck -F ${FS_TYPE[$R]} ${FS_FSCK_OPT[$R]} ${RLV[$R]}
fi
;;
esac ) &
# save the process id for monitoring the status
echo $! >> fsck_pids$$
(( j = j + 1 ))
(( R = R + 1 ))
done
# wait for background fsck's to finish
while read line
do
pid=$(echo $line|awk '{print $1}')
wait $pid
if (( $? != 0 ))
then
let 0
test_return 2
fi
done < fsck_pids$$
rm -f fsck_pids$$
done
# Check exit value (set if any preceeding fsck calls failed)
if (( $exit_value == 1 ))
then
deactivate_volume_group
deactivate_disk_group
print "\n\t########### Node \"$(hostname)\": Package start failed at $(date) ###########"
exit 1
fi
fi
integer F=0
integer j
set -A LogicalVolumes ${LV[@]}
integer L=${#LogicalVolumes
}
while (( F < L ))
do
# Re-create file for storing background pids
> mount_pids$$
j=0
while (( j < CONCURRENT_MOUNT_AND_UMOUNT_OPERATIONS && F < L ))
do
I=${LogicalVolumes[$F]}
if [[ $(mount | grep -e $I" "
= "" ]]
then
print "$(date '+%b %e %X') - Node \"$(hostname)\": Mounting $I at ${FS[$F]}"
case ${FS_TYPE[$F]} in
unk*) # Don't alter fsck/mount options.
;;
*) if [[ ${FS_TYPE[$F]} != "" ]]
then
FS_MOUNT_OPT[$F]="-F ${FS_TYPE[$F]} ${FS_MOUNT_OPT[$F]}"
fi
;;
esac
# Perform parallel file system mounts for better performance.
# Limit the number of parallel mounts to
# CONCURRENT_MOUNT_AND_UMOUNT_OPERATIONS
# if there is permission to kill the user, we can
# run fuser to kill the user, on the mount point.
# This would freeup the mount point, if it is busy
if (( $FS_MOUNT_RETRY_COUNT > 0 ))
then
(
mount ${FS_MOUNT_OPT[$F]} $I ${FS[$F]}
if (( $? != 0 ))
then
freeup_busy_mountpoint_and_mount_fs \
$I ${FS[$F]} ${FS_MOUNT_OPT[$F]}
fi
) &
else
(
mount ${FS_MOUNT_OPT[$F]} $I ${FS[$F]}
) &
fi
# save the process id for monitoring status
echo "$! $I" >> mount_pids$$
else
print "$(date '+%b %e %X') - Node \"$(hostname)\": WARNING: File system \"${FS[$F]}\" was already mounted."
fi
(( j = j + 1 ))
(( F = F + 1 ))
done
# wait for background mounts to finish
while read line
do
pid=$(echo $line|awk '{print $1}')
I="$(echo $line|awk '{print $2}')"
wait $pid
if (( $? != 0 ))
then
let 0
test_return 3
fi
done < mount_pids$$
rm -f mount_pids$$
# Check exit value (set if any preceeding mount calls failed)
if (( $exit_value == 1 ))
then
umount_fs
deactivate_volume_group
deactivate_disk_group
print "\n\t########### Node \"$(hostname)\": Package start failed at $(date) ###########"
exit 1
fi
done
}
function retry_print
{
if [[ $(echo $1 | grep "Retrying"
!= "" ]]
then
print "$1" >> $0.log
fi
}
# For each {IP address/subnet} pair, add the IP address to the subnet
# using cmmodnet(1m).
function add_ip_address
{
integer S=0
integer error=0
for I in ${IP[@]}
do
print "$(date '+%b %e %X') - Node \"$(hostname)\": Adding IP address $I to subnet ${SUBNET[$S]}"
XX=$( cmmodnet -a -i $I ${SUBNET[$S]} 2>&1 )
if (( $? != 0 ))
then
if [[ $(echo $XX | grep "Retried adding IP"
!= "" ]]
then
print "$XX" >> $0.log
(( error = 1 ))
elif [[ $(echo $XX | grep "heartbeat IP"
!= "" ]]
then
# IP has been configured as a heartbeat IP address.
print "$XX" >> $0.log
(( error = 1 ))
else
YY=$( netstat -in | awk '$4 == "'${I}'"')
if [[ -z $YY ]]
then
print "$XX" >> $0.log
print "\tERROR: Failed to add IP $I to subnet ${SUBNET[$S]}"
(( error = 1 ))
else
retry_print "$XX"
print "\tWARNING: IP $I is already configured on the subnet ${SUBNET[$S]}"
fi
fi
else
retry_print "$XX"
fi
(( S = $S + 1 ))
done
if (( error != 0 ))
then
# `let 0` is used to set the value of $? to 1. The function test_return
# requires $? to be set to 1 if it has to print error message.
let 0
test_return 4
fi
}
# Own and reset the DTC connections
function get_ownership_dtc
{
for I in ${DTC_NAME[@]}
do
print "$(date '+%b %e %X') - Node \"$(hostname)\": Assigning Ownership of the DTC $I"
dtcmodifyconfs -o $I
test_return 5
for J in ${IP[@]}
do
print "$(date '+%b %e %X') - Node \"$(hostname)\": Resetting the DTC connections to IP address $J"
dtcdiag -Q $J -q -f $I
test_return 6
done
done
}
# For each {service name/service command string} pair, start the
# service command string at the service name using cmrunserv(1m).
function start_services
{
integer C=0
for I in ${SERVICE_NAME[@]}
do
print "$(date '+%b %e %X') - Node \"$(hostname)\": Starting service $I using"
print " \"${SERVICE_CMD[$C]}\""
#
# Check if cmrunserv should be called the old
# way without a restart count.
#
if [[ "${SERVICE_RESTART[$C]}" = "" ]]
then
cmrunserv $I ">> $0.log 2>&1 ${SERVICE_CMD[$C]}"
else
cmrunserv ${SERVICE_RESTART[$C]} $I ">> $0.log 2>&1 ${SERVICE_CMD[$C]}"
fi
test_return 8
(( C = $C + 1 ))
done
}
# For each {deferred resource name}, start resource monitoring for this
# resource using cmstartres(1m).
function start_resources
{
for I in ${DEFERRED_RESOURCE_NAME[@]}
do
print "$(date '+%b %e %X') - Node \"$(hostname)\": Starting resource monitoring for $I"
cmstartres -u -p $PACKAGE $I >> $0.log 2>&1
test_return 15
done
}
# END OF RUN FUNCTIONS.
# START OF HALT FUNCTIONS
# For each {deferred resource name}, stop resource monitoring for this
# resource using cmstopres(1m).
function stop_resources
{
for I in ${DEFERRED_RESOURCE_NAME[@]}
do
print "$(date '+%b %e %X') - Node \"$(hostname)\": Stopping resource monitoring for $I"
cmstopres -p $PACKAGE $I >> $0.log 2>&1
test_return 16
done
}
# Halt each service using cmhaltserv(1m).
function halt_services
{
for I in ${SERVICE_NAME[@]}
do
print "$(date '+%b %e %X') - Node \"$(hostname)\": Halting service $I"
cmhaltserv $I
test_return 9
done
}
# Disown the DTC.
function disown_dtc
{
for I in ${DTC_NAME[@]}
do
print "$(date '+%b %e %X') - Node \"$(hostname)\": Disowning the DTC $I"
dtcmodifyconfs -d $I
test_return 11
done
}
# For each IP address/subnet pair, remove the IP address from the subnet
# using cmmodnet(1m).
function remove_ip_address
{
integer S=0
integer error=0
for I in ${IP[@]}
do
print "$(date '+%b %e %X') - Node \"$(hostname)\": Remove IP address $I from subnet ${SUBNET[$S]}"
XX=$( cmmodnet -r -i $I ${SUBNET[$S]} 2>&1 )
if (( $? != 0 ))
then
echo $XX | grep "is not configured on the subnet"
if (( $? != 0 ))
then
print "$XX" >> $0.log
(( error = 1 ))
fi
else
retry_print "$XX"
fi
(( S = $S + 1 ))
done
if (( $error != 0 ))
then
# `let 0` is used to set the value of $? to 1. The function test_return
# requires $? to be set to 1 if it has to print error message.
let 0
test_return 12
fi
}
# Unmount each logical volume.
function umount_fs
{
integer UM_CNT=${FS_UMOUNT_COUNT:-1}
integer ret
integer j
set -A LogicalVolumes ${LV[@]}
if [[ $UM_CNT < 1 ]]
then
UM_CNT=1
fi
integer L=${#LogicalVolumes
}
# Perform parallel file system umounts for better performance.
# Limit the number of parallel umounts to CONCURRENT_MOUNT_AND_UMOUNT_OPERATIONS
while (( L > 0 ))
do
# Re-create file for storing background pids
> umount_pids$$
j=0
while (( j < CONCURRENT_MOUNT_AND_UMOUNT_OPERATIONS && L > 0 ))
do
(( L = L - 1 ))
I=${LogicalVolumes[$L]}
mount | grep -e $I" " > /dev/null 2>&1
if (( $? == 0 ))
then
print "$(date '+%b %e %X') - Node \"$(hostname)\": Unmounting filesystem on $I"
(
umount ${FS_UMOUNT_OPT[$L]} $I; ret=$?
if (( ret != 0 ))
then
print "\tWARNING: Running fuser to remove anyone using the file system directly."
fi
UM_COUNT=$UM_CNT
while (( ret != 0 && UM_COUNT > 0 ))
do
fuser -ku $I
umount ${FS_UMOUNT_OPT[$L]} $I; ret=$?
if (( ret != 0 ))
then
(( UM_COUNT = $UM_COUNT - 1 ))
if (( $UM_COUNT > 0 ))
then
print "\t$(date '+%b %e %X') - Unmount $I failed, trying again."
sleep 1
fi
fi
done
return $ret
) &
# save the process id and name of logical volume to be used later
# while checking the exit status
echo "$! $I" >> umount_pids$$
(( j = j + 1 ))
fi
done
# wait for background umount processes to finish
while read line
do
pid=$(echo $line|awk '{print $1}')
I="$(echo $line|awk '{print $2}')"
wait $pid
if (( $? != 0 ))
then
let 0
test_return 13
fi
done < umount_pids$$
rm -f umount_pids$$
done
}
function deactivate_volume_group
{
# Perform multiple volume group deactivations at same time.
# Limit the number of concurrent deactivations to CONCURRENT_VGCHANGE_OPERATIONS
integer index=0
integer j
set -A VGS ${VG[@]}
integer num_vgs=${#VGS
}
while (( index < num_vgs ))
do
# Re-create file for storing background pids
> vgchange_pids$$
j=0
while (( j < CONCURRENT_VGCHANGE_OPERATIONS && index < num_vgs ))
do
I=${VGS[$index]}
print "$(date '+%b %e %X') - Node \"$(hostname)\": Deactivating volume group $I"
(
vgchange -a n $I
) &
# save the process id and name of VG, used while checking the exit status
echo "$! $I" >> vgchange_pids$$
(( j = j + 1 ))
(( index = index + 1 ))
done
# wait for background vg deactivations to finish
while read line
do
pid=$(echo $line|awk '{print $1}')
I="$(echo $line|awk '{print $2}')"
wait $pid
if (( $? != 0 ))
then
let 0
test_return 14
fi
done < vgchange_pids$$
rm -f vgchange_pids$$
done
}
function deactivate_disk_group
{
for I in ${CVM_DG[@]}
do
print "$(date '+%b %e %X') - Node \"$(hostname)\": Deactivating disk group $I"
vxdg -g $I set activation=off
test_return 25
done
# Perform parallel VxVM disk group deports for better performance.
# Limit the number of parallel disk group deports to specified
# CONCURRENT_DISKGROUP_OPERATIONS
integer index=0
integer j
set -A DGS ${VXVM_DG[@]}
integer num_dgs=${#DGS
}
while (( index < num_dgs ))
do
# Re-create file for storing background pids
> vxdg_deport_pids$$
j=0
while (( j < CONCURRENT_DISKGROUP_OPERATIONS && index < num_dgs ))
do
I=${DGS[$index]}
print "$(date '+%b %e %X') - Node \"$(hostname)\": Deporting disk group $I"
( vxdg deport $I ) &
# save the process id and name of DG, used while checking the exit status
echo "$! $I" >> vxdg_deport_pids$$
(( j = j + 1 ))
(( index = index + 1 ))
done
# wait for background vg deactivations to finish
while read line
do
pid=$(echo $line|awk '{print $1}')
I="$(echo $line|awk '{print $2}')"
wait $pid
if (( $? != 0 ))
then
let 0
test_return 26
fi
done < vxdg_deport_pids$$
rm -f vxdg_deport_pids$$
done
}
# END OF HALT FUNCTIONS.
# FUNCTIONS COMMON TO BOTH RUN AND HALT.
# Test return value of functions and exit with NO RESTART if bad.
# Return value of 0 - 50 are reserved for use by Hewlett-Packard.
# System administrators can use numbers above 50 for return values.
function test_return
{
if (( $? != 0 ))
then
case $1 in
1)
print "\tERROR: Function activate_volume_group"
print "\tERROR: Failed to activate $I"
exit_value=1
;;
2)
print "\tERROR: Function check_and_mount"
print "\tERROR: Failed to fsck one of the logical volumes."
exit_value=1
;;
3)
print "\tERROR: Function check_and_mount"
print "\tERROR: Failed to mount $I"
exit_value=1
;;
4)
print "\tERROR: Function add_ip_address"
print "\tERROR: Failed to add IP address to subnet"
remove_ip_address
umount_fs
deactivate_volume_group
deactivate_disk_group
exit 1
;;
5)
print "\tERROR: Function get_ownership_dtc"
print "\tERROR: Failed to own $I"
disown_dtc
remove_ip_address
umount_fs
deactivate_volume_group
deactivate_disk_group
exit 1
;;
6)
print "\tERROR: Function get_ownership_dtc"
print "\tERROR: Failed to switch $I"
disown_dtc
remove_ip_address
umount_fs
deactivate_volume_group
deactivate_disk_group
exit 1
;;
8)
print "\tERROR: Function start_services"
print "\tERROR: Failed to start service ${SERVICE_NAME[$C]}"
halt_services
customer_defined_halt_cmds
disown_dtc
remove_ip_address
umount_fs
deactivate_volume_group
deactivate_disk_group
exit 1
;;
9)
print "\tFunction halt_services"
print "\tWARNING: Failed to halt service $I"
;;
11)
print "\tERROR: Function disown_dtc"
print "\tERROR: Failed to disown $I from ${SUBNET[$S]}"
exit_value=1
;;
12)
print "\tERROR: Function remove_ip_address"
print "\tERROR: Failed to remove $I"
exit_value=1
;;
13)
print "\tERROR: Function umount_fs"
print "\tERROR: Failed to unmount $I"
exit_value=1
;;
14)
print "\tERROR: Function deactivate_volume_group"
print "\tERROR: Failed to deactivate $I"
exit_value=1
;;
15)
print "\tERROR: Function start_resources"
print "\tERROR: Failed to start resource $I"
stop_resources
halt_services
customer_defined_halt_cmds
disown_dtc
remove_ip_address
umount_fs
deactivate_volume_group
deactivate_disk_group
exit 1
;;
16)
print "\tERROR: Function stop_resources"
print "\tERROR: Failed to stop resource $I"
exit_value=1
;;
17)
print "\tERROR: Function freeup_busy_mountpoint_and_mount_fs"
print "\tERROR: Failed to mount $I to ${FS[$F]}"
exit_value=1
;;
21)
print "\tERROR: Function activate_disk_group"
print "\tERROR: Failed to activate $I"
deactivate_volume_group
deactivate_disk_group
exit 1
;;
22)
print "\tERROR: Function check_dg failed"
exit_value=1
;;
23)
print "\tERROR: Function activate_disk_group"
print "\tERROR: Failed to import $I"
exit_value=1
;;
24)
print "\tERROR: Function activate_disk_group"
print "\tERROR: Failed to vxvol -g $I startall"
deactivate_volume_group
deactivate_disk_group
exit 1
;;
25)
print "\tERROR: Function deactivate_disk_group"
print "\tERROR: Failed to deactivate $I"
exit_value=1
;;
26)
print "\tERROR: Function deactivate_disk_group"
print "\tERROR: Failed to deport $I"
exit_value=1
;;
50)
print "\tERROR: Function verify_ha_nfs"
print "\tERROR: Failed to start/stop NFS"
umount_fs
deactivate_volume_group
deactivate_disk_group
exit 1
;;
51)
print "\tERROR: Function customer_defined_run_cmds"
print "\tERROR: Failed to RUN customer commands"
halt_services
customer_defined_halt_cmds
disown_dtc
remove_ip_address
umount_fs
deactivate_volume_group
deactivate_disk_group
exit 1
;;
52)
print "\tERROR: Function customer_defined_halt_cmds"
print "\tERROR: Failed to HALT customer commands"
exit_value=1
;;
*)
print "\tERROR: Failed, unknown error."
;;
esac
fi
}
# END OF FUNCTIONS COMMON TO BOTH RUN AND HALT
#-------------------MAINLINE Control Script Code Starts Here-----------------
#
# FUNCTION STARTUP SECTION.
typeset MIN_VERSION="A.11.13" # Minimum version this control script works on
integer exit_value=0
typeset CUR_VERSION
#
# Check that this control script is being run on a A.10.03 or later release
# of MC/ServiceGuard or ServiceGuard OPS Edition. The control scripts are forward
# compatible but are not backward compatible because newer control
# scripts use commands and option not available on older releases.
CUR_VERSION="$(/usr/bin/what /usr/lbin/cmcld | /usr/bin/grep "Date" | \
/usr/bin/egrep '[AB]\...\...|NTT\...\...' | \
cut -f2 -d" "
"
if [[ "${CUR_VERSION}" = "" ]] || \
[[ "${CUR_VERSION#*.}" < "${MIN_VERSION#*.}" ]]
then
print "ERROR: Mismatched control script version ($MIN_VERSION). You cannot run"
print "\ta version ${MIN_VERSION} control_script on a node running pre"
print "\t${MIN_VERSION} MC/ServiceGuard or ServiceGuard OPS Edition software"
exit 1
fi
# Check that CONCURRENT_VGCHANGE_OPERATIONS is set to >=1.
if (( CONCURRENT_VGCHANGE_OPERATIONS < 1 ))
then
print "\tWARNING: Invalid CONCURRENT_VGCHANGE_OPERATIONS value. Defaulting it to 1."
CONCURRENT_VGCHANGE_OPERATIONS=1
fi
# Check that CONCURRENT_DISKGROUP_OPERATIONS is set to >=1.
if (( CONCURRENT_DISKGROUP_OPERATIONS < 1 ))
then
print "\tWARNING: Invalid CONCURRENT_DISKGROUP_OPERATIONS value. Defaulting it to 1."
CONCURRENT_DISKGROUP_OPERATIONS=1
fi
# Check that CONCURRENT_MOUNT_AND_UMOUNT_OPERATIONS is set to >=1.
if (( CONCURRENT_MOUNT_AND_UMOUNT_OPERATIONS < 1 ))
then
print "\tWARNING: Invalid CONCURRENT_MOUNT_AND_UMOUNT_OPERATIONS value. Defaulting it to 1."
CONCURRENT_MOUNT_AND_UMOUNT_OPERATIONS=1
fi
# Check that CONCURRENT_FSCK_OPERATIONS is set to >=1.
if (( CONCURRENT_FSCK_OPERATIONS < 1 ))
then
print "\tWARNING: Invalid CONCURRENT_FSCK_OPERATIONS value. Defaulting it to 1."
CONCURRENT_FSCK_OPERATIONS=1
fi
# Test to see if we are being called to run the package, or halt the package.
if [[ $1 = "start" ]]
then
print "\n\t########### Node \"$(hostname)\": Starting package at $(date) ###########"
verify_physical_data_replication # add hook for MetroCluster
activate_volume_group
activate_disk_group
check_and_mount
verify_ha_nfs $1 # add hook for NFS
add_ip_address
get_ownership_dtc
customer_defined_run_cmds
start_services
start_resources
# Check exit value
if (( $exit_value == 1 ))
then
print "\n\t########### Node \"$(hostname)\": Package start failed at $(date) ###########"
exit 1
else
print "\n\t########### Node \"$(hostname)\": Package start completed at $(date) ###########"
exit 0
fi
elif [[ $1 = "stop" ]]
then
print "\n\t########### Node \"$(hostname)\": Halting package at $(date) ###########"
stop_resources
halt_services
customer_defined_halt_cmds
disown_dtc
remove_ip_address
verify_ha_nfs $1 # add hook for NFS
umount_fs
deactivate_volume_group
deactivate_disk_group
# Check exit value
if (( $exit_value == 1 ))
then
print "\n\t########### Node \"$(hostname)\": Package halt failed at $(date) ###########"
exit 1
else
print "\n\t########### Node \"$(hostname)\": Package halt completed at $(date) ###########"
exit 0
fi
fi