summaryrefslogtreecommitdiffstats
path: root/rgmanager/src/resources/smb.sh.in
diff options
context:
space:
mode:
Diffstat (limited to 'rgmanager/src/resources/smb.sh.in')
-rw-r--r--rgmanager/src/resources/smb.sh.in698
1 files changed, 698 insertions, 0 deletions
diff --git a/rgmanager/src/resources/smb.sh.in b/rgmanager/src/resources/smb.sh.in
new file mode 100644
index 0000000..f2d566f
--- /dev/null
+++ b/rgmanager/src/resources/smb.sh.in
@@ -0,0 +1,698 @@
+#!@BASH_SHELL@
+
+#
+# Script to manage a Samba file-sharing service component.
+# Unline NFS, this should be placed at the top level of a service
+# because it will try to gather information necessary to run the
+# smbd/nmbd daemons at run-time from the service structure.
+#
+# Copyright (C) 1997-2003 Sistina Software, Inc. All rights reserved.
+# Copyright (C) 2004-2011 Red Hat, Inc. All rights reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# Author(s):
+# Lon Hohberger (lhh at redhat.com)
+# Tim Burke (tburke at redhat.com)
+#
+
+LC_ALL=C
+LANG=C
+PATH=/bin:/sbin:/usr/bin:/usr/sbin
+export LC_ALL LANG PATH
+
+#
+# Definitions!
+#
+declare SAMBA_CONFIG_DIR=/etc/samba
+declare SMBD_COMMAND=/usr/sbin/smbd
+declare NMBD_COMMAND=/usr/sbin/nmbd
+declare KILLALL_COMMAND=/usr/bin/killall
+declare SAMBA_PID_DIR=/var/run/samba
+declare SAMBA_LOCK_DIR=/var/cache/samba
+
+#
+# gross globals
+#
+declare -a ipkeys
+declare -a fskeys
+
+# Don't change please :)
+_FAIL=255
+
+. $(dirname $0)/ocf-shellfuncs
+
+meta_data()
+{
+ cat <<EOT
+<?xml version="1.0"?>
+<resource-agent version="rgmanager 2.0" name="smb">
+ <version>1.0</version>
+
+ <longdesc lang="en">
+ Dynamic smbd/nmbd resource agent
+ </longdesc>
+ <shortdesc lang="en">
+ Dynamic smbd/nmbd resource agent
+ </shortdesc>
+
+ <parameters>
+ <parameter name="name" unique="1" primary="1">
+ <longdesc lang="en">
+ Samba Symbolic Name. This name will
+ correspond to /etc/samba/smb.conf.NAME
+ </longdesc>
+ <shortdesc lang="en">
+ Samba Name
+ </shortdesc>
+ <content type="string"/>
+ </parameter>
+
+ <parameter name="workgroup">
+ <longdesc lang="en">
+ Workgroup name
+ </longdesc>
+ <shortdesc lang="en">
+ Workgroup name
+ </shortdesc>
+ <content type="string" default="LINUXCLUSTER"/>
+ </parameter>
+
+ <parameter name="service_name" inherit="service%name">
+ <longdesc lang="en">
+ Inherit the service name. We need to know
+ the service name in order to determine file
+ systems and IPs for this smb service.
+ </longdesc>
+ <shortdesc lang="en">
+ Inherit the service name.
+ </shortdesc>
+ <content type="string"/>
+ </parameter>
+ </parameters>
+
+ <actions>
+ <action name="start" timeout="0"/>
+ <action name="stop" timeout="0"/>
+
+ <!-- This is just a wrapper for LSB init scripts, so monitor
+ and status can't have a timeout, nor do they do any extra
+ work regardless of the depth -->
+ <action name="status" interval="30s" timeout="0"/>
+ <action name="monitor" interval="30s" timeout="0"/>
+
+ <action name="meta-data" timeout="0"/>
+ <action name="validate-all" timeout="0"/>
+ </actions>
+</resource-agent>
+EOT
+}
+
+
+#
+# Usage: ccs_get key
+#
+ccs_get()
+{
+ declare outp
+ declare key
+
+ [ -n "$1" ] || return $_FAIL
+
+ key="$*"
+
+ outp=$(ccs_tool query "$key" 2>&1)
+ if [ $? -ne 0 ]; then
+ if [ "$outp" = "${outp/No data available/}" ] || [ "$outp" = "${outp/Operation not permitted/}" ]; then
+ ocf_log err "$outp ($key)"
+ return $_FAIL
+ fi
+
+ # no real error, just no data available
+ return 0
+ fi
+
+ echo $outp
+
+ return 0
+}
+
+
+#
+# Build a list of service IP keys; traverse refs if necessary
+#
+get_service_ip_keys()
+{
+ declare svc=$1
+ declare -i x y=0
+ declare outp
+ declare key
+
+ #
+ # Find service-local IP keys
+ #
+ x=1
+ while : ; do
+ key="/cluster/rm/service[@name=\"$svc\"]/ip[$x]"
+
+ #
+ # Try direct method
+ #
+ outp=$(ccs_get "$key/@address")
+ if [ $? -ne 0 ]; then
+ return 1
+ fi
+
+ #
+ # Try by reference
+ #
+ if [ -z "$outp" ]; then
+ outp=$(ccs_get "$key/@ref")
+ if [ $? -ne 0 ]; then
+ return 1
+ fi
+ key="/cluster/rm/resources/ip[@address=\"$outp\"]"
+ fi
+
+ if [ -z "$outp" ]; then
+ break
+ fi
+
+ #ocf_log debug "IP $outp found @ $key"
+
+ ipkeys[$y]="$key"
+
+ ((y++))
+ ((x++))
+ done
+
+ ocf_log debug "$y IP addresses found for $svc/$OCF_RESKEY_name"
+
+ return 0
+}
+
+
+#
+# Build a list of service fs keys, traverse refs if necessary
+#
+get_service_fs_keys()
+{
+ declare svc=$1
+ declare -i x y=0
+ declare outp
+ declare key
+
+ #
+ # Find service-local IP keys
+ #
+ x=1
+ while : ; do
+ key="/cluster/rm/service[@name=\"$svc\"]/fs[$x]"
+
+ #
+ # Try direct method
+ #
+ outp=$(ccs_get "$key/@name")
+ if [ $? -ne 0 ]; then
+ return 1
+ fi
+
+ #
+ # Try by reference
+ #
+ if [ -z "$outp" ]; then
+ outp=$(ccs_get "$key/@ref")
+ if [ $? -ne 0 ]; then
+ return 1
+ fi
+ key="/cluster/rm/resources/fs[@name=\"$outp\"]"
+ fi
+
+ if [ -z "$outp" ]; then
+ break
+ fi
+
+ #ocf_log debug "filesystem $outp found @ $key"
+
+ fskeys[$y]="$key"
+
+ ((y++))
+ ((x++))
+ done
+
+ ocf_log debug "$y filesystems found for $svc/$OCF_RESKEY_name"
+
+ return 0
+}
+
+
+build_ip_list()
+{
+ declare ipaddrs ipaddr
+ declare -i x=0
+
+ while [ -n "${ipkeys[$x]}" ]; do
+ ipaddr=$(ccs_get "${ipkeys[$x]}/@address")
+ if [ -z "$ipaddr" ]; then
+ break
+ fi
+
+ ipaddrs="$ipaddrs $ipaddr"
+
+ ((x++))
+ done
+
+ echo $ipaddrs
+}
+
+
+add_sha1()
+{
+ declare sha1line="# rgmanager-sha1 $(sha1sum "$1")"
+ echo $sha1line >> "$1"
+}
+
+
+verify_sha1()
+{
+ declare tmpfile="$(mktemp /tmp/smb-$OCF_RESKEY_name.tmp.XXXXXX)"
+ declare current exp
+
+ exp=$(grep "^# rgmanager-sha1.*$1" "$1" | head -1)
+ if [ -z "$exp" ]; then
+ # No sha1 line. We're done.
+ ocf_log debug "No SHA1 info in $1"
+ return 1
+ fi
+
+ #
+ # Find expected sha1 and expected file name
+ #
+ exp=${exp/*sha1 /}
+ exp=${exp/ */}
+
+ grep -v "^# rgmanager-sha1" "$1" > "$tmpfile"
+ current=$(sha1sum "$tmpfile")
+ current=${current/ */}
+
+ rm -f "$tmpfile"
+
+ if [ "$current" = "$exp" ]; then
+ ocf_log debug "SHA1 sum matches for $1"
+ return 0
+ fi
+ ocf_log debug "SHA1 sum does not match for $1"
+ return 1
+}
+
+
+add_fs_entries()
+{
+ declare conf="$1"
+ declare sharename
+ declare sharepath key
+
+ declare -i x=0
+
+ while [ -n "${fskeys[$x]}" ]; do
+ key="${fskeys[$x]}/@name"
+
+ sharename=$(ccs_get "$key")
+ if [ -z "$sharename" ]; then
+ break
+ fi
+
+ key="${fskeys[$x]}/@mountpoint"
+ sharepath=$(ccs_get "$key")
+ if [ -z "$sharepath" ]; then
+ break
+ fi
+
+ cat >> "$conf" <<EODEV
+[$sharename]
+ comment = Auto-generated $sharename share
+ # Hide the secret cluster files
+ veto files = /.clumanager/.rgmanager/
+ browsable = yes
+ writable = no
+ public = yes
+ path = $sharepath
+
+EODEV
+
+ ((x++))
+ done
+}
+
+
+#
+# Generate the samba configuration if neede for this service.
+#
+gen_smb_conf()
+{
+ declare conf="$1"
+ declare lvl="debug"
+
+ if [ -f "$conf" ]; then
+ verify_sha1 "$conf"
+ if [ $? -ne 0 ]; then
+ ocf_log debug "Config file changed; skipping"
+ return 0
+ fi
+ else
+ lvl="info"
+ fi
+
+ ocf_log $lvl "Creating $conf"
+
+ get_service_ip_keys "$OCF_RESKEY_service_name"
+ get_service_fs_keys "$OCF_RESKEY_service_name"
+
+ cat > "$conf" <<EOT
+#
+# "$conf"
+#
+# This template configuration wass automatically generated, and will
+# be automatically regenerated if removed. Please modify this file to
+# speficy subdirectories and/or client access permissions.
+#
+# Once this file has been altered, automatic re-generation will stop.
+# Remember to copy this file to all other cluster members after making
+# changes, or your SMB service will not operate correctly.
+#
+# From a cluster perspective, the key fields are:
+# lock directory - must be unique per samba service.
+# bind interfaces only - must be present set to yes.
+# interfaces - must be set to service floating IP address.
+# path - must be the service mountpoint or subdirectory thereof.
+#
+
+[global]
+ workgroup = $OCF_RESKEY_workgroup
+ pid directory = /var/run/samba/$OCF_RESKEY_name
+ lock directory = /var/cache/samba/$OCF_RESKEY_name
+ log file = /var/log/samba/%m.log
+ #private dir = /var/
+ encrypt passwords = yes
+ bind interfaces only = yes
+ netbios name = ${OCF_RESKEY_name/ /_}
+
+ #
+ # Interfaces are based on ip resources at the top level of
+ # "$OCF_RESKEY_service_name"; IPv6 addresses may or may not
+ # work correctly.
+ #
+ interfaces = $(build_ip_list)
+
+#
+# Shares based on fs resources at the top level of "$OCF_RESKEY_service_name"
+#
+EOT
+ add_fs_entries "$conf"
+ add_sha1 "$conf"
+
+ return 0
+}
+
+
+#
+# Kill off the specified PID
+# (from clumanager 1.0.x/1.2.x)
+#
+# Killing off the samba daemons was miserable to implement, merely
+# because killall doesn't distinguish by program commandline.
+# Consequently I had to implement these routines to selectively pick 'em off.
+#
+# Kills of either the {smbd|nmbd} which is running and was started with
+# the specified argument. Can't use `killall` to do this because it
+# doesn't allow you to distinguish which process to kill based on any
+# of the program arguments.
+#
+# This routine is also called on "status" checks. In this case it doesn't
+# actually kill anything.
+#
+# Parameters:
+# daemonName - daemon name, can be either smbd or nmbd
+# command - [stop|start|status]
+# arg - argument passed to daemon. In this case its not the
+# full set of program args, rather its really just the
+# samba config file.
+#
+# Returns: 0 - success (or the daemon isn't currently running)
+# 1 - failure
+#
+kill_daemon_by_arg()
+{
+ declare daemonName=$1
+ declare action=$2
+ declare arg=$3
+ # Create a unique temporary file to stash off intermediate results
+ declare tmpfile_str=/tmp/sambapids.XXXXXX
+ declare tmpfile
+ declare ret
+
+ tmpfile=$(mktemp $tmpfile_str); ret_val=$?
+
+ if [ -z "$tmpfile" ]; then
+ ocf_log err "kill_daemon_by_arg: Can't create tmp file"
+ return $_FAIL
+ fi
+
+ # Mumble, need to strip off the /etc/samba portion, otherwise the
+ # grep pattern matching will fail.
+ declare confFile="$(basename $arg)"
+
+ # First generate a list of candidate pids.
+ pidof $daemonName > $tmpfile
+ if [ $? -ne 0 ]; then
+ ocf_log debug "kill_daemon_by_arg: no pids for $daemonName"
+ rm -f $tmpfile
+ case "$action" in
+ 'stop')
+ return 0
+ ;;
+ 'status')
+ return $_FAIL
+ ;;
+ esac
+ return 0
+ fi
+
+ # If you don't find any matching daemons for a "stop" operation, thats
+ # considered success; whereas for "status" inquiries its a failure.
+ case "$action" in
+ 'stop')
+ ret=0
+ ;;
+ 'status')
+ ret=$_FAIL
+ ;;
+ esac
+ #
+ # At this point tmpfile contains a set of pids for the corresponding
+ # {smbd|nmbd}. Now look though this candidate set of pids and compare
+ # the program arguments (samba config file name). This distinguishes
+ # which ones should be killed off.
+ #
+ declare daemonPid=""
+ for daemonPid in $(cat $tmpfile); do
+ declare commandLine=$(cat /proc/$daemonPid/cmdline)
+ declare confBase="$(basename $commandLine)"
+ if [ "$confBase" = "$confFile" ]; then
+ case "$action" in
+ 'status')
+ rm -f $tmpfile
+ return 0
+ ;;
+ esac
+ kill_daemon_pid $daemonPid
+ if [ $? -ne 0 ]; then
+ ret=$_FAIL
+ ocf_log err \
+ "kill_daemon_by_arg: kill_daemon_pid $daemonPid failed"
+ else
+ ocf_log debug \
+ "kill_daemon_by_arg: kill_daemon_pid $daemonPid success"
+ fi
+ fi
+ done
+ rm -f $tmpfile
+ return $ret
+}
+
+
+#
+# Kill off the specified PID
+# (from clumanager 1.0.x/1.2.x)
+#
+kill_daemon_pid()
+{
+ declare pid=$1
+ declare retval=0
+
+
+ kill -TERM $pid
+ if [ $? -eq 0 ]; then
+ ocf_log debug "Samba: successfully killed $pid"
+ else
+ ocf_log debug "Samba: failed to kill $pid"
+ retval=$_FAIL
+ fi
+ return $retval
+}
+
+
+share_start_stop()
+{
+ declare command=$1
+ declare conf="$SAMBA_CONFIG_DIR/smb.conf.$OCF_RESKEY_name"
+ declare smbd_command
+ declare nmbd_command
+ declare netbios_name
+
+ #
+ # Specify daemon options
+ # -D = spawn off as separate daemon
+ # -s = the following arg specifies the config file
+ #
+ declare smbd_options="-D -s"
+ declare nmbd_options="-D -s"
+
+ if [ "$command" = "start" ]; then
+ gen_smb_conf "$conf"
+ else
+ if ! [ -f "$conf" ]; then
+ ocf_log warn "\"$conf\" missing during $command"
+ fi
+ fi
+
+ #
+ # On clusters with multiple samba shares, we need to ensure (as much
+ # as possible) that each service is advertised as a separate netbios
+ # name.
+ #
+ # Generally, the admin sets this in smb.conf.NAME - but since
+ # it is not required, we need another option. Consequently, we use
+ # smb instance name (which must be unique)
+ #
+ if [ -f "$conf" ]; then
+ grep -qe "^\([[:space:]]\+n\|n\)etbios[[:space:]]\+name[[:space:]]*=[[:space:]]*[[:alnum:]]\+" "$conf"
+ if [ $? -ne 0 ]; then
+
+ netbios_name=$OCF_RESKEY_name
+
+ ocf_log notice "Using $netbios_name as NetBIOS name (service $OCF_RESKEY_service_name)"
+ nmbd_options=" -n $netbios_name $nmbd_options"
+ fi
+ fi
+
+ case $command in
+ start)
+ ocf_log info "Starting Samba instance \"$OCF_RESKEY_name\""
+ mkdir -p "$SAMBA_PID_DIR/$OCF_RESKEY_name"
+ mkdir -p "$SAMBA_LOCK_DIR/$OCF_RESKEY_name"
+
+ [ -f "$SMBD_COMMAND" ] || exit $OCF_ERR_INSTALLED
+ [ -f "$NMBD_COMMAND" ] || exit $OCF_ERR_INSTALLED
+
+ # Kick off the per-service smbd
+ $SMBD_COMMAND $smbd_options "$conf"
+ ret_val=$?
+ if [ $ret_val -ne 0 ]; then
+ ocf_log err "Samba service failed: $SMBD_COMMAND $smbd_options \"$conf\""
+ return $_FAIL
+ fi
+ ocf_log debug "Samba service succeeded: $SMBD_COMMAND $smbd_options \"$conf\""
+
+ # Kick off the per-service nmbd
+ $NMBD_COMMAND $nmbd_options "$conf"
+ ret_val=$?
+ if [ $ret_val -ne 0 ]; then
+ ocf_log err "Samba service failed: $NMBD_COMMAND $nmbd_options \"$conf\""
+ return $_FAIL
+ fi
+ ocf_log debug "Samba service succeeded: $NMBD_COMMAND $nmbd_options \"$conf\""
+ ;;
+ stop)
+ ocf_log info "Stopping Samba instance \"$OCF_RESKEY_name\""
+
+ kill_daemon_by_arg "nmbd" $command "$conf"
+ kill_daemon_by_arg "smbd" $command "$conf"
+ if [ "$SAMBA_PID_DIR/$OCF_RESKEY_name" != "/" ]; then
+ pushd "$SAMBA_PID_DIR" &> /dev/null
+ rm -rf "$OCF_RESKEY_name"
+ popd &> /dev/null
+ fi
+ if [ "$SAMBA_LOCK_DIR/$OCF_RESKEY_name" != "/" ]; then
+ pushd "$SAMBA_LOCK_DIR" &> /dev/null
+ rm -rf "$OCF_RESKEY_name"
+ popd &> /dev/null
+ fi
+ ;;
+ status)
+ ocf_log debug "Checking Samba instance \"$OCF_RESKEY_name\""
+ kill_daemon_by_arg "nmbd" $command "$conf"
+ if [ $? -ne 0 ]; then
+ ocf_log err \
+ "share_start_stop: nmbd for service $svc_name died!"
+ return $_FAIL
+ fi
+ kill_daemon_by_arg "smbd" $command "$conf"
+ if [ $? -ne 0 ]; then
+ ocf_log err \
+ "share_start_stop: nmbd for service $svc_name died!"
+ return $_FAIL
+ fi
+ ;;
+ esac
+}
+
+
+verify_all()
+{
+ [ -z "$OCF_RESKEY_workgroup" ] && export OCF_RESKEY_workgroup="LINUXCLUSTER"
+ [ -n "${OCF_RESKEY_name}" ] || exit $OCF_ERR_ARGS # Invalid Argument
+ if [ -z "${OCF_RESKEY_service_name}" ]; then
+ ocf_log ERR "Samba service ${OCF_RESKEY_name} is not the child of a service"
+ exit $OCF_ERR_ARGS
+ fi
+}
+
+case $1 in
+ meta-data)
+ meta_data
+ exit 0
+ ;;
+ start|stop)
+ verify_all
+ share_start_stop $1
+ exit $?
+ ;;
+ status|monitor)
+ verify_all
+ share_start_stop status
+ exit $?
+ ;;
+ validate-all)
+ verify_all
+ echo "Yer radio's workin', driver!"
+ exit 0
+ ;;
+ *)
+ echo "usage: $0 {start|stop|status|monitor|meta-data|validate-all}"
+ exit $OCF_ERR_UNIMPLEMENTED
+ ;;
+esac
+