From d4a36f47b36f47a847795660653b7fbc5baab706 Mon Sep 17 00:00:00 2001 From: David Vossel Date: Mon, 25 Aug 2014 14:55:50 -0500 Subject: [PATCH 1/4] iscsi agent updates --- heartbeat/iSCSILogicalUnit | 573 ++++++++++++++++++++++----------------- heartbeat/iSCSITarget | 661 +++++++++++++++++++++++++-------------------- 2 files changed, 690 insertions(+), 544 deletions(-) diff --git a/heartbeat/iSCSILogicalUnit b/heartbeat/iSCSILogicalUnit index 0ab4722..c4cee0d 100755 --- a/heartbeat/iSCSILogicalUnit +++ b/heartbeat/iSCSILogicalUnit @@ -3,10 +3,10 @@ # # iSCSILogicalUnit OCF RA. Exports and manages iSCSI Logical Units. # -# (c) 2013 LINBIT, Lars Ellenberg +# (c) 2013 LINBIT, Lars Ellenberg # (c) 2009-2010 Florian Haas, Dejan Muhamedagic, -# and Linux-HA contributors -# +# 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 @@ -36,11 +36,13 @@ # Defaults # Set a default implementation based on software installed if have_binary ietadm; then - OCF_RESKEY_implementation_default="iet" + OCF_RESKEY_implementation_default="iet" elif have_binary tgtadm; then - OCF_RESKEY_implementation_default="tgt" + OCF_RESKEY_implementation_default="tgt" elif have_binary lio_node; then - OCF_RESKEY_implementation_default="lio" + OCF_RESKEY_implementation_default="lio" +elif have_binary targetcli; then + OCF_RESKEY_implementation_default="lio-t" fi : ${OCF_RESKEY_implementation=${OCF_RESKEY_implementation_default}} @@ -91,9 +93,9 @@ an SCSI Target, exported via a daemon that speaks the iSCSI protocol. The iSCSI target daemon implementation. Must be one of "iet", "tgt", -or "lio". If unspecified, an implementation is selected based on the +"lio", or "lio-t". If unspecified, an implementation is selected based on the availability of management utilities, with "iet" being tried first, -then "tgt", then "lio". +then "tgt", then "lio", then "lio-t". iSCSI target daemon implementation @@ -228,12 +230,12 @@ in /sys/kernel/config/target/core/. - - - - - - + + + + + + END @@ -250,108 +252,150 @@ END } iSCSILogicalUnit_start() { - iSCSILogicalUnit_monitor - if [ $? = $OCF_SUCCESS ]; then - return $OCF_SUCCESS - fi + iSCSILogicalUnit_monitor + if [ $? = $OCF_SUCCESS ]; then + return $OCF_SUCCESS + fi - local params + local params - case $OCF_RESKEY_implementation in + case $OCF_RESKEY_implementation in iet) - params="Path=${OCF_RESKEY_path}" - # use blockio if path points to a block device, fileio - # otherwise. - if [ -b "${OCF_RESKEY_path}" ]; then - params="${params} Type=blockio" - else - params="${params} Type=fileio" - fi - # in IET, we have to set LU parameters on creation - if [ -n "${OCF_RESKEY_scsi_id}" ]; then - params="${params} ScsiId=${OCF_RESKEY_scsi_id}" - fi - if [ -n "${OCF_RESKEY_scsi_sn}" ]; then - params="${params} ScsiSN=${OCF_RESKEY_scsi_sn}" - fi - params="${params} ${OCF_RESKEY_additional_parameters}" - ocf_run ietadm --op new \ - --tid=${TID} \ - --lun=${OCF_RESKEY_lun} \ - --params ${params// /,} || exit $OCF_ERR_GENERIC - ;; + params="Path=${OCF_RESKEY_path}" + # use blockio if path points to a block device, fileio + # otherwise. + if [ -b "${OCF_RESKEY_path}" ]; then + params="${params} Type=blockio" + else + params="${params} Type=fileio" + fi + # in IET, we have to set LU parameters on creation + if [ -n "${OCF_RESKEY_scsi_id}" ]; then + params="${params} ScsiId=${OCF_RESKEY_scsi_id}" + fi + if [ -n "${OCF_RESKEY_scsi_sn}" ]; then + params="${params} ScsiSN=${OCF_RESKEY_scsi_sn}" + fi + params="${params} ${OCF_RESKEY_additional_parameters}" + ocf_run ietadm --op new \ + --tid=${TID} \ + --lun=${OCF_RESKEY_lun} \ + --params ${params// /,} || exit $OCF_ERR_GENERIC + ;; tgt) - # tgt requires that we create the LU first, then set LU - # parameters - params="" - local var - local envar - for var in scsi_id scsi_sn vendor_id product_id; do - envar="OCF_RESKEY_${var}" - if [ -n "${!envar}" ]; then - params="${params} ${var}=${!envar}" + # tgt requires that we create the LU first, then set LU + # parameters + params="" + local var + local envar + for var in scsi_id scsi_sn vendor_id product_id; do + envar="OCF_RESKEY_${var}" + if [ -n "${!envar}" ]; then + params="${params} ${var}=${!envar}" + fi + done + params="${params} ${OCF_RESKEY_additional_parameters}" + + # cleanup: tgt (as of tgtadm version 1.0.24) does not like an explicit "bsoflags=direct" + # when used with "bstype=aio" (which always uses O_DIRECT) + [[ $OCF_RESKEY_tgt_bstype/$OCF_RESKEY_tgt_bsoflags = "aio/direct" ]] && OCF_RESKEY_tgt_bsoflags="" + + tgt_args="" + [[ $OCF_RESKEY_tgt_bstype ]] && tgt_args="$tgt_args --bstype=$OCF_RESKEY_tgt_bstype" + [[ $OCF_RESKEY_tgt_bsoflags ]] && tgt_args="$tgt_args --bsoflags=$OCF_RESKEY_tgt_bsoflags" + [[ $OCF_RESKEY_tgt_device_type ]] && tgt_args="$tgt_args --device-type=$OCF_RESKEY_tgt_device_type" + + ocf_run tgtadm --lld iscsi --op new --mode logicalunit \ + --tid=${TID} \ + --lun=${OCF_RESKEY_lun} \ + $tgt_args \ + --backing-store ${OCF_RESKEY_path} || exit $OCF_ERR_GENERIC + if [ -z "$params" ]; then + return $OCF_SUCCESS + else + ocf_run tgtadm --lld iscsi --op update --mode logicalunit \ + --tid=${TID} \ + --lun=${OCF_RESKEY_lun} \ + --params ${params// /,} || exit $OCF_ERR_GENERIC + fi + ;; + lio) + # For lio, we first have to create a target device, then + # add it to the Target Portal Group as an LU. + + block_configfs_path="/sys/kernel/config/target/core/iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE}/udev_path" + if [ ! -e "${block_configfs_path}" ]; then + ocf_run tcm_node --createdev=iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE} \ + ${OCF_RESKEY_path} || exit $OCF_ERR_GENERIC + elif [ -e "$block_configfs_path" ] && [ $(cat "$block_configfs_path") != "${OCF_RESKEY_path}" ]; then + ocf_exit_reason "Existing iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE} has incorrect path: $(cat "$block_configfs_path") != ${OCF_RESKEY_path}" + exit $OCF_ERR_GENERIC + else + ocf_log info "iscsi iblock already exists: ${block_configfs_path}" fi - done - params="${params} ${OCF_RESKEY_additional_parameters}" - # cleanup: tgt (as of tgtadm version 1.0.24) does not like an explicit "bsoflags=direct" - # when used with "bstype=aio" (which always uses O_DIRECT) - [[ $OCF_RESKEY_tgt_bstype/$OCF_RESKEY_tgt_bsoflags = "aio/direct" ]] && OCF_RESKEY_tgt_bsoflags="" + if [ -n "${OCF_RESKEY_scsi_sn}" ]; then + ocf_run tcm_node --setunitserial=iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE} \ + ${OCF_RESKEY_scsi_sn} || exit $OCF_ERR_GENERIC + fi - tgt_args="" - [[ $OCF_RESKEY_tgt_bstype ]] && tgt_args="$tgt_args --bstype=$OCF_RESKEY_tgt_bstype" - [[ $OCF_RESKEY_tgt_bsoflags ]] && tgt_args="$tgt_args --bsoflags=$OCF_RESKEY_tgt_bsoflags" - [[ $OCF_RESKEY_tgt_device_type ]] && tgt_args="$tgt_args --device-type=$OCF_RESKEY_tgt_device_type" + lun_configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_target_iqn}/tpgt_1/lun/lun_${OCF_RESKEY_lun}/${OCF_RESOURCE_INSTANCE}/udev_path" + if [ ! -e "${lun_configfs_path}" ]; then + ocf_run lio_node --addlun=${OCF_RESKEY_target_iqn} 1 ${OCF_RESKEY_lun} \ + ${OCF_RESOURCE_INSTANCE} iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE} || exit $OCF_ERR_GENERIC + else + ocf_log info "iscsi lun already exists: ${lun_configfs_path}" + fi - ocf_run tgtadm --lld iscsi --op new --mode logicalunit \ - --tid=${TID} \ - --lun=${OCF_RESKEY_lun} \ - $tgt_args \ - --backing-store ${OCF_RESKEY_path} || exit $OCF_ERR_GENERIC - if [ -z "$params" ]; then - return $OCF_SUCCESS - else - ocf_run tgtadm --lld iscsi --op update --mode logicalunit \ - --tid=${TID} \ - --lun=${OCF_RESKEY_lun} \ - --params ${params// /,} || exit $OCF_ERR_GENERIC - fi - ;; - lio) - # For lio, we first have to create a target device, then - # add it to the Target Portal Group as an LU. - ocf_run tcm_node --createdev=iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE} \ - ${OCF_RESKEY_path} || exit $OCF_ERR_GENERIC - if [ -n "${OCF_RESKEY_scsi_sn}" ]; then - ocf_run tcm_node --setunitserial=iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE} \ - ${OCF_RESKEY_scsi_sn} || exit $OCF_ERR_GENERIC - fi - ocf_run lio_node --addlun=${OCF_RESKEY_target_iqn} 1 ${OCF_RESKEY_lun} \ - ${OCF_RESOURCE_INSTANCE} iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE} || exit $OCF_ERR_GENERIC - - if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then - for initiator in ${OCF_RESKEY_allowed_initiators}; do - ocf_run lio_node --addlunacl=${OCF_RESKEY_target_iqn} 1 \ - ${initiator} ${OCF_RESKEY_lun} ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC - done - fi - ;; - esac - - return $OCF_SUCCESS + if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then + for initiator in ${OCF_RESKEY_allowed_initiators}; do + acl_configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_target_iqn}/tpgt_1/acls/${initiator}/lun_${OCF_RESKEY_lun}" + if [ ! -e "${acl_configfs_path}" ]; then + ocf_run lio_node --addlunacl=${OCF_RESKEY_target_iqn} 1 \ + ${initiator} ${OCF_RESKEY_lun} ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC + else + ocf_log info "iscsi acl already exists: ${acl_configfs_path}" + fi + done + fi + ;; + lio-t) + # For lio, we first have to create a target device, then + # add it to the Target Portal Group as an LU. + ocf_run targetcli /backstores/block create name=${OCF_RESOURCE_INSTANCE} dev=${OCF_RESKEY_path} write_back=False || exit $OCF_ERR_GENERIC + if [ -n "${OCF_RESKEY_scsi_sn}" ]; then + echo ${OCF_RESKEY_scsi_sn} > /sys/kernel/config/target/core/iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE}/wwn/vpd_unit_serial + fi + ocf_run targetcli /iscsi/${OCF_RESKEY_target_iqn}/tpg1/luns create /backstores/block/${OCF_RESOURCE_INSTANCE} ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC + + if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then + for initiator in ${OCF_RESKEY_allowed_initiators}; do + ocf_run targetcli /iscsi/${OCF_RESKEY_target_iqn}/tpg1/acls create ${initiator} add_mapped_luns=False || exit $OCF_ERR_GENERIC + ocf_run targetcli /iscsi/${OCF_RESKEY_target_iqn}/tpg1/acls/${initiator} create ${OCF_RESKEY_lun} ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC + done + fi + ;; + esac + + # Force the monitor operation to pass before start is considered a success. + iSCSILogicalUnit_monitor } iSCSILogicalUnit_stop() { - iSCSILogicalUnit_monitor - if [ $? = $OCF_SUCCESS ]; then + iSCSILogicalUnit_monitor + if [ $? -eq $OCF_NOT_RUNNING ]; then + return $OCF_SUCCESS + fi + case $OCF_RESKEY_implementation in - iet) - # IET allows us to remove LUs while they are in use - ocf_run ietadm --op delete \ - --tid=${TID} \ - --lun=${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC + + iet) + # IET allows us to remove LUs while they are in use + ocf_run ietadm --op delete \ + --tid=${TID} \ + --lun=${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC ;; - tgt) + tgt) # tgt will fail to remove an LU while it is in use, # but at the same time does not allow us to # selectively shut down a connection that is using a @@ -359,202 +403,240 @@ iSCSILogicalUnit_stop() { # decides that the LU is no longer in use, or we get # timed out by the LRM. while ! ocf_run -warn tgtadm --lld iscsi --op delete --mode logicalunit \ - --tid ${TID} \ - --lun=${OCF_RESKEY_lun}; do - sleep 1 + --tid ${TID} \ + --lun=${OCF_RESKEY_lun}; do + sleep 1 + done + ;; + lio) + + acls_configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_target_iqn}/tpgt_1/acls" + for initiatorpath in ${acls_configfs_path}/*; do + initiator=$(basename "${initiatorpath}") + if [ -e "${initiatorpath}/lun_${OCF_RESKEY_lun}" ]; then + ocf_log info "deleting acl at ${initiatorpath}/lun_${OCF_RESKEY_lun}" + ocf_run lio_node --dellunacl=${OCF_RESKEY_target_iqn} 1 \ + ${initiator} ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC + fi done + lun_configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_target_iqn}/tpgt_1/lun/lun_#{${OCF_RESKEY_lun}/" + if [ -e "${lun_configfs_path}" ]; then + ocf_run lio_node --dellun=${OCF_RESKEY_target_iqn} 1 ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC + fi + block_configfs_path="/sys/kernel/config/target/core/iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESKEY_INSTANCE}/udev_path" + if [ -e "${block_configfs_path}" ]; then + ocf_run tcm_node --freedev=iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE} || exit $OCF_ERR_GENERIC + fi + ;; + lio-t) + ocf_run targetcli /iscsi/${OCF_RESKEY_target_iqn}/tpg1/luns delete ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC + if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then + for initiator in ${OCF_RESKEY_allowed_initiators}; do + if targetcli /iscsi/${OCF_RESKEY_target_iqn}/tpg1/acls/${initiator} status | grep "Mapped LUNs: 0" >/dev/null ; then + ocf_run targetcli /iscsi/${OCF_RESKEY_target_iqn}/tpg1/acls/ delete ${initiator} + fi + done + fi + + ocf_run targetcli /backstores/block delete ${OCF_RESOURCE_INSTANCE} || exit $OCF_ERR_GENERIC ;; - lio) - if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then - for initiator in ${OCF_RESKEY_allowed_initiators}; do - ocf_run lio_node --dellunacl=${OCF_RESKEY_target_iqn} 1 \ - ${initiator} ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC - done - fi - ocf_run lio_node --dellun=${OCF_RESKEY_target_iqn} 1 ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC - ocf_run tcm_node --freedev=iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE} || exit $OCF_ERR_GENERIC esac - fi - - return $OCF_SUCCESS + + return $OCF_SUCCESS } iSCSILogicalUnit_monitor() { - case $OCF_RESKEY_implementation in + case $OCF_RESKEY_implementation in iet) - # Figure out and set the target ID - TID=`sed -ne "s/tid:\([[:digit:]]\+\) name:${OCF_RESKEY_target_iqn}$/\1/p" < /proc/net/iet/volume` - if [ -z "${TID}" ]; then - # Our target is not configured, thus we're not - # running. - return $OCF_NOT_RUNNING - fi - # FIXME: this looks for a matching LUN and path, but does - # not actually test for the correct target ID. - grep -E -q "[[:space:]]+lun:${OCF_RESKEY_lun}.*path:${OCF_RESKEY_path}$" /proc/net/iet/volume && return $OCF_SUCCESS - ;; + # Figure out and set the target ID + TID=`sed -ne "s/tid:\([[:digit:]]\+\) name:${OCF_RESKEY_target_iqn}$/\1/p" < /proc/net/iet/volume` + if [ -z "${TID}" ]; then + # Our target is not configured, thus we're not + # running. + return $OCF_NOT_RUNNING + fi + # FIXME: this looks for a matching LUN and path, but does + # not actually test for the correct target ID. + grep -E -q "[[:space:]]+lun:${OCF_RESKEY_lun}.*path:${OCF_RESKEY_path}$" /proc/net/iet/volume && return $OCF_SUCCESS + ;; tgt) - # Figure out and set the target ID - TID=`tgtadm --lld iscsi --op show --mode target \ - | sed -ne "s/^Target \([[:digit:]]\+\): ${OCF_RESKEY_target_iqn}$/\1/p"` - if [ -z "$TID" ]; then - # Our target is not configured, thus we're not - # running. - return $OCF_NOT_RUNNING - fi - # This only looks for the backing store, but does not test - # for the correct target ID and LUN. - tgtadm --lld iscsi --op show --mode target \ - | grep -E -q "[[:space:]]+Backing store.*: ${OCF_RESKEY_path}$" && return $OCF_SUCCESS - ;; + # Figure out and set the target ID + TID=`tgtadm --lld iscsi --op show --mode target \ + | sed -ne "s/^Target \([[:digit:]]\+\): ${OCF_RESKEY_target_iqn}$/\1/p"` + if [ -z "$TID" ]; then + # Our target is not configured, thus we're not + # running. + return $OCF_NOT_RUNNING + fi + # This only looks for the backing store, but does not test + # for the correct target ID and LUN. + tgtadm --lld iscsi --op show --mode target \ + | grep -E -q "[[:space:]]+Backing store.*: ${OCF_RESKEY_path}$" && return $OCF_SUCCESS + ;; lio) - configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_target_iqn}/tpgt_1/lun/lun_${OCF_RESKEY_lun}/${OCF_RESOURCE_INSTANCE}/udev_path" - [ -e ${configfs_path} ] && [ `cat ${configfs_path}` = "${OCF_RESKEY_path}" ] && return $OCF_SUCCESS - ;; - esac - - return $OCF_NOT_RUNNING + configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_target_iqn}/tpgt_1/lun/lun_${OCF_RESKEY_lun}/${OCF_RESOURCE_INSTANCE}/udev_path" + [ -e ${configfs_path} ] && [ `cat ${configfs_path}` = "${OCF_RESKEY_path}" ] && return $OCF_SUCCESS + + # if we aren't activated, is a block device still left over? + block_configfs_path="/sys/kernel/config/target/core/iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESKEY_INSTANCE}/udev_path" + [ -e ${block_configfs_path} ] && ocf_log warn "existing block without an active lun: ${block_configfs_path}" + [ -e ${block_configfs_path} ] && return $OCF_ERR_GENERIC + + ;; + lio-t) + configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_target_iqn}/tpgt_1/lun/lun_${OCF_RESKEY_lun}/*/udev_path" + [ -e ${configfs_path} ] && [ `cat ${configfs_path}` = "${OCF_RESKEY_path}" ] && return $OCF_SUCCESS + ;; + esac + + return $OCF_NOT_RUNNING } iSCSILogicalUnit_validate() { - # Do we have all required variables? - for var in target_iqn lun path; do + # Do we have all required variables? + for var in target_iqn lun path; do param="OCF_RESKEY_${var}" if [ -z "${!param}" ]; then - ocf_log error "Missing resource parameter \"$var\"!" - exit $OCF_ERR_CONFIGURED + ocf_exit_reason "Missing resource parameter \"$var\"!" + exit $OCF_ERR_CONFIGURED fi - done + done - # Is the configured implementation supported? - case "$OCF_RESKEY_implementation" in - "iet"|"tgt"|"lio") - ;; + # Is the configured implementation supported? + case "$OCF_RESKEY_implementation" in + "iet"|"tgt"|"lio"|"lio-t") + ;; "") - # 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_log error "Undefined iSCSI target implementation" - exit $OCF_ERR_INSTALLED - ;; + # 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_log error "Unsupported iSCSI target implementation \"$OCF_RESKEY_implementation\"!" - exit $OCF_ERR_CONFIGURED - ;; - esac + ocf_exit_reason "Unsupported iSCSI target implementation \"$OCF_RESKEY_implementation\"!" + exit $OCF_ERR_CONFIGURED + ;; + esac - # Do we have a valid LUN? - case $OCF_RESKEY_implementation in + # Do we have a valid LUN? + case $OCF_RESKEY_implementation in iet) - # IET allows LUN 0 and up - [ $OCF_RESKEY_lun -ge 0 ] - case $? in + # IET allows LUN 0 and up + [ $OCF_RESKEY_lun -ge 0 ] + case $? in 0) - # OK - ;; + # OK + ;; 1) - ocf_log err "Invalid LUN $OCF_RESKEY_lun (must be a non-negative integer)." - exit $OCF_ERR_CONFIGURED - ;; + ocf_log err "Invalid LUN $OCF_RESKEY_lun (must be a non-negative integer)." + exit $OCF_ERR_CONFIGURED + ;; *) - ocf_log err "Invalid LUN $OCF_RESKEY_lun (must be an integer)." - exit $OCF_ERR_CONFIGURED - ;; - esac - ;; + ocf_log err "Invalid LUN $OCF_RESKEY_lun (must be an integer)." + exit $OCF_ERR_CONFIGURED + ;; + esac + ;; tgt) - # tgt reserves LUN 0 for its own purposes - [ $OCF_RESKEY_lun -ge 1 ] - case $? in + # tgt reserves LUN 0 for its own purposes + [ $OCF_RESKEY_lun -ge 1 ] + case $? in 0) - # OK - ;; + # OK + ;; 1) - ocf_log err "Invalid LUN $OCF_RESKEY_lun (must be greater than 0)." - exit $OCF_ERR_CONFIGURED - ;; + ocf_log err "Invalid LUN $OCF_RESKEY_lun (must be greater than 0)." + exit $OCF_ERR_CONFIGURED + ;; *) - ocf_log err "Invalid LUN $OCF_RESKEY_lun (must be an integer)." - exit $OCF_ERR_CONFIGURED - ;; - esac - ;; - 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 + ocf_log err "Invalid LUN $OCF_RESKEY_lun (must be an integer)." + exit $OCF_ERR_CONFIGURED + ;; + esac + ;; + 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) - # IET does not support setting the vendor and product ID - # (it always uses "IET" and "VIRTUAL-DISK") - unsupported_params="vendor_id product_id allowed_initiators lio_iblock tgt_bstype tgt_bsoflags tgt_device_type" - ;; + # IET does not support setting the vendor and product ID + # (it always uses "IET" and "VIRTUAL-DISK") + unsupported_params="vendor_id product_id allowed_initiators lio_iblock tgt_bstype tgt_bsoflags tgt_device_type" + ;; tgt) - unsupported_params="allowed_initiators lio_iblock" - ;; + unsupported_params="allowed_initiators lio_iblock" + ;; lio) - unsupported_params="scsi_id vendor_id product_id tgt_bstype tgt_bsoflags tgt_device_type" - ;; - 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 + unsupported_params="scsi_id vendor_id product_id tgt_bstype tgt_bsoflags tgt_device_type" + ;; + lio-t) + unsupported_params="scsi_id vendor_id product_id tgt_bstype tgt_bsoflags tgt_device_type lio_iblock" + ;; + 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? + if ! ocf_is_probe; then + # Do we have all required binaries? case $OCF_RESKEY_implementation in - iet) + iet) check_binary ietadm ;; - tgt) + tgt) check_binary tgtadm ;; - lio) + lio) check_binary tcm_node check_binary lio_node ;; + lio-t) + check_binary targetcli + ;; esac - # Is the required kernel functionality available? + # Is the required kernel functionality available? case $OCF_RESKEY_implementation in - iet) + 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 + 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 + tgt) + # tgt is userland only ;; esac - fi + fi - return $OCF_SUCCESS + return $OCF_SUCCESS } - case $1 in - meta-data) +meta-data) meta_data exit $OCF_SUCCESS ;; - usage|help) +usage|help) iSCSILogicalUnit_usage exit $OCF_SUCCESS ;; @@ -568,13 +650,14 @@ start) iSCSILogicalUnit_start;; stop) iSCSILogicalUnit_stop;; monitor|status) iSCSILogicalUnit_monitor;; reload) ocf_log err "Reloading..." - iSCSILogicalUnit_start + iSCSILogicalUnit_start ;; validate-all) ;; *) iSCSILogicalUnit_usage exit $OCF_ERR_UNIMPLEMENTED ;; esac + rc=$? ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc" exit $rc diff --git a/heartbeat/iSCSITarget b/heartbeat/iSCSITarget index a988fb2..72ec64a 100755 --- a/heartbeat/iSCSITarget +++ b/heartbeat/iSCSITarget @@ -1,7 +1,7 @@ #!/bin/bash # # -# iSCSITarget OCF RA. Exports and manages iSCSI targets. +# iSCSITarget OCF RA. Exports and manages iSCSI targets. # # (c) 2009-2010 Florian Haas, Dejan Muhamedagic, # and Linux-HA contributors @@ -34,11 +34,13 @@ # Defaults # Set a default implementation based on software installed if have_binary ietadm; then - OCF_RESKEY_implementation_default="iet" + OCF_RESKEY_implementation_default="iet" elif have_binary tgtadm; then - OCF_RESKEY_implementation_default="tgt" + OCF_RESKEY_implementation_default="tgt" elif have_binary lio_node; then - OCF_RESKEY_implementation_default="lio" + OCF_RESKEY_implementation_default="lio" +elif have_binary targetcli; then + OCF_RESKEY_implementation_default="lio-t" fi : ${OCF_RESKEY_implementation=${OCF_RESKEY_implementation_default}} @@ -67,12 +69,12 @@ Units (LUs) exported via a daemon that speaks the iSCSI protocol. The iSCSI target daemon implementation. Must be one of "iet", "tgt", -or "lio". If unspecified, an implementation is selected based on the +"lio", or "lio-t". If unspecified, an implementation is selected based on the availability of management utilities, with "iet" being tried first, -then "tgt", then "lio". +then "tgt", then "lio", then "lio-t". Specifies the iSCSI target implementation -("iet", "tgt" or "lio"). +("iet", "tgt", "lio", or "lio-t"). @@ -148,11 +150,11 @@ dependent. Neither the name nor the value may contain whitespace. - - - - - + + + + + @@ -170,182 +172,233 @@ END } iSCSITarget_start() { - iSCSITarget_monitor - if [ $? = $OCF_SUCCESS ]; then - return $OCF_SUCCESS - fi + iSCSITarget_monitor + if [ $? = $OCF_SUCCESS ]; then + return $OCF_SUCCESS + fi - local param - local name - local value - local initiator - local portal + local param + local name + local value + local initiator + local portal - case $OCF_RESKEY_implementation in + 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 - ;; + 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 - ;; + 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 + # 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_log warn "Unsupported iSCSI target parameter ${name}: will be ignored." + 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 - 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 + + # 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. + for portal in ${OCF_RESKEY_portals}; do + ocf_run targetcli /iscsi create ${OCF_RESKEY_iqn} || exit $OCF_ERR_GENERIC + 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 - 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 + # 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 targetcli /iscsi/${OCF_RESKEY_iqn}/tpg1/acls create ${initiator} || exit $OCF_ERR_GENERIC + done + 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 - # 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 - ;; - esac - - return $OCF_SUCCESS + # TODO: add CHAP authentication support when it gets added + # back into LIO + ocf_run targetcli /iscsi/${OCF_RESKEY_iqn}/tpg1/ set attribute authentication=0 || exit $OCF_ERR_GENERIC +# ocf_run targetcli /iscsi + ;; + esac + + iSCSITarget_monitor } iSCSITarget_stop() { - iSCSITarget_monitor - if [ $? = $OCF_SUCCESS ]; then + iSCSITarget_monitor + if [ $? -eq $OCF_NOT_RUNNING ]; then + return $OCF_SUCCESS + fi + local tid case $OCF_RESKEY_implementation in - iet) + 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 + 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) + /^[[: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 + # $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 + # 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 \ + ocf_run ietadm --op delete --user \ --tid=${tid} \ --params=IncomingUser=${OCF_RESKEY_incoming_username} \ || exit $OCF_ERR_GENERIC @@ -353,216 +406,226 @@ iSCSITarget_stop() { # 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 + 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" \ + 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" \ + ocf_run sed -e "/^${OCF_RESKEY_iqn}[[:space:]]/d" \ -i /etc/initiators.allow fi ;; - tgt) + 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; - }') + | 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 \ + # $2 $1 looks like "--sid=X --cid=Y" + ocf_run tgtadm --lld iscsi --op delete --mode connection \ --tid=${tid} $2 $1 - shift 2 + shift 2 done - # In tgt, we must first unbind the user account from + # 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 + 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 + 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) + 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_run targetcli /iscsi delete ${OCF_RESKEY_iqn} || exit $OCF_ERR_GENERIC + ;; esac - fi - return $OCF_SUCCESS + return $OCF_SUCCESS } iSCSITarget_monitor() { - case $OCF_RESKEY_implementation in + case $OCF_RESKEY_implementation in iet) - grep -Eq "tid:[0-9]+ name:${OCF_RESKEY_iqn}" /proc/net/iet/volume && return $OCF_SUCCESS - ;; + grep -Eq "tid:[0-9]+ name:${OCF_RESKEY_iqn}" /proc/net/iet/volume && return $OCF_SUCCESS + ;; tgt) - tgtadm --lld iscsi --op show --mode target \ + tgtadm --lld iscsi --op show --mode target \ | grep -Eq "Target [0-9]+: ${OCF_RESKEY_iqn}" && return $OCF_SUCCESS - ;; - lio) - # 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 - ;; - esac - - return $OCF_NOT_RUNNING + ;; + 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 + ;; + esac + + return $OCF_NOT_RUNNING } iSCSITarget_validate() { - # Do we have all required variables? - local required_vars - case $OCF_RESKEY_implementation in + # Do we have all required variables? + local required_vars + case $OCF_RESKEY_implementation in iet) - required_vars="iqn" - ;; + required_vars="iqn" + ;; tgt) - required_vars="iqn tid" - ;; - esac - 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 + 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") - ;; + # Is the configured implementation supported? + case "$OCF_RESKEY_implementation" in + "iet"|"tgt"|"lio"|"lio-t") + ;; "") - # 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_log error "Undefined iSCSI target implementation" - exit $OCF_ERR_INSTALLED - ;; + # 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_log error "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 + 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) - # TODO: Remove incoming_username and incoming_password - # from this check when LIO 3.0 gets CHAP authentication - unsupported_params="tid incoming_username incoming_password" - ;; - 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 + # IET and tgt do not support binding a target portal to a + # specific IP address. + unsupported_params="portals" + ;; + lio|lio-t) + # TODO: Remove incoming_username and incoming_password + # from this check when LIO 3.0 gets CHAP authentication + unsupported_params="tid incoming_username incoming_password" + ;; + esac - if ! ocf_is_probe; then - # Do we have all required binaries? + 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) + iet) check_binary ietadm ;; - tgt) + tgt) check_binary tgtadm ;; - lio) + lio) check_binary tcm_node check_binary lio_node ;; + lio-t) + check_binary targetcli + ;; esac - # Is the required kernel functionality available? + # Is the required kernel functionality available? case $OCF_RESKEY_implementation in - iet) + 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 + 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 + tgt) + # tgt is userland only ;; - lio) - # lio needs configfs to be mounted + 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 + 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 + # 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 + 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 + ;; esac - fi + fi - return $OCF_SUCCESS + return $OCF_SUCCESS } @@ -585,7 +648,7 @@ start) iSCSITarget_start;; stop) iSCSITarget_stop;; monitor|status) iSCSITarget_monitor;; reload) ocf_log err "Reloading..." - iSCSITarget_start + iSCSITarget_start ;; validate-all) ;; *) iSCSITarget_usage -- 1.8.4.2