#!/bin/sh # IBM(c) 2013 EPL license http://www.eclipse.org/legal/epl-v10.html ### BEGIN INIT INFO # Provides: xcatconf4z # Default-Start: 2 3 5 # Default-stop: 0 1 4 6 # Required-Start: $syslog # Should-Start: # Required-Stop: # Short-Description: xCAT disk initialization and configuration # Description: Reads class x files from the reader and acts based on the type of file. # Files of filetype "disk" cause SCSI disks be configured. # Other files are used to generate an ISO9660 disk for transporting xCAT configurations. ### END INIT INFO ############################################################################### # Authorized senders of configuration files listed here. Specify a list a # blank delimited list of userids with each userid in uppercase # (e.g. "ZHCP" or "ZHCP ZHCP2"), or '*' to indicate all are authorized. # If nothing is specified then this function will not process any # configuration files in the reader. ############################################################################### authorizedSenders='' function getOsVersion { # @Description: # Returns the Linux distro version in an easy to parse format. # @Input: # None # @Output: # os - Variable set with OS and version information. For example: # "rhel62" or "sles11sp2" # @Code: release=`cat /etc/*release` if echo $release | grep -i "SUSE Linux Enterprise Server" > /dev/null ; then os='sles' version=`echo "$release" | grep "VERSION =" | sed \ -e 's/^.*VERSION =//' \ -e 's/\s*$//' \ -e 's/.//' \ -e 's/[^0-9]*([0-9]+).*/$1/'` os=$os$version; # Append service level level=`echo "$release" | grep "LEVEL =" | sed \ -e 's/^.*LEVEL =//' \ -e 's/\s*$//' \ -e 's/.//' \ -e 's/[^0-9]*([0-9]+).*/$1/'` os=$os'sp'$level elif version=`echo $release | grep -i "Red Hat Enterprise Linux Server"`; then os='rhel' version=`echo $version | sed \ -e 's/[A-Za-z\/\.\(\)]//g' \ -e 's/^ *//g' \ -e 's/ *$//g' \ -e 's/\s.*$//'` os=$os$version fi return } function onlineDevice { # @Description: # Brings a Linux device online. # @Input: # Device number, e.g. "0.0.000c" # @Output: # Return code indicates success or failure # @Code: device=$1 local funcName="onlineDevice" rc=$(/sbin/chccwdev -e $device > /dev/null; echo $?) if (( rc != 0 )); then if [[ -e /sbin/cio_ignore ]]; then rc=$(/sbin/cio_ignore -r 0.0.$device > /dev/null; echo $?) which udevadm &> /dev/null && udevadm settle || udevsettle fi rc=$(/sbin/chccwdev -e $device > /dev/null; echo $?) if (( rc != 0 )); then echo "xcatconf4z $funcName (Error) Could not activate the virtual reader" return 1 fi fi which udevadm &> /dev/null && udevadm settle || udevsettle return 0 } function pullReader { # @Description: # Reads class x spool files from the reader if sent by an authorized sender. # Drives special processing functions for files of a specific type. # Files with a filetype of: # tgz are unpacked into the transport directory # disk files are read and cause the setupDisk function to be driven # all other files are unpacked into the transport directory # @Input: # None # @Output: # Return code indicates success if reader was brought online. # @Code: local funcName="pullReader" /sbin/modprobe vmcp # Online reader rc= onlineDevice "000c" if (( rc != 0 )); then return $rc fi # Grab the spool Id, class file name, and file type eval records=($(/usr/sbin/vmur li | tail -n +2 | cut -c 1-72 | awk '{print $1":"$2":"$3":"$10":"$11"\n"}' )) # Process each spool file that is class "x" for record in "${records[@]}" do record=$(echo $record | tr ":" " ") set $record originid=$1 spoolid=$2 class=$3 filename=$4 type=$5 if [[ $class != "X" ]]; then # Spool file is not of the class required for processing by this script. continue fi if [[ $authorizedSenders != "*" ]]; then if [[ " $authorizedSenders " != *" $originid "* ]]; then # Originator is not authorized to send configuration files. continue fi fi if [[ -n $type ]]; then file="$filename.$type" else file=$filename fi # Receive the spool file echo "Downloading record $spoolid: $file" if [[ $type == "txt" ]] || [[ $type == "sh" ]]; then # Receiving text rc=$(/usr/sbin/vmur re -t $spoolid $file) elif [[ $type == "tgz" ]]; then rc=$(/usr/sbin/vmur re $spoolid $file) /bin/tar xzf $file -C $transportdir rm $file elif [[ $type == "disk" ]]; then rc=$(/usr/sbin/vmur re $spoolid $file) if (( rc == 0 )); then setupDisk $transportdir'/'$file rc=0 fi else # Receive block rc=$(/usr/sbin/vmur re $spoolid $file) fi if (( rc != 0 )); then echo "xcatconf4z funcName (Error) Failed to download record $spoolid" fi done return 0 } function setupIso { # @Description: # Makes an ISO filesystem using the contents of the transport directory and # creates a loop device pointing to the ISO image. If an "init.sh" script # exists in the transport directory then it is driven. # @Input: # None # @Output: # None # @Code: # Create ISO based on transport directory iso="/var/opt/xcat/transport.iso" /usr/bin/mkisofs -l -o $iso $transportdir # Create loop back device pointing to ISO9660 image nextLoopDev=`/sbin/losetup -f` if [[ -n $nextLoopDev ]]; then /sbin/losetup $nextLoopDev $iso else return fi # Execute init script (if one exists) if [[ -e ${transportdir}/init.sh ]]; then chmod 755 ${transportdir}/init.sh ${transportdir}/init.sh fi } function setupDisk { # @Description: # Processes a disk file for the following functions: # create a file system node # Setup a SCSI volume # Removes a SCSI volume # @Input: # Location and name of the disk file. # @Output: # None # @Code: diskFile=$1 local funcName="setupDisk" # Read the file and verify we want to handle it if ! grep -q "# xCAT Init" "$diskFile"; then # File is not one that we handle. Leave it alone. return fi # Read the file now that we know it is our file oldIFS=$IFS IFS=$'\n' for line in $(cat "$diskFile"); do if [[ $line == \#* ]]; then # Ignore comment lines continue fi keyName=${line%\=*} value=${line#*\=} value=$(echo ${value} | sed -e 's/^ *//g') newKey='xcat_'$keyName eval $newKey=$value done IFS=$oldIFS # Remove the disk file after we have read it rm $diskFile ########################################################################## # Handle creating a file system node # Disk file input parameters: # action - "createfilesysnode" # srcFile - location/name of the source file for the mknod command # tgtFile - location/name of the target file for the mknod command ########################################################################## if [[ $xcat_action == "createfilesysnode" ]]; then echo "Creating a file system node, source: $xcat_srcFile, target: $xcat_tgtFile" if [[ ! -n $xcat_srcFile ]]; then echo "xcatconf4z $funcName (Error) Source file for creating a file system node was not specified" return fi if [[ ! -n $xcat_tgtFile ]]; then echo "xcatconf4z $funcName (Error) Target file for creating a file system node was not specified" return fi if [[ -e $xcat_tgtFile ]]; then echo "xcatconf4z $funcName (Error) Target file for creating a file system node already exists" return fi out=`stat -L --printf=%t:%T $xcat_srcFile` if (( $? != 0 )); then echo "xcatconf4z $funcName (Error) Unable to stat the source file: $xcat_srcFile" return fi major=${out%:*} major=$(echo ${major} | sed -e 's/^ *//g') minor=${out#*:} minor=$(echo ${minor} | sed -e 's/^ *//g') mknod $xcat_tgtFile b 0x$major 0x$minor ########################################################################## # Handle removing a file system node # Disk file input parameters: # action - "removefilesysnode" # tgtFile - location/name of the target file for the mknod command ########################################################################## elif [[ $xcat_action == "removefilesysnode" ]]; then echo "Removing a file system node, target: $xcat_tgtFile" if [[ ! -n $xcat_tgtFile ]]; then echo "xcatconf4z $funcName (Error) Target file for creating a file system node was not specified" return fi umount "$xcat_tgtFile" rm -f "$xcat_tgtFile" ########################################################################## # Handle adding a SCSI volume # Disk file input parameters: # action - "addScsiVolume" # fcpAddr - FCP device address # wwpn - WWPN number # lun - LUN number ########################################################################## elif [[ $xcat_action == "addScsiVolume" ]]; then echo "Adding a SCSI Volume, FCP addr: $xcat_fcpAddr, WWPN: $xcat_wwpn, LUN: $xcat_lun" # Validate the input if [[ ! -n $xcat_fcpAddr ]]; then echo "xcatconf4z $funcName (Error) FCP address was not specified" return fi xcat_fcpAddr=`echo $xcat_fcpAddr | tr '[A-Z]' '[a-z]'` if [[ ! -n $xcat_wwpn ]]; then echo "xcatconf4z $funcName (Error) WWPN was not specified" return fi xcat_wwpn=`echo $xcat_wwpn | tr '[A-Z]' '[a-z]'` if [[ ! -n $xcat_lun ]]; then echo "xcatconf4z $funcName (Error) LUN was not specified" return fi xcat_lun=`echo $xcat_lun | tr '[A-Z]' '[a-z]'` # Online the device rc= onlineDevice $xcat_fcpAddr if (( rc != 0 )); then return fi # Set WWPN and LUN in sysfs if [[ -e /sys/bus/ccw/drivers/zfcp/0.0.$xcat_fcpAddr/port_add ]]; then echo 0x$xcat_wwpn > /sys/bus/ccw/drivers/zfcp/0.0.$xcat_fcpAddr/port_add fi echo 0x$xcat_lun > /sys/bus/ccw/drivers/zfcp/0.0.$xcat_fcpAddr/0x$xcat_wwpn/unit_add # Set WWPN and LUN in configuration files # RHEL: /etc/zfcp.conf # SLES 10: /etc/sysconfig/hardware/hwcfg-zfcp-bus-ccw-* # SLES 11: /etc/udev/rules.d/51-zfcp* if [[ $os == sles10* ]]; then /sbin/zfcp_host_configure 0.0.$xcat_fcpAddr 1 /sbin/zfcp_disk_configure 0.0.$xcat_fcpAddr $xcat_wwpn $xcat_lun 1 echo "0x$xcat_wwpn:0x$xcat_lun" >> /etc/sysconfig/hardware/hwcfg-zfcp-bus-ccw-0.0.$xcat_fcpAddr elif [[ $os == sles11* ]]; then /sbin/zfcp_host_configure 0.0.$xcat_fcpAddr 1 /sbin/zfcp_disk_configure 0.0.$xcat_fcpAddr $xcat_wwpn $xcat_lun 1 # Configure zFCP device to be persistent touch /etc/udev/rules.d/51-zfcp-0.0.$xcat_fcpAddr.rules # Check if the file already contains the zFCP channel out=`cat "/etc/udev/rules.d/51-zfcp-0.0.$xcat_fcpAddr.rules" | egrep -i "ccw/0.0.$xcat_fcpAddr]online"` if [[ ! $out ]]; then echo "ACTION==\"add\", SUBSYSTEM==\"ccw\", KERNEL==\"0.0.$xcat_fcpAddr\", IMPORT{program}=\"collect 0.0.$xcat_fcpAddr %k 0.0.$xcat_fcpAddr zfcp\"" \ | tee -a /etc/udev/rules.d/51-zfcp-0.0.$xcat_fcpAddr.rules echo "ACTION==\"add\", SUBSYSTEM==\"drivers\", KERNEL==\"zfcp\", IMPORT{program}=\"collect 0.0.$xcat_fcpAddr %k 0.0.$xcat_fcpAddr zfcp\"" \ | tee -a /etc/udev/rules.d/51-zfcp-0.0.$xcat_fcpAddr.rules echo "ACTION==\"add\", ENV{COLLECT_0.0.$xcat_fcpAddr}==\"0\", ATTR{[ccw/0.0.$xcat_fcpAddr]online}=\"1\"" \ | tee -a /etc/udev/rules.d/51-zfcp-0.0.$xcat_fcpAddr.rules fi echo "ACTION==\"add\", KERNEL==\"rport-*\", ATTR{port_name}==\"0x$xcat_wwpn\", SUBSYSTEMS==\"ccw\", KERNELS==\"0.0.$xcat_fcpAddr\", ATTR{[ccw/0.0.$xcat_fcpAddr]0x$xcat_wwpn/unit_add}=\"0x$xcat_lun\"" \ | tee -a /etc/udev/rules.d/51-zfcp-0.0.$device.rules elif [[ $os == rhel* ]]; then echo "0.0.$xcat_fcpAddr 0x$xcat_wwpn 0x$xcat_lun" >> /etc/zfcp.conf if [[ $os == rhel6* ]]; then echo "add" > /sys/bus/ccw/devices/0.0.$xcat_fcpAddr/uevent fi fi # Settle the file system so when we are done the device is fully available if [[ $(which udevadm 2> /dev/null) != '' ]]; then udevadm settle else udevsettle fi if [[ ! -e "/dev/disk/by-path/ccw-0.0.${xcat_fcpAddr}-zfcp-0x${xcat_wwpn}:0x${xcat_lun}" ]]; then # Sometimes the file takes longer to appear. We will wait up to 3 minutes. maxTime=0 for time in 1 2 2 5 10 10 30 60 60 do if [[ -e "/dev/disk/by-path/ccw-0.0.${xcat_fcpAddr}-zfcp-0x${xcat_wwpn}:0x${xcat_lun}" ]]; then # Leave the loop now that the file exists break fi maxTime=$maxTime+$time echo "Sleeping for $time seconds to allow /dev/disk/by-path/ccw-0.0.${xcat_fcpAddr}-zfcp-0x${xcat_wwpn}:0x${xcat_lun} to be created" sleep $time done fi if [[ ! -e "/dev/disk/by-path/ccw-0.0.${xcat_fcpAddr}-zfcp-0x${xcat_wwpn}:0x${xcat_lun}" ]]; then echo "/dev/disk/by-path/ccw-0.0.${xcat_fcpAddr}-zfcp-0x${xcat_wwpn}:0x${xcat_lun} did not appear in $maxTime seconds, continuing." fi ########################################################################## # Handle removing a SCSI volume # Disk file input parameters: # action - "removeScsiVolume" # fcpAddr - FCP device address # wwpn - WWPN number # lun - LUN number ########################################################################## elif [[ $xcat_action == "removeScsiVolume" ]]; then echo "Removing a SCSI Volume, FCP addr: $xcat_fcpAddr, WWPN: $xcat_wwpn, LUN: $xcat_lun" # Validate the input if [[ ! -n $xcat_fcpAddr ]]; then echo "xcatconf4z $funcName (Error) FCP address was not specified" return fi xcat_fcpAddr=`echo $xcat_fcpAddr | tr '[A-Z]' '[a-z]'` if [[ ! -n $xcat_wwpn ]]; then echo "xcatconf4z $funcName (Error) WWPN was not specified" return fi xcat_wwpn=`echo $xcat_wwpn | tr '[A-Z]' '[a-z]'` if [[ ! -n $xcat_lun ]]; then echo "xcatconf4z $funcName (Error) LUN was not specified" return fi xcat_lun=`echo $xcat_lun | tr '[A-Z]' '[a-z]'` # Delete the SCSI device scsiDevice=`lszfcp -l 0x$xcat_lun | grep 0x$xcat_lun | cut -d " " -f2` if [[ -n $scsiDevice ]]; then echo 1 > "/sys/bus/scsi/devices/$scsiDevice/delete" fi # Delete WWPN and LUN from sysfs if [[ -e /sys/bus/ccw/drivers/zfcp/0.0.$xcat_fcpAddr/0x$xcat_wwpn/unit_remove ]]; then if [[ $(which udevadm 2> /dev/null) != '' ]]; then udevadm settle else udevsettle fi echo 0x$xcat_lun > /sys/bus/ccw/drivers/zfcp/0.0.$xcat_fcpAddr/0x$xcat_wwpn/unit_remove fi # Delete WWPN and LUN from configuration files # RHEL: /etc/zfcp.conf # SLES 10: /etc/sysconfig/hardware/hwcfg-zfcp-bus-ccw-* # SLES 11: /etc/udev/rules.d/51-zfcp* if [[ $os == sles10* ]]; then expression="/$xcat_lun/d" sed --in-place -e $expression /etc/sysconfig/hardware/hwcfg-zfcp-bus-ccw-0.0.$xcat_fcpAddr elif [[ $os == sles11* ]]; then expression="/$xcat_lun/d" sed --in-place -e $expression /etc/udev/rules.d/51-zfcp-0.0.$xcat_fcpAddr.rules elif [[ $os == rhel* ]]; then expression="/$xcat_lun/d" sed --in-place -e $expression /etc/zfcp.conf fi fi return } ############################################################################ # Main Code Section ############################################################################ case "$1" in start) if [[ -z "$authorizedSenders" ]]; then echo "xcatconf4z is disabled. There are no authorized senders of configuration files." else echo "xcatconf4z is starting" transportdir="/var/opt/xcat/transport" rm -Rf $transportdir /bin/mkdir -p $transportdir cd $transportdir # Get Linux version getOsVersion pullReader setupIso fi ;; stop|status|restart|reload|force-reload) # Do nothing ;; esac