dirsrvtests/suites
by Simon Pichugin
dirsrvtests/suites/replication/wait_for_async_feature_test.py | 280 ++++++++++
1 file changed, 280 insertions(+)
New commits:
commit 2c702c4f44512e8731c3d0a026cbc8838517345f
Author: Simon Pichugin <spichugi(a)redhat.com>
Date: Tue Oct 13 14:10:59 2015 +0200
Ticket 47957 - Add replication test suite for a wait async feature
Description: Test new attribute "nsDS5ReplicaWaitForAsyncResults".
After setting the attribute, supplier will sleep established
amount of millisecond if it finds the response from consumer
is not ready.
Tests:
- not integer value;
- multi value;
- check that value has been set correctly [None, 2000, 0, -5];
- replication behavior with valid values [None, 2000, 0, -5].
https://fedorahosted.org/389/ticket/47957
Reviewed by: nhosoi(a)redhat.com (Thanks, Noriko!)
diff --git a/dirsrvtests/suites/replication/wait_for_async_feature_test.py b/dirsrvtests/suites/replication/wait_for_async_feature_test.py
new file mode 100644
index 0000000..4905088
--- /dev/null
+++ b/dirsrvtests/suites/replication/wait_for_async_feature_test.py
@@ -0,0 +1,280 @@
+import os
+import sys
+import time
+import ldap
+import logging
+import pytest
+from lib389 import DirSrv, Entry, tools, tasks
+from lib389.tools import DirSrvTools
+from lib389._constants import *
+from lib389.properties import *
+from lib389.tasks import *
+from lib389.utils import *
+from collections import Counter
+
+logging.getLogger(__name__).setLevel(logging.DEBUG)
+log = logging.getLogger(__name__)
+
+installation1_prefix = None
+
+WAITFOR_ASYNC_ATTR = "nsDS5ReplicaWaitForAsyncResults"
+
+class TopologyReplication(object):
+ def __init__(self, master1, master2, m1_m2_agmt, m2_m1_agmt):
+ master1.open()
+ master2.open()
+ self.masters = ((master1, m1_m2_agmt),
+ (master2, m2_m1_agmt))
+
+
+(a)pytest.fixture(scope="module")
+def topology(request):
+ global installation1_prefix
+ if installation1_prefix:
+ args_instance[SER_DEPLOYED_DIR] = installation1_prefix
+
+ # Creating master 1...
+ master1 = DirSrv(verbose=False)
+ args_instance[SER_HOST] = HOST_MASTER_1
+ args_instance[SER_PORT] = PORT_MASTER_1
+ args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_1
+ args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX
+ args_master = args_instance.copy()
+ master1.allocate(args_master)
+ instance_master1 = master1.exists()
+ if instance_master1:
+ master1.delete()
+ master1.create()
+ master1.open()
+ master1.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER_1)
+
+ # Creating master 2...
+ master2 = DirSrv(verbose=False)
+ args_instance[SER_HOST] = HOST_MASTER_2
+ args_instance[SER_PORT] = PORT_MASTER_2
+ args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_2
+ args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX
+ args_master = args_instance.copy()
+ master2.allocate(args_master)
+ instance_master2 = master2.exists()
+ if instance_master2:
+ master2.delete()
+ master2.create()
+ master2.open()
+ master2.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER_2)
+
+ #
+ # Create all the agreements
+ #
+ # Creating agreement from master 1 to master 2
+ properties = {RA_NAME: r'meTo_$host:$port',
+ RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
+ RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
+ RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
+ RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
+ m1_m2_agmt = master1.agreement.create(suffix=SUFFIX, host=master2.host, port=master2.port, properties=properties)
+ if not m1_m2_agmt:
+ log.fatal("Fail to create a master -> master replica agreement")
+ sys.exit(1)
+ log.debug("%s created" % m1_m2_agmt)
+
+ # Creating agreement from master 2 to master 1
+ properties = {RA_NAME: r'meTo_$host:$port',
+ RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
+ RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
+ RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
+ RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
+ m2_m1_agmt = master2.agreement.create(suffix=SUFFIX, host=master1.host, port=master1.port, properties=properties)
+ if not m2_m1_agmt:
+ log.fatal("Fail to create a master -> master replica agreement")
+ sys.exit(1)
+ log.debug("%s created" % m2_m1_agmt)
+
+ # Allow the replicas to get situated with the new agreements...
+ time.sleep(5)
+
+ #
+ # Initialize all the agreements
+ #
+ master1.agreement.init(SUFFIX, HOST_MASTER_2, PORT_MASTER_2)
+ master1.waitForReplInit(m1_m2_agmt)
+ master2.agreement.init(SUFFIX, HOST_MASTER_1, PORT_MASTER_1)
+ master2.waitForReplInit(m2_m1_agmt)
+
+ # Check replication is working...
+ if master1.testReplication(DEFAULT_SUFFIX, master2):
+ log.info('Replication is working.')
+ else:
+ log.fatal('Replication is not working.')
+ assert False
+
+ log.info("Set Replication Debugging loglevel for the errorlog")
+ master1.setLogLevel(lib389.LOG_REPLICA)
+ master2.setLogLevel(lib389.LOG_REPLICA)
+
+ # Delete each instance in the end
+ def fin():
+ master1.delete()
+ master2.delete()
+ request.addfinalizer(fin)
+
+ # Clear out the tmp dir
+ master1.clearTmpDir(__file__)
+
+ return TopologyReplication(master1, master2, m1_m2_agmt, m2_m1_agmt)
+
+
+(a)pytest.fixture(params=[(None, (4, 10)),
+ ('2000', (0, 1)),
+ ('0', (4, 10)),
+ ('-5', (4, 10))])
+def waitfor_async_attr(topology, request):
+ """Sets attribute on all replicas"""
+
+ attr_value = request.param[0]
+ expected_result = request.param[1]
+
+ # Run through all masters
+ for master in topology.masters:
+ agmt = master[1]
+ try:
+ if attr_value:
+ log.info("Set %s: %s on %s" % (
+ WAITFOR_ASYNC_ATTR, attr_value, master[0].serverid))
+ mod = [(ldap.MOD_REPLACE, WAITFOR_ASYNC_ATTR, attr_value)]
+ else:
+ log.info("Delete %s from %s" % (
+ WAITFOR_ASYNC_ATTR, master[0].serverid))
+ mod = [(ldap.MOD_DELETE, WAITFOR_ASYNC_ATTR, None)]
+ master[0].modify_s(agmt, mod)
+ except ldap.LDAPError as e:
+ log.error('Failed to set or delete %s attribute: (%s)' % (
+ WAITFOR_ASYNC_ATTR, e.message['desc']))
+
+ return (attr_value, expected_result)
+
+
+(a)pytest.fixture
+def entries(topology, request):
+ """Adds entries to the master1"""
+
+ master1 = topology.masters[0][0]
+
+ TEST_OU = "test"
+ test_dn = SUFFIX
+ test_list = []
+
+ log.info("Add 100 nested entries under replicated suffix on %s" % master1.serverid)
+ for i in xrange(100):
+ test_dn = 'ou=%s%s,%s' % (TEST_OU, i, test_dn)
+ test_list.insert(0, test_dn)
+ try:
+ master1.add_s(Entry((test_dn,
+ {'objectclass': 'top',
+ 'objectclass': 'organizationalUnit',
+ 'ou': TEST_OU})))
+ except ldap.LDAPError as e:
+ log.error('Failed to add entry (%s): error (%s)' % (test_dn,
+ e.message['desc']))
+ assert False
+
+ log.info("Delete created entries")
+ for test_dn in test_list:
+ try:
+ master1.delete_s(test_dn)
+ except ldap.LDAPError, e:
+ log.error('Failed to delete entry (%s): error (%s)' % (test_dn,
+ e.message['desc']))
+ assert False
+
+ def fin():
+ log.info("Clear the errors log in the end of the test case")
+ with open(master1.errlog, 'w') as errlog:
+ errlog.writelines("")
+ request.addfinalizer(fin)
+
+
+def test_not_int_value(topology):
+ """Tests not integer value"""
+
+ master1 = topology.masters[0][0]
+ agmt = topology.masters[0][1]
+
+ log.info("Try to set %s: wv1" % WAITFOR_ASYNC_ATTR)
+ try:
+ mod = [(ldap.MOD_REPLACE, WAITFOR_ASYNC_ATTR, "wv1")]
+ master1.modify_s(agmt, mod)
+ except ldap.LDAPError as e:
+ assert e.message['desc'] == 'Invalid syntax'
+
+
+def test_multi_value(topology):
+ """Tests multi value"""
+
+ master1 = topology.masters[0][0]
+ agmt = topology.masters[0][1]
+ log.info("agmt: %s" % agmt)
+
+ log.info("Try to set %s: 100 and 101 in the same time (multi value test)" % (
+ WAITFOR_ASYNC_ATTR))
+ try:
+ mod = [(ldap.MOD_ADD, WAITFOR_ASYNC_ATTR, "100")]
+ master1.modify_s(agmt, mod)
+ mod = [(ldap.MOD_ADD, WAITFOR_ASYNC_ATTR, "101")]
+ master1.modify_s(agmt, mod)
+ except ldap.LDAPError as e:
+ assert e.message['desc'] == 'Object class violation'
+
+
+def test_value_check(topology, waitfor_async_attr):
+ """Checks that value has been set correctly"""
+
+ attr_value = waitfor_async_attr[0]
+
+ for master in topology.masters:
+ agmt = master[1]
+
+ log.info("Check attr %s on %s" % (WAITFOR_ASYNC_ATTR, master[0].serverid))
+ try:
+ if attr_value:
+ entry = master[0].search_s(agmt, ldap.SCOPE_BASE, "%s=%s" % (
+ WAITFOR_ASYNC_ATTR, attr_value))
+ assert entry
+ else:
+ entry = master[0].search_s(agmt, ldap.SCOPE_BASE, "%s=*" % WAITFOR_ASYNC_ATTR)
+ assert not entry
+ except ldap.LDAPError as e:
+ log.fatal('Search failed, error: ' + e.message['desc'])
+ assert False
+
+
+def test_behavior_with_value(topology, waitfor_async_attr, entries):
+ """Tests replication behavior with valid
+ nsDS5ReplicaWaitForAsyncResults attribute values
+ """
+
+ master1 = topology.masters[0][0]
+ sync_dict = Counter()
+ min_ap = waitfor_async_attr[1][0]
+ max_ap = waitfor_async_attr[1][1]
+
+ log.info("Gather all sync attempts within Counter dict, group by timestamp")
+ with open(master1.errlog, 'r') as errlog:
+ errlog_filtered = filter(lambda x: "waitfor_async_results" in x, errlog)
+ for line in errlog_filtered:
+ # Watch only over unsuccessful sync attempts
+ if line.split()[4] != line.split()[5]:
+ timestamp = line.split(']')[0]
+ sync_dict[timestamp] += 1
+
+ log.info("Take the most common timestamp and assert it has appeared " \
+ "in the range from %s to %s times" % (min_ap, max_ap))
+ most_common_val = sync_dict.most_common(1)[0][1]
+ assert min_ap <= most_common_val <= max_ap
+
+
+if __name__ == '__main__':
+ # Run isolated
+ # -s for DEBUG mode
+ CURRENT_FILE = os.path.realpath(__file__)
+ pytest.main("-s %s" % CURRENT_FILE)
8 years, 6 months
Branch '389-ds-base-1.3.4' - rpm.mk
by Richard Allen Megginson
rpm.mk | 4 ++++
1 file changed, 4 insertions(+)
New commits:
commit 46c40528284ee9a717aea59d99ff2bcab0c980f2
Author: Rich Megginson <rmeggins(a)redhat.com>
Date: Tue Jul 21 11:28:33 2015 -0600
Ticket #48227 rpm.mk doesn't build srpms for 389-ds and nunc-stans
https://fedorahosted.org/389/ticket/48227
Reviewed by: nhosoi (Thanks!)
Branch: 389-ds-base-1.3.4
Fix Description: Add makefile macros for the nunc stans tarball name
and url. Grab the nunc stans tarball from the url with wget and
copy it to the SOURCES.
Platforms tested: Fedora 21
Flag Day: no
Doc impact: no
(cherry picked from commit 684f8c5f10226ce4328a37c510a1ef0a61db4e69)
diff --git a/rpm.mk b/rpm.mk
index fffc528..aa397b7 100644
--- a/rpm.mk
+++ b/rpm.mk
@@ -4,6 +4,8 @@ RPM_RELEASE ?= $(shell $(PWD)/rpm/rpmverrel.sh release)
PACKAGE = 389-ds-base
RPM_NAME_VERSION = $(PACKAGE)-$(RPM_VERSION)
TARBALL = $(RPM_NAME_VERSION).tar.bz2
+NUNC_STANS_URL ?= $(shell rpmspec -P -D 'use_nunc_stans 1' $(PWD)/rpm/389-ds-base.spec.in | awk '/^Source3:/ {print $$2}')
+NUNC_STANS_TARBALL ?= $(shell basename "$(NUNC_STANS_URL)")
clean:
rm -rf dist
@@ -17,6 +19,7 @@ tarballs: local-archive
-mkdir -p dist/sources
cd dist; tar cfj sources/$(TARBALL) $(RPM_NAME_VERSION)
rm -rf dist/$(RPM_NAME_VERSION)
+ cd dist/sources; wget $(NUNC_STANS_URL)
rpmroot:
rm -rf $(RPMBUILD)
@@ -34,6 +37,7 @@ srpmdistdir:
rpmbuildprep:
cp dist/sources/$(TARBALL) $(RPMBUILD)/SOURCES/
+ cp dist/sources/$(NUNC_STANS_TARBALL) $(RPMBUILD)/SOURCES/
cp rpm/$(PACKAGE)-* $(RPMBUILD)/SOURCES/
sed -e s/__VERSION__/$(RPM_VERSION)/ -e s/__RELEASE__/$(RPM_RELEASE)/ \
rpm/$(PACKAGE).spec.in > $(RPMBUILD)/SPECS/$(PACKAGE).spec
8 years, 6 months
Branch '389-ds-base-1.3.4' - dirsrvtests/suites dirsrvtests/tickets
by Simon Pichugin
dirsrvtests/suites/acl/acl_test.py | 953 +++++++++++++++++
dirsrvtests/tickets/ticket47553_ger.py | 475 --------
dirsrvtests/tickets/ticket47553_rdn_write_test.py | 143 --
dirsrvtests/tickets/ticket47553_single_aci_test.py | 1137 ---------------------
4 files changed, 929 insertions(+), 1779 deletions(-)
New commits:
commit cc7229e97bd5cc40b5786ca693a7feed4d3521d5
Author: Simon Pichugin <spichugi(a)redhat.com>
Date: Wed Sep 2 11:27:36 2015 +0200
Ticket 48264 - Ticket 47553 tests refactoring
Description: Refactor these tests according to the pytest and PEP8 way:
- ticket47553_ger.py;
- ticket47553_rdn_write_test.py;
- ticket47553_single_aci_test.py.
Move them to the dirsrvtests/suites/acl/acl_test.py test suite.
https://fedorahosted.org/389/ticket/48264
Reviewed by: mreynolds(a)redhat.com (Thanks!)
(cherry picked from commit edaa28b1266312ef8dce737af46e09e130c7135a)
diff --git a/dirsrvtests/suites/acl/acl_test.py b/dirsrvtests/suites/acl/acl_test.py
index 36aed33..422a1ec 100644
--- a/dirsrvtests/suites/acl/acl_test.py
+++ b/dirsrvtests/suites/acl/acl_test.py
@@ -18,48 +18,167 @@ from lib389._constants import *
from lib389.properties import *
from lib389.tasks import *
from lib389.utils import *
+from ldap.controls.simple import GetEffectiveRightsControl
logging.getLogger(__name__).setLevel(logging.DEBUG)
log = logging.getLogger(__name__)
+#
+# important part. We can deploy Master1 and Master2 on different versions
+#
installation1_prefix = None
+installation2_prefix = None
+
+TEST_REPL_DN = "cn=test_repl, %s" % SUFFIX
+
+STAGING_CN = "staged user"
+PRODUCTION_CN = "accounts"
+EXCEPT_CN = "excepts"
+
+STAGING_DN = "cn=%s,%s" % (STAGING_CN, SUFFIX)
+PRODUCTION_DN = "cn=%s,%s" % (PRODUCTION_CN, SUFFIX)
+PROD_EXCEPT_DN = "cn=%s,%s" % (EXCEPT_CN, PRODUCTION_DN)
+
+STAGING_PATTERN = "cn=%s*,%s" % (STAGING_CN[:2], SUFFIX)
+PRODUCTION_PATTERN = "cn=%s*,%s" % (PRODUCTION_CN[:2], SUFFIX)
+BAD_STAGING_PATTERN = "cn=bad*,%s" % (SUFFIX)
+BAD_PRODUCTION_PATTERN = "cn=bad*,%s" % (SUFFIX)
+
+BIND_CN = "bind_entry"
+BIND_DN = "cn=%s,%s" % (BIND_CN, SUFFIX)
+BIND_PW = "password"
+NEW_ACCOUNT = "new_account"
+MAX_ACCOUNTS = 20
-class TopologyStandalone(object):
- def __init__(self, standalone):
- standalone.open()
- self.standalone = standalone
+CONFIG_MODDN_ACI_ATTR = "nsslapd-moddn-aci"
+
+SRC_ENTRY_CN = "tuser"
+EXT_RDN = "01"
+DST_ENTRY_CN = SRC_ENTRY_CN + EXT_RDN
+
+SRC_ENTRY_DN = "cn=%s,%s" % (SRC_ENTRY_CN, SUFFIX)
+DST_ENTRY_DN = "cn=%s,%s" % (DST_ENTRY_CN, SUFFIX)
+
+
+class TopologyMaster1Master2(object):
+ def __init__(self, master1, master2):
+ master1.open()
+ self.master1 = master1
+
+ master2.open()
+ self.master2 = master2
@pytest.fixture(scope="module")
def topology(request):
+ """This fixture is used to create a replicated topology for the 'module'.
+ The replicated topology is MASTER1 <-> Master2.
+ """
+
global installation1_prefix
+ global installation2_prefix
+
+ # allocate master1 on a given deployement
+ master1 = DirSrv(verbose=False)
if installation1_prefix:
args_instance[SER_DEPLOYED_DIR] = installation1_prefix
- # Creating standalone instance ...
- standalone = DirSrv(verbose=False)
- args_instance[SER_HOST] = HOST_STANDALONE
- args_instance[SER_PORT] = PORT_STANDALONE
- args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
- args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX
- args_standalone = args_instance.copy()
- standalone.allocate(args_standalone)
- instance_standalone = standalone.exists()
- if instance_standalone:
- standalone.delete()
- standalone.create()
- standalone.open()
-
- # Delete each instance in the end
+ # Args for the master1 instance
+ args_instance[SER_HOST] = HOST_MASTER_1
+ args_instance[SER_PORT] = PORT_MASTER_1
+ args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_1
+ args_master = args_instance.copy()
+ master1.allocate(args_master)
+
+ # allocate master1 on a given deployement
+ master2 = DirSrv(verbose=False)
+ if installation2_prefix:
+ args_instance[SER_DEPLOYED_DIR] = installation2_prefix
+
+ # Args for the consumer instance
+ args_instance[SER_HOST] = HOST_MASTER_2
+ args_instance[SER_PORT] = PORT_MASTER_2
+ args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_2
+ args_master = args_instance.copy()
+ master2.allocate(args_master)
+
+ # Get the status of the instance and restart it if it exists
+ instance_master1 = master1.exists()
+ instance_master2 = master2.exists()
+
+ # Remove all the instances
+ if instance_master1:
+ master1.delete()
+ if instance_master2:
+ master2.delete()
+
+ # Create the instances
+ master1.create()
+ master1.open()
+ master2.create()
+ master2.open()
+
+ #
+ # Now prepare the Master-Consumer topology
+ #
+ # First Enable replication
+ master1.replica.enableReplication(suffix=SUFFIX,
+ role=REPLICAROLE_MASTER,
+ replicaId=REPLICAID_MASTER_1)
+ master2.replica.enableReplication(suffix=SUFFIX,
+ role=REPLICAROLE_MASTER,
+ replicaId=REPLICAID_MASTER_2)
+
+ # Initialize the supplier->consumer
+
+ properties = {RA_NAME: r'meTo_$host:$port',
+ RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
+ RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
+ RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
+ RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
+ repl_agreement = master1.agreement.create(suffix=SUFFIX,
+ host=master2.host,
+ port=master2.port,
+ properties=properties)
+
+ if not repl_agreement:
+ log.fatal("Fail to create a replica agreement")
+ sys.exit(1)
+
+ log.debug("%s created" % repl_agreement)
+
+ properties = {RA_NAME: r'meTo_$host:$port',
+ RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
+ RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
+ RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
+ RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
+ master2.agreement.create(suffix=SUFFIX,
+ host=master1.host,
+ port=master1.port,
+ properties=properties)
+
+ master1.agreement.init(SUFFIX, HOST_MASTER_2, PORT_MASTER_2)
+ master1.waitForReplInit(repl_agreement)
+
+ # Check replication is working fine
+ if master1.testReplication(DEFAULT_SUFFIX, master2):
+ log.info('Replication is working.')
+ else:
+ log.fatal('Replication is not working.')
+ assert False
+
def fin():
- standalone.delete()
+ master1.delete()
+ master2.delete()
request.addfinalizer(fin)
- # Clear out the tmp dir
- standalone.clearTmpDir(__file__)
+ # clear the tmp directory
+ master1.clearTmpDir(__file__)
- return TopologyStandalone(standalone)
+ # Here we have two instances master and consumer
+ # with replication working.
+ return TopologyMaster1Master2(master1, master2)
def add_attr(topology, attr_name):
@@ -135,7 +254,7 @@ def test_aci_attr_subtype_targetattr(topology, aci_with_attr_subtype):
log.info(" Search for the added attribute")
try:
- entries = topology.standalone.search_s(DEFAULT_SUFFIX,
+ entries = topology.master1.search_s(DEFAULT_SUFFIX,
ldap.SCOPE_BASE,
'(objectclass=*)', ['aci'])
entry = str(entries[0])
@@ -147,6 +266,792 @@ def test_aci_attr_subtype_targetattr(topology, aci_with_attr_subtype):
assert False
+def _bind_manager(topology):
+ topology.master1.log.info("Bind as %s " % DN_DM)
+ topology.master1.simple_bind_s(DN_DM, PASSWORD)
+
+
+def _bind_normal(topology):
+ # bind as bind_entry
+ topology.master1.log.info("Bind as %s" % BIND_DN)
+ topology.master1.simple_bind_s(BIND_DN, BIND_PW)
+
+
+def _moddn_aci_deny_tree(topology, mod_type=None,
+ target_from=STAGING_DN, target_to=PROD_EXCEPT_DN):
+ """It denies the access moddn_to in cn=except,cn=accounts,SUFFIX"""
+
+ assert mod_type is not None
+
+ ACI_TARGET_FROM = ""
+ ACI_TARGET_TO = ""
+ if target_from:
+ ACI_TARGET_FROM = "(target_from = \"ldap:///%s\")" % (target_from)
+ if target_to:
+ ACI_TARGET_TO = "(target_to = \"ldap:///%s\")" % (target_to)
+
+ ACI_ALLOW = "(version 3.0; acl \"Deny MODDN to prod_except\"; deny (moddn)"
+ ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
+ ACI_BODY = ACI_TARGET_TO + ACI_TARGET_FROM + ACI_ALLOW + ACI_SUBJECT
+ mod = [(mod_type, 'aci', ACI_BODY)]
+ #topology.master1.modify_s(SUFFIX, mod)
+ topology.master1.log.info("Add a DENY aci under %s " % PROD_EXCEPT_DN)
+ topology.master1.modify_s(PROD_EXCEPT_DN, mod)
+
+
+def _write_aci_staging(topology, mod_type=None):
+ assert mod_type is not None
+
+ ACI_TARGET = "(targetattr= \"cn\")(target=\"ldap:///cn=*,%s\")" % STAGING_DN
+ ACI_ALLOW = "(version 3.0; acl \"write staging entries\"; allow (write)"
+ ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
+ ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
+ mod = [(mod_type, 'aci', ACI_BODY)]
+ topology.master1.modify_s(SUFFIX, mod)
+
+
+def _write_aci_production(topology, mod_type=None):
+ assert mod_type is not None
+
+ ACI_TARGET = "(targetattr= \"cn\")(target=\"ldap:///cn=*,%s\")" % PRODUCTION_DN
+ ACI_ALLOW = "(version 3.0; acl \"write production entries\"; allow (write)"
+ ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
+ ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
+ mod = [(mod_type, 'aci', ACI_BODY)]
+ topology.master1.modify_s(SUFFIX, mod)
+
+
+def _moddn_aci_staging_to_production(topology, mod_type=None,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN):
+ assert mod_type is not None
+
+
+ ACI_TARGET_FROM = ""
+ ACI_TARGET_TO = ""
+ if target_from:
+ ACI_TARGET_FROM = "(target_from = \"ldap:///%s\")" % (target_from)
+ if target_to:
+ ACI_TARGET_TO = "(target_to = \"ldap:///%s\")" % (target_to)
+
+ ACI_ALLOW = "(version 3.0; acl \"MODDN from staging to production\"; allow (moddn)"
+ ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
+ ACI_BODY = ACI_TARGET_FROM + ACI_TARGET_TO + ACI_ALLOW + ACI_SUBJECT
+ mod = [(mod_type, 'aci', ACI_BODY)]
+ topology.master1.modify_s(SUFFIX, mod)
+
+ _write_aci_staging(topology, mod_type=mod_type)
+
+
+def _moddn_aci_from_production_to_staging(topology, mod_type=None):
+ assert mod_type is not None
+
+ ACI_TARGET = "(target_from = \"ldap:///%s\") (target_to = \"ldap:///%s\")" % (
+ PRODUCTION_DN, STAGING_DN)
+ ACI_ALLOW = "(version 3.0; acl \"MODDN from production to staging\"; allow (moddn)"
+ ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
+ ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
+ mod = [(mod_type, 'aci', ACI_BODY)]
+ topology.master1.modify_s(SUFFIX, mod)
+
+ _write_aci_production(topology, mod_type=mod_type)
+
+
+(a)pytest.fixture(scope="module")
+def moddn_setup(topology):
+ """Creates
+ - a staging DIT
+ - a production DIT
+ - add accounts in staging DIT
+ - enable ACL logging (commented for performance reason)
+ """
+
+ topology.master1.log.info("\n\n######## INITIALIZATION ########\n")
+
+ # entry used to bind with
+ topology.master1.log.info("Add %s" % BIND_DN)
+ topology.master1.add_s(Entry((BIND_DN, {
+ 'objectclass': "top person".split(),
+ 'sn': BIND_CN,
+ 'cn': BIND_CN,
+ 'userpassword': BIND_PW})))
+
+ # DIT for staging
+ topology.master1.log.info("Add %s" % STAGING_DN)
+ topology.master1.add_s(Entry((STAGING_DN, {
+ 'objectclass': "top organizationalRole".split(),
+ 'cn': STAGING_CN,
+ 'description': "staging DIT"})))
+
+ # DIT for production
+ topology.master1.log.info("Add %s" % PRODUCTION_DN)
+ topology.master1.add_s(Entry((PRODUCTION_DN, {
+ 'objectclass': "top organizationalRole".split(),
+ 'cn': PRODUCTION_CN,
+ 'description': "production DIT"})))
+
+ # DIT for production/except
+ topology.master1.log.info("Add %s" % PROD_EXCEPT_DN)
+ topology.master1.add_s(Entry((PROD_EXCEPT_DN, {
+ 'objectclass': "top organizationalRole".split(),
+ 'cn': EXCEPT_CN,
+ 'description': "production except DIT"})))
+
+ # enable acl error logging
+ #mod = [(ldap.MOD_REPLACE, 'nsslapd-errorlog-level', '128')]
+ #topology.master1.modify_s(DN_CONFIG, mod)
+ #topology.master2.modify_s(DN_CONFIG, mod)
+
+ # add dummy entries in the staging DIT
+ for cpt in range(MAX_ACCOUNTS):
+ name = "%s%d" % (NEW_ACCOUNT, cpt)
+ topology.master1.add_s(Entry(("cn=%s,%s" % (name, STAGING_DN), {
+ 'objectclass': "top person".split(),
+ 'sn': name,
+ 'cn': name})))
+
+
+def test_mode_default_add_deny(topology, moddn_setup):
+ """This test case checks
+ that the ADD operation fails (no ADD aci on production)
+ """
+
+ topology.master1.log.info("\n\n######## mode moddn_aci : ADD (should fail) ########\n")
+
+ _bind_normal(topology)
+
+ #
+ # First try to add an entry in production => INSUFFICIENT_ACCESS
+ #
+ try:
+ topology.master1.log.info("Try to add %s" % PRODUCTION_DN)
+ name = "%s%d" % (NEW_ACCOUNT, 0)
+ topology.master1.add_s(Entry(("cn=%s,%s" % (name, PRODUCTION_DN), {
+ 'objectclass': "top person".split(),
+ 'sn': name,
+ 'cn': name})))
+ assert 0 # this is an error, we should not be allowed to add an entry in production
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+
+def test_mode_default_delete_deny(topology, moddn_setup):
+ """This test case checks
+ that the DEL operation fails (no 'delete' aci on production)
+ """
+
+ topology.master1.log.info("\n\n######## DELETE (should fail) ########\n")
+
+ _bind_normal(topology)
+ #
+ # Second try to delete an entry in staging => INSUFFICIENT_ACCESS
+ #
+ try:
+ topology.master1.log.info("Try to delete %s" % STAGING_DN)
+ name = "%s%d" % (NEW_ACCOUNT, 0)
+ topology.master1.delete_s("cn=%s,%s" % (name, STAGING_DN))
+ assert 0 # this is an error, we should not be allowed to add an entry in production
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+
+(a)pytest.mark.parametrize("index,tfrom,tto,failure",
+ [(0, STAGING_DN, PRODUCTION_DN, False),
+ (1, STAGING_DN, PRODUCTION_DN, False),
+ (2, STAGING_DN, BAD_PRODUCTION_PATTERN, True),
+ (3, STAGING_PATTERN, PRODUCTION_DN, False),
+ (4, BAD_STAGING_PATTERN, PRODUCTION_DN, True),
+ (5, STAGING_PATTERN, PRODUCTION_PATTERN, False),
+ (6, None, PRODUCTION_PATTERN, False),
+ (7, STAGING_PATTERN, None, False),
+ (8, None, None, False)])
+def test_moddn_staging_prod(topology, moddn_setup,
+ index, tfrom, tto, failure):
+ """This test case MOVE entry NEW_ACCOUNT0 from staging to prod
+ target_to/target_from: equality filter
+ """
+
+ topology.master1.log.info("\n\n######## MOVE staging -> Prod (%s) ########\n" % index)
+ _bind_normal(topology)
+
+ old_rdn = "cn=%s%s" % (NEW_ACCOUNT, index)
+ old_dn = "%s,%s" % (old_rdn, STAGING_DN)
+ new_rdn = old_rdn
+ new_superior = PRODUCTION_DN
+
+ #
+ # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
+ #
+ try:
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+ assert 0
+ except AssertionError:
+ topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+
+ # successfull MOD with the ACI
+ topology.master1.log.info("\n\n######## MOVE to and from equality filter ########\n")
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD,
+ target_from=tfrom, target_to=tto)
+ _bind_normal(topology)
+
+ try:
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ if failure:
+ assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+ # successfull MOD with the both ACI
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE,
+ target_from=tfrom, target_to=tto)
+ _bind_normal(topology)
+
+
+def test_moddn_staging_prod_9(topology, moddn_setup):
+ """This test case disable the 'moddn' right so a MODDN requires a 'add' right
+ to be successfull.
+ It fails to MOVE entry NEW_ACCOUNT9 from staging to prod.
+ Add a 'add' right to prod.
+ Then it succeeds to MOVE NEW_ACCOUNT9 from staging to prod.
+
+ Then enable the 'moddn' right so a MODDN requires a 'moddn' right
+ It fails to MOVE entry NEW_ACCOUNT10 from staging to prod.
+ Add a 'moddn' right to prod.
+ Then it succeeds to MOVE NEW_ACCOUNT10 from staging to prod.
+ """
+
+ topology.master1.log.info("\n\n######## MOVE staging -> Prod (9) ########\n")
+
+ _bind_normal(topology)
+ old_rdn = "cn=%s9" % NEW_ACCOUNT
+ old_dn = "%s,%s" % (old_rdn, STAGING_DN)
+ new_rdn = old_rdn
+ new_superior = PRODUCTION_DN
+
+ #
+ # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
+ #
+ try:
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+ assert 0
+ except AssertionError:
+ topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+ #############
+ # Now do tests with no support of moddn aci
+ #############
+ topology.master1.log.info("Disable the moddn right")
+ _bind_manager(topology)
+ mod = [(ldap.MOD_REPLACE, CONFIG_MODDN_ACI_ATTR, 'off')]
+ topology.master1.modify_s(DN_CONFIG, mod)
+
+ # Add the moddn aci that will not be evaluated because of the config flag
+ topology.master1.log.info("\n\n######## MOVE to and from equality filter ########\n")
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN)
+ _bind_normal(topology)
+
+ # It will fail because it will test the ADD right
+ try:
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+ assert 0
+ except AssertionError:
+ topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+ # remove the moddn aci
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN)
+ _bind_normal(topology)
+
+ #
+ # add the 'add' right to the production DN
+ # Then do a successfull moddn
+ #
+ ACI_ALLOW = "(version 3.0; acl \"ADD rights to allow moddn\"; allow (add)"
+ ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
+ ACI_BODY = ACI_ALLOW + ACI_SUBJECT
+
+ _bind_manager(topology)
+ mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
+ topology.master1.modify_s(PRODUCTION_DN, mod)
+ _write_aci_staging(topology, mod_type=ldap.MOD_ADD)
+ _bind_normal(topology)
+
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+
+ _bind_manager(topology)
+ mod = [(ldap.MOD_DELETE, 'aci', ACI_BODY)]
+ topology.master1.modify_s(PRODUCTION_DN, mod)
+ _write_aci_staging(topology, mod_type=ldap.MOD_DELETE)
+ _bind_normal(topology)
+
+ #############
+ # Now do tests with support of moddn aci
+ #############
+ topology.master1.log.info("Enable the moddn right")
+ _bind_manager(topology)
+ mod = [(ldap.MOD_REPLACE, CONFIG_MODDN_ACI_ATTR, 'on')]
+ topology.master1.modify_s(DN_CONFIG, mod)
+
+ topology.master1.log.info("\n\n######## MOVE staging -> Prod (10) ########\n")
+
+ _bind_normal(topology)
+ old_rdn = "cn=%s10" % NEW_ACCOUNT
+ old_dn = "%s,%s" % (old_rdn, STAGING_DN)
+ new_rdn = old_rdn
+ new_superior = PRODUCTION_DN
+
+ #
+ # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
+ #
+ try:
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+ assert 0
+ except AssertionError:
+ topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+ #
+ # add the 'add' right to the production DN
+ # Then do a failing moddn
+ #
+ ACI_ALLOW = "(version 3.0; acl \"ADD rights to allow moddn\"; allow (add)"
+ ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
+ ACI_BODY = ACI_ALLOW + ACI_SUBJECT
+
+ _bind_manager(topology)
+ mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
+ topology.master1.modify_s(PRODUCTION_DN, mod)
+ _write_aci_staging(topology, mod_type=ldap.MOD_ADD)
+ _bind_normal(topology)
+
+ try:
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+ assert 0
+ except AssertionError:
+ topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+ _bind_manager(topology)
+ mod = [(ldap.MOD_DELETE, 'aci', ACI_BODY)]
+ topology.master1.modify_s(PRODUCTION_DN, mod)
+ _write_aci_staging(topology, mod_type=ldap.MOD_DELETE)
+ _bind_normal(topology)
+
+ # Add the moddn aci that will be evaluated because of the config flag
+ topology.master1.log.info("\n\n######## MOVE to and from equality filter ########\n")
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN)
+ _bind_normal(topology)
+
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+
+ # remove the moddn aci
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN)
+ _bind_normal(topology)
+
+
+def test_moddn_prod_staging(topology, moddn_setup):
+ """This test checks that we can move ACCOUNT11 from staging to prod
+ but not move back ACCOUNT11 from prod to staging
+ """
+
+ topology.master1.log.info("\n\n######## MOVE staging -> Prod (11) ########\n")
+
+ _bind_normal(topology)
+
+ old_rdn = "cn=%s11" % NEW_ACCOUNT
+ old_dn = "%s,%s" % (old_rdn, STAGING_DN)
+ new_rdn = old_rdn
+ new_superior = PRODUCTION_DN
+
+ #
+ # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
+ #
+ try:
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+ assert 0
+ except AssertionError:
+ topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+ # successfull MOD with the ACI
+ topology.master1.log.info("\n\n######## MOVE to and from equality filter ########\n")
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN)
+ _bind_normal(topology)
+
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+
+ # Now check we can not move back the entry to staging
+ old_rdn = "cn=%s11" % NEW_ACCOUNT
+ old_dn = "%s,%s" % (old_rdn, PRODUCTION_DN)
+ new_rdn = old_rdn
+ new_superior = STAGING_DN
+
+ # add the write right because we want to check the moddn
+ _bind_manager(topology)
+ _write_aci_production(topology, mod_type=ldap.MOD_ADD)
+ _bind_normal(topology)
+
+ try:
+ topology.master1.log.info("Try to move back MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+ assert 0
+ except AssertionError:
+ topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+ _bind_manager(topology)
+ _write_aci_production(topology, mod_type=ldap.MOD_DELETE)
+ _bind_normal(topology)
+
+ # successfull MOD with the both ACI
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN)
+ _bind_normal(topology)
+
+
+def test_check_repl_M2_to_M1(topology, moddn_setup):
+ """Checks that replication is still working M2->M1, using ACCOUNT12"""
+
+ topology.master1.log.info("Bind as %s (M2)" % DN_DM)
+ topology.master2.simple_bind_s(DN_DM, PASSWORD)
+
+ rdn = "cn=%s12" % NEW_ACCOUNT
+ dn = "%s,%s" % (rdn, STAGING_DN)
+
+ # First wait for the ACCOUNT19 entry being replicated on M2
+ loop = 0
+ while loop <= 10:
+ try:
+ ent = topology.master2.getEntry(dn, ldap.SCOPE_BASE, "(objectclass=*)")
+ break
+ except ldap.NO_SUCH_OBJECT:
+ time.sleep(1)
+ loop += 1
+ assert loop <= 10
+
+ attribute = 'description'
+ tested_value = 'Hello world'
+ mod = [(ldap.MOD_ADD, attribute, tested_value)]
+ topology.master1.log.info("Update (M2) %s (%s)" % (dn, attribute))
+ topology.master2.modify_s(dn, mod)
+
+ loop = 0
+ while loop <= 10:
+ ent = topology.master1.getEntry(dn, ldap.SCOPE_BASE, "(objectclass=*)")
+ assert ent is not None
+ if ent.hasAttr(attribute) and (ent.getValue(attribute) == tested_value):
+ break
+
+ time.sleep(1)
+ loop += 1
+ assert loop < 10
+ topology.master1.log.info("Update %s (%s) replicated on M1" % (dn, attribute))
+
+
+def test_moddn_staging_prod_except(topology, moddn_setup):
+ """This test case MOVE entry NEW_ACCOUNT13 from staging to prod
+ but fails to move entry NEW_ACCOUNT14 from staging to prod_except
+ """
+
+ topology.master1.log.info("\n\n######## MOVE staging -> Prod (13) ########\n")
+ _bind_normal(topology)
+
+ old_rdn = "cn=%s13" % NEW_ACCOUNT
+ old_dn = "%s,%s" % (old_rdn, STAGING_DN)
+ new_rdn = old_rdn
+ new_superior = PRODUCTION_DN
+
+ #
+ # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
+ #
+ try:
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+ assert 0
+ except AssertionError:
+ topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+ # successfull MOD with the ACI
+ topology.master1.log.info("\n\n######## MOVE to and from equality filter ########\n")
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN)
+ _moddn_aci_deny_tree(topology, mod_type=ldap.MOD_ADD)
+ _bind_normal(topology)
+
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+
+ #
+ # Now try to move an entry under except
+ #
+ topology.master1.log.info("\n\n######## MOVE staging -> Prod/Except (14) ########\n")
+ old_rdn = "cn=%s14" % NEW_ACCOUNT
+ old_dn = "%s,%s" % (old_rdn, STAGING_DN)
+ new_rdn = old_rdn
+ new_superior = PROD_EXCEPT_DN
+ try:
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+ assert 0
+ except AssertionError:
+ topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+ # successfull MOD with the both ACI
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN)
+ _moddn_aci_deny_tree(topology, mod_type=ldap.MOD_DELETE)
+ _bind_normal(topology)
+
+
+def test_mode_default_ger_no_moddn(topology, moddn_setup):
+ topology.master1.log.info("\n\n######## mode moddn_aci : GER no moddn ########\n")
+ request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn: " + BIND_DN)
+ msg_id = topology.master1.search_ext(PRODUCTION_DN,
+ ldap.SCOPE_SUBTREE,
+ "objectclass=*",
+ serverctrls=[request_ctrl])
+ rtype, rdata, rmsgid, response_ctrl = topology.master1.result3(msg_id)
+ #ger={}
+ value = ''
+ for dn, attrs in rdata:
+ topology.master1.log.info("dn: %s" % dn)
+ value = attrs['entryLevelRights'][0]
+
+ topology.master1.log.info("######## entryLevelRights: %r" % value)
+ assert 'n' not in value
+
+
+def test_mode_default_ger_with_moddn(topology, moddn_setup):
+ """This test case adds the moddn aci and check ger contains 'n'"""
+
+ topology.master1.log.info("\n\n######## mode moddn_aci: GER with moddn ########\n")
+
+ # successfull MOD with the ACI
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN)
+ _bind_normal(topology)
+
+ request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn: " + BIND_DN)
+ msg_id = topology.master1.search_ext(PRODUCTION_DN,
+ ldap.SCOPE_SUBTREE,
+ "objectclass=*",
+ serverctrls=[request_ctrl])
+ rtype, rdata, rmsgid, response_ctrl = topology.master1.result3(msg_id)
+ #ger={}
+ value = ''
+ for dn, attrs in rdata:
+ topology.master1.log.info("dn: %s" % dn)
+ value = attrs['entryLevelRights'][0]
+
+ topology.master1.log.info("######## entryLevelRights: %r" % value)
+ assert 'n' in value
+
+ # successfull MOD with the both ACI
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN)
+ _bind_normal(topology)
+
+
+def test_mode_switch_default_to_legacy(topology, moddn_setup):
+ """This test switch the server from default mode to legacy"""
+
+ topology.master1.log.info("\n\n######## Disable the moddn aci mod ########\n")
+ _bind_manager(topology)
+ mod = [(ldap.MOD_REPLACE, CONFIG_MODDN_ACI_ATTR, 'off')]
+ topology.master1.modify_s(DN_CONFIG, mod)
+
+
+def test_mode_legacy_ger_no_moddn1(topology, moddn_setup):
+ topology.master1.log.info("\n\n######## mode legacy 1: GER no moddn ########\n")
+ request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn: " + BIND_DN)
+ msg_id = topology.master1.search_ext(PRODUCTION_DN,
+ ldap.SCOPE_SUBTREE,
+ "objectclass=*",
+ serverctrls=[request_ctrl])
+ rtype, rdata, rmsgid, response_ctrl = topology.master1.result3(msg_id)
+ #ger={}
+ value = ''
+ for dn, attrs in rdata:
+ topology.master1.log.info("dn: %s" % dn)
+ value = attrs['entryLevelRights'][0]
+
+ topology.master1.log.info("######## entryLevelRights: %r" % value)
+ assert 'n' not in value
+
+
+def test_mode_legacy_ger_no_moddn2(topology, moddn_setup):
+ topology.master1.log.info("\n\n######## mode legacy 2: GER no moddn ########\n")
+ # successfull MOD with the ACI
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN)
+ _bind_normal(topology)
+
+ request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn: " + BIND_DN)
+ msg_id = topology.master1.search_ext(PRODUCTION_DN,
+ ldap.SCOPE_SUBTREE,
+ "objectclass=*",
+ serverctrls=[request_ctrl])
+ rtype, rdata, rmsgid, response_ctrl = topology.master1.result3(msg_id)
+ #ger={}
+ value = ''
+ for dn, attrs in rdata:
+ topology.master1.log.info("dn: %s" % dn)
+ value = attrs['entryLevelRights'][0]
+
+ topology.master1.log.info("######## entryLevelRights: %r" % value)
+ assert 'n' not in value
+
+ # successfull MOD with the both ACI
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN)
+ _bind_normal(topology)
+
+
+def test_mode_legacy_ger_with_moddn(topology, moddn_setup):
+ topology.master1.log.info("\n\n######## mode legacy : GER with moddn ########\n")
+
+ # being allowed to read/write the RDN attribute use to allow the RDN
+ ACI_TARGET = "(target = \"ldap:///%s\")(targetattr=\"cn\")" % (PRODUCTION_DN)
+ ACI_ALLOW = "(version 3.0; acl \"MODDN production changing the RDN attribute\"; allow (read,search,write)"
+ ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
+ ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
+
+ # successfull MOD with the ACI
+ _bind_manager(topology)
+ mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
+ topology.master1.modify_s(SUFFIX, mod)
+ _bind_normal(topology)
+
+ request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn: " + BIND_DN)
+ msg_id = topology.master1.search_ext(PRODUCTION_DN,
+ ldap.SCOPE_SUBTREE,
+ "objectclass=*",
+ serverctrls=[request_ctrl])
+ rtype, rdata, rmsgid, response_ctrl = topology.master1.result3(msg_id)
+ #ger={}
+ value = ''
+ for dn, attrs in rdata:
+ topology.master1.log.info("dn: %s" % dn)
+ value = attrs['entryLevelRights'][0]
+
+ topology.master1.log.info("######## entryLevelRights: %r" % value)
+ assert 'n' in value
+
+ # successfull MOD with the both ACI
+ _bind_manager(topology)
+ mod = [(ldap.MOD_DELETE, 'aci', ACI_BODY)]
+ topology.master1.modify_s(SUFFIX, mod)
+ #_bind_normal(topology)
+
+
+(a)pytest.fixture(scope="module")
+def rdn_write_setup(topology):
+ topology.master1.log.info("\n\n######## Add entry tuser ########\n")
+ topology.master1.add_s(Entry((SRC_ENTRY_DN, {
+ 'objectclass': "top person".split(),
+ 'sn': SRC_ENTRY_CN,
+ 'cn': SRC_ENTRY_CN})))
+
+
+def test_rdn_write_get_ger(topology, rdn_write_setup):
+ ANONYMOUS_DN = ""
+ topology.master1.log.info("\n\n######## GER rights for anonymous ########\n")
+ request_ctrl = GetEffectiveRightsControl(criticality=True,
+ authzId="dn:" + ANONYMOUS_DN)
+ msg_id = topology.master1.search_ext(SUFFIX,
+ ldap.SCOPE_SUBTREE,
+ "objectclass=*",
+ serverctrls=[request_ctrl])
+ rtype, rdata, rmsgid, response_ctrl = topology.master1.result3(msg_id)
+ value = ''
+ for dn, attrs in rdata:
+ topology.master1.log.info("dn: %s" % dn)
+ for value in attrs['entryLevelRights']:
+ topology.master1.log.info("######## entryLevelRights: %r" % value)
+ assert 'n' not in value
+
+
+def test_rdn_write_modrdn_anonymous(topology, rdn_write_setup):
+ ANONYMOUS_DN = ""
+ topology.master1.close()
+ topology.master1.binddn = ANONYMOUS_DN
+ topology.master1.open()
+ msg_id = topology.master1.search_ext("", ldap.SCOPE_BASE, "objectclass=*")
+ rtype, rdata, rmsgid, response_ctrl = topology.master1.result3(msg_id)
+ for dn, attrs in rdata:
+ topology.master1.log.info("dn: %s" % dn)
+ for attr in attrs:
+ topology.master1.log.info("######## %r: %r" % (attr, attrs[attr]))
+
+ try:
+ topology.master1.rename_s(SRC_ENTRY_DN, "cn=%s" % DST_ENTRY_CN, delold=True)
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+ try:
+ topology.master1.getEntry(DST_ENTRY_DN, ldap.SCOPE_BASE, "objectclass=*")
+ assert False
+ except Exception as e:
+ topology.master1.log.info("The entry was not renamed (expected)")
+ isinstance(e, ldap.NO_SUCH_OBJECT)
+
+ _bind_manager(topology)
+
+
if __name__ == '__main__':
# Run isolated
# -s for DEBUG mode
diff --git a/dirsrvtests/tickets/ticket47553_ger.py b/dirsrvtests/tickets/ticket47553_ger.py
deleted file mode 100644
index 1829b48..0000000
--- a/dirsrvtests/tickets/ticket47553_ger.py
+++ /dev/null
@@ -1,475 +0,0 @@
-# --- BEGIN COPYRIGHT BLOCK ---
-# Copyright (C) 2015 Red Hat, Inc.
-# All rights reserved.
-#
-# License: GPL (version 3 or any later version).
-# See LICENSE for details.
-# --- END COPYRIGHT BLOCK ---
-#
-'''
-Created on Nov 7, 2013
-
-@author: tbordaz
-'''
-import os
-import sys
-import time
-import ldap
-import logging
-import pytest
-from lib389 import DirSrv, Entry, tools
-from lib389.tools import DirSrvTools
-from lib389._constants import *
-from lib389.properties import *
-from ldap.controls.simple import GetEffectiveRightsControl
-
-logging.getLogger(__name__).setLevel(logging.DEBUG)
-log = logging.getLogger(__name__)
-
-#
-# important part. We can deploy Master1 and Master2 on different versions
-#
-installation1_prefix = None
-installation2_prefix = None
-
-TEST_REPL_DN = "cn=test_repl, %s" % SUFFIX
-
-STAGING_CN = "staged user"
-PRODUCTION_CN = "accounts"
-EXCEPT_CN = "excepts"
-
-STAGING_DN = "cn=%s,%s" % (STAGING_CN, SUFFIX)
-PRODUCTION_DN = "cn=%s,%s" % (PRODUCTION_CN, SUFFIX)
-PROD_EXCEPT_DN = "cn=%s,%s" % (EXCEPT_CN, PRODUCTION_DN)
-
-STAGING_PATTERN = "cn=%s*,%s" % (STAGING_CN[:2], SUFFIX)
-PRODUCTION_PATTERN = "cn=%s*,%s" % (PRODUCTION_CN[:2], SUFFIX)
-BAD_STAGING_PATTERN = "cn=bad*,%s" % (SUFFIX)
-BAD_PRODUCTION_PATTERN = "cn=bad*,%s" % (SUFFIX)
-
-BIND_CN = "bind_entry"
-BIND_DN = "cn=%s,%s" % (BIND_CN, SUFFIX)
-BIND_PW = "password"
-
-NEW_ACCOUNT = "new_account"
-MAX_ACCOUNTS = 20
-
-CONFIG_MODDN_ACI_ATTR = "nsslapd-moddn-aci"
-
-
-class TopologyMaster1Master2(object):
- def __init__(self, master1, master2):
- master1.open()
- self.master1 = master1
-
- master2.open()
- self.master2 = master2
-
-
-(a)pytest.fixture(scope="module")
-def topology(request):
- '''
- This fixture is used to create a replicated topology for the 'module'.
- The replicated topology is MASTER1 <-> Master2.
- '''
- global installation1_prefix
- global installation2_prefix
-
- # allocate master1 on a given deployement
- master1 = DirSrv(verbose=False)
- if installation1_prefix:
- args_instance[SER_DEPLOYED_DIR] = installation1_prefix
-
- # Args for the master1 instance
- args_instance[SER_HOST] = HOST_MASTER_1
- args_instance[SER_PORT] = PORT_MASTER_1
- args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_1
- args_master = args_instance.copy()
- master1.allocate(args_master)
-
- # allocate master1 on a given deployement
- master2 = DirSrv(verbose=False)
- if installation2_prefix:
- args_instance[SER_DEPLOYED_DIR] = installation2_prefix
-
- # Args for the consumer instance
- args_instance[SER_HOST] = HOST_MASTER_2
- args_instance[SER_PORT] = PORT_MASTER_2
- args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_2
- args_master = args_instance.copy()
- master2.allocate(args_master)
-
- # Get the status of the instance and restart it if it exists
- instance_master1 = master1.exists()
- instance_master2 = master2.exists()
-
- # Remove all the instances
- if instance_master1:
- master1.delete()
- if instance_master2:
- master2.delete()
-
- # Create the instances
- master1.create()
- master1.open()
- master2.create()
- master2.open()
-
- #
- # Now prepare the Master-Consumer topology
- #
- # First Enable replication
- master1.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER_1)
- master2.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER_2)
-
- # Initialize the supplier->consumer
-
- properties = {RA_NAME: r'meTo_$host:$port',
- RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
- RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
- RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
- RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
- repl_agreement = master1.agreement.create(suffix=SUFFIX, host=master2.host, port=master2.port, properties=properties)
-
- if not repl_agreement:
- log.fatal("Fail to create a replica agreement")
- sys.exit(1)
-
- log.debug("%s created" % repl_agreement)
-
- properties = {RA_NAME: r'meTo_$host:$port',
- RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
- RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
- RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
- RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
- master2.agreement.create(suffix=SUFFIX, host=master1.host, port=master1.port, properties=properties)
-
- master1.agreement.init(SUFFIX, HOST_MASTER_2, PORT_MASTER_2)
- master1.waitForReplInit(repl_agreement)
-
- # Check replication is working fine
- if master1.testReplication(DEFAULT_SUFFIX, master2):
- log.info('Replication is working.')
- else:
- log.fatal('Replication is not working.')
- assert False
-
- # clear the tmp directory
- master1.clearTmpDir(__file__)
-
- # Here we have two instances master and consumer
- # with replication working.
- return TopologyMaster1Master2(master1, master2)
-
-
-def _bind_manager(topology):
- topology.master1.log.info("Bind as %s " % DN_DM)
- topology.master1.simple_bind_s(DN_DM, PASSWORD)
-
-
-def _bind_normal(topology):
- # bind as bind_entry
- topology.master1.log.info("Bind as %s" % BIND_DN)
- topology.master1.simple_bind_s(BIND_DN, BIND_PW)
-
-
-def _moddn_aci_deny_tree(topology, mod_type=None, target_from=STAGING_DN, target_to=PROD_EXCEPT_DN):
- '''
- It denies the access moddn_to in cn=except,cn=accounts,SUFFIX
- '''
- if mod_type is None:
- assert False
-
- ACI_TARGET_FROM = ""
- ACI_TARGET_TO = ""
- if target_from:
- ACI_TARGET_FROM = "(target_from = \"ldap:///%s\")" % (target_from)
- if target_to:
- ACI_TARGET_TO = "(target_to = \"ldap:///%s\")" % (target_to)
-
- ACI_ALLOW = "(version 3.0; acl \"Deny MODDN to prod_except\"; deny (moddn)"
- ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
- ACI_BODY = ACI_TARGET_TO + ACI_TARGET_FROM + ACI_ALLOW + ACI_SUBJECT
- mod = [(mod_type, 'aci', ACI_BODY)]
- #topology.master1.modify_s(SUFFIX, mod)
- topology.master1.log.info("Add a DENY aci under %s " % PROD_EXCEPT_DN)
- topology.master1.modify_s(PROD_EXCEPT_DN, mod)
-
-
-def _moddn_aci_staging_to_production(topology, mod_type=None, target_from=STAGING_DN, target_to=PRODUCTION_DN):
- if mod_type is None:
- assert False
-
- ACI_TARGET_FROM = ""
- ACI_TARGET_TO = ""
- if target_from:
- ACI_TARGET_FROM = "(target_from = \"ldap:///%s\")" % (target_from)
- if target_to:
- ACI_TARGET_TO = "(target_to = \"ldap:///%s\")" % (target_to)
-
- ACI_ALLOW = "(version 3.0; acl \"MODDN from staging to production\"; allow (moddn)"
- ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
- ACI_BODY = ACI_TARGET_FROM + ACI_TARGET_TO + ACI_ALLOW + ACI_SUBJECT
- mod = [(mod_type, 'aci', ACI_BODY)]
- topology.master1.modify_s(SUFFIX, mod)
-
-
-def _moddn_aci_from_production_to_staging(topology, mod_type=None):
- if mod_type is None:
- assert False
-
- ACI_TARGET = "(target_from = \"ldap:///%s\") (target_to = \"ldap:///%s\")" % (PRODUCTION_DN, STAGING_DN)
- ACI_ALLOW = "(version 3.0; acl \"MODDN from production to staging\"; allow (moddn)"
- ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
- ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
- mod = [(mod_type, 'aci', ACI_BODY)]
- topology.master1.modify_s(SUFFIX, mod)
-
-
-def test_ticket47553_init(topology):
- """
- Creates
- - a staging DIT
- - a production DIT
- - add accounts in staging DIT
- - enable ACL logging (commented for performance reason)
-
- """
-
- topology.master1.log.info("\n\n######################### INITIALIZATION ######################\n")
-
- # entry used to bind with
- topology.master1.log.info("Add %s" % BIND_DN)
- topology.master1.add_s(Entry((BIND_DN, {
- 'objectclass': "top person".split(),
- 'sn': BIND_CN,
- 'cn': BIND_CN,
- 'userpassword': BIND_PW})))
-
- # DIT for staging
- topology.master1.log.info("Add %s" % STAGING_DN)
- topology.master1.add_s(Entry((STAGING_DN, {
- 'objectclass': "top organizationalRole".split(),
- 'cn': STAGING_CN,
- 'description': "staging DIT"})))
-
- # DIT for production
- topology.master1.log.info("Add %s" % PRODUCTION_DN)
- topology.master1.add_s(Entry((PRODUCTION_DN, {
- 'objectclass': "top organizationalRole".split(),
- 'cn': PRODUCTION_CN,
- 'description': "production DIT"})))
-
- # DIT for production/except
- topology.master1.log.info("Add %s" % PROD_EXCEPT_DN)
- topology.master1.add_s(Entry((PROD_EXCEPT_DN, {
- 'objectclass': "top organizationalRole".split(),
- 'cn': EXCEPT_CN,
- 'description': "production except DIT"})))
-
- # enable acl error logging
- #mod = [(ldap.MOD_REPLACE, 'nsslapd-errorlog-level', '128')]
- #topology.master1.modify_s(DN_CONFIG, mod)
- #topology.master2.modify_s(DN_CONFIG, mod)
-
- # add dummy entries in the staging DIT
- for cpt in range(MAX_ACCOUNTS):
- name = "%s%d" % (NEW_ACCOUNT, cpt)
- topology.master1.add_s(Entry(("cn=%s,%s" % (name, STAGING_DN), {
- 'objectclass': "top person".split(),
- 'sn': name,
- 'cn': name})))
-
-
-def test_ticket47553_mode_default_add_deny(topology):
- '''
- This test case checks that the ADD operation fails (no ADD aci on production)
- '''
-
- topology.master1.log.info("\n\n######################### mode moddn_aci : ADD (should fail) ######################\n")
-
- _bind_normal(topology)
-
- #
- # First try to add an entry in production => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to add %s" % PRODUCTION_DN)
- name = "%s%d" % (NEW_ACCOUNT, 0)
- topology.master1.add_s(Entry(("cn=%s,%s" % (name, PRODUCTION_DN), {
- 'objectclass': "top person".split(),
- 'sn': name,
- 'cn': name})))
- assert 0 # this is an error, we should not be allowed to add an entry in production
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
-
-def test_ticket47553_mode_default_ger_no_moddn(topology):
- topology.master1.log.info("\n\n######################### mode moddn_aci : GER no moddn ######################\n")
- request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn: " + BIND_DN)
- msg_id = topology.master1.search_ext(PRODUCTION_DN, ldap.SCOPE_SUBTREE, "objectclass=*", serverctrls=[request_ctrl])
- rtype, rdata, rmsgid, response_ctrl = topology.master1.result3(msg_id)
- #ger={}
- value = ''
- for dn, attrs in rdata:
- topology.master1.log.info("dn: %s" % dn)
- value = attrs['entryLevelRights'][0]
-
- topology.master1.log.info("############### entryLevelRights: %r" % value)
- assert 'n' not in value
-
-
-def test_ticket47553_mode_default_ger_with_moddn(topology):
- '''
- This test case adds the moddn aci and check ger contains 'n'
- '''
-
- topology.master1.log.info("\n\n######################### mode moddn_aci: GER with moddn ######################\n")
-
- # successfull MOD with the ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
- request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn: " + BIND_DN)
- msg_id = topology.master1.search_ext(PRODUCTION_DN, ldap.SCOPE_SUBTREE, "objectclass=*", serverctrls=[request_ctrl])
- rtype, rdata, rmsgid, response_ctrl = topology.master1.result3(msg_id)
- #ger={}
- value = ''
- for dn, attrs in rdata:
- topology.master1.log.info("dn: %s" % dn)
- value = attrs['entryLevelRights'][0]
-
- topology.master1.log.info("############### entryLevelRights: %r" % value)
- assert 'n' in value
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
-
-def test_ticket47553_mode_switch_default_to_legacy(topology):
- '''
- This test switch the server from default mode to legacy
- '''
- topology.master1.log.info("\n\n######################### Disable the moddn aci mod ######################\n")
- _bind_manager(topology)
- mod = [(ldap.MOD_REPLACE, CONFIG_MODDN_ACI_ATTR, 'off')]
- topology.master1.modify_s(DN_CONFIG, mod)
-
-
-def test_ticket47553_mode_legacy_ger_no_moddn1(topology):
- topology.master1.log.info("\n\n######################### mode legacy 1: GER no moddn ######################\n")
- request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn: " + BIND_DN)
- msg_id = topology.master1.search_ext(PRODUCTION_DN, ldap.SCOPE_SUBTREE, "objectclass=*", serverctrls=[request_ctrl])
- rtype, rdata, rmsgid, response_ctrl = topology.master1.result3(msg_id)
- #ger={}
- value = ''
- for dn, attrs in rdata:
- topology.master1.log.info("dn: %s" % dn)
- value = attrs['entryLevelRights'][0]
-
- topology.master1.log.info("############### entryLevelRights: %r" % value)
- assert 'n' not in value
-
-
-def test_ticket47553_mode_legacy_ger_no_moddn2(topology):
- topology.master1.log.info("\n\n######################### mode legacy 2: GER no moddn ######################\n")
- # successfull MOD with the ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
- request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn: " + BIND_DN)
- msg_id = topology.master1.search_ext(PRODUCTION_DN, ldap.SCOPE_SUBTREE, "objectclass=*", serverctrls=[request_ctrl])
- rtype, rdata, rmsgid, response_ctrl = topology.master1.result3(msg_id)
- #ger={}
- value = ''
- for dn, attrs in rdata:
- topology.master1.log.info("dn: %s" % dn)
- value = attrs['entryLevelRights'][0]
-
- topology.master1.log.info("############### entryLevelRights: %r" % value)
- assert 'n' not in value
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
-
-def test_ticket47553_mode_legacy_ger_with_moddn(topology):
- topology.master1.log.info("\n\n######################### mode legacy : GER with moddn ######################\n")
-
- # being allowed to read/write the RDN attribute use to allow the RDN
- ACI_TARGET = "(target = \"ldap:///%s\")(targetattr=\"cn\")" % (PRODUCTION_DN)
- ACI_ALLOW = "(version 3.0; acl \"MODDN production changing the RDN attribute\"; allow (read,search,write)"
- ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
- ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
-
- # successfull MOD with the ACI
- _bind_manager(topology)
- mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
- topology.master1.modify_s(SUFFIX, mod)
- _bind_normal(topology)
-
- request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn: " + BIND_DN)
- msg_id = topology.master1.search_ext(PRODUCTION_DN, ldap.SCOPE_SUBTREE, "objectclass=*", serverctrls=[request_ctrl])
- rtype, rdata, rmsgid, response_ctrl = topology.master1.result3(msg_id)
- #ger={}
- value = ''
- for dn, attrs in rdata:
- topology.master1.log.info("dn: %s" % dn)
- value = attrs['entryLevelRights'][0]
-
- topology.master1.log.info("############### entryLevelRights: %r" % value)
- assert 'n' in value
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- mod = [(ldap.MOD_DELETE, 'aci', ACI_BODY)]
- topology.master1.modify_s(SUFFIX, mod)
- _bind_normal(topology)
-
-
-def test_ticket47553_final(topology):
- topology.master1.delete()
- topology.master2.delete()
- log.info('Testcase PASSED')
-
-
-def run_isolated():
- '''
- run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
- To run isolated without py.test, you need to
- - edit this file and comment '@pytest.fixture' line before 'topology' function.
- - set the installation prefix
- - run this program
- '''
- global installation1_prefix
- global installation2_prefix
- installation1_prefix = None
- installation2_prefix = None
-
- topo = topology(True)
- topo.master1.log.info("\n\n######################### Ticket 47553 ######################\n")
- test_ticket47553_init(topo)
-
- # Check that without appropriate aci we are not allowed to add/delete
- test_ticket47553_mode_default_add_deny(topo)
- test_ticket47553_mode_default_ger_no_moddn(topo)
- test_ticket47553_mode_default_ger_with_moddn(topo)
- test_ticket47553_mode_switch_default_to_legacy(topo)
- test_ticket47553_mode_legacy_ger_no_moddn1(topo)
- test_ticket47553_mode_legacy_ger_no_moddn2(topo)
- test_ticket47553_mode_legacy_ger_with_moddn(topo)
-
- test_ticket47553_final(topo)
-
-
-if __name__ == '__main__':
- run_isolated()
-
diff --git a/dirsrvtests/tickets/ticket47553_rdn_write_test.py b/dirsrvtests/tickets/ticket47553_rdn_write_test.py
deleted file mode 100644
index 15d334b..0000000
--- a/dirsrvtests/tickets/ticket47553_rdn_write_test.py
+++ /dev/null
@@ -1,143 +0,0 @@
-# --- BEGIN COPYRIGHT BLOCK ---
-# Copyright (C) 2015 Red Hat, Inc.
-# All rights reserved.
-#
-# License: GPL (version 3 or any later version).
-# See LICENSE for details.
-# --- END COPYRIGHT BLOCK ---
-#
-import os
-import sys
-import time
-import ldap
-import logging
-import pytest
-from lib389 import DirSrv, Entry, tools, tasks
-from lib389.tools import DirSrvTools
-from lib389._constants import *
-from lib389.properties import *
-from lib389.tasks import *
-from lib389.utils import *
-from ldap.controls.simple import GetEffectiveRightsControl
-
-logging.getLogger(__name__).setLevel(logging.DEBUG)
-log = logging.getLogger(__name__)
-
-installation1_prefix = None
-
-SRC_ENTRY_CN = "tuser"
-EXT_RDN = "01"
-DST_ENTRY_CN = SRC_ENTRY_CN + EXT_RDN
-
-SRC_ENTRY_DN = "cn=%s,%s" % (SRC_ENTRY_CN, SUFFIX)
-DST_ENTRY_DN = "cn=%s,%s" % (DST_ENTRY_CN, SUFFIX)
-
-
-class TopologyStandalone(object):
- def __init__(self, standalone):
- standalone.open()
- self.standalone = standalone
-
-
-(a)pytest.fixture(scope="module")
-def topology(request):
- global installation1_prefix
-
- # Creating standalone instance ...
- standalone = DirSrv(verbose=False)
- if installation1_prefix:
- args_instance[SER_DEPLOYED_DIR] = installation1_prefix
- args_instance[SER_HOST] = HOST_STANDALONE
- args_instance[SER_PORT] = PORT_STANDALONE
- args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
- args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX
- args_standalone = args_instance.copy()
- standalone.allocate(args_standalone)
- instance_standalone = standalone.exists()
- if instance_standalone:
- standalone.delete()
- standalone.create()
- standalone.open()
-
- # Clear out the tmp dir
- standalone.clearTmpDir(__file__)
-
- return TopologyStandalone(standalone)
-
-
-def test_ticket47553_rdn_write_init(topology):
- topology.standalone.log.info("\n\n######################### Add entry tuser ######################\n")
- topology.standalone.add_s(Entry((SRC_ENTRY_DN, {
- 'objectclass': "top person".split(),
- 'sn': SRC_ENTRY_CN,
- 'cn': SRC_ENTRY_CN})))
-
-
-def test_ticket47553_rdn_write_get_ger(topology):
- ANONYMOUS_DN = ""
- topology.standalone.log.info("\n\n######################### GER rights for anonymous ######################\n")
- request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn:" + ANONYMOUS_DN)
- msg_id = topology.standalone.search_ext(SUFFIX, ldap.SCOPE_SUBTREE, "objectclass=*", serverctrls=[request_ctrl])
- rtype, rdata, rmsgid, response_ctrl = topology.standalone.result3(msg_id)
- value = ''
- for dn, attrs in rdata:
- topology.standalone.log.info("dn: %s" % dn)
- for value in attrs['entryLevelRights']:
- topology.standalone.log.info("############### entryLevelRights: %r" % value)
- assert 'n' not in value
-
-
-def test_ticket47553_rdn_write_modrdn_anonymous(topology):
- ANONYMOUS_DN = ""
- topology.standalone.close()
- topology.standalone.binddn = ANONYMOUS_DN
- topology.standalone.open()
- msg_id = topology.standalone.search_ext("", ldap.SCOPE_BASE, "objectclass=*")
- rtype, rdata, rmsgid, response_ctrl = topology.standalone.result3(msg_id)
- for dn, attrs in rdata:
- topology.standalone.log.info("dn: %s" % dn)
- for attr in attrs:
- topology.standalone.log.info("############### %r: %r" % (attr, attrs[attr]))
-
- try:
- topology.standalone.rename_s(SRC_ENTRY_DN, "cn=%s" % DST_ENTRY_CN, delold=True)
- except Exception as e:
- topology.standalone.log.info("Exception (expected): %s" % type(e).__name__)
- isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- try:
- topology.standalone.getEntry(DST_ENTRY_DN, ldap.SCOPE_BASE, "objectclass=*")
- assert False
- except Exception as e:
- topology.standalone.log.info("The entry was not renamed (expected)")
- isinstance(e, ldap.NO_SUCH_OBJECT)
-
-
-def test_ticket47553_rdn_write(topology):
- '''
- Write your testcase here...
- '''
-
- log.info('Test complete')
-
-
-def test_ticket47553_rdn_write_final(topology):
- topology.standalone.delete()
- log.info('Testcase PASSED')
-
-
-def run_isolated():
- global installation1_prefix
- installation1_prefix = '/home/tbordaz/install_master'
-
- topo = topology(True)
- test_ticket47553_rdn_write_init(topo)
- test_ticket47553_rdn_write_get_ger(topo)
- test_ticket47553_rdn_write(topo)
- test_ticket47553_rdn_write_modrdn_anonymous(topo)
- test_ticket47553_rdn_write_final(topo)
-
-
-if __name__ == '__main__':
- run_isolated()
-
diff --git a/dirsrvtests/tickets/ticket47553_single_aci_test.py b/dirsrvtests/tickets/ticket47553_single_aci_test.py
deleted file mode 100644
index 1c0b88b..0000000
--- a/dirsrvtests/tickets/ticket47553_single_aci_test.py
+++ /dev/null
@@ -1,1137 +0,0 @@
-# --- BEGIN COPYRIGHT BLOCK ---
-# Copyright (C) 2015 Red Hat, Inc.
-# All rights reserved.
-#
-# License: GPL (version 3 or any later version).
-# See LICENSE for details.
-# --- END COPYRIGHT BLOCK ---
-#
-'''
-Created on Nov 7, 2013
-
-@author: tbordaz
-'''
-import os
-import sys
-import time
-import ldap
-import logging
-import pytest
-from lib389 import DirSrv, Entry, tools
-from lib389.tools import DirSrvTools
-from lib389._constants import *
-from lib389.properties import *
-from lib389._constants import REPLICAROLE_MASTER
-
-logging.getLogger(__name__).setLevel(logging.DEBUG)
-log = logging.getLogger(__name__)
-
-#
-# important part. We can deploy Master1 and Master2 on different versions
-#
-installation1_prefix = None
-installation2_prefix = None
-
-TEST_REPL_DN = "cn=test_repl, %s" % SUFFIX
-
-STAGING_CN = "staged user"
-PRODUCTION_CN = "accounts"
-EXCEPT_CN = "excepts"
-
-STAGING_DN = "cn=%s,%s" % (STAGING_CN, SUFFIX)
-PRODUCTION_DN = "cn=%s,%s" % (PRODUCTION_CN, SUFFIX)
-PROD_EXCEPT_DN = "cn=%s,%s" % (EXCEPT_CN, PRODUCTION_DN)
-
-STAGING_PATTERN = "cn=%s*,%s" % (STAGING_CN[:2], SUFFIX)
-PRODUCTION_PATTERN = "cn=%s*,%s" % (PRODUCTION_CN[:2], SUFFIX)
-BAD_STAGING_PATTERN = "cn=bad*,%s" % (SUFFIX)
-BAD_PRODUCTION_PATTERN = "cn=bad*,%s" % (SUFFIX)
-
-BIND_CN = "bind_entry"
-BIND_DN = "cn=%s,%s" % (BIND_CN, SUFFIX)
-BIND_PW = "password"
-
-NEW_ACCOUNT = "new_account"
-MAX_ACCOUNTS = 20
-
-CONFIG_MODDN_ACI_ATTR = "nsslapd-moddn-aci"
-
-
-class TopologyMaster1Master2(object):
- def __init__(self, master1, master2):
- master1.open()
- self.master1 = master1
-
- master2.open()
- self.master2 = master2
-
-
-(a)pytest.fixture(scope="module")
-def topology(request):
- '''
- This fixture is used to create a replicated topology for the 'module'.
- The replicated topology is MASTER1 <-> Master2.
- '''
- global installation1_prefix
- global installation2_prefix
-
- # allocate master1 on a given deployement
- master1 = DirSrv(verbose=False)
- if installation1_prefix:
- args_instance[SER_DEPLOYED_DIR] = installation1_prefix
-
- # Args for the master1 instance
- args_instance[SER_HOST] = HOST_MASTER_1
- args_instance[SER_PORT] = PORT_MASTER_1
- args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_1
- args_master = args_instance.copy()
- master1.allocate(args_master)
-
- # allocate master1 on a given deployement
- master2 = DirSrv(verbose=False)
- if installation2_prefix:
- args_instance[SER_DEPLOYED_DIR] = installation2_prefix
-
- # Args for the consumer instance
- args_instance[SER_HOST] = HOST_MASTER_2
- args_instance[SER_PORT] = PORT_MASTER_2
- args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_2
- args_master = args_instance.copy()
- master2.allocate(args_master)
-
- # Get the status of the instance
- instance_master1 = master1.exists()
- instance_master2 = master2.exists()
-
- # Remove all the instances
- if instance_master1:
- master1.delete()
- if instance_master2:
- master2.delete()
-
- # Create the instances
- master1.create()
- master1.open()
- master2.create()
- master2.open()
-
- #
- # Now prepare the Master-Consumer topology
- #
- # First Enable replication
- master1.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER_1)
- master2.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER_2)
-
- # Initialize the supplier->consumer
-
- properties = {RA_NAME: r'meTo_$host:$port',
- RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
- RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
- RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
- RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
- repl_agreement = master1.agreement.create(suffix=SUFFIX, host=master2.host, port=master2.port, properties=properties)
-
- if not repl_agreement:
- log.fatal("Fail to create a replica agreement")
- sys.exit(1)
-
- log.debug("%s created" % repl_agreement)
-
- properties = {RA_NAME: r'meTo_$host:$port',
- RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
- RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
- RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
- RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
- master2.agreement.create(suffix=SUFFIX, host=master1.host, port=master1.port, properties=properties)
-
- master1.agreement.init(SUFFIX, HOST_MASTER_2, PORT_MASTER_2)
- master1.waitForReplInit(repl_agreement)
-
- # Check replication is working fine
- if master1.testReplication(DEFAULT_SUFFIX, master2):
- log.info('Replication is working.')
- else:
- log.fatal('Replication is not working.')
- assert False
-
- # clear the tmp directory
- master1.clearTmpDir(__file__)
-
- # Here we have two instances master and consumer
- # with replication working.
- return TopologyMaster1Master2(master1, master2)
-
-
-def _bind_manager(topology):
- topology.master1.log.info("Bind as %s " % DN_DM)
- topology.master1.simple_bind_s(DN_DM, PASSWORD)
-
-
-def _bind_normal(topology):
- # bind as bind_entry
- topology.master1.log.info("Bind as %s" % BIND_DN)
- topology.master1.simple_bind_s(BIND_DN, BIND_PW)
-
-
-def _moddn_aci_deny_tree(topology, mod_type=None, target_from=STAGING_DN, target_to=PROD_EXCEPT_DN):
- '''
- It denies the access moddn_to in cn=except,cn=accounts,SUFFIX
- '''
- assert mod_type is not None
-
- ACI_TARGET_FROM = ""
- ACI_TARGET_TO = ""
- if target_from:
- ACI_TARGET_FROM = "(target_from = \"ldap:///%s\")" % (target_from)
- if target_to:
- ACI_TARGET_TO = "(target_to = \"ldap:///%s\")" % (target_to)
-
- ACI_ALLOW = "(version 3.0; acl \"Deny MODDN to prod_except\"; deny (moddn)"
- ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
- ACI_BODY = ACI_TARGET_TO + ACI_TARGET_FROM + ACI_ALLOW + ACI_SUBJECT
- mod = [(mod_type, 'aci', ACI_BODY)]
- #topology.master1.modify_s(SUFFIX, mod)
- topology.master1.log.info("Add a DENY aci under %s " % PROD_EXCEPT_DN)
- topology.master1.modify_s(PROD_EXCEPT_DN, mod)
-
-def _write_aci_staging(topology, mod_type=None):
- assert mod_type is not None
-
- ACI_TARGET = "(targetattr= \"cn\")(target=\"ldap:///cn=*,%s\")" % STAGING_DN
- ACI_ALLOW = "(version 3.0; acl \"write staging entries\"; allow (write)"
- ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
- ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
- mod = [(mod_type, 'aci', ACI_BODY)]
- topology.master1.modify_s(SUFFIX, mod)
-
-def _write_aci_production(topology, mod_type=None):
- assert mod_type is not None
-
- ACI_TARGET = "(targetattr= \"cn\")(target=\"ldap:///cn=*,%s\")" % PRODUCTION_DN
- ACI_ALLOW = "(version 3.0; acl \"write production entries\"; allow (write)"
- ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
- ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
- mod = [(mod_type, 'aci', ACI_BODY)]
- topology.master1.modify_s(SUFFIX, mod)
-
-def _moddn_aci_staging_to_production(topology, mod_type=None, target_from=STAGING_DN, target_to=PRODUCTION_DN):
- assert mod_type != None
-
-def _moddn_aci_staging_to_production(topology, mod_type=None, target_from=STAGING_DN, target_to=PRODUCTION_DN):
- assert mod_type is not None
-
- ACI_TARGET_FROM = ""
- ACI_TARGET_TO = ""
- if target_from:
- ACI_TARGET_FROM = "(target_from = \"ldap:///%s\")" % (target_from)
- if target_to:
- ACI_TARGET_TO = "(target_to = \"ldap:///%s\")" % (target_to)
-
- ACI_ALLOW = "(version 3.0; acl \"MODDN from staging to production\"; allow (moddn)"
- ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
- ACI_BODY = ACI_TARGET_FROM + ACI_TARGET_TO + ACI_ALLOW + ACI_SUBJECT
- mod = [(mod_type, 'aci', ACI_BODY)]
- topology.master1.modify_s(SUFFIX, mod)
-
- _write_aci_staging(topology, mod_type=mod_type)
-
-
-def _moddn_aci_from_production_to_staging(topology, mod_type=None):
- assert mod_type is not None
-
- ACI_TARGET = "(target_from = \"ldap:///%s\") (target_to = \"ldap:///%s\")" % (PRODUCTION_DN, STAGING_DN)
- ACI_ALLOW = "(version 3.0; acl \"MODDN from production to staging\"; allow (moddn)"
- ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
- ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
- mod = [(mod_type, 'aci', ACI_BODY)]
- topology.master1.modify_s(SUFFIX, mod)
-
- _write_aci_production(topology, mod_type=mod_type)
-
-
-def test_ticket47553_init(topology):
- """
- Creates
- - a staging DIT
- - a production DIT
- - add accounts in staging DIT
- - enable ACL logging (commented for performance reason)
-
- """
-
- topology.master1.log.info("\n\n######################### INITIALIZATION ######################\n")
-
- # entry used to bind with
- topology.master1.log.info("Add %s" % BIND_DN)
- topology.master1.add_s(Entry((BIND_DN, {
- 'objectclass': "top person".split(),
- 'sn': BIND_CN,
- 'cn': BIND_CN,
- 'userpassword': BIND_PW})))
-
- # DIT for staging
- topology.master1.log.info("Add %s" % STAGING_DN)
- topology.master1.add_s(Entry((STAGING_DN, {
- 'objectclass': "top organizationalRole".split(),
- 'cn': STAGING_CN,
- 'description': "staging DIT"})))
-
- # DIT for production
- topology.master1.log.info("Add %s" % PRODUCTION_DN)
- topology.master1.add_s(Entry((PRODUCTION_DN, {
- 'objectclass': "top organizationalRole".split(),
- 'cn': PRODUCTION_CN,
- 'description': "production DIT"})))
-
- # DIT for production/except
- topology.master1.log.info("Add %s" % PROD_EXCEPT_DN)
- topology.master1.add_s(Entry((PROD_EXCEPT_DN, {
- 'objectclass': "top organizationalRole".split(),
- 'cn': EXCEPT_CN,
- 'description': "production except DIT"})))
-
- # enable acl error logging
- mod = [(ldap.MOD_REPLACE, 'nsslapd-errorlog-level', str(128+262144))]
- topology.master1.modify_s(DN_CONFIG, mod)
- topology.master2.modify_s(DN_CONFIG, mod)
-
- # add dummy entries in the staging DIT
- for cpt in range(MAX_ACCOUNTS):
- name = "%s%d" % (NEW_ACCOUNT, cpt)
- topology.master1.add_s(Entry(("cn=%s,%s" % (name, STAGING_DN), {
- 'objectclass': "top person".split(),
- 'sn': name,
- 'cn': name})))
-
-
-def test_ticket47553_add(topology):
- '''
- This test case checks that the ADD operation fails (no ADD aci on production)
- '''
-
- topology.master1.log.info("\n\n######################### ADD (should fail) ######################\n")
-
- _bind_normal(topology)
-
- #
- # First try to add an entry in production => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to add %s" % PRODUCTION_DN)
- name = "%s%d" % (NEW_ACCOUNT, 0)
- topology.master1.add_s(Entry(("cn=%s,%s" % (name, PRODUCTION_DN), {
- 'objectclass': "top person".split(),
- 'sn': name,
- 'cn': name})))
- assert 0 # this is an error, we should not be allowed to add an entry in production
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
-
-def test_ticket47553_delete(topology):
- '''
- This test case checks that the DEL operation fails (no 'delete' aci on production)
- '''
-
- topology.master1.log.info("\n\n######################### DELETE (should fail) ######################\n")
-
- _bind_normal(topology)
- #
- # Second try to delete an entry in staging => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to delete %s" % STAGING_DN)
- name = "%s%d" % (NEW_ACCOUNT, 0)
- topology.master1.delete_s("cn=%s,%s" % (name, STAGING_DN))
- assert 0 # this is an error, we should not be allowed to add an entry in production
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
-
-def test_ticket47553_moddn_staging_prod_0(topology):
- '''
- This test case MOVE entry NEW_ACCOUNT0 from staging to prod
- target_to/target_from: equality filter
- '''
-
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (0) ######################\n")
- _bind_normal(topology)
-
- old_rdn = "cn=%s0" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
-
- # successfull MOD with the ACI
- topology.master1.log.info("\n\n######################### MOVE to and from equality filter ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
-
-def test_ticket47553_moddn_staging_prod_1(topology):
- '''
- This test case MOVE entry NEW_ACCOUNT1 from staging to prod
- target_to/target_from: substring/equality filter
- '''
-
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (1) ######################\n")
- _bind_normal(topology)
-
- old_rdn = "cn=%s1" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
-
- # successfull MOD with the ACI
- topology.master1.log.info("\n\n######################### MOVE to substring/ from equality filter ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_DN, target_to=PRODUCTION_PATTERN)
- _bind_normal(topology)
-
-
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_DN, target_to=PRODUCTION_PATTERN)
- _bind_normal(topology)
-
-
-def test_ticket47553_moddn_staging_prod_2(topology):
- '''
- This test case fails to MOVE entry NEW_ACCOUNT2 from staging to prod
- because of bad pattern
- '''
-
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (2) ######################\n")
- _bind_normal(topology)
-
- old_rdn = "cn=%s2" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
-
- # successfull MOD with the ACI
- topology.master1.log.info("\n\n######################### MOVE to substring (BAD)/ from equality filter ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_DN, target_to=BAD_PRODUCTION_PATTERN)
- _bind_normal(topology)
-
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_DN, target_to=BAD_PRODUCTION_PATTERN)
- _bind_normal(topology)
-
-
-def test_ticket47553_moddn_staging_prod_3(topology):
- '''
- This test case MOVE entry NEW_ACCOUNT3 from staging to prod
- target_to/target_from: equality/substring filter
- '''
-
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (3) ######################\n")
- _bind_normal(topology)
-
- old_rdn = "cn=%s3" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
-
- # successfull MOD with the ACI
- topology.master1.log.info("\n\n######################### MOVE to:equality filter / from substring filter ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_PATTERN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_PATTERN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
-
-def test_ticket47553_moddn_staging_prod_4(topology):
- '''
- This test case fails to MOVE entry NEW_ACCOUNT4 from staging to prod
- because of bad pattern
- '''
-
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (4) ######################\n")
- _bind_normal(topology)
-
- old_rdn = "cn=%s4" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- # successfull MOD with the ACI
- topology.master1.log.info("\n\n######################### MOVE to: equality filter/ from: substring (BAD) ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=BAD_STAGING_PATTERN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=BAD_STAGING_PATTERN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
-
-def test_ticket47553_moddn_staging_prod_5(topology):
- '''
- This test case MOVE entry NEW_ACCOUNT5 from staging to prod
- target_to/target_from: substring/substring filter
- '''
-
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (5) ######################\n")
- _bind_normal(topology)
-
- old_rdn = "cn=%s5" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- # successfull MOD with the ACI
- topology.master1.log.info("\n\n######################### MOVE to:substring filter / from: substring filter ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_PATTERN, target_to=PRODUCTION_PATTERN)
- _bind_normal(topology)
-
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_PATTERN, target_to=PRODUCTION_PATTERN)
- _bind_normal(topology)
-
-
-def test_ticket47553_moddn_staging_prod_6(topology):
- '''
- This test case MOVE entry NEW_ACCOUNT6 from staging to prod
- target_to/target_from: substring/<enmpty> filter
- '''
-
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (6) ######################\n")
- _bind_normal(topology)
-
- old_rdn = "cn=%s6" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- # successfull MOD with the ACI
- topology.master1.log.info("\n\n######################### MOVE to:substring filter / from: empty ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=None, target_to=PRODUCTION_PATTERN)
- _bind_normal(topology)
-
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=None, target_to=PRODUCTION_PATTERN)
- _bind_normal(topology)
-
-
-def test_ticket47553_moddn_staging_prod_7(topology):
- '''
- This test case MOVE entry NEW_ACCOUNT7 from staging to prod
- target_to/target_from: <empty>/substring filter
- '''
-
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (7) ######################\n")
- _bind_normal(topology)
-
- old_rdn = "cn=%s7" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- # successfull MOD with the ACI
- topology.master1.log.info("\n\n######################### MOVE to: empty/ from: substring filter ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_PATTERN, target_to=None)
- _bind_normal(topology)
-
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_PATTERN, target_to=None)
- _bind_normal(topology)
-
-
-def test_ticket47553_moddn_staging_prod_8(topology):
- '''
- This test case MOVE entry NEW_ACCOUNT8 from staging to prod
- target_to/target_from: <empty>/<empty> filter
- '''
-
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (8) ######################\n")
- _bind_normal(topology)
-
- old_rdn = "cn=%s8" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- # successfull MOD with the ACI
- topology.master1.log.info("\n\n######################### MOVE to: empty/ from: empty ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=None, target_to=None)
- _bind_normal(topology)
-
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=None, target_to=None)
- _bind_normal(topology)
-
-
-def test_ticket47553_moddn_staging_prod_9(topology):
- '''
- This test case disable the 'moddn' right so a MODDN requires a 'add' right
- to be successfull.
- It fails to MOVE entry NEW_ACCOUNT9 from staging to prod.
- Add a 'add' right to prod.
- Then it succeeds to MOVE NEW_ACCOUNT9 from staging to prod.
-
- Then enable the 'moddn' right so a MODDN requires a 'moddn' right
- It fails to MOVE entry NEW_ACCOUNT10 from staging to prod.
- Add a 'moddn' right to prod.
- Then it succeeds to MOVE NEW_ACCOUNT10 from staging to prod.
- '''
-
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (9) ######################\n")
-
- _bind_normal(topology)
- old_rdn = "cn=%s9" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- ############################################
- # Now do tests with no support of moddn aci
- ############################################
- topology.master1.log.info("Disable the moddn right")
- _bind_manager(topology)
- mod = [(ldap.MOD_REPLACE, CONFIG_MODDN_ACI_ATTR, 'off')]
- topology.master1.modify_s(DN_CONFIG, mod)
-
- # Add the moddn aci that will not be evaluated because of the config flag
- topology.master1.log.info("\n\n######################### MOVE to and from equality filter ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
- # It will fail because it will test the ADD right
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- # remove the moddn aci
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
- #
- # add the 'add' right to the production DN
- # Then do a successfull moddn
- #
- ACI_ALLOW = "(version 3.0; acl \"ADD rights to allow moddn\"; allow (add)"
- ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
- ACI_BODY = ACI_ALLOW + ACI_SUBJECT
-
- _bind_manager(topology)
- mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
- topology.master1.modify_s(PRODUCTION_DN, mod)
- _write_aci_staging(topology, mod_type=ldap.MOD_ADD)
- _bind_normal(topology)
-
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
-
- _bind_manager(topology)
- mod = [(ldap.MOD_DELETE, 'aci', ACI_BODY)]
- topology.master1.modify_s(PRODUCTION_DN, mod)
- _write_aci_staging(topology, mod_type=ldap.MOD_DELETE)
- _bind_normal(topology)
-
- ############################################
- # Now do tests with support of moddn aci
- ############################################
- topology.master1.log.info("Enable the moddn right")
- _bind_manager(topology)
- mod = [(ldap.MOD_REPLACE, CONFIG_MODDN_ACI_ATTR, 'on')]
- topology.master1.modify_s(DN_CONFIG, mod)
-
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (10) ######################\n")
-
- _bind_normal(topology)
- old_rdn = "cn=%s10" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- #
- # add the 'add' right to the production DN
- # Then do a failing moddn
- #
- ACI_ALLOW = "(version 3.0; acl \"ADD rights to allow moddn\"; allow (add)"
- ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
- ACI_BODY = ACI_ALLOW + ACI_SUBJECT
-
- _bind_manager(topology)
- mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
- topology.master1.modify_s(PRODUCTION_DN, mod)
- _write_aci_staging(topology, mod_type=ldap.MOD_ADD)
- _bind_normal(topology)
-
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- _bind_manager(topology)
- mod = [(ldap.MOD_DELETE, 'aci', ACI_BODY)]
- topology.master1.modify_s(PRODUCTION_DN, mod)
- _write_aci_staging(topology, mod_type=ldap.MOD_DELETE)
- _bind_normal(topology)
-
- # Add the moddn aci that will be evaluated because of the config flag
- topology.master1.log.info("\n\n######################### MOVE to and from equality filter ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
-
- # remove the moddn aci
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
-
-def test_ticket47553_moddn_prod_staging(topology):
- '''
- This test checks that we can move ACCOUNT11 from staging to prod
- but not move back ACCOUNT11 from prod to staging
- '''
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (11) ######################\n")
-
- _bind_normal(topology)
-
- old_rdn = "cn=%s11" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- # successfull MOD with the ACI
- topology.master1.log.info("\n\n######################### MOVE to and from equality filter ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
-
- # Now check we can not move back the entry to staging
- old_rdn = "cn=%s11" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, PRODUCTION_DN)
- new_rdn = old_rdn
- new_superior = STAGING_DN
-
- # add the write right because we want to check the moddn
- _bind_manager(topology)
- _write_aci_production(topology, mod_type=ldap.MOD_ADD)
- _bind_normal(topology)
-
- try:
- topology.master1.log.info("Try to move back MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- _bind_manager(topology)
- _write_aci_production(topology, mod_type=ldap.MOD_DELETE)
- _bind_normal(topology)
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
-
-def test_ticket47553_check_repl_M2_to_M1(topology):
- '''
- Checks that replication is still working M2->M1, using ACCOUNT12
- '''
-
- topology.master1.log.info("Bind as %s (M2)" % DN_DM)
- topology.master2.simple_bind_s(DN_DM, PASSWORD)
-
- rdn = "cn=%s12" % NEW_ACCOUNT
- dn = "%s,%s" % (rdn, STAGING_DN)
-
- # First wait for the ACCOUNT19 entry being replicated on M2
- loop = 0
- while loop <= 10:
- try:
- ent = topology.master2.getEntry(dn, ldap.SCOPE_BASE, "(objectclass=*)")
- break
- except ldap.NO_SUCH_OBJECT:
- time.sleep(1)
- loop += 1
- assert loop <= 10
-
- attribute = 'description'
- tested_value = 'Hello world'
- mod = [(ldap.MOD_ADD, attribute, tested_value)]
- topology.master1.log.info("Update (M2) %s (%s)" % (dn, attribute))
- topology.master2.modify_s(dn, mod)
-
- loop = 0
- while loop <= 10:
- ent = topology.master1.getEntry(dn, ldap.SCOPE_BASE, "(objectclass=*)")
- assert ent is not None
- if ent.hasAttr(attribute) and (ent.getValue(attribute) == tested_value):
- break
-
- time.sleep(1)
- loop += 1
- assert loop < 10
- topology.master1.log.info("Update %s (%s) replicated on M1" % (dn, attribute))
-
-
-def test_ticket47553_moddn_staging_prod_except(topology):
- '''
- This test case MOVE entry NEW_ACCOUNT13 from staging to prod
- but fails to move entry NEW_ACCOUNT14 from staging to prod_except
- '''
-
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (13) ######################\n")
- _bind_normal(topology)
-
- old_rdn = "cn=%s13" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- # successfull MOD with the ACI
- topology.master1.log.info("\n\n######################### MOVE to and from equality filter ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _moddn_aci_deny_tree(topology, mod_type=ldap.MOD_ADD)
- _bind_normal(topology)
-
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
-
- #
- # Now try to move an entry under except
- #
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod/Except (14) ######################\n")
- old_rdn = "cn=%s14" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PROD_EXCEPT_DN
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _moddn_aci_deny_tree(topology, mod_type=ldap.MOD_DELETE)
- _bind_normal(topology)
-
-
-def test_ticket47553_final(topology):
- topology.master1.delete()
- topology.master2.delete()
- log.info('Testcase PASSED')
-
-
-def run_isolated():
- '''
- run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
- To run isolated without py.test, you need to
- - edit this file and comment '@pytest.fixture' line before 'topology' function.
- - set the installation prefix
- - run this program
- '''
- global installation1_prefix
- global installation2_prefix
- installation1_prefix = None
- installation2_prefix = None
-
- topo = topology(True)
- topo.master1.log.info("\n\n######################### Ticket 47553 ######################\n")
- test_ticket47553_init(topo)
-
- # Check that without appropriate aci we are not allowed to add/delete
- test_ticket47553_add(topo)
- test_ticket47553_delete(topo)
-
- # tests the ACI as equality/substring filter
- test_ticket47553_moddn_staging_prod_0(topo)
- test_ticket47553_moddn_staging_prod_1(topo)
- test_ticket47553_moddn_staging_prod_2(topo)
- test_ticket47553_moddn_staging_prod_3(topo)
- test_ticket47553_moddn_staging_prod_4(topo)
- test_ticket47553_moddn_staging_prod_5(topo)
-
- # tests the ACI with undefined 'target_to'/'target_from'
- test_ticket47553_moddn_staging_prod_6(topo)
- test_ticket47553_moddn_staging_prod_7(topo)
- test_ticket47553_moddn_staging_prod_8(topo)
-
- # Check we can control the behavior with nsslapd-moddn-aci
- test_ticket47553_moddn_staging_prod_9(topo)
-
- # Check we can move entry 'from' -> 'to' but not 'to' -> 'from'
- test_ticket47553_moddn_prod_staging(topo)
-
- # check replication is still working
- test_ticket47553_check_repl_M2_to_M1(topo)
-
- # check DENY rule is working
- test_ticket47553_moddn_staging_prod_except(topo)
-
- test_ticket47553_final(topo)
-
-
-if __name__ == '__main__':
- run_isolated()
-
8 years, 6 months
dirsrvtests/suites dirsrvtests/tickets
by Simon Pichugin
dirsrvtests/suites/acl/acl_test.py | 953 +++++++++++++++++
dirsrvtests/tickets/ticket47553_ger.py | 475 --------
dirsrvtests/tickets/ticket47553_rdn_write_test.py | 143 --
dirsrvtests/tickets/ticket47553_single_aci_test.py | 1137 ---------------------
4 files changed, 929 insertions(+), 1779 deletions(-)
New commits:
commit edaa28b1266312ef8dce737af46e09e130c7135a
Author: Simon Pichugin <spichugi(a)redhat.com>
Date: Wed Sep 2 11:27:36 2015 +0200
Ticket 48264 - Ticket 47553 tests refactoring
Description: Refactor these tests according to the pytest and PEP8 way:
- ticket47553_ger.py;
- ticket47553_rdn_write_test.py;
- ticket47553_single_aci_test.py.
Move them to the dirsrvtests/suites/acl/acl_test.py test suite.
https://fedorahosted.org/389/ticket/48264
Reviewed by: mreynolds(a)redhat.com (Thanks!)
diff --git a/dirsrvtests/suites/acl/acl_test.py b/dirsrvtests/suites/acl/acl_test.py
index 36aed33..422a1ec 100644
--- a/dirsrvtests/suites/acl/acl_test.py
+++ b/dirsrvtests/suites/acl/acl_test.py
@@ -18,48 +18,167 @@ from lib389._constants import *
from lib389.properties import *
from lib389.tasks import *
from lib389.utils import *
+from ldap.controls.simple import GetEffectiveRightsControl
logging.getLogger(__name__).setLevel(logging.DEBUG)
log = logging.getLogger(__name__)
+#
+# important part. We can deploy Master1 and Master2 on different versions
+#
installation1_prefix = None
+installation2_prefix = None
+
+TEST_REPL_DN = "cn=test_repl, %s" % SUFFIX
+
+STAGING_CN = "staged user"
+PRODUCTION_CN = "accounts"
+EXCEPT_CN = "excepts"
+
+STAGING_DN = "cn=%s,%s" % (STAGING_CN, SUFFIX)
+PRODUCTION_DN = "cn=%s,%s" % (PRODUCTION_CN, SUFFIX)
+PROD_EXCEPT_DN = "cn=%s,%s" % (EXCEPT_CN, PRODUCTION_DN)
+
+STAGING_PATTERN = "cn=%s*,%s" % (STAGING_CN[:2], SUFFIX)
+PRODUCTION_PATTERN = "cn=%s*,%s" % (PRODUCTION_CN[:2], SUFFIX)
+BAD_STAGING_PATTERN = "cn=bad*,%s" % (SUFFIX)
+BAD_PRODUCTION_PATTERN = "cn=bad*,%s" % (SUFFIX)
+
+BIND_CN = "bind_entry"
+BIND_DN = "cn=%s,%s" % (BIND_CN, SUFFIX)
+BIND_PW = "password"
+NEW_ACCOUNT = "new_account"
+MAX_ACCOUNTS = 20
-class TopologyStandalone(object):
- def __init__(self, standalone):
- standalone.open()
- self.standalone = standalone
+CONFIG_MODDN_ACI_ATTR = "nsslapd-moddn-aci"
+
+SRC_ENTRY_CN = "tuser"
+EXT_RDN = "01"
+DST_ENTRY_CN = SRC_ENTRY_CN + EXT_RDN
+
+SRC_ENTRY_DN = "cn=%s,%s" % (SRC_ENTRY_CN, SUFFIX)
+DST_ENTRY_DN = "cn=%s,%s" % (DST_ENTRY_CN, SUFFIX)
+
+
+class TopologyMaster1Master2(object):
+ def __init__(self, master1, master2):
+ master1.open()
+ self.master1 = master1
+
+ master2.open()
+ self.master2 = master2
@pytest.fixture(scope="module")
def topology(request):
+ """This fixture is used to create a replicated topology for the 'module'.
+ The replicated topology is MASTER1 <-> Master2.
+ """
+
global installation1_prefix
+ global installation2_prefix
+
+ # allocate master1 on a given deployement
+ master1 = DirSrv(verbose=False)
if installation1_prefix:
args_instance[SER_DEPLOYED_DIR] = installation1_prefix
- # Creating standalone instance ...
- standalone = DirSrv(verbose=False)
- args_instance[SER_HOST] = HOST_STANDALONE
- args_instance[SER_PORT] = PORT_STANDALONE
- args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
- args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX
- args_standalone = args_instance.copy()
- standalone.allocate(args_standalone)
- instance_standalone = standalone.exists()
- if instance_standalone:
- standalone.delete()
- standalone.create()
- standalone.open()
-
- # Delete each instance in the end
+ # Args for the master1 instance
+ args_instance[SER_HOST] = HOST_MASTER_1
+ args_instance[SER_PORT] = PORT_MASTER_1
+ args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_1
+ args_master = args_instance.copy()
+ master1.allocate(args_master)
+
+ # allocate master1 on a given deployement
+ master2 = DirSrv(verbose=False)
+ if installation2_prefix:
+ args_instance[SER_DEPLOYED_DIR] = installation2_prefix
+
+ # Args for the consumer instance
+ args_instance[SER_HOST] = HOST_MASTER_2
+ args_instance[SER_PORT] = PORT_MASTER_2
+ args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_2
+ args_master = args_instance.copy()
+ master2.allocate(args_master)
+
+ # Get the status of the instance and restart it if it exists
+ instance_master1 = master1.exists()
+ instance_master2 = master2.exists()
+
+ # Remove all the instances
+ if instance_master1:
+ master1.delete()
+ if instance_master2:
+ master2.delete()
+
+ # Create the instances
+ master1.create()
+ master1.open()
+ master2.create()
+ master2.open()
+
+ #
+ # Now prepare the Master-Consumer topology
+ #
+ # First Enable replication
+ master1.replica.enableReplication(suffix=SUFFIX,
+ role=REPLICAROLE_MASTER,
+ replicaId=REPLICAID_MASTER_1)
+ master2.replica.enableReplication(suffix=SUFFIX,
+ role=REPLICAROLE_MASTER,
+ replicaId=REPLICAID_MASTER_2)
+
+ # Initialize the supplier->consumer
+
+ properties = {RA_NAME: r'meTo_$host:$port',
+ RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
+ RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
+ RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
+ RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
+ repl_agreement = master1.agreement.create(suffix=SUFFIX,
+ host=master2.host,
+ port=master2.port,
+ properties=properties)
+
+ if not repl_agreement:
+ log.fatal("Fail to create a replica agreement")
+ sys.exit(1)
+
+ log.debug("%s created" % repl_agreement)
+
+ properties = {RA_NAME: r'meTo_$host:$port',
+ RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
+ RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
+ RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
+ RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
+ master2.agreement.create(suffix=SUFFIX,
+ host=master1.host,
+ port=master1.port,
+ properties=properties)
+
+ master1.agreement.init(SUFFIX, HOST_MASTER_2, PORT_MASTER_2)
+ master1.waitForReplInit(repl_agreement)
+
+ # Check replication is working fine
+ if master1.testReplication(DEFAULT_SUFFIX, master2):
+ log.info('Replication is working.')
+ else:
+ log.fatal('Replication is not working.')
+ assert False
+
def fin():
- standalone.delete()
+ master1.delete()
+ master2.delete()
request.addfinalizer(fin)
- # Clear out the tmp dir
- standalone.clearTmpDir(__file__)
+ # clear the tmp directory
+ master1.clearTmpDir(__file__)
- return TopologyStandalone(standalone)
+ # Here we have two instances master and consumer
+ # with replication working.
+ return TopologyMaster1Master2(master1, master2)
def add_attr(topology, attr_name):
@@ -135,7 +254,7 @@ def test_aci_attr_subtype_targetattr(topology, aci_with_attr_subtype):
log.info(" Search for the added attribute")
try:
- entries = topology.standalone.search_s(DEFAULT_SUFFIX,
+ entries = topology.master1.search_s(DEFAULT_SUFFIX,
ldap.SCOPE_BASE,
'(objectclass=*)', ['aci'])
entry = str(entries[0])
@@ -147,6 +266,792 @@ def test_aci_attr_subtype_targetattr(topology, aci_with_attr_subtype):
assert False
+def _bind_manager(topology):
+ topology.master1.log.info("Bind as %s " % DN_DM)
+ topology.master1.simple_bind_s(DN_DM, PASSWORD)
+
+
+def _bind_normal(topology):
+ # bind as bind_entry
+ topology.master1.log.info("Bind as %s" % BIND_DN)
+ topology.master1.simple_bind_s(BIND_DN, BIND_PW)
+
+
+def _moddn_aci_deny_tree(topology, mod_type=None,
+ target_from=STAGING_DN, target_to=PROD_EXCEPT_DN):
+ """It denies the access moddn_to in cn=except,cn=accounts,SUFFIX"""
+
+ assert mod_type is not None
+
+ ACI_TARGET_FROM = ""
+ ACI_TARGET_TO = ""
+ if target_from:
+ ACI_TARGET_FROM = "(target_from = \"ldap:///%s\")" % (target_from)
+ if target_to:
+ ACI_TARGET_TO = "(target_to = \"ldap:///%s\")" % (target_to)
+
+ ACI_ALLOW = "(version 3.0; acl \"Deny MODDN to prod_except\"; deny (moddn)"
+ ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
+ ACI_BODY = ACI_TARGET_TO + ACI_TARGET_FROM + ACI_ALLOW + ACI_SUBJECT
+ mod = [(mod_type, 'aci', ACI_BODY)]
+ #topology.master1.modify_s(SUFFIX, mod)
+ topology.master1.log.info("Add a DENY aci under %s " % PROD_EXCEPT_DN)
+ topology.master1.modify_s(PROD_EXCEPT_DN, mod)
+
+
+def _write_aci_staging(topology, mod_type=None):
+ assert mod_type is not None
+
+ ACI_TARGET = "(targetattr= \"cn\")(target=\"ldap:///cn=*,%s\")" % STAGING_DN
+ ACI_ALLOW = "(version 3.0; acl \"write staging entries\"; allow (write)"
+ ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
+ ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
+ mod = [(mod_type, 'aci', ACI_BODY)]
+ topology.master1.modify_s(SUFFIX, mod)
+
+
+def _write_aci_production(topology, mod_type=None):
+ assert mod_type is not None
+
+ ACI_TARGET = "(targetattr= \"cn\")(target=\"ldap:///cn=*,%s\")" % PRODUCTION_DN
+ ACI_ALLOW = "(version 3.0; acl \"write production entries\"; allow (write)"
+ ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
+ ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
+ mod = [(mod_type, 'aci', ACI_BODY)]
+ topology.master1.modify_s(SUFFIX, mod)
+
+
+def _moddn_aci_staging_to_production(topology, mod_type=None,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN):
+ assert mod_type is not None
+
+
+ ACI_TARGET_FROM = ""
+ ACI_TARGET_TO = ""
+ if target_from:
+ ACI_TARGET_FROM = "(target_from = \"ldap:///%s\")" % (target_from)
+ if target_to:
+ ACI_TARGET_TO = "(target_to = \"ldap:///%s\")" % (target_to)
+
+ ACI_ALLOW = "(version 3.0; acl \"MODDN from staging to production\"; allow (moddn)"
+ ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
+ ACI_BODY = ACI_TARGET_FROM + ACI_TARGET_TO + ACI_ALLOW + ACI_SUBJECT
+ mod = [(mod_type, 'aci', ACI_BODY)]
+ topology.master1.modify_s(SUFFIX, mod)
+
+ _write_aci_staging(topology, mod_type=mod_type)
+
+
+def _moddn_aci_from_production_to_staging(topology, mod_type=None):
+ assert mod_type is not None
+
+ ACI_TARGET = "(target_from = \"ldap:///%s\") (target_to = \"ldap:///%s\")" % (
+ PRODUCTION_DN, STAGING_DN)
+ ACI_ALLOW = "(version 3.0; acl \"MODDN from production to staging\"; allow (moddn)"
+ ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
+ ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
+ mod = [(mod_type, 'aci', ACI_BODY)]
+ topology.master1.modify_s(SUFFIX, mod)
+
+ _write_aci_production(topology, mod_type=mod_type)
+
+
+(a)pytest.fixture(scope="module")
+def moddn_setup(topology):
+ """Creates
+ - a staging DIT
+ - a production DIT
+ - add accounts in staging DIT
+ - enable ACL logging (commented for performance reason)
+ """
+
+ topology.master1.log.info("\n\n######## INITIALIZATION ########\n")
+
+ # entry used to bind with
+ topology.master1.log.info("Add %s" % BIND_DN)
+ topology.master1.add_s(Entry((BIND_DN, {
+ 'objectclass': "top person".split(),
+ 'sn': BIND_CN,
+ 'cn': BIND_CN,
+ 'userpassword': BIND_PW})))
+
+ # DIT for staging
+ topology.master1.log.info("Add %s" % STAGING_DN)
+ topology.master1.add_s(Entry((STAGING_DN, {
+ 'objectclass': "top organizationalRole".split(),
+ 'cn': STAGING_CN,
+ 'description': "staging DIT"})))
+
+ # DIT for production
+ topology.master1.log.info("Add %s" % PRODUCTION_DN)
+ topology.master1.add_s(Entry((PRODUCTION_DN, {
+ 'objectclass': "top organizationalRole".split(),
+ 'cn': PRODUCTION_CN,
+ 'description': "production DIT"})))
+
+ # DIT for production/except
+ topology.master1.log.info("Add %s" % PROD_EXCEPT_DN)
+ topology.master1.add_s(Entry((PROD_EXCEPT_DN, {
+ 'objectclass': "top organizationalRole".split(),
+ 'cn': EXCEPT_CN,
+ 'description': "production except DIT"})))
+
+ # enable acl error logging
+ #mod = [(ldap.MOD_REPLACE, 'nsslapd-errorlog-level', '128')]
+ #topology.master1.modify_s(DN_CONFIG, mod)
+ #topology.master2.modify_s(DN_CONFIG, mod)
+
+ # add dummy entries in the staging DIT
+ for cpt in range(MAX_ACCOUNTS):
+ name = "%s%d" % (NEW_ACCOUNT, cpt)
+ topology.master1.add_s(Entry(("cn=%s,%s" % (name, STAGING_DN), {
+ 'objectclass': "top person".split(),
+ 'sn': name,
+ 'cn': name})))
+
+
+def test_mode_default_add_deny(topology, moddn_setup):
+ """This test case checks
+ that the ADD operation fails (no ADD aci on production)
+ """
+
+ topology.master1.log.info("\n\n######## mode moddn_aci : ADD (should fail) ########\n")
+
+ _bind_normal(topology)
+
+ #
+ # First try to add an entry in production => INSUFFICIENT_ACCESS
+ #
+ try:
+ topology.master1.log.info("Try to add %s" % PRODUCTION_DN)
+ name = "%s%d" % (NEW_ACCOUNT, 0)
+ topology.master1.add_s(Entry(("cn=%s,%s" % (name, PRODUCTION_DN), {
+ 'objectclass': "top person".split(),
+ 'sn': name,
+ 'cn': name})))
+ assert 0 # this is an error, we should not be allowed to add an entry in production
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+
+def test_mode_default_delete_deny(topology, moddn_setup):
+ """This test case checks
+ that the DEL operation fails (no 'delete' aci on production)
+ """
+
+ topology.master1.log.info("\n\n######## DELETE (should fail) ########\n")
+
+ _bind_normal(topology)
+ #
+ # Second try to delete an entry in staging => INSUFFICIENT_ACCESS
+ #
+ try:
+ topology.master1.log.info("Try to delete %s" % STAGING_DN)
+ name = "%s%d" % (NEW_ACCOUNT, 0)
+ topology.master1.delete_s("cn=%s,%s" % (name, STAGING_DN))
+ assert 0 # this is an error, we should not be allowed to add an entry in production
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+
+(a)pytest.mark.parametrize("index,tfrom,tto,failure",
+ [(0, STAGING_DN, PRODUCTION_DN, False),
+ (1, STAGING_DN, PRODUCTION_DN, False),
+ (2, STAGING_DN, BAD_PRODUCTION_PATTERN, True),
+ (3, STAGING_PATTERN, PRODUCTION_DN, False),
+ (4, BAD_STAGING_PATTERN, PRODUCTION_DN, True),
+ (5, STAGING_PATTERN, PRODUCTION_PATTERN, False),
+ (6, None, PRODUCTION_PATTERN, False),
+ (7, STAGING_PATTERN, None, False),
+ (8, None, None, False)])
+def test_moddn_staging_prod(topology, moddn_setup,
+ index, tfrom, tto, failure):
+ """This test case MOVE entry NEW_ACCOUNT0 from staging to prod
+ target_to/target_from: equality filter
+ """
+
+ topology.master1.log.info("\n\n######## MOVE staging -> Prod (%s) ########\n" % index)
+ _bind_normal(topology)
+
+ old_rdn = "cn=%s%s" % (NEW_ACCOUNT, index)
+ old_dn = "%s,%s" % (old_rdn, STAGING_DN)
+ new_rdn = old_rdn
+ new_superior = PRODUCTION_DN
+
+ #
+ # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
+ #
+ try:
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+ assert 0
+ except AssertionError:
+ topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+
+ # successfull MOD with the ACI
+ topology.master1.log.info("\n\n######## MOVE to and from equality filter ########\n")
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD,
+ target_from=tfrom, target_to=tto)
+ _bind_normal(topology)
+
+ try:
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ if failure:
+ assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+ # successfull MOD with the both ACI
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE,
+ target_from=tfrom, target_to=tto)
+ _bind_normal(topology)
+
+
+def test_moddn_staging_prod_9(topology, moddn_setup):
+ """This test case disable the 'moddn' right so a MODDN requires a 'add' right
+ to be successfull.
+ It fails to MOVE entry NEW_ACCOUNT9 from staging to prod.
+ Add a 'add' right to prod.
+ Then it succeeds to MOVE NEW_ACCOUNT9 from staging to prod.
+
+ Then enable the 'moddn' right so a MODDN requires a 'moddn' right
+ It fails to MOVE entry NEW_ACCOUNT10 from staging to prod.
+ Add a 'moddn' right to prod.
+ Then it succeeds to MOVE NEW_ACCOUNT10 from staging to prod.
+ """
+
+ topology.master1.log.info("\n\n######## MOVE staging -> Prod (9) ########\n")
+
+ _bind_normal(topology)
+ old_rdn = "cn=%s9" % NEW_ACCOUNT
+ old_dn = "%s,%s" % (old_rdn, STAGING_DN)
+ new_rdn = old_rdn
+ new_superior = PRODUCTION_DN
+
+ #
+ # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
+ #
+ try:
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+ assert 0
+ except AssertionError:
+ topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+ #############
+ # Now do tests with no support of moddn aci
+ #############
+ topology.master1.log.info("Disable the moddn right")
+ _bind_manager(topology)
+ mod = [(ldap.MOD_REPLACE, CONFIG_MODDN_ACI_ATTR, 'off')]
+ topology.master1.modify_s(DN_CONFIG, mod)
+
+ # Add the moddn aci that will not be evaluated because of the config flag
+ topology.master1.log.info("\n\n######## MOVE to and from equality filter ########\n")
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN)
+ _bind_normal(topology)
+
+ # It will fail because it will test the ADD right
+ try:
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+ assert 0
+ except AssertionError:
+ topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+ # remove the moddn aci
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN)
+ _bind_normal(topology)
+
+ #
+ # add the 'add' right to the production DN
+ # Then do a successfull moddn
+ #
+ ACI_ALLOW = "(version 3.0; acl \"ADD rights to allow moddn\"; allow (add)"
+ ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
+ ACI_BODY = ACI_ALLOW + ACI_SUBJECT
+
+ _bind_manager(topology)
+ mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
+ topology.master1.modify_s(PRODUCTION_DN, mod)
+ _write_aci_staging(topology, mod_type=ldap.MOD_ADD)
+ _bind_normal(topology)
+
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+
+ _bind_manager(topology)
+ mod = [(ldap.MOD_DELETE, 'aci', ACI_BODY)]
+ topology.master1.modify_s(PRODUCTION_DN, mod)
+ _write_aci_staging(topology, mod_type=ldap.MOD_DELETE)
+ _bind_normal(topology)
+
+ #############
+ # Now do tests with support of moddn aci
+ #############
+ topology.master1.log.info("Enable the moddn right")
+ _bind_manager(topology)
+ mod = [(ldap.MOD_REPLACE, CONFIG_MODDN_ACI_ATTR, 'on')]
+ topology.master1.modify_s(DN_CONFIG, mod)
+
+ topology.master1.log.info("\n\n######## MOVE staging -> Prod (10) ########\n")
+
+ _bind_normal(topology)
+ old_rdn = "cn=%s10" % NEW_ACCOUNT
+ old_dn = "%s,%s" % (old_rdn, STAGING_DN)
+ new_rdn = old_rdn
+ new_superior = PRODUCTION_DN
+
+ #
+ # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
+ #
+ try:
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+ assert 0
+ except AssertionError:
+ topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+ #
+ # add the 'add' right to the production DN
+ # Then do a failing moddn
+ #
+ ACI_ALLOW = "(version 3.0; acl \"ADD rights to allow moddn\"; allow (add)"
+ ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
+ ACI_BODY = ACI_ALLOW + ACI_SUBJECT
+
+ _bind_manager(topology)
+ mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
+ topology.master1.modify_s(PRODUCTION_DN, mod)
+ _write_aci_staging(topology, mod_type=ldap.MOD_ADD)
+ _bind_normal(topology)
+
+ try:
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+ assert 0
+ except AssertionError:
+ topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+ _bind_manager(topology)
+ mod = [(ldap.MOD_DELETE, 'aci', ACI_BODY)]
+ topology.master1.modify_s(PRODUCTION_DN, mod)
+ _write_aci_staging(topology, mod_type=ldap.MOD_DELETE)
+ _bind_normal(topology)
+
+ # Add the moddn aci that will be evaluated because of the config flag
+ topology.master1.log.info("\n\n######## MOVE to and from equality filter ########\n")
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN)
+ _bind_normal(topology)
+
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+
+ # remove the moddn aci
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN)
+ _bind_normal(topology)
+
+
+def test_moddn_prod_staging(topology, moddn_setup):
+ """This test checks that we can move ACCOUNT11 from staging to prod
+ but not move back ACCOUNT11 from prod to staging
+ """
+
+ topology.master1.log.info("\n\n######## MOVE staging -> Prod (11) ########\n")
+
+ _bind_normal(topology)
+
+ old_rdn = "cn=%s11" % NEW_ACCOUNT
+ old_dn = "%s,%s" % (old_rdn, STAGING_DN)
+ new_rdn = old_rdn
+ new_superior = PRODUCTION_DN
+
+ #
+ # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
+ #
+ try:
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+ assert 0
+ except AssertionError:
+ topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+ # successfull MOD with the ACI
+ topology.master1.log.info("\n\n######## MOVE to and from equality filter ########\n")
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN)
+ _bind_normal(topology)
+
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+
+ # Now check we can not move back the entry to staging
+ old_rdn = "cn=%s11" % NEW_ACCOUNT
+ old_dn = "%s,%s" % (old_rdn, PRODUCTION_DN)
+ new_rdn = old_rdn
+ new_superior = STAGING_DN
+
+ # add the write right because we want to check the moddn
+ _bind_manager(topology)
+ _write_aci_production(topology, mod_type=ldap.MOD_ADD)
+ _bind_normal(topology)
+
+ try:
+ topology.master1.log.info("Try to move back MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+ assert 0
+ except AssertionError:
+ topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+ _bind_manager(topology)
+ _write_aci_production(topology, mod_type=ldap.MOD_DELETE)
+ _bind_normal(topology)
+
+ # successfull MOD with the both ACI
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN)
+ _bind_normal(topology)
+
+
+def test_check_repl_M2_to_M1(topology, moddn_setup):
+ """Checks that replication is still working M2->M1, using ACCOUNT12"""
+
+ topology.master1.log.info("Bind as %s (M2)" % DN_DM)
+ topology.master2.simple_bind_s(DN_DM, PASSWORD)
+
+ rdn = "cn=%s12" % NEW_ACCOUNT
+ dn = "%s,%s" % (rdn, STAGING_DN)
+
+ # First wait for the ACCOUNT19 entry being replicated on M2
+ loop = 0
+ while loop <= 10:
+ try:
+ ent = topology.master2.getEntry(dn, ldap.SCOPE_BASE, "(objectclass=*)")
+ break
+ except ldap.NO_SUCH_OBJECT:
+ time.sleep(1)
+ loop += 1
+ assert loop <= 10
+
+ attribute = 'description'
+ tested_value = 'Hello world'
+ mod = [(ldap.MOD_ADD, attribute, tested_value)]
+ topology.master1.log.info("Update (M2) %s (%s)" % (dn, attribute))
+ topology.master2.modify_s(dn, mod)
+
+ loop = 0
+ while loop <= 10:
+ ent = topology.master1.getEntry(dn, ldap.SCOPE_BASE, "(objectclass=*)")
+ assert ent is not None
+ if ent.hasAttr(attribute) and (ent.getValue(attribute) == tested_value):
+ break
+
+ time.sleep(1)
+ loop += 1
+ assert loop < 10
+ topology.master1.log.info("Update %s (%s) replicated on M1" % (dn, attribute))
+
+
+def test_moddn_staging_prod_except(topology, moddn_setup):
+ """This test case MOVE entry NEW_ACCOUNT13 from staging to prod
+ but fails to move entry NEW_ACCOUNT14 from staging to prod_except
+ """
+
+ topology.master1.log.info("\n\n######## MOVE staging -> Prod (13) ########\n")
+ _bind_normal(topology)
+
+ old_rdn = "cn=%s13" % NEW_ACCOUNT
+ old_dn = "%s,%s" % (old_rdn, STAGING_DN)
+ new_rdn = old_rdn
+ new_superior = PRODUCTION_DN
+
+ #
+ # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
+ #
+ try:
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+ assert 0
+ except AssertionError:
+ topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+ # successfull MOD with the ACI
+ topology.master1.log.info("\n\n######## MOVE to and from equality filter ########\n")
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN)
+ _moddn_aci_deny_tree(topology, mod_type=ldap.MOD_ADD)
+ _bind_normal(topology)
+
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+
+ #
+ # Now try to move an entry under except
+ #
+ topology.master1.log.info("\n\n######## MOVE staging -> Prod/Except (14) ########\n")
+ old_rdn = "cn=%s14" % NEW_ACCOUNT
+ old_dn = "%s,%s" % (old_rdn, STAGING_DN)
+ new_rdn = old_rdn
+ new_superior = PROD_EXCEPT_DN
+ try:
+ topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
+ topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
+ assert 0
+ except AssertionError:
+ topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+ # successfull MOD with the both ACI
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN)
+ _moddn_aci_deny_tree(topology, mod_type=ldap.MOD_DELETE)
+ _bind_normal(topology)
+
+
+def test_mode_default_ger_no_moddn(topology, moddn_setup):
+ topology.master1.log.info("\n\n######## mode moddn_aci : GER no moddn ########\n")
+ request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn: " + BIND_DN)
+ msg_id = topology.master1.search_ext(PRODUCTION_DN,
+ ldap.SCOPE_SUBTREE,
+ "objectclass=*",
+ serverctrls=[request_ctrl])
+ rtype, rdata, rmsgid, response_ctrl = topology.master1.result3(msg_id)
+ #ger={}
+ value = ''
+ for dn, attrs in rdata:
+ topology.master1.log.info("dn: %s" % dn)
+ value = attrs['entryLevelRights'][0]
+
+ topology.master1.log.info("######## entryLevelRights: %r" % value)
+ assert 'n' not in value
+
+
+def test_mode_default_ger_with_moddn(topology, moddn_setup):
+ """This test case adds the moddn aci and check ger contains 'n'"""
+
+ topology.master1.log.info("\n\n######## mode moddn_aci: GER with moddn ########\n")
+
+ # successfull MOD with the ACI
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN)
+ _bind_normal(topology)
+
+ request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn: " + BIND_DN)
+ msg_id = topology.master1.search_ext(PRODUCTION_DN,
+ ldap.SCOPE_SUBTREE,
+ "objectclass=*",
+ serverctrls=[request_ctrl])
+ rtype, rdata, rmsgid, response_ctrl = topology.master1.result3(msg_id)
+ #ger={}
+ value = ''
+ for dn, attrs in rdata:
+ topology.master1.log.info("dn: %s" % dn)
+ value = attrs['entryLevelRights'][0]
+
+ topology.master1.log.info("######## entryLevelRights: %r" % value)
+ assert 'n' in value
+
+ # successfull MOD with the both ACI
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN)
+ _bind_normal(topology)
+
+
+def test_mode_switch_default_to_legacy(topology, moddn_setup):
+ """This test switch the server from default mode to legacy"""
+
+ topology.master1.log.info("\n\n######## Disable the moddn aci mod ########\n")
+ _bind_manager(topology)
+ mod = [(ldap.MOD_REPLACE, CONFIG_MODDN_ACI_ATTR, 'off')]
+ topology.master1.modify_s(DN_CONFIG, mod)
+
+
+def test_mode_legacy_ger_no_moddn1(topology, moddn_setup):
+ topology.master1.log.info("\n\n######## mode legacy 1: GER no moddn ########\n")
+ request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn: " + BIND_DN)
+ msg_id = topology.master1.search_ext(PRODUCTION_DN,
+ ldap.SCOPE_SUBTREE,
+ "objectclass=*",
+ serverctrls=[request_ctrl])
+ rtype, rdata, rmsgid, response_ctrl = topology.master1.result3(msg_id)
+ #ger={}
+ value = ''
+ for dn, attrs in rdata:
+ topology.master1.log.info("dn: %s" % dn)
+ value = attrs['entryLevelRights'][0]
+
+ topology.master1.log.info("######## entryLevelRights: %r" % value)
+ assert 'n' not in value
+
+
+def test_mode_legacy_ger_no_moddn2(topology, moddn_setup):
+ topology.master1.log.info("\n\n######## mode legacy 2: GER no moddn ########\n")
+ # successfull MOD with the ACI
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN)
+ _bind_normal(topology)
+
+ request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn: " + BIND_DN)
+ msg_id = topology.master1.search_ext(PRODUCTION_DN,
+ ldap.SCOPE_SUBTREE,
+ "objectclass=*",
+ serverctrls=[request_ctrl])
+ rtype, rdata, rmsgid, response_ctrl = topology.master1.result3(msg_id)
+ #ger={}
+ value = ''
+ for dn, attrs in rdata:
+ topology.master1.log.info("dn: %s" % dn)
+ value = attrs['entryLevelRights'][0]
+
+ topology.master1.log.info("######## entryLevelRights: %r" % value)
+ assert 'n' not in value
+
+ # successfull MOD with the both ACI
+ _bind_manager(topology)
+ _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE,
+ target_from=STAGING_DN, target_to=PRODUCTION_DN)
+ _bind_normal(topology)
+
+
+def test_mode_legacy_ger_with_moddn(topology, moddn_setup):
+ topology.master1.log.info("\n\n######## mode legacy : GER with moddn ########\n")
+
+ # being allowed to read/write the RDN attribute use to allow the RDN
+ ACI_TARGET = "(target = \"ldap:///%s\")(targetattr=\"cn\")" % (PRODUCTION_DN)
+ ACI_ALLOW = "(version 3.0; acl \"MODDN production changing the RDN attribute\"; allow (read,search,write)"
+ ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
+ ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
+
+ # successfull MOD with the ACI
+ _bind_manager(topology)
+ mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
+ topology.master1.modify_s(SUFFIX, mod)
+ _bind_normal(topology)
+
+ request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn: " + BIND_DN)
+ msg_id = topology.master1.search_ext(PRODUCTION_DN,
+ ldap.SCOPE_SUBTREE,
+ "objectclass=*",
+ serverctrls=[request_ctrl])
+ rtype, rdata, rmsgid, response_ctrl = topology.master1.result3(msg_id)
+ #ger={}
+ value = ''
+ for dn, attrs in rdata:
+ topology.master1.log.info("dn: %s" % dn)
+ value = attrs['entryLevelRights'][0]
+
+ topology.master1.log.info("######## entryLevelRights: %r" % value)
+ assert 'n' in value
+
+ # successfull MOD with the both ACI
+ _bind_manager(topology)
+ mod = [(ldap.MOD_DELETE, 'aci', ACI_BODY)]
+ topology.master1.modify_s(SUFFIX, mod)
+ #_bind_normal(topology)
+
+
+(a)pytest.fixture(scope="module")
+def rdn_write_setup(topology):
+ topology.master1.log.info("\n\n######## Add entry tuser ########\n")
+ topology.master1.add_s(Entry((SRC_ENTRY_DN, {
+ 'objectclass': "top person".split(),
+ 'sn': SRC_ENTRY_CN,
+ 'cn': SRC_ENTRY_CN})))
+
+
+def test_rdn_write_get_ger(topology, rdn_write_setup):
+ ANONYMOUS_DN = ""
+ topology.master1.log.info("\n\n######## GER rights for anonymous ########\n")
+ request_ctrl = GetEffectiveRightsControl(criticality=True,
+ authzId="dn:" + ANONYMOUS_DN)
+ msg_id = topology.master1.search_ext(SUFFIX,
+ ldap.SCOPE_SUBTREE,
+ "objectclass=*",
+ serverctrls=[request_ctrl])
+ rtype, rdata, rmsgid, response_ctrl = topology.master1.result3(msg_id)
+ value = ''
+ for dn, attrs in rdata:
+ topology.master1.log.info("dn: %s" % dn)
+ for value in attrs['entryLevelRights']:
+ topology.master1.log.info("######## entryLevelRights: %r" % value)
+ assert 'n' not in value
+
+
+def test_rdn_write_modrdn_anonymous(topology, rdn_write_setup):
+ ANONYMOUS_DN = ""
+ topology.master1.close()
+ topology.master1.binddn = ANONYMOUS_DN
+ topology.master1.open()
+ msg_id = topology.master1.search_ext("", ldap.SCOPE_BASE, "objectclass=*")
+ rtype, rdata, rmsgid, response_ctrl = topology.master1.result3(msg_id)
+ for dn, attrs in rdata:
+ topology.master1.log.info("dn: %s" % dn)
+ for attr in attrs:
+ topology.master1.log.info("######## %r: %r" % (attr, attrs[attr]))
+
+ try:
+ topology.master1.rename_s(SRC_ENTRY_DN, "cn=%s" % DST_ENTRY_CN, delold=True)
+ except Exception as e:
+ topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
+ isinstance(e, ldap.INSUFFICIENT_ACCESS)
+
+ try:
+ topology.master1.getEntry(DST_ENTRY_DN, ldap.SCOPE_BASE, "objectclass=*")
+ assert False
+ except Exception as e:
+ topology.master1.log.info("The entry was not renamed (expected)")
+ isinstance(e, ldap.NO_SUCH_OBJECT)
+
+ _bind_manager(topology)
+
+
if __name__ == '__main__':
# Run isolated
# -s for DEBUG mode
diff --git a/dirsrvtests/tickets/ticket47553_ger.py b/dirsrvtests/tickets/ticket47553_ger.py
deleted file mode 100644
index 1829b48..0000000
--- a/dirsrvtests/tickets/ticket47553_ger.py
+++ /dev/null
@@ -1,475 +0,0 @@
-# --- BEGIN COPYRIGHT BLOCK ---
-# Copyright (C) 2015 Red Hat, Inc.
-# All rights reserved.
-#
-# License: GPL (version 3 or any later version).
-# See LICENSE for details.
-# --- END COPYRIGHT BLOCK ---
-#
-'''
-Created on Nov 7, 2013
-
-@author: tbordaz
-'''
-import os
-import sys
-import time
-import ldap
-import logging
-import pytest
-from lib389 import DirSrv, Entry, tools
-from lib389.tools import DirSrvTools
-from lib389._constants import *
-from lib389.properties import *
-from ldap.controls.simple import GetEffectiveRightsControl
-
-logging.getLogger(__name__).setLevel(logging.DEBUG)
-log = logging.getLogger(__name__)
-
-#
-# important part. We can deploy Master1 and Master2 on different versions
-#
-installation1_prefix = None
-installation2_prefix = None
-
-TEST_REPL_DN = "cn=test_repl, %s" % SUFFIX
-
-STAGING_CN = "staged user"
-PRODUCTION_CN = "accounts"
-EXCEPT_CN = "excepts"
-
-STAGING_DN = "cn=%s,%s" % (STAGING_CN, SUFFIX)
-PRODUCTION_DN = "cn=%s,%s" % (PRODUCTION_CN, SUFFIX)
-PROD_EXCEPT_DN = "cn=%s,%s" % (EXCEPT_CN, PRODUCTION_DN)
-
-STAGING_PATTERN = "cn=%s*,%s" % (STAGING_CN[:2], SUFFIX)
-PRODUCTION_PATTERN = "cn=%s*,%s" % (PRODUCTION_CN[:2], SUFFIX)
-BAD_STAGING_PATTERN = "cn=bad*,%s" % (SUFFIX)
-BAD_PRODUCTION_PATTERN = "cn=bad*,%s" % (SUFFIX)
-
-BIND_CN = "bind_entry"
-BIND_DN = "cn=%s,%s" % (BIND_CN, SUFFIX)
-BIND_PW = "password"
-
-NEW_ACCOUNT = "new_account"
-MAX_ACCOUNTS = 20
-
-CONFIG_MODDN_ACI_ATTR = "nsslapd-moddn-aci"
-
-
-class TopologyMaster1Master2(object):
- def __init__(self, master1, master2):
- master1.open()
- self.master1 = master1
-
- master2.open()
- self.master2 = master2
-
-
-(a)pytest.fixture(scope="module")
-def topology(request):
- '''
- This fixture is used to create a replicated topology for the 'module'.
- The replicated topology is MASTER1 <-> Master2.
- '''
- global installation1_prefix
- global installation2_prefix
-
- # allocate master1 on a given deployement
- master1 = DirSrv(verbose=False)
- if installation1_prefix:
- args_instance[SER_DEPLOYED_DIR] = installation1_prefix
-
- # Args for the master1 instance
- args_instance[SER_HOST] = HOST_MASTER_1
- args_instance[SER_PORT] = PORT_MASTER_1
- args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_1
- args_master = args_instance.copy()
- master1.allocate(args_master)
-
- # allocate master1 on a given deployement
- master2 = DirSrv(verbose=False)
- if installation2_prefix:
- args_instance[SER_DEPLOYED_DIR] = installation2_prefix
-
- # Args for the consumer instance
- args_instance[SER_HOST] = HOST_MASTER_2
- args_instance[SER_PORT] = PORT_MASTER_2
- args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_2
- args_master = args_instance.copy()
- master2.allocate(args_master)
-
- # Get the status of the instance and restart it if it exists
- instance_master1 = master1.exists()
- instance_master2 = master2.exists()
-
- # Remove all the instances
- if instance_master1:
- master1.delete()
- if instance_master2:
- master2.delete()
-
- # Create the instances
- master1.create()
- master1.open()
- master2.create()
- master2.open()
-
- #
- # Now prepare the Master-Consumer topology
- #
- # First Enable replication
- master1.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER_1)
- master2.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER_2)
-
- # Initialize the supplier->consumer
-
- properties = {RA_NAME: r'meTo_$host:$port',
- RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
- RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
- RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
- RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
- repl_agreement = master1.agreement.create(suffix=SUFFIX, host=master2.host, port=master2.port, properties=properties)
-
- if not repl_agreement:
- log.fatal("Fail to create a replica agreement")
- sys.exit(1)
-
- log.debug("%s created" % repl_agreement)
-
- properties = {RA_NAME: r'meTo_$host:$port',
- RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
- RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
- RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
- RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
- master2.agreement.create(suffix=SUFFIX, host=master1.host, port=master1.port, properties=properties)
-
- master1.agreement.init(SUFFIX, HOST_MASTER_2, PORT_MASTER_2)
- master1.waitForReplInit(repl_agreement)
-
- # Check replication is working fine
- if master1.testReplication(DEFAULT_SUFFIX, master2):
- log.info('Replication is working.')
- else:
- log.fatal('Replication is not working.')
- assert False
-
- # clear the tmp directory
- master1.clearTmpDir(__file__)
-
- # Here we have two instances master and consumer
- # with replication working.
- return TopologyMaster1Master2(master1, master2)
-
-
-def _bind_manager(topology):
- topology.master1.log.info("Bind as %s " % DN_DM)
- topology.master1.simple_bind_s(DN_DM, PASSWORD)
-
-
-def _bind_normal(topology):
- # bind as bind_entry
- topology.master1.log.info("Bind as %s" % BIND_DN)
- topology.master1.simple_bind_s(BIND_DN, BIND_PW)
-
-
-def _moddn_aci_deny_tree(topology, mod_type=None, target_from=STAGING_DN, target_to=PROD_EXCEPT_DN):
- '''
- It denies the access moddn_to in cn=except,cn=accounts,SUFFIX
- '''
- if mod_type is None:
- assert False
-
- ACI_TARGET_FROM = ""
- ACI_TARGET_TO = ""
- if target_from:
- ACI_TARGET_FROM = "(target_from = \"ldap:///%s\")" % (target_from)
- if target_to:
- ACI_TARGET_TO = "(target_to = \"ldap:///%s\")" % (target_to)
-
- ACI_ALLOW = "(version 3.0; acl \"Deny MODDN to prod_except\"; deny (moddn)"
- ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
- ACI_BODY = ACI_TARGET_TO + ACI_TARGET_FROM + ACI_ALLOW + ACI_SUBJECT
- mod = [(mod_type, 'aci', ACI_BODY)]
- #topology.master1.modify_s(SUFFIX, mod)
- topology.master1.log.info("Add a DENY aci under %s " % PROD_EXCEPT_DN)
- topology.master1.modify_s(PROD_EXCEPT_DN, mod)
-
-
-def _moddn_aci_staging_to_production(topology, mod_type=None, target_from=STAGING_DN, target_to=PRODUCTION_DN):
- if mod_type is None:
- assert False
-
- ACI_TARGET_FROM = ""
- ACI_TARGET_TO = ""
- if target_from:
- ACI_TARGET_FROM = "(target_from = \"ldap:///%s\")" % (target_from)
- if target_to:
- ACI_TARGET_TO = "(target_to = \"ldap:///%s\")" % (target_to)
-
- ACI_ALLOW = "(version 3.0; acl \"MODDN from staging to production\"; allow (moddn)"
- ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
- ACI_BODY = ACI_TARGET_FROM + ACI_TARGET_TO + ACI_ALLOW + ACI_SUBJECT
- mod = [(mod_type, 'aci', ACI_BODY)]
- topology.master1.modify_s(SUFFIX, mod)
-
-
-def _moddn_aci_from_production_to_staging(topology, mod_type=None):
- if mod_type is None:
- assert False
-
- ACI_TARGET = "(target_from = \"ldap:///%s\") (target_to = \"ldap:///%s\")" % (PRODUCTION_DN, STAGING_DN)
- ACI_ALLOW = "(version 3.0; acl \"MODDN from production to staging\"; allow (moddn)"
- ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
- ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
- mod = [(mod_type, 'aci', ACI_BODY)]
- topology.master1.modify_s(SUFFIX, mod)
-
-
-def test_ticket47553_init(topology):
- """
- Creates
- - a staging DIT
- - a production DIT
- - add accounts in staging DIT
- - enable ACL logging (commented for performance reason)
-
- """
-
- topology.master1.log.info("\n\n######################### INITIALIZATION ######################\n")
-
- # entry used to bind with
- topology.master1.log.info("Add %s" % BIND_DN)
- topology.master1.add_s(Entry((BIND_DN, {
- 'objectclass': "top person".split(),
- 'sn': BIND_CN,
- 'cn': BIND_CN,
- 'userpassword': BIND_PW})))
-
- # DIT for staging
- topology.master1.log.info("Add %s" % STAGING_DN)
- topology.master1.add_s(Entry((STAGING_DN, {
- 'objectclass': "top organizationalRole".split(),
- 'cn': STAGING_CN,
- 'description': "staging DIT"})))
-
- # DIT for production
- topology.master1.log.info("Add %s" % PRODUCTION_DN)
- topology.master1.add_s(Entry((PRODUCTION_DN, {
- 'objectclass': "top organizationalRole".split(),
- 'cn': PRODUCTION_CN,
- 'description': "production DIT"})))
-
- # DIT for production/except
- topology.master1.log.info("Add %s" % PROD_EXCEPT_DN)
- topology.master1.add_s(Entry((PROD_EXCEPT_DN, {
- 'objectclass': "top organizationalRole".split(),
- 'cn': EXCEPT_CN,
- 'description': "production except DIT"})))
-
- # enable acl error logging
- #mod = [(ldap.MOD_REPLACE, 'nsslapd-errorlog-level', '128')]
- #topology.master1.modify_s(DN_CONFIG, mod)
- #topology.master2.modify_s(DN_CONFIG, mod)
-
- # add dummy entries in the staging DIT
- for cpt in range(MAX_ACCOUNTS):
- name = "%s%d" % (NEW_ACCOUNT, cpt)
- topology.master1.add_s(Entry(("cn=%s,%s" % (name, STAGING_DN), {
- 'objectclass': "top person".split(),
- 'sn': name,
- 'cn': name})))
-
-
-def test_ticket47553_mode_default_add_deny(topology):
- '''
- This test case checks that the ADD operation fails (no ADD aci on production)
- '''
-
- topology.master1.log.info("\n\n######################### mode moddn_aci : ADD (should fail) ######################\n")
-
- _bind_normal(topology)
-
- #
- # First try to add an entry in production => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to add %s" % PRODUCTION_DN)
- name = "%s%d" % (NEW_ACCOUNT, 0)
- topology.master1.add_s(Entry(("cn=%s,%s" % (name, PRODUCTION_DN), {
- 'objectclass': "top person".split(),
- 'sn': name,
- 'cn': name})))
- assert 0 # this is an error, we should not be allowed to add an entry in production
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
-
-def test_ticket47553_mode_default_ger_no_moddn(topology):
- topology.master1.log.info("\n\n######################### mode moddn_aci : GER no moddn ######################\n")
- request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn: " + BIND_DN)
- msg_id = topology.master1.search_ext(PRODUCTION_DN, ldap.SCOPE_SUBTREE, "objectclass=*", serverctrls=[request_ctrl])
- rtype, rdata, rmsgid, response_ctrl = topology.master1.result3(msg_id)
- #ger={}
- value = ''
- for dn, attrs in rdata:
- topology.master1.log.info("dn: %s" % dn)
- value = attrs['entryLevelRights'][0]
-
- topology.master1.log.info("############### entryLevelRights: %r" % value)
- assert 'n' not in value
-
-
-def test_ticket47553_mode_default_ger_with_moddn(topology):
- '''
- This test case adds the moddn aci and check ger contains 'n'
- '''
-
- topology.master1.log.info("\n\n######################### mode moddn_aci: GER with moddn ######################\n")
-
- # successfull MOD with the ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
- request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn: " + BIND_DN)
- msg_id = topology.master1.search_ext(PRODUCTION_DN, ldap.SCOPE_SUBTREE, "objectclass=*", serverctrls=[request_ctrl])
- rtype, rdata, rmsgid, response_ctrl = topology.master1.result3(msg_id)
- #ger={}
- value = ''
- for dn, attrs in rdata:
- topology.master1.log.info("dn: %s" % dn)
- value = attrs['entryLevelRights'][0]
-
- topology.master1.log.info("############### entryLevelRights: %r" % value)
- assert 'n' in value
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
-
-def test_ticket47553_mode_switch_default_to_legacy(topology):
- '''
- This test switch the server from default mode to legacy
- '''
- topology.master1.log.info("\n\n######################### Disable the moddn aci mod ######################\n")
- _bind_manager(topology)
- mod = [(ldap.MOD_REPLACE, CONFIG_MODDN_ACI_ATTR, 'off')]
- topology.master1.modify_s(DN_CONFIG, mod)
-
-
-def test_ticket47553_mode_legacy_ger_no_moddn1(topology):
- topology.master1.log.info("\n\n######################### mode legacy 1: GER no moddn ######################\n")
- request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn: " + BIND_DN)
- msg_id = topology.master1.search_ext(PRODUCTION_DN, ldap.SCOPE_SUBTREE, "objectclass=*", serverctrls=[request_ctrl])
- rtype, rdata, rmsgid, response_ctrl = topology.master1.result3(msg_id)
- #ger={}
- value = ''
- for dn, attrs in rdata:
- topology.master1.log.info("dn: %s" % dn)
- value = attrs['entryLevelRights'][0]
-
- topology.master1.log.info("############### entryLevelRights: %r" % value)
- assert 'n' not in value
-
-
-def test_ticket47553_mode_legacy_ger_no_moddn2(topology):
- topology.master1.log.info("\n\n######################### mode legacy 2: GER no moddn ######################\n")
- # successfull MOD with the ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
- request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn: " + BIND_DN)
- msg_id = topology.master1.search_ext(PRODUCTION_DN, ldap.SCOPE_SUBTREE, "objectclass=*", serverctrls=[request_ctrl])
- rtype, rdata, rmsgid, response_ctrl = topology.master1.result3(msg_id)
- #ger={}
- value = ''
- for dn, attrs in rdata:
- topology.master1.log.info("dn: %s" % dn)
- value = attrs['entryLevelRights'][0]
-
- topology.master1.log.info("############### entryLevelRights: %r" % value)
- assert 'n' not in value
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
-
-def test_ticket47553_mode_legacy_ger_with_moddn(topology):
- topology.master1.log.info("\n\n######################### mode legacy : GER with moddn ######################\n")
-
- # being allowed to read/write the RDN attribute use to allow the RDN
- ACI_TARGET = "(target = \"ldap:///%s\")(targetattr=\"cn\")" % (PRODUCTION_DN)
- ACI_ALLOW = "(version 3.0; acl \"MODDN production changing the RDN attribute\"; allow (read,search,write)"
- ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
- ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
-
- # successfull MOD with the ACI
- _bind_manager(topology)
- mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
- topology.master1.modify_s(SUFFIX, mod)
- _bind_normal(topology)
-
- request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn: " + BIND_DN)
- msg_id = topology.master1.search_ext(PRODUCTION_DN, ldap.SCOPE_SUBTREE, "objectclass=*", serverctrls=[request_ctrl])
- rtype, rdata, rmsgid, response_ctrl = topology.master1.result3(msg_id)
- #ger={}
- value = ''
- for dn, attrs in rdata:
- topology.master1.log.info("dn: %s" % dn)
- value = attrs['entryLevelRights'][0]
-
- topology.master1.log.info("############### entryLevelRights: %r" % value)
- assert 'n' in value
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- mod = [(ldap.MOD_DELETE, 'aci', ACI_BODY)]
- topology.master1.modify_s(SUFFIX, mod)
- _bind_normal(topology)
-
-
-def test_ticket47553_final(topology):
- topology.master1.delete()
- topology.master2.delete()
- log.info('Testcase PASSED')
-
-
-def run_isolated():
- '''
- run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
- To run isolated without py.test, you need to
- - edit this file and comment '@pytest.fixture' line before 'topology' function.
- - set the installation prefix
- - run this program
- '''
- global installation1_prefix
- global installation2_prefix
- installation1_prefix = None
- installation2_prefix = None
-
- topo = topology(True)
- topo.master1.log.info("\n\n######################### Ticket 47553 ######################\n")
- test_ticket47553_init(topo)
-
- # Check that without appropriate aci we are not allowed to add/delete
- test_ticket47553_mode_default_add_deny(topo)
- test_ticket47553_mode_default_ger_no_moddn(topo)
- test_ticket47553_mode_default_ger_with_moddn(topo)
- test_ticket47553_mode_switch_default_to_legacy(topo)
- test_ticket47553_mode_legacy_ger_no_moddn1(topo)
- test_ticket47553_mode_legacy_ger_no_moddn2(topo)
- test_ticket47553_mode_legacy_ger_with_moddn(topo)
-
- test_ticket47553_final(topo)
-
-
-if __name__ == '__main__':
- run_isolated()
-
diff --git a/dirsrvtests/tickets/ticket47553_rdn_write_test.py b/dirsrvtests/tickets/ticket47553_rdn_write_test.py
deleted file mode 100644
index 15d334b..0000000
--- a/dirsrvtests/tickets/ticket47553_rdn_write_test.py
+++ /dev/null
@@ -1,143 +0,0 @@
-# --- BEGIN COPYRIGHT BLOCK ---
-# Copyright (C) 2015 Red Hat, Inc.
-# All rights reserved.
-#
-# License: GPL (version 3 or any later version).
-# See LICENSE for details.
-# --- END COPYRIGHT BLOCK ---
-#
-import os
-import sys
-import time
-import ldap
-import logging
-import pytest
-from lib389 import DirSrv, Entry, tools, tasks
-from lib389.tools import DirSrvTools
-from lib389._constants import *
-from lib389.properties import *
-from lib389.tasks import *
-from lib389.utils import *
-from ldap.controls.simple import GetEffectiveRightsControl
-
-logging.getLogger(__name__).setLevel(logging.DEBUG)
-log = logging.getLogger(__name__)
-
-installation1_prefix = None
-
-SRC_ENTRY_CN = "tuser"
-EXT_RDN = "01"
-DST_ENTRY_CN = SRC_ENTRY_CN + EXT_RDN
-
-SRC_ENTRY_DN = "cn=%s,%s" % (SRC_ENTRY_CN, SUFFIX)
-DST_ENTRY_DN = "cn=%s,%s" % (DST_ENTRY_CN, SUFFIX)
-
-
-class TopologyStandalone(object):
- def __init__(self, standalone):
- standalone.open()
- self.standalone = standalone
-
-
-(a)pytest.fixture(scope="module")
-def topology(request):
- global installation1_prefix
-
- # Creating standalone instance ...
- standalone = DirSrv(verbose=False)
- if installation1_prefix:
- args_instance[SER_DEPLOYED_DIR] = installation1_prefix
- args_instance[SER_HOST] = HOST_STANDALONE
- args_instance[SER_PORT] = PORT_STANDALONE
- args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
- args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX
- args_standalone = args_instance.copy()
- standalone.allocate(args_standalone)
- instance_standalone = standalone.exists()
- if instance_standalone:
- standalone.delete()
- standalone.create()
- standalone.open()
-
- # Clear out the tmp dir
- standalone.clearTmpDir(__file__)
-
- return TopologyStandalone(standalone)
-
-
-def test_ticket47553_rdn_write_init(topology):
- topology.standalone.log.info("\n\n######################### Add entry tuser ######################\n")
- topology.standalone.add_s(Entry((SRC_ENTRY_DN, {
- 'objectclass': "top person".split(),
- 'sn': SRC_ENTRY_CN,
- 'cn': SRC_ENTRY_CN})))
-
-
-def test_ticket47553_rdn_write_get_ger(topology):
- ANONYMOUS_DN = ""
- topology.standalone.log.info("\n\n######################### GER rights for anonymous ######################\n")
- request_ctrl = GetEffectiveRightsControl(criticality=True, authzId="dn:" + ANONYMOUS_DN)
- msg_id = topology.standalone.search_ext(SUFFIX, ldap.SCOPE_SUBTREE, "objectclass=*", serverctrls=[request_ctrl])
- rtype, rdata, rmsgid, response_ctrl = topology.standalone.result3(msg_id)
- value = ''
- for dn, attrs in rdata:
- topology.standalone.log.info("dn: %s" % dn)
- for value in attrs['entryLevelRights']:
- topology.standalone.log.info("############### entryLevelRights: %r" % value)
- assert 'n' not in value
-
-
-def test_ticket47553_rdn_write_modrdn_anonymous(topology):
- ANONYMOUS_DN = ""
- topology.standalone.close()
- topology.standalone.binddn = ANONYMOUS_DN
- topology.standalone.open()
- msg_id = topology.standalone.search_ext("", ldap.SCOPE_BASE, "objectclass=*")
- rtype, rdata, rmsgid, response_ctrl = topology.standalone.result3(msg_id)
- for dn, attrs in rdata:
- topology.standalone.log.info("dn: %s" % dn)
- for attr in attrs:
- topology.standalone.log.info("############### %r: %r" % (attr, attrs[attr]))
-
- try:
- topology.standalone.rename_s(SRC_ENTRY_DN, "cn=%s" % DST_ENTRY_CN, delold=True)
- except Exception as e:
- topology.standalone.log.info("Exception (expected): %s" % type(e).__name__)
- isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- try:
- topology.standalone.getEntry(DST_ENTRY_DN, ldap.SCOPE_BASE, "objectclass=*")
- assert False
- except Exception as e:
- topology.standalone.log.info("The entry was not renamed (expected)")
- isinstance(e, ldap.NO_SUCH_OBJECT)
-
-
-def test_ticket47553_rdn_write(topology):
- '''
- Write your testcase here...
- '''
-
- log.info('Test complete')
-
-
-def test_ticket47553_rdn_write_final(topology):
- topology.standalone.delete()
- log.info('Testcase PASSED')
-
-
-def run_isolated():
- global installation1_prefix
- installation1_prefix = '/home/tbordaz/install_master'
-
- topo = topology(True)
- test_ticket47553_rdn_write_init(topo)
- test_ticket47553_rdn_write_get_ger(topo)
- test_ticket47553_rdn_write(topo)
- test_ticket47553_rdn_write_modrdn_anonymous(topo)
- test_ticket47553_rdn_write_final(topo)
-
-
-if __name__ == '__main__':
- run_isolated()
-
diff --git a/dirsrvtests/tickets/ticket47553_single_aci_test.py b/dirsrvtests/tickets/ticket47553_single_aci_test.py
deleted file mode 100644
index 1c0b88b..0000000
--- a/dirsrvtests/tickets/ticket47553_single_aci_test.py
+++ /dev/null
@@ -1,1137 +0,0 @@
-# --- BEGIN COPYRIGHT BLOCK ---
-# Copyright (C) 2015 Red Hat, Inc.
-# All rights reserved.
-#
-# License: GPL (version 3 or any later version).
-# See LICENSE for details.
-# --- END COPYRIGHT BLOCK ---
-#
-'''
-Created on Nov 7, 2013
-
-@author: tbordaz
-'''
-import os
-import sys
-import time
-import ldap
-import logging
-import pytest
-from lib389 import DirSrv, Entry, tools
-from lib389.tools import DirSrvTools
-from lib389._constants import *
-from lib389.properties import *
-from lib389._constants import REPLICAROLE_MASTER
-
-logging.getLogger(__name__).setLevel(logging.DEBUG)
-log = logging.getLogger(__name__)
-
-#
-# important part. We can deploy Master1 and Master2 on different versions
-#
-installation1_prefix = None
-installation2_prefix = None
-
-TEST_REPL_DN = "cn=test_repl, %s" % SUFFIX
-
-STAGING_CN = "staged user"
-PRODUCTION_CN = "accounts"
-EXCEPT_CN = "excepts"
-
-STAGING_DN = "cn=%s,%s" % (STAGING_CN, SUFFIX)
-PRODUCTION_DN = "cn=%s,%s" % (PRODUCTION_CN, SUFFIX)
-PROD_EXCEPT_DN = "cn=%s,%s" % (EXCEPT_CN, PRODUCTION_DN)
-
-STAGING_PATTERN = "cn=%s*,%s" % (STAGING_CN[:2], SUFFIX)
-PRODUCTION_PATTERN = "cn=%s*,%s" % (PRODUCTION_CN[:2], SUFFIX)
-BAD_STAGING_PATTERN = "cn=bad*,%s" % (SUFFIX)
-BAD_PRODUCTION_PATTERN = "cn=bad*,%s" % (SUFFIX)
-
-BIND_CN = "bind_entry"
-BIND_DN = "cn=%s,%s" % (BIND_CN, SUFFIX)
-BIND_PW = "password"
-
-NEW_ACCOUNT = "new_account"
-MAX_ACCOUNTS = 20
-
-CONFIG_MODDN_ACI_ATTR = "nsslapd-moddn-aci"
-
-
-class TopologyMaster1Master2(object):
- def __init__(self, master1, master2):
- master1.open()
- self.master1 = master1
-
- master2.open()
- self.master2 = master2
-
-
-(a)pytest.fixture(scope="module")
-def topology(request):
- '''
- This fixture is used to create a replicated topology for the 'module'.
- The replicated topology is MASTER1 <-> Master2.
- '''
- global installation1_prefix
- global installation2_prefix
-
- # allocate master1 on a given deployement
- master1 = DirSrv(verbose=False)
- if installation1_prefix:
- args_instance[SER_DEPLOYED_DIR] = installation1_prefix
-
- # Args for the master1 instance
- args_instance[SER_HOST] = HOST_MASTER_1
- args_instance[SER_PORT] = PORT_MASTER_1
- args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_1
- args_master = args_instance.copy()
- master1.allocate(args_master)
-
- # allocate master1 on a given deployement
- master2 = DirSrv(verbose=False)
- if installation2_prefix:
- args_instance[SER_DEPLOYED_DIR] = installation2_prefix
-
- # Args for the consumer instance
- args_instance[SER_HOST] = HOST_MASTER_2
- args_instance[SER_PORT] = PORT_MASTER_2
- args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_2
- args_master = args_instance.copy()
- master2.allocate(args_master)
-
- # Get the status of the instance
- instance_master1 = master1.exists()
- instance_master2 = master2.exists()
-
- # Remove all the instances
- if instance_master1:
- master1.delete()
- if instance_master2:
- master2.delete()
-
- # Create the instances
- master1.create()
- master1.open()
- master2.create()
- master2.open()
-
- #
- # Now prepare the Master-Consumer topology
- #
- # First Enable replication
- master1.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER_1)
- master2.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER_2)
-
- # Initialize the supplier->consumer
-
- properties = {RA_NAME: r'meTo_$host:$port',
- RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
- RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
- RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
- RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
- repl_agreement = master1.agreement.create(suffix=SUFFIX, host=master2.host, port=master2.port, properties=properties)
-
- if not repl_agreement:
- log.fatal("Fail to create a replica agreement")
- sys.exit(1)
-
- log.debug("%s created" % repl_agreement)
-
- properties = {RA_NAME: r'meTo_$host:$port',
- RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
- RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
- RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
- RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
- master2.agreement.create(suffix=SUFFIX, host=master1.host, port=master1.port, properties=properties)
-
- master1.agreement.init(SUFFIX, HOST_MASTER_2, PORT_MASTER_2)
- master1.waitForReplInit(repl_agreement)
-
- # Check replication is working fine
- if master1.testReplication(DEFAULT_SUFFIX, master2):
- log.info('Replication is working.')
- else:
- log.fatal('Replication is not working.')
- assert False
-
- # clear the tmp directory
- master1.clearTmpDir(__file__)
-
- # Here we have two instances master and consumer
- # with replication working.
- return TopologyMaster1Master2(master1, master2)
-
-
-def _bind_manager(topology):
- topology.master1.log.info("Bind as %s " % DN_DM)
- topology.master1.simple_bind_s(DN_DM, PASSWORD)
-
-
-def _bind_normal(topology):
- # bind as bind_entry
- topology.master1.log.info("Bind as %s" % BIND_DN)
- topology.master1.simple_bind_s(BIND_DN, BIND_PW)
-
-
-def _moddn_aci_deny_tree(topology, mod_type=None, target_from=STAGING_DN, target_to=PROD_EXCEPT_DN):
- '''
- It denies the access moddn_to in cn=except,cn=accounts,SUFFIX
- '''
- assert mod_type is not None
-
- ACI_TARGET_FROM = ""
- ACI_TARGET_TO = ""
- if target_from:
- ACI_TARGET_FROM = "(target_from = \"ldap:///%s\")" % (target_from)
- if target_to:
- ACI_TARGET_TO = "(target_to = \"ldap:///%s\")" % (target_to)
-
- ACI_ALLOW = "(version 3.0; acl \"Deny MODDN to prod_except\"; deny (moddn)"
- ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
- ACI_BODY = ACI_TARGET_TO + ACI_TARGET_FROM + ACI_ALLOW + ACI_SUBJECT
- mod = [(mod_type, 'aci', ACI_BODY)]
- #topology.master1.modify_s(SUFFIX, mod)
- topology.master1.log.info("Add a DENY aci under %s " % PROD_EXCEPT_DN)
- topology.master1.modify_s(PROD_EXCEPT_DN, mod)
-
-def _write_aci_staging(topology, mod_type=None):
- assert mod_type is not None
-
- ACI_TARGET = "(targetattr= \"cn\")(target=\"ldap:///cn=*,%s\")" % STAGING_DN
- ACI_ALLOW = "(version 3.0; acl \"write staging entries\"; allow (write)"
- ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
- ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
- mod = [(mod_type, 'aci', ACI_BODY)]
- topology.master1.modify_s(SUFFIX, mod)
-
-def _write_aci_production(topology, mod_type=None):
- assert mod_type is not None
-
- ACI_TARGET = "(targetattr= \"cn\")(target=\"ldap:///cn=*,%s\")" % PRODUCTION_DN
- ACI_ALLOW = "(version 3.0; acl \"write production entries\"; allow (write)"
- ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
- ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
- mod = [(mod_type, 'aci', ACI_BODY)]
- topology.master1.modify_s(SUFFIX, mod)
-
-def _moddn_aci_staging_to_production(topology, mod_type=None, target_from=STAGING_DN, target_to=PRODUCTION_DN):
- assert mod_type != None
-
-def _moddn_aci_staging_to_production(topology, mod_type=None, target_from=STAGING_DN, target_to=PRODUCTION_DN):
- assert mod_type is not None
-
- ACI_TARGET_FROM = ""
- ACI_TARGET_TO = ""
- if target_from:
- ACI_TARGET_FROM = "(target_from = \"ldap:///%s\")" % (target_from)
- if target_to:
- ACI_TARGET_TO = "(target_to = \"ldap:///%s\")" % (target_to)
-
- ACI_ALLOW = "(version 3.0; acl \"MODDN from staging to production\"; allow (moddn)"
- ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
- ACI_BODY = ACI_TARGET_FROM + ACI_TARGET_TO + ACI_ALLOW + ACI_SUBJECT
- mod = [(mod_type, 'aci', ACI_BODY)]
- topology.master1.modify_s(SUFFIX, mod)
-
- _write_aci_staging(topology, mod_type=mod_type)
-
-
-def _moddn_aci_from_production_to_staging(topology, mod_type=None):
- assert mod_type is not None
-
- ACI_TARGET = "(target_from = \"ldap:///%s\") (target_to = \"ldap:///%s\")" % (PRODUCTION_DN, STAGING_DN)
- ACI_ALLOW = "(version 3.0; acl \"MODDN from production to staging\"; allow (moddn)"
- ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
- ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
- mod = [(mod_type, 'aci', ACI_BODY)]
- topology.master1.modify_s(SUFFIX, mod)
-
- _write_aci_production(topology, mod_type=mod_type)
-
-
-def test_ticket47553_init(topology):
- """
- Creates
- - a staging DIT
- - a production DIT
- - add accounts in staging DIT
- - enable ACL logging (commented for performance reason)
-
- """
-
- topology.master1.log.info("\n\n######################### INITIALIZATION ######################\n")
-
- # entry used to bind with
- topology.master1.log.info("Add %s" % BIND_DN)
- topology.master1.add_s(Entry((BIND_DN, {
- 'objectclass': "top person".split(),
- 'sn': BIND_CN,
- 'cn': BIND_CN,
- 'userpassword': BIND_PW})))
-
- # DIT for staging
- topology.master1.log.info("Add %s" % STAGING_DN)
- topology.master1.add_s(Entry((STAGING_DN, {
- 'objectclass': "top organizationalRole".split(),
- 'cn': STAGING_CN,
- 'description': "staging DIT"})))
-
- # DIT for production
- topology.master1.log.info("Add %s" % PRODUCTION_DN)
- topology.master1.add_s(Entry((PRODUCTION_DN, {
- 'objectclass': "top organizationalRole".split(),
- 'cn': PRODUCTION_CN,
- 'description': "production DIT"})))
-
- # DIT for production/except
- topology.master1.log.info("Add %s" % PROD_EXCEPT_DN)
- topology.master1.add_s(Entry((PROD_EXCEPT_DN, {
- 'objectclass': "top organizationalRole".split(),
- 'cn': EXCEPT_CN,
- 'description': "production except DIT"})))
-
- # enable acl error logging
- mod = [(ldap.MOD_REPLACE, 'nsslapd-errorlog-level', str(128+262144))]
- topology.master1.modify_s(DN_CONFIG, mod)
- topology.master2.modify_s(DN_CONFIG, mod)
-
- # add dummy entries in the staging DIT
- for cpt in range(MAX_ACCOUNTS):
- name = "%s%d" % (NEW_ACCOUNT, cpt)
- topology.master1.add_s(Entry(("cn=%s,%s" % (name, STAGING_DN), {
- 'objectclass': "top person".split(),
- 'sn': name,
- 'cn': name})))
-
-
-def test_ticket47553_add(topology):
- '''
- This test case checks that the ADD operation fails (no ADD aci on production)
- '''
-
- topology.master1.log.info("\n\n######################### ADD (should fail) ######################\n")
-
- _bind_normal(topology)
-
- #
- # First try to add an entry in production => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to add %s" % PRODUCTION_DN)
- name = "%s%d" % (NEW_ACCOUNT, 0)
- topology.master1.add_s(Entry(("cn=%s,%s" % (name, PRODUCTION_DN), {
- 'objectclass': "top person".split(),
- 'sn': name,
- 'cn': name})))
- assert 0 # this is an error, we should not be allowed to add an entry in production
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
-
-def test_ticket47553_delete(topology):
- '''
- This test case checks that the DEL operation fails (no 'delete' aci on production)
- '''
-
- topology.master1.log.info("\n\n######################### DELETE (should fail) ######################\n")
-
- _bind_normal(topology)
- #
- # Second try to delete an entry in staging => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to delete %s" % STAGING_DN)
- name = "%s%d" % (NEW_ACCOUNT, 0)
- topology.master1.delete_s("cn=%s,%s" % (name, STAGING_DN))
- assert 0 # this is an error, we should not be allowed to add an entry in production
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
-
-def test_ticket47553_moddn_staging_prod_0(topology):
- '''
- This test case MOVE entry NEW_ACCOUNT0 from staging to prod
- target_to/target_from: equality filter
- '''
-
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (0) ######################\n")
- _bind_normal(topology)
-
- old_rdn = "cn=%s0" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
-
- # successfull MOD with the ACI
- topology.master1.log.info("\n\n######################### MOVE to and from equality filter ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
-
-def test_ticket47553_moddn_staging_prod_1(topology):
- '''
- This test case MOVE entry NEW_ACCOUNT1 from staging to prod
- target_to/target_from: substring/equality filter
- '''
-
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (1) ######################\n")
- _bind_normal(topology)
-
- old_rdn = "cn=%s1" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
-
- # successfull MOD with the ACI
- topology.master1.log.info("\n\n######################### MOVE to substring/ from equality filter ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_DN, target_to=PRODUCTION_PATTERN)
- _bind_normal(topology)
-
-
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_DN, target_to=PRODUCTION_PATTERN)
- _bind_normal(topology)
-
-
-def test_ticket47553_moddn_staging_prod_2(topology):
- '''
- This test case fails to MOVE entry NEW_ACCOUNT2 from staging to prod
- because of bad pattern
- '''
-
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (2) ######################\n")
- _bind_normal(topology)
-
- old_rdn = "cn=%s2" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
-
- # successfull MOD with the ACI
- topology.master1.log.info("\n\n######################### MOVE to substring (BAD)/ from equality filter ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_DN, target_to=BAD_PRODUCTION_PATTERN)
- _bind_normal(topology)
-
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_DN, target_to=BAD_PRODUCTION_PATTERN)
- _bind_normal(topology)
-
-
-def test_ticket47553_moddn_staging_prod_3(topology):
- '''
- This test case MOVE entry NEW_ACCOUNT3 from staging to prod
- target_to/target_from: equality/substring filter
- '''
-
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (3) ######################\n")
- _bind_normal(topology)
-
- old_rdn = "cn=%s3" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
-
- # successfull MOD with the ACI
- topology.master1.log.info("\n\n######################### MOVE to:equality filter / from substring filter ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_PATTERN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_PATTERN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
-
-def test_ticket47553_moddn_staging_prod_4(topology):
- '''
- This test case fails to MOVE entry NEW_ACCOUNT4 from staging to prod
- because of bad pattern
- '''
-
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (4) ######################\n")
- _bind_normal(topology)
-
- old_rdn = "cn=%s4" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- # successfull MOD with the ACI
- topology.master1.log.info("\n\n######################### MOVE to: equality filter/ from: substring (BAD) ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=BAD_STAGING_PATTERN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=BAD_STAGING_PATTERN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
-
-def test_ticket47553_moddn_staging_prod_5(topology):
- '''
- This test case MOVE entry NEW_ACCOUNT5 from staging to prod
- target_to/target_from: substring/substring filter
- '''
-
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (5) ######################\n")
- _bind_normal(topology)
-
- old_rdn = "cn=%s5" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- # successfull MOD with the ACI
- topology.master1.log.info("\n\n######################### MOVE to:substring filter / from: substring filter ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_PATTERN, target_to=PRODUCTION_PATTERN)
- _bind_normal(topology)
-
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_PATTERN, target_to=PRODUCTION_PATTERN)
- _bind_normal(topology)
-
-
-def test_ticket47553_moddn_staging_prod_6(topology):
- '''
- This test case MOVE entry NEW_ACCOUNT6 from staging to prod
- target_to/target_from: substring/<enmpty> filter
- '''
-
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (6) ######################\n")
- _bind_normal(topology)
-
- old_rdn = "cn=%s6" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- # successfull MOD with the ACI
- topology.master1.log.info("\n\n######################### MOVE to:substring filter / from: empty ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=None, target_to=PRODUCTION_PATTERN)
- _bind_normal(topology)
-
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=None, target_to=PRODUCTION_PATTERN)
- _bind_normal(topology)
-
-
-def test_ticket47553_moddn_staging_prod_7(topology):
- '''
- This test case MOVE entry NEW_ACCOUNT7 from staging to prod
- target_to/target_from: <empty>/substring filter
- '''
-
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (7) ######################\n")
- _bind_normal(topology)
-
- old_rdn = "cn=%s7" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- # successfull MOD with the ACI
- topology.master1.log.info("\n\n######################### MOVE to: empty/ from: substring filter ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_PATTERN, target_to=None)
- _bind_normal(topology)
-
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_PATTERN, target_to=None)
- _bind_normal(topology)
-
-
-def test_ticket47553_moddn_staging_prod_8(topology):
- '''
- This test case MOVE entry NEW_ACCOUNT8 from staging to prod
- target_to/target_from: <empty>/<empty> filter
- '''
-
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (8) ######################\n")
- _bind_normal(topology)
-
- old_rdn = "cn=%s8" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- # successfull MOD with the ACI
- topology.master1.log.info("\n\n######################### MOVE to: empty/ from: empty ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=None, target_to=None)
- _bind_normal(topology)
-
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=None, target_to=None)
- _bind_normal(topology)
-
-
-def test_ticket47553_moddn_staging_prod_9(topology):
- '''
- This test case disable the 'moddn' right so a MODDN requires a 'add' right
- to be successfull.
- It fails to MOVE entry NEW_ACCOUNT9 from staging to prod.
- Add a 'add' right to prod.
- Then it succeeds to MOVE NEW_ACCOUNT9 from staging to prod.
-
- Then enable the 'moddn' right so a MODDN requires a 'moddn' right
- It fails to MOVE entry NEW_ACCOUNT10 from staging to prod.
- Add a 'moddn' right to prod.
- Then it succeeds to MOVE NEW_ACCOUNT10 from staging to prod.
- '''
-
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (9) ######################\n")
-
- _bind_normal(topology)
- old_rdn = "cn=%s9" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- ############################################
- # Now do tests with no support of moddn aci
- ############################################
- topology.master1.log.info("Disable the moddn right")
- _bind_manager(topology)
- mod = [(ldap.MOD_REPLACE, CONFIG_MODDN_ACI_ATTR, 'off')]
- topology.master1.modify_s(DN_CONFIG, mod)
-
- # Add the moddn aci that will not be evaluated because of the config flag
- topology.master1.log.info("\n\n######################### MOVE to and from equality filter ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
- # It will fail because it will test the ADD right
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- # remove the moddn aci
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
- #
- # add the 'add' right to the production DN
- # Then do a successfull moddn
- #
- ACI_ALLOW = "(version 3.0; acl \"ADD rights to allow moddn\"; allow (add)"
- ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
- ACI_BODY = ACI_ALLOW + ACI_SUBJECT
-
- _bind_manager(topology)
- mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
- topology.master1.modify_s(PRODUCTION_DN, mod)
- _write_aci_staging(topology, mod_type=ldap.MOD_ADD)
- _bind_normal(topology)
-
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
-
- _bind_manager(topology)
- mod = [(ldap.MOD_DELETE, 'aci', ACI_BODY)]
- topology.master1.modify_s(PRODUCTION_DN, mod)
- _write_aci_staging(topology, mod_type=ldap.MOD_DELETE)
- _bind_normal(topology)
-
- ############################################
- # Now do tests with support of moddn aci
- ############################################
- topology.master1.log.info("Enable the moddn right")
- _bind_manager(topology)
- mod = [(ldap.MOD_REPLACE, CONFIG_MODDN_ACI_ATTR, 'on')]
- topology.master1.modify_s(DN_CONFIG, mod)
-
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (10) ######################\n")
-
- _bind_normal(topology)
- old_rdn = "cn=%s10" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- #
- # add the 'add' right to the production DN
- # Then do a failing moddn
- #
- ACI_ALLOW = "(version 3.0; acl \"ADD rights to allow moddn\"; allow (add)"
- ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
- ACI_BODY = ACI_ALLOW + ACI_SUBJECT
-
- _bind_manager(topology)
- mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
- topology.master1.modify_s(PRODUCTION_DN, mod)
- _write_aci_staging(topology, mod_type=ldap.MOD_ADD)
- _bind_normal(topology)
-
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- _bind_manager(topology)
- mod = [(ldap.MOD_DELETE, 'aci', ACI_BODY)]
- topology.master1.modify_s(PRODUCTION_DN, mod)
- _write_aci_staging(topology, mod_type=ldap.MOD_DELETE)
- _bind_normal(topology)
-
- # Add the moddn aci that will be evaluated because of the config flag
- topology.master1.log.info("\n\n######################### MOVE to and from equality filter ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
-
- # remove the moddn aci
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
-
-def test_ticket47553_moddn_prod_staging(topology):
- '''
- This test checks that we can move ACCOUNT11 from staging to prod
- but not move back ACCOUNT11 from prod to staging
- '''
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (11) ######################\n")
-
- _bind_normal(topology)
-
- old_rdn = "cn=%s11" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- # successfull MOD with the ACI
- topology.master1.log.info("\n\n######################### MOVE to and from equality filter ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
-
- # Now check we can not move back the entry to staging
- old_rdn = "cn=%s11" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, PRODUCTION_DN)
- new_rdn = old_rdn
- new_superior = STAGING_DN
-
- # add the write right because we want to check the moddn
- _bind_manager(topology)
- _write_aci_production(topology, mod_type=ldap.MOD_ADD)
- _bind_normal(topology)
-
- try:
- topology.master1.log.info("Try to move back MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- _bind_manager(topology)
- _write_aci_production(topology, mod_type=ldap.MOD_DELETE)
- _bind_normal(topology)
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _bind_normal(topology)
-
-
-def test_ticket47553_check_repl_M2_to_M1(topology):
- '''
- Checks that replication is still working M2->M1, using ACCOUNT12
- '''
-
- topology.master1.log.info("Bind as %s (M2)" % DN_DM)
- topology.master2.simple_bind_s(DN_DM, PASSWORD)
-
- rdn = "cn=%s12" % NEW_ACCOUNT
- dn = "%s,%s" % (rdn, STAGING_DN)
-
- # First wait for the ACCOUNT19 entry being replicated on M2
- loop = 0
- while loop <= 10:
- try:
- ent = topology.master2.getEntry(dn, ldap.SCOPE_BASE, "(objectclass=*)")
- break
- except ldap.NO_SUCH_OBJECT:
- time.sleep(1)
- loop += 1
- assert loop <= 10
-
- attribute = 'description'
- tested_value = 'Hello world'
- mod = [(ldap.MOD_ADD, attribute, tested_value)]
- topology.master1.log.info("Update (M2) %s (%s)" % (dn, attribute))
- topology.master2.modify_s(dn, mod)
-
- loop = 0
- while loop <= 10:
- ent = topology.master1.getEntry(dn, ldap.SCOPE_BASE, "(objectclass=*)")
- assert ent is not None
- if ent.hasAttr(attribute) and (ent.getValue(attribute) == tested_value):
- break
-
- time.sleep(1)
- loop += 1
- assert loop < 10
- topology.master1.log.info("Update %s (%s) replicated on M1" % (dn, attribute))
-
-
-def test_ticket47553_moddn_staging_prod_except(topology):
- '''
- This test case MOVE entry NEW_ACCOUNT13 from staging to prod
- but fails to move entry NEW_ACCOUNT14 from staging to prod_except
- '''
-
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod (13) ######################\n")
- _bind_normal(topology)
-
- old_rdn = "cn=%s13" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PRODUCTION_DN
-
- #
- # Try to rename without the apropriate ACI => INSUFFICIENT_ACCESS
- #
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- # successfull MOD with the ACI
- topology.master1.log.info("\n\n######################### MOVE to and from equality filter ######################\n")
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _moddn_aci_deny_tree(topology, mod_type=ldap.MOD_ADD)
- _bind_normal(topology)
-
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
-
- #
- # Now try to move an entry under except
- #
- topology.master1.log.info("\n\n######################### MOVE staging -> Prod/Except (14) ######################\n")
- old_rdn = "cn=%s14" % NEW_ACCOUNT
- old_dn = "%s,%s" % (old_rdn, STAGING_DN)
- new_rdn = old_rdn
- new_superior = PROD_EXCEPT_DN
- try:
- topology.master1.log.info("Try to MODDN %s -> %s,%s" % (old_dn, new_rdn, new_superior))
- topology.master1.rename_s(old_dn, new_rdn, newsuperior=new_superior)
- assert 0
- except AssertionError:
- topology.master1.log.info("Exception (not really expected exception but that is fine as it fails to rename)")
- except Exception as e:
- topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
- assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
-
- # successfull MOD with the both ACI
- _bind_manager(topology)
- _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_DN, target_to=PRODUCTION_DN)
- _moddn_aci_deny_tree(topology, mod_type=ldap.MOD_DELETE)
- _bind_normal(topology)
-
-
-def test_ticket47553_final(topology):
- topology.master1.delete()
- topology.master2.delete()
- log.info('Testcase PASSED')
-
-
-def run_isolated():
- '''
- run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
- To run isolated without py.test, you need to
- - edit this file and comment '@pytest.fixture' line before 'topology' function.
- - set the installation prefix
- - run this program
- '''
- global installation1_prefix
- global installation2_prefix
- installation1_prefix = None
- installation2_prefix = None
-
- topo = topology(True)
- topo.master1.log.info("\n\n######################### Ticket 47553 ######################\n")
- test_ticket47553_init(topo)
-
- # Check that without appropriate aci we are not allowed to add/delete
- test_ticket47553_add(topo)
- test_ticket47553_delete(topo)
-
- # tests the ACI as equality/substring filter
- test_ticket47553_moddn_staging_prod_0(topo)
- test_ticket47553_moddn_staging_prod_1(topo)
- test_ticket47553_moddn_staging_prod_2(topo)
- test_ticket47553_moddn_staging_prod_3(topo)
- test_ticket47553_moddn_staging_prod_4(topo)
- test_ticket47553_moddn_staging_prod_5(topo)
-
- # tests the ACI with undefined 'target_to'/'target_from'
- test_ticket47553_moddn_staging_prod_6(topo)
- test_ticket47553_moddn_staging_prod_7(topo)
- test_ticket47553_moddn_staging_prod_8(topo)
-
- # Check we can control the behavior with nsslapd-moddn-aci
- test_ticket47553_moddn_staging_prod_9(topo)
-
- # Check we can move entry 'from' -> 'to' but not 'to' -> 'from'
- test_ticket47553_moddn_prod_staging(topo)
-
- # check replication is still working
- test_ticket47553_check_repl_M2_to_M1(topo)
-
- # check DENY rule is working
- test_ticket47553_moddn_staging_prod_except(topo)
-
- test_ticket47553_final(topo)
-
-
-if __name__ == '__main__':
- run_isolated()
-
8 years, 6 months
Branch '389-ds-base-1.2.11' - ldap/servers
by Noriko Hosoi
ldap/servers/slapd/log.c | 109 ++++++++++++++++++++++++++++-------------------
1 file changed, 67 insertions(+), 42 deletions(-)
New commits:
commit 217ea08b60eedb2da254517d47991ab0d42e578a
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Thu Oct 8 10:30:07 2015 -0700
Ticket #48304 - ns-slapd - LOGINFO:Unable to remove file
Description: In the log rotation, if a log file to be deleted does
not exist, the "Unable to remove file" is logged in the error log,
which is not necessary.
This patch updates the logging code to suppress the unnecessary log
messages as well as replace with more detailed ones.
https://fedorahosted.org/389/ticket/48304
Reviewed by mreynolds(a)redhat.com (Thank you, Mark!!)
(cherry picked from commit e2abffcc5cf6e63136fc0bcb5b0e12830cca22a5)
(cherry picked from commit 6c71c0d96d2287bcae88942ce6d5a0f7df5bee84)
(cherry picked from commit 8081a91a7a1714396a377871d1f676f000d7a4d5)
diff --git a/ldap/servers/slapd/log.c b/ldap/servers/slapd/log.c
index 3a31260..4db8946 100644
--- a/ldap/servers/slapd/log.c
+++ b/ldap/servers/slapd/log.c
@@ -2466,15 +2466,25 @@ log__delete_access_logfile()
loginfo.log_access_fdes = NULL;
PR_snprintf (buffer, sizeof(buffer), "%s", loginfo.log_access_file);
if (PR_Delete(buffer) != PR_SUCCESS) {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s\n", loginfo.log_access_file,0,0);
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_access_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s error %d (%s)\n",
+ loginfo.log_access_file, prerr, slapd_pr_strerror(prerr));
+ }
}
/* Delete the rotation file also. */
PR_snprintf (buffer, sizeof(buffer), "%s.rotationinfo", loginfo.log_access_file);
if (PR_Delete(buffer) != PR_SUCCESS) {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s.rotationinfo\n", loginfo.log_access_file,0,0);
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_access_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s.rotationinfo error %d (%s)\n",
+ loginfo.log_access_file, prerr, slapd_pr_strerror(prerr));
+ }
}
return 0;
}
@@ -2576,15 +2586,15 @@ delete_logfile:
log_convert_time (delete_logp->l_ctime, tbuf, 1 /*short */);
PR_snprintf (buffer, sizeof(buffer), "%s.%s", loginfo.log_access_file, tbuf);
if (PR_Delete(buffer) != PR_SUCCESS) {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s.%s\n",
- loginfo.log_access_file,tbuf,0);
-
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_access_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s.%s error %d (%s)\n",
+ loginfo.log_access_file, tbuf, prerr, slapd_pr_strerror(prerr));
+ }
} else {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Removed file:%s.%s because of (%s)\n",
- loginfo.log_access_file, tbuf,
- logstr);
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Removed file:%s.%s because of (%s)\n", loginfo.log_access_file, tbuf, logstr);
}
slapi_ch_free((void**)&delete_logp);
loginfo.log_numof_access_logs--;
@@ -3246,7 +3256,6 @@ log__delete_error_logfile(int locked)
char buffer[BUFSIZ];
char tbuf[TBUFSIZE];
-
/* If we have only one log, then will delete this one */
if (loginfo.log_error_maxnumlogs == 1) {
LOG_CLOSE(loginfo.log_error_fdes);
@@ -3254,10 +3263,14 @@ log__delete_error_logfile(int locked)
PR_snprintf (buffer, sizeof(buffer), "%s", loginfo.log_error_file);
if (PR_Delete(buffer) != PR_SUCCESS) {
if (!locked) {
- /* if locked, we should not call LDAPDebug,
- which tries to get a lock internally. */
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s\n", loginfo.log_error_file,0,0);
+ /* If locked, we should not call LDAPDebug, which tries to get a lock internally. */
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_error_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s error %d (%s)\n",
+ loginfo.log_error_file, prerr, slapd_pr_strerror(prerr));
+ }
}
}
@@ -3265,11 +3278,14 @@ log__delete_error_logfile(int locked)
PR_snprintf (buffer, sizeof(buffer), "%s.rotationinfo", loginfo.log_error_file);
if (PR_Delete(buffer) != PR_SUCCESS) {
if (!locked) {
- /* if locked, we should not call LDAPDebug,
- which tries to get a lock internally. */
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s.rotationinfo\n",
- loginfo.log_error_file,0,0);
+ /* If locked, we should not call LDAPDebug, which tries to get a lock internally. */
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_error_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s.rotationinfo error %d (%s)\n",
+ loginfo.log_error_file, prerr, slapd_pr_strerror(prerr));
+ }
}
}
return 0;
@@ -3381,10 +3397,11 @@ delete_logfile:
PR_snprintf (buffer, sizeof(buffer), "%s.%s", loginfo.log_error_file, tbuf);
if (PR_Delete(buffer) != PR_SUCCESS) {
PRErrorCode prerr = PR_GetError();
- PR_snprintf(buffer, sizeof(buffer),
- "LOGINFO:Unable to remove file:%s.%s error %d (%s)\n",
- loginfo.log_error_file, tbuf, prerr, slapd_pr_strerror(prerr));
- log__error_emergency(buffer, 0, locked);
+ if (PR_FILE_NOT_FOUND_ERROR != prerr) {
+ PR_snprintf(buffer, sizeof(buffer), "LOGINFO:Unable to remove file:%s.%s error %d (%s)\n",
+ loginfo.log_error_file, tbuf, prerr, slapd_pr_strerror(prerr));
+ log__error_emergency(buffer, 0, locked);
+ }
}
slapi_ch_free((void**)&delete_logp);
loginfo.log_numof_error_logs--;
@@ -3424,15 +3441,25 @@ log__delete_audit_logfile()
loginfo.log_audit_fdes = NULL;
PR_snprintf(buffer, sizeof(buffer), "%s", loginfo.log_audit_file);
if (PR_Delete(buffer) != PR_SUCCESS) {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s\n", loginfo.log_audit_file,0,0);
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_audit_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s error %d (%s)\n",
+ loginfo.log_audit_file, prerr, slapd_pr_strerror(prerr));
+ }
}
/* Delete the rotation file also. */
PR_snprintf(buffer, sizeof(buffer), "%s.rotationinfo", loginfo.log_audit_file);
if (PR_Delete(buffer) != PR_SUCCESS) {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s.rotationinfo\n", loginfo.log_audit_file,0,0);
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_audit_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s.rotatoininfo error %d (%s)\n",
+ loginfo.log_audit_file, prerr, slapd_pr_strerror(prerr));
+ }
}
return 0;
}
@@ -3533,15 +3560,15 @@ delete_logfile:
log_convert_time (delete_logp->l_ctime, tbuf, 1 /*short */);
PR_snprintf(buffer, sizeof(buffer), "%s.%s", loginfo.log_audit_file, tbuf );
if (PR_Delete(buffer) != PR_SUCCESS) {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s.%s\n",
- loginfo.log_audit_file, tbuf,0);
-
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_audit_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s.%s error %d (%s)\n",
+ loginfo.log_audit_file, tbuf, prerr, slapd_pr_strerror(prerr));
+ }
} else {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Removed file:%s.%s because of (%s)\n",
- loginfo.log_audit_file, tbuf,
- logstr);
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Removed file:%s.%s because of (%s)\n", loginfo.log_audit_file, tbuf, logstr);
}
slapi_ch_free((void**)&delete_logp);
loginfo.log_numof_audit_logs--;
@@ -3823,10 +3850,8 @@ log__open_errorlogfile(int logfile_state, int locked)
Even if PR_Rename fails with the error, we continue logging.
*/
if (PR_FILE_EXISTS_ERROR != prerr) {
- PR_snprintf(buffer, sizeof(buffer),
- "Failed to rename errors log file, "
- SLAPI_COMPONENT_NAME_NSPR " error %d (%s). Exiting...",
- prerr, slapd_pr_strerror(prerr));
+ PR_snprintf(buffer, sizeof(buffer), "Failed to rename errors log file, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s). Exiting...\n", prerr, slapd_pr_strerror(prerr));
log__error_emergency(buffer, 1, 1);
slapi_ch_free((void **)&log);
if (!locked) LOG_ERROR_UNLOCK_WRITE();
8 years, 6 months
Branch '389-ds-base-1.2.11' - ldap/servers
by Mark Reynolds
ldap/servers/plugins/replication/cl5_api.c | 452 ++++++++++++++--
ldap/servers/plugins/replication/cl5_api.h | 5
ldap/servers/plugins/replication/repl5_replica_config.c | 44 -
3 files changed, 433 insertions(+), 68 deletions(-)
New commits:
commit a1dc207eb1566b5b64ceeb54bb59b6d2b50c48f1
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Wed Jul 8 11:48:27 2015 -0400
Ticket 48208 - CleanAllRUV should completely purge changelog
Bug Description: After cleanAllRUV finishes, the changelog still
contains entries from the cleaned rid. Under certain
conditions this can allow the RUV to get polluted
again, and the ruv element will be missing the replica
url.
Fix Description: At the end of the cleaning task, fire of a thread to
to completely purge the changelog of all entries
containing the cleaned rid.
Also, improved the cleanAllRUV task when dealing
with a server shutdown - previously if the timing is
right the task can "delay/hang" the shutdown process.
https://fedorahosted.org/389/ticket/48208
Reviewed by: nhosoi(Thanks!)
(cherry picked from commit ff1c34538b0600259dba4801da2b2f0993fa5404)
(cherry picked from commit 9e4cf12cfbfde0761325b75c3fd5a8b39223760a)
(cherry picked from commit 264f67218aec5e11f68ad4e36e444730c8c3110c)
(cherry picked from commit e8803f5ad77ec742c57c0121dfc83822633ab602)
diff --git a/ldap/servers/plugins/replication/cl5_api.c b/ldap/servers/plugins/replication/cl5_api.c
index dd3168a..13bf203 100644
--- a/ldap/servers/plugins/replication/cl5_api.c
+++ b/ldap/servers/plugins/replication/cl5_api.c
@@ -345,14 +345,18 @@ static int _cl5TrimInit ();
static void _cl5TrimCleanup ();
static int _cl5TrimMain (void *param);
static void _cl5DoTrimming (ReplicaId rid);
-static void _cl5TrimFile (Object *obj, long *numToTrim, ReplicaId cleaned_rid);
static PRBool _cl5CanTrim (time_t time, long *numToTrim);
+static void _cl5TrimFile (Object *obj, long *numToTrim);
+
+static void _cl5PurgeRID(Object *obj, ReplicaId cleaned_rid);
+static int _cl5PurgeGetFirstEntry (Object *obj, CL5Entry *entry, void **iterator, DB_TXN *txnid, int rid, DBT *key);
+static int _cl5PurgeGetNextEntry (CL5Entry *entry, void *iterator, DBT *key);
static int _cl5ReadRUV (const char *replGen, Object *obj, PRBool purge);
static int _cl5WriteRUV (CL5DBFile *file, PRBool purge);
static int _cl5ConstructRUV (const char *replGen, Object *obj, PRBool purge);
static int _cl5UpdateRUV (Object *obj, CSN *csn, PRBool newReplica, PRBool purge);
static int _cl5GetRUV2Purge2 (Object *fileObj, RUV **ruv);
-void trigger_cl_trimming_thread(void *rid);
+void trigger_cl_purging_thread(void *rid);
/* bakup/recovery, import/export */
static int _cl5LDIF2Operation (char *ldifEntry, slapi_operation_parameters *op,
@@ -3467,10 +3471,18 @@ static void _cl5DoTrimming (ReplicaId rid)
trimmed more often than other. We might have to fix that by, for
example, randomizing starting point */
obj = objset_first_obj (s_cl5Desc.dbFiles);
- while (obj && _cl5CanTrim ((time_t)0, &numToTrim))
- {
- _cl5TrimFile (obj, &numToTrim, rid);
- obj = objset_next_obj (s_cl5Desc.dbFiles, obj);
+ while (obj && (_cl5CanTrim ((time_t)0, &numToTrim) || rid))
+ {
+ if (rid){
+ /*
+ * We are cleaning an invalid rid, and need to strip it
+ * from the changelog.
+ */
+ _cl5PurgeRID (obj, rid);
+ } else {
+ _cl5TrimFile (obj, &numToTrim);
+ }
+ obj = objset_next_obj (s_cl5Desc.dbFiles, obj);
}
if (obj)
@@ -3481,12 +3493,351 @@ static void _cl5DoTrimming (ReplicaId rid)
return;
}
+/*
+ * If the rid is not set it is the very first iteration of the changelog.
+ * If the rid is set, we are doing another pass, and we have a key as our
+ * starting point.
+ */
+static int
+_cl5PurgeGetFirstEntry(Object *obj, CL5Entry *entry, void **iterator, DB_TXN *txnid, int rid, DBT *key)
+{
+ DBC *cursor = NULL;
+ DBT data = {0};
+ CL5Iterator *it;
+ CL5DBFile *file;
+ int rc;
+
+ file = (CL5DBFile*)object_get_data (obj);
+
+ /* create cursor */
+ rc = file->db->cursor(file->db, txnid, &cursor, 0);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5PurgeGetFirstEntry: failed to create cursor; db error - %d %s\n", rc, db_strerror(rc));
+ rc = CL5_DB_ERROR;
+ goto done;
+ }
+
+ key->flags = DB_DBT_MALLOC;
+ data.flags = DB_DBT_MALLOC;
+ while ((rc = cursor->c_get(cursor, key, &data, rid?DB_SET:DB_NEXT)) == 0)
+ {
+ /* skip service entries on the first pass (rid == 0)*/
+ if (!rid && cl5HelperEntry ((char*)key->data, NULL))
+ {
+ slapi_ch_free(&key->data);
+ slapi_ch_free(&(data.data));
+ continue;
+ }
+
+ /* format entry */
+ rc = cl5DBData2Entry(data.data, data.size, entry);
+ slapi_ch_free(&(data.data));
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5PurgeGetFirstEntry: failed to format entry: %d\n", rc);
+ goto done;
+ }
+
+ it = (CL5Iterator*)slapi_ch_malloc(sizeof (CL5Iterator));
+ it->cursor = cursor;
+ object_acquire (obj);
+ it->file = obj;
+ *(CL5Iterator**)iterator = it;
+
+ return CL5_SUCCESS;
+ }
+
+ slapi_ch_free(&key->data);
+ slapi_ch_free(&(data.data));
+
+ /* walked of the end of the file */
+ if (rc == DB_NOTFOUND)
+ {
+ rc = CL5_NOTFOUND;
+ goto done;
+ }
+
+ /* db error occured while iterating */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5PurgeGetFirstEntry: failed to get entry; db error - %d %s\n",
+ rc, db_strerror(rc));
+ rc = CL5_DB_ERROR;
+
+done:
+ /*
+ * We didn't success in assigning this cursor to the iterator,
+ * so we need to free the cursor here.
+ */
+ if (cursor)
+ cursor->c_close(cursor);
+
+ return rc;
+}
+
+/*
+ * Get the next entry. If we get a lock error we will restart the process
+ * starting at the current key.
+ */
+static int
+_cl5PurgeGetNextEntry (CL5Entry *entry, void *iterator, DBT *key)
+{
+ CL5Iterator *it;
+ DBT data={0};
+ int rc;
+
+ it = (CL5Iterator*) iterator;
+
+ key->flags = DB_DBT_MALLOC;
+ data.flags = DB_DBT_MALLOC;
+ while ((rc = it->cursor->c_get(it->cursor, key, &data, DB_NEXT)) == 0)
+ {
+ if (cl5HelperEntry ((char*)key->data, NULL))
+ {
+ slapi_ch_free(&key->data);
+ slapi_ch_free(&(data.data));
+ continue;
+ }
+
+ /* format entry */
+ rc = cl5DBData2Entry (data.data, data.size, entry);
+ slapi_ch_free (&(data.data));
+ if (rc != 0)
+ {
+ if (rc != CL5_DB_LOCK_ERROR){
+ /* Not a lock error, free the key */
+ slapi_ch_free(&key->data);
+ }
+ slapi_log_error(rc == CL5_DB_LOCK_ERROR?SLAPI_LOG_REPL:SLAPI_LOG_FATAL,
+ repl_plugin_name_cl,
+ "_cl5PurgeGetNextEntry: failed to format entry: %d\n",
+ rc);
+
+ }
+
+ return rc;
+ }
+ slapi_ch_free(&(data.data));
+
+ /* walked of the end of the file or entry is out of range */
+ if (rc == 0 || rc == DB_NOTFOUND){
+ slapi_ch_free(&key->data);
+ return CL5_NOTFOUND;
+ }
+ if (rc != CL5_DB_LOCK_ERROR){
+ /* Not a lock error, free the key */
+ slapi_ch_free(&key->data);
+ }
+
+ /* cursor operation failed */
+ slapi_log_error(rc == CL5_DB_LOCK_ERROR?SLAPI_LOG_REPL:SLAPI_LOG_FATAL,
+ repl_plugin_name_cl,
+ "_cl5PurgeGetNextEntry: failed to get entry; db error - %d %s\n",
+ rc, db_strerror(rc));
+
+ return rc;
+}
+
+#define MAX_RETRIES 10
+/*
+ * _cl5PurgeRID(Object *obj, ReplicaId cleaned_rid)
+ *
+ * Clean the entire changelog of updates from the "cleaned rid" via CLEANALLRUV
+ * Delete entries in batches so we don't consume too many db locks, and we don't
+ * lockup the changelog during the entire purging process using one transaction.
+ * We save the key from the last iteration so we don't have to start from the
+ * beginning for each new iteration.
+ */
+static void
+_cl5PurgeRID(Object *obj, ReplicaId cleaned_rid)
+{
+ slapi_operation_parameters op = {0};
+ ReplicaId csn_rid;
+ CL5Entry entry;
+ DB_TXN *txnid = NULL;
+ DBT key = {0};
+ void *iterator = NULL;
+ long totalTrimmed = 0;
+ long trimmed = 0;
+ char *starting_key = NULL;
+ int batch_count = 0;
+ int db_lock_retry_count = 0;
+ int first_pass = 1;
+ int finished = 0;
+ int rc = 0;
+
+ PR_ASSERT (obj);
+ entry.op = &op;
+
+ /*
+ * Keep processing the changelog until we are done, shutting down, or we
+ * maxed out on the db lock retries.
+ */
+ while (!finished && db_lock_retry_count < MAX_RETRIES && !slapi_is_shutting_down()){
+ trimmed = 0;
+
+ /*
+ * Sleep a bit to allow others to use the changelog - we can't hog the
+ * changelog for the entire purge.
+ */
+ DS_Sleep(PR_MillisecondsToInterval(100));
+
+ rc = TXN_BEGIN(s_cl5Desc.dbEnv, NULL, &txnid, 0);
+ if (rc != 0){
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5PurgeRID: failed to begin transaction; db error - %d %s. "
+ "Changelog was not purged of rid(%d)\n",
+ rc, db_strerror(rc), cleaned_rid);
+ return;
+ }
+
+ /*
+ * Check every changelog entry for the cleaned rid
+ */
+ rc = _cl5PurgeGetFirstEntry(obj, &entry, &iterator, txnid, first_pass?0:cleaned_rid, &key);
+ first_pass = 0;
+ while (rc == CL5_SUCCESS && !slapi_is_shutting_down()) {
+ /*
+ * Store the new starting key - we need this starting key in case
+ * we run out of locks and have to start the transaction over.
+ */
+ slapi_ch_free_string(&starting_key);
+ starting_key = slapi_ch_strdup((char*)key.data);
+
+ if(trimmed == 10000 || (batch_count && trimmed == batch_count)){
+ /*
+ * Break out, and commit these deletes. Do not free the key,
+ * we need it for the next pass.
+ */
+ cl5_operation_parameters_done (&op);
+ db_lock_retry_count = 0; /* reset the retry count */
+ break;
+ }
+ if(op.csn){
+ csn_rid = csn_get_replicaid (op.csn);
+ if (csn_rid == cleaned_rid){
+ rc = _cl5CurrentDeleteEntry (iterator);
+ if (rc != CL5_SUCCESS){
+ /* log error */
+ cl5_operation_parameters_done (&op);
+ if (rc == CL5_DB_LOCK_ERROR){
+ /*
+ * Ran out of locks, need to restart the transaction.
+ * Reduce the the batch count and reset the key to
+ * the starting point
+ */
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5PurgeRID: Ran out of db locks deleting entry. "
+ "Reduce the batch value and restart.\n");
+ batch_count = trimmed - 10;
+ if (batch_count < 10){
+ batch_count = 10;
+ }
+ trimmed = 0;
+ slapi_ch_free(&(key.data));
+ key.data = starting_key;
+ starting_key = NULL;
+ db_lock_retry_count++;
+ break;
+ } else {
+ /* fatal error */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5PurgeRID: fatal error (%d)\n", rc);
+ slapi_ch_free(&(key.data));
+ finished = 1;
+ break;
+ }
+ }
+ trimmed++;
+ }
+ }
+ slapi_ch_free(&(key.data));
+ cl5_operation_parameters_done (&op);
+
+ rc = _cl5PurgeGetNextEntry (&entry, iterator, &key);
+ if (rc == CL5_DB_LOCK_ERROR){
+ /*
+ * Ran out of locks, need to restart the transaction.
+ * Reduce the the batch count and reset the key to the starting
+ * point.
+ */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5PurgeRID: Ran out of db locks getting the next entry. "
+ "Reduce the batch value and restart.\n");
+ batch_count = trimmed - 10;
+ if (batch_count < 10){
+ batch_count = 10;
+ }
+ trimmed = 0;
+ cl5_operation_parameters_done (&op);
+ slapi_ch_free(&(key.data));
+ key.data = starting_key;
+ starting_key = NULL;
+ db_lock_retry_count++;
+ break;
+ }
+ }
+
+ if (rc == CL5_NOTFOUND){
+ /* Scanned the entire changelog, we're done */
+ finished = 1;
+ }
+
+ /* Destroy the iterator before we finish with the txn */
+ cl5DestroyIterator (iterator);
+
+ /*
+ * Commit or abort the txn
+ */
+ if (rc == CL5_SUCCESS || rc == CL5_NOTFOUND){
+ rc = TXN_COMMIT (txnid, 0);
+ if (rc != 0){
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5PurgeRID: failed to commit transaction; db error - %d %s. "
+ "Changelog was not completely purged of rid (%d)\n",
+ rc, db_strerror(rc), cleaned_rid);
+ break;
+ } else if (finished){
+ /* We're done */
+ totalTrimmed += trimmed;
+ break;
+ } else {
+ /* Not done yet */
+ totalTrimmed += trimmed;
+ trimmed = 0;
+ }
+ } else {
+ rc = TXN_ABORT (txnid);
+ if (rc != 0){
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5PurgeRID: failed to abort transaction; db error - %d %s. "
+ "Changelog was not completely purged of rid (%d)\n",
+ rc, db_strerror(rc), cleaned_rid);
+ }
+ if (batch_count == 0){
+ /* This was not a retry. Fatal error, break out */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5PurgeRID: Changelog was not purged of rid (%d)\n",
+ cleaned_rid);
+ break;
+ }
+ }
+ }
+ slapi_ch_free_string(&starting_key);
+
+ slapi_log_error (SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5PurgeRID: Removed (%ld entries) that originated from rid (%d)\n",
+ totalTrimmed, cleaned_rid);
+}
+
/* Note that each file contains changes for a single replicated area.
trimming algorithm:
*/
#define CL5_TRIM_MAX_PER_TRANSACTION 10
-static void _cl5TrimFile (Object *obj, long *numToTrim, ReplicaId cleaned_rid)
+static void _cl5TrimFile (Object *obj, long *numToTrim)
{
DB_TXN *txnid;
RUV *ruv = NULL;
@@ -3509,7 +3860,6 @@ static void _cl5TrimFile (Object *obj, long *numToTrim, ReplicaId cleaned_rid)
}
entry.op = &op;
-
while ( !finished && !slapi_is_shutting_down() )
{
it = NULL;
@@ -3530,7 +3880,7 @@ static void _cl5TrimFile (Object *obj, long *numToTrim, ReplicaId cleaned_rid)
}
finished = _cl5GetFirstEntry (obj, &entry, &it, txnid);
- while ( !finished )
+ while ( !finished && !slapi_is_shutting_down())
{
/*
* This change can be trimmed if it exceeds purge
@@ -3544,11 +3894,12 @@ static void _cl5TrimFile (Object *obj, long *numToTrim, ReplicaId cleaned_rid)
continue;
}
csn_rid = csn_get_replicaid (op.csn);
+
if ( (*numToTrim > 0 || _cl5CanTrim (entry.time, numToTrim)) &&
ruv_covers_csn_strict (ruv, op.csn) )
{
rc = _cl5CurrentDeleteEntry (it);
- if ( rc == CL5_SUCCESS && cleaned_rid != csn_rid)
+ if ( rc == CL5_SUCCESS)
{
rc = _cl5UpdateRUV (obj, op.csn, PR_FALSE, PR_TRUE);
}
@@ -3562,7 +3913,6 @@ static void _cl5TrimFile (Object *obj, long *numToTrim, ReplicaId cleaned_rid)
/* The above two functions have logged the error */
abort = PR_TRUE;
}
-
}
else
{
@@ -3619,7 +3969,7 @@ static void _cl5TrimFile (Object *obj, long *numToTrim, ReplicaId cleaned_rid)
rc = TXN_ABORT (txnid);
if (rc != 0)
{
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
"_cl5TrimFile: failed to abort transaction; db error - %d %s\n",
rc, db_strerror(rc));
}
@@ -3630,7 +3980,7 @@ static void _cl5TrimFile (Object *obj, long *numToTrim, ReplicaId cleaned_rid)
if (rc != 0)
{
finished = 1;
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
"_cl5TrimFile: failed to commit transaction; db error - %d %s\n",
rc, db_strerror(rc));
}
@@ -4654,9 +5004,9 @@ static int _cl5WriteOperationTxn(const char *replName, const char *replGen,
goto done;
}
#endif
- /* back off */
+ /* back off */
interval = PR_MillisecondsToInterval(slapi_rand() % 100);
- DS_Sleep(interval);
+ DS_Sleep(interval);
}
#if USE_DB_TXN
/* begin transaction */
@@ -4702,19 +5052,19 @@ static int _cl5WriteOperationTxn(const char *replName, const char *replGen,
}
cnt ++;
}
-
+
if (rc == 0) /* we successfully added entry */
{
#if USE_DB_TXN
rc = TXN_COMMIT (txnid, 0);
#endif
}
- else
+ else
{
- char s[CSN_STRSIZE];
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ char s[CSN_STRSIZE];
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
"_cl5WriteOperationTxn: failed to write entry with csn (%s); "
- "db error - %d %s\n", csn_as_string(op->csn,PR_FALSE,s),
+ "db error - %d %s\n", csn_as_string(op->csn,PR_FALSE,s),
rc, db_strerror(rc));
#if USE_DB_TXN
rc = TXN_ABORT (txnid);
@@ -4735,7 +5085,7 @@ static int _cl5WriteOperationTxn(const char *replName, const char *replGen,
/* update purge vector if we have not seen any changes from this replica before */
_cl5UpdateRUV (file_obj, op->csn, PR_TRUE, PR_TRUE);
- slapi_log_error(SLAPI_LOG_PLUGIN, repl_plugin_name_cl,
+ slapi_log_error(SLAPI_LOG_PLUGIN, repl_plugin_name_cl,
"cl5WriteOperationTxn: successfully written entry with csn (%s)\n", csnStr);
rc = CL5_SUCCESS;
done:
@@ -4749,7 +5099,7 @@ done:
return rc;
}
-static int _cl5WriteOperation(const char *replName, const char *replGen,
+static int _cl5WriteOperation(const char *replName, const char *replGen,
const slapi_operation_parameters *op, PRBool local)
{
return _cl5WriteOperationTxn(replName, replGen, op, local, NULL);
@@ -4800,7 +5150,7 @@ static int _cl5GetFirstEntry (Object *obj, CL5Entry *entry, void **iterator, DB_
goto done;
}
- it = (CL5Iterator*)slapi_ch_malloc (sizeof (CL5Iterator));
+ it = (CL5Iterator*)slapi_ch_malloc(sizeof (CL5Iterator));
it->cursor = cursor;
object_acquire (obj);
it->file = obj;
@@ -4875,7 +5225,7 @@ static int _cl5GetNextEntry (CL5Entry *entry, void *iterator)
slapi_ch_free (&(data.data));
if (rc != 0)
{
- slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
"_cl5GetNextEntry: failed to format entry: %d\n", rc);
}
@@ -4904,38 +5254,42 @@ static int _cl5GetNextEntry (CL5Entry *entry, void *iterator)
}
/* cursor operation failed */
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
- "_cl5GetNextEntry: failed to get entry; db error - %d %s\n",
- rc, db_strerror(rc));
+ slapi_log_error(rc == CL5_DB_LOCK_ERROR?SLAPI_LOG_REPL:SLAPI_LOG_FATAL,
+ repl_plugin_name_cl,
+ "_cl5GetNextEntry: failed to get entry; db error - %d %s\n",
+ rc, db_strerror(rc));
- return CL5_DB_ERROR;
+ return rc;
}
static int _cl5CurrentDeleteEntry (void *iterator)
{
int rc;
CL5Iterator *it;
- CL5DBFile *file;
+ CL5DBFile *file;
- PR_ASSERT (iterator);
+ PR_ASSERT (iterator);
it = (CL5Iterator*)iterator;
rc = it->cursor->c_del (it->cursor, 0);
if (rc == 0) {
- /* decrement entry count */
- file = (CL5DBFile*)object_get_data (it->file);
- PR_AtomicDecrement (&file->entryCount);
- return CL5_SUCCESS;
- } else {
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
- "_cl5CurrentDeleteEntry failed, err=%d %s\n",
- rc, db_strerror(rc));
- /* We don't free(close) the cursor here, as the caller will free it by a call to cl5DestroyIterator */
- /* Freeing it here is a potential bug, as the cursor can't be referenced later once freed */
- return CL5_DB_ERROR;
- }
+ /* decrement entry count */
+ file = (CL5DBFile*)object_get_data (it->file);
+ PR_AtomicDecrement (&file->entryCount);
+ return CL5_SUCCESS;
+ } else {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5CurrentDeleteEntry failed, err=%d %s\n",
+ rc, db_strerror(rc));
+ /*
+ * We don't free(close) the cursor here, as the caller will free it by
+ * a call to cl5DestroyIterator. Freeing it here is a potential bug,
+ * as the cursor can't be referenced later once freed.
+ */
+ return rc;
+ }
}
static PRBool _cl5IsValidIterator (const CL5Iterator *iterator)
@@ -6186,7 +6540,7 @@ static int _cl5ExportFile (PRFileDesc *prFile, Object *obj)
slapi_write_buffer (prFile, "\n", strlen("\n"));
entry.op = &op;
- rc = _cl5GetFirstEntry (obj, &entry, &iterator, NULL);
+ rc = _cl5GetFirstEntry (obj, &entry, &iterator, NULL);
while (rc == CL5_SUCCESS)
{
rc = _cl5Operation2LDIF (&op, file->replGen, &buff, &len);
@@ -6607,16 +6961,16 @@ cl5CleanRUV(ReplicaId rid){
slapi_rwlock_unlock (s_cl5Desc.stLock);
}
-void trigger_cl_trimming(ReplicaId rid){
+void trigger_cl_purging(ReplicaId rid){
PRThread *trim_tid = NULL;
- slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "trigger_cl_trimming: rid (%d)\n",(int)rid);
- trim_tid = PR_CreateThread(PR_USER_THREAD, (VFP)(void*)trigger_cl_trimming_thread,
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "trigger_cl_purging: rid (%d)\n",(int)rid);
+ trim_tid = PR_CreateThread(PR_USER_THREAD, (VFP)(void*)trigger_cl_purging_thread,
(void *)&rid, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
PR_UNJOINABLE_THREAD, DEFAULT_THREAD_STACKSIZE);
if (NULL == trim_tid){
slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
- "trigger_cl_trimming: failed to create trimming "
+ "trigger_cl_purging: failed to create trimming "
"thread; NSPR error - %d\n", PR_GetError ());
} else {
/* need a little time for the thread to get started */
@@ -6625,7 +6979,7 @@ void trigger_cl_trimming(ReplicaId rid){
}
void
-trigger_cl_trimming_thread(void *arg){
+trigger_cl_purging_thread(void *arg){
ReplicaId rid = *(ReplicaId *)arg;
/* make sure we have a change log, and we aren't closing it */
@@ -6634,7 +6988,7 @@ trigger_cl_trimming_thread(void *arg){
}
if (CL5_SUCCESS != _cl5AddThread()) {
slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
- "trigger_cl_trimming: failed to increment thread count "
+ "trigger_cl_purging: failed to increment thread count "
"NSPR error - %d\n", PR_GetError ());
}
_cl5DoTrimming(rid);
diff --git a/ldap/servers/plugins/replication/cl5_api.h b/ldap/servers/plugins/replication/cl5_api.h
index 9b285ca..b46a691 100644
--- a/ldap/servers/plugins/replication/cl5_api.h
+++ b/ldap/servers/plugins/replication/cl5_api.h
@@ -145,6 +145,9 @@ enum
CL5_CSN_ERROR, /* CSN API failed */
CL5_RUV_ERROR, /* RUV API failed */
CL5_OBJSET_ERROR, /* namedobjset api failed */
+ CL5_DB_LOCK_ERROR, /* bdb returns error 12 when the db runs out of locks,
+ this var needs to be in slot 12 of the list.
+ Do not re-order enum above! */
CL5_PURGED_DATA, /* requested data has been purged */
CL5_MISSING_DATA, /* data should be in the changelog, but is missing */
CL5_UNKNOWN_ERROR, /* unclassified error */
@@ -490,6 +493,6 @@ int cl5WriteRUV();
int cl5DeleteRUV();
void cl5CleanRUV(ReplicaId rid);
void cl5NotifyCleanup(int rid);
-void trigger_cl_trimming(ReplicaId rid);
+void trigger_cl_purging(ReplicaId rid);
#endif
diff --git a/ldap/servers/plugins/replication/repl5_replica_config.c b/ldap/servers/plugins/replication/repl5_replica_config.c
index ae4c2ff..68b3ce5 100644
--- a/ldap/servers/plugins/replication/repl5_replica_config.c
+++ b/ldap/servers/plugins/replication/repl5_replica_config.c
@@ -1216,6 +1216,11 @@ replica_execute_cleanruv_task (Object *r, ReplicaId rid, char *returntext /* not
*/
cl5CleanRUV(rid);
+ /*
+ * Now purge the changelog
+ */
+ trigger_cl_purging(rid);
+
if (rc != RUV_SUCCESS){
slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanruv_task: task failed(%d)\n",rc);
return LDAP_OPERATIONS_ERROR;
@@ -1603,7 +1608,7 @@ replica_cleanallruv_thread(void *arg)
/* no agmts, just clean this replica */
break;
}
- while (agmt_obj){
+ while (agmt_obj && !slapi_is_shutting_down()){
agmt = (Repl_Agmt*)object_get_data (agmt_obj);
if(!agmt_is_enabled(agmt) || get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
@@ -1685,13 +1690,15 @@ replica_cleanallruv_thread(void *arg)
break;
}
/*
- * need to sleep between passes
+ * Need to sleep between passes unless we are shutting down
*/
- cleanruv_log(data->task, data->rid, CLEANALLRUV_ID, "Replicas have not been cleaned yet, "
- "retrying in %d seconds", interval);
- PR_Lock( notify_lock );
- PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
- PR_Unlock( notify_lock );
+ if (!slapi_is_shutting_down()){
+ cleanruv_log(data->task, data->rid, CLEANALLRUV_ID, "Replicas have not been cleaned yet, "
+ "retrying in %d seconds", interval);
+ PR_Lock( notify_lock );
+ PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
+ PR_Unlock( notify_lock );
+ }
if(interval < 14400){ /* 4 hour max */
interval = interval * 2;
@@ -1702,10 +1709,9 @@ replica_cleanallruv_thread(void *arg)
done:
/*
- * If the replicas are cleaned, release the rid, and trim the changelog
+ * If the replicas are cleaned, release the rid
*/
if(!aborted){
- trigger_cl_trimming(data->rid);
delete_cleaned_rid_config(data);
/* make sure all the replicas have been "pre_cleaned" before finishing */
check_replicas_are_done_cleaning(data);
@@ -1715,7 +1721,7 @@ done:
/*
* Shutdown or abort
*/
- if(!is_task_aborted(data->rid)){
+ if(!is_task_aborted(data->rid) || slapi_is_shutting_down()){
cleanruv_log(data->task, data->rid, CLEANALLRUV_ID,"Server shutting down. Process will resume at server startup");
} else {
cleanruv_log(data->task, data->rid, CLEANALLRUV_ID,"Task aborted for rid(%d).",data->rid);
@@ -1918,7 +1924,7 @@ check_agmts_are_caught_up(cleanruv_data *data, char *maxcsn)
not_all_caughtup = 0;
break;
}
- while (agmt_obj){
+ while (agmt_obj && !slapi_is_shutting_down()){
agmt = (Repl_Agmt*)object_get_data (agmt_obj);
if(!agmt_is_enabled(agmt) || get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
@@ -1976,7 +1982,7 @@ check_agmts_are_alive(Replica *replica, ReplicaId rid, Slapi_Task *task)
not_all_alive = 0;
break;
}
- while (agmt_obj){
+ while (agmt_obj && !slapi_is_shutting_down()){
agmt = (Repl_Agmt*)object_get_data (agmt_obj);
if(!agmt_is_enabled(agmt) || get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
@@ -2746,12 +2752,14 @@ replica_abort_task_thread(void *arg)
break;
}
/*
- * need to sleep between passes
+ * Need to sleep between passes. unless we are shutting down
*/
- cleanruv_log(data->task, data->rid, ABORT_CLEANALLRUV_ID,"Retrying in %d seconds",interval);
- PR_Lock( notify_lock );
- PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
- PR_Unlock( notify_lock );
+ if (!slapi_is_shutting_down()){
+ cleanruv_log(data->task, data->rid, ABORT_CLEANALLRUV_ID,"Retrying in %d seconds",interval);
+ PR_Lock( notify_lock );
+ PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
+ PR_Unlock( notify_lock );
+ }
if(interval < 14400){ /* 4 hour max */
interval = interval * 2;
@@ -2769,7 +2777,7 @@ done:
* Wait for this server to stop its cleanallruv task(which removes the rid from the cleaned list)
*/
cleanruv_log(data->task, data->rid, ABORT_CLEANALLRUV_ID, "Waiting for CleanAllRUV task to abort...");
- while(is_cleaned_rid(data->rid)){
+ while(is_cleaned_rid(data->rid) && !slapi_is_shutting_down()){
DS_Sleep(PR_SecondsToInterval(1));
count++;
if(count == 60){ /* it should not take this long */
8 years, 6 months
Branch '389-ds-base-1.3.1' - ldap/servers
by Mark Reynolds
ldap/servers/plugins/replication/cl5_api.c | 452 ++++++++++++++--
ldap/servers/plugins/replication/cl5_api.h | 5
ldap/servers/plugins/replication/repl5_replica_config.c | 44 -
3 files changed, 433 insertions(+), 68 deletions(-)
New commits:
commit e8803f5ad77ec742c57c0121dfc83822633ab602
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Wed Jul 8 11:48:27 2015 -0400
Ticket 48208 - CleanAllRUV should completely purge changelog
Bug Description: After cleanAllRUV finishes, the changelog still
contains entries from the cleaned rid. Under certain
conditions this can allow the RUV to get polluted
again, and the ruv element will be missing the replica
url.
Fix Description: At the end of the cleaning task, fire of a thread to
to completely purge the changelog of all entries
containing the cleaned rid.
Also, improved the cleanAllRUV task when dealing
with a server shutdown - previously if the timing is
right the task can "delay/hang" the shutdown process.
https://fedorahosted.org/389/ticket/48208
Reviewed by: nhosoi(Thanks!)
(cherry picked from commit ff1c34538b0600259dba4801da2b2f0993fa5404)
(cherry picked from commit 9e4cf12cfbfde0761325b75c3fd5a8b39223760a)
(cherry picked from commit 264f67218aec5e11f68ad4e36e444730c8c3110c)
diff --git a/ldap/servers/plugins/replication/cl5_api.c b/ldap/servers/plugins/replication/cl5_api.c
index 4ab0eb0..9e31074 100644
--- a/ldap/servers/plugins/replication/cl5_api.c
+++ b/ldap/servers/plugins/replication/cl5_api.c
@@ -350,14 +350,18 @@ static int _cl5TrimInit ();
static void _cl5TrimCleanup ();
static int _cl5TrimMain (void *param);
static void _cl5DoTrimming (ReplicaId rid);
-static void _cl5TrimFile (Object *obj, long *numToTrim, ReplicaId cleaned_rid);
static PRBool _cl5CanTrim (time_t time, long *numToTrim);
+static void _cl5TrimFile (Object *obj, long *numToTrim);
+
+static void _cl5PurgeRID(Object *obj, ReplicaId cleaned_rid);
+static int _cl5PurgeGetFirstEntry (Object *obj, CL5Entry *entry, void **iterator, DB_TXN *txnid, int rid, DBT *key);
+static int _cl5PurgeGetNextEntry (CL5Entry *entry, void *iterator, DBT *key);
static int _cl5ReadRUV (const char *replGen, Object *obj, PRBool purge);
static int _cl5WriteRUV (CL5DBFile *file, PRBool purge);
static int _cl5ConstructRUV (const char *replGen, Object *obj, PRBool purge);
static int _cl5UpdateRUV (Object *obj, CSN *csn, PRBool newReplica, PRBool purge);
static int _cl5GetRUV2Purge2 (Object *fileObj, RUV **ruv);
-void trigger_cl_trimming_thread(void *rid);
+void trigger_cl_purging_thread(void *rid);
/* bakup/recovery, import/export */
static int _cl5LDIF2Operation (char *ldifEntry, slapi_operation_parameters *op,
@@ -3477,10 +3481,18 @@ static void _cl5DoTrimming (ReplicaId rid)
trimmed more often than other. We might have to fix that by, for
example, randomizing starting point */
obj = objset_first_obj (s_cl5Desc.dbFiles);
- while (obj && _cl5CanTrim ((time_t)0, &numToTrim))
- {
- _cl5TrimFile (obj, &numToTrim, rid);
- obj = objset_next_obj (s_cl5Desc.dbFiles, obj);
+ while (obj && (_cl5CanTrim ((time_t)0, &numToTrim) || rid))
+ {
+ if (rid){
+ /*
+ * We are cleaning an invalid rid, and need to strip it
+ * from the changelog.
+ */
+ _cl5PurgeRID (obj, rid);
+ } else {
+ _cl5TrimFile (obj, &numToTrim);
+ }
+ obj = objset_next_obj (s_cl5Desc.dbFiles, obj);
}
if (obj)
@@ -3491,12 +3503,351 @@ static void _cl5DoTrimming (ReplicaId rid)
return;
}
+/*
+ * If the rid is not set it is the very first iteration of the changelog.
+ * If the rid is set, we are doing another pass, and we have a key as our
+ * starting point.
+ */
+static int
+_cl5PurgeGetFirstEntry(Object *obj, CL5Entry *entry, void **iterator, DB_TXN *txnid, int rid, DBT *key)
+{
+ DBC *cursor = NULL;
+ DBT data = {0};
+ CL5Iterator *it;
+ CL5DBFile *file;
+ int rc;
+
+ file = (CL5DBFile*)object_get_data (obj);
+
+ /* create cursor */
+ rc = file->db->cursor(file->db, txnid, &cursor, 0);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5PurgeGetFirstEntry: failed to create cursor; db error - %d %s\n", rc, db_strerror(rc));
+ rc = CL5_DB_ERROR;
+ goto done;
+ }
+
+ key->flags = DB_DBT_MALLOC;
+ data.flags = DB_DBT_MALLOC;
+ while ((rc = cursor->c_get(cursor, key, &data, rid?DB_SET:DB_NEXT)) == 0)
+ {
+ /* skip service entries on the first pass (rid == 0)*/
+ if (!rid && cl5HelperEntry ((char*)key->data, NULL))
+ {
+ slapi_ch_free(&key->data);
+ slapi_ch_free(&(data.data));
+ continue;
+ }
+
+ /* format entry */
+ rc = cl5DBData2Entry(data.data, data.size, entry);
+ slapi_ch_free(&(data.data));
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5PurgeGetFirstEntry: failed to format entry: %d\n", rc);
+ goto done;
+ }
+
+ it = (CL5Iterator*)slapi_ch_malloc(sizeof (CL5Iterator));
+ it->cursor = cursor;
+ object_acquire (obj);
+ it->file = obj;
+ *(CL5Iterator**)iterator = it;
+
+ return CL5_SUCCESS;
+ }
+
+ slapi_ch_free(&key->data);
+ slapi_ch_free(&(data.data));
+
+ /* walked of the end of the file */
+ if (rc == DB_NOTFOUND)
+ {
+ rc = CL5_NOTFOUND;
+ goto done;
+ }
+
+ /* db error occured while iterating */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5PurgeGetFirstEntry: failed to get entry; db error - %d %s\n",
+ rc, db_strerror(rc));
+ rc = CL5_DB_ERROR;
+
+done:
+ /*
+ * We didn't success in assigning this cursor to the iterator,
+ * so we need to free the cursor here.
+ */
+ if (cursor)
+ cursor->c_close(cursor);
+
+ return rc;
+}
+
+/*
+ * Get the next entry. If we get a lock error we will restart the process
+ * starting at the current key.
+ */
+static int
+_cl5PurgeGetNextEntry (CL5Entry *entry, void *iterator, DBT *key)
+{
+ CL5Iterator *it;
+ DBT data={0};
+ int rc;
+
+ it = (CL5Iterator*) iterator;
+
+ key->flags = DB_DBT_MALLOC;
+ data.flags = DB_DBT_MALLOC;
+ while ((rc = it->cursor->c_get(it->cursor, key, &data, DB_NEXT)) == 0)
+ {
+ if (cl5HelperEntry ((char*)key->data, NULL))
+ {
+ slapi_ch_free(&key->data);
+ slapi_ch_free(&(data.data));
+ continue;
+ }
+
+ /* format entry */
+ rc = cl5DBData2Entry (data.data, data.size, entry);
+ slapi_ch_free (&(data.data));
+ if (rc != 0)
+ {
+ if (rc != CL5_DB_LOCK_ERROR){
+ /* Not a lock error, free the key */
+ slapi_ch_free(&key->data);
+ }
+ slapi_log_error(rc == CL5_DB_LOCK_ERROR?SLAPI_LOG_REPL:SLAPI_LOG_FATAL,
+ repl_plugin_name_cl,
+ "_cl5PurgeGetNextEntry: failed to format entry: %d\n",
+ rc);
+
+ }
+
+ return rc;
+ }
+ slapi_ch_free(&(data.data));
+
+ /* walked of the end of the file or entry is out of range */
+ if (rc == 0 || rc == DB_NOTFOUND){
+ slapi_ch_free(&key->data);
+ return CL5_NOTFOUND;
+ }
+ if (rc != CL5_DB_LOCK_ERROR){
+ /* Not a lock error, free the key */
+ slapi_ch_free(&key->data);
+ }
+
+ /* cursor operation failed */
+ slapi_log_error(rc == CL5_DB_LOCK_ERROR?SLAPI_LOG_REPL:SLAPI_LOG_FATAL,
+ repl_plugin_name_cl,
+ "_cl5PurgeGetNextEntry: failed to get entry; db error - %d %s\n",
+ rc, db_strerror(rc));
+
+ return rc;
+}
+
+#define MAX_RETRIES 10
+/*
+ * _cl5PurgeRID(Object *obj, ReplicaId cleaned_rid)
+ *
+ * Clean the entire changelog of updates from the "cleaned rid" via CLEANALLRUV
+ * Delete entries in batches so we don't consume too many db locks, and we don't
+ * lockup the changelog during the entire purging process using one transaction.
+ * We save the key from the last iteration so we don't have to start from the
+ * beginning for each new iteration.
+ */
+static void
+_cl5PurgeRID(Object *obj, ReplicaId cleaned_rid)
+{
+ slapi_operation_parameters op = {0};
+ ReplicaId csn_rid;
+ CL5Entry entry;
+ DB_TXN *txnid = NULL;
+ DBT key = {0};
+ void *iterator = NULL;
+ long totalTrimmed = 0;
+ long trimmed = 0;
+ char *starting_key = NULL;
+ int batch_count = 0;
+ int db_lock_retry_count = 0;
+ int first_pass = 1;
+ int finished = 0;
+ int rc = 0;
+
+ PR_ASSERT (obj);
+ entry.op = &op;
+
+ /*
+ * Keep processing the changelog until we are done, shutting down, or we
+ * maxed out on the db lock retries.
+ */
+ while (!finished && db_lock_retry_count < MAX_RETRIES && !slapi_is_shutting_down()){
+ trimmed = 0;
+
+ /*
+ * Sleep a bit to allow others to use the changelog - we can't hog the
+ * changelog for the entire purge.
+ */
+ DS_Sleep(PR_MillisecondsToInterval(100));
+
+ rc = TXN_BEGIN(s_cl5Desc.dbEnv, NULL, &txnid, 0);
+ if (rc != 0){
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5PurgeRID: failed to begin transaction; db error - %d %s. "
+ "Changelog was not purged of rid(%d)\n",
+ rc, db_strerror(rc), cleaned_rid);
+ return;
+ }
+
+ /*
+ * Check every changelog entry for the cleaned rid
+ */
+ rc = _cl5PurgeGetFirstEntry(obj, &entry, &iterator, txnid, first_pass?0:cleaned_rid, &key);
+ first_pass = 0;
+ while (rc == CL5_SUCCESS && !slapi_is_shutting_down()) {
+ /*
+ * Store the new starting key - we need this starting key in case
+ * we run out of locks and have to start the transaction over.
+ */
+ slapi_ch_free_string(&starting_key);
+ starting_key = slapi_ch_strdup((char*)key.data);
+
+ if(trimmed == 10000 || (batch_count && trimmed == batch_count)){
+ /*
+ * Break out, and commit these deletes. Do not free the key,
+ * we need it for the next pass.
+ */
+ cl5_operation_parameters_done (&op);
+ db_lock_retry_count = 0; /* reset the retry count */
+ break;
+ }
+ if(op.csn){
+ csn_rid = csn_get_replicaid (op.csn);
+ if (csn_rid == cleaned_rid){
+ rc = _cl5CurrentDeleteEntry (iterator);
+ if (rc != CL5_SUCCESS){
+ /* log error */
+ cl5_operation_parameters_done (&op);
+ if (rc == CL5_DB_LOCK_ERROR){
+ /*
+ * Ran out of locks, need to restart the transaction.
+ * Reduce the the batch count and reset the key to
+ * the starting point
+ */
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5PurgeRID: Ran out of db locks deleting entry. "
+ "Reduce the batch value and restart.\n");
+ batch_count = trimmed - 10;
+ if (batch_count < 10){
+ batch_count = 10;
+ }
+ trimmed = 0;
+ slapi_ch_free(&(key.data));
+ key.data = starting_key;
+ starting_key = NULL;
+ db_lock_retry_count++;
+ break;
+ } else {
+ /* fatal error */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5PurgeRID: fatal error (%d)\n", rc);
+ slapi_ch_free(&(key.data));
+ finished = 1;
+ break;
+ }
+ }
+ trimmed++;
+ }
+ }
+ slapi_ch_free(&(key.data));
+ cl5_operation_parameters_done (&op);
+
+ rc = _cl5PurgeGetNextEntry (&entry, iterator, &key);
+ if (rc == CL5_DB_LOCK_ERROR){
+ /*
+ * Ran out of locks, need to restart the transaction.
+ * Reduce the the batch count and reset the key to the starting
+ * point.
+ */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5PurgeRID: Ran out of db locks getting the next entry. "
+ "Reduce the batch value and restart.\n");
+ batch_count = trimmed - 10;
+ if (batch_count < 10){
+ batch_count = 10;
+ }
+ trimmed = 0;
+ cl5_operation_parameters_done (&op);
+ slapi_ch_free(&(key.data));
+ key.data = starting_key;
+ starting_key = NULL;
+ db_lock_retry_count++;
+ break;
+ }
+ }
+
+ if (rc == CL5_NOTFOUND){
+ /* Scanned the entire changelog, we're done */
+ finished = 1;
+ }
+
+ /* Destroy the iterator before we finish with the txn */
+ cl5DestroyIterator (iterator);
+
+ /*
+ * Commit or abort the txn
+ */
+ if (rc == CL5_SUCCESS || rc == CL5_NOTFOUND){
+ rc = TXN_COMMIT (txnid, 0);
+ if (rc != 0){
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5PurgeRID: failed to commit transaction; db error - %d %s. "
+ "Changelog was not completely purged of rid (%d)\n",
+ rc, db_strerror(rc), cleaned_rid);
+ break;
+ } else if (finished){
+ /* We're done */
+ totalTrimmed += trimmed;
+ break;
+ } else {
+ /* Not done yet */
+ totalTrimmed += trimmed;
+ trimmed = 0;
+ }
+ } else {
+ rc = TXN_ABORT (txnid);
+ if (rc != 0){
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5PurgeRID: failed to abort transaction; db error - %d %s. "
+ "Changelog was not completely purged of rid (%d)\n",
+ rc, db_strerror(rc), cleaned_rid);
+ }
+ if (batch_count == 0){
+ /* This was not a retry. Fatal error, break out */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5PurgeRID: Changelog was not purged of rid (%d)\n",
+ cleaned_rid);
+ break;
+ }
+ }
+ }
+ slapi_ch_free_string(&starting_key);
+
+ slapi_log_error (SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5PurgeRID: Removed (%ld entries) that originated from rid (%d)\n",
+ totalTrimmed, cleaned_rid);
+}
+
/* Note that each file contains changes for a single replicated area.
trimming algorithm:
*/
#define CL5_TRIM_MAX_PER_TRANSACTION 10
-static void _cl5TrimFile (Object *obj, long *numToTrim, ReplicaId cleaned_rid)
+static void _cl5TrimFile (Object *obj, long *numToTrim)
{
DB_TXN *txnid;
RUV *ruv = NULL;
@@ -3519,7 +3870,6 @@ static void _cl5TrimFile (Object *obj, long *numToTrim, ReplicaId cleaned_rid)
}
entry.op = &op;
-
while ( !finished && !slapi_is_shutting_down() )
{
it = NULL;
@@ -3540,7 +3890,7 @@ static void _cl5TrimFile (Object *obj, long *numToTrim, ReplicaId cleaned_rid)
}
finished = _cl5GetFirstEntry (obj, &entry, &it, txnid);
- while ( !finished )
+ while ( !finished && !slapi_is_shutting_down())
{
/*
* This change can be trimmed if it exceeds purge
@@ -3554,11 +3904,12 @@ static void _cl5TrimFile (Object *obj, long *numToTrim, ReplicaId cleaned_rid)
continue;
}
csn_rid = csn_get_replicaid (op.csn);
+
if ( (*numToTrim > 0 || _cl5CanTrim (entry.time, numToTrim)) &&
ruv_covers_csn_strict (ruv, op.csn) )
{
rc = _cl5CurrentDeleteEntry (it);
- if ( rc == CL5_SUCCESS && cleaned_rid != csn_rid)
+ if ( rc == CL5_SUCCESS)
{
rc = _cl5UpdateRUV (obj, op.csn, PR_FALSE, PR_TRUE);
}
@@ -3572,7 +3923,6 @@ static void _cl5TrimFile (Object *obj, long *numToTrim, ReplicaId cleaned_rid)
/* The above two functions have logged the error */
abort = PR_TRUE;
}
-
}
else
{
@@ -3629,7 +3979,7 @@ static void _cl5TrimFile (Object *obj, long *numToTrim, ReplicaId cleaned_rid)
rc = TXN_ABORT (txnid);
if (rc != 0)
{
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
"_cl5TrimFile: failed to abort transaction; db error - %d %s\n",
rc, db_strerror(rc));
}
@@ -3640,7 +3990,7 @@ static void _cl5TrimFile (Object *obj, long *numToTrim, ReplicaId cleaned_rid)
if (rc != 0)
{
finished = 1;
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
"_cl5TrimFile: failed to commit transaction; db error - %d %s\n",
rc, db_strerror(rc));
}
@@ -4664,9 +5014,9 @@ static int _cl5WriteOperationTxn(const char *replName, const char *replGen,
goto done;
}
#endif
- /* back off */
+ /* back off */
interval = PR_MillisecondsToInterval(slapi_rand() % 100);
- DS_Sleep(interval);
+ DS_Sleep(interval);
}
#if USE_DB_TXN
/* begin transaction */
@@ -4712,19 +5062,19 @@ static int _cl5WriteOperationTxn(const char *replName, const char *replGen,
}
cnt ++;
}
-
+
if (rc == 0) /* we successfully added entry */
{
#if USE_DB_TXN
rc = TXN_COMMIT (txnid, 0);
#endif
}
- else
+ else
{
- char s[CSN_STRSIZE];
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ char s[CSN_STRSIZE];
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
"_cl5WriteOperationTxn: failed to write entry with csn (%s); "
- "db error - %d %s\n", csn_as_string(op->csn,PR_FALSE,s),
+ "db error - %d %s\n", csn_as_string(op->csn,PR_FALSE,s),
rc, db_strerror(rc));
#if USE_DB_TXN
rc = TXN_ABORT (txnid);
@@ -4745,7 +5095,7 @@ static int _cl5WriteOperationTxn(const char *replName, const char *replGen,
/* update purge vector if we have not seen any changes from this replica before */
_cl5UpdateRUV (file_obj, op->csn, PR_TRUE, PR_TRUE);
- slapi_log_error(SLAPI_LOG_PLUGIN, repl_plugin_name_cl,
+ slapi_log_error(SLAPI_LOG_PLUGIN, repl_plugin_name_cl,
"cl5WriteOperationTxn: successfully written entry with csn (%s)\n", csnStr);
rc = CL5_SUCCESS;
done:
@@ -4759,7 +5109,7 @@ done:
return rc;
}
-static int _cl5WriteOperation(const char *replName, const char *replGen,
+static int _cl5WriteOperation(const char *replName, const char *replGen,
const slapi_operation_parameters *op, PRBool local)
{
return _cl5WriteOperationTxn(replName, replGen, op, local, NULL);
@@ -4810,7 +5160,7 @@ static int _cl5GetFirstEntry (Object *obj, CL5Entry *entry, void **iterator, DB_
goto done;
}
- it = (CL5Iterator*)slapi_ch_malloc (sizeof (CL5Iterator));
+ it = (CL5Iterator*)slapi_ch_malloc(sizeof (CL5Iterator));
it->cursor = cursor;
object_acquire (obj);
it->file = obj;
@@ -4885,7 +5235,7 @@ static int _cl5GetNextEntry (CL5Entry *entry, void *iterator)
slapi_ch_free (&(data.data));
if (rc != 0)
{
- slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
"_cl5GetNextEntry: failed to format entry: %d\n", rc);
}
@@ -4914,38 +5264,42 @@ static int _cl5GetNextEntry (CL5Entry *entry, void *iterator)
}
/* cursor operation failed */
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
- "_cl5GetNextEntry: failed to get entry; db error - %d %s\n",
- rc, db_strerror(rc));
+ slapi_log_error(rc == CL5_DB_LOCK_ERROR?SLAPI_LOG_REPL:SLAPI_LOG_FATAL,
+ repl_plugin_name_cl,
+ "_cl5GetNextEntry: failed to get entry; db error - %d %s\n",
+ rc, db_strerror(rc));
- return CL5_DB_ERROR;
+ return rc;
}
static int _cl5CurrentDeleteEntry (void *iterator)
{
int rc;
CL5Iterator *it;
- CL5DBFile *file;
+ CL5DBFile *file;
- PR_ASSERT (iterator);
+ PR_ASSERT (iterator);
it = (CL5Iterator*)iterator;
rc = it->cursor->c_del (it->cursor, 0);
if (rc == 0) {
- /* decrement entry count */
- file = (CL5DBFile*)object_get_data (it->file);
- PR_AtomicDecrement (&file->entryCount);
- return CL5_SUCCESS;
- } else {
- slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
- "_cl5CurrentDeleteEntry failed, err=%d %s\n",
- rc, db_strerror(rc));
- /* We don't free(close) the cursor here, as the caller will free it by a call to cl5DestroyIterator */
- /* Freeing it here is a potential bug, as the cursor can't be referenced later once freed */
- return CL5_DB_ERROR;
- }
+ /* decrement entry count */
+ file = (CL5DBFile*)object_get_data (it->file);
+ PR_AtomicDecrement (&file->entryCount);
+ return CL5_SUCCESS;
+ } else {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5CurrentDeleteEntry failed, err=%d %s\n",
+ rc, db_strerror(rc));
+ /*
+ * We don't free(close) the cursor here, as the caller will free it by
+ * a call to cl5DestroyIterator. Freeing it here is a potential bug,
+ * as the cursor can't be referenced later once freed.
+ */
+ return rc;
+ }
}
static PRBool _cl5IsValidIterator (const CL5Iterator *iterator)
@@ -6217,7 +6571,7 @@ static int _cl5ExportFile (PRFileDesc *prFile, Object *obj)
slapi_write_buffer (prFile, "\n", strlen("\n"));
entry.op = &op;
- rc = _cl5GetFirstEntry (obj, &entry, &iterator, NULL);
+ rc = _cl5GetFirstEntry (obj, &entry, &iterator, NULL);
while (rc == CL5_SUCCESS)
{
rc = _cl5Operation2LDIF (&op, file->replGen, &buff, &len);
@@ -6638,16 +6992,16 @@ cl5CleanRUV(ReplicaId rid){
slapi_rwlock_unlock (s_cl5Desc.stLock);
}
-void trigger_cl_trimming(ReplicaId rid){
+void trigger_cl_purging(ReplicaId rid){
PRThread *trim_tid = NULL;
- slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "trigger_cl_trimming: rid (%d)\n",(int)rid);
- trim_tid = PR_CreateThread(PR_USER_THREAD, (VFP)(void*)trigger_cl_trimming_thread,
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "trigger_cl_purging: rid (%d)\n",(int)rid);
+ trim_tid = PR_CreateThread(PR_USER_THREAD, (VFP)(void*)trigger_cl_purging_thread,
(void *)&rid, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
PR_UNJOINABLE_THREAD, DEFAULT_THREAD_STACKSIZE);
if (NULL == trim_tid){
slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
- "trigger_cl_trimming: failed to create trimming "
+ "trigger_cl_purging: failed to create trimming "
"thread; NSPR error - %d\n", PR_GetError ());
} else {
/* need a little time for the thread to get started */
@@ -6656,7 +7010,7 @@ void trigger_cl_trimming(ReplicaId rid){
}
void
-trigger_cl_trimming_thread(void *arg){
+trigger_cl_purging_thread(void *arg){
ReplicaId rid = *(ReplicaId *)arg;
/* make sure we have a change log, and we aren't closing it */
@@ -6665,7 +7019,7 @@ trigger_cl_trimming_thread(void *arg){
}
if (CL5_SUCCESS != _cl5AddThread()) {
slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
- "trigger_cl_trimming: failed to increment thread count "
+ "trigger_cl_purging: failed to increment thread count "
"NSPR error - %d\n", PR_GetError ());
}
_cl5DoTrimming(rid);
diff --git a/ldap/servers/plugins/replication/cl5_api.h b/ldap/servers/plugins/replication/cl5_api.h
index 9b285ca..b46a691 100644
--- a/ldap/servers/plugins/replication/cl5_api.h
+++ b/ldap/servers/plugins/replication/cl5_api.h
@@ -145,6 +145,9 @@ enum
CL5_CSN_ERROR, /* CSN API failed */
CL5_RUV_ERROR, /* RUV API failed */
CL5_OBJSET_ERROR, /* namedobjset api failed */
+ CL5_DB_LOCK_ERROR, /* bdb returns error 12 when the db runs out of locks,
+ this var needs to be in slot 12 of the list.
+ Do not re-order enum above! */
CL5_PURGED_DATA, /* requested data has been purged */
CL5_MISSING_DATA, /* data should be in the changelog, but is missing */
CL5_UNKNOWN_ERROR, /* unclassified error */
@@ -490,6 +493,6 @@ int cl5WriteRUV();
int cl5DeleteRUV();
void cl5CleanRUV(ReplicaId rid);
void cl5NotifyCleanup(int rid);
-void trigger_cl_trimming(ReplicaId rid);
+void trigger_cl_purging(ReplicaId rid);
#endif
diff --git a/ldap/servers/plugins/replication/repl5_replica_config.c b/ldap/servers/plugins/replication/repl5_replica_config.c
index 73eef6f..7bc387a 100644
--- a/ldap/servers/plugins/replication/repl5_replica_config.c
+++ b/ldap/servers/plugins/replication/repl5_replica_config.c
@@ -1324,6 +1324,11 @@ replica_execute_cleanruv_task (Object *r, ReplicaId rid, char *returntext /* not
*/
cl5CleanRUV(rid);
+ /*
+ * Now purge the changelog
+ */
+ trigger_cl_purging(rid);
+
if (rc != RUV_SUCCESS){
slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cleanruv_task: task failed(%d)\n",rc);
return LDAP_OPERATIONS_ERROR;
@@ -1711,7 +1716,7 @@ replica_cleanallruv_thread(void *arg)
/* no agmts, just clean this replica */
break;
}
- while (agmt_obj){
+ while (agmt_obj && !slapi_is_shutting_down()){
agmt = (Repl_Agmt*)object_get_data (agmt_obj);
if(!agmt_is_enabled(agmt) || get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
@@ -1793,13 +1798,15 @@ replica_cleanallruv_thread(void *arg)
break;
}
/*
- * need to sleep between passes
+ * Need to sleep between passes unless we are shutting down
*/
- cleanruv_log(data->task, data->rid, CLEANALLRUV_ID, "Replicas have not been cleaned yet, "
- "retrying in %d seconds", interval);
- PR_Lock( notify_lock );
- PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
- PR_Unlock( notify_lock );
+ if (!slapi_is_shutting_down()){
+ cleanruv_log(data->task, data->rid, CLEANALLRUV_ID, "Replicas have not been cleaned yet, "
+ "retrying in %d seconds", interval);
+ PR_Lock( notify_lock );
+ PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
+ PR_Unlock( notify_lock );
+ }
if(interval < 14400){ /* 4 hour max */
interval = interval * 2;
@@ -1810,10 +1817,9 @@ replica_cleanallruv_thread(void *arg)
done:
/*
- * If the replicas are cleaned, release the rid, and trim the changelog
+ * If the replicas are cleaned, release the rid
*/
if(!aborted){
- trigger_cl_trimming(data->rid);
delete_cleaned_rid_config(data);
/* make sure all the replicas have been "pre_cleaned" before finishing */
check_replicas_are_done_cleaning(data);
@@ -1823,7 +1829,7 @@ done:
/*
* Shutdown or abort
*/
- if(!is_task_aborted(data->rid)){
+ if(!is_task_aborted(data->rid) || slapi_is_shutting_down()){
cleanruv_log(data->task, data->rid, CLEANALLRUV_ID,"Server shutting down. Process will resume at server startup");
} else {
cleanruv_log(data->task, data->rid, CLEANALLRUV_ID,"Task aborted for rid(%d).",data->rid);
@@ -2026,7 +2032,7 @@ check_agmts_are_caught_up(cleanruv_data *data, char *maxcsn)
not_all_caughtup = 0;
break;
}
- while (agmt_obj){
+ while (agmt_obj && !slapi_is_shutting_down()){
agmt = (Repl_Agmt*)object_get_data (agmt_obj);
if(!agmt_is_enabled(agmt) || get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
agmt_obj = agmtlist_get_next_agreement_for_replica (data->replica, agmt_obj);
@@ -2084,7 +2090,7 @@ check_agmts_are_alive(Replica *replica, ReplicaId rid, Slapi_Task *task)
not_all_alive = 0;
break;
}
- while (agmt_obj){
+ while (agmt_obj && !slapi_is_shutting_down()){
agmt = (Repl_Agmt*)object_get_data (agmt_obj);
if(!agmt_is_enabled(agmt) || get_agmt_agreement_type(agmt) == REPLICA_TYPE_WINDOWS){
agmt_obj = agmtlist_get_next_agreement_for_replica (replica, agmt_obj);
@@ -2853,12 +2859,14 @@ replica_abort_task_thread(void *arg)
break;
}
/*
- * need to sleep between passes
+ * Need to sleep between passes. unless we are shutting down
*/
- cleanruv_log(data->task, data->rid, ABORT_CLEANALLRUV_ID,"Retrying in %d seconds",interval);
- PR_Lock( notify_lock );
- PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
- PR_Unlock( notify_lock );
+ if (!slapi_is_shutting_down()){
+ cleanruv_log(data->task, data->rid, ABORT_CLEANALLRUV_ID,"Retrying in %d seconds",interval);
+ PR_Lock( notify_lock );
+ PR_WaitCondVar( notify_cvar, PR_SecondsToInterval(interval) );
+ PR_Unlock( notify_lock );
+ }
if(interval < 14400){ /* 4 hour max */
interval = interval * 2;
@@ -2876,7 +2884,7 @@ done:
* Wait for this server to stop its cleanallruv task(which removes the rid from the cleaned list)
*/
cleanruv_log(data->task, data->rid, ABORT_CLEANALLRUV_ID, "Waiting for CleanAllRUV task to abort...");
- while(is_cleaned_rid(data->rid)){
+ while(is_cleaned_rid(data->rid) && !slapi_is_shutting_down()){
DS_Sleep(PR_SecondsToInterval(1));
count++;
if(count == 60){ /* it should not take this long */
8 years, 6 months
Branch '389-ds-base-1.3.3' - ldap/servers
by Noriko Hosoi
ldap/servers/slapd/log.c | 109 ++++++++++++++++++++++++++++-------------------
1 file changed, 67 insertions(+), 42 deletions(-)
New commits:
commit 8081a91a7a1714396a377871d1f676f000d7a4d5
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Thu Oct 8 10:30:07 2015 -0700
Ticket #48304 - ns-slapd - LOGINFO:Unable to remove file
Description: In the log rotation, if a log file to be deleted does
not exist, the "Unable to remove file" is logged in the error log,
which is not necessary.
This patch updates the logging code to suppress the unnecessary log
messages as well as replace with more detailed ones.
https://fedorahosted.org/389/ticket/48304
Reviewed by mreynolds(a)redhat.com (Thank you, Mark!!)
(cherry picked from commit e2abffcc5cf6e63136fc0bcb5b0e12830cca22a5)
(cherry picked from commit 6c71c0d96d2287bcae88942ce6d5a0f7df5bee84)
diff --git a/ldap/servers/slapd/log.c b/ldap/servers/slapd/log.c
index 1014a03..817751a 100644
--- a/ldap/servers/slapd/log.c
+++ b/ldap/servers/slapd/log.c
@@ -2465,15 +2465,25 @@ log__delete_access_logfile()
loginfo.log_access_fdes = NULL;
PR_snprintf (buffer, sizeof(buffer), "%s", loginfo.log_access_file);
if (PR_Delete(buffer) != PR_SUCCESS) {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s\n", loginfo.log_access_file,0,0);
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_access_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s error %d (%s)\n",
+ loginfo.log_access_file, prerr, slapd_pr_strerror(prerr));
+ }
}
/* Delete the rotation file also. */
PR_snprintf (buffer, sizeof(buffer), "%s.rotationinfo", loginfo.log_access_file);
if (PR_Delete(buffer) != PR_SUCCESS) {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s.rotationinfo\n", loginfo.log_access_file,0,0);
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_access_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s.rotationinfo error %d (%s)\n",
+ loginfo.log_access_file, prerr, slapd_pr_strerror(prerr));
+ }
}
return 0;
}
@@ -2575,15 +2585,15 @@ delete_logfile:
log_convert_time (delete_logp->l_ctime, tbuf, 1 /*short */);
PR_snprintf (buffer, sizeof(buffer), "%s.%s", loginfo.log_access_file, tbuf);
if (PR_Delete(buffer) != PR_SUCCESS) {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s.%s\n",
- loginfo.log_access_file,tbuf,0);
-
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_access_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s.%s error %d (%s)\n",
+ loginfo.log_access_file, tbuf, prerr, slapd_pr_strerror(prerr));
+ }
} else {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Removed file:%s.%s because of (%s)\n",
- loginfo.log_access_file, tbuf,
- logstr);
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Removed file:%s.%s because of (%s)\n", loginfo.log_access_file, tbuf, logstr);
}
slapi_ch_free((void**)&delete_logp);
loginfo.log_numof_access_logs--;
@@ -3245,7 +3255,6 @@ log__delete_error_logfile(int locked)
char buffer[BUFSIZ];
char tbuf[TBUFSIZE];
-
/* If we have only one log, then will delete this one */
if (loginfo.log_error_maxnumlogs == 1) {
LOG_CLOSE(loginfo.log_error_fdes);
@@ -3253,10 +3262,14 @@ log__delete_error_logfile(int locked)
PR_snprintf (buffer, sizeof(buffer), "%s", loginfo.log_error_file);
if (PR_Delete(buffer) != PR_SUCCESS) {
if (!locked) {
- /* if locked, we should not call LDAPDebug,
- which tries to get a lock internally. */
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s\n", loginfo.log_error_file,0,0);
+ /* If locked, we should not call LDAPDebug, which tries to get a lock internally. */
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_error_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s error %d (%s)\n",
+ loginfo.log_error_file, prerr, slapd_pr_strerror(prerr));
+ }
}
}
@@ -3264,11 +3277,14 @@ log__delete_error_logfile(int locked)
PR_snprintf (buffer, sizeof(buffer), "%s.rotationinfo", loginfo.log_error_file);
if (PR_Delete(buffer) != PR_SUCCESS) {
if (!locked) {
- /* if locked, we should not call LDAPDebug,
- which tries to get a lock internally. */
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s.rotationinfo\n",
- loginfo.log_error_file,0,0);
+ /* If locked, we should not call LDAPDebug, which tries to get a lock internally. */
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_error_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s.rotationinfo error %d (%s)\n",
+ loginfo.log_error_file, prerr, slapd_pr_strerror(prerr));
+ }
}
}
return 0;
@@ -3380,10 +3396,11 @@ delete_logfile:
PR_snprintf (buffer, sizeof(buffer), "%s.%s", loginfo.log_error_file, tbuf);
if (PR_Delete(buffer) != PR_SUCCESS) {
PRErrorCode prerr = PR_GetError();
- PR_snprintf(buffer, sizeof(buffer),
- "LOGINFO:Unable to remove file:%s.%s error %d (%s)\n",
- loginfo.log_error_file, tbuf, prerr, slapd_pr_strerror(prerr));
- log__error_emergency(buffer, 0, locked);
+ if (PR_FILE_NOT_FOUND_ERROR != prerr) {
+ PR_snprintf(buffer, sizeof(buffer), "LOGINFO:Unable to remove file:%s.%s error %d (%s)\n",
+ loginfo.log_error_file, tbuf, prerr, slapd_pr_strerror(prerr));
+ log__error_emergency(buffer, 0, locked);
+ }
}
slapi_ch_free((void**)&delete_logp);
loginfo.log_numof_error_logs--;
@@ -3423,15 +3440,25 @@ log__delete_audit_logfile()
loginfo.log_audit_fdes = NULL;
PR_snprintf(buffer, sizeof(buffer), "%s", loginfo.log_audit_file);
if (PR_Delete(buffer) != PR_SUCCESS) {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s\n", loginfo.log_audit_file,0,0);
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_audit_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s error %d (%s)\n",
+ loginfo.log_audit_file, prerr, slapd_pr_strerror(prerr));
+ }
}
/* Delete the rotation file also. */
PR_snprintf(buffer, sizeof(buffer), "%s.rotationinfo", loginfo.log_audit_file);
if (PR_Delete(buffer) != PR_SUCCESS) {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s.rotationinfo\n", loginfo.log_audit_file,0,0);
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_audit_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s.rotatoininfo error %d (%s)\n",
+ loginfo.log_audit_file, prerr, slapd_pr_strerror(prerr));
+ }
}
return 0;
}
@@ -3532,15 +3559,15 @@ delete_logfile:
log_convert_time (delete_logp->l_ctime, tbuf, 1 /*short */);
PR_snprintf(buffer, sizeof(buffer), "%s.%s", loginfo.log_audit_file, tbuf );
if (PR_Delete(buffer) != PR_SUCCESS) {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s.%s\n",
- loginfo.log_audit_file, tbuf,0);
-
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_audit_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s.%s error %d (%s)\n",
+ loginfo.log_audit_file, tbuf, prerr, slapd_pr_strerror(prerr));
+ }
} else {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Removed file:%s.%s because of (%s)\n",
- loginfo.log_audit_file, tbuf,
- logstr);
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Removed file:%s.%s because of (%s)\n", loginfo.log_audit_file, tbuf, logstr);
}
slapi_ch_free((void**)&delete_logp);
loginfo.log_numof_audit_logs--;
@@ -3822,10 +3849,8 @@ log__open_errorlogfile(int logfile_state, int locked)
Even if PR_Rename fails with the error, we continue logging.
*/
if (PR_FILE_EXISTS_ERROR != prerr) {
- PR_snprintf(buffer, sizeof(buffer),
- "Failed to rename errors log file, "
- SLAPI_COMPONENT_NAME_NSPR " error %d (%s). Exiting...",
- prerr, slapd_pr_strerror(prerr));
+ PR_snprintf(buffer, sizeof(buffer), "Failed to rename errors log file, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s). Exiting...\n", prerr, slapd_pr_strerror(prerr));
log__error_emergency(buffer, 1, 1);
slapi_ch_free((void **)&log);
if (!locked) LOG_ERROR_UNLOCK_WRITE();
8 years, 6 months
Branch '389-ds-base-1.3.4' - ldap/servers
by Noriko Hosoi
ldap/servers/slapd/log.c | 109 ++++++++++++++++++++++++++++-------------------
1 file changed, 67 insertions(+), 42 deletions(-)
New commits:
commit 6c71c0d96d2287bcae88942ce6d5a0f7df5bee84
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Thu Oct 8 10:30:07 2015 -0700
Ticket #48304 - ns-slapd - LOGINFO:Unable to remove file
Description: In the log rotation, if a log file to be deleted does
not exist, the "Unable to remove file" is logged in the error log,
which is not necessary.
This patch updates the logging code to suppress the unnecessary log
messages as well as replace with more detailed ones.
https://fedorahosted.org/389/ticket/48304
Reviewed by mreynolds(a)redhat.com (Thank you, Mark!!)
(cherry picked from commit e2abffcc5cf6e63136fc0bcb5b0e12830cca22a5)
diff --git a/ldap/servers/slapd/log.c b/ldap/servers/slapd/log.c
index 1458e54..2ec90de 100644
--- a/ldap/servers/slapd/log.c
+++ b/ldap/servers/slapd/log.c
@@ -2330,15 +2330,25 @@ log__delete_access_logfile()
loginfo.log_access_fdes = NULL;
PR_snprintf (buffer, sizeof(buffer), "%s", loginfo.log_access_file);
if (PR_Delete(buffer) != PR_SUCCESS) {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s\n", loginfo.log_access_file,0,0);
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_access_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s error %d (%s)\n",
+ loginfo.log_access_file, prerr, slapd_pr_strerror(prerr));
+ }
}
/* Delete the rotation file also. */
PR_snprintf (buffer, sizeof(buffer), "%s.rotationinfo", loginfo.log_access_file);
if (PR_Delete(buffer) != PR_SUCCESS) {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s.rotationinfo\n", loginfo.log_access_file,0,0);
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_access_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s.rotationinfo error %d (%s)\n",
+ loginfo.log_access_file, prerr, slapd_pr_strerror(prerr));
+ }
}
return 0;
}
@@ -2440,15 +2450,15 @@ delete_logfile:
log_convert_time (delete_logp->l_ctime, tbuf, 1 /*short */);
PR_snprintf (buffer, sizeof(buffer), "%s.%s", loginfo.log_access_file, tbuf);
if (PR_Delete(buffer) != PR_SUCCESS) {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s.%s\n",
- loginfo.log_access_file,tbuf,0);
-
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_access_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s.%s error %d (%s)\n",
+ loginfo.log_access_file, tbuf, prerr, slapd_pr_strerror(prerr));
+ }
} else {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Removed file:%s.%s because of (%s)\n",
- loginfo.log_access_file, tbuf,
- logstr);
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Removed file:%s.%s because of (%s)\n", loginfo.log_access_file, tbuf, logstr);
}
slapi_ch_free((void**)&delete_logp);
loginfo.log_numof_access_logs--;
@@ -3067,7 +3077,6 @@ log__delete_error_logfile(int locked)
char buffer[BUFSIZ];
char tbuf[TBUFSIZE];
-
/* If we have only one log, then will delete this one */
if (loginfo.log_error_maxnumlogs == 1) {
LOG_CLOSE(loginfo.log_error_fdes);
@@ -3075,10 +3084,14 @@ log__delete_error_logfile(int locked)
PR_snprintf (buffer, sizeof(buffer), "%s", loginfo.log_error_file);
if (PR_Delete(buffer) != PR_SUCCESS) {
if (!locked) {
- /* if locked, we should not call LDAPDebug,
- which tries to get a lock internally. */
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s\n", loginfo.log_error_file,0,0);
+ /* If locked, we should not call LDAPDebug, which tries to get a lock internally. */
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_error_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s error %d (%s)\n",
+ loginfo.log_error_file, prerr, slapd_pr_strerror(prerr));
+ }
}
}
@@ -3086,11 +3099,14 @@ log__delete_error_logfile(int locked)
PR_snprintf (buffer, sizeof(buffer), "%s.rotationinfo", loginfo.log_error_file);
if (PR_Delete(buffer) != PR_SUCCESS) {
if (!locked) {
- /* if locked, we should not call LDAPDebug,
- which tries to get a lock internally. */
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s.rotationinfo\n",
- loginfo.log_error_file,0,0);
+ /* If locked, we should not call LDAPDebug, which tries to get a lock internally. */
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_error_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s.rotationinfo error %d (%s)\n",
+ loginfo.log_error_file, prerr, slapd_pr_strerror(prerr));
+ }
}
}
return 0;
@@ -3202,10 +3218,11 @@ delete_logfile:
PR_snprintf (buffer, sizeof(buffer), "%s.%s", loginfo.log_error_file, tbuf);
if (PR_Delete(buffer) != PR_SUCCESS) {
PRErrorCode prerr = PR_GetError();
- PR_snprintf(buffer, sizeof(buffer),
- "LOGINFO:Unable to remove file:%s.%s error %d (%s)\n",
- loginfo.log_error_file, tbuf, prerr, slapd_pr_strerror(prerr));
- log__error_emergency(buffer, 0, locked);
+ if (PR_FILE_NOT_FOUND_ERROR != prerr) {
+ PR_snprintf(buffer, sizeof(buffer), "LOGINFO:Unable to remove file:%s.%s error %d (%s)\n",
+ loginfo.log_error_file, tbuf, prerr, slapd_pr_strerror(prerr));
+ log__error_emergency(buffer, 0, locked);
+ }
}
slapi_ch_free((void**)&delete_logp);
loginfo.log_numof_error_logs--;
@@ -3245,15 +3262,25 @@ log__delete_audit_logfile()
loginfo.log_audit_fdes = NULL;
PR_snprintf(buffer, sizeof(buffer), "%s", loginfo.log_audit_file);
if (PR_Delete(buffer) != PR_SUCCESS) {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s\n", loginfo.log_audit_file,0,0);
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_audit_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s error %d (%s)\n",
+ loginfo.log_audit_file, prerr, slapd_pr_strerror(prerr));
+ }
}
/* Delete the rotation file also. */
PR_snprintf(buffer, sizeof(buffer), "%s.rotationinfo", loginfo.log_audit_file);
if (PR_Delete(buffer) != PR_SUCCESS) {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s.rotationinfo\n", loginfo.log_audit_file,0,0);
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_audit_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s.rotatoininfo error %d (%s)\n",
+ loginfo.log_audit_file, prerr, slapd_pr_strerror(prerr));
+ }
}
return 0;
}
@@ -3354,15 +3381,15 @@ delete_logfile:
log_convert_time (delete_logp->l_ctime, tbuf, 1 /*short */);
PR_snprintf(buffer, sizeof(buffer), "%s.%s", loginfo.log_audit_file, tbuf );
if (PR_Delete(buffer) != PR_SUCCESS) {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s.%s\n",
- loginfo.log_audit_file, tbuf,0);
-
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_audit_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s.%s error %d (%s)\n",
+ loginfo.log_audit_file, tbuf, prerr, slapd_pr_strerror(prerr));
+ }
} else {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Removed file:%s.%s because of (%s)\n",
- loginfo.log_audit_file, tbuf,
- logstr);
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Removed file:%s.%s because of (%s)\n", loginfo.log_audit_file, tbuf, logstr);
}
slapi_ch_free((void**)&delete_logp);
loginfo.log_numof_audit_logs--;
@@ -3640,10 +3667,8 @@ log__open_errorlogfile(int logfile_state, int locked)
Even if PR_Rename fails with the error, we continue logging.
*/
if (PR_FILE_EXISTS_ERROR != prerr) {
- PR_snprintf(buffer, sizeof(buffer),
- "Failed to rename errors log file, "
- SLAPI_COMPONENT_NAME_NSPR " error %d (%s). Exiting...",
- prerr, slapd_pr_strerror(prerr));
+ PR_snprintf(buffer, sizeof(buffer), "Failed to rename errors log file, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s). Exiting...\n", prerr, slapd_pr_strerror(prerr));
log__error_emergency(buffer, 1, 1);
slapi_ch_free((void **)&log);
if (!locked) LOG_ERROR_UNLOCK_WRITE();
8 years, 6 months
ldap/servers
by Noriko Hosoi
ldap/servers/slapd/log.c | 109 ++++++++++++++++++++++++++++-------------------
1 file changed, 67 insertions(+), 42 deletions(-)
New commits:
commit e2abffcc5cf6e63136fc0bcb5b0e12830cca22a5
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Thu Oct 8 10:30:07 2015 -0700
Ticket #48304 - ns-slapd - LOGINFO:Unable to remove file
Description: In the log rotation, if a log file to be deleted does
not exist, the "Unable to remove file" is logged in the error log,
which is not necessary.
This patch updates the logging code to suppress the unnecessary log
messages as well as replace with more detailed ones.
https://fedorahosted.org/389/ticket/48304
Reviewed by mreynolds(a)redhat.com (Thank you, Mark!!)
diff --git a/ldap/servers/slapd/log.c b/ldap/servers/slapd/log.c
index 1458e54..2ec90de 100644
--- a/ldap/servers/slapd/log.c
+++ b/ldap/servers/slapd/log.c
@@ -2330,15 +2330,25 @@ log__delete_access_logfile()
loginfo.log_access_fdes = NULL;
PR_snprintf (buffer, sizeof(buffer), "%s", loginfo.log_access_file);
if (PR_Delete(buffer) != PR_SUCCESS) {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s\n", loginfo.log_access_file,0,0);
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_access_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s error %d (%s)\n",
+ loginfo.log_access_file, prerr, slapd_pr_strerror(prerr));
+ }
}
/* Delete the rotation file also. */
PR_snprintf (buffer, sizeof(buffer), "%s.rotationinfo", loginfo.log_access_file);
if (PR_Delete(buffer) != PR_SUCCESS) {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s.rotationinfo\n", loginfo.log_access_file,0,0);
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_access_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s.rotationinfo error %d (%s)\n",
+ loginfo.log_access_file, prerr, slapd_pr_strerror(prerr));
+ }
}
return 0;
}
@@ -2440,15 +2450,15 @@ delete_logfile:
log_convert_time (delete_logp->l_ctime, tbuf, 1 /*short */);
PR_snprintf (buffer, sizeof(buffer), "%s.%s", loginfo.log_access_file, tbuf);
if (PR_Delete(buffer) != PR_SUCCESS) {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s.%s\n",
- loginfo.log_access_file,tbuf,0);
-
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_access_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s.%s error %d (%s)\n",
+ loginfo.log_access_file, tbuf, prerr, slapd_pr_strerror(prerr));
+ }
} else {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Removed file:%s.%s because of (%s)\n",
- loginfo.log_access_file, tbuf,
- logstr);
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Removed file:%s.%s because of (%s)\n", loginfo.log_access_file, tbuf, logstr);
}
slapi_ch_free((void**)&delete_logp);
loginfo.log_numof_access_logs--;
@@ -3067,7 +3077,6 @@ log__delete_error_logfile(int locked)
char buffer[BUFSIZ];
char tbuf[TBUFSIZE];
-
/* If we have only one log, then will delete this one */
if (loginfo.log_error_maxnumlogs == 1) {
LOG_CLOSE(loginfo.log_error_fdes);
@@ -3075,10 +3084,14 @@ log__delete_error_logfile(int locked)
PR_snprintf (buffer, sizeof(buffer), "%s", loginfo.log_error_file);
if (PR_Delete(buffer) != PR_SUCCESS) {
if (!locked) {
- /* if locked, we should not call LDAPDebug,
- which tries to get a lock internally. */
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s\n", loginfo.log_error_file,0,0);
+ /* If locked, we should not call LDAPDebug, which tries to get a lock internally. */
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_error_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s error %d (%s)\n",
+ loginfo.log_error_file, prerr, slapd_pr_strerror(prerr));
+ }
}
}
@@ -3086,11 +3099,14 @@ log__delete_error_logfile(int locked)
PR_snprintf (buffer, sizeof(buffer), "%s.rotationinfo", loginfo.log_error_file);
if (PR_Delete(buffer) != PR_SUCCESS) {
if (!locked) {
- /* if locked, we should not call LDAPDebug,
- which tries to get a lock internally. */
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s.rotationinfo\n",
- loginfo.log_error_file,0,0);
+ /* If locked, we should not call LDAPDebug, which tries to get a lock internally. */
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_error_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s.rotationinfo error %d (%s)\n",
+ loginfo.log_error_file, prerr, slapd_pr_strerror(prerr));
+ }
}
}
return 0;
@@ -3202,10 +3218,11 @@ delete_logfile:
PR_snprintf (buffer, sizeof(buffer), "%s.%s", loginfo.log_error_file, tbuf);
if (PR_Delete(buffer) != PR_SUCCESS) {
PRErrorCode prerr = PR_GetError();
- PR_snprintf(buffer, sizeof(buffer),
- "LOGINFO:Unable to remove file:%s.%s error %d (%s)\n",
- loginfo.log_error_file, tbuf, prerr, slapd_pr_strerror(prerr));
- log__error_emergency(buffer, 0, locked);
+ if (PR_FILE_NOT_FOUND_ERROR != prerr) {
+ PR_snprintf(buffer, sizeof(buffer), "LOGINFO:Unable to remove file:%s.%s error %d (%s)\n",
+ loginfo.log_error_file, tbuf, prerr, slapd_pr_strerror(prerr));
+ log__error_emergency(buffer, 0, locked);
+ }
}
slapi_ch_free((void**)&delete_logp);
loginfo.log_numof_error_logs--;
@@ -3245,15 +3262,25 @@ log__delete_audit_logfile()
loginfo.log_audit_fdes = NULL;
PR_snprintf(buffer, sizeof(buffer), "%s", loginfo.log_audit_file);
if (PR_Delete(buffer) != PR_SUCCESS) {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s\n", loginfo.log_audit_file,0,0);
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_audit_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s error %d (%s)\n",
+ loginfo.log_audit_file, prerr, slapd_pr_strerror(prerr));
+ }
}
/* Delete the rotation file also. */
PR_snprintf(buffer, sizeof(buffer), "%s.rotationinfo", loginfo.log_audit_file);
if (PR_Delete(buffer) != PR_SUCCESS) {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s.rotationinfo\n", loginfo.log_audit_file,0,0);
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_audit_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s.rotatoininfo error %d (%s)\n",
+ loginfo.log_audit_file, prerr, slapd_pr_strerror(prerr));
+ }
}
return 0;
}
@@ -3354,15 +3381,15 @@ delete_logfile:
log_convert_time (delete_logp->l_ctime, tbuf, 1 /*short */);
PR_snprintf(buffer, sizeof(buffer), "%s.%s", loginfo.log_audit_file, tbuf );
if (PR_Delete(buffer) != PR_SUCCESS) {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Unable to remove file:%s.%s\n",
- loginfo.log_audit_file, tbuf,0);
-
+ PRErrorCode prerr = PR_GetError();
+ if (PR_FILE_NOT_FOUND_ERROR == prerr) {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "File %s already removed\n", loginfo.log_audit_file);
+ } else {
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Unable to remove file:%s.%s error %d (%s)\n",
+ loginfo.log_audit_file, tbuf, prerr, slapd_pr_strerror(prerr));
+ }
} else {
- LDAPDebug(LDAP_DEBUG_TRACE,
- "LOGINFO:Removed file:%s.%s because of (%s)\n",
- loginfo.log_audit_file, tbuf,
- logstr);
+ slapi_log_error(SLAPI_LOG_TRACE, "LOGINFO", "Removed file:%s.%s because of (%s)\n", loginfo.log_audit_file, tbuf, logstr);
}
slapi_ch_free((void**)&delete_logp);
loginfo.log_numof_audit_logs--;
@@ -3640,10 +3667,8 @@ log__open_errorlogfile(int logfile_state, int locked)
Even if PR_Rename fails with the error, we continue logging.
*/
if (PR_FILE_EXISTS_ERROR != prerr) {
- PR_snprintf(buffer, sizeof(buffer),
- "Failed to rename errors log file, "
- SLAPI_COMPONENT_NAME_NSPR " error %d (%s). Exiting...",
- prerr, slapd_pr_strerror(prerr));
+ PR_snprintf(buffer, sizeof(buffer), "Failed to rename errors log file, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s). Exiting...\n", prerr, slapd_pr_strerror(prerr));
log__error_emergency(buffer, 1, 1);
slapi_ch_free((void **)&log);
if (!locked) LOG_ERROR_UNLOCK_WRITE();
8 years, 6 months