Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: Linux-HA: Dev

slapd ocf resource agent

 

 

Linux-HA dev RSS feed   Index | Next | Previous | View Threaded


jeroen at intuxicated

Feb 2, 2011, 8:01 AM

Post #1 of 15 (1005 views)
Permalink
slapd ocf resource agent

Hi,

I created a resource agent for slapd, and want to submit it to the project.
I know I should upload it as a patch, but I was having some difficulties
with that, so I'm doing it this way instead. If I should use the official
method or use different steps, please let me know.

I will happily modify the script or provide additional information to get
it included.

Best regards,

Jeroen Koekkoek
Attachments: slapd.sh (10.8 KB)


florian.haas at linbit

Feb 3, 2011, 1:15 AM

Post #2 of 15 (955 views)
Permalink
Re: slapd ocf resource agent [In reply to]

On 2011-02-02 17:01, jeroen [at] intuxicated wrote:
> Hi,
>
> I created a resource agent for slapd, and want to submit it to the project.
> I know I should upload it as a patch, but I was having some difficulties
> with that, so I'm doing it this way instead. If I should use the official
> method or use different steps, please let me know.
>
> I will happily modify the script or provide additional information to get
> it included.

Hi Jeroen,

thanks! As an initial step in the review, has this been run through
ocf-tester?

Cheers,
Florian
Attachments: signature.asc (0.26 KB)


jeroen at intuxicated

Feb 3, 2011, 1:50 AM

Post #3 of 15 (957 views)
Permalink
Re: slapd ocf resource agent [In reply to]

On Thu, 03 Feb 2011 10:15:31 +0100, Florian Haas <florian.haas [at] linbit>
wrote:
> On 2011-02-02 17:01, jeroen [at] intuxicated wrote:
>> Hi,
>>
>> I created a resource agent for slapd, and want to submit it to the
>> project.
>> I know I should upload it as a patch, but I was having some difficulties
>> with that, so I'm doing it this way instead. If I should use the
official
>> method or use different steps, please let me know.
>>
>> I will happily modify the script or provide additional information to
get
>> it included.
>
> Hi Jeroen,
>
> thanks! As an initial step in the review, has this been run through
> ocf-tester?
>
> Cheers,
> Florian

Hi Florian,

Yes, I tested it using ocf-tester and did some basic checking with
pacemaker. I cleaned the code up a little, so here's an updated version.

Regards,
Jeroen
Attachments: slapd.sh (10.7 KB)


dejanmm at fastmail

Feb 3, 2011, 2:10 AM

Post #4 of 15 (953 views)
Permalink
Re: slapd ocf resource agent [In reply to]

Hi,

On Wed, Feb 02, 2011 at 05:01:19PM +0100, jeroen [at] intuxicated wrote:
> Hi,
>
> I created a resource agent for slapd, and want to submit it to the project.
> I know I should upload it as a patch, but I was having some difficulties
> with that, so I'm doing it this way instead. If I should use the official
> method or use different steps, please let me know.

It is fine as is. However, the current best practice is to have
resource agents shipped with the software it actually supports
whenever possible. The interesting parts of a resource agent
obviously have to do with the software it manages. Since we here
have only occasionaly some expertise in other areas, the resource
agent would benefit from more qualified critique from people
involved in the respective software project.

> I will happily modify the script or provide additional information to get
> it included.

It would be interesting to have this RA support multi-state.
Last time I looked at openldap, it supported a master-slave setup
where every slave was capable of answering queries, but all
modifications went to the master instance. That fits well with
the OCF multi-state resource concept.

The monitor operation in the agent is very basic. An OCF RA
should do better. Extra points if the query can be made
configurable so that users can monitor whichever directory part
is of most importance.

You should lower the severity to debug of the log message on
success in the monitor operation. Otherwise, it's going to make
to much noise.

Various sed scripts should be consolidated into one function
dedicated to getting information from the slapd configuration.

config_file can be a directory. Better name it just config.

The slapd_validate_all() should return with OCF_ERR_INSTALLED
instead of OCF_ERR_GENERIC.

The big for loop in validation is, well, big and unwieldy. Not
sure if it's absolutely necessary to do this kind of validation.

Not sure, but some bits look bash-specific. Either remove
bashisms (preferred) or change #!/bin/sh to #!/bin/bash.

Though we don't have any particular coding style imposed, could
you perhaps reduce the vertical white space somewhat. Seems like
there are too many empty lines to me.

This is not exhaustive and there'd probably be more, but should
keep you busy for a while :)

BTW, there has been once an openldap resource agent posted to
this list, but unfortunately didn't get timely response (entirely
my fault) and the author never responded to the late RA review.
See http://marc.info/?l=linux-ha&m=123003594213018&w=2 and
http://marc.info/?l=linux-ha&m=124327185429394&w=2

And many thanks for the effort.

Cheers,

Dejan

> Best regards,
>
> Jeroen Koekkoek


> _______________________________________________________
> Linux-HA-Dev: Linux-HA-Dev [at] lists
> http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev
> Home Page: http://linux-ha.org/

_______________________________________________________
Linux-HA-Dev: Linux-HA-Dev [at] lists
http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev
Home Page: http://linux-ha.org/


dejanmm at fastmail

Feb 3, 2011, 2:12 AM

Post #5 of 15 (951 views)
Permalink
Re: slapd ocf resource agent [In reply to]

Hi Florian,

On Thu, Feb 03, 2011 at 10:15:31AM +0100, Florian Haas wrote:
> On 2011-02-02 17:01, jeroen [at] intuxicated wrote:
> > Hi,
> >
> > I created a resource agent for slapd, and want to submit it to the project.
> > I know I should upload it as a patch, but I was having some difficulties
> > with that, so I'm doing it this way instead. If I should use the official
> > method or use different steps, please let me know.
> >
> > I will happily modify the script or provide additional information to get
> > it included.
>
> Hi Jeroen,
>
> thanks! As an initial step in the review, has this been run through
> ocf-tester?

I've already done some analysis of the contribution. Probably
good in future to have this coordinated somehow, so that we don't
duplicate effort.

Cheers,

Dejan

> Cheers,
> Florian
>



> _______________________________________________________
> Linux-HA-Dev: Linux-HA-Dev [at] lists
> http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev
> Home Page: http://linux-ha.org/

_______________________________________________________
Linux-HA-Dev: Linux-HA-Dev [at] lists
http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev
Home Page: http://linux-ha.org/


jeroen at intuxicated

Feb 3, 2011, 3:05 AM

Post #6 of 15 (960 views)
Permalink
Re: slapd ocf resource agent [In reply to]

> It is fine as is. However, the current best practice is to have
> resource agents shipped with the software it actually supports
> whenever possible. The interesting parts of a resource agent
> obviously have to do with the software it manages. Since we here
> have only occasionaly some expertise in other areas, the resource
> agent would benefit from more qualified critique from people
> involved in the respective software project.

If I find the time, I'll post this somewhere else so more experienced LDAP
people can have a look at it.

> It would be interesting to have this RA support multi-state.
> Last time I looked at openldap, it supported a master-slave setup
> where every slave was capable of answering queries, but all
> modifications went to the master instance. That fits well with
> the OCF multi-state resource concept.

If I can come up with something quickly, I'll look into it. I do think
however, that having a RA for LDAP is good to have even though it doesn't
support master-slave setups. Other people can add master-slave
functionality if they need it and send in patches.

> The monitor operation in the agent is very basic. An OCF RA
> should do better. Extra points if the query can be made
> configurable so that users can monitor whichever directory part
> is of most importance.

Will look into this.

> You should lower the severity to debug of the log message on
> success in the monitor operation. Otherwise, it's going to make
> to much noise.

Will do.

> Various sed scripts should be consolidated into one function
> dedicated to getting information from the slapd configuration.
>
> config_file can be a directory. Better name it just config.
>
> The slapd_validate_all() should return with OCF_ERR_INSTALLED
> instead of OCF_ERR_GENERIC.

Will do.

> The big for loop in validation is, well, big and unwieldy. Not
> sure if it's absolutely necessary to do this kind of validation.

Well, I ran into the problem myself a few times. I thought it would come in
handy.

> Not sure, but some bits look bash-specific. Either remove
> bashisms (preferred) or change #!/bin/sh to #!/bin/bash.

Did my best not to make it bash specific. I don't currently have another
system to test this on, I'll try to get something up quickly and test the
script on that.

> Though we don't have any particular coding style imposed, could
> you perhaps reduce the vertical white space somewhat. Seems like
> there are too many empty lines to me.

Will look into this.

> This is not exhaustive and there'd probably be more, but should
> keep you busy for a while :)
>
> BTW, there has been once an openldap resource agent posted to
> this list, but unfortunately didn't get timely response (entirely
> my fault) and the author never responded to the late RA review.
> See http://marc.info/?l=linux-ha&m=123003594213018&w=2 and
> http://marc.info/?l=linux-ha&m=124327185429394&w=2

I read the thread. The script itself wasn't that good, but I did make sure
my version didn't have the issues people back then reported.

Regards,
Jeroen
_______________________________________________________
Linux-HA-Dev: Linux-HA-Dev [at] lists
http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev
Home Page: http://linux-ha.org/


jeroen at intuxicated

Feb 4, 2011, 7:16 AM

Post #7 of 15 (937 views)
Permalink
Re: slapd ocf resource agent [In reply to]

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.

Jeroen
Attachments: slapd.sh (14.9 KB)


lars.ellenberg at linbit

Feb 4, 2011, 2:14 PM

Post #8 of 15 (941 views)
Permalink
Re: slapd ocf resource agent [In reply to]

On Fri, Feb 04, 2011 at 04:16:23PM +0100, jeroen [at] intuxicated 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.
>
> Jeroen

Thanks. This is no actual review,
but only a suggestion to cut down on the "unwieldy for loop"
Dejan complained about.

> #
> # 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

Why would a world writeable data directory not be a problem
if the service runs as root?

> IFS=$NEWLINE
>
> if [ -d "$config_file" ]; then
> for dir in `find "$config_file"/'cn=config' -type f -name olcDatabase* -exec \

Careful, unescaped *, don't do that.
Will break in completely non-obvious ways
if for some obscure reason in the current workingdirectory
there are files named olcDatabase-something.

> sed -ne 's/^olcDbDirectory:[[:space:]]\+\(.\+\)/\1/p' {} \;`

find | xargs sed ?
Sure that there is no leading space allowed?
/me is outing himself has ignorant to ldap configuration syntax.

> do
> dir=${dir#\"*}

no * necessary, actually the * is misleading here.

> dir=${dir%\"*}

the same

> dirs="$dirs$NEWLINE$dir"

what do you $NEWLINE for, there?
do you want to allow for spaces in directories,
but no newline?

> done

why not strip the quotes in sed as well,
so you can say "dirs=$(whatever)" ?

this should be equivalent to this for loop:
dirs=$(find "$config_file/cn=config" -type f -name "olcDatabase*" -print0 |
xargs -0 sed -n -e '/^olcDbDirectory:[[:space:]]/!d;' \
-e 's/^[^:]*:[[:space:]]*//;s/^"//;s/"$//;p')

> 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

the same,
dirs=$(sed -n -e '/^directory[[:space:]]/!d;' \
-e 's/^[a-z]*[[:space:]]*//;s/^"//;s/"$//;p' \
< "$config_file")

what about the else ?
no -d, and no -f either,
probably not existing (ignore specials for a second).
That's not good either?

> fi

>
> state=$OCF_SUCCESS
>
> for dir in $dirs; do
> IFS=$ORIG_IFS

In case you actually wanted to allow spaces (but no newlines)
in directory names, as I believe you attempted, with bash you'd do
ORIG_IFS=$IFS
IFS=$'\n'
dirs=($( .... sed ... ))
IFS=$ORIG_IFS

and then later again
for dir in "${dirs[@]}"; do
...

But see below.

> 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
> }

If I read that correctly, it checks if some directories are
* in some way writeable by $user
* complain, if dir is not mode 0700 and owned by $user
* does not care if it exists (was that intentional?)

dirs=$( find $dirs -maxdepth 0 -not \( -type d -user $user -perm 0700 \) )
for dir in $dirs; do
if ! su $user -s /bin/sh -c "test -w '$dir'" ; then
state=$OCF_ERR_GENERIC
ocf_log err "... $dir not writable by $user ..."
else
ocf_log warn "... consider to 'chmod 0700 $dir; chown $user $dir;'"
fi
done

Note about spaces in path names... gets more ugly, but doable.
You need to decide wether you want to allow something that
no-one is actually doing, ever ;-)
and simply refuse it, in step 1, when gathering the
list of directories to check.


--
: Lars Ellenberg
: LINBIT | Your Way to High Availability
: DRBD/HA support and consulting http://www.linbit.com

DRBD® and LINBIT® are registered trademarks of LINBIT, Austria.
_______________________________________________________
Linux-HA-Dev: Linux-HA-Dev [at] lists
http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev
Home Page: http://linux-ha.org/


dejanmm at fastmail

Feb 8, 2011, 4:10 AM

Post #9 of 15 (930 views)
Permalink
Re: slapd ocf resource agent [In reply to]

On Fri, Feb 04, 2011 at 11:14:59PM +0100, Lars Ellenberg wrote:
> On Fri, Feb 04, 2011 at 04:16:23PM +0100, jeroen [at] intuxicated 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.
> >
> > Jeroen
>
> Thanks. This is no actual review,

Hmm, what would an actual review look like me wonders ;-)

Jeroen, did you try to contribute this RA to the openldap
distribution? That would definitely be for the best.

Cheers,

Dejan
_______________________________________________________
Linux-HA-Dev: Linux-HA-Dev [at] lists
http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev
Home Page: http://linux-ha.org/


lars.ellenberg at linbit

Feb 8, 2011, 4:39 AM

Post #10 of 15 (927 views)
Permalink
Re: slapd ocf resource agent [In reply to]

On Tue, Feb 08, 2011 at 01:10:19PM +0100, Dejan Muhamedagic wrote:
> On Fri, Feb 04, 2011 at 11:14:59PM +0100, Lars Ellenberg wrote:
> > On Fri, Feb 04, 2011 at 04:16:23PM +0100, jeroen [at] intuxicated 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.
> > >
> > > Jeroen
> >
> > Thanks. This is no actual review,
>
> Hmm, what would an actual review look like me wonders ;-)

Well, I only reviewed that validate function,
and completely ignored the rest of the code.

> Jeroen, did you try to contribute this RA to the openldap
> distribution? That would definitely be for the best.

Yes please.

--
: Lars Ellenberg
: LINBIT | Your Way to High Availability
: DRBD/HA support and consulting http://www.linbit.com

DRBD® and LINBIT® are registered trademarks of LINBIT, Austria.
_______________________________________________________
Linux-HA-Dev: Linux-HA-Dev [at] lists
http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev
Home Page: http://linux-ha.org/


dejanmm at fastmail

Apr 7, 2011, 2:26 AM

Post #11 of 15 (828 views)
Permalink
Re: slapd ocf resource agent [In reply to]

Hi Jeroen,

On Fri, Feb 04, 2011 at 04:16:23PM +0100, jeroen [at] intuxicated 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.bhatia [at] ipax>.
> #
> # 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 [at] lists
http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev
Home Page: http://linux-ha.org/


nozawat at gmail

Aug 25, 2011, 8:06 PM

Post #12 of 15 (644 views)
Permalink
Re: slapd ocf resource agent [In reply to]

Hi All

How does this RA current status?

Regards,
Tomo

2011/4/7 Dejan Muhamedagic <dejanmm [at] fastmail>

> Hi Jeroen,
>
> On Fri, Feb 04, 2011 at 04:16:23PM +0100, jeroen [at] intuxicated 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.bhatia [at] ipax>.
> > #
> > # 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 [at] lists
> http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev
> Home Page: http://linux-ha.org/
>


jeroen at intuxicated

Aug 26, 2011, 12:52 AM

Post #13 of 15 (636 views)
Permalink
Re: slapd ocf resource agent [In reply to]

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 <nozawat [at] gmail> wrote:
> Hi All
>
> How does this RA current status?
>
> Regards,
> Tomo
>
> 2011/4/7 Dejan Muhamedagic <dejanmm [at] fastmail>
>
>> Hi Jeroen,
>>
>> On Fri, Feb 04, 2011 at 04:16:23PM +0100, jeroen [at] intuxicated 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.bhatia [at] ipax>.
>> > #
>> > # 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 [at] lists
>> http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev
>> Home Page: http://linux-ha.org/
>>
Attachments: slapd.gz (3.65 KB)


nozawat at gmail

Aug 26, 2011, 1:04 AM

Post #14 of 15 (632 views)
Permalink
Re: slapd ocf resource agent [In reply to]

Hi Jeroen

Thank you, and I use it, too!

Regards,
Tomo

2011/8/26 <jeroen [at] intuxicated>

> 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 <nozawat [at] gmail> wrote:
> > Hi All
> >
> > How does this RA current status?
> >
> > Regards,
> > Tomo
> >
> > 2011/4/7 Dejan Muhamedagic <dejanmm [at] fastmail>
> >
> >> Hi Jeroen,
> >>
> >> On Fri, Feb 04, 2011 at 04:16:23PM +0100, jeroen [at] intuxicated 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.bhatia [at] ipax>.
> >> > #
> >> > # 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 [at] lists
> >> http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev
> >> Home Page: http://linux-ha.org/
> >>
>
> _______________________________________________________
> Linux-HA-Dev: Linux-HA-Dev [at] lists
> http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev
> Home Page: http://linux-ha.org/
>
>


nozawat at gmail

Sep 7, 2011, 2:53 AM

Post #15 of 15 (586 views)
Permalink
Re: slapd ocf resource agent [In reply to]

Hi Jeroen

I asked you a question in OpenLDAP-ML.Therefore I got the following
answers.
<http://www.openldap.org/lists/openldap-technical/201109/msg00052.html>

If config_file is directory, I want to change it into handling of slapcat.

Regards,
Tomo

2011/8/26 <jeroen [at] intuxicated>

> 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 <nozawat [at] gmail> wrote:
> > Hi All
> >
> > How does this RA current status?
> >
> > Regards,
> > Tomo
> >
> > 2011/4/7 Dejan Muhamedagic <dejanmm [at] fastmail>
> >
> >> Hi Jeroen,
> >>
> >> On Fri, Feb 04, 2011 at 04:16:23PM +0100, jeroen [at] intuxicated 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.bhatia [at] ipax>.
> >> > #
> >> > # 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 [at] lists
> >> http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev
> >> Home Page: http://linux-ha.org/
> >>
>
> _______________________________________________________
> Linux-HA-Dev: Linux-HA-Dev [at] lists
> http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev
> Home Page: http://linux-ha.org/
>
>

Linux-HA dev RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact Gossamer Threads
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.