Hi All How does this RA current status?
Regards, Tomo 2011/4/7 Dejan Muhamedagic <deja...@fastmail.fm> > Hi Jeroen, > > On Fri, Feb 04, 2011 at 04:16:23PM +0100, jer...@intuxicated.org wrote: > > Hi, > > > > I've updated the resource agent so that it tries to establish an LDAP > > connection. Most of the issues where resolved, but I haven't had the time > > yet to test with other OSes so I changed /bin/sh to /bin/bash. I'll try > to > > remove bashisms as soon as possible. > > Here's a review of your slapd RA. Took a while, sorry about that. > Any news on talking to openldap people? > > Cheers, > > Dejan > > **** > > > #!/bin/bash > > # > > # Stand-alone LDAP Daemon (slapd) > > # > > # Description: Manages Stand-alone LDAP Daemon (slapd) as an OCF > resource in > > # an high-availability setup. > > # > > # Author: Jeroen Koekkoek > > # 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.bha...@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_file > > # 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 > > # > > > ################################################################################ > > > > # Initialization: > > > > : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/resource.d/heartbeat} > > . ${OCF_FUNCTIONS_DIR}/.ocf-shellfuncs > > > > : ${OCF_RESKEY_slapd="/usr/sbin/slapd"} > > : ${OCF_RESKEY_ldapsearch="/usr/bin/ldapsearch"} > > : ${OCF_RESKEY_config_file=""} > > : ${OCF_RESKEY_user=""} > > : ${OCF_RESKEY_group=""} > > : ${OCF_RESKEY_services="ldap:///"} > > : ${OCF_RESKEY_watch_suffix=""} > > : ${OCF_RESKEY_ignore_suffix=""} > > : ${OCF_RESKEY_bind_dn=""} > > : ${OCF_RESKEY_password=""} > > : ${OCF_RESKEY_parameters=""} > > > > 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> > > > > <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="/usr/sbin/slapd" /> > > </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 slapd binary</shortdesc> > > Not slapd, but ldapsearch. > > > <content type="string" default="/usr/bin/ldapsearch" /> > > </parameter> > > Make this default to just "ldapsearch". It is expected to be in > PATH depending on the installation. > > > <parameter name="config_file" 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>Full path to configuration directory or file</shortdesc> > > <content type="string" default=""/> > > </parameter> > > If this parameter can be a file or a directory, then better > change the name. Perhaps just "config". Alternatively, use two > parameters (configfile and there's some openldap name I cannot > recall now for the cn=config configuration type). Then, exactly > one of these parameters must be set. > > > <parameter name="user" unique="1" 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="" /> > > </parameter> > > This is not unique. > > > <parameter name="group" unique="1" 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="" /> > > </parameter> > > This is not unique. > > > <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>LDAP (and other scheme) URLs to serve</shortdesc> > > <content type="string" default="ldap:///"/> > > </parameter> > > Is this unique? Probably. > > > <parameter name="watch_suffix" required="0" unique="1"> > > <longdesc lang="en"> > > Suffix (database backend) that will be monitored for availability. > Multiple > > suffixes can be specified by providing a space seperated list. By > providing one > > or more suffixes here, the ignore_suffix parameter is discarded. All > suffixes > > will be monitored if left blank. > > </longdesc> > > <shortdesc>Suffix that will be monitored for availability.</shortdesc> > > <content type="string" default=""/> > > </parameter> > > Not unique if it can be blank. > > > <parameter name="ignore_suffix" required="0" unique="1"> > > <longdesc lang="en"> > > Suffix (database backend) that will not be monitored for availability. > Multiple > > suffixes can be specified by providing a space seperated list. No suffix > will > > be excluded if left blank. > > </longdesc> > > <shortdesc>Suffix that will not be monitored for > availability.</shortdesc> > > <content type="string" default=""/> > > </parameter> > > Not unique. > > > <parameter name="bind_dn" required="0" unique="1"> > > <longdesc lang="en"> > > Distinguished Name used to bind to the LDAP directory. Leave blank to > bind to > > the LDAP directory anonymously. > > </longdesc> > > <shortdesc>Distinguished Name used to bind to the LDAP > directory.</shortdesc> > > <content type="string" default=""/> > > </parameter> > > > > <parameter name="password" required="0" unique="1"> > > <longdesc lang="en"> > > Password used to bind to the LDAP directory. > > </longdesc> > > <shortdesc>Password used to bind to the LDAP directory.</shortdesc> > > <content type="string" default=""/> > > Bind_dn/password for testing? If so, then add that to the > description. > > Also does not have to be unique. > > > <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"></shortdesc> > > No shortdesc. > > > <content type="string" default="" /> > > </parameter> > > > > </parameters> > > > > <actions> > > <action name="start" timeout="20s" /> > > <action name="stop" timeout="20s" /> > > <action name="monitor" depth="0" timeout="20s" interval="60s" /> > > Did you consider the timeouts or are these copies from another > agent? They should be set to the minimum suggested values. > > > <action name="validate-all" timeout="20s" /> > > <action name="meta-data" timeout="5s" /> > > </actions> > > </resource-agent> > > END > > } > > > > terminate() > > { > > local pid=$1 > > local signal=$2 > > local recheck=$3 > > local result > > > > if [ -z "$recheck" ]; then > > recheck=1 > > fi > > > > kill -$signal $pid >/dev/null 2>&1; result=$? > > > > if [ $result -eq 0 ] && [ $recheck -gt 0 ]; then > > # Grant some time for shutdown and recheck n times. > > local i=0 > > > > while [ $result -eq 0 ] && [ $i -lt $recheck ]; do > > kill -0 $pid >/dev/null 2>&1; result=$? > > let "i += 1" > > > > if [ $result -eq 0 ]; then > > sleep 1 > > fi > > done > > else > > result=1 > > fi > > > > if [ $result -ne 0 ]; then > > return 0 > > fi > > > > return 1 > > } > > > > watch_suffix() > > { > > local result > > > > if [ -n "$OFC_RESKEY_watch_suffix" ]; then > > if echo "'$OCF_RESKEY_watch_suffix'" | grep "'$1'" >/dev/null 2>&1; > then > > result=0 > > else > > result=1 > > fi > > else > > if echo "'$OCF_RESKEY_ignore_suffix'" | grep "'$1'" >/dev/null 2>&1; > then > > result=1 > > else > > result=0 > > fi > > fi > > > > return $result > > } > > > > slapd_pid() > > { > > local pid > > > > if [ -f "$pid_file" ]; then > > pid=`head -n 1 "$pid_file" 2>/dev/null` > > > > if [ -n "$pid" ]; then > > echo "$pid" > > return $OCF_SUCCESS > > fi > > > > ocf_log err "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 > > local state > > > > pid=`slapd_pid`; state=$? > > > > if [ $state -eq $OCF_SUCCESS ]; then > > > > if ! kill -0 $pid >/dev/null 2>&1; then > > return $OCF_NOT_RUNNING > > else > > echo "$pid" > > return $OCF_SUCCESS > > fi > > fi > > > > return $state > > } > > This function does unexpected things, i.e. it echos the pid. > That's confusing. I suggest to do something like this in callers > of slapd_status(): > > slapd_status `slapd_pid` > > and to save pid in a local var only in terminate which is > actually using it. > > > slapd_start() > > { > > local options > > local pid > > local reason > > local result > > local state > > > > pid=`slapd_status`; state=$? > > > > if [ $state -eq $OCF_SUCCESS ]; then > > ocf_log info "slapd already running." > > return $state > > elif [ $state -eq $OCF_ERR_GENERIC ]; then > > ocf_log err "slapd returned error." > > Is this message necessary? It can only happen if the pid file is > empty. > > > return $state > > fi > > > > options="-u $user -g $group" > > In the meta-data neither of these two parameters are required. > To match this code they should be. > > > if [ -d "$config_file" ]; then > > options="$options -F $config_file" > > else > > options="$options -f $config_file" > > fi > > > > if [ -n "$parameters" ]; then > > options="$options $parameters" > > fi > > > > if [ -n "$services" ]; then > > $slapd -h "$services" $options 2>&1; result=$? > > else > > $slapd $options 2>&1; result=$? > > fi > > > > if [ $result -ne 0 ]; then > > ocf_log err "slapd returned error." > > > > return $OCF_ERR_GENERIC > > fi > > > > ocf_log info "slapd started." > > > > return $OCF_SUCCESS > > } > > > > slapd_stop() > > { > > local pid > > local result > > local state > > > > pid=`slapd_status`; state=$? > > > > if [ $state -eq $OCF_NOT_RUNNING ]; then > > ocf_log info "slapd already stopped." > > return $OCF_SUCCESS > > elif [ $state -eq $OCF_ERR_GENERIC ]; then > > ocf_log err "slapd returned error." > > Is this message necessary? This branch can only happen if the pid > file is empty. > > > return $state > > fi > > > > terminate $pid 15 5; result=$? > > if [ $result -ne 0 ]; then > > ocf_log err "slapd failed to stop. Escalating to KILL." > > > > terminate $pid 9 5; result=$? > > if [ $result -ne 0 ]; then > > > > ocf_log err "slapd failed to stop." > > return $OCF_ERR_GENERIC > > The best practice is to loop while status returns true and let > the higher layer decide when the operation was taking too long. > Theoreticaly you can't say how long a process will take to > cleanup. > > > fi > > 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 pid > > local result > > local state > > local suffix > > local suffixes > > > > pid=`slapd_status`; state=$? > > if [ $state -eq $OCF_NOT_RUNNING ]; then > > ocf_log debug "slapd is stopped." > > return $state > > elif [ $state -ne $OCF_SUCCESS ]; then > > ocf_log err "slapd returned error." > > return $state > > fi > > > > if [ -d "$config_file" ]; then > > for suffix in `find "$config_file"/'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_file" ]; then > > for suffix in `sed -ne > 's/^[[:space:]]*suffix[[:space:]]\+\(.\+\)/\1/p' "$config_file"` > > do > > suffix=${suffix#\"*} > > suffix=${suffix%\"*} > > > > if watch_suffix $suffix; then > > suffixes="$suffixes $suffix" > > fi > > These two loop bodies are the same. > > > done > > fi > > > > options="-LLL -s base -x" > > > > if [ -n "$bind_dn" ]; then > > options="$options -D '$bind_dn' -w '$password'" > > fi > > > > for suffix in $suffixes; do > > ldapsearch -H "$services" -b "$suffix" $options >/dev/null 2>&1; > result=$? > > > > case "$result" in > > "0") > > ocf_log debug "slapd database with suffix '$suffix' reachable" > > ;; > > "49") > > ocf_log err "slapd database with suffix '$suffic' unreachable. > Invalid credentials." > > '$suffic' -> '$suffix' > > > return $OCF_ERR_CONFIGURED > > ;; > > *) > > ocf_log err "slapd database with suffix '$suffix' unreachable." > > state=$OCF_ERR_GENERIC > > ;; > > esac > > done > > > > return $state > > } > > > > slapd_validate_all() > > { > > if [ ! -x $slapd ]; then > > ocf_log err "slapd binary '$slapd' does not exist or cannot be > executed." > > return $OCF_ERR_INSTALLED > > fi > > > > if [ ! -x $ldapsearch ]; then > > ocf_log err "slapd binary '$ldapsearch' does not exist or cannot be > executed." > > return $OCF_ERR_INSTALLED > > fi > > check_binary? > > > if [ ! -d $config_file ] && [ ! -f $config_file ]; then > > ocf_log err "slapd configuration file '$config_file' does not exist." > > return $OCF_ERR_INSTALLED > > fi > > > > if ! id "$user" >/dev/null 2>&1; then > > ocf_log err "slapd user '$user' does not exist $ret" > > return $OCF_ERR_INSTALLED > > fi > > > > if ! grep "^$group:" /etc/group >/dev/null 2>&1; then > > ocf_log err "slapd group '$group' does not exist" > > return $OCF_ERR_INSTALED > > fi > > > > return $OCF_SUCCESS > > } > > > > # > > # slapd_validate_dirs: retrieves all slapd database directories from the > > # configuration file(s) and verifies existence and > > # permissions. > > # > > slapd_validate_dirs() > > { > > local dir > > local dirs > > local groups=`groups $user | sed -ne 's/^[^:]\+: \(.*\)$/\1/p' | sed > 's/ \+/\\\|/' 2>/dev/null` > > local perms > > local result > > local state > > > > > > [ "$user" = "root" ] && return $OCF_SUCCESS > > > > IFS=$NEWLINE > > > > if [ -d "$config_file" ]; then > > for dir in `find "$config_file"/'cn=config' -type f -name > olcDatabase* -exec \ > > sed -ne 's/^olcDbDirectory:[[:space:]]\+\(.\+\)/\1/p' {} > \;` > > do > > dir=${dir#\"*} > > dir=${dir%\"*} > > dirs="$dirs$NEWLINE$dir" > > done > > elif [ -f "$config_file" ]; then > > for dir in `sed -ne 's/^directory[[:space:]]\+\(.\+\)/\1\n/p' > "$config_file"` > > do > > dir=${dir#\"*} > > dir=${dir%\"*} > > dirs="$dirs$NEWLINE$dir" > > done > > fi > > > > state=$OCF_SUCCESS > > > > for dir in $dirs; do > > IFS=$ORIG_IFS > > > > perms=`stat -c "%U:%G:%a" "$dir"`; result=$? > > > > > > if [ $result -eq 0 ]; then > > > > echo "$perms" | grep "$user:[^:]\+:7.." >/dev/null 2>&1; result=$? > > > > if [ $result -ne 0 ]; then > > > > if [ -n "$groups" ]; then > > echo "$perms" | grep "[^:]\+:\($group\|$groups\):.7." > >/dev/null 2>&1; result=$? > > else > > echo "$perms" | grep "[^:]\+:$group:.7." >/dev/null 2>&1; > result=$? > > fi > > > > > > if [ $result -ne 0 ]; then > > > > echo "$perms" | grep ":..7" >/dev/null 2>&1; result=$? > > > > if [ $result -ne 0 ]; then > > state=$OCF_ERR_GENERIC > > ocf_log err "slapd data directory '$dir' is not writable." > > else > > ocf_log warn "slapd data directory '$dir' is world writable. > Mode 0700 recommended." > > fi > > else > > ocf_log warn "slapd data directory '$dir' is group writable. > Mode 0700 recommended." > > fi > > > > else > > ocf_log warn "slapd data directory '$dir' is accessible by > others. Mode 0700 recommended." > > fi > > fi > > > > IFS=$NEWLINE > > done > > > > IFS=$ORIG_IFS > > > > return $state > > } > > I still find checking directories superfluous. > > > # > > # Main > > # > > > > slapd=$OCF_RESKEY_slapd > > ldapsearch=$OCF_RESKEY_ldapsearch > > config_file=$OCF_RESKEY_config_file > > 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='' > > > > if [ -z "$config_file" ]; then > > if [ -e "/etc/ldap/slapd.d" ]; then > > config_file="/etc/ldap/slapd.d" > > else > > config_file="/etc/ldap/slapd.conf" > > fi > > fi > > > > if [ -d "$config_file" ]; then > > pid_file=`sed -ne \ > > 's/^olcPidFile:[[:space:]]\+\(.\+\)[[:space:]]*/\1/p' \ > > "$config_file"/'cn=config.ldif' 2>/dev/null` > > elif [ -f "$config_file" ]; then > > pid_file=`sed -ne \ > > 's/^pidfile[[:space:]]\+\(.\+\)/\1/p' \ > > "$config_file" 2>/dev/null` > > fi > > It would be good to move parsing of configuration files to > separate functions. > > > if test -z "$user"; then > > user=`id -nu 2>/dev/null` > > elif ocf_is_decimal "$user"; then > > user=`sed -ne "s/^\([^:]\+\):[^:]\+:$user:.*/\1/p" /etc/passwd > 2>/dev/null` > > fi > > > > if test -z "$group"; then > > group=`id -ng 2>/dev/null` > > elif ocf_is_decimal "$group"; then > > group=`sed -ne "s/^\([^:]\+\):[^:]\+:$group:.*/\1/p" /etc/group > 2>/dev/null` > > fi > > This won't work if the passwd/group databases are for instance in > LDAP ;-) Best to keep it simple and just require users to provide > names. > > > 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 > > > > [ $? -eq $OCF_SUCCESS ] || exit $? > > > > case $1 in > > status) > > pid=`slapd_status`; 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) > > pid=`slapd_monitor`; state=$? > > exit $? > > ;; > > validate-all) > > slapd_validate_dirs > > exit $? > > ;; > > *) > > usage > > exit $OCF_ERR_UNIMPLEMENTED > > ;; > > esac > _______________________________________________________ > Linux-HA-Dev: Linux-HA-Dev@lists.linux-ha.org > http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev > Home Page: http://linux-ha.org/ >
_______________________________________________________ Linux-HA-Dev: Linux-HA-Dev@lists.linux-ha.org http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev Home Page: http://linux-ha.org/