From 2df8301bd6d46e1542b91c591f9ef4e708ce10e7 Mon Sep 17 00:00:00 2001 From: Quanah Gibson-Mount Date: Thu, 6 Jan 2011 19:03:17 +0000 Subject: [PATCH] Add syncrepl suffixmassage --- CHANGES | 1 + doc/man/man5/slapd-config.5 | 8 + doc/man/man5/slapd.conf.5 | 8 + servers/slapd/syncrepl.c | 216 +++++++++++++-- tests/scripts/test059-slave-config | 432 +++++++++++++++++++++++++++++ 5 files changed, 648 insertions(+), 17 deletions(-) create mode 100755 tests/scripts/test059-slave-config diff --git a/CHANGES b/CHANGES index aa061f769a..a5e993f0bf 100644 --- a/CHANGES +++ b/CHANGES @@ -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) diff --git a/doc/man/man5/slapd-config.5 b/doc/man/man5/slapd-config.5 index 5ae1bb8c92..5c159794d5 100644 --- a/doc/man/man5/slapd-config.5 +++ b/doc/man/man5/slapd-config.5 @@ -1677,6 +1677,7 @@ FALSE, meaning the contextCSN is stored in the context entry. .B [tls_reqcert=never|allow|try|demand] .B [tls_ciphersuite=] .B [tls_crlcheck=none|peer|all] +.B [suffixmassage=] .B [logbase=] .B [logfilter=] .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 diff --git a/doc/man/man5/slapd.conf.5 b/doc/man/man5/slapd.conf.5 index eb83966034..6e6800c4b4 100644 --- a/doc/man/man5/slapd.conf.5 +++ b/doc/man/man5/slapd.conf.5 @@ -1656,6 +1656,7 @@ the contextCSN is stored in the context entry. .B [tls_reqcert=never|allow|try|demand] .B [tls_ciphersuite=] .B [tls_crlcheck=none|peer|all] +.B [suffixmassage=] .B [logbase=] .B [logfilter=] .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 diff --git a/servers/slapd/syncrepl.c b/servers/slapd/syncrepl.c index aaa99a77a9..ac2c34e849 100644 --- a/servers/slapd/syncrepl.c +++ b/servers/slapd/syncrepl.c @@ -31,6 +31,11 @@ #include "ldap_rq.h" +#ifdef ENABLE_REWRITE +#include "rewrite.h" +#define SUFFIXM_CTX "" +#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 = ⊅ } 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 "=\"" ); diff --git a/tests/scripts/test059-slave-config b/tests/scripts/test059-slave-config new file mode 100755 index 0000000000..bc2a9c77c3 --- /dev/null +++ b/tests/scripts/test059-slave-config @@ -0,0 +1,432 @@ +#! /bin/sh +# $OpenLDAP$ +## This work is part of OpenLDAP Software . +## +## 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 +## . + +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 < $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 <> $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 <> $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 <>$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 <>$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 <>$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 <>$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 <>$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 -- 2.39.5