rc script for iSCSI initiator
Miroslav Lachman
000.fbsd at quip.cz
Thu Jan 28 23:24:19 UTC 2010
Hi,
iSCSI initiator is in the base for a long time, but there is not
rc.d/iscsi script to start iSCSI sessions. I found one old in mailing
list and take it as base for my work.
I attached two versions.
*rc.d_iscsi.all.txt* manage all defined targets at start / stop command
*rc.d_iscsi.individual.txt* can selectively start / stop individual
sessions (targets defined in /etc/iscsi.conf and in rc.conf
iscsi_targets="")
It is not intended to direct commit, it is just work in progress and
needs some discussion and improvements from rc folks.
Scripts are too verbose for better debugging.
Both of them can be called as:
/etc/rc.d/iscsi start|stop
The "individual" version can be called:
/etc/rc.d/iscsi start|stop [target_name]
For example:
# /etc/rc.d/iscsi start styx_storage_1
debug.iscsi_initiator: 2 -> 0
Starting iSCSI session for styx_storage_1
Waiting for /dev/ufs/styx0p1: . OK
/dev/ufs/styx0p1: FILE SYSTEM CLEAN; SKIPPING CHECKS
/dev/ufs/styx0p1: clean, 856565848 free (896 frags, 107070619 blocks,
0.0% fragmentation)
/dev/ufs/styx0p1 on /vol1 (ufs, local, soft-updates, fsid 2d3d5e4b8b67f290)
# /etc/rc.d/iscsi stop styx_storage_1
Unmounting iSCSI volumes for styx_storage_1
/dev/ufs/styx0p1: unmount from /vol1
Stopping iSCSI session for: styx_storage_1
.....All iSCSI sessions were stopped
My main problem with this script is how to get a PID of started
iscontrol and as I didn't found a "right way" to do it, the script
contains some ugly hack with writing temporary file. This must be fixed
by somebody more skilled than me.
I am open to any comments, sugesstions, warnings etc.
Miroslav Lachman
-------------- next part --------------
#!/bin/sh
# PROVIDE: iscsi
# REQUIRE: NETWORKING
# BEFORE: DAEMON
# KEYWORD: nojail shutdown
#
# This script supports starting and stopping individual sessions
# from the iscsi_targets list:
# rc.d/iscsi start my_first_target
# rc.d/iscsi stop another_target
#
# Targets must be defined in /etc/iscsi.conf
# Each target has its own fstab file named as $iscsi_fstab.target_name
#
# Add the following lines to /etc/rc.conf to enable iscsi:
#
# iscsi_enable="YES"
# iscsi_targets="" # list of targets defined in /etc/iscsi.conf
# iscsi_fstab="/etc/fstab.iscsi" # prefix for per target fstabs
# iscsi_debug="" # 0,1,2
# iscsi_exports=""
# iscsi_zfs=""
#
. /etc/rc.subr
name=iscsi
rcvar=`set_rcvar`
command=/sbin/iscontrol
iscsi_enable=${iscsi_enable:-"NO"}
iscsi_fstab=${iscsi_fstab:-"/etc/fstab.iscsi"}
iscsi_exports=${iscsi_exports:-"/etc/exports.iscsi"}
iscsi_debug=${iscsi_debug:-0}
start_cmd="iscsi_start"
faststop_cmp="iscsi_stop"
stop_cmd="iscsi_stop"
stop_postcmd="iscsi_poststop"
required_modules="iscsi_initiator:iscsi"
iscsi_wait()
{
dev=$1
trap "echo 'Wait loop cancelled'; exit 1" 2
count=0
while true; do
if [ -c $dev ]; then
break;
fi
if [ $count -eq 0 ]; then
echo -n "Waiting for ${dev}: "
fi
count=$((${count} + 1))
if [ $count -eq 6 ]; then
echo ' FAILED'
return 0
break
fi
echo -n '.'
sleep 5;
done
echo ' OK'
return 1
}
iscsi_start()
{
sysctl debug.iscsi_initiator=$iscsi_debug
#
# start iscontrol for each target
if [ -n "${iscsi_targets}" ]; then
_tmp_dir=`mktemp -d /tmp/iscsi.XXXXXXXX` || \
err 3 "$name: Can't create temp dir, exiting..."
for target in ${iscsi_targets}; do
_pid_file="/var/run/iscontrol_${target}.pid"
if [ -f "${_pid_file}" ]; then
pgrep -F "${_pid_file}" iscontrol > /dev/null
_return=$?
if [ $_return -eq 0 ]; then
echo "Session for ${target} is already running"
continue
fi
echo "Removing stale pidfile ${_pid_file}"
rm "${_pid_file}"
fi
echo "Starting iSCSI session for ${target}"
_tmp_iscsi=${_tmp_dir}/iscontrol.${target}
${command} ${rc_flags} -n ${target} > ${_tmp_iscsi} 2>&1
# I do not know the better way to get iscontrol PID
head -1 "${_tmp_iscsi}" | sed -E 's/.*\[([0-9]*)\].*/\1/' > "${_pid_file}"
# rm -f "$_tmp_iscsi"
## file specified as _tmp_iscsi remains open until iscontrol is closed
## lsof +aL1 /tmp # lists unlinked files, still opened
done
# rmdir "${_tmp_dir}"
else
# no targets, no devices, no mounts, just exit
warn 'You must specify iscsi_targets list'
return 1
fi
# We have separate fstab file for each target (/etc/fstab.iscsi.target_name)
for target in ${iscsi_targets}; do
target_fstab="${iscsi_fstab}.${target}"
if [ -f "${target_fstab}" ]; then
while read spec file type opt t1 t2
do
case ${spec} in
\#*|'')
;;
*)
if iscsi_wait ${spec}; then
break;
fi
# Check if not already mounted and run fsck
mount | grep "^${spec} "
if [ $? -ne 0 ]; then
#echo "type=${type} spec=${spec} file=${file} opt=${opt}"
fsck -p -t ${type} ${spec}
else
debug "${spec} is already mounted, skipping fsck"
fi
;;
esac
done < "${target_fstab}"
# Mount all filesystems from given fstab file
mount -a -v -F "${target_fstab}"
fi
done
if [ -f "${iscsi_exports}" ]; then
# ??? same content will be appended on each start!
# it should be checked with diff / uniq
cat ${iscsi_exports} >> /etc/exports
#/etc/rc.d/mountd reload
kill -1 `cat /var/run/mountd.pid`
fi
if checkyesno zfs_enable; then
if checkyesno iscsi_zfs; then
sleep 4
zpool import -d /dev/label -a
# presumably we can ignore zfs mount -a share -a and swapon
# some zfs dataset may be exported "legacy", so hup mountd
kill -1 `cat /var/run/mountd.pid`
fi
fi
}
iscsi_stop()
{
for target in ${iscsi_targets}; do
target_fstab="${iscsi_fstab}.${target}"
if [ -f "${target_fstab}" ]; then
echo "Unmounting iSCSI volumes for ${target}"
umount -a -fv -F "${target_fstab}"
fi
done
echo -n 'Stopping iSCSI session for:'
_poststop=0
# Stop iscontrol for each target
if [ -n "${iscsi_targets}" ]; then
if [ `sysctl -n net.iscsi.sessions` -gt 0 ]; then
# We will run iscsi_poststop loop
_poststop=1
fi
for target in ${iscsi_targets}; do
echo -n " ${target}"
_iscsi_pid_file="/var/run/iscontrol_${target}.pid"
if [ -f "${_iscsi_pid_file}" ]; then
_pid=$(head -1 "${_iscsi_pid_file}")
# Safety check if PID from file is PID of iscontrol
_grep_pid="$(pgrep -F "${_iscsi_pid_file}" iscontrol)"
if [ "${_pid}" = "${_grep_pid}" ]; then
kill -HUP ${_pid} && rm "${_iscsi_pid_file}"
_pids="${_pids} $_pid"
fi
else
echo -e "\n Cannot stop session ${target}. No PID in /var/run"
fi
done
fi
echo ''
}
iscsi_poststop()
{
_dying=0
while [ $_poststop -gt 0 -a -n "${_pids}" ];
do
if [ -n "$(ps -o pid= -o command= -p ${_pids})" ]; then
sleep 2
echo -n '.'
_dying=$(($_dying + 1))
if [ $_dying -gt 10 ]; then
echo 'Some session does not want stop, giving up'
return 1
break
fi
else
echo 'All iSCSI sessions were stopped'
return 0
break
fi
done
}
load_rc_config $name
cmd="$1"
if [ $# -gt 0 ]; then
shift
fi
if [ -n "$*" ]; then
iscsi_targets="$*"
fi
run_rc_command "${cmd}"
-------------- next part --------------
#!/bin/sh
# PROVIDE: iscsi
# REQUIRE: NETWORKING
# BEFORE: DAEMON
# KEYWORD: nojail shutdown
#
# Add the following lines to /etc/rc.conf to enable iscsi:
#
# iscsi_enable="YES"
# iscsi_targets="" # list of targets defined in /etc/iscsi.conf
# iscsi_fstab="/etc/fstab.iscsi"
# iscsi_debug="" # 0,1,2
# iscsi_exports=""
# iscsi_zfs=""
#
. /etc/rc.subr
name=iscsi
rcvar=`set_rcvar`
command=/sbin/iscontrol
iscsi_enable=${iscsi_enable:-"NO"}
iscsi_fstab=${iscsi_fstab:-"/etc/fstab.iscsi"}
iscsi_exports=${iscsi_exports:-"/etc/exports.iscsi"}
iscsi_debug=${iscsi_debug:-0}
start_cmd="iscsi_start"
faststop_cmp="iscsi_stop"
stop_cmd="iscsi_stop"
stop_postcmd="iscsi_poststop"
required_modules="iscsi_initiator:iscsi"
iscsi_wait()
{
dev=$1
trap "echo 'Wait loop cancelled'; exit 1" 2
count=0
while true; do
if [ -c $dev ]; then
break;
fi
if [ $count -eq 0 ]; then
echo -n "Waiting for ${dev}: "
fi
count=$((${count} + 1))
if [ $count -eq 6 ]; then
echo ' FAILED'
return 0
break
fi
echo -n '.'
sleep 5;
done
echo ' OK'
return 1
}
iscsi_start()
{
sysctl debug.iscsi_initiator=$iscsi_debug
#
# start iscontrol for each target
if [ -n "${iscsi_targets}" ]; then
_tmp_dir=`mktemp -d /tmp/iscsi.XXXXXXXX` || \
err 3 "$name: Can't create temp dir, exiting..."
for target in ${iscsi_targets}; do
_pid_file="/var/run/iscontrol_${target}.pid"
if [ -f "${_pid_file}" ]; then
pgrep -F "${_pid_file}" iscontrol > /dev/null
_return=$?
if [ $_return -eq 0 ]; then
echo "Session for ${target} is already running"
continue
fi
echo "Removing stale pidfile ${_pid_file}"
rm "${_pid_file}"
fi
echo "Starting iSCSI session for ${target}"
_tmp_iscsi=${_tmp_dir}/iscontrol.${target}
${command} ${rc_flags} -n ${target} > ${_tmp_iscsi} 2>&1
# I do not know the better way to get iscontrol PID
head -1 "${_tmp_iscsi}" | sed -E 's/.*\[([0-9]*)\].*/\1/' > "${_pid_file}"
# rm -f "$_tmp_iscsi"
## file specified as _tmp_iscsi remains open until iscontrol is closed
## lsof +aL1 /tmp # lists unlinked files, still opened
done
# rmdir "${_tmp_dir}"
else
# no targets, no devices, no mounts, just exit
warn 'You must specify iscsi_targets list'
return 1
fi
if [ -f "${iscsi_fstab}" ]; then
while read spec file type opt t1 t2
do
case ${spec} in
\#*|'')
;;
*)
if iscsi_wait ${spec}; then
break;
fi
# Check if not already mounted and run fsck
mount | grep "^${spec} "
if [ $? -ne 0 ]; then
#echo "type=${type} spec=${spec} file=${file} opt=${opt}"
fsck -p -t ${type} ${spec}
else
debug "${spec} is already mounted, skipping fsck"
fi
;;
esac
done < ${iscsi_fstab}
# Mount all filesystems from given fstab file
mount -a -v -F "${iscsi_fstab}"
fi
if [ -f "${iscsi_exports}" ]; then
# ??? same content will be appended on each start!
# it should be checked with diff / uniq
cat ${iscsi_exports} >> /etc/exports
#/etc/rc.d/mountd reload
kill -1 `cat /var/run/mountd.pid`
fi
if checkyesno zfs_enable; then
if checkyesno iscsi_zfs; then
sleep 4
zpool import -d /dev/label -a
# presumably we can ignore zfs mount -a share -a and swapon
# some zfs dataset may be exported "legacy", so hup mountd
kill -1 `cat /var/run/mountd.pid`
fi
fi
}
iscsi_stop()
{
if [ -f "${iscsi_fstab}" ]; then
echo 'Unmounting all iSCSI volumes:'
umount -a -fv -F ${iscsi_fstab}
fi
echo -n 'Stopping iSCSI session for:'
_poststop=0
# Stop iscontrol for each target
if [ -n "${iscsi_targets}" ]; then
if [ `sysctl -n net.iscsi.sessions` -gt 0 ]; then
# We will run iscsi_poststop loop
_poststop=1
fi
for target in ${iscsi_targets}; do
echo -n " ${target}"
_iscsi_pid_file="/var/run/iscontrol_${target}.pid"
if [ -f "${_iscsi_pid_file}" ]; then
_pid=$(head -1 "${_iscsi_pid_file}")
# Safety check if PID from file is PID of iscontrol
_grep_pid="$(pgrep -F "${_iscsi_pid_file}" iscontrol)"
if [ "${_pid}" = "${_grep_pid}" ]; then
kill -HUP ${_pid} && rm "${_iscsi_pid_file}"
_pids="${_pids} $_pid"
fi
else
echo -e "\n Cannot stop session ${target}. No PID in /var/run"
fi
done
fi
echo ''
}
iscsi_poststop()
{
_dying=0
while [ $_poststop -gt 0 -a -n "${_pids}" ];
do
if [ -n "$(ps -o pid= -o command= -p ${_pids})" ]; then
sleep 2
echo -n '.'
_dying=$(($_dying + 1))
if [ $_dying -gt 10 ]; then
echo 'Some session does not want stop, giving up'
return 1
break
fi
else
echo 'All iSCSI sessions were stopped'
return 0
break
fi
done
}
load_rc_config $name
run_rc_command "$1"
More information about the freebsd-rc
mailing list