mirror of
https://git.openldap.org/openldap/openldap.git
synced 2026-06-08 16:22:09 -04:00
Add syncrepl suffixmassage
This commit is contained in:
parent
c525828af1
commit
2df8301bd6
5 changed files with 648 additions and 17 deletions
1
CHANGES
1
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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 = ⊅
|
||||
} 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 "=\"" );
|
||||
|
|
|
|||
432
tests/scripts/test059-slave-config
Executable file
432
tests/scripts/test059-slave-config
Executable 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
|
||||
Loading…
Reference in a new issue