This is an automated email from the git hooks/post-receive script.
mreynolds pushed a commit to branch 389-ds-base-1.3.7
in repository 389-ds-base.
commit 9c2ec6911b66e5aae7504ead9892e2680b015f2e
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Fri May 11 10:53:06 2018 -0400
Ticket 49671 - Readonly replicas should not write internal ops to changelog
Bug Description: When a hub receives an update that triggers the memberOf
plugin, but that interal operation has no csn and that
causes the update to the changelog to fail and break
replication.
Fix Description: Do not write internal updates with no csns to the changelog
on read-only replicas.
https://pagure.io/389-ds-base/issue/49671
Reviewed by: simon, tbordaz, and lkrispen (Thanks!!!)
(cherry picked from commit afb755bd95f1643665ea34c5a5fa2bb26bfa21b9)
---
.../tests/suites/replication/cascading_test.py | 150 +++++++++++++++++++++
ldap/servers/plugins/replication/repl5_plugins.c | 10 ++
2 files changed, 160 insertions(+)
diff --git a/dirsrvtests/tests/suites/replication/cascading_test.py
b/dirsrvtests/tests/suites/replication/cascading_test.py
new file mode 100644
index 0000000..7331f20
--- /dev/null
+++ b/dirsrvtests/tests/suites/replication/cascading_test.py
@@ -0,0 +1,150 @@
+# --- BEGIN COPYRIGHT BLOCK ---
+# Copyright (C) 2018 Red Hat, Inc.
+# All rights reserved.
+#
+# License: GPL (version 3 or any later version).
+# See LICENSE for details.
+# --- END COPYRIGHT BLOCK ---
+#
+import logging
+import pytest
+import os
+import ldap
+from lib389._constants import *
+from lib389.replica import ReplicationManager
+from lib389.plugins import MemberOfPlugin
+from lib389.agreement import Agreements
+from lib389.idm.user import UserAccount, TEST_USER_PROPERTIES
+from lib389.idm.group import Groups
+from lib389.topologies import topology_m1h1c1 as topo
+
+DEBUGGING = os.getenv("DEBUGGING", default=False)
+if DEBUGGING:
+ logging.getLogger(__name__).setLevel(logging.DEBUG)
+else:
+ logging.getLogger(__name__).setLevel(logging.INFO)
+log = logging.getLogger(__name__)
+
+BIND_DN = 'uid=tuser1,ou=People,dc=example,dc=com'
+BIND_RDN = 'tuser1'
+
+
+def config_memberof(server):
+ """Configure memberOf plugin and configure fractional
+ to prevent total init to send memberof
+ """
+
+ memberof = MemberOfPlugin(server)
+ memberof.enable()
+ memberof.set_autoaddoc('nsMemberOf')
+ server.restart()
+ agmts = Agreements(server)
+ for agmt in agmts.list():
+ log.info('update %s to add nsDS5ReplicatedAttributeListTotal' % agmt.dn)
+ agmt.replace_many(('nsDS5ReplicatedAttributeListTotal',
'(objectclass=*) $ EXCLUDE '),
+ ('nsDS5ReplicatedAttributeList', '(objectclass=*) $
EXCLUDE memberOf'))
+
+
+def test_basic_with_hub(topo):
+ """Check that basic operations work in cascading replication, this
includes
+ testing plugins that perform internal operatons, and replicated password
+ policy state attributes.
+
+ :id: 4ac85552-45bc-477b-89a4-226dfff8c6cc
+ :setup: 1 master, 1 hub, 1 consumer
+ :steps:
+ 1. Enable memberOf plugin and set password account lockout settings
+ 2. Restart the instance
+ 3. Add a user
+ 4. Add a group
+ 5. Test that the replication works
+ 6. Add the user as a member to the group
+ 7. Test that the replication works
+ 8. Issue bad binds to update passwordRetryCount
+ 9. Test that replicaton works
+ 10. Check that passwordRetyCount was replicated
+ :expectedresults:
+ 1. Should be a success
+ 2. Should be a success
+ 3. Should be a success
+ 4. Should be a success
+ 5. Should be a success
+ 6. Should be a success
+ 7. Should be a success
+ 8. Should be a success
+ 9. Should be a success
+ 10. Should be a success
+ """
+
+ repl_manager = ReplicationManager(DEFAULT_SUFFIX)
+ master = topo.ms["master1"]
+ consumer = topo.cs["consumer1"]
+ hub = topo.hs["hub1"]
+
+ for inst in topo:
+ config_memberof(inst)
+ inst.config.set('passwordlockout', 'on')
+ inst.config.set('passwordlockoutduration', '60')
+ inst.config.set('passwordmaxfailure', '3')
+ inst.config.set('passwordIsGlobalPolicy', 'on')
+
+ # Create user
+ user1 = UserAccount(master, BIND_DN)
+ user_props = TEST_USER_PROPERTIES.copy()
+ user_props.update({'sn': BIND_RDN,
+ 'cn': BIND_RDN,
+ 'uid': BIND_RDN,
+ 'inetUserStatus': '1',
+ 'objectclass': 'extensibleObject',
+ 'userpassword': PASSWORD})
+ user1.create(properties=user_props, basedn=SUFFIX)
+
+ # Create group
+ groups = Groups(master, DEFAULT_SUFFIX)
+ group = groups.create(properties={'cn': 'group'})
+
+ # Test replication
+ repl_manager.test_replication(master, consumer)
+
+ # Trigger memberOf plugin by adding user to group
+ group.replace('member', user1.dn)
+
+ # Test replication once more
+ repl_manager.test_replication(master, consumer)
+
+ # Issue bad password to update passwordRetryCount
+ try:
+ master.simple_bind_s(user1.dn, "badpassword")
+ except:
+ pass
+
+ # Test replication one last time
+ master.simple_bind_s(DN_DM, PASSWORD)
+ repl_manager.test_replication(master, consumer)
+
+ # Finally check if passwordRetyCount was replicated to the hub and consumer
+ user1 = UserAccount(hub, BIND_DN)
+ count = user1.get_attr_val_int('passwordRetryCount')
+ if count is None:
+ log.fatal('PasswordRetyCount was not replicated to hub')
+ assert False
+ if int(count) != 1:
+ log.fatal('PasswordRetyCount has unexpected value: {}'.format(count))
+ assert False
+
+ user1 = UserAccount(consumer, BIND_DN)
+ count = user1.get_attr_val_int('passwordRetryCount')
+ if count is None:
+ log.fatal('PasswordRetyCount was not replicated to consumer')
+ assert False
+ if int(count) != 1:
+ log.fatal('PasswordRetyCount has unexpected value: {}'.format(count))
+ assert False
+
+
+if __name__ == '__main__':
+ # Run isolated
+ # -s for DEBUG mode
+ CURRENT_FILE = os.path.realpath(__file__)
+ pytest.main(["-s", CURRENT_FILE])
+
diff --git a/ldap/servers/plugins/replication/repl5_plugins.c
b/ldap/servers/plugins/replication/repl5_plugins.c
index 0aee882..324e382 100644
--- a/ldap/servers/plugins/replication/repl5_plugins.c
+++ b/ldap/servers/plugins/replication/repl5_plugins.c
@@ -1059,6 +1059,16 @@ write_changelog_and_ruv(Slapi_PBlock *pb)
goto common_return;
}
+ /* Skip internal operations with no op csn if this is a read-only replica */
+ if (op_params->csn == NULL &&
+ operation_is_flag_set(op, OP_FLAG_INTERNAL) &&
+ replica_get_type(r) == REPLICA_TYPE_READONLY)
+ {
+ slapi_log_err(SLAPI_LOG_REPL, "write_changelog_and_ruv",
+ "Skipping internal operation on read-only
replica\n");
+ goto common_return;
+ }
+
/* we might have stripped all the mods - in that case we do not
log the operation */
if (op_params->operation_type != SLAPI_OPERATION_MODIFY ||
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.