mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-10-26 08:55:24 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1552 lines
		
	
	
		
			51 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1552 lines
		
	
	
		
			51 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
| #!/bin/bash
 | |
| #
 | |
| # Usage:
 | |
| #
 | |
| # There are utils for diskdiscover and configraid.
 | |
| #
 | |
| 
 | |
| log_file=$1
 | |
| 
 | |
| ##############################
 | |
| # declare all commands
 | |
| ##############################
 | |
| awk="awk"
 | |
| sed="sed"
 | |
| cut="cut"
 | |
| sleep="sleep"
 | |
| sort="sort"
 | |
| ps="ps"
 | |
| head="head"
 | |
| readlink="readlink"
 | |
| basename="basename"
 | |
| udevadm="udevadm"
 | |
| touch="touch"
 | |
| tail="tail"
 | |
| dmesg="dmesg"
 | |
| grep="grep"
 | |
| lspci="lspci"
 | |
| 
 | |
| ############################################
 | |
| #
 | |
| # source raidcmd
 | |
| #
 | |
| ###########################################
 | |
| str_dir_name=`dirname $0`
 | |
| . $str_dir_name/raidcmd
 | |
| 
 | |
| ################################################################
 | |
| #
 | |
| #  Input PCI_ID to get PCI location
 | |
| #
 | |
| #  input: pci_id
 | |
| #
 | |
| #  output: pci locations 
 | |
| #
 | |
| ################################################################
 | |
| function get_pciloc_by_id {
 | |
|     local __in_pciid=$1
 | |
|     if echo "$__in_pciid" | $grep -sq "_"; then
 | |
|         __in_pciid=`echo "$__in_pciid" | $sed -e 's/_/:/'`
 | |
|     fi
 | |
|     local sysdevdir=/sys/bus/pci/devices
 | |
|     local pcilocs=`cd $sysdevdir 2>/dev/null && for dev in *
 | |
|     do
 | |
|         lines=$($udevadm info --query=property --path=$sysdevdir/$dev)
 | |
|         if echo "$lines" | $grep -i -sq -E "^PCI_ID=$__in_pciid$|^PCI_SUBSYS_ID=$__in_pciid$"; then
 | |
|             echo $dev
 | |
|         fi
 | |
|     done `
 | |
|     [ -z "$pcilocs" ] && return 1
 | |
|     echo "$pcilocs"
 | |
|     return 0
 | |
| }
 | |
| 
 | |
| ######################################################
 | |
| #
 | |
| # get pci_slot scsi device
 | |
| #
 | |
| # input: slocs, for example, 0:0:0:0 0:0:1:0
 | |
| #
 | |
| # output: <sloc>=<device_name> ... 
 | |
| #         <sloc>=<device_name>
 | |
| #
 | |
| ######################################################
 | |
| function convert_sloc_to_sg {
 | |
|     local __slocs="$*"
 | |
|     for __sloc in $__slocs
 | |
|     do
 | |
|         if echo "$__sloc" | grep -sq "[0-9]\+:[0-9]\+:[0-9]\+:[0-9]\+"; then
 | |
|             __sg=`$readlink /sys/class/scsi_device/$__sloc/device/generic`
 | |
|             if [ "$__sg" ]; then
 | |
|                 __sg=`$basename $__sg`
 | |
|             fi
 | |
|         elif echo "$__sloc" | grep -sq -E '^sg[0-9]+|^sd[a-z]+'; then
 | |
|             __sg="$__sloc"
 | |
|             __sloc=`convert_sg_to_sloc $__sg | $awk -F= '{print $2}'`
 | |
|         fi
 | |
|         echo "$__sloc=$__sg"
 | |
|     done
 | |
|     return 0
 | |
| }
 | |
| 
 | |
| #################################################################
 | |
| #
 | |
| #  Through PCI/SCSI device to find PCI/SCSI location
 | |
| #
 | |
| #  input: device names, 
 | |
| #         sg0 ...sgn
 | |
| #
 | |
| #  output: <dev>=<sloc>... <dev>=<sloc>
 | |
| #
 | |
| ################################################################
 | |
| function convert_sg_to_sloc {
 | |
|     local __sgs="$*"
 | |
|     local __sloc=""
 | |
|     for __sg in $__sgs
 | |
|     do
 | |
|         if echo "$__sg" | grep -sq "^sg[0-9]\+"; then
 | |
|             __sloc=`$readlink /sys/class/scsi_generic/$__sg/device`
 | |
|             if [ "$__sloc" ]; then
 | |
|                 __sloc=`$basename $__sloc`
 | |
|             fi
 | |
|         elif echo "$__sg" | grep -sq "^sd[a-z]\+"; then
 | |
|             __sloc=`$readlink /sys/block/$__sg/device`
 | |
|             if [ "$__sloc" ]; then
 | |
|                 __sloc=`$basename $__sloc`
 | |
|             fi
 | |
|         elif echo "$__sg" | grep -sq "[0-9]\+:[0-9]\+:[0-9]\+:[0-9]\+"; then
 | |
|             __sloc="$__sg"
 | |
|             __sg=`convert_sloc_to_sg $__sloc | $awk -F= '{print $2}'`
 | |
|         fi
 | |
|         echo "$__sg=$__sloc"
 | |
|     done
 | |
|     return 0
 | |
| }
 | |
| 
 | |
| ############################################################################
 | |
| #
 | |
| # get devices which are qualified to be used to create raid
 | |
| # it should equals to "query-raid-create" after all array had
 | |
| # been deleted.
 | |
| # Note: output format of this command is multilines
 | |
| # <pciloc_of_ioa1>=<sloc_of_disk1>,<sloc_of_disk2>,...
 | |
| # <pciloc_of_ioa2>=<sloc_of_disk1>,<sloc_of_disk2>,...
 | |
| # ...
 | |
| ###########################################################################
 | |
| function get_raid_create_devices_by_pciloc {
 | |
|     local lines=""
 | |
|     local pcilocs="$*"
 | |
|     [ -z "$pcilocs" ] && return 1
 | |
| 
 | |
|     # reorder ipr ioa pcilocs by its Primary and Secondary state
 | |
|     local ioas=`get_ipr_ioas_by_pciloc $pcilocs`
 | |
|     pcilocs=`get_sg_pciloc $ioas | $awk -F= '{print $2}' `
 | |
|     lines=`cmd_show_config`
 | |
|     local slocs=""
 | |
|     local line=""
 | |
|     for pciloc in $pcilocs
 | |
|     do
 | |
|         # exclude:
 | |
|         # 1) scsi adapter(ioa);
 | |
|         # 2) scsi enclosure;
 | |
|         # 3) disk array;
 | |
|         slocs=`echo "$lines" \
 | |
|         | grep '^.*[ ]\+'$pciloc'\/[0-9]\+:[0-9]\+:[0-9]\+:[0-9]\+.*$' \
 | |
|         | grep -v -E "Adapter|Enclosure|Disk Array" \
 | |
|         | cut_sloc_from_iprconfig_line \
 | |
|         | $sort -V \
 | |
|         | $sed -e 's/ /,/g' \
 | |
|         | awk '{printf (NR>1)?","$0:$0}'`
 | |
|         if [ -n "$slocs" ]; then
 | |
|             line="$pciloc=$slocs"
 | |
|             echo "$line"
 | |
|         fi
 | |
|     done
 | |
|     return 0
 | |
| }
 | |
| 
 | |
| ########################################################################################
 | |
| #
 | |
| # return list of ioas on target pciloc with order of Primary --> Secondary --> Others
 | |
| #
 | |
| # input: pci locations
 | |
| # 
 | |
| # output: sorted raid adapters location list
 | |
| #
 | |
| #########################################################################################
 | |
| function get_ipr_ioas_by_pciloc {
 | |
|     local pcilocs="$*"
 | |
|     [ -z "$pcilocs" ] && return 1
 | |
| 
 | |
|     # find out all ioas and its current adapter state
 | |
|     local ioas_all=`cmd_show_ioas | grep "^sg[0-9]\+.*Operational" | $awk '{print $1}'`
 | |
|     # group them into "Primary" and "Secondary" groups
 | |
|     local lines=`for ioa in $ioas_all
 | |
|     do
 | |
|         state=$(cmd_show_details $ioa | grep "Current Dual Adapter State" | $sed -e 's/^.* : \+\(.*\)$/\1/')
 | |
|         echo "$state=$ioa"
 | |
|     done`
 | |
|     local ioa_primary=`echo "$lines" | $awk -F= '($1 == "Primary") {print $2}'`
 | |
|     local ioa_secondary=`echo "$lines" | $awk -F= '($1 == "Secondary") {print $2}'`
 | |
|     local ioa_others=`echo "$lines" | $awk -F= '($1 != "Primary") && ($1 != "Secondary") {print $2}'`
 | |
|     ioas_all="$ioa_primary $ioa_secondary $ioa_others"
 | |
| 
 | |
|     # pick up ioa on target pciloc
 | |
|     lines=`echo "$pcilocs" | $sed -e 's/[, ]/\n/g'`
 | |
|     local ioas_in=""
 | |
|     if [ "$lines" = "all" ]; then
 | |
|         ioas_in="$ioas_all"
 | |
|     else
 | |
|         ioas_in=`for ioa in $ioas_all
 | |
|         do
 | |
|             ioa_pciloc=$(get_sg_pciloc $ioa | awk -F= '{print $2}')
 | |
|             if echo "$lines" | grep -sq -i "^${ioa_pciloc}$"; then
 | |
|                 echo $ioa
 | |
|             fi
 | |
|         done `
 | |
|     fi
 | |
|     [ -z "$ioas_in" ] && return 1
 | |
|     echo "$ioas_in"
 | |
|     return 0
 | |
| }
 | |
| 
 | |
| ###############################################
 | |
| #
 | |
| # use udev to determine pciloc of sg device
 | |
| #
 | |
| # input: disk name list
 | |
| #
 | |
| # output: <dev>=<sloc>...<dev>=<sloc>
 | |
| #
 | |
| ###############################################
 | |
| function get_sg_pciloc {
 | |
|     local sgs="$*"
 | |
|     [ -z "$sgs" ] && return 1
 | |
| 
 | |
|     local sg=""
 | |
|     local pciloc=""
 | |
|     for item in $sgs
 | |
|     do
 | |
|         sg=`convert_sloc_to_sg $item | $awk -F= '{print $2}'`
 | |
|         [ -z "$sg" ] && continue
 | |
|         pciloc=`cmd_show_details $sg \
 | |
|                 | grep "^PCI Address" \
 | |
|                 | $sed -e 's/.*:[ ]\+\([0-9]\+:[0-9]\+:[0-9]\+\.[0-9]\+\).*$/\1/'`
 | |
| 
 | |
|         if [ -n "$pciloc" ]; then
 | |
|             echo "$sg=$pciloc"
 | |
|         fi
 | |
|     done
 | |
|     return 0
 | |
| }
 | |
| 
 | |
| ######################################################
 | |
| #
 | |
| # cut resouce_path
 | |
| #
 | |
| #####################################################
 | |
| function cut_sloc_from_iprconfig_line {
 | |
|     $sed -e 's/^.*[ ]\+\(.*\)\/\([0-9]\+:[0-9]\+:[0-9]\+:[0-9]\+\).*$/\2/g'
 | |
| }
 | |
| 
 | |
| #####################################################################
 | |
| #
 | |
| # find descriptions and status for device
 | |
| #
 | |
| # input: pci locations
 | |
| #
 | |
| # output:  descriptions and status from "iprconfig -c show-config" 
 | |
| #
 | |
| ###################################################################
 | |
| function find_desc_status_sg {
 | |
|     local lines=""
 | |
|     local pciscsilocs="$*"
 | |
|     [ -z "$pciscsilocs" ] && return 1
 | |
| 
 | |
|     lines=`cmd_show_config`
 | |
|     local slocs=""
 | |
|     local line=""
 | |
|     for pciscsiloc in $pciscsilocs
 | |
|     do
 | |
|         slocs=`echo "$lines" \
 | |
|         | $grep "${pciscsilocs}" \
 | |
|         | awk '{for(i=3;i<=NF;++i) printf $i "\t";printf "\n"}'`
 | |
|         echo $slocs
 | |
|     done
 | |
|     return 0
 | |
|     
 | |
| }
 | |
| 
 | |
| #######################################################
 | |
| #
 | |
| #  get disk devices through pci_id
 | |
| #
 | |
| #  input: pci id
 | |
| #
 | |
| #######################################################
 | |
| function get_devices_by_pciid {
 | |
| 
 | |
|     local pciid="$*"
 | |
|     [ -z "$pciid" ] && return 1
 | |
| 
 | |
|     pcilocs=`get_pciloc_by_id $pciid`
 | |
| 
 | |
| 
 | |
|     if [ -z "$pcilocs" ]; then
 | |
|         echo "There is no PCI_SLOT_NAME for PCI_ID:$pciid."
 | |
|         return 1
 | |
|     fi
 | |
|     slocs_grps=`get_raid_create_devices_by_pciloc $pcilocs`
 | |
|     if [ -z "$slocs_grps" ]; then
 | |
|         echo "Could not find any disk on target pciloc ${pcilocs}!"
 | |
|         return 1
 | |
|     fi
 | |
|     arrage_output $pciid "$slocs_grps"
 | |
| 
 | |
| }
 | |
| 
 | |
| ######################################################################
 | |
| #
 | |
| # get ipr raid arrays by PCI location
 | |
| #
 | |
| # input: pci locations
 | |
| #
 | |
| # output: raid arrays
 | |
| #
 | |
| #####################################################################
 | |
| function get_ipr_arrays_by_pciloc {
 | |
|     local pcilocs="$*"
 | |
|     [ -z "$pcilocs" ] && return 1
 | |
| 
 | |
|     # reorder ipr ioa pcilocs by its Primary and Secondary state
 | |
|     local ioas=`get_ipr_ioas_by_pciloc $pcilocs`
 | |
|     pcilocs=`get_sg_pciloc $ioas | $awk -F= '{print $2}' `
 | |
| 
 | |
|     local lines=$(cmd_show_arrays)
 | |
|     local slocs=`for pciloc in $pcilocs
 | |
|     do
 | |
|         echo "$lines" 
 | |
|     done `
 | |
|     [ -n "$slocs" ] && echo "$slocs"
 | |
|     return 0
 | |
| }
 | |
| 
 | |
| #####################################################################
 | |
| #
 | |
| # get all af and jbod disks 
 | |
| #
 | |
| # input: no
 | |
| #
 | |
| # output: all devices table
 | |
| #
 | |
| ####################################################################
 | |
| function get_all_devices_for_raid {
 | |
| 
 | |
|     local showlines=`cmd_show_config`
 | |
| 
 | |
|     pcilocs=`echo "$showlines" \
 | |
|              | $grep -v -E "Adapter|Enclosure|Disk Array" \
 | |
|              | $grep '^.*[ ]\+\(.*\)\/\([0-9]\+:[0-9]\+:[0-9]\+:[0-9]\+\).*$'|$sed 's/ /,/g'|cut -c 8-19`
 | |
| 
 | |
|     [ -z "$pcilocs" ] && return 1
 | |
|     slocs_grps=`get_raid_create_devices_by_pciloc $pcilocs`
 | |
|     if [ -z "$slocs_grps" ]; then
 | |
|         echo "Could not find any disk on target pciloc ${pcilocs}!"
 | |
|     fi
 | |
|     arrage_output "null" "$slocs_grps"
 | |
| }
 | |
| 
 | |
| #####################################################################
 | |
| #
 | |
| # output of disks and arrays
 | |
| #
 | |
| # input: pci_id sloc_grps
 | |
| #
 | |
| # output: all devices table
 | |
| #
 | |
| ####################################################################
 | |
| function arrage_output {
 | |
|     pciid=$1
 | |
|     shift
 | |
|     slocs_grps=$*
 | |
| 
 | |
|     # find the required member disks
 | |
|     echo "--------------------------------------------------------------------------"
 | |
|     echo "PCI_ID     PCI_SLOT_NAME  Resource_Path  Device  Description   Status"
 | |
|     echo "------     -------------  -------------  ------  -----------   ----------------"
 | |
|     slocs=""
 | |
|     for item in $slocs_grps
 | |
|     do
 | |
|          pciloc=`echo "$item" | $awk -F= '{print $1}'`
 | |
|          slocs_grp=`echo "$item" | $awk -F= '{print $2;}'i \
 | |
|                                  | $sed 's/,/ /g'`
 | |
| 
 | |
|          if [ x$pciid == "xnull" ]; then
 | |
|              pciid=`get_PCI_ID $pciloc`
 | |
|          fi
 | |
|          for sloc in $slocs_grp
 | |
|          do
 | |
|               pciscsiloc="$pciloc/$sloc"
 | |
|               desc=`find_desc_status_sg $pciscsiloc`
 | |
|               disk=`convert_sloc_to_sg $sloc | $awk -F= '{print $2}'`
 | |
|               echo "$pciid  $pciloc   $sloc        $disk     $desc "
 | |
|          done
 | |
|          echo "-------------------------------------------------------------------"
 | |
|          echo "Get ipr RAID arrays by PCI_SLOT_NAME: $pciloc"
 | |
|          echo "-------------------------------------------------------------------"
 | |
|          get_ipr_arrays_by_pciloc $pciloc
 | |
|     done
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| ###############################################################
 | |
| #
 | |
| # get PCI_ID through lspci
 | |
| #
 | |
| # input: pci location
 | |
| #
 | |
| # output: pci id
 | |
| #
 | |
| ###############################################################
 | |
| function get_PCI_ID {
 | |
|     pcislot=$1
 | |
|     pciid=`$lspci | $grep ${pcislot} | $awk '{print $5}'`
 | |
|     echo $pciid
 | |
| }
 | |
| 
 | |
| ###########################################
 | |
| #
 | |
| # Identify if sloc is exist or not
 | |
| #
 | |
| # input: dev sloc
 | |
| #
 | |
| # output: 0  exist
 | |
| #         1  not
 | |
| # 
 | |
| ##########################################
 | |
| function sloc_exist {
 | |
|     local __sloc="$1"
 | |
|     __sloc=`convert_sg_to_sloc $__sloc | $awk -F= '{print $2}'`
 | |
|     rc=1
 | |
|     [ -n "$__sloc" ] && [ -d /sys/class/scsi_device/$__sloc/device ] && rc=0
 | |
|     return $rc
 | |
| }
 | |
| 
 | |
| ###########################################
 | |
| #
 | |
| # get all raid arrays
 | |
| #
 | |
| # output : array1#array2..
 | |
| #
 | |
| ##########################################
 | |
| function get_all_raid_arrays {
 | |
|     local arrays=`cmd_show_arrays \
 | |
|                   | $awk '{print $1}'\
 | |
|                   | $sed -n '3,$p'`
 | |
|     echo $arrays
 | |
| }
 | |
| 
 | |
| #################################################
 | |
| #
 | |
| # Identify if sloc is raid or not
 | |
| #
 | |
| # input : dev sloc
 | |
| #
 | |
| # return : 1  ------not raid
 | |
| #          0  ------is raid
 | |
| #
 | |
| ##################################################
 | |
| function is_ipr_array {
 | |
|     local __sloc="$1"
 | |
|     local __sg=`convert_sloc_to_sg $__sloc | $awk -F= '{print $2}'`
 | |
|     [ -n "$__sg" ] && is_array $__sg
 | |
| }
 | |
| 
 | |
| #################################################
 | |
| #
 | |
| # get all ioas
 | |
| #
 | |
| ##################################################
 | |
| function get_ipr_ioas {
 | |
|     get_ipr_ioas_by_pciloc all
 | |
| }
 | |
| 
 | |
| #################################################
 | |
| #
 | |
| # cut pci location from iprconfig line
 | |
| #
 | |
| ##################################################
 | |
| function cut_pciloc_from_iprconfig_line {
 | |
|     $sed -e 's/^.*[ ]\+\(.*\)\/\([0-9]\+:[0-9]\+:[0-9]\+:[0-9]\+\).*$/\1/g'
 | |
| }
 | |
| 
 | |
| ##############################################
 | |
| #
 | |
| # get member disk for ipr array
 | |
| #
 | |
| # input : array name
 | |
| #
 | |
| # output : member sloc list
 | |
| #          "member_sloc1 member_sloc2 ...." 
 | |
| #
 | |
| #############################################
 | |
| function get_ipr_array_members {
 | |
|     local array="$1"
 | |
|     local array_sloc=`convert_sg_to_sloc $array | $awk -F= '{print $2}'`
 | |
|     # array does not exist, error with rc=1
 | |
|     [ -z "$array_sloc" ] && return 1
 | |
| 
 | |
|     local lines=`cmd_show_config`
 | |
|     # get scsi locations of disk array members
 | |
|     local member_slocs=`echo "$lines" \
 | |
|     | $awk '
 | |
|     BEGIN { hit=0; members=""; }
 | |
|     /^.*\/'$array_sloc'[ ]+.*Disk Array.*$/ { hit=1; next; }
 | |
|     {
 | |
|         if (hit==1) {
 | |
|             if ($0 ~ /RAID .* Member/) {
 | |
|                 # ignore "Remote" array members
 | |
|                 if ($0 !~ / *Remote *$/) {
 | |
|                     print $0
 | |
|                 }
 | |
|             } else {
 | |
|                 hit=0
 | |
|             }
 | |
|         }
 | |
|     }' \
 | |
|     | cut_sloc_from_iprconfig_line `
 | |
|     # array does not have any member which should not, error with rc=1
 | |
|     [ -z "$member_slocs" ] && return 1
 | |
| 
 | |
|     echo "$member_slocs"
 | |
|     log_details "array[$array] has member disks[$member_slocs]" >&2
 | |
|     return 0
 | |
| }
 | |
| 
 | |
| #####################################################################
 | |
| #
 | |
| # get array by disk
 | |
| #
 | |
| # input : array disk member name
 | |
| #
 | |
| # output : array sloc
 | |
| #
 | |
| ###################################################################
 | |
| function get_ipr_array_by_member {
 | |
|     local sg="$1"
 | |
|     local member_sloc=`convert_sg_to_sloc $sg | $awk -F= '{print $2}'`
 | |
|     # member does not exists, error with rc=1
 | |
|     [ -z "$member_sloc" ] && return 1
 | |
| 
 | |
|     local lines=`cmd_show_config`
 | |
|     local array_sloc=`echo "$lines" \
 | |
|     | $awk '
 | |
|     BEGIN { hit=0; line="na"; }
 | |
|     /Disk Array/ { hit=1; line=$0; next; }
 | |
|     {
 | |
|         if (hit==1) {
 | |
|             if ($0 ~ /RAID .* Member/) {
 | |
|                 if ($0 ~ /\/'$member_sloc'[ ]+.*/) {
 | |
|                     print line
 | |
|                     exit 0
 | |
|                 }
 | |
|             } else {
 | |
|               hit=0; line="na"
 | |
|             }
 | |
|         }
 | |
|     }' \
 | |
|     | cut_sloc_from_iprconfig_line`
 | |
|     # disk does not belongs to any array, error with rc=1
 | |
|     [ -z "$array_sloc" ] && return 1
 | |
| 
 | |
|     echo "$array_sloc"
 | |
|     log_details "array[$array_sloc] owns disk[$sg]" >&2
 | |
|     return 0
 | |
| }
 | |
| 
 | |
| #################################################
 | |
| #
 | |
| # get process
 | |
| # input : pids
 | |
| # output : child_pids pids
 | |
| #
 | |
| ##################################################
 | |
| function getpstree {
 | |
|     local pids="$*"
 | |
| 
 | |
|     local pslines=`$ps -e -o pid,ppid`
 | |
|     while true
 | |
|     do
 | |
|         local has_expand=0
 | |
|         local lines=`echo "$pids" | $sed -e 's/ /\n/g'`
 | |
|         for pid in $pids
 | |
|         do
 | |
|             local child_pids=`echo "$pslines" | $awk -v pid=$pid '$2 == pid{print $1}'`
 | |
|             child_pids=`for pid2 in $child_pids
 | |
|             do
 | |
|                 echo "$lines" | grep -sq "^$pid2$" || echo "$pid2"
 | |
|             done `
 | |
|             if [ -n "$child_pids" ]; then
 | |
|                 pids="$child_pids $pids"
 | |
|                 has_expand=1
 | |
|             fi
 | |
|         done
 | |
|         if [ $has_expand -eq 0 ]; then
 | |
|             break
 | |
|         fi
 | |
|     done
 | |
|     echo "$pids"
 | |
| }
 | |
| 
 | |
| #####################################################################
 | |
| #
 | |
| # delete used disks from slocs
 | |
| #
 | |
| # input : disk slocs
 | |
| #
 | |
| # output : unused disk slocs
 | |
| #
 | |
| ###################################################################
 | |
| function delete_disks_belong_array_from_slocs {
 | |
|     local slocs=$*
 | |
|     validslocs=""
 | |
|     usedslocs=""
 | |
|     for sloc in $slocs
 | |
|     do
 | |
|         line=$(get_ipr_array_by_member $sloc)
 | |
|         if [ $? -eq 0 ]; then
 | |
|             if [ "x$usedslocs" != x ]; then
 | |
|                 usedslocs=$usedslocs" "$sloc
 | |
|             else
 | |
|                 usedslocs=$sloc
 | |
|             fi
 | |
|         fi
 | |
|     done
 | |
|     if [ -n "$usedslocs" ]; then
 | |
|         validslocs=`echo $slocs|sed "s/$usedslocs//g"`
 | |
|         if [ -n "$validslocs" ]; then
 | |
|             echo $validslocs
 | |
|         fi
 | |
|     else
 | |
|         echo $slocs
 | |
|     fi
 | |
| }
 | |
| 
 | |
| ####################################################################################
 | |
| #
 | |
| # create raid array
 | |
| #
 | |
| # input : $1 minutes,
 | |
| #            Times to wait for the raid creation finish, minutes
 | |
| #
 | |
| #         $2 seconds
 | |
| #            Interval of minitoring raid creation, status check
 | |
| #
 | |
| #         left: member disks , iprconfig_args
 | |
| #
 | |
| # output : 
 | |
| #
 | |
| ################################################################################
 | |
| function create_ipr_array {
 | |
|     local global_rc=0
 | |
|     local lines=""
 | |
|     local monCnt=$1
 | |
|     shift
 | |
|     local monInt=$1
 | |
|     shift
 | |
|     local member_sgs=`echo "$1" | $sed -e 's/,/ /g'`
 | |
|     shift
 | |
| 
 | |
|     local stage_1_timeout=1        # unit minutes
 | |
|     local stage_1_last_tick_count=`$awk -v monInt=$monInt -v timeout=$stage_1_timeout 'END{print timeout*60/monInt}' </dev/null`
 | |
| 
 | |
|     [ -z "$member_sgs" ] && return 1
 | |
|     local member_slocs=`convert_sg_to_sloc $member_sgs | $awk -F= '{print $2}' `
 | |
|     local member_sgs=`convert_sloc_to_sg $member_sgs | $awk -F= '{print $2}' `
 | |
|     [ -z "$member_sgs" ] && return 1
 | |
| 
 | |
|     local iprconfig_args="$*"
 | |
|     # log for details
 | |
|     {
 | |
|         echo "Attempt to create ipr array with command: iprconfig -c raid-create \"$iprconfig_args\" \"$member_sgs\""
 | |
|         for member_sg in $member_sgs
 | |
|         do
 | |
|             echo "-------------------------------------"
 | |
|             cmd_show_details $member_sg | $sed -e 's/^/details['$member_sg']: >> /g'
 | |
|         done
 | |
|         echo "-------------------------------------"
 | |
|         for member_sg in $member_sgs
 | |
|         do
 | |
|             cmd_show_status $member_sg | $sed -e 's/^/status['$member_sg']: >> /g'
 | |
|         done
 | |
|         echo "-------------------------------------"
 | |
|     } | log_lines details >&2
 | |
| 
 | |
|     # prepare tmp log file for iprconfig worker process
 | |
|     local ftmp="/tmp/log_create.log.$$"
 | |
|     $touch $ftmp
 | |
| 
 | |
|     # launch the iprconfig worker process
 | |
|     cmd_raid_create "$iprconfig_args" "$member_sgs" >$ftmp 2>&1 &
 | |
|     local pid_create=$!
 | |
|     # log for debug
 | |
|     local line=`$ps -f -p $pid_create | $awk -v pid=$pid_create '$2==pid{print $0}' | $head -n1`
 | |
|     log_details "ps1: $line"
 | |
| 
 | |
|     # monitor the worker process and show status
 | |
|     # array_stage=0, monitor array member disk states only
 | |
|     # array_stage=1, wait for array showes up after array member disks are in termination states
 | |
|     # array_stage=2, monitor array state
 | |
|     local array_stage=0
 | |
|     local array_sloc=""
 | |
|     # is that possible sg names of member disks were changed after issued raid-create on top of them?
 | |
|     local slocs="$member_slocs"
 | |
|     local i=$monCnt
 | |
|     while [ $i -gt 0 -a $monCnt -gt 0 ];
 | |
|     do
 | |
|         # Get status of all sgs which might include array itself.
 | |
|         local status_lines=""
 | |
|         local rc=0
 | |
|         local sloc=""
 | |
|         [ $array_stage -ne 1 ] && \
 | |
|         for sloc in $slocs
 | |
|         do
 | |
|             local status=""
 | |
|             local sg=`convert_sloc_to_sg $sloc | $awk -F= '{print $2}'`
 | |
|             if [ -n "$sg" ]; then
 | |
|                 status=`cmd_show_status $sg `
 | |
|             else
 | |
|                 status="Missing-sg_name"
 | |
|             fi
 | |
|             [ -z "$status" ] && status="no_status"
 | |
| 
 | |
|             local msg="status[$sloc/$sg]=\"$status\""
 | |
|             log_details "array create stage[$array_stage], $msg"
 | |
| 
 | |
|             # list of "termination" status for member disks and target array
 | |
|             # Refer to "Disk array states" section in ipr doc.
 | |
|             local status_exp
 | |
|             if [ $array_stage -eq 0 -o $array_stage -eq 1 ]; then
 | |
|                 # 1) If a physical disk fail to be formated as IPR AF, its status will be "Format Required" and be "Failed" later.
 | |
|                 # Should we handle this?
 | |
|                 status_exp="Active|Failed|Offline|Missing|R/W Protected|Format Required"
 | |
| 
 | |
|                 # I saw phy disk in following state which not in the doc.
 | |
|                 status_exp+="|Optimized|Non-Optimized"
 | |
| 
 | |
|                 # my faked status for disk
 | |
|                 status_exp+="|Missing-sg_name"
 | |
|             else
 | |
|                 # Note:
 | |
|                 # - Array state "Missing" is not a terminate state, exclude it by adding "#" as prefix
 | |
|                 status_exp="Optimized|Active|Non-Optimized|Degraded|#Missing|Offline|Failed|R/W Protected|Rebuilding"
 | |
|             fi
 | |
|             # if not "termination" status, we record it and wait for next cycle.
 | |
|             if ! echo "$status" | grep -i -sq -E "$status_exp"; then
 | |
|                 # aggregate status messages.
 | |
|                 [ -n "$status_lines" ] && status_lines+=","
 | |
|                 status_lines+="$msg"
 | |
|                 rc=1
 | |
|             fi
 | |
|         done
 | |
|         # if all terminated, we fall back to check staus of array itself
 | |
|         if [ $rc -eq 0 ]; then
 | |
|             if [ $array_stage -eq 2 ]; then
 | |
|                 log_info "Create array($array_sg=$array_sloc) successfully on top of disks: $member_slocs."
 | |
|                 break
 | |
|             else # end if stage == 2
 | |
|                 if [ $array_stage -eq 0 ]; then
 | |
|                     # since all disks were in termination states, let's move to stage 2
 | |
|                     # to wait for array to be created and start rebuild.
 | |
|                     #
 | |
|                     # It's possible that such array could not be created for some critical
 | |
|                     # error, such in-sufficient disks for required raid level.
 | |
|                     #
 | |
|                     # Though there was smart way to handle this, here I only use a simple way
 | |
|                     # by waiting for a fixed time(1 minute) before return error.
 | |
|                     log_details "array create stage[1], entered, after finished formatting member disks $slocs"
 | |
|                     lines=`{ cmd_show_config; cmd_show_alt_config; } | $sed -e 's/^/[0-->1] >> /g'`
 | |
|                     log_lines details "$lines"
 | |
|                     ((array_stage=1))
 | |
|                     ((stage_1_last_tick_count=i-stage_1_last_tick_count))
 | |
|                 fi
 | |
|                 # IPR might had problem if some disks failed to response.
 | |
|                 # These disks will disapear in the system with sloc and sg were all gone.
 | |
|                 # in these case, we drop these disks in the operation and abort the operation
 | |
|                 # if all member disks were gone.
 | |
|                 local slocs_new=""
 | |
|                 local __tmp_item=""
 | |
|                 for __tmp_item in $slocs
 | |
|                 do
 | |
|                     if sloc_exist $__tmp_item; then
 | |
|                         [ -n "$slocs_new" ] && slocs_new+=" "
 | |
|                         slocs_new+="$__tmp_item"
 | |
|                     else
 | |
|                         log_error "$i: disk $__tmp_item disapear..."
 | |
|                     fi
 | |
|                 done
 | |
|                 if [ -n "$slocs_new" ]; then
 | |
|                     slocs="$slocs_new"
 | |
|                 else
 | |
|                     global_rc=1
 | |
|                     log_error "All array member disks, $member_slocs, were gone, abort!"
 | |
|                     break
 | |
|                 fi
 | |
|                 # get array owner of each member sg
 | |
|                 local array_slocs=`for __tmp_item in $slocs
 | |
|                 do
 | |
|                     local sg_owner_sloc=$(get_ipr_array_by_member $__tmp_item)
 | |
|                     [ -n "$sg_owner_sloc" ] && echo "$sg_owner_sloc"
 | |
|                 done \
 | |
|                 | $sort -u -V `
 | |
|                 # we only allow one unique array owns all member disks.
 | |
|                 # or, we we need to break out?
 | |
|                 local array_cnt=`echo "$array_slocs" | $awk 'END {print NF; exit 0;}'`
 | |
|                 log_details "All \"$array_cnt\" array(es), \"$array_slocs\", contain target disks, \"$slocs\"." >&2
 | |
|                 if [ $array_cnt -gt 0 ]; then
 | |
| 
 | |
|                     array_sloc=`echo "$array_slocs" | $awk '{print $1}'`
 | |
|                     local array_sg=`convert_sloc_to_sg $array_sloc | $awk -F= '{print $2}'`
 | |
|                     if [ -n "$array_sg" ]; then
 | |
|                         log_details "array create stage[2], entered, after array show up with sg name $array_sg and sloc $array_sloc" >&2
 | |
|                         array_stage=2
 | |
|                         slocs="$array_sloc"
 | |
|                     else
 | |
|                         log_warn "$i: >> Why new array $array_sloc($array_slocs) does not have a valid sg name?" >&2
 | |
|                         log_warn "$i: >> Let wait for a while to see if it could show up or not until tick count equals to $stage_1_last_tick_count" >&2
 | |
|                     fi
 | |
|                 elif [ $array_stage -eq 1 -a $i -lt $stage_1_last_tick_count ]; then
 | |
|                     log_error "Fail to wait array($array_slocs) showes up after its member disks, $member_slocs, were finished formatting." >&2
 | |
|                     # log for debug
 | |
|                     lines=`{
 | |
|                         echo "$i: Current IPR configuration";
 | |
|                         {
 | |
|                             cmd_show_config;
 | |
|                             cmd_show_alt_config;
 | |
|                         } | $sed -e 's/^/'$i': >> /g';
 | |
|                     }`
 | |
|                     log_lines details "$lines"
 | |
| 
 | |
|                     global_rc=2
 | |
|                     break
 | |
|                 else
 | |
|                     # see if we need to issue the raid-create again.
 | |
|                     # for some reason, previous raid-create might be terminated unexpectedly with disks
 | |
|                     # actually had been formated for raid and ready to be used. So, we try to issue
 | |
|                     # the raid-create command again to see if that would help. This usually happened when
 | |
|                     # some failures when formtting physical disks to ipr AF. In that situation, iprconfig
 | |
|                     # might abort without have array created after it had actually formatted those disks.
 | |
|                     local pid_create_still_alive=0
 | |
|                     local pid_create_cur=`getpstree $pid_create`
 | |
|                     local pid_cur
 | |
|                     for pid_cur in $pid_create_cur
 | |
|                     do
 | |
|                         if $kill -0 $pid_cur 2>/dev/null; then
 | |
|                             pid_create_still_alive=1
 | |
|                             break
 | |
|                         fi
 | |
|                     done
 | |
|                     if [ $pid_create_still_alive -eq 0 ]; then
 | |
|                         log_info "$i: disks $slocs had finished formatting, but array was not shown up, and iprconfig process($pid_create) had terminated."
 | |
| 
 | |
|                         log_details "$i: Last several raid-create output:"
 | |
|                         lines=`$tail -n10 $ftmp | $sed -e 's/^/'$i': >> /g'`
 | |
|                         log_lines details "$lines"
 | |
|                         # launch the iprconfig worker process again
 | |
|                         member_sgs=`convert_sloc_to_sg $member_slocs | $awk -F= '{print $2}'`
 | |
|                         if [ -n "$member_sgs" ]; then
 | |
|                             $iprconfig -c raid-create $iprconfig_args $member_sgs >$ftmp 2>&1 &
 | |
|                             pid_create=$!
 | |
| 
 | |
|                             log_info "$i: Restart \"iprconfig -c raid-create $iprconfig_args $member_sgs\" with new pid $pid_create." >&2
 | |
| 
 | |
|                             # log for debug
 | |
|                             local line=`$ps -f -p $pid_create | $awk -v pid=$pid_create '$2==pid{print $0}' | $head -n1`
 | |
|                             if [ -n "$line" ]; then
 | |
|                                 log_details "ps1.2: $line" >&2
 | |
|                             else
 | |
|                                 log_error "ps1.2: new iprconfig($pid_create) was gone" >&2
 | |
|                             fi
 | |
|                         else
 | |
|                             log_warn "$i: Fail to restart iprconfig since $member_slocs could not be mapped to sg." >&2
 | |
|                             log_warn "$i: Let try again next loop until tick count equals to $stage_1_last_tick_count" >&2
 | |
|                         fi
 | |
|                     else
 | |
|                         log_warn "$i: Wait for array($array_slocs) showes up after disk format were finished on $slocs until tick count equals to $stage_1_last_tick_count" >&2
 | |
|                         log_details "$i: Last several raid-create output:" >&2
 | |
|                         lines=`$tail -n2 $ftmp | $sed -e 's/^/'$i': >> /g'`
 | |
|                         log_info debug "$lines" >&2
 | |
|                     fi
 | |
|                 fi
 | |
|             fi # end else if stage == 2
 | |
|         fi # end if $rc eq 0
 | |
| 
 | |
|         # log status for monitor
 | |
|         # log for debug
 | |
|         if [ -n "$status_lines" ]; then
 | |
|             log_status "Creating IPR array with last info at time \""`date "+%Y-%m-%d %H:%M:%S"`"\": $status_lines" >&2
 | |
|             lines=`echo "$status_lines" | $sed -e 's/,/\n/g' | $sed -e "s/^/$i: >> /g"`
 | |
|             log_lines details "$lines" >&2
 | |
|         fi
 | |
| 
 | |
|         $sleep $monInt
 | |
|         [ $monCnt -gt 0 ] && ((i-=1))
 | |
|     done
 | |
| 
 | |
|     # log for debug
 | |
|     line=`$ps -f -p $pid_create | $awk -v pid=$pid_create '$2==pid{print $0}' | $head -n1`
 | |
|     [ -n "$line" ] && log_details "ps2: $line"
 | |
|     if $kill -0 $pid_create 2>/dev/null; then
 | |
|         # If succ out, array status should in "rebuilding" state while iprconfig is still running
 | |
|         # until the rebuild had finished. But we do not need to wait for its termination since the
 | |
|         # block device is actually ready to use though performance might be downgrade.
 | |
|         # so, by default, we will just kill the "iprconfig" command(? not sure if that would affect
 | |
|         # the rebuild or not) and let raid controller do its job at backend.
 | |
|         # in order to wait for the whole rebuilding, set IPR_REBUILD_WAIT=true explicitly.
 | |
|         if [ "x$IPR_REBUILD_WAIT" = "xtrue" -a $i -gt 0 ]; then
 | |
|             log_info "Wait for ipr raid creation command to finish. pid=$pid_create" >&2
 | |
|             wait $pid_create
 | |
|         else
 | |
|             log_warn "Terminate ipr raid creation process enforcely. pid=$pid_create" >&2
 | |
|             $kill -TERM $pid_create 2>/dev/null
 | |
|             $sleep 1
 | |
|             $kill -0 $pid_create 2>/dev/null \
 | |
|             && $kill -KILL $pid_create 2>/dev/null
 | |
|         fi
 | |
|     fi
 | |
|     # log for debug
 | |
|     line=`$ps -f -p $pid_create | $awk -v pid=$pid_create '$2==pid{print $0}' | $head -n1`
 | |
|     [ -n "$line" ] && log_details "ps3: $line" >&2
 | |
| 
 | |
|     log_details "Last several raid-create output:" >&2
 | |
|     lines=`$tail -n10 $ftmp | sed -e 's/^/[last]: >> /g'`
 | |
|     log_lines details "$lines" >&2
 | |
|     rm -f $ftmp
 | |
|     # Log "failed" status to PCM/xCAT with reason and instruction for future investigation.
 | |
|     if [ $global_rc -ne 0 ]; then
 | |
|         # set node "status" to "failed" to indicate that the installation was failed.
 | |
|         fstatus_app=/tmp/baz.py
 | |
|         if [ -x "$fstatus_app" ]; then
 | |
|             $fstatus_app "installstatus failed" >&2
 | |
|         fi
 | |
| 
 | |
|         # set node state with brief reason why installation failed and future instructions.
 | |
|         # end user can get this message by running "nodestate" command to target nodes.
 | |
|         log_status "Fail to create IPR array with return code \"$global_rc\"! Refer to more details in syslog by checking \"rhPreDbg\" flag..." >&2
 | |
|     fi
 | |
|     return $global_rc
 | |
| }
 | |
| 
 | |
| ###########################################################################################
 | |
| #
 | |
| # main process to handle create raid array when using pci_id or pci_slot_name
 | |
| #
 | |
| ##########################################################################################
 | |
| function handle_create_raid_array {
 | |
|     local striple_size=$1
 | |
|     local raidlevel=$2
 | |
|     local disknum=$3
 | |
|     local pcilocs=$4
 | |
|     local disknames=$5
 | |
| 
 | |
|     if [ "x$pcilocs" != "xnull" ]; then
 | |
| 
 | |
|         # Find out all member disks in target IOAs
 | |
|         # pciloc=sloc,sloc,sloc...
 | |
|         slocs_grps=`get_raid_create_devices_by_pciloc $pcilocs `
 | |
|         if [ -z "$slocs_grps" ]; then
 | |
|             log_error "Could not find any disk on target pciloc ${pcilocs}!" >&2
 | |
|             return 1
 | |
|         else
 | |
|             log_info "Disks in target IPR raid adapter: \"$slocs_grps\"" >&2
 | |
|         fi
 | |
| 
 | |
|         # find the required member disks
 | |
|         slocs=""
 | |
|         validslocs=""
 | |
|         for item in $slocs_grps
 | |
|         do
 | |
|             pciloc=`echo "$item" | $awk -F= '{print $1}'`
 | |
|             slocs_grp=`echo "$item" | $awk -F= '{print $2;}'`
 | |
|             # order disks by its resource path
 | |
|             slocs_grp=`sort_devices_by_resource_path $slocs_grp`
 | |
| 
 | |
|             slocs=`echo "$slocs_grp" | sed 's/,/ /g'`
 | |
|             if [ -n "$slocs" ]; then
 | |
|                 break
 | |
|             else
 | |
|                 log_warn "Could not find enough disk on target adapter $pciloc which only has following disks ${slocs_grp}!" >&2
 | |
|             fi
 | |
|         done
 | |
|         if [ -z "$slocs" ]; then
 | |
|             log_error "Could not find enough disk on target adapter ${pciloc}!" >&2
 | |
|             return 1
 | |
|         else
 | |
|             log_info "Find member disks $slocs on target IOA $pciloc" >&2
 | |
|             slocs=`echo "$slocs" | $sed -e 's/,/ /g'`
 | |
|             # if it is the first create_raid, do nothing, else:
 | |
|             # delete used disks belong to existed raid array
 | |
|             validslocs=`delete_disks_belong_array_from_slocs $slocs`
 | |
|             if [ -z "$validslocs" ]; then
 | |
|                 log_error "Could not find enough unused disk on target adapter $pciloc."
 | |
|                 return 1
 | |
|             else
 | |
|                 slocs="$validslocs"
 | |
|                 log_info "Find unused member disks $slocs on target IOA $pciloc" >&2
 | |
|             fi
 | |
| 
 | |
|         fi
 | |
|         # handle disk_num
 | |
|         # if disknum is all, do nothing
 | |
|         # if disknum is a number, then it should be compared with actual_disknum
 | |
|         actual_disknum=`echo "$slocs"| $awk '{print NF}'`
 | |
|         slocs=`compare_disknum_actualnum $disknum $actual_disknum $slocs`
 | |
| 
 | |
|     else
 | |
|         # find the slocs for disks in disknames
 | |
|         disklist=`echo $disknames|sed 's/#/ /g'`
 | |
|         slocs_grp=`convert_sg_to_sloc $disklist`
 | |
|         slocs=`echo "$slocs_grp"|awk -F= '{print $2}'`
 | |
|     fi
 | |
|     # check if target disks were already in a reusable array.
 | |
|     # if not, create one by calling block command "create_ipr_array".
 | |
|     # after than, check again to confirm if the target array was ready.
 | |
|     array_sloc=""
 | |
|     ((__i=0))
 | |
|     while [ $__i -lt 2 ];
 | |
|     do
 | |
|         # get disk --> array association
 | |
|         # format 0:0:0:0=sg0
 | |
|         declare array_slocs_lines=`for sloc in $slocs
 | |
|             do
 | |
|                 line=$(get_ipr_array_by_member $sloc)
 | |
|                 echo "$sloc=$line"
 | |
|             done`
 | |
| 
 | |
|         # extract arrays from associations
 | |
|         # get sg0 sg1
 | |
|         declare array_slocs=`echo "$array_slocs_lines" \
 | |
|                              | $awk -F= '{print $2}' | $sort -u`
 | |
| 
 | |
|         # count the number of arrays on target disks
 | |
|         # which might include "blank" array
 | |
|         declare n_arrays_lines=`echo "$array_slocs" | $awk 'END {print NR}'`
 | |
|         # count the number of arrays on target disks, again
 | |
|         # w/o "blank" array
 | |
|         declare n_arrays=`echo "$array_slocs" | grep -v "^ *$" | $awk 'END {print NR}'`
 | |
|         # get the sg names for owner arrays.
 | |
|         declare array_sgs=""
 | |
|         if [ $n_arrays -gt 0 ]; then
 | |
|              array_sgs=`convert_sloc_to_sg $array_slocs \
 | |
|                         | $awk -F= '{print $2}' `
 | |
|         fi
 | |
|         # (cond_1): if ALL target disks are in ONE array, reuse it.
 | |
|         if [ $n_arrays_lines -eq 1 -a $n_arrays -eq 1 ]; then
 | |
|             if [ $__i -eq 0 ]; then
 | |
|                 log_info "Target disks, $slocs, were already in an array, $array_slocs." >&2
 | |
|             else
 | |
|                 log_info "An array, $array_slocs, had been created to include target disks, $slocs" >&2
 | |
|             fi
 | |
|             lines=`{   cmd_show_details $array_sgs;
 | |
|                        cmd_show_status $array_sgs;
 | |
|                     } | $sed -e 's/^/>> /g'`
 | |
|             log_lines details "$lines"
 | |
|             array_sloc="$array_slocs"
 | |
|             break
 | |
|         fi
 | |
|         # (cond_2): delete arrays which owe target disks first before any future operations.
 | |
|         #           NOTE: we redo the loop after "delete" command was issued to ipr
 | |
|         if [ $n_arrays -gt 0 ]; then
 | |
|             log_info "Target disks, $slocs, were owned by multiple arrays, \"$array_slocs\"($array_sgs). Delete them first before creating a new array on top of them." >&2
 | |
|             delete_ipr_array enforce=1 tryCnt=360 tryInt=60 -- $array_sgs
 | |
|             continue
 | |
|         fi
 | |
|         # (cond_3): create an array to include all target disks
 | |
|         #           we assume all these disks are ready to be included into an array.
 | |
|         if [ $__i -eq 0 ]; then
 | |
|             declare sgs=`convert_sloc_to_sg $slocs \
 | |
|                          | $awk -F= '{print $2}' | $sed -e 's/ /,/g'`
 | |
|             # Times to wait for the raid creation finish
 | |
|             # The lager capacity of member disks, longer times to wait.
 | |
|             # :unit minutes
 | |
|             monTime=240
 | |
|             # Interval of minitoring raid creation, status check
 | |
|             # :unit seconds
 | |
|             monInt=30
 | |
|             monCnt=`$awk -v monInt=$monInt -v monTime=$monTime 'END{print 60*monTime/monInt}' </dev/null`
 | |
|             log_status "Creating RAID $raidlevel array on top of disks \""`echo "$slocs" | $sed -e 's/ /,/g'`"\"/\"$sgs\"..." >&2
 | |
|             # handle striple_size
 | |
|             if [ "x$striple_size" == "xdefault" ]; then
 | |
|                 create_ipr_array $monCnt $monInt "$sgs" -r $raidlevel
 | |
|             elif [ -z $striple_size ]; then
 | |
|                 create_ipr_array $monCnt $monInt "$sgs" -r $raidlevel
 | |
|             else
 | |
|                 create_ipr_array $monCnt $monInt "$sgs" -r $raidlevel -s $striple_size
 | |
|             fi
 | |
|         fi
 | |
|     ((__i+=1))
 | |
|     done
 | |
|     lines=`cmd_show_config`
 | |
|     if [ $__i -lt 2 -a -n "$array_sloc" ]; then
 | |
|         array_sd=`echo "$lines" \
 | |
|                 | grep '^sd[a-z]\+[ ]\+.*\/'$array_sloc'[ ]\+.*Disk Array' \
 | |
|                 | $awk '{print $1}'`
 | |
|         if [ -n "$array_sd" ]; then
 | |
|             log_info "array_dev=$array_sd"
 | |
|             return 0
 | |
|         else
 | |
|             log_error "Fail to get scsi device name for new array $array_sloc" >&2
 | |
|             echo "$lines" | $sed -e 's/^/>> /g' | log_lines error >&2
 | |
|             return 1
 | |
|         fi
 | |
|     else
 | |
|         log_error "Fail to create array on top of disks $slocs" >&2
 | |
|         echo "$lines" | $sed -e 's/^/>> /g' | log_lines error >&2
 | |
|         return 1
 | |
|     fi
 | |
| 
 | |
| }
 | |
| 
 | |
| ############################################################################
 | |
| #
 | |
| # handle disk_num
 | |
| # if disknum is all, do nothing
 | |
| # if disknum is a number, then it should be compared with actual_disknum
 | |
| # return <disknum> of slocs
 | |
| #
 | |
| ##############################################################################
 | |
| function compare_disknum_actualnum {
 | |
|     local disknum=$1
 | |
|     local actualnum=$2
 | |
|     shift;
 | |
|     shift;
 | |
|     local slocs=$*
 | |
|     local actualslocs
 | |
|     if [ "x$disknum" != "xall" ]; then
 | |
|         if [ $actualnum -ge $disknum ]; then
 | |
|             actualslocs=`echo "$slocs"| \
 | |
|                          awk -v anum=$disknum '{ for ( i=1; i<=anum; i++ ){print $i}}'`
 | |
|             echo $actualslocs
 | |
| 
 | |
|         else
 | |
|             log_error "Could not find enough disk on target adapter ${pciloc}!" >&2
 | |
|         fi
 | |
|     else
 | |
|         echo "$slocs"
 | |
|     fi
 | |
| 
 | |
| }
 | |
| 
 | |
| ############################################################################
 | |
| #
 | |
| # Delete raid array
 | |
| #
 | |
| # input format : enforce=1 tryCnt=2 tryInt=60 -- arrays_name list
 | |
| #
 | |
| ##########################################################################
 | |
| function delete_ipr_array {
 | |
|     # default to NO if enforcely wait for rebuilding array
 | |
|     local enforce=0
 | |
|     # default to wait 2 minutes for array rebuilding to finish
 | |
|     local tryCnt=2
 | |
|     # monitor rebuilding status every 60 seconds
 | |
|     local tryInt=60
 | |
| 
 | |
|     # parser input arguments
 | |
|     while [ -n "$1" ];
 | |
|     do
 | |
|         local key=`echo "$1" | $cut -s -d= -f1`
 | |
|         if [ "$key" = "tryCnt" ] || \
 | |
|            [ "$key" = "tryInt" ] || \
 | |
|            [ "$key" = "enforce" ]; then
 | |
|             local val=`echo "$1" | $cut -s -d= -f2-`
 | |
|             eval "$key=\"$val\""
 | |
|         elif [ "$1" = "--" ]; then
 | |
|             shift
 | |
|             arrays="$*"
 | |
|             break
 | |
|         fi
 | |
|         shift
 | |
|     done
 | |
|     # should not with empty array list, if yes, error with rc=1
 | |
|     if [ -z "$arrays" ]; then
 | |
|         log_error "No array to delete, assume success!" >&2
 | |
|         return 0
 | |
|     fi
 | |
|     local array_slocs=`convert_sg_to_sloc $arrays | awk -F= '{print $2}'`
 | |
|     # if none of arrays were valid, error with rc=1
 | |
|     if [ -z "$array_slocs" ]; then
 | |
|         log_error "Fail to map arrayes, $arrays, to scsi location before deletion!"
 | |
|         return 1
 | |
|     fi
 | |
|     local ioas=`get_ipr_ioas`
 | |
| 
 | |
|     local i=1
 | |
|     while [ $i -le $tryCnt ];
 | |
|     do
 | |
|         # verify if all target arrays are still exists
 | |
|         local tmp_array_slocs=`for _tmp_sloc in $array_slocs
 | |
|         do
 | |
|             is_ipr_array $_tmp_sloc && echo "$_tmp_sloc"
 | |
|         done `
 | |
|         if [ "$tmp_array_slocs" != "$array_slocs" ]; then
 | |
|             array_slocs="$tmp_array_slocs"
 | |
|             log_details "Renew available target arrays which will be deleting, \"$array_slocs\"" >&2
 | |
|         fi
 | |
|         if [ -z "$array_slocs" ]; then
 | |
|             log_details "Round $i: All target arrays were gone!" >&2
 | |
|             break
 | |
|         fi
 | |
|         # find out sg devs for all deletable arrays
 | |
|         local array_slocs_deletable=`for ioa in $ioas
 | |
|         do
 | |
|             # [root@dn01-dat ~]# iprconfig -c query-raid-delete sg5
 | |
|             # Name   PCI/SCSI Location         Description               Status
 | |
|             # ------ ------------------------- ------------------------- -----------------
 | |
|             # sdk    0003:70:00.0/0:2:0:0       RAID 0 Disk Array         Optimized
 | |
|             # sdl    0003:70:00.0/0:2:1:0       RAID 0 Disk Array         Optimized
 | |
|             cmd_query_raid_delete $ioa \
 | |
|             | grep "Disk Array" \
 | |
|             | cut_sloc_from_iprconfig_line
 | |
|         done`
 | |
|         if [ -z "$array_slocs_deletable" -a $enforce -eq 0 ]; then
 | |
|             log_details "Round $i: No deletable array, nothing to do and finish." >&2
 | |
|             break
 | |
|         fi
 | |
|         # log for debug
 | |
|         {
 | |
|             echo "$array_slocs_deletable" | $sed -e 's/^/Round '$i': Deletable array >> /g'
 | |
|             cmd_show_config | $sed -e 's/^/Round '$i': ipr info before delete >> /g'
 | |
|         } | log_lines details >&2
 | |
|         log_info "Round $i: delete_ipr_array, \"$array_slocs\"" >&2
 | |
| 
 | |
|         # if requested array is a deletable array, mark it to be deleted in this round.
 | |
|         local array_slocs_verified=`for array_sloc in $array_slocs
 | |
|         do
 | |
|             if echo "$array_slocs_deletable" | grep -sq "^$array_sloc$"; then
 | |
|                 echo $array_sloc
 | |
|             else
 | |
|                 log_warn "Round $i: Array $array_sloc is un-deletable at present." >&2
 | |
|             fi
 | |
|         done`
 | |
|         if [ -n "$array_slocs_verified" ]; then
 | |
|             log_details "Round $i: Verified array slocs for deletion are \"$array_slocs_verified\"." >&2
 | |
|         else
 | |
|             log_info "Round $i: All remaining target arrayes are un-deletable now." >&2
 | |
|             if [ $enforce -eq 1 ]; then
 | |
|                 log_info "Round $i: Wait for these un-deletable arrayes deletable with tryCnt=$tryCnt, tryInt=$tryInt." >&2
 | |
|                 wait_for_ipr_device_status \
 | |
|                     tryCnt=$tryCnt tryInt=$tryInt cmd="grep -sq -E 'Optimized'" \
 | |
|                     -- \
 | |
|                     `echo "$array_slocs" | $sed -e "s/ /,/g"`
 | |
|                 # if wait succ, let's try to delete again
 | |
|                 if [ $? -eq 0 ]; then
 | |
|                     ((i+=1))
 | |
|                     continue
 | |
|                 else
 | |
|                     break
 | |
|                 fi
 | |
|             fi
 | |
|         fi
 | |
| 
 | |
|         # issue delete command
 | |
|         local dcnt=0
 | |
|         for array_sloc in $array_slocs_verified
 | |
|         do
 | |
|             local array=`convert_sloc_to_sg $array_sloc | awk -F= '{print $2}'`
 | |
|             [ -z "$array" ] && continue
 | |
| 
 | |
|             log_details "Round $i: Delete $dcnt array $array=$array_sloc" >&2
 | |
|             cmd__raid_delete $array
 | |
|             ((dcnt+=1))
 | |
|         done
 | |
| 
 | |
|         # break out the loop forcely if nothing deleted.
 | |
|         [ $dcnt -eq 0 ] && break
 | |
| 
 | |
|         # wait for next round
 | |
|         $sleep $tryInt
 | |
|         ((i+=1))
 | |
|     done
 | |
|     test $i -lt $tryCnt -a -z "$array_slocs"
 | |
|     return $?
 | |
| }
 | |
| 
 | |
| #################################################
 | |
| #
 | |
| # sort devices by resource path,
 | |
| #
 | |
| # input: dev list, "sg0,..sgn"
 | |
| #
 | |
| ##################################################
 | |
| function sort_devices_by_resource_path {
 | |
|     local sgs="$*"
 | |
| 
 | |
|     local del=","
 | |
|     if [ $# -gt 1 ]; then
 | |
|         del=" "
 | |
|     else
 | |
|         sgs=`echo "$sgs" | $sed -e "s/,/ /g"`
 | |
|     fi
 | |
| 
 | |
|     # [root@dn01-dat ~]# iprconfig -c show-alt-config
 | |
|     # Name   Resource Path/Address      Vendor   Product ID       Status
 | |
|     # ------ -------------------------- -------- ---------------- -----------------
 | |
|     # sg15   FE                         IBM      57D7001SISIOA    Operational
 | |
|     # sg10   00-0C                      IBM      HUC101212CSS600  Active
 | |
|     # sg11   00-0D                      IBM      HUC101212CSS600  Active
 | |
|     local lines=`$iprconfig -c show-alt-config | grep "^sg"`
 | |
|     local item
 | |
|     local lines_out=`for item in $sgs
 | |
|     do
 | |
|         local sg=$(convert_sloc_to_sg $item | $awk -F= '{print $2;}')
 | |
|         local rp=$(echo "$lines" | $awk -vsg=$sg '$1 == sg { print $2; }')
 | |
|         echo "$item $sg $rp"
 | |
|     done \
 | |
|     | $sort -t' ' -k3`
 | |
|     # log for debug
 | |
|     {
 | |
|         echo "sort devices \"$sgs\" by IPR resource path:"
 | |
|         echo "$lines_out" | $sed -e 's/^/sort by rp output: >> /g'
 | |
|     } | log_lines details >&2
 | |
| 
 | |
|     # deliver ordered result
 | |
|     lines_out=`echo "$lines_out" | $awk '{print $1;}' `
 | |
|     if [ "$del" = "," ]; then
 | |
|         echo "$lines_out" | $sed -e "s/ /,/g"
 | |
|     fi
 | |
|     return 0
 | |
| }
 | |
| 
 | |
| ##########################################################################################################################
 | |
| #
 | |
| # wait to check ipr device status
 | |
| # usage: wait_for_ipr_device_status tryCnt=<minitutes> tryInt=<interval_seconds> cmd="check_cmd_line" -- "sg0,sg1,...,sgn"
 | |
| #
 | |
| #########################################################################################################################
 | |
| function wait_for_ipr_device_status {
 | |
|     local tryCnt=1
 | |
|     local tryInt=10
 | |
|     local cmd="true"
 | |
| 
 | |
|     # parser input arguments
 | |
|     while [ -n "$1" ];
 | |
|     do
 | |
|         local key=`echo "$1" | $cut -s -d= -f1`
 | |
|         if [ "$key" = "tryCnt" ] || \
 | |
|            [ "$key" = "tryInt" ] || \
 | |
|            [ "$key" = "cmd" ]; then
 | |
|             local val=`echo "$1" | $cut -s -d= -f2-`
 | |
|             eval "$key=\"$val\""
 | |
|         elif [ "$1" = "--" ]; then
 | |
|             shift
 | |
|             sgs="$*"
 | |
|             break
 | |
|         fi
 | |
|         shift
 | |
|     done
 | |
|     sgs=`echo "$sgs" | $sed -e "s/,/ /g"`
 | |
|     local cnt=0
 | |
|     local lines
 | |
|     while [ $cnt -lt $tryCnt -o $tryCnt -le 0 ];
 | |
|     do
 | |
|         # sleep for specific interval for next cycle
 | |
|         [ $cnt -gt 0 ] && $sleep $tryInt
 | |
| 
 | |
|         lines=`check_ipr_device_status $sgs`
 | |
|         local status_lines=""
 | |
|         local neg=0
 | |
|         local sg
 | |
|         for sg in $sgs
 | |
|         do
 | |
|             local _sg_status=`echo "$lines" | grep "^$sg=" | $cut -d= -f2- -s`
 | |
|             echo "$_sg_status" | eval $cmd >&2
 | |
|             if [ $? -ne 0 ]; then
 | |
|                 neg=1
 | |
|                 status_lines="${status_lines}${status_lines:+,}status[$sg]=\"$_sg_status\""
 | |
|             fi
 | |
|         done
 | |
| 
 | |
|         # break out if NO negative matching
 | |
|         # or, try next loop
 | |
|         if [ $neg -eq 0 ]; then
 | |
|             break
 | |
|         else
 | |
|             log_status "Wait for device status at time \""`date "+%Y-%m-%d %H:%M:%S"`"\": $status_lines, expect: \"$cmd\"."
 | |
|         fi
 | |
| 
 | |
|         ((cnt+=1))
 | |
|     done
 | |
|     test $cnt -lt $tryCnt -o $tryCnt -le 0
 | |
|     local rc=$?
 | |
| 
 | |
|     # log for debug
 | |
|     if [ $rc -eq 0 ]; then
 | |
|         log_info "Wait for status on devices: \"$sgs\" succeed! (expected: \"$cmd\")"
 | |
|     else
 | |
|         log_warn "Wait for status on devices: \"$sgs\" failed! (expected: \"$cmd\")"
 | |
|         echo "$lines" | $sed -e 's/^/last device status: >> /g' | log_lines debug
 | |
|     fi
 | |
| 
 | |
|     return $rc
 | |
| }
 | |
| 
 | |
| ##############################################################
 | |
| #
 | |
| # check status of ipr devices
 | |
| # input : slocs list, for example, 0:0:0:0 0:0:1:0
 | |
| # usage : check_ipr_device_status <sloc1> <sloc2> ... <slocn>
 | |
| #
 | |
| ##############################################################
 | |
| function check_ipr_device_status {
 | |
|     local sgs="$*"
 | |
|     local lines=`convert_sloc_to_sg $sgs`
 | |
| 
 | |
|     local item
 | |
|     for item in $sgs
 | |
|     do
 | |
|         declare sg=`echo "$lines" | $awk -F= -vkey=$item '$1 == key {print $2;}'`
 | |
|         declare _sg_status=`$iprconfig -c status $sg`
 | |
|         if [ "$_sg_status" = "Rebuilding" ]; then
 | |
|             declare _sg_status_alt=`cmd_alt_status $sg`
 | |
|             [ -n "$_sg_status_alt" ] && _sg_status="$_sg_status, $_sg_status_alt"
 | |
|         fi
 | |
|         echo "$item=$_sg_status"
 | |
|     done
 | |
|     return 0
 | |
| }
 | |
| 
 | |
| 
 | |
| ######################################################
 | |
| #
 | |
| # log lines
 | |
| #
 | |
| # input : details or status or error
 | |
| #
 | |
| ######################################################
 | |
| function log_lines {
 | |
|     local pcnt=$#
 | |
|     local __level=$1
 | |
|     shift
 | |
|     local cmd=log_${__level}
 | |
| 
 | |
|     local hit=0
 | |
|     local OIFS=$IFS
 | |
|     local NIFS=$'\n'
 | |
|     IFS=$NIFS
 | |
|     local __msg
 | |
|     for __msg in $*
 | |
|     do
 | |
|         IFS=$OIFS
 | |
|         $cmd "$__msg"
 | |
|         hit=1
 | |
|         IFS=$NIFS
 | |
|     done
 | |
|     IFS=$OIFS
 | |
| 
 | |
|     [ $hit -eq 0 -a $pcnt -le 1 ] && \
 | |
|     while read __msg;
 | |
|     do
 | |
|         $cmd "$__msg"
 | |
|     done
 | |
| }
 | |
| 
 | |
| ######################################################
 | |
| #
 | |
| # error information
 | |
| #
 | |
| ######################################################
 | |
| function log_error {
 | |
|     local __msg="$*"
 | |
|     $log_print_cmd $log_print_arg "[E]: $__msg" >&2
 | |
|     return 0
 | |
| }
 | |
| 
 | |
| ######################################################
 | |
| #
 | |
| # warning information
 | |
| #
 | |
| # input : message
 | |
| #
 | |
| ######################################################
 | |
| function log_warn {
 | |
|     local __msg="$*"
 | |
|     $log_print_cmd $log_print_arg "[W]: $__msg" >&2
 | |
|     return 0
 | |
| }
 | |
| 
 | |
| ######################################################
 | |
| #
 | |
| # log information
 | |
| #
 | |
| # input : message
 | |
| #
 | |
| ######################################################
 | |
| function log_info {
 | |
|     local __msg="$*"
 | |
|     $log_print_cmd $log_print_arg "[I]: $__msg" >&2
 | |
|     return 0
 | |
| }
 | |
| 
 | |
| ######################################################
 | |
| #
 | |
| # more details information
 | |
| #
 | |
| ######################################################
 | |
| function log_details {
 | |
|     local __msg="$*"
 | |
|     $log_print_cmd $log_print_arg "[I]: $__msg" >&2
 | |
|     return 0
 | |
| }
 | |
| 
 | |
| ####################################################
 | |
| #
 | |
| # print command status
 | |
| #
 | |
| ###################################################
 | |
| __my_log_status=
 | |
| function log_status {
 | |
|     local __msg="$*"
 | |
|     $log_print_cmd $log_print_arg "[S]: $__msg" >&2
 | |
| 
 | |
|     # call my_log_status hook to triger more processing for status messages.
 | |
|     if [ -n "$__my_log_status" ]; then
 | |
|         $__my_log_status "$__msg"
 | |
|     fi
 | |
|     return 0
 | |
| }
 | |
| 
 | |
| ####################################################
 | |
| #
 | |
| # print output and logfile
 | |
| #
 | |
| ###################################################
 | |
| function log_print_default {
 | |
|     echo $*
 | |
|     echo $* >> $log_file
 | |
| }
 | |
| 
 | |
| ####################################################
 | |
| #
 | |
| # handle command
 | |
| #
 | |
| ###################################################
 | |
| function set_log_print {
 | |
|     local cmd="$1"
 | |
|     if [ -z "$cmd" ]; then
 | |
|         return 1
 | |
|     fi
 | |
|     shift
 | |
|     local args="$*"
 | |
| 
 | |
|     eval "log_print_cmd=\"$cmd\""
 | |
|     eval "log_print_arg=\"$args\""
 | |
| }
 | |
| 
 | |
| # let log work
 | |
| [ -z "$log_print" ] && set_log_print "log_print_default"
 | |
| 
 | |
| 
 | |
| 
 |