| #!/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.<reversed domain name>[: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 |