diff options
Diffstat (limited to 'heartbeat/slapd.in')
-rw-r--r-- | heartbeat/slapd.in | 594 |
1 files changed, 594 insertions, 0 deletions
diff --git a/heartbeat/slapd.in b/heartbeat/slapd.in new file mode 100644 index 0000000..ffccd1d --- /dev/null +++ b/heartbeat/slapd.in @@ -0,0 +1,594 @@ +#!@BASH_SHELL@ +# +# Stand-alone LDAP Daemon (slapd) +# +# Description: Manages Stand-alone LDAP Daemon (slapd) as an OCF resource in +# an high-availability setup. +# +# Authors: Jeroen Koekkoek +# nozawat@gmail.com +# John Keith Hohm +# +# License: GNU General Public License (GPL) +# Copyright: (C) 2011 Pagelink B.V. +# +# The OCF code was inspired by the Postfix resource script written by +# Raoul Bhatia <r.bhatia@ipax.at>. +# +# The code for managing the slapd instance is based on the the slapd init +# script found in Debian GNU/Linux 6.0. +# +# OCF parameters: +# OCF_RESKEY_slapd +# OCF_RESKEY_ldapsearch +# OCF_RESKEY_config +# OCF_RESKEY_pidfile +# OCF_RESKEY_user +# OCF_RESKEY_group +# OCF_RESKEY_services +# OCF_RESKEY_watch_suffix +# OCF_RESKEY_ignore_suffix +# OCF_RESKEY_bind_dn +# OCF_RESKEY_password +# OCF_RESKEY_parameters +# OCF_RESKEY_stop_escalate +# OCF_RESKEY_maxfiles +# +################################################################################ + +# Initialization: + +: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} +. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs + +# Parameter defaults + +OCF_RESKEY_slapd_default="/usr/sbin/slapd" +OCF_RESKEY_ldapsearch_default="ldapsearch" +OCF_RESKEY_config_default="" +OCF_RESKEY_pidfile_default="" +OCF_RESKEY_user_default="" +OCF_RESKEY_group_default="" +OCF_RESKEY_services_default="ldap:///" +OCF_RESKEY_watch_suffix_default="" +OCF_RESKEY_ignore_suffix_default="" +OCF_RESKEY_bind_dn_default="" +OCF_RESKEY_password_default="" +OCF_RESKEY_parameters_default="" +OCF_RESKEY_stop_escalate_default="15" +OCF_RESKEY_maxfiles_default="" + +: ${OCF_RESKEY_slapd=${OCF_RESKEY_slapd_default}} +: ${OCF_RESKEY_ldapsearch=${OCF_RESKEY_ldapsearch_default}} +: ${OCF_RESKEY_config=${OCF_RESKEY_config_default}} +: ${OCF_RESKEY_pidfile=${OCF_RESKEY_pidfile_default}} +: ${OCF_RESKEY_user=${OCF_RESKEY_user_default}} +: ${OCF_RESKEY_group=${OCF_RESKEY_group_default}} +: ${OCF_RESKEY_services=${OCF_RESKEY_services_default}} +: ${OCF_RESKEY_watch_suffix=${OCF_RESKEY_watch_suffix_default}} +: ${OCF_RESKEY_ignore_suffix=${OCF_RESKEY_ignore_suffix_default}} +: ${OCF_RESKEY_bind_dn=${OCF_RESKEY_bind_dn_default}} +: ${OCF_RESKEY_password=${OCF_RESKEY_password_default}} +: ${OCF_RESKEY_parameters=${OCF_RESKEY_parameters_default}} +: ${OCF_RESKEY_stop_escalate=${OCF_RESKEY_stop_escalate_default}} +: ${OCF_RESKEY_maxfiles=${OCF_RESKEY_maxfiles_default}} + +USAGE="Usage: $0 {start|stop|status|monitor|validate-all|meta-data}" +ORIG_IFS=$IFS +NEWLINE=' +' + +################################################################################ + +usage() { + echo $USAGE >&2 +} + +meta_data() +{ + cat <<END +<?xml version="1.0"?> +<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd"> +<resource-agent name="slapd" version="0.1"> +<version>1.0</version> + +<longdesc lang="en"> +Resource script for Stand-alone LDAP Daemon (slapd). It manages a slapd instance as an OCF resource. +</longdesc> +<shortdesc lang="en">Manages a Stand-alone LDAP Daemon (slapd) instance</shortdesc> + +<parameters> + +<parameter name="slapd" unique="0" required="0"> +<longdesc lang="en"> +Full path to the slapd binary. +For example, "/usr/sbin/slapd". +</longdesc> +<shortdesc lang="en">Full path to slapd binary</shortdesc> +<content type="string" default="${OCF_RESKEY_slapd_default}" /> +</parameter> + +<parameter name="ldapsearch" unique="0" required="0"> +<longdesc lang="en"> +Full path to the ldapsearch binary. +For example, "/usr/bin/ldapsearch". +</longdesc> +<shortdesc lang="en">Full path to ldapsearch binary</shortdesc> +<content type="string" default="${OCF_RESKEY_ldapsearch_default}" /> +</parameter> + +<parameter name="config" required="0" unique="1"> +<longdesc lang="en"> +Full path to a slapd configuration directory or a slapd configuration file. +For example, "/etc/ldap/slapd.d" or "/etc/ldap/slapd.conf". +</longdesc> +<shortdesc lang="en">Full path to configuration directory or file</shortdesc> +<content type="string" default="${OCF_RESKEY_config_default}"/> +</parameter> + +<parameter name="pidfile" required="0" unique="0"> +<longdesc lang="en"> +File to read the PID from; read from olcPidFile/pidfile in config if not set. +</longdesc> +<shortdesc lang="en">File to read PID from</shortdesc> +<content type="string" default="${OCF_RESKEY_pidfile_default}" /> +</parameter> + +<parameter name="user" unique="0" required="0"> +<longdesc lang="en"> +User name or id slapd will run with. The group id is also changed to this +user's gid, unless the group parameter is used to override. +</longdesc> +<shortdesc lang="en">User name or id slapd will run with</shortdesc> +<content type="string" default="${OCF_RESKEY_user_default}" /> +</parameter> + +<parameter name="group" unique="0" required="0"> +<longdesc lang="en"> +Group name or id slapd will run with. +</longdesc> +<shortdesc lang="en">Group name or id slapd will run with</shortdesc> +<content type="string" default="${OCF_RESKEY_group_default}" /> +</parameter> + +<parameter name="services" required="0" unique="1"> +<longdesc lang="en"> +LDAP (and other scheme) URLs slapd will serve. +For example, "ldap://127.0.0.1:389 ldaps:/// ldapi:///" +</longdesc> +<shortdesc lang="en">LDAP (and other scheme) URLs to serve</shortdesc> +<content type="string" default="${OCF_RESKEY_services_default}"/> +</parameter> + +<parameter name="watch_suffix" required="0" unique="0"> +<longdesc lang="en"> +Suffix (database backend) that will be monitored for availability. Multiple +suffixes can be specified by providing a space separated list. By providing one +or more suffixes here, the ignore_suffix parameter is discarded. All suffixes +will be monitored if left blank. +</longdesc> +<shortdesc lang="en">Suffix that will be monitored for availability.</shortdesc> +<content type="string" default="${OCF_RESKEY_watch_suffix_default}"/> +</parameter> + +<parameter name="ignore_suffix" required="0" unique="0"> +<longdesc lang="en"> +Suffix (database backend) that will not be monitored for availability. Multiple +suffixes can be specified by providing a space separated list. No suffix will +be excluded if left blank. +</longdesc> +<shortdesc lang="en">Suffix that will not be monitored for availability.</shortdesc> +<content type="string" default="${OCF_RESKEY_ignore_suffix_default}"/> +</parameter> + +<parameter name="bind_dn" required="0" unique="0"> +<longdesc lang="en"> +Distinguished Name used to bind to the LDAP directory for testing. Leave blank +to bind to the LDAP directory anonymously. +</longdesc> +<shortdesc lang="en">Distinguished Name used to bind to the LDAP directory for testing.</shortdesc> +<content type="string" default="${OCF_RESKEY_bind_dn_default}"/> +</parameter> + +<parameter name="password" required="0" unique="0"> +<longdesc lang="en"> +Password used to bind to the LDAP directory for testing. +</longdesc> +<shortdesc lang="en">Password used to bind to the LDAP directory for testing.</shortdesc> +<content type="string" default="${OCF_RESKEY_password_default}"/> +</parameter> + +<parameter name="parameters" unique="0" required="0"> +<longdesc lang="en"> +slapd may be called with additional parameters. +Specify any of them here. +</longdesc> +<shortdesc lang="en">Any additional parameters to slapd.</shortdesc> +<content type="string" default="${OCF_RESKEY_parameters_default}" /> +</parameter> + +<parameter name="stop_escalate" unique="0" required="0"> +<longdesc lang="en"> +Number of seconds to wait for shutdown (using SIGTERM) before resorting to +SIGKILL +</longdesc> +<shortdesc lang="en">Seconds before stop escalation to KILL</shortdesc> +<content type="integer" default="${OCF_RESKEY_stop_escalate_default}" /> +</parameter> + +<parameter name="maxfiles"> +<longdesc lang="en"> +Maximum number of open files (for ulimit -n) +</longdesc> +<shortdesc lang="en">Max open files</shortdesc> +<content type="string" default="${OCF_RESKEY_maxfiles_default}" /> +</parameter> +</parameters> + +<actions> +<action name="start" timeout="20s" /> +<action name="stop" timeout="20s" /> +<action name="monitor" depth="0" timeout="20s" interval="60s" /> +<action name="validate-all" timeout="20s" /> +<action name="meta-data" timeout="5s" /> +</actions> +</resource-agent> +END +} + +watch_suffix() +{ + local rc + + if [ -n "$OCF_RESKEY_watch_suffix" ]; then + if echo "'$OCF_RESKEY_watch_suffix'" | grep "'$1'" >/dev/null 2>&1; then + rc=0 + else + rc=1 + fi + else + if echo "'$OCF_RESKEY_ignore_suffix'" | grep "'$1'" >/dev/null 2>&1; then + rc=1 + else + rc=0 + fi + fi + + return $rc +} + +slapd_pid() +{ + local pid + + if [ -f "$pid_file" ]; then + pid=`head -n 1 "$pid_file" 2>/dev/null` + + if [ "X$pid" != "X" ]; then + echo "$pid" + return $OCF_SUCCESS + fi + + ocf_exit_reason "slapd pid file '$pid_file' empty." + return $OCF_ERR_GENERIC + fi + + ocf_log info "slapd pid file '$pid_file' does not exist." + return $OCF_NOT_RUNNING +} + +slapd_status() +{ + local pid=$1 + + if ! kill -0 $pid >/dev/null 2>&1; then + return $OCF_NOT_RUNNING + else + return $OCF_SUCCESS + fi +} + +slapd_start() +{ + local options + local reason + local rc + local state + + slapd_status `slapd_pid`; state=$? + + if [ $state -eq $OCF_SUCCESS ]; then + ocf_log info "slapd already running." + return $state + elif [ $state -eq $OCF_ERR_GENERIC ]; then + return $state + fi + + options="-u $user -g $group" + + if [ -d "$config" ]; then + options="$options -F $config" + elif [ -f "$config" ]; then + options="$options -f $config" + else + ocf_exit_reason "slapd configuration '$config' does not exist." + return $OCF_ERR_INSTALLED + fi + + if [ -n "$parameters" ]; then + options="$options $parameters" + fi + + if [ -n "$OCF_RESKEY_maxfiles" ]; then + ulimit -n $OCF_RESKEY_maxfiles + u_rc=$? + if [ "$u_rc" -ne 0 ]; then + ocf_log warn "Could not set ulimit for open files for slapd to '$OCF_RESKEY_maxfiles'" + fi + fi + + if [ -n "$services" ]; then + $slapd -h "$services" $options 2>&1; rc=$? + else + $slapd $options 2>&1; rc=$? + fi + + if [ $rc -ne 0 ]; then + ocf_exit_reason "slapd returned error." + + return $OCF_ERR_GENERIC + fi + + while true; do + slapd_monitor start + if [ $? = "$OCF_SUCCESS" ]; then + break + fi + sleep 1 + done + + ocf_log info "slapd started." + + return $OCF_SUCCESS +} + +slapd_stop() +{ + local pid + local rc + local state + + pid=`slapd_pid`; slapd_status $pid; state=$? + + if [ $state -eq $OCF_NOT_RUNNING ]; then + ocf_log info "slapd already stopped." + return $OCF_SUCCESS + elif [ $state -eq $OCF_ERR_GENERIC ]; then + return $state + fi + + ocf_stop_processes TERM $OCF_RESKEY_stop_escalate $pid; rc=$? + if [ $rc -eq 1 ]; then + ocf_log err "cannot stop slapd." + return $OCF_ERR_GENERIC + fi + + if [ -f "$pid_file" ]; then + rm -f "$pid_file" >/dev/null 2>&1 + fi + + ocf_log info "slapd stopped." + return $OCF_SUCCESS +} + +slapd_monitor() +{ + local options + local rc + local state + local suffix + local suffixes + local err_option="-info" + + slapd_status `slapd_pid`; state=$? + if [ $state -eq $OCF_NOT_RUNNING ]; then + if [ -z "$1" ];then + if ! ocf_is_probe; then + ocf_exit_reason "slapd process not found." + fi + fi + return $state + elif [ $state -ne $OCF_SUCCESS ]; then + ocf_exit_reason "slapd returned error." + return $state + fi + + if [ -d "$config" ]; then + for suffix in `find "$config"/'cn=config' -type f -name olcDatabase* -exec \ + sed -ne 's/^[[:space:]]*olcSuffix:[[:space:]]\+\(.\+\)/\1/p' {} \;` + do + suffix=${suffix#\"*} + suffix=${suffix%\"*} + + if watch_suffix $suffix; then + suffixes="$suffixes $suffix" + fi + done + + elif [ -f "$config" ]; then + for suffix in `sed -ne 's/^[[:space:]]*suffix[[:space:]]\+\(.\+\)/\1/p' "$config"` + do + suffix=${suffix#\"*} + suffix=${suffix%\"*} + + if watch_suffix $suffix; then + suffixes="$suffixes $suffix" + fi + done + + else + if ocf_is_probe; then + ocf_log info "slapd configuration '$config' does not exist during probe." + else + ocf_exit_reason "slapd configuration '$config' does not exist." + return $OCF_ERR_INSTALLED + fi + fi + + options="-LLL -s base -x" + + if [ -n "$bind_dn" ]; then + options="$options -D $bind_dn -w $password" + fi + + [ -z "$1" ] && err_option="" + for suffix in $suffixes; do + ocf_run -q $err_option "$ldapsearch" -H "$services" -b "$suffix" $options >/dev/null 2>&1; rc=$? + + case "$rc" in + "0") + ocf_log debug "slapd database with suffix '$suffix' reachable" + ;; + "49") + ocf_exit_reason "slapd database with suffix '$suffix' unreachable. Invalid credentials." + return $OCF_ERR_CONFIGURED + ;; + *) + if [ -z "$1" ] || [ -n "$1" -a $rc -ne 1 ]; then + ocf_exit_reason "slapd database with suffix '$suffix' unreachable. exit code ($rc)" + fi + state=$OCF_ERR_GENERIC + ;; + esac + done + + return $state +} + +slapd_validate_all() +{ + check_binary "$slapd" + check_binary "$ldapsearch" + + if [ -z "$pid_file" ]; then + if [ -d "$config" ]; then + pid_file=`sed -ne \ + 's/^olcPidFile:[[:space:]]\+\(.\+\)[[:space:]]*/\1/p' \ + "$config"/'cn=config.ldif' 2>/dev/null` + elif [ -f "$config" ]; then + pid_file=`sed -ne \ + 's/^pidfile[[:space:]]\+\(.\+\)/\1/p' \ + "$config" 2>/dev/null` + else + if ocf_is_probe; then + ocf_log info "slapd configuration '$config' does not exist during probe." + else + ocf_exit_reason "slapd configuration '$config' does not exist." + return $OCF_ERR_INSTALLED + fi + fi + fi + + if [ -z "$user" ]; then + user=`id -nu 2>/dev/null` + elif ! id "$user" >/dev/null 2>&1; then + ocf_exit_reason "slapd user '$user' does not exist" + return $OCF_ERR_INSTALLED + fi + + if [ -z "$group" ]; then + group=`id -ng 2>/dev/null` + elif ! grep "^$group:" /etc/group >/dev/null 2>&1; then + ocf_exit_reason "slapd group '$group' does not exist" + return $OCF_ERR_INSTALLED + fi + + pid_dir=`dirname "$pid_file"` + if [ ! -d "$pid_dir" ]; then + mkdir -p "$pid_dir" + chown -R "$user" "$pid_dir" + chgrp -R "$group" "$pid_dir" + fi + + return $OCF_SUCCESS +} + +# +# Main +# + +slapd=$OCF_RESKEY_slapd +ldapsearch=$OCF_RESKEY_ldapsearch +config=$OCF_RESKEY_config +user=$OCF_RESKEY_user +group=$OCF_RESKEY_group +services=$OCF_RESKEY_services +bind_dn=$OCF_RESKEY_bind_dn +password=$OCF_RESKEY_password +parameters=$OCF_RESKEY_parameters +pid_file=$OCF_RESKEY_pidfile + +if [ -z "$config" ]; then + config_dirname="/etc/ldap" + if [ -e "/etc/openldap" ]; then + config_dirname="/etc/openldap" + fi + + config="$config_dirname/slapd.conf" + if [ -e "$config_dirname/slapd.d" ]; then + config="$config_dirname/slapd.d" + fi +fi + +if [ $# -ne 1 ]; then + usage + exit $OCF_ERR_ARGS +fi + +case $1 in + meta-data) + meta_data + exit $OCF_SUCCESS + ;; + usage|help) + usage + exit $OCF_SUCCESS + ;; +esac + +slapd_validate_all +rc=$? +[ $rc -eq $OCF_SUCCESS ] || exit $rc + +case $1 in + status) + slapd_status `slapd_pid`; state=$? + + if [ $state -eq $OCF_SUCCESS ]; then + ocf_log debug "slapd is running." + elif [ $state -eq $OCF_NOT_RUNNING ]; then + ocf_log debug "slapd is stopped." + fi + + exit $state + ;; + start) + slapd_start + exit $? + ;; + stop) + slapd_stop + exit $? + ;; + monitor) + slapd_monitor; state=$? + exit $state + ;; + validate-all) + exit $OCF_SUCCESS + ;; + *) + usage + exit $OCF_ERR_UNIMPLEMENTED + ;; +esac |