Add syncrepl suffixmassage

This commit is contained in:
Quanah Gibson-Mount 2011-01-06 19:03:17 +00:00
parent c525828af1
commit 2df8301bd6
5 changed files with 648 additions and 17 deletions

View file

@ -7,6 +7,7 @@ OpenLDAP 2.4.24 Engineering
Added libldap x500UniqueIdentifier handling (ITS#6741)
Added slapadd attribute value checking (ITS#6592)
Added slapcat continue mode for problematic DBs (ITS#6482)
Added slapd syncrepl suffixmassage support
Added slapd-meta paged results control fowarding (ITS#6664)
Added slapd-null back-config support (ITS#6624)
Added slapd-sql autocommit support (ITS#6612)

View file

@ -1677,6 +1677,7 @@ FALSE, meaning the contextCSN is stored in the context entry.
.B [tls_reqcert=never|allow|try|demand]
.B [tls_ciphersuite=<ciphers>]
.B [tls_crlcheck=none|peer|all]
.B [suffixmassage=<real DN>]
.B [logbase=<base DN>]
.B [logfilter=<filter str>]
.B [syncdata=default|accesslog|changelog]
@ -1837,6 +1838,13 @@ fails. Otherwise the syncrepl session continues without TLS. The
tls_reqcert setting defaults to "demand" and the other TLS settings
default to the same as the main slapd TLS settings.
The
.B suffixmassage
parameter allows the consumer to pull entries from a remote directory
whose DN suffix differs from the local directory. The portion of the
remote entries' DNs that matches the \fIsearchbase\fP will be replaced
with the suffixmassage DN.
Rather than replicating whole entries, the consumer can query logs of
data modifications. This mode of operation is referred to as \fIdelta
syncrepl\fP. In addition to the above parameters, the

View file

@ -1656,6 +1656,7 @@ the contextCSN is stored in the context entry.
.B [tls_reqcert=never|allow|try|demand]
.B [tls_ciphersuite=<ciphers>]
.B [tls_crlcheck=none|peer|all]
.B [suffixmassage=<real DN>]
.B [logbase=<base DN>]
.B [logfilter=<filter str>]
.B [syncdata=default|accesslog|changelog]
@ -1835,6 +1836,13 @@ fails. Otherwise the syncrepl session continues without TLS. The
tls_reqcert setting defaults to "demand" and the other TLS settings
default to the same as the main slapd TLS settings.
The
.B suffixmassage
parameter allows the consumer to pull entries from a remote directory
whose DN suffix differs from the local directory. The portion of the
remote entries' DNs that matches the \fIsearchbase\fP will be replaced
with the suffixmassage DN.
Rather than replicating whole entries, the consumer can query logs of
data modifications. This mode of operation is referred to as \fIdelta
syncrepl\fP. In addition to the above parameters, the

View file

@ -31,6 +31,11 @@
#include "ldap_rq.h"
#ifdef ENABLE_REWRITE
#include "rewrite.h"
#define SUFFIXM_CTX "<suffix massage>"
#endif
struct nonpresent_entry {
struct berval *npe_name;
struct berval *npe_nname;
@ -111,6 +116,10 @@ typedef struct syncinfo_s {
LDAP *si_ld;
Connection *si_conn;
LDAP_LIST_HEAD(np, nonpresent_entry) si_nonpresentlist;
#ifdef ENABLE_REWRITE
struct rewrite_info *si_rewrite;
struct berval si_suffixm;
#endif
ldap_pvt_thread_mutex_t si_mutex;
} syncinfo_t;
@ -1558,6 +1567,46 @@ deleted:
return NULL;
}
#ifdef ENABLE_REWRITE
static int
syncrepl_rewrite_dn(
syncinfo_t *si,
struct berval *dn,
struct berval *sdn )
{
char nul;
int rc;
nul = dn->bv_val[dn->bv_len];
dn->bv_val[dn->bv_len] = 0;
rc = rewrite( si->si_rewrite, SUFFIXM_CTX, dn->bv_val, &sdn->bv_val );
dn->bv_val[dn->bv_len] = nul;
if ( sdn->bv_val == dn->bv_val )
sdn->bv_val = NULL;
else if ( rc == REWRITE_REGEXEC_OK && sdn->bv_val )
sdn->bv_len = strlen( sdn->bv_val );
return rc;
}
#define REWRITE_VAL(si, ad, bv, bv2) \
BER_BVZERO( &bv2 ); \
if ( si->si_rewrite && ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName) \
syncrepl_rewrite_dn( si, &bv, &bv2); \
if ( BER_BVISNULL( &bv2 )) \
ber_dupbv( &bv2, &bv )
#define REWRITE_DN(si, bv, bv2, dn, ndn) \
BER_BVZERO( &bv2 ); \
if (si->si_rewrite) \
syncrepl_rewrite_dn(si, &bv, &bv2); \
rc = dnPrettyNormal( NULL, bv2.bv_val ? &bv2 : &bv, &dn, &ndn, op->o_tmpmemctx ); \
ch_free(bv2.bv_val)
#else
#define REWRITE_VAL(si, ad, bv, bv2) ber_dupbv(&bv2, &bv)
#define REWRITE_DN(si, bv, bv2, dn, ndn) \
rc = dnPrettyNormal( NULL, &bv, &dn, &ndn, op->o_tmpmemctx )
#endif
static slap_verbmasks modops[] = {
{ BER_BVC("add"), LDAP_REQ_ADD },
{ BER_BVC("delete"), LDAP_REQ_DELETE },
@ -1642,7 +1691,7 @@ syncrepl_accesslog_mods(
if ( colon[2] == ' ' ) {
bv.bv_val = colon + 3;
bv.bv_len = vals[i].bv_len - ( bv.bv_val - vals[i].bv_val );
ber_dupbv( &bv2, &bv );
REWRITE_VAL( si, ad, bv, bv2 );
ber_bvarray_add( &mod->sml_values, &bv2 );
mod->sml_numvals++;
}
@ -1679,7 +1728,7 @@ syncrepl_message_to_op(
size_t textlen = sizeof txtbuf;
struct berval bdn, dn = BER_BVNULL, ndn;
struct berval bv, *bvals = NULL;
struct berval bv, bv2, *bvals = NULL;
struct berval rdn = BER_BVNULL, sup = BER_BVNULL,
prdn = BER_BVNULL, nrdn = BER_BVNULL,
psup = BER_BVNULL, nsup = BER_BVNULL;
@ -1710,7 +1759,7 @@ syncrepl_message_to_op(
op->o_tag = LBER_DEFAULT;
op->o_bd = si->si_wbe;
if ( BER_BVISEMPTY( &bdn ) && !BER_BVISEMPTY( &op->o_bd->be_nsuffix[0] ) ) {
if ( BER_BVISEMPTY( &bdn )) {
Debug( LDAP_DEBUG_ANY,
"syncrepl_message_to_op: %s got empty dn",
si->si_ridtxt, 0, 0 );
@ -1724,7 +1773,7 @@ syncrepl_message_to_op(
if ( !ber_bvstrcasecmp( &bv, &ls->ls_dn ) ) {
bdn = bvals[0];
rc = dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx );
REWRITE_DN( si, bdn, bv2, dn, ndn );
if ( rc != LDAP_SUCCESS ) {
Debug( LDAP_DEBUG_ANY,
"syncrepl_message_to_op: %s "
@ -1841,9 +1890,9 @@ syncrepl_message_to_op(
goto done;
}
if ( !BER_BVISNULL( &sup ) ) {
if ( dnPrettyNormal( NULL, &sup, &psup, &nsup, NULL ) ) {
REWRITE_DN( si, sup, bv2, psup, nsup );
if ( rc )
goto done;
}
op->orr_newSup = &psup;
op->orr_nnewSup = &nsup;
} else {
@ -1933,7 +1982,7 @@ syncrepl_message_to_entry(
char txtbuf[SLAP_TEXT_BUFLEN];
size_t textlen = sizeof txtbuf;
struct berval bdn = BER_BVNULL, dn, ndn;
struct berval bdn = BER_BVNULL, dn, ndn, bv2;
int rc, is_ctx;
*modlist = NULL;
@ -1973,7 +2022,7 @@ syncrepl_message_to_entry(
return -1;
}
rc = dnPrettyNormal( NULL, &bdn, &dn, &ndn, op->o_tmpmemctx );
REWRITE_DN( si, bdn, bv2, dn, ndn );
if ( rc != LDAP_SUCCESS ) {
/* One of the things that could happen is that the schema
* is not lined-up; this could result in unknown attributes.
@ -2026,6 +2075,26 @@ syncrepl_message_to_entry(
mod->sml_nvalues = NULL;
mod->sml_numvals = 0; /* slap_mods_check will set this */
#ifdef ENABLE_REWRITE
if (si->si_rewrite) {
AttributeDescription *ad = NULL;
slap_bv2ad( &tmp.sml_type, &ad, &text );
if ( ad ) {
mod->sml_desc = ad;
mod->sml_type = ad->ad_cname;
if ( ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) {
int i;
for ( i = 0; tmp.sml_values[i].bv_val; i++ ) {
syncrepl_rewrite_dn( si, &tmp.sml_values[i], &bv2);
if ( !BER_BVISNULL( &bv2 )) {
ber_memfree( tmp.sml_values[i].bv_val );
tmp.sml_values[i] = bv2;
}
}
}
}
}
#endif
*modtail = mod;
modtail = &mod->sml_next;
}
@ -2240,8 +2309,16 @@ syncrepl_entry(
op->ors_deref = LDAP_DEREF_NEVER;
/* get the entry for this UUID */
op->o_req_dn = si->si_base;
op->o_req_ndn = si->si_base;
#ifdef ENABLE_REWRITE
if ( si->si_rewrite ) {
op->o_req_dn = si->si_suffixm;
op->o_req_ndn = si->si_suffixm;
} else
#endif
{
op->o_req_dn = si->si_base;
op->o_req_ndn = si->si_base;
}
op->o_time = slap_get_time();
op->ors_tlimit = SLAP_NO_LIMIT;
@ -2717,8 +2794,16 @@ syncrepl_del_nonpresent(
struct berval pdn = BER_BVNULL;
struct berval csn;
op->o_req_dn = si->si_base;
op->o_req_ndn = si->si_base;
#ifdef ENABLE_REWRITE
if ( si->si_rewrite ) {
op->o_req_dn = si->si_suffixm;
op->o_req_ndn = si->si_suffixm;
} else
#endif
{
op->o_req_dn = si->si_base;
op->o_req_ndn = si->si_base;
}
cb.sc_response = nonpresent_callback;
cb.sc_private = si;
@ -3924,12 +4009,54 @@ syncinfo_free( syncinfo_t *sie, int free_all )
ch_free( sie->si_cookieState );
}
}
#ifdef ENABLE_REWRITE
if ( sie->si_rewrite )
rewrite_info_delete( &sie->si_rewrite );
if ( sie->si_suffixm.bv_val )
ch_free( sie->si_suffixm.bv_val );
#endif
ch_free( sie );
sie = si_next;
} while ( free_all && si_next );
}
#ifdef ENABLE_REWRITE
static int
config_suffixm( ConfigArgs *c, syncinfo_t *si )
{
char *argvEngine[] = { "rewriteEngine", "on", NULL };
char *argvContext[] = { "rewriteContext", SUFFIXM_CTX, NULL };
char *argvRule[] = { "rewriteRule", NULL, NULL, ":", NULL };
char *vnc, *rnc;
int rc;
if ( si->si_rewrite )
rewrite_info_delete( &si->si_rewrite );
si->si_rewrite = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 2, argvEngine );
if ( rc != LDAP_SUCCESS )
return rc;
rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 2, argvContext );
if ( rc != LDAP_SUCCESS )
return rc;
vnc = ch_malloc( si->si_base.bv_len + 6 );
strcpy( vnc, "(.*)" );
lutil_strcopy( lutil_strcopy( vnc+4, si->si_base.bv_val ), "$" );
argvRule[1] = vnc;
rnc = ch_malloc( si->si_suffixm.bv_len + 3 );
strcpy( rnc, "%1" );
strcpy( rnc+2, si->si_suffixm.bv_val );
argvRule[2] = rnc;
rc = rewrite_parse( si->si_rewrite, c->fname, c->lineno, 4, argvRule );
ch_free( vnc );
return rc;
}
#endif
/* NOTE: used & documented in slapd.conf(5) */
#define IDSTR "rid"
@ -3948,6 +4075,7 @@ syncinfo_free( syncinfo_t *sie, int free_all )
#define SYNCDATASTR "syncdata"
#define LOGBASESTR "logbase"
#define LOGFILTERSTR "logfilter"
#define SUFFIXMSTR "suffixmassage"
/* FIXME: undocumented */
#define EXATTRSSTR "exattrs"
@ -3974,6 +4102,7 @@ enum {
GOT_EXATTRS = 0x00010000U,
GOT_MANAGEDSAIT = 0x00020000U,
GOT_BINDCONF = 0x00040000U,
GOT_SUFFIXM = 0x00080000U,
/* check */
GOT_REQUIRED = (GOT_RID|GOT_PROVIDER|GOT_SEARCHBASE)
@ -4171,16 +4300,38 @@ parse_syncrepl_line(
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
return -1;
}
if ( !be_issubordinate( c->be, &si->si_base ) ) {
ch_free( si->si_base.bv_val );
BER_BVZERO( &si->si_base );
si->si_got |= GOT_SEARCHBASE;
#ifdef ENABLE_REWRITE
} else if ( !strncasecmp( c->argv[ i ], SUFFIXMSTR "=",
STRLENOF( SUFFIXMSTR "=" ) ) )
{
struct berval bv;
int rc;
val = c->argv[ i ] + STRLENOF( SUFFIXMSTR "=" );
if ( si->si_suffixm.bv_val ) {
ch_free( si->si_suffixm.bv_val );
}
ber_str2bv( val, 0, 0, &bv );
rc = dnNormalize( 0, NULL, NULL, &bv, &si->si_suffixm, NULL );
if ( rc != LDAP_SUCCESS ) {
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"Base DN \"%s\" is not within the database naming context",
"Invalid massage DN \"%s\": %d (%s)",
val, rc, ldap_err2string( rc ) );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
return -1;
}
if ( !be_issubordinate( c->be, &si->si_suffixm )) {
ch_free( si->si_suffixm.bv_val );
BER_BVZERO( &si->si_suffixm );
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"Massage DN \"%s\" is not within the database naming context",
val );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
return -1;
}
si->si_got |= GOT_SEARCHBASE;
si->si_got |= GOT_SUFFIXM;
#endif
} else if ( !strncasecmp( c->argv[ i ], LOGBASESTR "=",
STRLENOF( LOGBASESTR "=" ) ) )
{
@ -4443,6 +4594,29 @@ parse_syncrepl_line(
return -1;
}
if ( !be_issubordinate( c->be, &si->si_base ) && !( si->si_got & GOT_SUFFIXM )) {
ch_free( si->si_base.bv_val );
BER_BVZERO( &si->si_base );
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"Base DN \"%s\" is not within the database naming context",
val );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
return -1;
}
#ifdef ENABLE_REWRITE
if ( si->si_got & GOT_SUFFIXM ) {
if (config_suffixm( c, si )) {
ch_free( si->si_suffixm.bv_val );
BER_BVZERO( &si->si_suffixm );
snprintf( c->cr_msg, sizeof( c->cr_msg ),
"Error configuring rewrite engine" );
Debug( LDAP_DEBUG_ANY, "%s: %s.\n", c->log, c->cr_msg, 0 );
return -1;
}
}
#endif
if ( !( si->si_got & GOT_RETRY ) ) {
Debug( LDAP_DEBUG_ANY, "syncrepl %s " SEARCHBASESTR "=\"%s\": no retry defined, using default\n",
si->si_ridtxt, c->be->be_suffix ? c->be->be_suffix[ 0 ].bv_val : "(null)", 0 );
@ -4669,6 +4843,14 @@ syncrepl_unparse( syncinfo_t *si, struct berval *bv )
ptr = lutil_strcopy( ptr, si->si_base.bv_val );
*ptr++ = '"';
}
#ifdef ENABLE_REWRITE
if ( !BER_BVISNULL( &si->si_suffixm ) ) {
if ( WHATSLEFT <= STRLENOF( " " SUFFIXMSTR "=\"" "\"" ) + si->si_suffixm.bv_len ) return;
ptr = lutil_strcopy( ptr, " " SUFFIXMSTR "=\"" );
ptr = lutil_strcopy( ptr, si->si_suffixm.bv_val );
*ptr++ = '"';
}
#endif
if ( !BER_BVISEMPTY( &si->si_logfilterstr ) ) {
if ( WHATSLEFT <= STRLENOF( " " LOGFILTERSTR "=\"" "\"" ) + si->si_logfilterstr.bv_len ) return;
ptr = lutil_strcopy( ptr, " " LOGFILTERSTR "=\"" );

View file

@ -0,0 +1,432 @@
#! /bin/sh
# $OpenLDAP$
## This work is part of OpenLDAP Software <http://www.openldap.org/>.
##
## Copyright 1998-2011 The OpenLDAP Foundation.
## All rights reserved.
##
## Redistribution and use in source and binary forms, with or without
## modification, are permitted only as authorized by the OpenLDAP
## Public License.
##
## A copy of this license is available in the file LICENSE in the
## top-level directory of the distribution or, alternatively, at
## <http://www.OpenLDAP.org/license.html>.
echo "running defines.sh"
. $SRCDIR/scripts/defines.sh
if test $SYNCPROV = syncprovno; then
echo "Syncrepl provider overlay not available, test skipped"
exit 0
fi
CFPRO=$TESTDIR/cfpro.d
CFCON=$TESTDIR/cfcon.d
mkdir -p $TESTDIR $DBDIR1A $DBDIR1B $DBDIR2A $CFPRO $CFCON
$SLAPPASSWD -g -n >$CONFIGPWF
if test x"$SYNCMODE" = x ; then
SYNCMODE=rp
fi
case "$SYNCMODE" in
ro)
SYNCTYPE="type=refreshOnly interval=00:00:00:03"
;;
rp)
SYNCTYPE="type=refreshAndPersist"
;;
*)
echo "unknown sync mode $SYNCMODE"
exit 1;
;;
esac
#
# Test replication of dynamic config with alternate slave config:
# - start provider
# - start consumer
# - configure over ldap
# - populate over ldap
# - configure syncrepl over ldap
# - retrieve database over ldap and compare against expected results
#
echo "Starting provider slapd on TCP/IP port $PORT1..."
. $CONFFILTER $BACKEND $MONITORDB < $DYNAMICCONF > $CONFLDIF
$SLAPADD -F $CFPRO -n 0 -l $CONFLDIF
$SLAPD -F $CFPRO -h $URI1 -d $LVL $TIMING > $LOG1 2>&1 &
PID=$!
if test $WAIT != 0 ; then
echo PID $PID
read foo
fi
KILLPIDS="$PID"
sleep 1
echo "Using ldapsearch to check that provider slapd is running..."
for i in 0 1 2 3 4 5; do
$LDAPSEARCH -s base -b "" -H $URI1 \
'objectclass=*' > /dev/null 2>&1
RC=$?
if test $RC = 0 ; then
break
fi
echo "Waiting 5 seconds for slapd to start..."
sleep 5
done
if test $RC != 0 ; then
echo "ldapsearch failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Inserting syncprov overlay on provider..."
if [ "$SYNCPROV" = syncprovmod ]; then
$LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF <<EOF > $TESTOUT 2>&1
dn: cn=module,cn=config
objectClass: olcModuleList
cn: module
olcModulePath: ../servers/slapd/overlays
olcModuleLoad: syncprov.la
EOF
RC=$?
if test $RC != 0 ; then
echo "ldapadd failed for moduleLoad ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
fi
read CONFIGPW < $CONFIGPWF
$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
dn: olcOverlay=syncprov,olcDatabase={0}config,cn=config
changetype: add
objectClass: olcOverlayConfig
objectClass: olcSyncProvConfig
olcOverlay: syncprov
EOF
RC=$?
if test $RC != 0 ; then
echo "ldapmodify failed for syncprov config ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
# Slaves will not replicate the master's actual cn=config.
# Instead, they will use an alternate DB so that they may be
# configured differently from the master. This alternate DB
# will also be a consumer for the real cn=schema,cn=config tree.
# It has MirrorMode enabled so that it can be written directly
# while being a slave of the main schema.
echo "Configuring slave config DB on provider..."
$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >> $TESTOUT 2>&1
dn: cn=config
changetype: modify
add: olcServerID
olcServerID: 1
dn: olcDatabase={1}ldif,cn=config
changetype: add
objectClass: olcDatabaseConfig
objectClass: olcLdifConfig
olcDatabase: {1}ldif
olcDbDirectory: $DBDIR1A
olcSuffix: cn=config,cn=slave
olcRootDN: cn=config,cn=slave
olcRootPW: repsecret
olcAccess: to * by dn.base="cn=config" write
dn: olcOverlay=syncprov,olcDatabase={1}ldif,cn=config
changetype: add
objectClass: olcOverlayConfig
objectClass: olcSyncProvConfig
olcOverlay: syncprov
dn: cn=config,cn=slave
changetype: add
objectClass: olcGlobal
cn: slaveconfig
dn: cn=schema,cn=config,cn=slave
changetype: add
objectClass: olcSchemaConfig
cn: schema
dn: olcDatabase={0}config,cn=config,cn=slave
changetype: add
objectClass: olcDatabaseConfig
olcDatabase: {0}config
olcRootPW: topsecret
olcSyncrepl: {0}rid=001 provider=$URI1 binddn="cn=config,cn=slave"
bindmethod=simple credentials=repsecret searchbase="cn=config,cn=slave"
$SYNCTYPE retry="3 5 300 5" timeout=3 suffixmassage="cn=config"
olcUpdateRef: $URI1
dn: olcDatabase={1}ldif,cn=config
changetype: modify
add: olcSyncrepl
olcSyncrepl: {0}rid=001 provider=$URI1 binddn="cn=config"
bindmethod=simple credentials=$CONFIGPW searchbase="cn=schema,cn=config"
$SYNCTYPE retry="3 5 300 5" timeout=3
suffixmassage="cn=schema,cn=config,cn=slave"
-
add: olcMirrorMode
olcMirrorMode: TRUE
EOF
RC=$?
if test $RC != 0 ; then
echo "ldapmodify failed for slave DB config ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Starting consumer slapd on TCP/IP port $PORT2..."
$SLAPADD -F $CFCON -n 0 -l $CONFLDIF
$SLAPD -F $CFCON -h $URI2 -d $LVL $TIMING > $LOG2 2>&1 &
SLAVEPID=$!
if test $WAIT != 0 ; then
echo SLAVEPID $SLAVEPID
read foo
fi
KILLPIDS="$KILLPIDS $SLAVEPID"
sleep 1
echo "Using ldapsearch to check that consumer slapd is running..."
for i in 0 1 2 3 4 5; do
$LDAPSEARCH -s base -b "" -H $URI2 \
'objectclass=*' > /dev/null 2>&1
RC=$?
if test $RC = 0 ; then
break
fi
echo "Waiting 5 seconds for slapd to start..."
sleep 5
done
if test $RC != 0 ; then
echo "ldapsearch failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Configuring syncrepl on consumer..."
$LDAPMODIFY -D cn=config -H $URI2 -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
dn: olcDatabase={0}config,cn=config
changetype: modify
add: olcSyncRepl
olcSyncRepl: rid=001 provider=$URI1 binddn="cn=config,cn=slave"
bindmethod=simple credentials=repsecret searchbase="cn=config,cn=slave"
$SYNCTYPE retry="3 5 300 5" timeout=3
suffixmassage="cn=config"
-
add: olcUpdateRef
olcUpdateRef: $URI1
EOF
echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
sleep $SLEEP1
echo "Using ldapsearch to check that syncrepl received config changes..."
RC=32
for i in 0 1 2 3 4 5; do
RESULT=`$LDAPSEARCH -H $URI2 -D cn=config -y $CONFIGPWF \
-s base -b "olcDatabase={0}config,cn=config" \
'(olcUpdateRef=*)' 2>&1 | awk '/^dn:/ {print "OK"}'`
if test "x$RESULT" = "xOK" ; then
RC=0
break
fi
echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
sleep $SLEEP1
done
if test $RC != 0 ; then
echo "ldapsearch failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Adding schema and databases on provider..."
$LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
include: file://$ABS_SCHEMADIR/core.ldif
include: file://$ABS_SCHEMADIR/cosine.ldif
include: file://$ABS_SCHEMADIR/inetorgperson.ldif
include: file://$ABS_SCHEMADIR/openldap.ldif
include: file://$ABS_SCHEMADIR/nis.ldif
EOF
RC=$?
if test $RC != 0 ; then
echo "ldapadd failed for schema config ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
nullExclude="" nullOK=""
test $BACKEND = null && nullExclude="# " nullOK="OK"
if [ "$BACKENDTYPE" = mod ]; then
$LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
dn: cn=module,cn=config
objectClass: olcModuleList
cn: module
olcModulePath: ../servers/slapd/back-$BACKEND
olcModuleLoad: back_$BACKEND.la
dn: cn=module,cn=config,cn=slave
objectClass: olcModuleList
cn: module
olcModulePath: ../servers/slapd/back-$BACKEND
olcModuleLoad: back_$BACKEND.la
EOF
RC=$?
if test $RC != 0 ; then
echo "ldapadd failed for backend config ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
fi
$LDAPADD -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
dn: olcDatabase={2}$BACKEND,cn=config
objectClass: olcDatabaseConfig
${nullExclude}objectClass: olc${BACKEND}Config
olcDatabase: {2}$BACKEND
olcSuffix: $BASEDN
${nullExclude}olcDbDirectory: $DBDIR1B
olcRootDN: $MANAGERDN
olcRootPW: $PASSWD
olcSyncRepl: rid=002 provider=$URI1 binddn="$MANAGERDN" bindmethod=simple
credentials=$PASSWD searchbase="$BASEDN" $SYNCTYPE
retry="3 5 300 5" timeout=3
olcUpdateRef: $URI1
dn: olcOverlay=syncprov,olcDatabase={2}${BACKEND},cn=config
changetype: add
objectClass: olcOverlayConfig
objectClass: olcSyncProvConfig
olcOverlay: syncprov
dn: olcDatabase={1}$BACKEND,cn=config,cn=slave
objectClass: olcDatabaseConfig
${nullExclude}objectClass: olc${BACKEND}Config
olcDatabase: {1}$BACKEND
olcSuffix: $BASEDN
${nullExclude}olcDbDirectory: $DBDIR2A
olcRootDN: $MANAGERDN
olcRootPW: $PASSWD
olcSyncRepl: rid=002 provider=$URI1 binddn="$MANAGERDN" bindmethod=simple
credentials=$PASSWD searchbase="$BASEDN" $SYNCTYPE
retry="3 5 300 5" timeout=3
olcUpdateRef: $URI1
EOF
RC=$?
if test $RC != 0 ; then
echo "ldapadd failed for database config ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
case $BACKEND in
bdb | hdb)
$LDAPMODIFY -D cn=config -H $URI1 -y $CONFIGPWF <<EOF >>$TESTOUT 2>&1
dn: olcDatabase={2}$BACKEND,cn=config
changetype: modify
add: olcDbIndex
olcDbIndex: objectClass,entryUUID,entryCSN eq
olcDbIndex: cn,uid pres,eq,sub
EOF
RC=$?
if test $RC != 0 ; then
echo "ldapadd modify for database config ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
;;
esac
echo "Using ldapadd to populate provider..."
$LDAPADD -D "$MANAGERDN" -H $URI1 -w $PASSWD -f $LDIFORDERED \
>> $TESTOUT 2>&1
RC=$?
if test $RC != 0 ; then
echo "ldapadd failed for database config ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
sleep $SLEEP1
echo "Using ldapsearch to check that syncrepl received database changes..."
RC=32
for i in 0 1 2 3 4 5; do
RESULT=`$LDAPSEARCH -H $URI2 \
-s base -b "cn=Ursula Hampster,ou=Alumni Association,ou=People,dc=example,dc=com" \
'(objectClass=*)' 2>&1 | awk '/^dn:/ {print "OK"}'`
if test "x$RESULT$nullOK" = "xOK" ; then
RC=0
break
fi
echo "Waiting $SLEEP1 seconds for syncrepl to receive changes..."
sleep $SLEEP1
done
if test $RC != 0 ; then
echo "ldapsearch failed ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Using ldapsearch to read all the entries from the provider..."
$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI1 -w $PASSWD \
'objectclass=*' > $MASTEROUT 2>&1
RC=$?
if test $RC != 0 ; then
echo "ldapsearch failed at provider ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
echo "Using ldapsearch to read all the entries from the consumer..."
$LDAPSEARCH -S "" -b "$BASEDN" -D "$MANAGERDN" -H $URI2 -w $PASSWD \
'objectclass=*' > $SLAVEOUT 2>&1
RC=$?
if test $RC != 0 ; then
echo "ldapsearch failed at consumer ($RC)!"
test $KILLSERVERS != no && kill -HUP $KILLPIDS
exit $RC
fi
test $KILLSERVERS != no && kill -HUP $KILLPIDS
echo "Filtering provider results..."
$LDIFFILTER < $MASTEROUT > $MASTERFLT
echo "Filtering consumer results..."
$LDIFFILTER < $SLAVEOUT > $SLAVEFLT
echo "Comparing retrieved entries from provider and consumer..."
$CMP $MASTERFLT $SLAVEFLT > $CMPOUT
if test $? != 0 ; then
echo "test failed - provider and consumer databases differ"
exit 1
fi
echo ">>>>> Test succeeded"
test $KILLSERVERS != no && wait
exit 0