#!@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 < 1.0 Dynamic smbd/nmbd resource agent Dynamic smbd/nmbd resource agent Samba Symbolic Name. This name will correspond to /etc/samba/smb.conf.NAME Samba Name Workgroup name Workgroup name Inherit the service name. We need to know the service name in order to determine file systems and IPs for this smb service. Inherit the service name. 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" < "$conf" < $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