#!/bin/ksh # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # bos720 src/bos/usr/lib/nim/methods/swts.sh 1.15 # # Licensed Materials - Property of IBM # # COPYRIGHT International Business Machines Corp. 2006,2011 # All Rights Reserved # # US Government Users Restricted Rights - Use, duplication or # disclosure restricted by GSA ADP Schedule Contract with IBM Corp. # # IBM_PROLOG_END_TAG # @(#)88 1.15 src/bos/usr/lib/nim/methods/swts.sh, cmdnim, bos720 7/14/11 19:58:16 # # COMPONENT_NAME: CMDNIM # # FUNCTIONS: ./usr/lib/nim/methods/swts.sh # # ORIGINS: 27 # NIMPATH=/usr/lpp/bos.sysmgt/nim NIM_METHODS="${NIMPATH}/methods" export NIMPATH NIM_METHODS . ${NIM_METHODS}/c_sh_lib . ${NIM_METHODS}/libcosi # --------------------------- module globals REQUIRED_ATTRS="pull_request" OPTIONAL_ATTRS="verbose" IS_CLIENT="" IS_MASTER="" allow_boot="" cosi="" time="" ARGUMENT="" # --------------------------------------------------------------------------- # # NAME: usage # # FUNCTION: Print usage message # # PARAMETERS: None. # # RETURNS: 0 - successful function execution # --------------------------------------------------------------------------- # function usage { /usr/bin/dspmsg -s ${MSG_SET} cmdnim.cat ${MSG_SWTS_USAGE} \ '%1$s [-c Image] [-n | -t Time] [-v] [ThinServer]\n' "${PROGNAME}" return 0 } # --------------------------------------------------------------------------- # # NAME: ck_attr # # FUNCTION: Check for valid attribute. # # PARAMETERS: None. # # RETURNS: 0 - valid attribute # 1 - invalid attribute # --------------------------------------------------------------------------- # function ck_attr { # Check the following global flag: # ARGUMENT # source # location typeset tserver="" ck_user || return 1 if [[ $(/usr/bin/ps -ef -o args | /usr/bin/grep "nim \\-o swts" >/dev/null 2>&1; echo $?) -eq 0 ]]; then /usr/bin/dspmsg -s ${MSG_SET} cmdnim.cat ${MSG_PLEASE_EXECUTE_CMD} \ 'Please execute the command from %1$s.\n' "${PROGNAME}" return 1 fi if [[ $client_initiated = "yes" ]]; then time="now" thinservers=$ARGUMENT cosi=`/usr/sbin/lsnim -a select $ARGUMENT | /usr/bin/awk '(NR==2) {print $3}'` if [[ $(obj_exist "master" $cosi; echo $?) -ne 0 ]]; then /usr/bin/dspmsg -s ${MSG_SET} cmdnim.cat ${MSG_TS_NOT_SET} \ '%1$s: Thin server \"%2$s\" is not set up to switch common image.\n' "${PROGNAME}" "${thinservers}" return 1 fi elif [[ $IS_MASTER = "yes" ]]; then if [[ -z $cosi ]]; then /usr/bin/dspmsg -s ${MSG_SET} cmdnim.cat ${MSG_COSI_REQUIRED} \ '%1$s: A common image is required.\n' "${PROGNAME}" usage return 1 else if [[ $(obj_exist "master" $cosi; echo $?) -ne 0 ]]; then /usr/bin/dspmsg -s ${MSG_SET} cmdnim.cat ${MSG_CMD_NOT_EXIST} \ '%1$s: \"%2$s\" does not exist.\n' "${PROGNAME}" "${cosi}" return 1 fi fi if [[ -n $ARGUMENT ]]; then # Ensure the clients are diskless/dataless for tserver in $ARGUMENT do if [[ $(obj_exist "master" $tserver; echo $?) -ne 0 ]]; then /usr/bin/dspmsg -s ${MSG_SET} cmdnim.cat ${MSG_CMD_NOT_EXIST} \ '%1$s: \"%2$s\" does not exist.\n' "${PROGNAME}" "${tserver}" return 1 else machine_type=`get_attr_value "master" $tserver "type"` if [[ $machine_type != "diskless" ]] && [[ $machine_type != "dataless" ]]; then /usr/bin/dspmsg -s ${MSG_SET} cmdnim.cat ${MSG_ONLY_SWITCH_TS} \ '%1$s: Only thin server can be switched!\n' "${PROGNAME}" return 1 fi fi done thinservers=$ARGUMENT else return 1 fi if [[ -n $time ]] && [[ -n $allow_boot ]]; then usage return 1 elif [[ -z $time && -z $allow_boot ]]; then time="now" elif [[ -z $time && -n $allow_boot ]]; then time="client" fi ck_cron || return 1 elif [[ $IS_CLIENT = "yes" ]]; then if [[ -n $cosi ]]; then /usr/bin/dspmsg -s ${MSG_SET} cmdnim.cat ${MSG_NO_COSI_ARG} \ '%1$s: Common image argument is not allowed when executed on a thin server.\n' "${PROGNAME}" usage return 1 fi if [[ -n $ARGUMENT ]]; then /usr/bin/dspmsg -s ${MSG_SET} cmdnim.cat ${MSG_NO_THINSERVER_ARG} \ '%1$s: Thin server argument is not allowed when executed on a thin server.\n' "${PROGNAME}" usage return 1 fi if [[ -n $time ]]; then /usr/bin/dspmsg -s ${MSG_SET} cmdnim.cat ${MSG_TIME_ARG_NOT_ALLOWED} \ '%1$s: Time argument is not allowed when executed on a thin server.\n' "${PROGNAME}" usage return 1 fi cosi=`/usr/sbin/nimclient -l -a select $NIM_NAME | /usr/bin/awk '(NR==2) {print $3}'` if [[ $(obj_exist "client" $cosi; echo $?) -ne 0 ]]; then /usr/bin/dspmsg -s ${MSG_SET} cmdnim.cat ${MSG_TS_NOT_SET} \ '%1$s: Thin server \"%2$s\" is not set up to switch common image.\n' "${PROGNAME}" "${NIM_NAME}" return 1 fi time=now thinservers=$NIM_NAME fi return 0 } # --------------------------------------------------------------------------- # # NAME: switch_ts # # FUNCTION: Switch thinserver to new common image. # # PARAMETERS: None. # # RETURNS: 0 - successful # 1 - unsuccessful # --------------------------------------------------------------------------- # function switch_ts { trap "" 2 11 15 typeset -i count=0 typeset -i rc=0 while getopts :T:c:t: option do case $option in T) tserver="${OPTARG}";; c) cosi="${OPTARG}";; t) time="${OPTARG}";; esac done if [[ $client_initiated = "yes" ]]; then switch $tserver $cosi rc=$? elif [[ $IS_MASTER = "yes" ]]; then for ts in $tserver do if [[ $time = "now" ]]; then switch $ts $cosi rc=$? elif [[ "${time}" = "client" ]]; then /usr/lpp/bos.sysmgt/nim/methods/m_chattr -a select=$cosi $ts >/dev/null 2>&1 if [[ $? -ne 0 ]]; then /usr/bin/dspmsg -s ${MSG_SET} cmdnim.cat ${MSG_UNABLE_SET_COSI} \ '%1$s: Unable to set common image %2$s to thinserver %3$s.\n' \ "${PROGNAME}" "${cosi}" "${ts}" return 1 fi else # Add crontab entry echo "/usr/sbin/swts -c $cosi $ts" | /usr/bin/at -t $time > /dev/null 2>&1 if [[ $? -ne 0 ]]; then /usr/bin/dspmsg -s ${MSG_SET} cmdnim.cat ${MSG_UNABLE_ADD_CRON} \ '%1$s: Unable to add cron entry for %2$s.\n' "${PROGNAME}" "${ts}" return 1 fi fi done elif [[ $IS_CLIENT = "yes" ]]; then [[ -s /tmp/__NIM_shutdown ]] && rm_file /tmp/__NIM_shutdown > /dev/null 2>&1 /usr/bin/dspmsg -s ${MSG_SET} cmdnim.cat ${MSG_ROOT_SYNC_DD_CLIENTS_INST} \ '\n Installing software in the root directories of any diskless or dataless\n\ clients served by this SPOT. This may take several minutes ...\n\n' /usr/sbin/nimclient -Fo change -a control=$NIM_NAME /usr/sbin/nimclient -o swts & count=0 rc=1 while [[ $count -lt 80 ]]; do sleep 1 ((count=count+1)) if [[ -s /tmp/__NIM_shutdown ]]; then /usr/bin/dspmsg -s ${MSG_SET} cmdnim.cat ${MSG_DONE} 'done\n' rc=0 break fi done [[ $rc -eq 1 ]] && /usr/bin/dspmsg -s ${MSG_SET} cmdnim.cat ${MSG_FAILED} 'failed\n' fi return $rc } # --------------------------------------------------------------------------- # # NAME: switch # # FUNCTION: Perform actual switch. # # PARAMETERS: None. # # RETURNS: 0 - successful # 1 - unsuccessful # --------------------------------------------------------------------------- # function switch { trap "" 2 11 15 typeset client=$1 typeset cosi=$2 typeset switch_dump="no" typeset backup_res="" typeset common_image="" typeset machine_type="" typeset resource="" typeset server="" typeset type="" typeset dump="" common_image=`get_attr_value "master" $client "spot"` if [[ -z $common_image ]]; then /usr/bin/dspmsg -s ${MSG_SET} cmdnim.cat ${MSG_UNABLE_SWITCH} \ '%1$s: Unable to switch thinserver %2$s because a common image is not allocated.\n' \ "${PROGNAME}" "${client}" return 1 fi res_loc=`get_attr_value "master" $cosi "location"` inst_root_sz=`LANG=C /usr/bin/du -sm "${res_loc}/lpp/bos/inst_root" | /usr/bin/awk '{print $1}'` root_res=`get_attr_value "master" "${client}" "root"` root_loc=`get_attr_value "master" "${root_res}" "location"` fs_info =`LANG=C /usr/bin/df -m ${root_loc} | /usr/bin/awk '(NR==2){print $3":"$7}'` fs_sz=${fs_info%%:*} root_loc=${fs_info##*:} /usr/bin/dspmsg -s ${MSG_SET} cmdnim.cat ${MSG_SPACE_FS} 'Checking %s space requirement...' $root_loc if (( $inst_root_sz > $fs_sz )); then let inst_root_sz="$inst_root_sz - $fs_sz + 10" /usr/sbin/chfs -a size=+${inst_root_sz}M $root_loc if [[ $? -ne 0 ]]; then return 1 fi fi machine_type=`get_attr_value "master" $client "type"` /usr/sbin/lsnim -c resources $client | /usr/bin/grep -v "^boot " | /usr/bin/awk '{print $1":"$2}'> /tmp/swts_$$.txt # Set the bootlist on the diskless/dataless to boot off the net for res_type in `/usr/bin/cat /tmp/swts_$$.txt` do resource=`echo $res_type | /usr/bin/cut -d: -f1` type=`echo $res_type | /usr/bin/cut -d: -f2` if [[ "${type}" != "spot" ]]; then #POC dump if [[ "${type}" == "dump" ]]; then dump_resource=$resource new_dump=dump_${cosi} dumpServer=`get_attr_value "master" $cosi "server"` # If the client's spot server is different than the one it will switch to, # then create the new dump resource on the server to match the spot if [[ $dumpServer != `get_attr_value "master" $common_image "server"` ]]; then # The SPOT location is in the form //usr # This means dumpLocation will need to be at the location. # If not, the dump will not create due to NFS restriction for the SPOT location. dumpLocation=`get_attr_value "master" $cosi "location"` dumpLocation=`dirname $dumpLocation` dumpLocation=`dirname $dumpLocation` switch_dump="yes" if [[ $(obj_exist "master" $new_dump; echo $?) -ne 0 ]]; then define_res dump "$new_dump" $dumpServer $dumpLocation/$new_dump || switch_dump="no" fi fi fi fi if [[ "${type}" = "root" ]] || [[ "${type}" = "tmp" ]] || [[ "${type}" = "home" ]]; then backup_res="$backup_res $resource" fi done backup_client $client $backup_res # Define a clone NIM object of the client client_clone="${client}_CLONE_$$" net_settings=`get_attr_value "master" $client "net_setting1"` comments=`get_attr_value "master" $client "comments"` /usr/sbin/nim -o define -t $machine_type \ -a if1="find_net ${client} 0" -a cable_type1=N/A \ -a netboot_kernel=mp ${net_settings:+-a net_settings1="$net_settings"} \ ${comments:+-a comments="$comments"} ${client_clone} if [[ $(obj_exist "master" $client_clone; echo $?) -ne 0 ]]; then /usr/bin/dspmsg -s ${ERR_SET} cmdnim.cat ${ERR_CANT_DEFINE_OBJ} \ '%1$s: Unable to define %2$s object.\n' "${PROGNAME}" $client_clone undo fi # Allocate the new spot against the clone to add the entry to /etc/exports /usr/sbin/nim -o allocate -a spot=$cosi $client_clone if [[ $? -ne 0 ]]; then /usr/bin/dspmsg -s ${ERR_SET} cmdnim.cat ${ERR_CANNOT_ALLOC} \ '0042-207 %s: Unable to allocate the %s resource to %s.' \ "${PROGNAME}" $cosi $client_clone undo fi /usr/lpp/bos.sysmgt/nim/methods/m_chattr -a spot=$cosi $client || undo /usr/lpp/bos.sysmgt/nim/methods/m_chattr -a spot=$common_image $client_clone || undo client_object_id=`/usr/sbin/lsnim -Fl $client | /usr/bin/egrep "^[ ]+id[ ]+=" | /usr/bin/awk '{print $3}'` common_image_location=`get_attr_value "master" $common_image "location"` cosi_location=`get_attr_value "master" $cosi "location"` if [[ -n $client_object_id ]] && [[ -n $common_image_location ]] && [[ -n $cosi_location ]]; then echo "nim_attr: value=$cosi_location" | \ /usr/bin/odmchange -o nim_attr -q "id=$client_object_id and value=$common_image_location" fi # Remove the boot attribute from the original client. # This will allow the dump resource to be deallocated from the original client and # to re-initialize the original client with the new resources. /usr/lpp/bos.sysmgt/nim/methods/m_chattr -a boot="" $client > /dev/null 2>&1 # POC, to be remove when the dump resource is not tie to the SPOT resource if [[ $switch_dump = "yes" ]]; then # ignore failure because of dump is not crucial for booting thin server /usr/sbin/nim -o deallocate -a dump=$dump_resource $client > /dev/null 2>&1 /usr/sbin/nim -o allocate -a dump=$new_dump $client > /dev/null 2>&1 fi /usr/lpp/bos.sysmgt/nim/methods/m_chattr -a control=master $client > /dev/null 2>&1 # Initialize the clone client. if [[ $machine_type = "diskless" ]]; then /usr/sbin/nim -o dkls_init $client elif [[ $machine_type = "dataless" ]]; then /usr/sbin/nim -o dtls_init $client fi if [[ $? -ne 0 ]]; then # Error would come from dkls_init/dtls_init undo fi if [[ `get_attr_value "master" "$client" "Mstate"` = "currently running" ]]; then if [[ `get_attr_value "master" "$client" "control"` != "master" ]]; then /usr/sbin/nim -Fo change -a control=master $client > /dev/null 2>&1 if [[ $? -ne 0 ]]; then # 0042-001 %s: processing error encountered on "%s": # %s" /usr/bin/dspmsg -s ${ERR_SET} cmdnim.cat ${ERR_METHOD} \ '0042-001 %s: processing error encountered on \"%s\":\n%s' \ "${PROGNAME}" $client "nim -Fo change -a control=master $client" undo fi fi /usr/sbin/nim -o reboot $client if [[ $? -eq 0 ]]; then server=`get_attr_value "master" "$client" "if" | /usr/bin/awk '{print $2}'` while [[ $(/etc/ping -c1 -w1 $server > /dev/null 2>&1; echo $?) -eq 0 ]]; do sleep 1 done fi fi restore_client $r_file # r_file return from backup_client /usr/lpp/bos.sysmgt/nim/methods/m_chattr -a select= $client >/dev/null 2>&1 uninitialize_ts $client_clone rm_nim_obj "$client_clone" rm_file $r_file rm_file /tmp/swts_$$.txt return 0 } # --------------------------------------------------------------------------- # # NAME: undo # # FUNCTION: Perform undo operation. # # PARAMETERS: None. # # RETURNS: 0 - successful # 1 - unsuccessful # --------------------------------------------------------------------------- # function undo { if [[ $(obj_exist "master" $client_clone; echo $?) -ne 0 ]]; then uninitialize_ts $client_clone rm_nim_obj "$client_clone" fi rm_file $r_file rm_file /tmp/swts_$$.txt return 1 } # ----------------------------------- swts ---------------------------------- # # # NAME: swts # # FUNCTION: /usr/sbin/swts command # # NOTES: # # RETURNS: (int) # 0 = SUCCESS # 1 = FAILURE # # --------------------------------------------------------------------------- # trap cleanup 0 trap undo 1 trap 'err_signal' 2 11 15 # NIM initialization nim_init # set parameters from command line while getopts :a:c:nt:v x do case ${x} in a) # Command initated by nimclient. # validate the attr ass parse_attr_ass "${OPTARG}" # include the assignment for use in this environment eval ${variable}=\"${value}\" if [[ $variable = "pull_request" ]]; then client_initiated=yes fi if [[ $variable = "verbose" ]]; then set -x for i in $(typeset +f) do typeset -ft $i done fi ;; c) # Specify to commit cosi=${OPTARG} ;; n) # Specify to remove allow_boot=true ;; t) # Specify the source for creating the common image. time=${OPTARG} ;; v) # verbose mode (for debugging) set -x for i in $(typeset +f) do typeset -ft $i done ;; \?) # unknown option usage exit 1 ;; esac done shift $((OPTIND - 1)) ARGUMENT=$* ck_nim_env_ts || exit 1 ck_attr || exit 1 switch_ts -c $cosi -t "${time}" -T "${thinservers}" rc=$? exit $rc # end of script