blob: 48235ff9c6e106a2f7358c5faa3f64cc4747dcea [file] [log] [blame]
#!/bin/bash
#
#
# SCSTTarget OCF RA. Exports and manages iSCSI SCST targets.
#
# (c) 2012 Riccardo Bicelli
# 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.
#
#######################################################################
# Initialization:
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
# Set portal to none by default
OCF_RESKEY_portals_default="none"
: ${OCF_RESKEY_portals=${OCF_RESKEY_portals_default}}
# Lockfile, used for selecting a target ID
LOCKFILE=${HA_RSCTMP}/SCSTTarget-${OCF_RESKEY_implementation}.lock
ISCSI_DAEMON="/usr/local/sbin/iscsi-scstd"
SYSFS_PATH="/sys/kernel/scst_tgt/targets/iscsi"
SCST_BASE="/sys/kernel/scst_tgt"
ISCSI_BASE="${SCST_BASE}/targets/iscsi"
#######################################################################
meta_data() {
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="SCSTTarget" version="0.1">
<version>1.0</version>
<longdesc lang="en">
Manages SCST 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">SCST iSCSI target export agent</shortdesc>
<parameters>
<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="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 all IP addresses.
</longdesc>
<shortdesc lang="en">iSCSI portal addresses</shortdesc>
<content type="string" default="${OCF_RESKEY_portals_default}"/>
</parameter>
<parameter name="allowed_initiators" required="0" unique="0">
<longdesc lang="en">
TODO: 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">TODO: List of iSCSI initiators allowed to connect
to this target</shortdesc>
<content type="string" 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.
</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="10" />
<action name="stop" timeout="180" />
<action name="status" timeout="10" interval="10" depth="0" />
<action name="monitor" timeout="10" interval="10" depth="0" />
<action name="meta-data" timeout="5" />
<action name="validate-all" timeout="10" />
</actions>
</resource-agent>
END
}
l_load_module () {
n=`lsmod | grep -c "^$1 "`
if [ $n -gt 0 ];
then
return 0
else
modprobe $1> /dev/null 2>&1 || return 1
return 0
fi
}
l_start_service () {
local running
# Handler modules are loaded in LUN resource agent
# Check if modules are loaded
if [ ! -d ${SYSFS_PATH} ]; then
ocf_log info "Loading scst Modules"
l_load_module scst || return 1
l_load_module iscsi_scst || return 1
#Not critical modules, not unloaded on stop.
l_load_module crc32c
l_load_module crc32c_intel
fi
# Start Daemon
if [ ! "$(pidof ${ISCSI_DAEMON})" ]; then
ocf_run $ISCSI_DAEMON || return 1
ocf_run scstadmin -force -noprompt -clear_config >/dev/null 2>&1
fi
return 0
}
l_stop_service () {
#Stop SCST Services, if there are no targets active.
local TARGET_NOT_PRESENT=true
#Are there targets active?
for i in $( ls "${ISCSI_BASE}" ) ; do
if [ -d "${ISCSI_BASE}/${i}" ]; then
ocf_log warn "Found target running: ${i}"
TARGET_NOT_PRESENT=false
fi
done
#Close sessions
for i in `/bin/ls ${ISCSI_BASE}/${OCF_RESKEY_iqn}/sessions`; do
ocf_log warn "Force closing session to initiator ${i}"
echo "1" > "${ISCSI_BASE}/${OCF_RESKEY_iqn}/sessions/${i}/force_close"
done
#Stop process and unload modules
if $TARGET_NOT_PRESENT ; then
ocf_log warn "Daemon not required, stopping ..."
pkill -TERM -f $ISCSI_DAEMON
rmmod iscsi_scst
rmmod scst
fi
}
SCSTTarget_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
}
SCSTTarget_start() {
SCSTTarget_monitor
if [ $? = $OCF_SUCCESS ]; then
return $OCF_SUCCESS
fi
local param
local name
local value
local initiator
# Start Service
l_start_service
# Set incoming username and password globally
if [ "${OCF_RESKEY_incoming_username}" != "" ]; then
echo "add_attribute IncomingUser ${OCF_RESKEY_incoming_username} ${OCF_RESKEY_incoming_password}" > ${ISCSI_BASE}/mgmt
if [ $? -ne 0 ]; then
ocf_log warn "Unable to set CHAP Authentication!"
fi
fi
ocf_log info "target ${OCF_RESKEY_iqn}: Starting..."
# Create Target
echo "add_target ${OCF_RESKEY_iqn}" > ${ISCSI_BASE}/mgmt || exit $OCF_ERR_GENERIC
# Set Allowed Portals
if [ "${OCF_RESKEY_portals}" != "none" ]; then
for param in ${OCF_RESKEY_portals}; do
ocf_log info "Adding allowed portal ${param} to target ${OCF_RESKEY_iqn}"
echo "add_target_attribute ${OCF_RESKEY_iqn} allowed_portal ${param}" > ${ISCSI_BASE}/mgmt
if [ $? -ne 0 ]; then
ocf_log warn "Unable to set Allowed Portal!"
fi
done
fi
# Set incoming username and password
if [ "${OCF_RESKEY_incoming_username}" != "" ]; then
echo "add_target_attribute ${OCF_RESKEY_iqn} IncomingUser ${OCF_RESKEY_incoming_username} ${OCF_RESKEY_incoming_password}" > ${ISCSI_BASE}/mgmt
if [ $? -ne 0 ]; then
ocf_log warn "Unable to set CHAP Authentication!"
fi
fi
ocf_log info "Enabling target ${OCF_RESKEY_iqn}"
# Enable iSCSI Target
echo 1 > "${ISCSI_BASE}/enabled" || exit $OCF_ERR_GENERIC
ocf_log debug "SCST target ${OCF_RESKEY_iqn}: Started."
#Debugging purpose
#scstadmin -write_config /tmp/scst.conf.start
return $OCF_SUCCESS
}
SCSTTarget_stop() {
SCSTTarget_monitor
if [ $? = $OCF_SUCCESS ]; then
local param
ocf_log info "target ${OCF_RESKEY_iqn}: Stopping..."
# Check if there are connected luns
for i in $( ls "${ISCSI_BASE}/${OCF_RESKEY_iqn}/luns" ) ; do
if [ -d "${ISCSI_BASE}/${OCF_RESKEY_iqn}/luns/${i}" ]; then
ocf_log err "Unable to stop target ${OCF_RESKEY_iqn}: lun ${i} connected!"
exit $OCF_ERR_GENERIC
fi
done
# Disable Target
ocf_log info "disabling target ${OCF_RESKEY_iqn}"
echo 0 > ${ISCSI_BASE}/${OCF_RESKEY_iqn}/enabled || exit $OCF_ERR_GENERIC
#Remove Target
ocf_log info "deleting target ${OCF_RESKEY_iqn}"
echo "del_target ${OCF_RESKEY_iqn}" > ${ISCSI_BASE}/mgmt
if [ $? -ne 0 ]; then
ocf_log err "Unable to delete Target ${OCF_RESKY_iqn}"
exit $OCF_ERR_GENERIC
fi
#Debugging purpose
#scstadmin -write_config /tmp/scst.conf.stop
#Check if other targets are running, then stop service and unload modules
l_stop_service
ocf_log info "target ${OCF_RESKEY_iqn}: Stopped."
fi
return $OCF_SUCCESS
}
SCSTTarget_monitor() {
if [ -d "${SYSFS_PATH}/${OCF_RESKEY_iqn}" ]; then
return $OCF_SUCCESS
else
return $OCF_NOT_RUNNING
fi
}
SCSTTarget_validate() {
# Do we have all required variables?
local required_vars
required_vars="iqn"
for var in ${required_vars}; do
param="OCF_RESKEY_${var}"
if [ -z "${!param}" ]; then
ocf_log error "Missing resource parameter \"$var\"!"
exit $OCF_ERR_CONFIGURED
fi
done
if ! ocf_is_probe; then
check_binary scstadmin
fi
return $OCF_SUCCESS
}
case $1 in
meta-data)
meta_data
exit $OCF_SUCCESS
;;
usage|help)
SCSTTarget_usage
exit $OCF_SUCCESS
;;
esac
# Everything except usage and meta-data must pass the validate test
SCSTTarget_validate
case $__OCF_ACTION in
start) SCSTTarget_start;;
stop) SCSTTarget_stop;;
monitor|status) SCSTTarget_monitor;;
#reload) ocf_log err "Reloading..."
# SCSTTarget_start
# ;;
validate-all) ;;
*) SCSTTarget_usage
exit $OCF_ERR_UNIMPLEMENTED
;;
esac
rc=$?
ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc"
exit $rc