#!/bin/bash
# Generated by jinja2 template

fcp_list="{{ fcp_list }}"
input_wwpns="{{ wwpns }}"
# lun example: 0x0100000000000000
lun="{{ lun }}"
# 1. if the lun id less than 256,
#    the file under /dev/disk/by-path/ will as below,
#    take 'lun id = 0' as example:
#    ccw-0.0.5c03-fc-0x5005076802400c1a-lun-0, the the lun id is decimal.
# 2. if the lun id is equal or more than 256,
#    the file under /dev/disk/by-path/ will as below,
#    take 'lun id = 256' as example:
#    ccw-0.0.1a0d-fc-0x500507680b26bac7-lun-0x0100000000000000,
#    the lun id is hex.
lun_id="{{ lun_id }}"
target_filename="{{ target_filename }}"

# OK(0): success
OK=0
# MULTIPATH_SERVICE_NOT_ACTIVE(1): failed because multipathd service is not active
MULTIPATH_SERVICE_NOT_ACTIVE=1
# INVALID_PARAMETERS(2): failed because input parameters may have problems
INVALID_PARAMETERS=2
# INVALID_WWPNS(3): failed because can not found intersection between input WWPNs and lszfcp output
INVALID_WWPNS=3
# DEVICE_PATH_NOT_FOUND(4): failed because no disk file found in the target VM, means no volume shown in the target VM
DEVICE_PATH_NOT_FOUND=4

echo "Enter UBUNTU attach script with parameters: FCP list:${fcp_list[@]}, INPUT WWPNS:${input_wwpns[@]}, LUN:$lun lun_id:$lun_id, target_filename:$target_filename."

# ensure multipathd service is up
echo "Checking status of multipathd service ..."
check_multipathd_service=`systemctl is-active --quiet multipathd`
exit_code=$?
if [[ $exit_code != 0 ]]; then
    echo "Attach script terminated because multipathd service is not active, exit with code $MULTIPATH_SERVICE_NOT_ACTIVE."
    exit $MULTIPATH_SERVICE_NOT_ACTIVE
fi

# because jinja2's problem, we can not use # to count the array_size
fcp_count=0
for fcp in ${fcp_list[@]}
do
    echo "Got FCP $fcp"
    fcp_count=$((fcp_count+=1))
done

if [[ $fcp_count -eq 0 ]]; then
    echo "fcp_list is empty, exit with code $INVALID_PARAMETERS."
    exit $INVALID_PARAMETERS
fi

# see if zfcp is enable
echo "Begin to enable zfcp mode ..."
enable_zfcp_mod=`lsmod | grep zfcp`
if [ -z "$enable_zfcp_mod" ];then
    modprobe zfcp
    echo "zfcp mode enabled successfully"
else
    echo "zfcp mode is already enabled"
fi

# online fcp devices
for fcp in ${fcp_list[@]}
do
    echo "Begin to online FCP $fcp ..."
    /sbin/chzdev zfcp-host $fcp -e
    echo "FCP $fcp is online now"
done

# Print info of each FCP
for fcp in ${fcp_list[@]}
do
    # print the status of FCP port for debug
    host=$(lszfcp | grep -i $fcp | awk -F' ' '{print $2}')
    if [[ -n "$host" ]]; then
        if [[ -e /sys/class/fc_host/$host/port_state ]]; then
            port_state=$(cat /sys/class/fc_host/$host/port_state)
            echo "Port state of fcp: $fcp is: $port_state"
        else
            echo "Can not get port statue of fcp $fcp because file /sys/class/fc_host/$host/port_state not exist"
        fi
    else
        echo "Failed to find host of fcp: $fcp from the lszfcp output, cann't get port state"
    fi
done

# send an iSCSI scan request with given host and optionally the ctl 
# the ctl means, c: channel,default to -
#                t: target, default to -
#                l: lun, default to -
all_hosts=(`ls /sys/class/scsi_host/`)
for host in ${all_hosts[@]}
do
    echo "Scan on host $host triggered"
    echo "- - -" > /sys/class/scsi_host/$host/scan
    echo "Scan on host $host completed"
done

# the number WWPNs is generated dynamically
# so we need to get them from the filesystem
# the number WWPNs is generated dynamically
# so we need to get them from the filesystem
# and get the intersection between input wwpns and lszfcp output
lszfcp_output=`lszfcp -P | awk '{print $1}' | awk -F'/' '{print $1,$2}'`
echo -e "lszfcp -P output port info:\n$lszfcp_output"

declare -A valid_dict
for fcp in ${fcp_list[@]}
do
    # Retry each FCP device to make sure there are matched WWPNs for it
    Timeout=10
    while [[ $Timeout -gt 0 ]]
    do
        # Get WWPNs under /sys/bus/ccw/drivers/zfcp/.
        wwpns_shown_in_sys=`ls /sys/bus/ccw/drivers/zfcp/0.0.$fcp/ | grep "0x"`
        echo -e "Target WWPNs shown under /sys/bus/ccw/drivers/zfcp/0.0.$fcp/:\n$wwpns_shown_in_sys"
        # Try to find match between system WWPNs(from lszfcp output or under /sys) and input WWPNs
        found_match=0
        for wwpn in ${input_wwpns[@]}
        do
            fcp_wwpn_str="0.0.${fcp} ${wwpn}"
            if [[ $lszfcp_output =~ $fcp_wwpn_str || $wwpns_shown_in_sys =~ $wwpn ]]; then
                found_match=1
                echo "$fcp_wwpn_str matched with the ouput of lszfcp or WWPNs shown under /sys/bus/ccw/drivers/zfcp/."
                # Add this combination into valid_dict
                if [[ -z ${valid_dict[$fcp]} ]]; then
                    valid_dict+=([$fcp]="$wwpn")
                else
                    old_value=${valid_dict[$fcp]}
                    new_value=${old_value}" "$wwpn
                    valid_dict[$fcp]=$new_value
                fi
            fi
        done
        # If no matched wwpn found, need retry
        if [[ $found_match -eq 0 ]]; then
            sleep 1
            Timeout=$((Timeout-1))
            echo "Retrying to get the target WWPNs for FCP device $fcp, $Timeout seconds left..."
            lszfcp_output=`lszfcp -P | awk '{print $1}' | awk -F'/' '{print $1,$2}'`
        else
            echo "Found target WWPNs ${valid_dict[$fcp]} for FCP device $fcp."
            break
        fi
    done
done
echo "Got valid wwpns, list of key is: ${!valid_dict[@]}, list of value is: ${valid_dict[@]} ."

# check the content of valid_dict, if no content, return error
valid_fcp_count=0
for fcp in ${!valid_dict[@]}
do
    valid_fcp_count=$((valid_fcp_count+=1))
done
if [[ $valid_fcp_count -eq 0 ]]; then
    echo "Can not find the intersection between input wwpns: ${input_wwpns[@]} and lszfcp output: $lszfcp_output, exit with code $INVALID_WWPNS."
    exit $INVALID_WWPNS
fi

# flag which indicate whether we found a valid and accessable path for the volume
FoundDiskPath=0
# wait for the device ready
for fcp in ${!valid_dict[@]}
do
    ActiveWWPNs=(${valid_dict[$fcp]})
    echo "Discover WWPNs: ${ActiveWWPNs[@]} for FCP device: $fcp"
    
    # If auto-discovery of LUNs is disabled on s390 platforms
    # luns need to be added to the configuration through
    # the unit_add interface
    AutoLunScan=`cat /sys/module/zfcp/parameters/allow_lun_scan`
    if [[ "$AutoLunScan" != "Y" ]]; then
        echo "Auto LUN scan is disabled, so manually configure the SCSI devices."
        for wwpn in ${ActiveWWPNs[@]}
        do
            echo "Begin to register SCSI device 0.0.$fcp:$wwpn:$lun ..."
            /sbin/chzdev zfcp-lun 0.0.$fcp:$wwpn:$lun -e
            echo "Registration for SCSI device 0.0.$fcp:$wwpn:$lun was done"
        done
    fi

    echo "Start to execute udev settle"
    if [[ $(which udevadm 2> /dev/null) != '' ]]; then
        udevadm settle
        echo "Execution of udevadm settle was done"
    else
        udevsettle
        echo "Execution of udevsettle was done"
    fi

    # wait for the devices ready
    # timeout set to 10 seconds
    Timeout=10
    while [ $FoundDiskPath -eq 0 ]
    do
        # if timeout less or equal 0 seconds, means no time left
        if [ $Timeout -le 0 ]; then
            echo "Waiting for devices ready timed out after 10 seconds."
            break
        fi

        # loop all the WWPNs to found the alive device
        for j in ${ActiveWWPNs[@]}
        do
            x="/dev/disk/by-path/ccw-0.0.$fcp-fc-$j-lun-$lun_id"
            # the x would be like:
            # ccw-0.0.1d13-zfcp-0x5005076306035388:0x4014400400000000
            echo "Try to detect disk $x"
            if [ -e $x ]; then
                echo "Disk $x detected"
                diskPath=$x
                FoundDiskPath=1
                break
            fi
        done
        # if devices still not ready, wait another 5 seconds and retry
        if [ $FoundDiskPath -eq 0 ]; then
            sleep 1
            Timeout=$((Timeout-=1))
            echo "Sleep 1 second to wait the devices ready, timeout left: $Timeout"
        fi
    done
done

if [ $FoundDiskPath -eq 1 ]; then
    echo "The storage device is ready and found disk path: $diskPath."
else
    echo "Error happens during attachment because the device file of $fcp not found, will exit with code $DEVICE_PATH_NOT_FOUND."
    exit $DEVICE_PATH_NOT_FOUND
fi

WWID=`/lib/udev/scsi_id --page 0x83 --whitelisted $diskPath`
echo "scsi_id command get WWID:$WWID for device $diskPath."

ConfigLib="/lib/udev/rules.d/56-zfcp.rules"
if [ -e "$ConfigLib" ]
then
    ConfigFile="/lib/udev/rules.d/56-zfcp.rules"
else
    ConfigFile="/etc/udev/rules.d/56-zfcp.rules"
fi

LinkItem="KERNEL==\"dm-*\", ENV{DM_UUID}==\"mpath-$WWID\", SYMLINK+=\"$target_filename\""
echo -e $LinkItem >> $ConfigFile

echo "Begin to reload udev rules ..."
udevadm control --reload
udevadm trigger --sysname-match=dm-*
echo "Undev rules reload done"

echo "Exit UBUNTU attach script"
exit $OK

