#!/usr/bin/ksh
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# NWS DataServices within SunCluster reconfiguration script.
#
# Description:
#
# This script is called from /usr/cluster/lib/sc/run_reserve at
# appropriate times to start and stop the NWS DataServices as SunCluster
# disk device groups are brought online or taken offline.
#
# SNDR configuration requires that a resource group to be configured.
# 1. The resource group name should be same as device group name with -stor-rg
# added. e.g. if device group name is abc-dg then resource group name
# would be abc-dg-stor-rg.
# 2. It should have 2 resources in it, unless one of the resource types is the
# SUNW.GeoCtlAVS. One of type SUNW.LogicalHostname and either SUNW.HAStorage
# or SUNW.HAStoragePlus types. Resource type versioning is ignored.
# HAStorage type resource, should have ServicePaths property set to
# device group name. HAStoragePlus type resource, should have either the
# FilesystemMountPoints pointing to a files system associated with the
# device group name, or GlobalDevicePaths property set to device group name.
# LogicalHostname type resource should have a failoverIP address in it and
# it will be used by SNDR to communicate with the secondary side.
#
# As SNDR requires that the LogicalHost (failover) IP address which is a
# part of resource group for SNDR, to be hosted on the same node where the
# device group is, it tries to move the resource group also alongwith the
# device group, in become_primary case of run_reserve script. While
# in primary_to_secondary case, it will try to kill the switchover function
# if it is still running in background, after stopping NWS data services.
#
# Usage:
#
# /usr/cluster/sbin/dscfg_reconfigure { start | stop } diskgroup
#
# Configuration:
#
# Scripts to be run should have been symlinked into $NWS_START_DIR and
# $NWS_STOP_DIR. Note that the scripts are processed in lexical order,
# and that unlike /etc/rc?.d/ there is no leading S or K character.
#
# Exit status:
#
# 0 - success
# 1 - error
#
#
# Global variables
#
# this program
typeset -r ARGV0=$(basename $0)
# directory full of start scripts
typeset -r NWS_START_DIR=/usr/cluster/lib/dscfg/start
# directory full of stop scripts
typeset -r NWS_STOP_DIR=/usr/cluster/lib/dscfg/stop
# the syslog facility to use.
# - conceptually this should be based on the output of
# "scha_cluster_get -O SYSLOG_FACILITY", but that won't work early
# during boot.
typeset -r SYSLOG_FACILITY=daemon
PATH=$PATH:/usr/cluster/bin:/etc
# Variables for retrying scswitch of Resource group for SNDR
retry_num=12
retry_interval=10
rgname=
rgstat=
skip_resource=0
count_LogicalHostname=0
count_HAStoragePlus=0
# Since the switchover of the resource group is called in background,
# the stop action of the reconfig script will kill the background switchover
# if it is running. Since we are stopping the NWS services on the node, there
# is no need to switch the resource group, so it is killed.
# The pid of the process is kept in file /var/run/scnws/$dg.pid.
# Input: dg - device group
# Output: Nothing, kills the process
function kill_scswitch
{
dg=$1
if [ -f /var/run/scnws/$dg.pid ]
then
for i in `cat /var/run/scnws/$dg.pid`
do
pid=$i
kill -9 $pid
done
rm -f /var/run/scnws/$dg.pid
fi
}
# Get the status of the resource group on this node, using scha commands.
# Input: resource group - $1
# Output: Status
function get_rgstat
{
rg=$1
rgstat=`scha_resourcegroup_get -O RG_STATE -G $rg`
}
# This function is called in background from do_scswitch function, to
# switch the resource group to this node, which is becoming primary for
# the diskgroup. If the status of resource group is Offline, it will use
# scswitch command to switch the resource group to this node. If it has
# become Online, cleanup pid file. If it is Pending, the resource group
# is in the state of becoming online, so wait for sometime to become Online..
# scswitch may fail, so the function retries $retry_num times, waiting for
# $retry_interval seconds.
# Input: resource group - $1, Diskgroup/Diskset - $2
# Output: 0 - success, 1 - failure
function switchfunc
{
rg=$1
dg=$2
how_many=0
sleep 2
while [ $how_many != $retry_num ]
do
get_rgstat $rg
case "$rgstat" in
"ONLINE")
rm -f /var/run/scnws/$dg.pid
return 0
;;
"OFFLINE")
logger -p ${SYSLOG_FACILITY}.notice \
-t "NWS.[$ARGV0]" `gettext "scswitch of resource group"` "$rg"
scswitch -z -g $rg -h $(hostname)
retval=$?
if [ $retval != 0 ]
then
sleep $retry_interval
how_many=$(($how_many + 1))
fi
;;
"PENDING_ONLINE")
logger -p ${SYSLOG_FACILITY}.notice \
-t "NWS.[$ARGV0]" `gettext "pending online of resource group"` "$rg"
sleep $retry_interval
how_many=$(($how_many + 1))
;;
*)
logger -p ${SYSLOG_FACILITY}.notice \
-t "NWS.[$ARGV0]" `gettext "Improper resource group status for Remote Mirror"` "$rgstat"
rm -f /var/run/scnws/$dg.pid
return 1
;;
esac
done
logger -p ${SYSLOG_FACILITY}.err \
-t "NWS.[$ARGV0]" "Did not switch resource group for Remote Mirror. System Administrator intervention required"
rm -f /var/run/scnws/$dg.pid
return 1
}
# This function calls switchfunc function in background, to switch the
# resource group for SNDR. It validates the diskgroup/diskset is configured
# for SNDR, checks if the resource group is in Managed state etc.
# If it detects a mis-configuration, it will disable SNDR for the
# device group being processed. This is to prevent cluster hangs and panics.
#
# The ServicePaths extension property of HAStorage type resource or the
# GlobalDevicePaths extension property of HAStoragePlus, both of which
# specify the device group, serve as a link or mapping to retrieve the
# resource group associated with the SNDR configured device group.
# Switchfunc is called in the background to avoid the deadlock situation arising
# out of switchover of resource group from within device group switchover.
#
# In run_reserve context, we are doing the device group switchover, trying to
# bring it online on the node. Device group is not completely switched online,
# until the calling script run_reserve returns. In the process, we are calling
# the associated SNDR resource group switchover using scswitch command.
# Resource group switchover will trigger the switchover of device group also.
#
# If resource group switchover is called in foreground, before the device
# group has become online, then it will result in switching the device group
# again, resulting in deadlock. Resource group can not become online until
# the device group is online and the device group can not become online until the
# script returns, causing this circular dependency resulting in deadlock.
#
# Calling the resource group switch in background allows current run_reserve
# script to return immediately, allowing device group to become online.
# If the device group is already online on the node, then the resource group
# does not cause the device group switchover again.
#
# Input: Device group dg - $1
# Output: 0 - success
# 1 - either dg not applicable for SNDR or error
# 2 - SNDR mis-configuration
function do_scswitch
{
dg=$1
if [ ! -x /usr/cluster/bin/scha_resource_get \
-o ! -x /usr/cluster/bin/scha_resourcegroup_get ]
then
return 1
fi
# hard coded rg name from dg
rgname="$dg-stor-rg"
scha_resourcegroup_get -O rg_description -G $rgname > /dev/null
if [ $? != 0 ]
then
# There is no device group configured in cluster for SNDR with this cluster tag
return 1
fi
# Check the state of resource group
get_rgstat $rgname
if [ -z "$rgstat" \
-o "$rgstat" = "UNMANAGED" -o "$rgstat" = "ERROR_STOP_FAILED" ]
then
logger -p ${SYSLOG_FACILITY}.notice \
-t "NWS.[$ARGV0]" \
`gettext "Improper Remote Mirror resource group state"` "$rgstat"
return 2
fi
# Check whether resources are of proper type and they are enabled
rs_list=`scha_resourcegroup_get -O resource_list -G $rgname`
if [ -z "$rs_list" ]
then
logger -p ${SYSLOG_FACILITY}.notice \
-t "NWS.[$ARGV0]" \
`gettext "No resources in Remote Mirror resource group <$rgname>"`
return 2
fi
for rs in $rs_list
do
rs_type=`scha_resource_get -O type -R $rs -G $rgname | cut -d':' -f1`
case "$rs_type" in
SUNW.LogicalHostname)
rs_enb=`scha_resource_get -O ON_OFF_SWITCH -R $rs -G $rgname`
if [ "$rs_enb" = "ENABLED" ]
then
count_LogicalHostname=$(($count_LogicalHostname + 1))
fi
;;
SUNW.HAStoragePlus)
rs_enb=`scha_resource_get -O ON_OFF_SWITCH -R $rs -G $rgname`
if [ "$rs_enb" = "ENABLED" ]
then
count_HAStoragePlus=$(($count_HAStoragePlus + 1))
fi
;;
esac
done
if [ $count_LogicalHostname -lt 1 ]
then
logger -p ${SYSLOG_FACILITY}.notice \
-t "NWS.[$ARGV0]" `gettext "Missing Enabled Logical Host in resource group <$rgname> for Remote Mirror"`
return 2
elif [ $count_LogicalHostname -gt 1 ]
then
logger -p ${SYSLOG_FACILITY}.notice \
-t "NWS.[$ARGV0]" `gettext "Too Many Enabled Logical Host in resource group <$rgname> for Remote Mirror"`
return 2
fi
if [ $count_HAStoragePlus -lt 1 ]
then
logger -p ${SYSLOG_FACILITY}.notice \
-t "NWS.[$ARGV0]" `gettext "Missing Enabled HAStoragePlus in resource group <$rgname> for Remote Mirror"`
return 2
elif [ $count_HAStoragePlus -gt 1 ]
then
logger -p ${SYSLOG_FACILITY}.notice \
-t "NWS.[$ARGV0]" `gettext "Too Many Enabled HAStoragePlus in resource group <$rgname> for Remote Mirror"`
return 2
fi
# Invoke switchfunc to switch the resource group.
switchfunc $rgname $dg &
pid=$!
mkdir -p /var/run/scnws/
rm -f /var/run/scnws/$dg.pid
echo $pid > /var/run/scnws/$dg.pid
return 0
}
#
# Functions
#
usage()
{
logger -p ${SYSLOG_FACILITY}.err \
-t "NWS.[$ARGV0]" "usage: $ARGV0 { start | stop } diskgroup"
exit 1
}
# Input: arg1) $NWS_START_DIR - location of NWS scripts
# arg2) start / stop
# arg3 ) device group - $2
# arg4) sndr_ena / sndr_dis
# Output: Nothing. Log error if seen
process_dir()
{
typeset dir=$1
typeset arg1=$2
typeset dg=$3
typeset arg2=$4
typeset RDC=$dir/10rdc
if [[ -d $dir ]]
then
for f in $dir/*
do
# process scripts in the directories in lexical order
# note - no leading S or K unlike /etc/rc?.d/
if [ -s $f ] && [ $arg2 != "sndr_dis" ]
then
# run script and pipe output through
# logger into syslog
/usr/bin/ksh $f $arg1 $dg 2>&1 |
logger -p ${SYSLOG_FACILITY}.notice \
-t "NWS.[${ARGV0}:$(basename $f)]"
else
# SNDR misconfigured - prevent start
if [ -s $f ] && [ $f != $RDC ]
then
# run script and pipe output through
# logger into syslog
/usr/bin/ksh $f $arg1 $dg 2>&1 |
logger -p ${SYSLOG_FACILITY}.notice \
-t "NWS.[${ARGV0}:$(basename $f)]"
fi
fi
done
else
logger -p ${SYSLOG_FACILITY}.err \
-t "NWS.[$ARGV0]" "no directory: $dir"
fi
}
#
# main
#
if [ $# -ne 2 ]
then
usage
# not reached
fi
case "$1" in
start)
logger -p ${SYSLOG_FACILITY}.notice -t "NWS.[$ARGV0]" "starting: $ARGV0 $*"
do_scswitch $2
retval=$?
if [ $retval == 2 ]
then
logger -p ${SYSLOG_FACILITY}.err \
-t "NWS.[$ARGV0]" "**FATAL ERROR** Remote Mirror is mis-configured and DISABLED for devicegroup <"$2"> "
# Disable SNDR
process_dir $NWS_START_DIR start "$2" sndr_dis
else
process_dir $NWS_START_DIR start "$2" sndr_ena
fi
;;
stop)
logger -p ${SYSLOG_FACILITY}.notice -t "NWS.[$ARGV0]" "stopping: $ARGV0 $*"
process_dir $NWS_STOP_DIR stop "$2" sndr_ena
kill_scswitch $2
;;
*)
usage
# not reached
;;
esac
logger -p ${SYSLOG_FACILITY}.notice -t "NWS.[$ARGV0]" "completed: $ARGV0 $*"
exit 0