Раздавать SCSI-ID - хостадаптерам старшие (7,6,5...)
ДИскам - поменьше, в порядке убывания приоритета (2,1,15,14,13...)
Название группы: vg[порядковый номер группы][номер стартового узла]
Минор - совпадающий с названием. 0x0[номер группы][номер узла]000
первый разряд - обязан быть 0, второй - у всех должен быть разным
mkdir /dev/vg31
mknod /dev/vg31/group c 64 0x031000
vgcreate /dev/vg31/group /dev/dsk/c1t8d0 /dev/dsk/c1t9d0
Экспорт группы на другой узел кластера
vhchange -a n /dev/vg31 # Отключить, иначе не экспортирует
vgexport -s -p -m /tmp/vg31 /dev/vg31
-s - группа будет shared
-p - preview (оставить оригинал на мете)
-m mapfile
rcp /tmp/vg31 node2:/tmp/vg31
rlogin node2
mkdir /dev/vg31
mknod /dev/vg31/group c 64 0x031000
vgimport -s -m /tmp/vg31 /dev/vg31
vgchange -c y /dev/vg31 # Отдать кластеру
vhchange -a e /dev/vg31 # Активировать vg монопольно
vhchange -a n /dev/vg31 # Отключить
vgchange -c n /dev/vg31 # Забрать у кластера
vhchange -a y /dev/vg31 # Активировать vg немонопольно
Komandy:
/usr/sbin/cm*
Generaciya konfigura
cd /etc/cmcluster
Wpisat' spisok uzlow w fajl
/etc/cmcluster/cmclnodelist
mos032
mos034
klaster
nodes
packages
services - programma, za nalichiem kotoroj klaster sledit.
Perezapuskaet, skol'ko zakazano raz, esli ona umerla -
paketu delaetsya halt, i on restartuetsya na nowom uzle.
Esli w washem pakete net programm, kotorye startuyut w foregraunde,
nado napisat' programmku monitor - kotoraya sama za nimi sledit,
i swom okonchaniembudet goworit' klasteru - paket nado gasit'
/usr/sbin/cmquerycl -C jj -n mos032 -n mos034
# **********************************************************************
# ********* HIGH AVAILABILITY CLUSTER CONFIGURATION FILE ***************
# ***** For complete details about cluster parameters and how to ****
# ***** set them, consult the cmquerycl(1m) manpage or your manual. ****
# **********************************************************************
# Enter a name for this cluster. This name will be used to identify the
# cluster when viewing or manipulating it.
CLUSTER_NAME cluster1
# Cluster Lock Device Parameters. This is the volume group that
# holds the cluster lock which is used to break a cluster formation
# tie. This volume group should not be used by any other cluster
# as cluster lock device.
FIRST_CLUSTER_LOCK_VG /dev/vg03
# Definition of nodes in the cluster.
# Repeat node definitions as necessary for additional nodes.
NODE_NAME mos032
NETWORK_INTERFACE lan0
HEARTBEAT_IP 15.188.208.32
NETWORK_INTERFACE lan1
FIRST_CLUSTER_LOCK_PV /dev/dsk/c1t9d0
# List of serial device file names
# For example:
# SERIAL_DEVICE_FILE /dev/tty0p0
# Possible standby Network Interfaces for lan0: lan1.
NODE_NAME mos034
NETWORK_INTERFACE lan0
HEARTBEAT_IP 15.188.208.34
NETWORK_INTERFACE lan1
FIRST_CLUSTER_LOCK_PV /dev/dsk/c0t9d0
# List of serial device file names
# For example:
# SERIAL_DEVICE_FILE /dev/tty0p0
# Possible standby Network Interfaces for lan0: lan1.
# Cluster Timing Parmeters (microseconds).
HEARTBEAT_INTERVAL 1000000
NODE_TIMEOUT 2000000
# Configuration/Reconfiguration Timing Parameters (microseconds).
AUTO_START_TIMEOUT 600000000
NETWORK_POLLING_INTERVAL 2000000
# Package Configuration Parameters.
# Enter the maximum number of packages which will be configured in the cluster.
# You can not add packages beyond this limit.
# This parameter is required.
MAX_CONFIGURED_PACKAGES 0
# List of cluster aware Volume Groups. These volume groups will
# be used by package applications via the vgchange -a e command.
# For example:
# VOLUME_GROUP /dev/vgdatabase.
# VOLUME_GROUP /dev/vg02.
VOLUME_GROUP /dev/vg03
cmmakepkg -s paket1.sh
cmmakepkg -p paket1.conf
# **********************************************************************
# ****** HIGH AVAILABILITY PACKAGE CONFIGURATION FILE (template) *******
# **********************************************************************
# ******* Note: This file MUST be edited before it can be used. ********
# * For complete details about package parameters and how to set them, *
# * consult the MC/ServiceGuard or MC/LockManager manpages or manuals. *
# **********************************************************************
# Enter a name for this package. This name will be used to identify the
# package when viewing or manipulating it. It must be different from
# the other configured package names.
PACKAGE_NAME
# Enter the failover policy for this package. This policy will be used
# to select an adoptive node whenever the package needs to be started.
# The default policy unless otherwise specified is CONFIGURED_NODE.
# This policy will select nodes in priority order from the list of
# NODE_NAME entries specified below.
#
# The alternative policy is MIN_PACKAGE_NODE. This policy will select
# the node, from the list of NODE_NAME entries below, which is
# running the least number of packages at the time this package needs
# to start.
FAILOVER_POLICY CONFIGURED_NODE
# Enter the failback policy for this package. This policy will be used
# to determine what action to take when a package is not running on
# its primary node and its primary node is capable of running the
# package. The default policy unless otherwise specified is MANUAL.
# The MANUAL policy means no attempt will be made to move the package
# back to its primary node when it is running on an adoptive node.
#
# The alternative policy is AUTOMATIC. This policy will attempt to
# move the package back to its primary node whenever the primary node
# is capable of running the package.
FAILBACK_POLICY MANUAL
# Enter the names of the nodes configured for this package. Repeat
# this line as necessary for additional adoptive nodes.
# Order IS relevant. Put the second Adoptive Node AFTER the first
# one.
# Example : NODE_NAME original_node
# NODE_NAME adoptive_node
NODE_NAME
# Enter the complete path for the run and halt scripts. In most cases
# the run script and halt script specified here will be the same script,
# the package control script generated by the cmmakepkg command. This
# control script handles the run(ning) and halt(ing) of the package.
# If the script has not completed by the specified timeout value,
# it will be terminated. The default for each script timeout is
# NO_TIMEOUT. Adjust the timeouts as necessary to permit full
# execution of each script.
# Note: The HALT_SCRIPT_TIMEOUT should be greater than the sum of
# all SERVICE_HALT_TIMEOUT specified for all services.
RUN_SCRIPT
RUN_SCRIPT_TIMEOUT NO_TIMEOUT
HALT_SCRIPT
HALT_SCRIPT_TIMEOUT NO_TIMEOUT
# Enter the SERVICE_NAME, the SERVICE_FAIL_FAST_ENABLED and the
# SERVICE_HALT_TIMEOUT values for this package. Repeat these
# three lines as necessary for additional service names. All
# service names MUST correspond to the service names used by
# cmrunserv and cmhaltserv commands in the run and halt scripts.
#
# The value for SERVICE_FAIL_FAST_ENABLED can be either YES or
# NO. If set to YES, in the event of a service failure, the
# cluster software will halt the node on which the service is
# running. If SERVICE_FAIL_FAST_ENABLED is not specified, the
# default will be NO.
#
# SERVICE_HALT_TIMEOUT is represented in the number of seconds.
# This timeout is used to determine the length of time (in
# seconds) the cluster software will wait for the service to
# halt before a SIGKILL signal is sent to force the termination
# of the service. In the event of a service halt, the cluster
# software will first send a SIGTERM signal to terminate the
# service. If the service does not halt, after waiting for the
# specified SERVICE_HALT_TIMEOUT, the cluster software will send
# out the SIGKILL signal to the service to force its termination.
# This timeout value should be large enough to allow all cleanup
# processes associated with the service to complete. If the
# SERVICE_HALT_TIMEOUT is not specified, a zero timeout will be
# assumed, meaning the cluster software will not wait at all
# before sending the SIGKILL signal to halt the service.
#
# Example: SERVICE_NAME DB_SERVICE
# SERVICE_FAIL_FAST_ENABLED NO
# SERVICE_HALT_TIMEOUT 300
#
# To configure a service, uncomment the following lines and
# fill in the values for all of the keywords.
#
#SERVICE_NAME
#SERVICE_FAIL_FAST_ENABLED
#SERVICE_HALT_TIMEOUT
# Enter the network subnet name that is to be monitored for this package.
# Repeat this line as necessary for additional subnet names. If any of
# the subnets defined goes down, the package will be switched to another
# node that is configured for this package and has all the defined subnets
# available.
#SUBNET
# The following keywords (RESOURCE_NAME, RESOURCE_POLLING_INTERVAL, and
# RESOURCE_UP_VALUE) are used to specify Package Resource Dependencies. To
# define a Package Resource Dependency, a RESOURCE_NAME line with a fully
# qualified resource path name, and one or more RESOURCE_UP_VALUE lines are
# required. A RESOURCE_POLLING_INTERVAL line (how often in seconds the resource
# is to be monitored) is optional and defaults to 60 seconds. An operator and
# a value are used with RESOURCE_UP_VALUE to define when the resource is to be
# considered up. The operators are =, !=, >, <, >=, and <=, depending on the
# type of value. Values can be string or numeric. If the type is string, then
# only = and != are valid operators. If the string contains whitespace, it
# must be enclosed in quotes. String values are case sensitive. For example,
#
# Resource is up when its value is
# --------------------------------
# RESOURCE_UP_VALUE = UP "UP"
# RESOURCE_UP_VALUE != DOWN Any value except "DOWN"
# RESOURCE_UP_VALUE = "On Course" "On Course"
#
# If the type is numeric, then it can specify a threshold, or a range to
# define a resource up condition. If it is a threshold, then any operator
# may be used. If a range is to be specified, then only > or >= may be used
# for the first operator, and only < or <= may be used for the second operator.
# For example,
# Resource is up when its value is
# --------------------------------
# RESOURCE_UP_VALUE = 5 5 (threshold)
# RESOURCE_UP_VALUE > 5.1 greater than 5.1 (threshold)
# RESOURCE_UP_VALUE > -5 and < 10 between -5 and 10 (range)
#
# Note that "and" is required between the lower limit and upper limit
# when specifying a range. The upper limit must be greater than the lower
# limit. If RESOURCE_UP_VALUE is repeated within a RESOURCE_NAME block, then
# they are inclusively OR'd together. Package Resource Dependencies may be
# defined by repeating the entire RESOURCE_NAME block.
#
# Example : RESOURCE_NAME /net/interfaces/lan/status/lan0
# RESOURCE_POLLING_INTERVAL 120
# RESOURCE_UP_VALUE = RUNNING
# RESOURCE_UP_VALUE = ONLINE
#
# Means that the value of resource /net/interfaces/lan/status/lan0
# will be checked every 120 seconds, and is considered to
# be 'up' when its value is "RUNNING" or "ONLINE".
#
# Uncomment the following lines to specify Package Resource Dependencies.
#
#RESOURCE_NAME
#RESOURCE_POLLING_INTERVAL
#RESOURCE_UP_VALUE [and ]
# The default for PKG_SWITCHING_ENABLED is YES. In the event of a
# failure, this permits the cluster software to transfer the package
# to an adoptive node. Adjust as necessary.
PKG_SWITCHING_ENABLED YES
# The default for NET_SWITCHING_ENABLED is YES. In the event of a
# failure, this permits the cluster software to switch LANs locally
# (transfer to a standby LAN card). Adjust as necessary.
NET_SWITCHING_ENABLED YES
# The default for NODE_FAIL_FAST_ENABLED is NO. If set to YES,
# in the event of a failure, the cluster software will halt the node
# on which the package is running. Adjust as necessary.
NODE_FAIL_FAST_ENABLED NO
cmcheckconf -C jj -P paket1.conf -P paket2.conf
Sozdanie gologo klastera
cmaplyconf -C jj
cmruncl
cmview -v
cmhaltnode mos032
cmrunnode mos032
cmhaltcl
Dobawlenie ili modifikaciya imeyushegosya paketa
cmcheckconf -P paket1.conf
cmaplyconf -P paket1.conf
Ah, da, wse skripty obyazatel'no kopirowat' po wsem uzlam klastera
cmhaltpkg paket1
posle ostanowki paket awtomaticheski disablitsq na uzle, de on umer,
dlq obratnogo enablirowaniq paketa:
cmmodpkg -e paket1
cmmodpkg -n mos032 -e paket1
cmmodpkg -n mos034 -e paket1
cmrunpkg [ -n mos032 ] paket1
Prosmotr statusa klastera
CLUSTER STATUS
karelia up
NODE STATUS STATE
mos031 up running
Network_Parameters:
INTERFACE STATUS PATH NAME
PRIMARY up 8/16/6 lan0
STANDBY up 8/20/5/8 lan1
PACKAGE STATUS STATE PKG_SWITCH NODE
pkg28162 up running enabled mos031
Policy_Parameters:
POLICY_NAME CONFIGURED_VALUE
Failover configured_node
Failback automatic
Script_Parameters:
ITEM STATUS MAX_RESTARTS RESTARTS NAME
Service up 3 0 qwerty
Subnet up 15.188.208.0
Resource up /system/filesystem/availMb/home
Resource up /cluster/localNode/status/karelia
Node_Switching_Parameters:
NODE_TYPE STATUS SWITCHING NAME
Primary up enabled mos031 (current)
Alternate up enabled mos033
NODE STATUS STATE
mos033 up running
Network_Parameters:
INTERFACE STATUS PATH NAME
PRIMARY up 8/16/6 lan0
STANDBY up 8/20/5/8 lan1
PACKAGE STATUS STATE PKG_SWITCH NODE
nc starting starting enabled mos033
Policy_Parameters:
POLICY_NAME CONFIGURED_VALUE
Failover configured_node
Failback automatic
Script_Parameters:
ITEM STATUS MAX_RESTARTS RESTARTS NAME
Service up 0 0 nc
Subnet up 15.188.208.0
Resource up /system/filesystem/availMb/home
Node_Switching_Parameters:
NODE_TYPE STATUS SWITCHING NAME
Primary up enabled mos033 (current)
Alternate up enabled mos031
udalenie paketa
cmdeleteconf -P paket2
/usr/sbin/cmapplyconf /usr/sbin/cmhaltserv /usr/sbin/cmrunnode
/usr/sbin/cmcheckconf /usr/sbin/cmmakepkg /usr/sbin/cmrunpkg
/usr/sbin/cmdeleteconf /usr/sbin/cmmigrate /usr/sbin/cmrunserv
/usr/sbin/cmgetconf /usr/sbin/cmmodnet /usr/sbin/cmscancl
/usr/sbin/cmhaltcl /usr/sbin/cmmodpkg /usr/sbin/cmviewcl
/usr/sbin/cmhaltnode /usr/sbin/cmquerycl /usr/sbin/cmviewconf
/usr/sbin/cmhaltpkg /usr/sbin/cmruncl
Prosmotr debaga
tail -f /var/adm/syslog/syslog.log
tail -f /etc/cmcluster/paket1.sh.log
Obrashenie s resursami:
Prosmotret' spiski dostupnyh resursow
resls /net/interfaces/lan/status
prosmotret' ih znachenie ya ne znayu kak
poluchit' nastoyashie konfigurniki iz klastera
cmgetconf -c cluster_name output_filename
cmgetconf -p package_name output_filename
#"(#) A.11.05 $Revision: 82.3 $ $Date: 98/11/03 10:56:49 $"
# **********************************************************************
# * *
# * HIGH AVAILABILITY PACKAGE CONTROL SCRIPT (template) *
# * *
# * Note: This file MUST be edited before it can be used. *
# * *
# **********************************************************************
# UNCOMMENT the variables as you set them.
# Set PATH to reference the appropriate directories.
PATH=/sbin:/usr/bin:/usr/sbin:/etc:/bin
# VOLUME GROUP ACTIVATION:
# Specify the method of activation for volume groups.
# Leave the default ("VGCHANGE="vgchange -a e") if you want volume
# groups activated in exclusive mode. This assumes the volume groups have
# been initialized with 'vgchange -c y' at the time of creation.
#
# Uncomment the first line (VGCHANGE="vgchange -a e -q n"), and comment
# out the default, if your disks are mirrored on separate physical paths,
#
# Uncomment the second line (VGCHANGE="vgchange -a e -q n -s"), and comment
# out the default, if your disks are mirrored on separate physical paths,
# and you want the mirror resynchronization to ocurr in parallel with
# the package startup.
#
# Uncomment the third line (VGCHANGE="vgchange -a y") if you wish to
# use non-exclusive activation mode. Single node cluster configurations
# must use non-exclusive activation.
#
# VGCHANGE="vgchange -a e -q n"
# VGCHANGE="vgchange -a e -q n -s"
# VGCHANGE="vgchange -a y"
VGCHANGE="vgchange -a e" # Default
# VOLUME GROUPS
# Specify which volume groups are used by this package. Uncomment VG[0]=""
# and fill in the name of your first volume group. You must begin with
# VG[0], and increment the list in sequence.
#
# For example, if this package uses your volume groups vg01 and vg02, enter:
# VG[0]=vg01
# VG[1]=vg02
#
# The volume group activation method is defined above. The filesystems
# associated with these volume groups are specified below.
#
#VG[0]=""
# FILESYSTEMS
# Specify the filesystems which are used by this package. Uncomment
# LV[0]=""; FS[0]=""; FS_MOUNT_OPT[0]="" and fill in the name of your first
# logical volume, filesystem and mount option for the file system. You must
# begin with LV[0], FS[0] and FS_MOUNT_OPT[0] and increment the list in
# sequence.
#
# For example, if this package uses the file systems pkg1a and pkg1b,
# which are mounted on the logical volumes lvol1 and lvol2 with read and
# write options enter:
# LV[0]=/dev/vg01/lvol1; FS[0]=/pkg1a; FS_MOUNT_OPT[0]="-o rw"
# LV[1]=/dev/vg01/lvol2; FS[1]=/pkg1b; FS_MOUNT_OPT[1]="-o rw"
#
# The filesystems are defined as triplets of entries specifying the logical
# volume, the mount point and the mount options for the file system. Each
# filesystem will be fsck'd prior to being mounted. The filesystems will be
# mounted in the order specified during package startup and will be unmounted
# in reverse order during package shutdown. Ensure that volume groups
# referenced by the logical volume definitions below are included in
# volume group definitions above.
#
#LV[0]=""; FS[0]=""; FS_MOUNT_OPT[0]=""
# FILESYSTEM UNMOUNT COUNT
# Specify the number of unmount attempts for each filesystem during package
# shutdown. The default is set to 1.
LV_UMOUNT_COUNT=1
# IP ADDRESSES
# Specify the IP and Subnet address pairs which are used by this package.
# Uncomment IP[0]="" and SUBNET[0]="" and fill in the name of your first
# IP and subnet address. You must begin with IP[0] and SUBNET[0] and
# increment the list in sequence.
#
# For example, if this package uses an IP of 192.10.25.12 and a subnet of
# 192.10.25.0 enter:
# IP[0]=192.10.25.12
# SUBNET[0]=192.10.25.0 # (netmask=255.255.255.0)
#
# Hint: Run "netstat -i" to see the available subnets in the Network field.
#
# IP/Subnet address pairs for each IP address you want to add to a subnet
# interface card. Must be set in pairs, even for IP addresses on the same
# subnet.
#
#IP[0]=""
#SUBNET[0]=""
# SERVICE NAMES AND COMMANDS.
# Specify the service name, command, and restart parameters which are
# used by this package. Uncomment SERVICE_NAME[0]="", SERVICE_CMD[0]="",
# SERVICE_RESTART[0]="" and fill in the name of the first service, command,
# and restart parameters. You must begin with SERVICE_NAME[0], SERVICE_CMD[0],
# and SERVICE_RESTART[0] and increment the list in sequence.
#
# For example:
# SERVICE_NAME[0]=pkg1a
# SERVICE_CMD[0]="/usr/bin/X11/xclock -display 192.10.25.54:0"
# SERVICE_RESTART[0]="" # Will not restart the service.
#
# SERVICE_NAME[1]=pkg1b
# SERVICE_CMD[1]="/usr/bin/X11/xload -display 192.10.25.54:0"
# SERVICE_RESTART[1]="-r 2" # Will restart the service twice.
#
# SERVICE_NAME[2]=pkg1c
# SERVICE_CMD[2]="/usr/sbin/ping"
# SERVICE_RESTART[2]="-R" # Will restart the service an infinite
# number of times.
#
# Note: No environmental variables will be passed to the command, this
# includes the PATH variable. Absolute path names are required for the
# service command definition. Default shell is /usr/bin/sh.
#
#SERVICE_NAME[0]=""
#SERVICE_CMD[0]=""
#SERVICE_RESTART[0]=""
# DTC manager information for each DTC.
# Example: DTC[0]=dtc_20
#DTC_NAME[0]=
# START OF CUSTOMER DEFINED FUNCTIONS
# This function is a place holder for customer define functions.
# You should define all actions you want to happen here, before the service is
# started. You can create as many functions as you need.
function customer_defined_run_cmds
{
# ADD customer defined run commands.
: # do nothing instruction, because a function must contain some command.
test_return 51
}
# This function is a place holder for customer define functions.
# You should define all actions you want to happen here, before the service is
# halted.
function customer_defined_halt_cmds
{
# ADD customer defined halt commands.
: # do nothing instruction, because a function must contain some command.
test_return 52
}
# END OF CUSTOMER DEFINED FUNCTIONS
# START OF RUN FUNCTIONS
function activate_volume_group
{
for I in ${VG[@]}
do
if [[ "${VGCHANGE}" = "vgchange -a y" ]]
then
print "$(date '+%b %e %X') - Node \"$(hostname)\": Activating volume group $I with non-exclusive option."
else
print "$(date '+%b %e %X') - \"$(hostname)\": Activating volume group $I with exclusive option."
fi
$VGCHANGE $I
test_return 1
# If the -s option has been specified, then we perform
# the resynchronization as a background task
#
if [[ ${VGCHANGE#*-s} != ${VGCHANGE} ]]
then
{
if /sbin/vgsync $I
then
print "$(date '+%b %e %X') - Node \"$(hostname)\": Resynchronized volume group $I"
else
print "$(date '+%b %e %X') - Node \"$(hostname)\": Resynchronization of volume group $I encountered an error"
fi
} &
fi
done
}
# For each {file system/logical volume} pair, fsck the file system
# and mount it.
function check_and_mount
{
integer R=0
for I in ${LV[@]}
do
if [[ $(mount -p | awk '$1 == "'$I'"') = "" ]]
then
RLV[$R]="${I%/*}/r${I##*/}"
if [ -x /usr/sbin/fstyp ]
then
fstype[$R]=$(fstyp $I)
fi
(( R = $R + 1 ))
fi
done
# Verify that there is at least one file system to check and what type.
if [[ ${RLV[@]} != "" ]]
then
print -n "$(date '+%b %e %X') - Node \"$(hostname)\": "
print "Checking filesystems:"
print ${LV[@]} | tr ' ' '\012' | sed -e 's/^/ /'
# If there is more than one filesystem type being checked
# then each filesystem is check individually.
#
R=$(print ${fstype[*]} | tr ' ' '\012' | sort -u | wc -l)
if (( R > 1 ))
then
R=0
while (( R < ${#RLV[*]} ))
do
case ${fstype[$R]} in
hfs) fsck -F hfs -P ${RLV[$R]}
test_return 2
;;
vxfs) fsck -F vxfs -y ${RLV[$R]}
test_return 2
;;
unk*) fsck ${RLV[$R]}
test_return 2
;;
*) if [[ ${fstype[$R]} = "" ]]
then
fsck ${RLV[$R]}
else
fsck -F ${fstype[$R]} ${RLV[$R]}
fi
test_return 2
;;
esac
(( R = R + 1 ))
done
# If there is only one filesystem type being checked, then
# multiple invocations of fsck can be avoided. All filesystems
# are specified on the command line to one fsck invocation.
#
else
case ${fstype} in
hfs) fsck -F hfs -P ${RLV[@]}
test_return 2
;;
vxfs) fsck -F vxfs -y ${RLV[@]}
test_return 2
;;
unk*) fsck ${RLV[@]}
test_return 2
;;
*) if [[ ${fstype} = "" ]]
then
fsck ${RLV[@]}
else
fsck -F ${fstype} ${RLV[@]}
fi
test_return 2
;;
esac
fi
fi
integer F=0
for I in ${LV[@]}
do
if [[ $(mount | grep -e $I" ") = "" ]]
then
print "$(date '+%b %e %X') - Node \"$(hostname)\": Mounting $I at ${FS[$F]}"
mount ${FS_MOUNT_OPT[$F]} $I ${FS[$F]}
test_return 3
else
print "$(date '+%b %e %X') - Node \"$(hostname)\": WARNING: File system \"${FS[$F]}\" was already mounted."
fi
(( F = $F + 1 ))
done
}
# 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 "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
print "\tWARNING: IP $I is already configured on the subnet ${SUBNET[$S]}"
fi
fi
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
}
# END OF RUN FUNCTIONS.
# START OF HALT FUNCTIONS
# 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
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=${LV_UMOUNT_COUNT:-1}
if [[ $UM_CNT < 1 ]]
then
UM_CNT=1
fi
for I in $(print ${LV[@]} | awk '{ for(i=NF; i>0; i--) print $i }')
do
mount | grep -e $I" " > /dev/null 2>&1
if (( $? == 0 ))
then
print "$(date '+%b %e %X') - Node \"$(hostname)\": Unmounting filesystem on $I"
print "\tWARNING: Running fuser to remove anyone using the file system directly."
UM_COUNT=$UM_CNT
while (( $UM_COUNT > 0 ))
do
fuser -ku $I
umount $I
if (( $? == 0 ))
then
(( UM_COUNT = 0 ))
else
if (( $UM_COUNT == 1 ))
then
let 0
test_return 13
fi
(( UM_COUNT = $UM_COUNT - 1 ))
sleep 1
if (( $UM_COUNT > 0 ))
then
print "\t$(date '+%b %e %X') - Unmount failed, trying again."
fi
fi
done
fi
done
}
function deactivate_volume_group
{
for I in ${VG[@]}
do
print "$(date '+%b %e %X') - Node \"$(hostname)\": Deactivating volume group $I"
vgchange -a n $I
test_return 14
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"
deactivate_volume_group
exit 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 to ${FS[$F]}"
umount_fs
deactivate_volume_group
exit 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
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
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
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
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
;;
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
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.10.03" # 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 MC/LockManager. 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 MC/LockManager software"
exit 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) ###########"
activate_volume_group
check_and_mount
add_ip_address
get_ownership_dtc
customer_defined_run_cmds
start_services
# 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) ###########"
halt_services
customer_defined_halt_cmds
disown_dtc
remove_ip_address
umount_fs
deactivate_volume_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