Hi Tomo, I'm using the RA in our production setup. I attached the latest version to this email.
Regards, Jeroen On Fri, 26 Aug 2011 12:06:22 +0900, nozawat <noza...@gmail.com> wrote: > 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/ >>
slapd.gz
Description: GNU Zip compressed data
_______________________________________________________ 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/