[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH v2] hotplug/Linux: add iscsi block hotplug script



On 26/04/13 17:17, Ian Campbell wrote:
> On Fri, 2013-04-26 at 14:30 +0100, Roger Pau Monne wrote:
>> This hotplug script has been tested with IET and NetBSD iSCSI targets,
>> without authentication.
>>
>> This hotplug script will only work with PV guests not using pygrub.
>>
>> Signed-off-by: Roger Pau Monnà <roger.pau@xxxxxxxxxx>
>> Cc: Ian Campbell <ian.campbell@xxxxxxxxxx>
>> Cc: Ian Jackson <ian.jackson@xxxxxxxxxx>
>> ---
>> Changes since v1:
>>  * Added an example in the script header to show the usage.
>>  * Changed shebang to use bash.
>>  * Replace type with command, for portability reasons.
>>  * Replace echo with fatal/log functions.
>>  * Include block-common.sh.
>>  * Prevent infinite loop when waitign for device to settle.
>>  * Only redirect stdout to /dev/null.
>> Changes due to 4.3 release freeze:
>>  * We can no longer provide a user/password, because they will be
>>    stored in xenstore "params" backend node, which can be read by the
>>    guest.
>>  * Only works with PV domains because we don't have a hook in libxl to
>>    pass the block device created by the script to Qemu.
>>  * Doesn't work with pygrub because we don't call the script until
>>    pygrub has already been executed, and even if we called it earlier
>>    we still need a hook in order to provide the right block device to
>>    pygrub.
>> Changes since v1:
>>  * Add -e to script shebang, and use 'set +e' if we know hotplug
>>    execution might fail.
>> ---
>>  tools/hotplug/Linux/Makefile    |    1 +
>>  tools/hotplug/Linux/block-iscsi |  209 
>> +++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 210 insertions(+), 0 deletions(-)
>>  create mode 100644 tools/hotplug/Linux/block-iscsi
>>
>> diff --git a/tools/hotplug/Linux/Makefile b/tools/hotplug/Linux/Makefile
>> index 0605559..98c7738 100644
>> --- a/tools/hotplug/Linux/Makefile
>> +++ b/tools/hotplug/Linux/Makefile
>> @@ -21,6 +21,7 @@ XEN_SCRIPTS += blktap
>>  XEN_SCRIPTS += xen-hotplug-cleanup
>>  XEN_SCRIPTS += external-device-migrate
>>  XEN_SCRIPTS += vscsi
>> +XEN_SCRIPTS += block-iscsi
>>  XEN_SCRIPT_DATA = xen-script-common.sh locking.sh logging.sh
>>  XEN_SCRIPT_DATA += xen-hotplug-common.sh xen-network-common.sh vif-common.sh
>>  XEN_SCRIPT_DATA += block-common.sh
>> diff --git a/tools/hotplug/Linux/block-iscsi 
>> b/tools/hotplug/Linux/block-iscsi
>> new file mode 100644
>> index 0000000..9f74c20
>> --- /dev/null
>> +++ b/tools/hotplug/Linux/block-iscsi
>> @@ -0,0 +1,209 @@
>> +#!/bin/bash -e
>> +#
>> +# Open-iSCSI Xen block device hotplug script
>> +#
>> +# Author Roger Pau Monnà <roger.pau@xxxxxxxxxx>
>> +#
>> +# This program is free software; you can redistribute it and/or modify
>> +# it under the terms of the GNU Lesser General Public License as published
>> +# by the Free Software Foundation; version 2.1 only. with the special
>> +# exception on linking described in file LICENSE.
>> +#
>> +# This program is distributed in the hope that it will be useful,
>> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
>> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> +# GNU Lesser General Public License for more details.
>> +#
>> +# Usage:
>> +#
>> +# Target should be specified using the following syntax:
>> +#
>> +# script=block-iscsi,vdev=xvda,target=iqn=<iqn>,portal=<portal IP>
>> +#
>> +# Portal address must be in IP format.
>> +#
>> +
>> +dir=$(dirname "$0")
>> +. "$dir/block-common.sh"
>> +
>> +remove_label()
>> +{
>> +    echo $1 | sed "s/^\("$2"\)//"
>> +}
>> +
>> +check_tools()
>> +{
>> +    if ! command -v iscsiadm > /dev/null 2>&1; then
>> +        fatal "Unable to find iscsiadm tool"
>> +        return 1
>> +    fi
>> +    if [ "$multipath" = "y" ] && ! command -v multipath > /dev/null 2>&1; 
>> then
>> +        fatal "Unable to find multipath"
> 
> this isn't critical unless the user asked for multipath I think?

That's why we check for $multipath = "y", if the user requested
multipath and the hotplug script cannot find it, crash.

> 
>> +        return 1
>> +    fi
>> +}
>> +
>> +# Sets the following global variables based on the params field passed in as
>> +# a parameter: iqn, portal, auth_method, user, multipath, password
>> +parse_target()
>> +{
>> +    # set multipath default value
>> +    multipath="n"
>> +    for param in $(echo "$1" | tr "," "\n")
>> +    do
>> +        case $param in
>> +        iqn=*)
>> +            iqn=$(remove_label $param "iqn=")
>> +            ;;
>> +        portal=*)
>> +            portal=$(remove_label $param "portal=")
>> +            ;;
>> +        multipath=*)
>> +            multipath=$(remove_label $param "multipath=")
>> +            ;;
>> +        esac
>> +    done
>> +    if [ -z "$iqn" ] || [ -z "$portal" ]; then
>> +        fatal "iqn= and portal= are required parameters"
>> +        return 1
>> +    fi
>> +    if [ "$multipath" != "y" ] && [ "$multipath" != "n" ]; then
>> +        fatal "multipath valid values are y and n, $multipath not a valid 
>> value"
>> +        return 1
> 
> fatal already exits.

Ack, will change all occurrences.

> 
>> +    fi
>> +    return 0
>> +}
>> +
>> +# Sets $dev to point to the device associated with the value in iqn
>> +find_device()
>> +{
>> +    count=0
>> +    while [ ! -e /dev/disk/by-path/*"$iqn"-lun-0 ]; do
>> +        sleep 0.1
>> +        count=`expr $count + 1`
>> +        if [ count = 100 ]; then
>> +            # 10s timeout while waiting for iSCSI disk to settle
>> +            fatal "timeout waiting for iSCSI disk to settle"
>> +            return 1
>> +        fi
>> +    done
>> +    sddev=$(readlink -f /dev/disk/by-path/*"$iqn"-lun-0 || true)
>> +    if [ ! -b "$sddev" ]; then
>> +        fatal "Unable to find attached device path"
>> +        return 1
>> +    fi
>> +    if [ "$multipath" = "y" ]; then
>> +        mdev=$(multipath -ll "$sddev" | head -1 | awk '{ print $1}')
>> +        if [ ! -b /dev/mapper/"$mdev" ]; then
>> +            fatal "Unable to find attached device multipath"
>> +            return 1
>> +        fi
>> +        dev="/dev/mapper/$mdev"
>> +    else
>> +        dev="$sddev"
>> +    fi
>> +    return 0
>> +}
>> +
>> +# Attaches the target $iqn in $portal and sets $dev to point to the
>> +# multipath device
>> +attach()
>> +{
>> +    set +e
>> +    iscsiadm -m node --targetname "$iqn" -p "$portal" --login > /dev/null
>> +    rc=$?
>> +    set -e
>> +    if [ $rc -ne 0 ]; then
>> +        fatal "Unable to connect to target"
>> +        return 1
>> +    fi
> 
> This is roughly the same as do_or_die iscsiadm -m node etc , apart from
> the specifics of the log message.
> 
> If you want to keep the message as is then is it the same as 
>       iscsiadm -m node ... || fatal "Unable,..."

I've switched to do_or_die, at the end the message didn't provide much
more info, and it's probably better to print the command that failed.

>> +    find_device
> 
> set -e is back in force here, so won't this barf before you have a
> chance to check $? 
> 
> In fact now I look at it find device either calls fatal (and exits) or
> returns 0...

Yes, since the script calls fatal I've removed all the checks for the
return values of internal functions.

> 
>> +    if [ $? -ne 0 ]; then
>> +        fatal "Unable to find iSCSI device"
>> +        return 1
>> +    fi
>> +    return 0
>> +}
>> +
>> +# Discovers targets in $portal and checks that $iqn is one of those targets
>> +# Also sets the auth parameters to attach the device
>> +prepare()
>> +{
>> +    # Check if target is already opened
>> +    set +e
>> +    iscsiadm -m session 2>&1 | grep -q "$iqn"
> 
> Does the use of a pipe here make this incompatible with do_or_die? or
> the use of || fatal "mmm"?

In this specific case I should use &&, because we expect the command to
fail.

> 
>> +    rc=$?
>> +    set -e
>> +    if [ $rc -eq 0 ]; then
>> +        fatal "Device already opened"
>> +        return 1
>> +    fi
>> +    # Discover portal targets
>> +    set +e
>> +    iscsiadm -m discovery -t st -p $portal 2>&1 | grep -q "$iqn"

Here a || is appropriate.

>> +    rc=$?
>> +    set -e
>> +    if [ $rc -ne 0 ]; then
>> +        fatal "No matching target iqn found"
>> +        return 1
>> +    fi
>> +    return 0
>> +}
>> +
>> +# Attaches the device and writes xenstore backend entries to connect
>> +# the device
>> +add()
>> +{
>> +    attach
>> +    if [ $? -ne 0 ]; then
>> +        fatal "Failed to attach device"
>> +        return 1
>> +    fi
> 
> attach either succeeds or exits.

Done.

> 
>> +    write_dev $dev
>> +    return 0
>> +}
>> +
>> +# Disconnects the device
>> +remove()
>> +{
>> +    find_device
>> +    if [ $? -ne 0 ]; then
>> +        fatal "Unable to find device"
>> +        return 1
>> +    fi
>> +    set +e
>> +    iscsiadm -m node --targetname "$iqn" -p "$portal" --logout > /dev/null
>> +    rc=$?
>> +    set -e
>> +    if [ $rc -ne 0 ]; then
>> +        fatal "Unable to disconnect target"
>> +        return 1
>> +    fi
>> +    return 0
>> +}
>> +
>> +command=$1
>> +target=$(xenstore-read $XENBUS_PATH/params || true)
>> +if [ -z "$target" ]; then
>> +    fatal "No information about the target"
>> +    exit 1
>> +fi
>> +
>> +parse_target "$target"
>> +
>> +check_tools || exit 1
>> +
>> +case $command in
>> +add)
>> +    prepare
>> +    add
>> +    exit $?
>> +    ;;
>> +remove)
>> +    remove
>> +    exit $?
>> +    ;;
>> +*)
>> +    exit 1
>> +    ;;
>> +esac

I'm going to send v3 ASAP with all the comments addressed.


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.