summaryrefslogtreecommitdiffstats
path: root/heartbeat/iSCSITarget.in
diff options
context:
space:
mode:
Diffstat (limited to 'heartbeat/iSCSITarget.in')
-rw-r--r--heartbeat/iSCSITarget.in766
1 files changed, 766 insertions, 0 deletions
diff --git a/heartbeat/iSCSITarget.in b/heartbeat/iSCSITarget.in
new file mode 100644
index 0000000..2a9ddf0
--- /dev/null
+++ b/heartbeat/iSCSITarget.in
@@ -0,0 +1,766 @@
+#!@BASH_SHELL@
+#
+#
+# iSCSITarget OCF RA. Exports and manages iSCSI targets.
+#
+# (c) 2009-2010 Florian Haas, Dejan Muhamedagic,
+# and Linux-HA contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of version 2 of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#
+# Further, this software is distributed without any warranty that it is
+# free of the rightful claim of any third person regarding infringement
+# or the like. Any license provided herein, whether implied or
+# otherwise, applies only to this software file. Patent licenses, if
+# any, provided herein do not apply to combinations of this program with
+# other software, or any other product whatsoever.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+#
+
+#######################################################################
+# Initialization:
+: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
+. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
+
+# Defaults
+# Set a default implementation based on software installed
+if have_binary ietadm; then
+ OCF_RESKEY_implementation_default="iet"
+elif have_binary tgtadm; then
+ OCF_RESKEY_implementation_default="tgt"
+elif have_binary lio_node; then
+ OCF_RESKEY_implementation_default="lio"
+elif have_binary targetcli; then
+ OCF_RESKEY_implementation_default="lio-t"
+elif have_binary scstadmin; then
+ OCF_RESKEY_implementation_default="scst"
+fi
+: ${OCF_RESKEY_implementation=${OCF_RESKEY_implementation_default}}
+
+# Listen on 0.0.0.0:3260 by default
+OCF_RESKEY_portals_default="0.0.0.0:3260"
+: ${OCF_RESKEY_portals=${OCF_RESKEY_portals_default}}
+
+OCF_RESKEY_allowed_initiators_default=""
+: ${OCF_RESKEY_allowed_initiators=${OCF_RESKEY_allowed_initiators_default}}
+
+# Lockfile, used for selecting a target ID
+LOCKFILE=${HA_RSCTMP}/iSCSITarget-${OCF_RESKEY_implementation}.lock
+
+# targetcli: iSCSITarget and iSCSILogicalUnit must use the same lockfile
+TARGETLOCKFILE=${HA_RSCTMP}/targetcli.lock
+
+# Timeout for waiting for initiators to log out (only used in scst)
+INIT_LOGOUT_TIMEOUT=20
+#######################################################################
+
+meta_data() {
+ cat <<END
+<?xml version="1.0"?>
+<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
+<resource-agent name="iSCSITarget" version="0.9">
+<version>1.0</version>
+
+<longdesc lang="en">
+Manages iSCSI targets. An iSCSI target is a collection of SCSI Logical
+Units (LUs) exported via a daemon that speaks the iSCSI protocol.
+</longdesc>
+<shortdesc lang="en">iSCSI target export agent</shortdesc>
+
+<parameters>
+<parameter name="implementation" required="0" unique="0">
+<longdesc lang="en">
+The iSCSI target daemon implementation. Must be one of "iet", "tgt",
+"lio", "lio-t", or "scst". If unspecified, an implementation is selected based on the
+availability of management utilities, with "iet" being tried first,
+then "tgt", then "lio", then "lio-t", then "scst".
+</longdesc>
+<shortdesc lang="en">Specifies the iSCSI target implementation
+("iet", "tgt", "lio", "lio-t", or "scst").</shortdesc>
+<content type="string" default="${OCF_RESKEY_implementation_default}"/>
+</parameter>
+
+<parameter name="iqn" required="1" unique="1">
+<longdesc lang="en">
+The target iSCSI Qualified Name (IQN). Should follow the conventional
+"iqn.yyyy-mm.&lt;reversed domain name&gt;[:identifier]" syntax.
+</longdesc>
+<shortdesc lang="en">iSCSI target IQN</shortdesc>
+<content type="string" />
+</parameter>
+
+<parameter name="tid" required="0" unique="1">
+<longdesc lang="en">
+The iSCSI target ID. Required for tgt.
+</longdesc>
+<shortdesc lang="en">iSCSI target ID</shortdesc>
+<content type="integer" />
+</parameter>
+
+<parameter name="portals" required="0" unique="0">
+<longdesc lang="en">
+iSCSI network portal addresses. Not supported by all
+implementations. If unset, the default is to create one portal that
+listens on ${OCF_RESKEY_portal_default}.
+</longdesc>
+<shortdesc lang="en">iSCSI portal addresses</shortdesc>
+<content type="string" default="${OCF_RESKEY_portals_default}"/>
+</parameter>
+
+<parameter name="iser_portals" required="0" unique="0">
+<longdesc lang="en">
+iSCSI iSER network portal addresses. Not supported by all
+implementations.
+</longdesc>
+<shortdesc lang="en">iSCSI iSER enabled portal addresses</shortdesc>
+<content type="string"/>
+</parameter>
+
+<parameter name="allowed_initiators" required="0" unique="0">
+<longdesc lang="en">
+Allowed initiators. A space-separated list of initiators allowed to
+connect to this target. Initiators may be listed in any syntax
+the target implementation allows. If this parameter is empty or
+not set, access to this target will be allowed from any initiator.
+</longdesc>
+<shortdesc lang="en">List of iSCSI initiators allowed to connect
+to this target</shortdesc>
+<content type="string" default="${OCF_RESKEY_allowed_initiators_default}"/>
+</parameter>
+
+<parameter name="incoming_username" required="0" unique="1">
+<longdesc lang="en">
+A username used for incoming initiator authentication. If unspecified,
+allowed initiators will be able to log in without authentication.
+This is a unique parameter, as it not allowed to re-use a single
+username across multiple target instances.
+</longdesc>
+<shortdesc lang="en">Incoming account username</shortdesc>
+<content type="string"/>
+</parameter>
+
+<parameter name="incoming_password" required="0" unique="0">
+<longdesc lang="en">
+A password used for incoming initiator authentication.
+</longdesc>
+<shortdesc lang="en">Incoming account password</shortdesc>
+<content type="string"/>
+</parameter>
+
+<parameter name="additional_parameters" required="0" unique="0">
+<longdesc lang="en">
+Additional target parameters. A space-separated list of "name=value"
+pairs which will be passed through to the iSCSI daemon's management
+interface. The supported parameters are implementation
+dependent. Neither the name nor the value may contain whitespace.
+</longdesc>
+<shortdesc lang="en">List of iSCSI target parameters</shortdesc>
+<content type="string" />
+</parameter>
+
+</parameters>
+
+<actions>
+<action name="start" timeout="10s" />
+<action name="stop" timeout="10s" />
+<action name="status" timeout="10s" interval="10s" depth="0" />
+<action name="monitor" timeout="10s" interval="10s" depth="0" />
+<action name="meta-data" timeout="5s" />
+<action name="validate-all" timeout="10s" />
+</actions>
+</resource-agent>
+END
+}
+
+#######################################################################
+
+iSCSITarget_usage() {
+ cat <<END
+usage: $0 {start|stop|status|monitor|validate-all|meta-data}
+
+Expects to have a fully populated OCF RA-compliant environment set.
+END
+}
+
+iSCSITarget_start() {
+ iSCSITarget_monitor
+ if [ $? = $OCF_SUCCESS ]; then
+ return $OCF_SUCCESS
+ fi
+
+ local param
+ local name
+ local value
+ local initiator
+ local portal
+
+ case $OCF_RESKEY_implementation in
+ iet)
+ local lasttid
+ local tid
+ if [ "${OCF_RESKEY_tid}" ]; then
+ tid="${OCF_RESKEY_tid}"
+ else
+ # Figure out the last used target ID, add 1 to get the new
+ # target ID.
+ ocf_take_lock $LOCKFILE
+ ocf_release_lock_on_exit $LOCKFILE
+ lasttid=`sed -ne "s/tid:\([[:digit:]]\+\) name:.*/\1/p" < /proc/net/iet/volume | sort -n | tail -n1`
+ [ -z "${lasttid}" ] && lasttid=0
+ tid=$((++lasttid))
+ fi
+
+ # Create the target.
+ ocf_run ietadm --op new \
+ --tid=${tid} \
+ --params Name=${OCF_RESKEY_iqn} || exit $OCF_ERR_GENERIC
+
+ # Set additional parameters.
+ for param in ${OCF_RESKEY_additional_parameters}; do
+ name=${param%=*}
+ value=${param#*=}
+ ocf_run ietadm --op update \
+ --tid=${tid} \
+ --params ${name}=${value} || exit $OCF_ERR_GENERIC
+ done
+
+ # Legacy versions of IET allow targets by default, current
+ # versions deny. To be safe we manage both the .allow and
+ # .deny files.
+ if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then
+ echo "${OCF_RESKEY_iqn} ALL" >> /etc/initiators.deny
+ echo "${OCF_RESKEY_iqn} ${OCF_RESKEY_allowed_initiators// /,}" >> /etc/initiators.allow
+ else
+ echo "${OCF_RESKEY_iqn} ALL" >> /etc/initiators.allow
+ fi
+ # In iet, adding a new user and assigning it to a target
+ # is one operation.
+ if [ -n "${OCF_RESKEY_incoming_username}" ]; then
+ ocf_run ietadm --op new --user \
+ --tid=${tid} \
+ --params=IncomingUser=${OCF_RESKEY_incoming_username},Password=${OCF_RESKEY_incoming_password} \
+ || exit $OCF_ERR_GENERIC
+ fi
+ ;;
+ tgt)
+ local tid
+ tid="${OCF_RESKEY_tid}"
+ # Create the target.
+ ocf_run tgtadm --lld iscsi --op new --mode target \
+ --tid=${tid} \
+ --targetname ${OCF_RESKEY_iqn} || exit $OCF_ERR_GENERIC
+
+ # Set parameters.
+ for param in ${OCF_RESKEY_additional_parameters}; do
+ name=${param%=*}
+ value=${param#*=}
+ ocf_run tgtadm --lld iscsi --op update --mode target \
+ --tid=${tid} \
+ --name=${name} --value=${value} || exit $OCF_ERR_GENERIC
+ done
+
+ # For tgt, we always have to add access per initiator;
+ # access to targets is denied by default. If
+ # "allowed_initiators" is unset, we must use the special
+ # keyword ALL.
+ for initiator in ${OCF_RESKEY_allowed_initiators=ALL}; do
+ ocf_run tgtadm --lld iscsi --op bind --mode target \
+ --tid=${tid} \
+ --initiator-address=${initiator} || exit $OCF_ERR_GENERIC
+ done
+
+ # In tgt, we must first create a user account, then assign
+ # it to a target using the "bind" operation.
+ if [ -n "${OCF_RESKEY_incoming_username}" ]; then
+ ocf_run tgtadm --lld iscsi --mode account --op new \
+ --user=${OCF_RESKEY_incoming_username} \
+ --password=${OCF_RESKEY_incoming_password} || exit $OCF_ERR_GENERIC
+ ocf_run tgtadm --lld iscsi --mode account --op bind \
+ --tid=${tid} \
+ --user=${OCF_RESKEY_incoming_username} || exit $OCF_ERR_GENERIC
+ fi
+ ;;
+ lio)
+ # lio distinguishes between targets and target portal
+ # groups (TPGs). We will always create one TPG, with the
+ # number 1. In lio, creating a network portal
+ # automatically creates the corresponding target if it
+ # doesn't already exist.
+ for portal in ${OCF_RESKEY_portals}; do
+ ocf_run lio_node --addnp ${OCF_RESKEY_iqn} 1 \
+ ${portal} || exit $OCF_ERR_GENERIC
+ done
+
+ # in lio, we can set target parameters by manipulating
+ # the appropriate configfs entries
+ for param in ${OCF_RESKEY_additional_parameters}; do
+ name=${param%=*}
+ value=${param#*=}
+ configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn}/tpgt_1/param/${name}"
+ if [ -e ${configfs_path} ]; then
+ echo ${value} > ${configfs_path} || exit $OCF_ERR_GENERIC
+ else
+ ocf_log warn "Unsupported iSCSI target parameter ${name}: will be ignored."
+ fi
+ done
+
+ # lio does per-initiator filtering by default. To disable
+ # this, we need to switch the target to "permissive mode".
+ if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then
+ for initiator in ${OCF_RESKEY_allowed_initiators}; do
+ ocf_run lio_node --addnodeacl ${OCF_RESKEY_iqn} 1 \
+ ${initiator} || exit $OCF_ERR_GENERIC
+ done
+ else
+ ocf_run lio_node --permissive ${OCF_RESKEY_iqn} 1 || exit $OCF_ERR_GENERIC
+ # permissive mode enables read-only access by default,
+ # so we need to change that to RW to be in line with
+ # the other implementations.
+ echo 0 > "/sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn}/tpgt_1/attrib/demo_mode_write_protect"
+ if [ `cat /sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn}/tpgt_1/attrib/demo_mode_write_protect` -ne 0 ]; then
+ ocf_log err "Failed to disable write protection for target ${OCF_RESKEY_iqn}."
+ exit $OCF_ERR_GENERIC
+ fi
+ fi
+
+ # TODO: add CHAP authentication support when it gets added
+ # back into LIO
+ ocf_run lio_node --disableauth ${OCF_RESKEY_iqn} 1 || exit $OCF_ERR_GENERIC
+ # Finally, we need to enable the target to allow
+ # initiators to connect
+ ocf_run lio_node --enabletpg=${OCF_RESKEY_iqn} 1 || exit $OCF_ERR_GENERIC
+ ;;
+ lio-t)
+ # lio distinguishes between targets and target portal
+ # groups (TPGs). We will always create one TPG, with the
+ # number 1. In lio, creating a network portal
+ # automatically creates the corresponding target if it
+ # doesn't already exist.
+ ocf_take_lock $TARGETLOCKFILE
+ ocf_release_lock_on_exit $TARGETLOCKFILE
+ ocf_run targetcli /iscsi set global auto_add_default_portal=false || exit $OCF_ERR_GENERIC
+ if ! [ -d /sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn} ] ; then
+ ocf_run targetcli /iscsi create ${OCF_RESKEY_iqn} || exit $OCF_ERR_GENERIC
+ fi
+ for portal in ${OCF_RESKEY_portals}; do
+ if [ $portal != ${OCF_RESKEY_portals_default} ] ; then
+ IFS=':' read -a sep_portal <<< "$portal"
+ ocf_run targetcli /iscsi/${OCF_RESKEY_iqn}/tpg1/portals create "${sep_portal[0]}" "${sep_portal[1]}" || exit $OCF_ERR_GENERIC
+ fi
+ done
+ # in lio, we can set target parameters by manipulating
+ # the appropriate configfs entries
+ for param in ${OCF_RESKEY_additional_parameters}; do
+ name=${param%=*}
+ value=${param#*=}
+ configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn}/tpgt_1/param/${name}"
+ if [ -e ${configfs_path} ]; then
+ echo ${value} > ${configfs_path} || exit $OCF_ERR_GENERIC
+ else
+ ocf_log warn "Unsupported iSCSI target parameter ${name}: will be ignored."
+ fi
+ done
+
+ # allow iSER enabled portal
+ for iser_portal in ${OCF_RESKEY_iser_portals}; do
+ configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn}/tpgt_1/np/${iser_portal}\:*/iser"
+ if [ -f ${configfs_path} ]; then
+ echo "1" > ${configfs_path} || exit $OCF_ERR_GENERIC
+ else
+ ocf_log warn "Unable to set iSER on: $iser_portal"
+ fi
+ done
+
+ # lio does per-initiator filtering by default. To disable
+ # this, we need to switch the target to "permissive mode".
+ if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then
+ # enable authentication for tpg1 if incoming_username
+ # is defined
+ if [ -n "${OCF_RESKEY_incoming_username}" ]; then
+ ocf_run targetcli /iscsi/${OCF_RESKEY_iqn}/tpg1/ set attribute authentication=1 || exit $OCF_ERR_GENERIC
+ ocf_run targetcli /iscsi/${OCF_RESKEY_iqn}/tpg1/ set attribute generate_node_acls=0 || exit $OCF_ERR_GENERIC
+ fi
+ for initiator in ${OCF_RESKEY_allowed_initiators}; do
+ ocf_run targetcli /iscsi/${OCF_RESKEY_iqn}/tpg1/acls create ${initiator} || exit $OCF_ERR_GENERIC
+ # enable chap if incoming_username is defined
+ if [ -n "${OCF_RESKEY_incoming_username}" ]; then
+ ocf_run targetcli /iscsi/${OCF_RESKEY_iqn}/tpg1/acls/${initiator}/ set auth userid=${OCF_RESKEY_incoming_username} || exit $OCF_ERR_GENERIC
+ ocf_run targetcli /iscsi/${OCF_RESKEY_iqn}/tpg1/acls/${initiator}/ set auth password=${OCF_RESKEY_incoming_password} || exit $OCF_ERR_GENERIC
+ fi
+ done
+ else
+ if [ -n "${OCF_RESKEY_incoming_username}" ]; then
+ ocf_run targetcli /iscsi/${OCF_RESKEY_iqn}/tpg1/ set attribute authentication=1 demo_mode_write_protect=0 generate_node_acls=1 cache_dynamic_acls=1 || exit $OCF_ERR_GENERIC
+ ocf_run targetcli /iscsi/${OCF_RESKEY_iqn}/tpg1/ set auth userid=${OCF_RESKEY_incoming_username} || exit $OCF_ERR_GENERIC
+ ocf_run targetcli /iscsi/${OCF_RESKEY_iqn}/tpg1/ set auth password=${OCF_RESKEY_incoming_password} || exit $OCF_ERR_GENERIC
+ else
+ ocf_run targetcli /iscsi/${OCF_RESKEY_iqn}/tpg1/ set attribute authentication=0 demo_mode_write_protect=0 generate_node_acls=1 cache_dynamic_acls=1 || exit $OCF_ERR_GENERIC
+ fi
+ fi
+ ;;
+ scst)
+ ocf_run scstadmin -add_target ${OCF_RESKEY_iqn} -driver iscsi
+
+ for portal in ${OCF_RESKEY_portals}; do
+ # scst only wants the IP address for some reason, so strip the port
+ portal_ip="${portal%%:*}"
+ ocf_run scstadmin -add_tgt_attr ${OCF_RESKEY_iqn} -driver iscsi -attributes "allowed_portal=${portal_ip}"
+ done
+ ocf_run scstadmin -add_group allowed -driver iscsi -target ${OCF_RESKEY_iqn}
+ if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then
+ for initiator in ${OCF_RESKEY_allowed_initiators}; do
+ ocf_run scstadmin -add_init ${initiator} -group allowed -driver iscsi -target ${OCF_RESKEY_iqn}
+ done
+ fi
+
+ if [ "${OCF_RESKEY_incoming_username}" != "" ]; then
+ ocf_run scstadmin -add_tgt_attr ${OCF_RESKEY_iqn} -driver iscsi -attributes "IncomingUser ${OCF_RESKEY_incoming_username} ${OCF_RESKEY_incoming_password}"
+ fi
+
+ ocf_run scstadmin -enable_target ${OCF_RESKEY_iqn} -driver iscsi
+ echo 1 > /sys/kernel/scst_tgt/targets/iscsi/enabled
+ ;;
+ esac
+
+ iSCSITarget_monitor
+}
+
+iSCSITarget_stop() {
+ iSCSITarget_monitor
+ if [ $? -eq $OCF_NOT_RUNNING ]; then
+ return $OCF_SUCCESS
+ fi
+
+ local tid
+ case $OCF_RESKEY_implementation in
+ iet)
+ # Figure out the target ID
+ tid=`sed -ne "s/tid:\([[:digit:]]\+\) name:${OCF_RESKEY_iqn}/\1/p" < /proc/net/iet/volume`
+ if [ -z "${tid}" ]; then
+ ocf_log err "Failed to retrieve target ID for IQN ${OCF_RESKEY_iqn}"
+ exit $OCF_ERR_GENERIC
+ fi
+ # Close existing connections. There is no other way to
+ # do this in IET than to parse the contents of
+ # /proc/net/iet/session.
+ set -- $(sed -ne '/^tid:'${tid}' /,/^tid/ {
+ /^[[:space:]]*sid:\([0-9]\+\)/ {
+ s/^[[:space:]]*sid:\([0-9]*\).*/--sid=\1/; h;
+ };
+ /^[[:space:]]*cid:\([0-9]\+\)/ {
+ s/^[[:space:]]*cid:\([0-9]*\).*/--cid=\1/; G; p;
+ };
+ }' < /proc/net/iet/session)
+ while [[ -n $2 ]]; do
+ # $2 $1 looks like "--sid=X --cid=Y"
+ ocf_run ietadm --op delete \
+ --tid=${tid} $2 $1
+ shift 2
+ done
+ # In iet, unassigning a user from a target and
+ # deleting the user account is one operation.
+ if [ -n "${OCF_RESKEY_incoming_username}" ]; then
+ ocf_run ietadm --op delete --user \
+ --tid=${tid} \
+ --params=IncomingUser=${OCF_RESKEY_incoming_username} \
+ || exit $OCF_ERR_GENERIC
+ fi
+ # Loop on delete. Keep trying until we time out, if
+ # necessary.
+ while true; do
+ if ietadm --op delete --tid=${tid}; then
+ ocf_log debug "Removed target ${OCF_RESKEY_iqn}."
+ break
+ else
+ ocf_log warn "Failed to remove target ${OCF_RESKEY_iqn}, retrying."
+ sleep 1
+ fi
+ done
+ # Avoid stale /etc/initiators.{allow,deny} entries
+ # for this target
+ if [ -e /etc/initiators.deny ]; then
+ ocf_run sed -e "/^${OCF_RESKEY_iqn}[[:space:]]/d" \
+ -i /etc/initiators.deny
+ fi
+ if [ -e /etc/initiators.allow ]; then
+ ocf_run sed -e "/^${OCF_RESKEY_iqn}[[:space:]]/d" \
+ -i /etc/initiators.allow
+ fi
+ ;;
+ tgt)
+ tid="${OCF_RESKEY_tid}"
+ # Close existing connections. There is no other way to
+ # do this in tgt than to parse the output of "tgtadm --op
+ # show".
+ set -- $(tgtadm --lld iscsi --op show --mode target \
+ | sed -ne '/^Target '${tid}':/,/^Target/ {
+ /^[[:space:]]*I_T nexus: \([0-9]\+\)/ {
+ s/^.*: \([0-9]*\).*/--sid=\1/; h;
+ };
+ /^[[:space:]]*Connection: \([0-9]\+\)/ {
+ s/^.*: \([0-9]*\).*/--cid=\1/; G; p;
+ };
+ /^[[:space:]]*LUN information:/ q;
+ }')
+ while [[ -n $2 ]]; do
+ # $2 $1 looks like "--sid=X --cid=Y"
+ ocf_run tgtadm --lld iscsi --op delete --mode connection \
+ --tid=${tid} $2 $1
+ shift 2
+ done
+ # In tgt, we must first unbind the user account from
+ # the target, then remove the account itself.
+ if [ -n "${OCF_RESKEY_incoming_username}" ]; then
+ ocf_run tgtadm --lld iscsi --mode account --op unbind \
+ --tid=${tid} \
+ --user=${OCF_RESKEY_incoming_username} || exit $OCF_ERR_GENERIC
+ ocf_run tgtadm --lld iscsi --mode account --op delete \
+ --user=${OCF_RESKEY_incoming_username} || exit $OCF_ERR_GENERIC
+ fi
+ # Loop on delete. Keep trying until we time out, if
+ # necessary.
+ while true; do
+ if tgtadm --lld iscsi --op delete --mode target --tid=${tid}; then
+ ocf_log debug "Removed target ${OCF_RESKEY_iqn}."
+ break
+ else
+ ocf_log warn "Failed to remove target ${OCF_RESKEY_iqn}, retrying."
+ sleep 1
+ fi
+ done
+ # In tgt, we don't have to worry about our ACL
+ # entries. They are automatically removed upon target
+ # deletion.
+ ;;
+ lio)
+ # In lio, removing a target automatically removes all
+ # associated TPGs, network portals, and LUNs.
+ ocf_run lio_node --deliqn ${OCF_RESKEY_iqn} || exit $OCF_ERR_GENERIC
+ ;;
+ lio-t)
+ ocf_take_lock $TARGETLOCKFILE
+ ocf_release_lock_on_exit $TARGETLOCKFILE
+ ocf_run targetcli /iscsi delete ${OCF_RESKEY_iqn} || exit $OCF_ERR_GENERIC
+ ;;
+ scst)
+ ocf_run scstadmin -disable_target ${OCF_RESKEY_iqn} -driver iscsi -force -noprompt
+ for i in $(find /sys/kernel/scst_tgt/targets/iscsi/${OCF_RESKEY_iqn}/ -name force_close); do
+ echo 1 > ${i}
+ done
+
+ timer=0
+ while ls -Ad /sys/kernel/scst_tgt/targets/iscsi/${OCF_RESKEY_iqn}/sessions/* > /dev/null 2>&1; do
+ if [ ${timer} -gt ${INIT_LOGOUT_TIMEOUT} ]; then
+ ocf_log warn "Some initiators still logged in after ${INIT_LOGOUT_TIMEOUT} seconds. Continuing."
+ break
+ fi
+ timer=$((timer + 1))
+ sleep 1
+ done
+
+ scstadmin -rem_target ${OCF_RESKEY_iqn} -driver iscsi -force -noprompt
+ ;;
+ esac
+
+ return $OCF_SUCCESS
+}
+
+iSCSITarget_monitor() {
+ case $OCF_RESKEY_implementation in
+ iet)
+ grep -Eq "tid:[0-9]+ name:${OCF_RESKEY_iqn}" /proc/net/iet/volume && return $OCF_SUCCESS
+ ;;
+ tgt)
+ tgtadm --lld iscsi --op show --mode target \
+ | grep -Eq "Target [0-9]+: ${OCF_RESKEY_iqn}" && return $OCF_SUCCESS
+ ;;
+ lio | lio-t)
+ # if we have no configfs entry for the target, it's
+ # definitely stopped
+ [ -d /sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn} ] || return $OCF_NOT_RUNNING
+ # if the target is there, but its TPG is not enabled, then
+ # we also consider it stopped
+ [ `cat /sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn}/tpgt_1/enable` -eq 1 ] || return $OCF_NOT_RUNNING
+ return $OCF_SUCCESS
+ ;;
+ scst)
+ [ -d /sys/kernel/scst_tgt/targets/iscsi/${OCF_RESKEY_iqn} ] || return $OCF_NOT_RUNNING
+ [ $(cat /sys/kernel/scst_tgt/targets/iscsi/${OCF_RESKEY_iqn}/enabled) -eq 1 ] || return $OCF_NOT_RUNNING
+ return $OCF_SUCCESS
+ ;;
+ esac
+
+ return $OCF_NOT_RUNNING
+}
+
+iSCSITarget_validate() {
+ # Do we have all required variables?
+ local required_vars
+ case $OCF_RESKEY_implementation in
+ iet)
+ required_vars="iqn"
+ ;;
+ tgt)
+ required_vars="iqn tid"
+ ;;
+ esac
+
+ for var in ${required_vars}; do
+ param="OCF_RESKEY_${var}"
+ if [ -z "${!param}" ]; then
+ ocf_exit_reason "Missing resource parameter \"$var\"!"
+ exit $OCF_ERR_CONFIGURED
+ fi
+ done
+
+ # Is the configured implementation supported?
+ case "$OCF_RESKEY_implementation" in
+ "iet"|"tgt"|"lio"|"lio-t"|"scst")
+ ;;
+ "")
+ # The user didn't specify an implementation, and we were
+ # unable to determine one from installed binaries (in
+ # other words: no binaries for any supported
+ # implementation could be found)
+ ocf_exit_reason "Undefined iSCSI target implementation"
+ exit $OCF_ERR_INSTALLED
+ ;;
+ *)
+ ocf_exit_reason "Unsupported iSCSI target implementation \"$OCF_RESKEY_implementation\"!"
+ exit $OCF_ERR_CONFIGURED
+ ;;
+ esac
+
+ # Do we have any configuration parameters that the current
+ # implementation does not support?
+ local unsupported_params
+ local var
+ local envar
+ case $OCF_RESKEY_implementation in
+ iet|tgt)
+ # IET and tgt do not support binding a target portal to a
+ # specific IP address.
+ unsupported_params="portals"
+ ;;
+ lio|lio-t)
+ unsupported_params="tid"
+ ;;
+ scst)
+ unsupported_params="tid iser_portals"
+ ;;
+ esac
+
+ for var in ${unsupported_params}; do
+ envar=OCF_RESKEY_${var}
+ defvar=OCF_RESKEY_${var}_default
+ if [ -n "${!envar}" ]; then
+ if [[ "${!envar}" != "${!defvar}" ]];then
+ case "$__OCF_ACTION" in
+ start|validate-all)
+ ocf_log warn "Configuration parameter \"${var}\"" \
+ "is not supported by the iSCSI implementation" \
+ "and will be ignored." ;;
+ esac
+ fi
+ fi
+ done
+
+ if ! ocf_is_probe; then
+ # Do we have all required binaries?
+ case $OCF_RESKEY_implementation in
+ iet)
+ check_binary ietadm
+ ;;
+ tgt)
+ check_binary tgtadm
+ ;;
+ lio)
+ check_binary tcm_node
+ check_binary lio_node
+ ;;
+ lio-t)
+ check_binary targetcli
+ ;;
+ scst)
+ check_binary scstadmin
+ ;;
+ esac
+
+ # Is the required kernel functionality available?
+ case $OCF_RESKEY_implementation in
+ iet)
+ [ -d /proc/net/iet ]
+ if [ $? -ne 0 ]; then
+ ocf_log err "/proc/net/iet does not exist or is not a directory -- check if required modules are loaded."
+ exit $OCF_ERR_INSTALLED
+ fi
+ ;;
+ tgt)
+ # tgt is userland only
+ ;;
+ lio)
+ # lio needs configfs to be mounted
+ if ! grep -Eq "^.*/sys/kernel/config[[:space:]]+configfs" /proc/mounts; then
+ ocf_log err "configfs not mounted at /sys/kernel/config -- check if required modules are loaded."
+ exit $OCF_ERR_INSTALLED
+ fi
+ # check for configfs entries created by target_core_mod
+ if [ ! -d /sys/kernel/config/target ]; then
+ ocf_log err "/sys/kernel/config/target does not exist or is not a directory -- check if required modules are loaded."
+ exit $OCF_ERR_INSTALLED
+ fi
+ ;;
+ lio-t)
+ #targetcli loads the needed kernel modules
+ ;;
+ scst)
+ if [ ! -d /sys/kernel/scst_tgt ]; then
+ ocf_log err "/sys/kernel/scst_tgt does not exist or is not a directory -- check if required modules are loaded."
+ exit $OCF_ERR_INSTALLED
+ fi
+ ;;
+ esac
+ fi
+
+ return $OCF_SUCCESS
+}
+
+
+case $1 in
+ meta-data)
+ meta_data
+ exit $OCF_SUCCESS
+ ;;
+ usage|help)
+ iSCSITarget_usage
+ exit $OCF_SUCCESS
+ ;;
+esac
+
+# Everything except usage and meta-data must pass the validate test
+iSCSITarget_validate
+
+case $__OCF_ACTION in
+start) iSCSITarget_start;;
+stop) iSCSITarget_stop;;
+monitor|status) iSCSITarget_monitor;;
+reload) ocf_log err "Reloading..."
+ iSCSITarget_start
+ ;;
+validate-all) ;;
+*) iSCSITarget_usage
+ exit $OCF_ERR_UNIMPLEMENTED
+ ;;
+esac
+rc=$?
+ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc"
+exit $rc