#!/bin/bash -e # # Open-iSCSI Xen block device hotplug script # # Author Roger Pau Monné # # 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=,portal= # # 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" fi if [ "$multipath" = "y" ] && ! command -v multipath > /dev/null 2>&1; then fatal "Unable to find multipath" 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" fi if [ "$multipath" != "y" ] && [ "$multipath" != "n" ]; then fatal "multipath valid values are y and n, $multipath not a valid value" fi } # 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" fi done sddev=$(readlink -f /dev/disk/by-path/*"$iqn"-lun-0 || true) if [ ! -b "$sddev" ]; then fatal "Unable to find attached device path" 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" fi dev="/dev/mapper/$mdev" else dev="$sddev" fi } # Attaches the target $iqn in $portal and sets $dev to point to the # multipath device attach() { do_or_die iscsiadm -m node --targetname "$iqn" -p "$portal" --login > /dev/null find_device } # 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 iscsiadm -m session 2>&1 | grep -q "$iqn" && fatal "Device already opened" # Discover portal targets iscsiadm -m discovery -t st -p $portal 2>&1 | grep -q "$iqn" || \ fatal "No matching target iqn found" } # Attaches the device and writes xenstore backend entries to connect # the device add() { attach write_dev $dev } # Disconnects the device remove() { find_device do_or_die iscsiadm -m node --targetname "$iqn" -p "$portal" --logout > /dev/null } command=$1 target=$(xenstore-read $XENBUS_PATH/params || true) if [ -z "$target" ]; then fatal "No information about the target" fi parse_target "$target" check_tools || exit 1 case $command in add) prepare add ;; remove) remove ;; *) exit 1 ;; esac