dirsrvtests/README dirsrvtests/stress rpm/389-ds-base.spec.in
by Mark Reynolds
dirsrvtests/README | 28 +
dirsrvtests/stress/README | 13
dirsrvtests/stress/__init__.py | 1
dirsrvtests/stress/reliabilty/reliab_7_5_test.py | 570 +++++++++++++++++++++++
rpm/389-ds-base.spec.in | 23
5 files changed, 635 insertions(+)
New commits:
commit 27da34cf51a8719581cee07cc015ac7ea9472b5a
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Mon Dec 21 17:23:58 2015 -0500
Ticket 48376 - Create a 389-ds-base-tests RPM package
Description: Create a sub-package for the lib389 CI tests
(requires python-lib389)
Also added a stress test that was not committed
yet, and some READMEs for the tests.
https://fedorahosted.org/389/ticket/48376
Reviewed by: nhosoi(Thanks!)
diff --git a/dirsrvtests/README b/dirsrvtests/README
new file mode 100644
index 0000000..48b003f
--- /dev/null
+++ b/dirsrvtests/README
@@ -0,0 +1,28 @@
+389-ds-base-tests README
+=================================================
+
+Prerequisites:
+-------------------------------------------------
+Install the python-lib389 packages, or
+download the source(git clone ssh://git.fedorahosted.org/git/389/lib389.git) and set your PYTHONPATH accordingly
+
+
+Description:
+-------------------------------------------------
+This package includes python-lib389 based python scripts for testing the Directory Server. The following describes the various types of tests available:
+
+tickets - These scripts test individual bug fixes
+suites - These test functinoal areas of the server
+stress - These tests perform "stress" tests on the server
+
+There is also a "create_test.py" script available to construct a template test script for creating new tests.
+
+
+Documentation:
+-------------------------------------------------
+See http://www.port389.org for the latest information
+
+http://www.port389.org/docs/389ds/FAQ/upstream-test-framework.html
+http://www.port389.org/docs/389ds/howto/howto-write-lib389.html
+http://www.port389.org/docs/389ds/howto/howto-run-lib389-jenkins.html
+
diff --git a/dirsrvtests/stress/README b/dirsrvtests/stress/README
new file mode 100644
index 0000000..758cad4
--- /dev/null
+++ b/dirsrvtests/stress/README
@@ -0,0 +1,13 @@
+README for "Stress" Tests
+
+Reliablity Tests
+==============================
+
+A generic high load, long running tests
+
+reliab7_5_test.py
+------------------------------
+
+This script is a light-weight version of the legacy TET stress test called "Reliabilty 15". This test consists of two MMR Masters, and a 5000 entry database. The test starts off with two threads doing unindexed searchesi(1 for each master). These do not exit untl the entire test completes. Then while the unindexed searches are going on, the test performs a set of adds, mods, deletes, and modrdns on each master at the same time. It performs this set of operations 1000 times. The main goal of this script is to test stablilty, replication convergence, and memory growth/fragmentation.
+
+Known issue: the server can deadlock in the libdb4 code while performing modrdns(under investigation via https://fedorahosted.org/389/ticket/48166)
diff --git a/dirsrvtests/stress/__init__.py b/dirsrvtests/stress/__init__.py
new file mode 100644
index 0000000..40a96af
--- /dev/null
+++ b/dirsrvtests/stress/__init__.py
@@ -0,0 +1 @@
+# -*- coding: utf-8 -*-
diff --git a/dirsrvtests/stress/reliabilty/__init__.py b/dirsrvtests/stress/reliabilty/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/dirsrvtests/stress/reliabilty/reliab_7_5_test.py b/dirsrvtests/stress/reliabilty/reliab_7_5_test.py
new file mode 100644
index 0000000..b827033
--- /dev/null
+++ b/dirsrvtests/stress/reliabilty/reliab_7_5_test.py
@@ -0,0 +1,570 @@
+# --- 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 sys
+import time
+import ldap
+import logging
+import pytest
+import threading
+import random
+from lib389 import DirSrv, Entry
+from lib389._constants import *
+from lib389.properties import *
+from lib389.tasks import *
+from lib389.utils import *
+
+logging.getLogger(__name__).setLevel(logging.DEBUG)
+formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s' +
+ ' - %(message)s')
+handler = logging.StreamHandler()
+handler.setFormatter(formatter)
+log = logging.getLogger(__name__)
+log.addHandler(handler)
+
+installation1_prefix = None
+NUM_USERS = 5000
+MAX_PASSES = 1000
+CHECK_CONVERGENCE = True
+ENABLE_VALGRIND = False
+RUNNING = True
+
+
+class TopologyReplication(object):
+ def __init__(self, master1, master2):
+ master1.open()
+ self.master1 = master1
+ master2.open()
+ self.master2 = master2
+
+
+(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=True)
+ 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)
+
+ #
+ # Import tests entries into master1 before we initialize master2
+ #
+ tmp_dir = master1.getDir(__file__, TMP_DIR)
+
+ import_ldif = tmp_dir + '/rel7.5-entries.ldif'
+
+ # First generate an ldif
+ try:
+ ldif = open(import_ldif, 'w')
+ except IOError as e:
+ log.fatal('Failed to create test ldif, error: %s - %s' %
+ (e.errno, e.strerror))
+ assert False
+
+ # Create the root node
+ ldif.write('dn: ' + DEFAULT_SUFFIX + '\n')
+ ldif.write('objectclass: top\n')
+ ldif.write('objectclass: domain\n')
+ ldif.write('dc: example\n')
+ ldif.write('\n')
+
+ # Create the entries
+ idx = 0
+ while idx < NUM_USERS:
+ count = str(idx)
+ ldif.write('dn: uid=master1_entry' + count + ',' +
+ DEFAULT_SUFFIX + '\n')
+ ldif.write('objectclass: top\n')
+ ldif.write('objectclass: person\n')
+ ldif.write('objectclass: inetorgperson\n')
+ ldif.write('objectclass: organizationalperson\n')
+ ldif.write('uid: master1_entry' + count + '\n')
+ ldif.write('cn: master1 entry' + count + '\n')
+ ldif.write('givenname: master1 ' + count + '\n')
+ ldif.write('sn: entry ' + count + '\n')
+ ldif.write('userpassword: master1_entry' + count + '\n')
+ ldif.write('description: ' + 'a' * random.randint(1, 1000) + '\n')
+ ldif.write('\n')
+
+ ldif.write('dn: uid=master2_entry' + count + ',' +
+ DEFAULT_SUFFIX + '\n')
+ ldif.write('objectclass: top\n')
+ ldif.write('objectclass: person\n')
+ ldif.write('objectclass: inetorgperson\n')
+ ldif.write('objectclass: organizationalperson\n')
+ ldif.write('uid: master2_entry' + count + '\n')
+ ldif.write('cn: master2 entry' + count + '\n')
+ ldif.write('givenname: master2 ' + count + '\n')
+ ldif.write('sn: entry ' + count + '\n')
+ ldif.write('userpassword: master2_entry' + count + '\n')
+ ldif.write('description: ' + 'a' * random.randint(1, 1000) + '\n')
+ ldif.write('\n')
+ idx += 1
+
+ ldif.close()
+
+ # Now import it
+ try:
+ master1.tasks.importLDIF(suffix=DEFAULT_SUFFIX, input_file=import_ldif,
+ args={TASK_WAIT: True})
+ except ValueError:
+ log.fatal('test_reliab_7.5: Online import failed')
+ assert False
+
+ #
+ # Initialize all the agreements
+ #
+ master1.agreement.init(SUFFIX, HOST_MASTER_2, PORT_MASTER_2)
+ master1.waitForReplInit(m1_m2_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
+
+ # Clear out the tmp dir
+ master1.clearTmpDir(__file__)
+
+ # Delete each instance in the end
+ def fin():
+ master1.delete()
+ master2.delete()
+ request.addfinalizer(fin)
+
+ return TopologyReplication(master1, master2)
+
+
+class AddDelUsers(threading.Thread):
+ def __init__(self, inst, masterid):
+ threading.Thread.__init__(self)
+ self.daemon = True
+ self.inst = inst
+ self.id = masterid
+
+ def run(self):
+ # Add 5000 entries
+ idx = 0
+ RDN = 'uid=add_del_master_' + self.id + '-'
+
+ conn = self.inst.openConnection()
+ while idx < NUM_USERS:
+ USER_DN = RDN + str(idx) + ',' + DEFAULT_SUFFIX
+ try:
+ conn.add_s(Entry((USER_DN, {'objectclass':
+ 'top extensibleObject'.split(),
+ 'uid': 'user' + str(idx),
+ 'cn': 'g' * random.randint(1, 500)
+ })))
+ except ldap.LDAPError as e:
+ log.fatal('Add users to master ' + self.id + ' failed (' +
+ USER_DN + ') error: ' + e.message['desc'])
+ idx += 1
+ conn.close()
+
+ # Delete 5000 entries
+ conn = self.inst.openConnection()
+ idx = 0
+ while idx < NUM_USERS:
+ USER_DN = RDN + str(idx) + ',' + DEFAULT_SUFFIX
+ try:
+ conn.delete_s(USER_DN)
+ except ldap.LDAPError as e:
+ log.fatal('Failed to delete (' + USER_DN + ') on master ' +
+ self.id + ': error ' + e.message['desc'])
+ idx += 1
+ conn.close()
+
+
+class ModUsers(threading.Thread):
+ # Do mods and modrdns
+ def __init__(self, inst, masterid):
+ threading.Thread.__init__(self)
+ self.daemon = True
+ self.inst = inst
+ self.id = masterid
+
+ def run(self):
+ # Mod existing entries
+ conn = self.inst.openConnection()
+ idx = 0
+ while idx < NUM_USERS:
+ USER_DN = ('uid=master' + self.id + '_entry' + str(idx) + ',' +
+ DEFAULT_SUFFIX)
+ try:
+ conn.modify(USER_DN, [(ldap.MOD_REPLACE,
+ 'givenname',
+ 'new givenname master1-' + str(idx))])
+ except ldap.LDAPError as e:
+ log.fatal('Failed to modify (' + USER_DN + ') on master ' +
+ self.id + ': error ' + e.message['desc'])
+ idx += 1
+ conn.close()
+
+ # Modrdn existing entries
+ conn = self.inst.openConnection()
+ idx = 0
+ while idx < NUM_USERS:
+ USER_DN = ('uid=master' + self.id + '_entry' + str(idx) + ',' +
+ DEFAULT_SUFFIX)
+ NEW_RDN = 'cn=master' + self.id + '_entry' + str(idx)
+ try:
+ conn.rename(USER_DN, NEW_RDN, delold=1)
+ except ldap.LDAPError as e:
+ log.error('Failed to modrdn (' + USER_DN + ') on master ' +
+ self.id + ': error ' + e.message['desc'])
+ idx += 1
+ conn.close()
+
+ # Undo modrdn to we can rerun this test
+ conn = self.inst.openConnection()
+ idx = 0
+ while idx < NUM_USERS:
+ USER_DN = ('cn=master' + self.id + '_entry' + str(idx) + ',' +
+ DEFAULT_SUFFIX)
+ NEW_RDN = 'uid=master' + self.id + '_entry' + str(idx)
+ try:
+ conn.rename(USER_DN, NEW_RDN, delold=1)
+ except ldap.LDAPError as e:
+ log.error('Failed to modrdn (' + USER_DN + ') on master ' +
+ self.id + ': error ' + e.message['desc'])
+ idx += 1
+ conn.close()
+
+
+class DoSearches(threading.Thread):
+ # Search a master
+ def __init__(self, inst, masterid):
+ threading.Thread.__init__(self)
+ self.daemon = True
+ self.inst = inst
+ self.id = masterid
+
+ def run(self):
+ # Equality
+ conn = self.inst.openConnection()
+ idx = 0
+ while idx < NUM_USERS:
+ search_filter = ('(|(uid=master' + self.id + '_entry' + str(idx) +
+ ')(cn=master' + self.id + '_entry' + str(idx) +
+ '))')
+ try:
+ conn.search(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, search_filter)
+ except ldap.LDAPError as e:
+ log.fatal('Search Users: Search failed (%s): %s' %
+ (search_filter, e.message['desc']))
+ conn.close()
+ return
+
+ idx += 1
+ conn.close()
+
+ # Substring
+ conn = self.inst.openConnection()
+ idx = 0
+ while idx < NUM_USERS:
+ search_filter = ('(|(uid=master' + self.id + '_entry' + str(idx) +
+ '*)(cn=master' + self.id + '_entry' + str(idx) +
+ '*))')
+ try:
+ conn.search(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE, search_filter)
+ except ldap.LDAPError as e:
+ log.fatal('Search Users: Search failed (%s): %s' %
+ (search_filter, e.message['desc']))
+ conn.close()
+ return
+
+ idx += 1
+ conn.close()
+
+
+class DoFullSearches(threading.Thread):
+ # Search a master
+ def __init__(self, inst):
+ threading.Thread.__init__(self)
+ self.daemon = True
+ self.inst = inst
+
+ def run(self):
+ global RUNNING
+ conn = self.inst.openConnection()
+ while RUNNING:
+ time.sleep(2)
+ try:
+ conn.search_s(DEFAULT_SUFFIX,
+ ldap.SCOPE_SUBTREE,
+ 'objectclass=top')
+ except ldap.LDAPError as e:
+ log.fatal('Full Search Users: Search failed (%s): %s' %
+ ('objectclass=*', e.message['desc']))
+ conn.close()
+ assert False
+
+ conn.close()
+
+
+def test_reliab7_5_init(topology):
+ '''
+ Reduce entry cache - to increase the cache churn
+
+ Then process "reliability 15" type tests
+ '''
+
+ BACKEND_DN = 'cn=userroot,cn=ldbm database,cn=plugins,cn=config'
+
+ # Update master 1
+ try:
+ topology.master1.modify_s(BACKEND_DN, [(ldap.MOD_REPLACE,
+ 'nsslapd-cachememsize',
+ '512000'),
+ (ldap.MOD_REPLACE,
+ 'nsslapd-cachesize',
+ '500')])
+ except ldap.LDAPError as e:
+ log.fatal('Failed to set cache settings: error ' + e.message['desc'])
+ assert False
+
+ # Update master 2
+ try:
+ topology.master2.modify_s(BACKEND_DN, [(ldap.MOD_REPLACE,
+ 'nsslapd-cachememsize',
+ '512000'),
+ (ldap.MOD_REPLACE,
+ 'nsslapd-cachesize',
+ '500')])
+ except ldap.LDAPError as e:
+ log.fatal('Failed to set cache settings: error ' + e.message['desc'])
+ assert False
+
+ # Restart the masters to pick up the new cache settings
+ topology.master1.stop(timeout=10)
+ topology.master2.stop(timeout=10)
+
+ # This is the time to enable valgrind (if enabled)
+ if ENABLE_VALGRIND:
+ sbin_dir = get_sbin_dir(prefix=topology.master1.prefix)
+ valgrind_enable(sbin_dir)
+
+ topology.master1.start(timeout=30)
+ topology.master2.start(timeout=30)
+
+
+def test_reliab7_5_run(topology):
+ '''
+ Starting issuing adds, deletes, mods, modrdns, and searches
+ '''
+ global RUNNING
+ count = 1
+ RUNNING = True
+
+ # Start some searches to run through the entire stress test
+ fullSearch1 = DoFullSearches(topology.master1)
+ fullSearch1.start()
+ fullSearch2 = DoFullSearches(topology.master2)
+ fullSearch2.start()
+
+ while count <= MAX_PASSES:
+ log.info('################## Reliabilty 7.5 Pass: %d' % count)
+
+ # Master 1
+ add_del_users1 = AddDelUsers(topology.master1, '1')
+ add_del_users1.start()
+ mod_users1 = ModUsers(topology.master1, '1')
+ mod_users1.start()
+ search1 = DoSearches(topology.master1, '1')
+ search1.start()
+
+ # Master 2
+ add_del_users2 = AddDelUsers(topology.master2, '2')
+ add_del_users2.start()
+ mod_users2 = ModUsers(topology.master2, '2')
+ mod_users2.start()
+ search2 = DoSearches(topology.master2, '2')
+ search2.start()
+
+ # Search the masters
+ search3 = DoSearches(topology.master1, '1')
+ search3.start()
+ search4 = DoSearches(topology.master2, '2')
+ search4.start()
+
+ # Wait for threads to finish
+ log.info('################## Waiting for threads to finish...')
+ add_del_users1.join()
+ mod_users1.join()
+ add_del_users2.join()
+ mod_users2.join()
+ log.info('################## Update threads finished.')
+ search1.join()
+ search2.join()
+ search3.join()
+ search4.join()
+ log.info('################## All threads finished.')
+
+ # Allow some time for replication to catch up before firing
+ # off the next round of updates
+ time.sleep(5)
+ count += 1
+
+ #
+ # Wait for replication to converge
+ #
+ if CHECK_CONVERGENCE:
+ # Add an entry to each master, and wait for it to replicate
+ MASTER1_DN = 'uid=rel7.5-master1,' + DEFAULT_SUFFIX
+ MASTER2_DN = 'uid=rel7.5-master2,' + DEFAULT_SUFFIX
+
+ # Master 1
+ try:
+ topology.master1.add_s(Entry((MASTER1_DN, {'objectclass':
+ ['top',
+ 'extensibleObject'],
+ 'sn': '1',
+ 'cn': 'user 1',
+ 'uid': 'rel7.5-master1',
+ 'userpassword':
+ PASSWORD})))
+ except ldap.LDAPError as e:
+ log.fatal('Failed to add replication test entry ' + MASTER1_DN +
+ ': error ' + e.message['desc'])
+ assert False
+
+ log.info('################## Waiting for master 2 to converge...')
+
+ while True:
+ entry = None
+ try:
+ entry = topology.master2.search_s(MASTER1_DN,
+ ldap.SCOPE_BASE,
+ 'objectclass=*')
+ except ldap.NO_SUCH_OBJECT:
+ pass
+ except ldap.LDAPError as e:
+ log.fatal('Search Users: Search failed (%s): %s' %
+ (MASTER1_DN, e.message['desc']))
+ assert False
+ if entry:
+ break
+ time.sleep(5)
+
+ log.info('################## Master 2 converged.')
+
+ # Master 2
+ try:
+ topology.master2.add_s(
+ Entry((MASTER2_DN, {'objectclass': ['top',
+ 'extensibleObject'],
+ 'sn': '1',
+ 'cn': 'user 1',
+ 'uid': 'rel7.5-master2',
+ 'userpassword': PASSWORD})))
+ except ldap.LDAPError as e:
+ log.fatal('Failed to add replication test entry ' + MASTER1_DN +
+ ': error ' + e.message['desc'])
+ assert False
+
+ log.info('################## Waiting for master 1 to converge...')
+ while True:
+ entry = None
+ try:
+ entry = topology.master1.search_s(MASTER2_DN,
+ ldap.SCOPE_BASE,
+ 'objectclass=*')
+ except ldap.NO_SUCH_OBJECT:
+ pass
+ except ldap.LDAPError as e:
+ log.fatal('Search Users: Search failed (%s): %s' %
+ (MASTER2_DN, e.message['desc']))
+ assert False
+ if entry:
+ break
+ time.sleep(5)
+
+ log.info('################## Master 1 converged.')
+
+ # Stop the full searches
+ RUNNING = False
+ fullSearch1.join()
+ fullSearch2.join()
+
+ if ENABLE_VALGRIND:
+ # We're done, disable valgrind...
+ sbin_dir = get_sbin_dir(prefix=topology.master1.prefix)
+ valgrind_disable(sbin_dir)
+
+
+if __name__ == '__main__':
+ # Run isolated
+ # -s for DEBUG mode
+ CURRENT_FILE = os.path.realpath(__file__)
+ pytest.main("-s %s" % CURRENT_FILE)
diff --git a/rpm/389-ds-base.spec.in b/rpm/389-ds-base.spec.in
index 6e4bc48..68d7830 100644
--- a/rpm/389-ds-base.spec.in
+++ b/rpm/389-ds-base.spec.in
@@ -197,6 +197,14 @@ Requires: libtevent
%description devel
Development Libraries and headers for the 389 Directory Server base package.
+%package tests
+Summary: The lib389 Continuous Integration Tests
+Group: Development/Libraries
+Requires: python-lib389
+
+%description tests
+The lib389 CI tests that can be run against the Directory Server.
+
%prep
%setup -q -n %{name}-%{version}%{?prerel}
@@ -286,6 +294,13 @@ rm -f $RPM_BUILD_ROOT%{_libdir}/%{pkgname}/plugins/*.la
# make sure perl scripts have a proper shebang
sed -i -e 's|#{{PERL-EXEC}}|#!/usr/bin/perl|' $RPM_BUILD_ROOT%{_datadir}/%{pkgname}/script-templates/template-*.pl
+pushd ../%{name}-%{version}%{?prerel}
+cp -r dirsrvtests $RPM_BUILD_ROOT/%{_sysconfdir}/%{pkgname}
+find $RPM_BUILD_ROOT/%{_sysconfdir}/%{pkgname}/dirsrvtests -type f -name '*.pyc' -delete
+find $RPM_BUILD_ROOT/%{_sysconfdir}/%{pkgname}/dirsrvtests -type f -name '*.pyo' -delete
+find $RPM_BUILD_ROOT/%{_sysconfdir}/%{pkgname}/dirsrvtests -type d -name '__pycache__' -delete
+popd
+
%clean
rm -rf $RPM_BUILD_ROOT
@@ -440,7 +455,15 @@ fi
%{_libdir}/%{pkgname}/libjemalloc.so*
%endif
+%files tests
+%defattr(-,root,root,-)
+%doc LICENSE LICENSE.GPLv3+
+%{_sysconfdir}/%{pkgname}/dirsrvtests
+
%changelog
+* Mon Dec 21 2015 Mark Reynolds <mreynolds(a)redhat.com> - 1.3.4.1-3
+- Ticket 48376 - Create subpackage for lib389 CI tests
+
* Mon Dec 14 2015 Mark Reynolds <mreynolds(a)redhat.com> - 1.3.4.1-2
- Ticket 48377 - Include the jemalloc library
7 years, 11 months
3 commits - dirsrvtests/tickets ldap/servers man/man1
by Noriko Hosoi
dirsrvtests/tickets/ticket48294_test.py | 290 ++++++++++++++++++++++++
ldap/servers/plugins/linkedattrs/linked_attrs.c | 10
man/man1/dbgen.pl.1 | 3
3 files changed, 302 insertions(+), 1 deletion(-)
New commits:
commit c3b4c0c2ab30fd219e35f1ab4d8a05dd065f685c
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Fri Dec 18 17:13:33 2015 -0800
Ticket #48294 - CI test: added test cases for ticket 48294
Description: Linked Attributes plug-in - won't update links after MODRDN operation
https://fedorahosted.org/389/ticket/48294
diff --git a/dirsrvtests/tickets/ticket48294_test.py b/dirsrvtests/tickets/ticket48294_test.py
new file mode 100644
index 0000000..109a67e
--- /dev/null
+++ b/dirsrvtests/tickets/ticket48294_test.py
@@ -0,0 +1,290 @@
+# --- 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
+import shutil
+from lib389 import DirSrv, Entry, tools
+from lib389 import DirSrvTools
+from lib389.tools import DirSrvTools
+from lib389._constants import *
+from lib389.properties import *
+
+log = logging.getLogger(__name__)
+
+installation_prefix = None
+
+LINKEDATTR_PLUGIN = 'cn=Linked Attributes,cn=plugins,cn=config'
+MANAGER_LINK = 'cn=Manager Link,' + LINKEDATTR_PLUGIN
+OU_PEOPLE = 'ou=People,' + DEFAULT_SUFFIX
+LINKTYPE = 'directReport'
+MANAGEDTYPE = 'manager'
+
+class TopologyStandalone(object):
+ def __init__(self, standalone):
+ standalone.open()
+ self.standalone = standalone
+
+
+(a)pytest.fixture(scope="module")
+def topology(request):
+ '''
+ This fixture is used to standalone topology for the 'module'.
+ '''
+ global installation_prefix
+
+ if installation_prefix:
+ args_instance[SER_DEPLOYED_DIR] = installation_prefix
+
+ standalone = DirSrv(verbose=False)
+
+ # Args for the standalone instance
+ args_instance[SER_HOST] = HOST_STANDALONE
+ args_instance[SER_PORT] = PORT_STANDALONE
+ args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
+ args_standalone = args_instance.copy()
+ standalone.allocate(args_standalone)
+
+ # Get the status of the instance and restart it if it exists
+ instance_standalone = standalone.exists()
+
+ # Remove the instance
+ if instance_standalone:
+ standalone.delete()
+
+ # Create the instance
+ standalone.create()
+
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
+ # Here we have standalone instance up and running
+ return TopologyStandalone(standalone)
+
+
+def _header(topology, label):
+ topology.standalone.log.info("###############################################")
+ topology.standalone.log.info("####### %s" % label)
+ topology.standalone.log.info("###############################################")
+
+def check_attr_val(topology, dn, attr, expected):
+ try:
+ centry = topology.standalone.search_s(dn, ldap.SCOPE_BASE, 'uid=*')
+ if centry:
+ val = centry[0].getValue(attr)
+ if val.lower() == expected.lower():
+ log.info('Value of %s is %s' % (attr, expected))
+ else:
+ log.info('Value of %s is not %s, but %s' % (attr, expected, val))
+ assert False
+ else:
+ log.fatal('Failed to get %s' % dn)
+ assert False
+ except ldap.LDAPError as e:
+ log.fatal('Failed to search ' + dn + ': ' + e.message['desc'])
+ assert False
+
+
+def _modrdn_entry(topology=None, entry_dn=None, new_rdn=None, del_old=0, new_superior=None):
+ assert topology is not None
+ assert entry_dn is not None
+ assert new_rdn is not None
+
+ topology.standalone.log.info("\n\n######################### MODRDN %s ######################\n" % new_rdn)
+ try:
+ if new_superior:
+ topology.standalone.rename_s(entry_dn, new_rdn, newsuperior=new_superior, delold=del_old)
+ else:
+ topology.standalone.rename_s(entry_dn, new_rdn, delold=del_old)
+ except ldap.NO_SUCH_ATTRIBUTE:
+ topology.standalone.log.info("accepted failure due to 47833: modrdn reports error.. but succeeds")
+ attempt = 0
+ if new_superior:
+ dn = "%s,%s" % (new_rdn, new_superior)
+ base = new_superior
+ else:
+ base = ','.join(entry_dn.split(",")[1:])
+ dn = "%s, %s" % (new_rdn, base)
+ myfilter = entry_dn.split(',')[0]
+
+ while attempt < 10:
+ try:
+ ent = topology.standalone.getEntry(dn, ldap.SCOPE_BASE, myfilter)
+ break
+ except ldap.NO_SUCH_OBJECT:
+ topology.standalone.log.info("Accept failure due to 47833: unable to find (base) a modrdn entry")
+ attempt += 1
+ time.sleep(1)
+ if attempt == 10:
+ ent = topology.standalone.getEntry(base, ldap.SCOPE_SUBTREE, myfilter)
+ ent = topology.standalone.getEntry(dn, ldap.SCOPE_BASE, myfilter)
+
+
+def _48294_init(topology):
+ """
+ Set up Linked Attribute
+ """
+ _header(topology, 'Testing Ticket 48294 - Linked Attributes plug-in - won\'t update links after MODRDN operation')
+
+ log.info('Enable Dynamic plugins, and the linked Attrs plugin')
+ try:
+ topology.standalone.modify_s(DN_CONFIG, [(ldap.MOD_REPLACE, 'nsslapd-dynamic-plugins', 'on')])
+ except ldap.LDAPError as e:
+ ldap.fatal('Failed to enable dynamic plugin!' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.plugins.enable(name=PLUGIN_LINKED_ATTRS)
+ except ValueError as e:
+ ldap.fatal('Failed to enable linked attributes plugin!' + e.message['desc'])
+ assert False
+
+ log.info('Add the plugin config entry')
+ try:
+ topology.standalone.add_s(Entry((MANAGER_LINK, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'cn': 'Manager Link',
+ 'linkType': LINKTYPE,
+ 'managedType': MANAGEDTYPE
+ })))
+ except ldap.LDAPError as e:
+ log.fatal('Failed to add linked attr config entry: error ' + e.message['desc'])
+ assert False
+
+ log.info('Add 2 entries: manager1 and employee1')
+ try:
+ topology.standalone.add_s(Entry(('uid=manager1,%s' % OU_PEOPLE, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'manager1'})))
+ except ldap.LDAPError as e:
+ log.fatal('Add manager1 failed: error ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry(('uid=employee1,%s' % OU_PEOPLE, {
+ 'objectclass': 'top extensibleObject'.split(),
+ 'uid': 'employee1'})))
+ except ldap.LDAPError as e:
+ log.fatal('Add employee1 failed: error ' + e.message['desc'])
+ assert False
+
+ log.info('Add linktype to manager1')
+ topology.standalone.modify_s('uid=manager1,%s' % OU_PEOPLE,
+ [(ldap.MOD_ADD, LINKTYPE, 'uid=employee1,%s' % OU_PEOPLE)])
+
+ log.info('Check managed attribute')
+ check_attr_val(topology, 'uid=employee1,%s' % OU_PEOPLE, MANAGEDTYPE, 'uid=manager1,%s' % OU_PEOPLE)
+
+ log.info('PASSED')
+
+
+def _48294_run_0(topology):
+ """
+ Rename employee1 to employee2 and adjust the value of directReport by replace
+ """
+ _header(topology, 'Case 0 - Rename employee1 and adjust the link type value by replace')
+
+ log.info('Rename employee1 to employee2')
+ _modrdn_entry(topology, entry_dn='uid=employee1,%s' % OU_PEOPLE, new_rdn='uid=employee2')
+
+ log.info('Modify the value of directReport to uid=employee2')
+ try:
+ topology.standalone.modify_s('uid=manager1,%s' % OU_PEOPLE,
+ [(ldap.MOD_REPLACE, LINKTYPE, 'uid=employee2,%s' % OU_PEOPLE)])
+ except ldap.LDAPError as e:
+ log.fatal('Failed to replace uid=employee1 with employee2: ' + e.message['desc'])
+ assert False
+
+ log.info('Check managed attribute')
+ check_attr_val(topology, 'uid=employee2,%s' % OU_PEOPLE, MANAGEDTYPE, 'uid=manager1,%s' % OU_PEOPLE)
+
+ log.info('PASSED')
+
+
+def _48294_run_1(topology):
+ """
+ Rename employee2 to employee3 and adjust the value of directReport by delete and add
+ """
+ _header(topology, 'Case 1 - Rename employee2 and adjust the link type value by delete and add')
+
+ log.info('Rename employee2 to employee3')
+ _modrdn_entry(topology, entry_dn='uid=employee2,%s' % OU_PEOPLE, new_rdn='uid=employee3')
+
+ log.info('Modify the value of directReport to uid=employee3')
+ try:
+ topology.standalone.modify_s('uid=manager1,%s' % OU_PEOPLE,
+ [(ldap.MOD_DELETE, LINKTYPE, 'uid=employee2,%s' % OU_PEOPLE)])
+ except ldap.LDAPError as e:
+ log.fatal('Failed to delete employee2: ' + e.message['desc'])
+ assert False
+
+ try:
+ topology.standalone.modify_s('uid=manager1,%s' % OU_PEOPLE,
+ [(ldap.MOD_ADD, LINKTYPE, 'uid=employee3,%s' % OU_PEOPLE)])
+ except ldap.LDAPError as e:
+ log.fatal('Failed to add employee3: ' + e.message['desc'])
+ assert False
+
+ log.info('Check managed attribute')
+ check_attr_val(topology, 'uid=employee3,%s' % OU_PEOPLE, MANAGEDTYPE, 'uid=manager1,%s' % OU_PEOPLE)
+
+ log.info('PASSED')
+
+
+def _48294_run_2(topology):
+ """
+ Rename manager1 to manager2 and make sure the managed attribute value is updated
+ """
+ _header(topology, 'Case 2 - Rename manager1 to manager2 and make sure the managed attribute value is updated')
+
+ log.info('Rename manager1 to manager2')
+ _modrdn_entry(topology, entry_dn='uid=manager1,%s' % OU_PEOPLE, new_rdn='uid=manager2')
+
+ log.info('Check managed attribute')
+ check_attr_val(topology, 'uid=employee3,%s' % OU_PEOPLE, MANAGEDTYPE, 'uid=manager2,%s' % OU_PEOPLE)
+
+ log.info('PASSED')
+
+
+def _48294_final(topology):
+ topology.standalone.delete()
+ log.info('All PASSED')
+
+
+def test_ticket48294(topology):
+ '''
+ 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 installation_prefix
+ installation_prefix = None
+
+ _48294_init(topology)
+
+ _48294_run_0(topology)
+ _48294_run_1(topology)
+ _48294_run_2(topology)
+
+ _48294_final(topology)
+
+if __name__ == '__main__':
+ # Run isolated
+ # -s for DEBUG mode
+
+ CURRENT_FILE = os.path.realpath(__file__)
+ pytest.main("-s %s" % CURRENT_FILE)
commit 26a749a68e83b76cac2fbb5a031a36cd120bd800
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Fri Dec 18 16:05:22 2015 -0800
Ticket #48294 - Linked Attributes plug-in - won't update links after MODRDN operation
Description: When an entry is renamed and the DN is a value of linktype,
since the linktype value is under control by the user, the value needs to
be manually modified to adjust to the new DN.
But the modification failed in linked_attrs_mod_backpointers due to the
too tight error checking. This patch allows LDAP_NO_SUCH_OBJECT for the
deletion of the old DN and LDAP_TYPE_OR_VALUE_EXISTS for adding a managed
entry which exists prior to the modification.
https://fedorahosted.org/389/ticket/48294
Reviewed by mreynolds(a)redhat.com (Thank you, Mark!!)
diff --git a/ldap/servers/plugins/linkedattrs/linked_attrs.c b/ldap/servers/plugins/linkedattrs/linked_attrs.c
index 5d1a77d..0d07a1f 100644
--- a/ldap/servers/plugins/linkedattrs/linked_attrs.c
+++ b/ldap/servers/plugins/linkedattrs/linked_attrs.c
@@ -1463,7 +1463,15 @@ linked_attrs_mod_backpointers(Slapi_PBlock *pb, char *linkdn, char *type,
linked_attrs_get_plugin_id(), 0);
slapi_modify_internal_pb(mod_pb);
slapi_pblock_get(mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
- if(rc != LDAP_SUCCESS){
+ if (((LDAP_MOD_DELETE == modop) && (LDAP_NO_SUCH_OBJECT == rc)) ||
+ ((LDAP_MOD_ADD == modop) && (LDAP_TYPE_OR_VALUE_EXISTS == rc))) {
+ /*
+ * We should ignore LDAP_NO_SUCH_OBJECT and LDAP_TYPE_OR_VALUE_EXISTS
+ * to support the case:
+ * target entry was renamed and the linktype value is being adjusted.
+ */
+ rc = LDAP_SUCCESS;
+ } else if (rc != LDAP_SUCCESS) {
char *err_msg = NULL;
err_msg = PR_smprintf("Linked Attrs Plugin: Failed to update "
commit 1076f51ae51d2bfe76b01d963a85c8275352d4d0
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Fri Dec 18 12:21:49 2015 -0800
Ticket #48290 - No man page entry for - option '-u' of dbgen.pl for adding group entries with uniquemembers
Description: Adding a missing option to the man page for dbgen.pl.
-u Add groups containing uniquemembers; generate a group for every
100 user entries created that contains the 100 members
https://fedorahosted.org/389/ticket/48290
Reviewed by mreynolds(a)redhat.com (Thank you, Mark!!)
diff --git a/man/man1/dbgen.pl.1 b/man/man1/dbgen.pl.1
index 6ef4d28..6f25080 100644
--- a/man/man1/dbgen.pl.1
+++ b/man/man1/dbgen.pl.1
@@ -71,6 +71,9 @@ Beginning number for RDN e.g. uid=1 (ending number is \-n value + beginning numb
.TP
.B \-j number
0 pad numbers used in RDN to this many digits e.g. with 4 1 becomes 0001 (ignored unless \-b number is specified)
+.TP
+.B \-u
+Add groups containing uniquemembers; generate a group for every 100 user entries created that contains the 100 members
.br
.SH AUTHOR
dbgen.pl was written by the 389 Project.
7 years, 11 months
rpm.mk
by Mark Reynolds
rpm.mk | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
New commits:
commit c44a3e9220964060ddd160ed4a3199eee8e7bf81
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Mon Dec 21 08:56:45 2015 -0500
Ticket 48277 - Disable jemalloc by default in rpm.mk
Description: Bunding jemalloc should not be the default in rpm.mk
https://fedorahosted.org/389/ticket/48377
diff --git a/rpm.mk b/rpm.mk
index 4d89777..c58c365 100644
--- a/rpm.mk
+++ b/rpm.mk
@@ -9,7 +9,7 @@ NUNC_STANS_TARBALL ?= $(shell basename "$(NUNC_STANS_URL)")
JEMALLOC_URL ?= $(shell rpmspec -P $(RPMBUILD)/SPECS/389-ds-base.spec | awk '/^Source3:/ {print $$2}')
JEMALLOC_TARBALL ?= $(shell basename "$(JEMALLOC_URL)")
NUNC_STANS_ON = 1
-BUNDLE_JEMALLOC = 1
+BUNDLE_JEMALLOC = 0
clean:
rm -rf dist
7 years, 11 months
ldap/servers
by Mark Reynolds
ldap/servers/plugins/cos/cos_cache.c | 17 ++++++-
ldap/servers/slapd/main.c | 27 +++++++----
ldap/servers/slapd/plugin.c | 85 +++++++++++++++++++++++++++++++----
ldap/servers/slapd/proto-slap.h | 9 ++-
ldap/servers/slapd/utf8compare.c | 34 +++++++-------
5 files changed, 134 insertions(+), 38 deletions(-)
New commits:
commit c7c3d5963243574f8f8cf5f292fba27486a40d4a
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Fri Dec 18 16:38:33 2015 -0500
Ticket 48388 - db2ldif -r segfaults from time to time
Bug Description: db2ldif starts all the plugins before generating
the ldif file. If the retro changelog is enabled
and it starts to trim itself the server can crash
when cos tries to process the retrocl triming
operations.
Fix Description: First, fix the NULL dereferences in COS. Then
when doing a "db2ldif -r" only startup the
plugins that "db2ldif -r" needs (which is just
the replication plugin and its dependencies).
Revised the plugin_startall() function to remove
unused parameters (start_backends & global_plugins)
Also did a little code clean up slapi_utf8casecmp.
https://fedorahosted.org/389/ticket/48388
Valgrind: passed
Reviewed by: nhosoi(Thanks!)
diff --git a/ldap/servers/plugins/cos/cos_cache.c b/ldap/servers/plugins/cos/cos_cache.c
index cb5cb69..8a32630 100644
--- a/ldap/servers/plugins/cos/cos_cache.c
+++ b/ldap/servers/plugins/cos/cos_cache.c
@@ -3034,7 +3034,8 @@ static int cos_cache_attr_compare(const void *e1, const void *e2)
cosTemplates *pTemplate1 = (cosTemplates*)pAttr1->pParent;
/* Now compare the names of the attributes */
- com_Result = slapi_utf8casecmp((unsigned char*)(*(cosAttributes**)e1)->pAttrName,(unsigned char*)(*(cosAttributes**)e2)->pAttrName);
+ com_Result = slapi_utf8casecmp((unsigned char*)(*(cosAttributes**)e1)->pAttrName,
+ (unsigned char*)(*(cosAttributes**)e2)->pAttrName);
if(0 == com_Result){
/* Now compare the cosPriorities */
com_Result = pTemplate->cosPriority - pTemplate1->cosPriority;
@@ -3047,6 +3048,13 @@ static int cos_cache_attr_compare(const void *e1, const void *e2)
static int cos_cache_string_compare(const void *e1, const void *e2)
{
+ if (!e1 && e2) {
+ return 1;
+ } else if (e1 && !e2) {
+ return -1;
+ } else if (!e1 && !e2) {
+ return 0;
+ }
return slapi_utf8casecmp((*(unsigned char**)e1),(*(unsigned char**)e2));
}
@@ -3054,6 +3062,13 @@ static int cos_cache_template_index_compare(const void *e1, const void *e2)
{
int ret = 0;
+ if (!e1 && e2) {
+ return 1;
+ } else if (e1 && !e2) {
+ return -1;
+ } else if (!e1 && !e2) {
+ return 0;
+ }
if(0 == slapi_dn_issuffix((const char*)e1,*(const char**)e2))
ret = slapi_utf8casecmp(*(unsigned char**)e2,(unsigned char*)e1);
else
diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c
index 4f9fbfe..b048dc5 100644
--- a/ldap/servers/slapd/main.c
+++ b/ldap/servers/slapd/main.c
@@ -1051,7 +1051,7 @@ main( int argc, char **argv)
pw_exp_init ();
plugin_print_lists();
- plugin_startall(argc, argv, 1 /* Start Backends */, 1 /* Start Globals */);
+ plugin_startall(argc, argv, NULL /* specific plugin list */);
compute_plugins_started();
if (housekeeping_start((time_t)0, NULL) == NULL) {
return_value = 1;
@@ -2216,13 +2216,24 @@ slapd_exemode_db2ldif(int argc, char** argv)
else
pb.pb_server_running = 0;
- if (db2ldif_dump_replica) {
- eq_init(); /* must be done before plugins started */
- ps_init_psearch_system(); /* must come before plugin_startall() */
- plugin_startall(argc, argv, 1 /* Start Backends */,
- 1 /* Start Globals */);
- eq_start(); /* must be done after plugins started */
- }
+ if (db2ldif_dump_replica) {
+ char **plugin_list = NULL;
+ char *repl_plg_name = "Multimaster Replication Plugin";
+
+ /*
+ * Only start the necessary plugins for "db2ldif -r"
+ *
+ * We need replication, but replication has its own
+ * dependencies
+ */
+ plugin_get_plugin_dependencies(repl_plg_name, &plugin_list);
+
+ eq_init(); /* must be done before plugins started */
+ ps_init_psearch_system(); /* must come before plugin_startall() */
+ plugin_startall(argc, argv, plugin_list);
+ eq_start(); /* must be done after plugins started */
+ charray_free(plugin_list);
+ }
pb.pb_ldif_file = NULL;
if ( archive_name ) { /* redirect stdout to this file: */
diff --git a/ldap/servers/slapd/plugin.c b/ldap/servers/slapd/plugin.c
index 4ab644b..2d3a5ce 100644
--- a/ldap/servers/slapd/plugin.c
+++ b/ldap/servers/slapd/plugin.c
@@ -1390,6 +1390,47 @@ plugin_free_plugin_dep_config(plugin_dep_config **cfg)
}
}
+/*
+ * Take a given plugin and recursively set all the plugin dependency names
+ */
+void
+plugin_get_plugin_dependencies(char *plugin_name, char ***names)
+{
+ entry_and_plugin_t *ep = dep_plugin_entries;
+ char **depends = NULL;
+ char *dep_attr = "nsslapd-plugin-depends-on-named";
+ int i;
+
+ /* Add the original plugin name to the list */
+ if (!charray_inlist(*names, plugin_name)){
+ charray_add(names, slapi_ch_strdup(plugin_name));
+ }
+
+ /* Find the plugin and grab its dependencies */
+ while(ep)
+ {
+ if (ep->plugin){
+ if(strcasecmp(ep->plugin->plg_name, plugin_name) == 0){
+ /* We found our plugin, now grab its dependencies */
+ depends = slapi_entry_attr_get_charray(ep->e, dep_attr);
+ break;
+ }
+ }
+ ep = ep->next;
+ }
+
+ if (depends){
+ /* Add the plugin's dependencies */
+ charray_merge_nodup(names, depends, 1);
+
+ /* Add each dependency's dependencies */
+ for (i = 0; depends[i]; i++){
+ /* recurse */
+ plugin_get_plugin_dependencies(depends[i], names);
+ }
+ slapi_ch_array_free(depends);
+ }
+}
/*
* plugin_dependency_startall()
@@ -1407,7 +1448,7 @@ plugin_free_plugin_dep_config(plugin_dep_config **cfg)
*/
static int
-plugin_dependency_startall(int argc, char** argv, char *errmsg, int operation)
+plugin_dependency_startall(int argc, char** argv, char *errmsg, int operation, char** plugin_list)
{
int ret = 0;
Slapi_PBlock pb;
@@ -1419,7 +1460,7 @@ plugin_dependency_startall(int argc, char** argv, char *errmsg, int operation)
int i = 0; /* general index iterator */
plugin_dep_type the_plugin_type;
int index = 0;
- char * value;
+ char *value = NULL;
int plugins_started;
int num_plg_started;
struct slapdplugin *plugin;
@@ -1435,25 +1476,50 @@ plugin_dependency_startall(int argc, char** argv, char *errmsg, int operation)
global_plugin_callbacks_enabled = 0;
/* Count the plugins so we can allocate memory for the config array */
- while(ep)
+ while(ep)
{
total_plugins++;
-
ep = ep->next;
}
/* allocate the config array */
config = (plugin_dep_config*)slapi_ch_calloc(total_plugins + 1, sizeof(plugin_dep_config));
-
ep = dep_plugin_entries;
+ if (plugin_list){
+ /* We have a plugin list, so we need to reset the plugin count */
+ total_plugins = 0;
+ }
/* Collect relevant config */
- while(ep)
+ while(ep)
{
plugin = ep->plugin;
- if(plugin == 0)
+ if(plugin == 0){
+ ep = ep->next;
continue;
+ }
+
+ if (plugin_list){
+ /*
+ * We have a specific list of plugins to start, skip the others...
+ */
+ int found = 0;
+ for (i = 0; plugin_list[i]; i++){
+ if (strcasecmp(plugin->plg_name, plugin_list[i]) == 0){
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found){
+ /* Skip this plugin, it's not in the list */
+ ep = ep->next;
+ continue;
+ } else {
+ total_plugins++;
+ }
+ }
pblock_init(&pb);
slapi_pblock_set( &pb, SLAPI_ARGC, &argc);
@@ -1824,12 +1890,13 @@ plugin_dependency_closeall()
* stuff is done with. So this function goes through and starts all plugins
*/
void
-plugin_startall(int argc, char** argv, int start_backends, int start_global)
+plugin_startall(int argc, char** argv, char **plugin_list)
{
/* initialize special plugin structures */
default_plugin_init ();
- plugin_dependency_startall(argc, argv, "plugin startup failed\n", SLAPI_PLUGIN_START_FN);
+ plugin_dependency_startall(argc, argv, "plugin startup failed\n",
+ SLAPI_PLUGIN_START_FN, plugin_list);
}
/*
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
index 7d965b0..f0a5257 100644
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -865,11 +865,14 @@ int plugin_setup(Slapi_Entry *plugin_entry, struct slapi_componentid *group,
int plugin_call_exop_plugins( Slapi_PBlock *pb, char *oid );
const char *plugin_extended_op_oid2string( const char *oid );
void plugin_closeall(int close_backends, int close_globals);
-void plugin_startall(int argc,char **argv,int start_backends, int start_global);
+void plugin_startall(int argc, char **argv, char **plugin_list);
+void plugin_get_plugin_dependencies(char *plugin_name, char ***names);
struct slapdplugin *get_plugin_list(int plugin_list_index);
-PRBool plugin_invoke_plugin_sdn (struct slapdplugin *plugin, int operation, Slapi_PBlock *pb, Slapi_DN *target_spec);
+PRBool plugin_invoke_plugin_sdn (struct slapdplugin *plugin, int operation,
+ Slapi_PBlock *pb, Slapi_DN *target_spec);
struct slapdplugin *plugin_get_by_name(char *name);
-struct slapdplugin *plugin_get_pwd_storage_scheme(char *name, int len, int index);
+struct slapdplugin *plugin_get_pwd_storage_scheme(char *name, int len,
+ int index);
char *plugin_get_pwd_storage_scheme_list(int index);
int plugin_add_descriptive_attributes( Slapi_Entry *e,
struct slapdplugin *plugin );
diff --git a/ldap/servers/slapd/utf8compare.c b/ldap/servers/slapd/utf8compare.c
index 3201df7..592f039 100644
--- a/ldap/servers/slapd/utf8compare.c
+++ b/ldap/servers/slapd/utf8compare.c
@@ -2115,15 +2115,15 @@ slapi_utf8casecmp(unsigned char *s0, unsigned char *s1)
d0 = d1 = NULL;
if (s0 == NULL || *s0 == '\0') {
- if (s1 == NULL || *s1 == '\0') {
- rval = 0;
- } else {
- rval = -1; /* regardless s1, s0 < s1 */
- }
- goto end;
+ if (s1 == NULL || *s1 == '\0') {
+ rval = 0;
+ } else {
+ rval = -1; /* regardless s1, s0 < s1 */
+ }
+ goto end;
} else if (s1 == NULL || *s1 == '\0') {
- rval = 1; /* regardless s0, s0 > s1 */
- goto end;
+ rval = 1; /* regardless s0, s0 > s1 */
+ goto end;
}
has8_s0 = slapi_has8thBit(s0);
@@ -2141,9 +2141,9 @@ slapi_utf8casecmp(unsigned char *s0, unsigned char *s1)
d0 = slapi_utf8StrToLower(s0);
d1 = slapi_utf8StrToLower(s1);
if (d0 == NULL || d1 == NULL || /* either is not a UTF-8 string */
- (d0 && *d0 == '\0') || (d1 && *d1 == '\0')) {
- rval = strcasecmp((char *)s0, (char *)s1);
- goto end;
+ (d0 && *d0 == '\0') || (d1 && *d1 == '\0')) {
+ rval = strcasecmp((char *)s0, (char *)s1);
+ goto end;
}
p0 = d0;
@@ -2157,25 +2157,25 @@ slapi_utf8casecmp(unsigned char *s0, unsigned char *s1)
n0 = (unsigned char *)ldap_utf8next((char *)p0);
n1 = (unsigned char *)ldap_utf8next((char *)p1);
if (n0 > t0 || n1 > t1) {
- break;
- }
+ break;
+ }
i0 = n0 - p0;
i1 = n1 - p1;
- rval = i0 - i1;
+ rval = i0 - i1;
if (rval) { /* length is different */
goto end;
- }
+ }
/* i0 == i1: same length */
for (x0 = p0, x1 = p1; x0 < n0; x0++, x1++) {
rval = *x0 - *x1;
if (rval) {
goto end;
- }
+ }
}
- p0 = n0; p1 = n1; /* goto next */
+ p0 = n0; p1 = n1; /* goto next */
}
/* finished scanning the shared part and check the leftover */
l0 = t0 - n0;
7 years, 11 months
Branch '389-ds-base-1.2.11' - ldap/admin
by Noriko Hosoi
ldap/admin/src/scripts/DSCreate.pm.in | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
New commits:
commit 3f2ea36e763c8e08b88265bd365c6daa5081419c
Author: William Brown <firstyear(a)redhat.com>
Date: Thu Nov 26 13:11:17 2015 +1000
Ticket 48332 - allow users to specify to relax the FQDN constraint
Bug Description: There are situations when the machine name for ds may not
match the dns name. In these cases we should allow installation without the
strict hostname checks we carry out.
Fix Description: Add a new option, General.StrictHostCheck which defaults
to true. If true, host name checking is carried out. If false, it is disabled
and any hostname in General.FullMachineName is considered valid.
https://fedorahosted.org/389/ticket/48332
Author: wibrown
Review by: rmeggins (Thanks!)
(cherry picked from commit 026956c7e3b4dc00b6738f9a195e6653fed03d79)
(cherry picked from commit 5d0f57335c1bf97529849d5d47cad769083052d0)
(cherry picked from commit e62ef7f4d19d78d015efa915f7740f4d8b615da4)
diff --git a/ldap/admin/src/scripts/DSCreate.pm.in b/ldap/admin/src/scripts/DSCreate.pm.in
index b7f9498..dbfcedf 100644
--- a/ldap/admin/src/scripts/DSCreate.pm.in
+++ b/ldap/admin/src/scripts/DSCreate.pm.in
@@ -150,9 +150,18 @@ sub sanityCheckParams {
debug(0, "WARNING: The root password is less than 8 characters long. You should choose a longer one.\n");
}
- if (@errs = checkHostname($inf->{General}->{FullMachineName}, 0)) {
- debug(1, @errs);
- return @errs;
+ $inf->{General}->{StrictHostCheck} = lc $inf->{General}->{StrictHostCheck};
+
+ if ("true" ne $inf->{General}->{StrictHostCheck} && "false" ne $inf->{General}->{StrictHostCheck}) {
+ debug(1, "StrictHostCheck is not a valid boolean");
+ return ('error_invalid_boolean', $inf->{General}->{StrictHostCheck});
+ }
+
+ if ($inf->{General}->{StrictHostCheck} eq "true" ) {
+ if (@errs = checkHostname($inf->{General}->{FullMachineName}, 0)) {
+ debug(1, @errs);
+ return @errs;
+ }
}
return ();
@@ -888,6 +897,10 @@ sub setDefaults {
"@datadir@",
$inf->{General}->{prefix});
+ if (!defined($inf->{General}->{StrictHostCheck})) {
+ $inf->{General}->{StrictHostCheck} = "true";
+ }
+
if (!defined($inf->{slapd}->{inst_dir})) {
$inf->{slapd}->{inst_dir} = "$inf->{General}->{ServerRoot}/slapd-$servid";
}
7 years, 11 months
Branch '389-ds-base-1.3.3' - 2 commits - ldap/admin ldap/servers
by Noriko Hosoi
ldap/admin/src/scripts/DSCreate.pm.in | 19 ++++++++++++++++---
ldap/servers/slapd/tools/ldclt/ldclt.c | 5 +++++
2 files changed, 21 insertions(+), 3 deletions(-)
New commits:
commit e62ef7f4d19d78d015efa915f7740f4d8b615da4
Author: William Brown <firstyear(a)redhat.com>
Date: Thu Nov 26 13:11:17 2015 +1000
Ticket 48332 - allow users to specify to relax the FQDN constraint
Bug Description: There are situations when the machine name for ds may not
match the dns name. In these cases we should allow installation without the
strict hostname checks we carry out.
Fix Description: Add a new option, General.StrictHostCheck which defaults
to true. If true, host name checking is carried out. If false, it is disabled
and any hostname in General.FullMachineName is considered valid.
https://fedorahosted.org/389/ticket/48332
Author: wibrown
Review by: rmeggins (Thanks!)
(cherry picked from commit 026956c7e3b4dc00b6738f9a195e6653fed03d79)
(cherry picked from commit 5d0f57335c1bf97529849d5d47cad769083052d0)
diff --git a/ldap/admin/src/scripts/DSCreate.pm.in b/ldap/admin/src/scripts/DSCreate.pm.in
index 7285625..4e75026 100644
--- a/ldap/admin/src/scripts/DSCreate.pm.in
+++ b/ldap/admin/src/scripts/DSCreate.pm.in
@@ -154,9 +154,18 @@ sub sanityCheckParams {
debug(0, "WARNING: The root password is less than 8 characters long. You should choose a longer one.\n");
}
- if (@errs = checkHostname($inf->{General}->{FullMachineName}, 0)) {
- debug(1, @errs);
- return @errs;
+ $inf->{General}->{StrictHostCheck} = lc $inf->{General}->{StrictHostCheck};
+
+ if ("true" ne $inf->{General}->{StrictHostCheck} && "false" ne $inf->{General}->{StrictHostCheck}) {
+ debug(1, "StrictHostCheck is not a valid boolean");
+ return ('error_invalid_boolean', $inf->{General}->{StrictHostCheck});
+ }
+
+ if ($inf->{General}->{StrictHostCheck} eq "true" ) {
+ if (@errs = checkHostname($inf->{General}->{FullMachineName}, 0)) {
+ debug(1, @errs);
+ return @errs;
+ }
}
return ();
@@ -903,6 +912,10 @@ sub setDefaults {
"@datadir@",
$inf->{General}->{prefix});
+ if (!defined($inf->{General}->{StrictHostCheck})) {
+ $inf->{General}->{StrictHostCheck} = "true";
+ }
+
if (!defined($inf->{slapd}->{inst_dir})) {
$inf->{slapd}->{inst_dir} = "$inf->{General}->{ServerRoot}/slapd-$servid";
}
commit 26613cf3d1dbca136a43e15ee5d6a20f3641b362
Author: Stanislav Zidek <szidek(a)redhat.com>
Date: Wed Oct 21 17:58:31 2015 -0700
Ticket #48289 - 389-ds-base: ldclt-bin killed by SIGSEGV
Description: If NULL source string was passed to parseFilter, it caused
NULL dereference.
https://fedorahosted.org/389/ticket/48289
Reviewed by nhosoi(a)redhat.com.
(cherry picked from commit 5b33c781d2568c930a0856f0a42c1e1d53e3358f)
(cherry picked from commit 8cd610a944daf72a41e5b35065f8b363f8154f28)
(cherry picked from commit 49d0ef667441e009af071fd0f4d48f31f3514063)
diff --git a/ldap/servers/slapd/tools/ldclt/ldclt.c b/ldap/servers/slapd/tools/ldclt/ldclt.c
index 2ccba82..2d668d1 100644
--- a/ldap/servers/slapd/tools/ldclt/ldclt.c
+++ b/ldap/servers/slapd/tools/ldclt/ldclt.c
@@ -1225,6 +1225,11 @@ parseFilter (
{
int i, j;
+ if (!src) {
+ printf ("Error: NULL source string is passed.\n");
+ return (-1);
+ }
+
for (i=0 ; (i<strlen(src)) && (src[i]!='X') ; i++);
*head = (char *)malloc(i+1);
if (*head == NULL)
7 years, 11 months
Branch '389-ds-base-1.3.4' - ldap/admin
by Noriko Hosoi
ldap/admin/src/scripts/DSCreate.pm.in | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
New commits:
commit 5d0f57335c1bf97529849d5d47cad769083052d0
Author: William Brown <firstyear(a)redhat.com>
Date: Thu Nov 26 13:11:17 2015 +1000
Ticket 48332 - allow users to specify to relax the FQDN constraint
Bug Description: There are situations when the machine name for ds may not
match the dns name. In these cases we should allow installation without the
strict hostname checks we carry out.
Fix Description: Add a new option, General.StrictHostCheck which defaults
to true. If true, host name checking is carried out. If false, it is disabled
and any hostname in General.FullMachineName is considered valid.
https://fedorahosted.org/389/ticket/48332
Author: wibrown
Review by: rmeggins (Thanks!)
(cherry picked from commit 026956c7e3b4dc00b6738f9a195e6653fed03d79)
diff --git a/ldap/admin/src/scripts/DSCreate.pm.in b/ldap/admin/src/scripts/DSCreate.pm.in
index 7082fd9..0c4928a 100644
--- a/ldap/admin/src/scripts/DSCreate.pm.in
+++ b/ldap/admin/src/scripts/DSCreate.pm.in
@@ -126,9 +126,18 @@ sub sanityCheckParams {
debug(0, "WARNING: The root password is less than 8 characters long. You should choose a longer one.\n");
}
- if (@errs = checkHostname($inf->{General}->{FullMachineName}, 0)) {
- debug(1, @errs);
- return @errs;
+ $inf->{General}->{StrictHostCheck} = lc $inf->{General}->{StrictHostCheck};
+
+ if ("true" ne $inf->{General}->{StrictHostCheck} && "false" ne $inf->{General}->{StrictHostCheck}) {
+ debug(1, "StrictHostCheck is not a valid boolean");
+ return ('error_invalid_boolean', $inf->{General}->{StrictHostCheck});
+ }
+
+ if ($inf->{General}->{StrictHostCheck} eq "true" ) {
+ if (@errs = checkHostname($inf->{General}->{FullMachineName}, 0)) {
+ debug(1, @errs);
+ return @errs;
+ }
}
return ();
@@ -876,6 +885,10 @@ sub setDefaults {
"@datadir@",
$inf->{General}->{prefix});
+ if (!defined($inf->{General}->{StrictHostCheck})) {
+ $inf->{General}->{StrictHostCheck} = "true";
+ }
+
if (!defined($inf->{slapd}->{inst_dir})) {
$inf->{slapd}->{inst_dir} = "$inf->{General}->{ServerRoot}/slapd-$servid";
}
7 years, 11 months
ldap/servers
by William Brown
ldap/servers/plugins/cos/cos_cache.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
New commits:
commit d7c71db218f27cdbc2fcc39401a97b00e8d890a4
Author: William Brown <firstyear(a)redhat.com>
Date: Thu Dec 17 15:00:18 2015 +1000
Ticket 48387 - ASAN invalid read in cos_cache.c
Bug Description: ==7050== ERROR: AddressSanitizer?: global-buffer-overflow on
address 0x7f643b32c5ff at pc 0x7f643b3217aa bp 0x7f64331c5f60 sp 0x7f64331c5f50
READ of size 1 at 0x7f643b32c5ff thread T5
#0 0x7f643b3217a9 in cos_cache_backwards_stricmp_and_clip
ds/ldap/servers/plugins/cos/cos_cache.c:3428
Issue exists in the array offset check, which allows the value to go to -1
causing the invalid read.
Fix Description: Fix the check to only allow the offset to go to 0, not -1
https://fedorahosted.org/389/ticket/48387
Author: wibrown
Review by: nhosoi (Thank you!)
diff --git a/ldap/servers/plugins/cos/cos_cache.c b/ldap/servers/plugins/cos/cos_cache.c
index db90ffa..cb5cb69 100644
--- a/ldap/servers/plugins/cos/cos_cache.c
+++ b/ldap/servers/plugins/cos/cos_cache.c
@@ -3413,14 +3413,18 @@ static int cos_cache_backwards_stricmp_and_clip(char*s1,char*s2)
int s1len = 0;
int s2len = 0;
- LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_backwards_stricmp_and_clip\n",0,0,0);
-
s1len = strlen(s1);
s2len = strlen(s2);
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_backwards_stricmp_and_clip s1 %d s2 %d\n",s1len,s2len,0);
+
if(s1len > s2len && s2len > 0)
{
- while(s1len > -1 && s2len > -1)
+ /* In some cases this can go below 0 causing invalid reads
+ * We make the check for > 0, because if we are at 1 -> 0 is next
+ * If the check is > -1, we can easily get to 0, then -1, creating invalid read.
+ */
+ while(s1len > 0 && s2len > 0)
{
s1len--;
s2len--;
7 years, 11 months
3 commits - dirsrvtests/tickets ldap/servers
by Noriko Hosoi
dirsrvtests/tickets/ticket142_test.py | 330 +++++++++++++++++++++++++++++++++
ldap/servers/plugins/cos/cos_cache.c | 2
ldap/servers/slapd/back-ldbm/dblayer.c | 13 +
ldap/servers/slapd/libglobs.c | 34 +++
ldap/servers/slapd/proto-slap.h | 2
ldap/servers/slapd/pw.c | 27 ++
ldap/servers/slapd/slap.h | 3
7 files changed, 405 insertions(+), 6 deletions(-)
New commits:
commit f5b9053e3d408c9b81d5ac537bd772360515a641
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Wed Dec 16 17:49:34 2015 -0800
Ticket #48244 - No validation check for the value for nsslapd-db-locks
Description: Added a validation check for the value for nsslapd-db-locks.
The default value is 10000 and now the lower value is set, it is set back
to the default value with this error message:
[..] - New max db lock count is too small. Resetting it to the default value 10000.
https://fedorahosted.org/389/ticket/48244
Reviewed by firstyear(a)redhat.com (Thank you, William!!)
diff --git a/ldap/servers/slapd/back-ldbm/dblayer.c b/ldap/servers/slapd/back-ldbm/dblayer.c
index 9168c8c..e65f3cf 100644
--- a/ldap/servers/slapd/back-ldbm/dblayer.c
+++ b/ldap/servers/slapd/back-ldbm/dblayer.c
@@ -1661,8 +1661,19 @@ dblayer_start(struct ldbminfo *li, int dbmode)
priv->dblayer_previous_ncache, priv->dblayer_ncache, 0);
}
if (priv->dblayer_lock_config != priv->dblayer_previous_lock_config) {
- LDAPDebug(LDAP_DEBUG_ANY, "resizing max db lock count: %d -> %d\n",
+ /*
+ * The default value of nsslapd-db-locks is 10000.
+ * We don't allow lower value than that.
+ */
+ if (priv->dblayer_lock_config <= 10000) {
+ LDAPDebug0Args(LDAP_DEBUG_ANY, "New max db lock count is too small. "
+ "Resetting it to the default value 10000.\n");
+ priv->dblayer_lock_config = 10000;
+ }
+ if (priv->dblayer_lock_config != priv->dblayer_previous_lock_config) {
+ LDAPDebug(LDAP_DEBUG_ANY, "resizing max db lock count: %d -> %d\n",
priv->dblayer_previous_lock_config, priv->dblayer_lock_config, 0);
+ }
}
dblayer_reset_env(li);
/*
commit 1c3fa84d3ef74c660ee0743e2d5516d066f948b7
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Wed Dec 16 10:42:08 2015 -0800
Ticket 142 - CI test: added test cases for ticket 142
Description: [RFE] Default password syntax settings don't work with fine-grained policies
diff --git a/dirsrvtests/tickets/ticket142_test.py b/dirsrvtests/tickets/ticket142_test.py
new file mode 100644
index 0000000..53cb82f
--- /dev/null
+++ b/dirsrvtests/tickets/ticket142_test.py
@@ -0,0 +1,330 @@
+# --- 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
+import shutil
+from lib389 import DirSrv, Entry, tools
+from lib389 import DirSrvTools
+from lib389.tools import DirSrvTools
+from lib389._constants import *
+from lib389.properties import *
+
+log = logging.getLogger(__name__)
+
+installation_prefix = None
+
+CONFIG_DN = 'cn=config'
+OU_PEOPLE = 'ou=People,' + DEFAULT_SUFFIX
+PWP_CONTAINER = 'nsPwPolicyContainer'
+PWP_CONTAINER_DN = 'cn=' + PWP_CONTAINER + ',' + OU_PEOPLE
+PWP_ENTRY_DN = 'cn=nsPwPolicyEntry,' + OU_PEOPLE
+PWP_TEMPLATE_ENTRY_DN = 'cn=nsPwTemplateEntry,' + OU_PEOPLE
+ATTR_INHERIT_GLOBAL = 'nsslapd-pwpolicy-inherit-global'
+
+BN = 'uid=buser,' + DEFAULT_SUFFIX
+
+class TopologyStandalone(object):
+ def __init__(self, standalone):
+ standalone.open()
+ self.standalone = standalone
+
+
+(a)pytest.fixture(scope="module")
+def topology(request):
+ '''
+ This fixture is used to standalone topology for the 'module'.
+ '''
+ global installation_prefix
+
+ if installation_prefix:
+ args_instance[SER_DEPLOYED_DIR] = installation_prefix
+
+ standalone = DirSrv(verbose=False)
+
+ # Args for the standalone instance
+ args_instance[SER_HOST] = HOST_STANDALONE
+ args_instance[SER_PORT] = PORT_STANDALONE
+ args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
+ args_standalone = args_instance.copy()
+ standalone.allocate(args_standalone)
+
+ # Get the status of the instance and restart it if it exists
+ instance_standalone = standalone.exists()
+
+ # Remove the instance
+ if instance_standalone:
+ standalone.delete()
+
+ # Create the instance
+ standalone.create()
+
+ # Used to retrieve configuration information (dbdir, confdir...)
+ standalone.open()
+
+ # clear the tmp directory
+ standalone.clearTmpDir(__file__)
+
+ # Here we have standalone instance up and running
+ return TopologyStandalone(standalone)
+
+
+def _header(topology, label):
+ topology.standalone.log.info("###############################################")
+ topology.standalone.log.info("####### %s" % label)
+ topology.standalone.log.info("###############################################")
+
+def check_attr_val(topology, dn, attr, expected):
+ try:
+ centry = topology.standalone.search_s(dn, ldap.SCOPE_BASE, 'cn=*')
+ if centry:
+ val = centry[0].getValue(attr)
+ if val == expected:
+ log.info('Default value of %s is %s' % (attr, expected))
+ else:
+ log.info('Default value of %s is not %s, but %s' % (attr, expected, val))
+ assert False
+ else:
+ log.fatal('Failed to get %s' % dn)
+ assert False
+ except ldap.LDAPError as e:
+ log.fatal('Failed to search ' + dn + ': ' + e.message['desc'])
+ assert False
+
+def _142_init(topology):
+ """
+ Set global password policy.
+ Then, set fine-grained subtree level password policy to ou=People with no password syntax.
+ Note: do not touch nsslapd-pwpolicy-inherit-global -- off by default
+ Also, adding an ordinary bind user.
+ """
+ _header(topology, 'Testing Ticket 142 - Default password syntax settings do not work with fine-grained policies')
+
+ log.info("Setting global password policy with password syntax.")
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, 'nsslapd-pwpolicy-local', 'on')])
+
+ log.info("Setting fine-grained password policy.")
+ topology.standalone.add_s(Entry((PWP_CONTAINER_DN, {
+ 'objectclass': "top nsContainer".split()})))
+ topology.standalone.add_s(Entry(('cn="%s",%s' % (PWP_ENTRY_DN, PWP_CONTAINER_DN), {
+ 'objectclass': "top ldapsubentry passwordpolicy".split()})))
+ topology.standalone.add_s(Entry(('cn="%s",%s' % (PWP_TEMPLATE_ENTRY_DN, PWP_CONTAINER_DN), {
+ 'objectclass': "top ldapsubentry costemplate".split(),
+ 'pwdpolicysubentry': 'cn="%s",%s' % (PWP_ENTRY_DN, PWP_CONTAINER_DN)})))
+ topology.standalone.add_s(Entry(('cn=nsPwPolicy_CoS,%s' % OU_PEOPLE, {
+ 'objectclass': "top ldapsubentry cosSuperDefinition cosPointerDefinition".split(),
+ 'cosTemplateDn': 'cn="%s",%s' % (PWP_TEMPLATE_ENTRY_DN, PWP_CONTAINER_DN),
+ 'cosAttribute': 'pwdpolicysubentry default operational-default'})))
+
+ log.info(" with the default settings.")
+ topology.standalone.modify_s('cn="%s",%s' % (PWP_ENTRY_DN, PWP_CONTAINER_DN),
+ [(ldap.MOD_REPLACE, 'passwordMustChange', 'off'),
+ (ldap.MOD_REPLACE, 'passwordExp', 'off'),
+ (ldap.MOD_REPLACE, 'passwordMinAge', '0'),
+ (ldap.MOD_REPLACE, 'passwordChange', 'off'),
+ (ldap.MOD_REPLACE, 'passwordStorageScheme', 'ssha')])
+
+ check_attr_val(topology, CONFIG_DN, ATTR_INHERIT_GLOBAL, 'off')
+ check_attr_val(topology, CONFIG_DN, 'passwordCheckSyntax', 'off')
+
+ log.info('Adding a bind user.')
+ topology.standalone.add_s(Entry((BN,
+ {'objectclass': "top person organizationalPerson inetOrgPerson".split(),
+ 'cn': 'bind user',
+ 'sn': 'bind user',
+ 'userPassword': PASSWORD})))
+
+ log.info('Adding an aci for the bind user.')
+ topology.standalone.modify_s(OU_PEOPLE,
+ [(ldap.MOD_ADD,
+ 'aci',
+ '(targetattr="*")(version 3.0; acl "pwp test"; allow (all) userdn="ldap:///%s";)' % BN)])
+
+
+def _142_run_0(topology):
+ """
+ Make sure an entry added to ou=people has no password syntax restrictions.
+ """
+ _header(topology, 'Case 0 - Make sure an entry added to ou=people has no password syntax restrictions.')
+
+ topology.standalone.simple_bind_s(BN, PASSWORD)
+ try:
+ topology.standalone.add_s(Entry(('cn=test0,%s' % OU_PEOPLE,
+ {'objectclass': "top person organizationalPerson inetOrgPerson".split(),
+ 'cn': 'test0',
+ 'sn': 'test0',
+ 'userPassword': 'short'})))
+ except ldap.LDAPError as e:
+ log.fatal('Failed to add cn=test0 with userPassword: short: ' + e.message['desc'])
+ assert False
+
+ log.info('PASSED')
+
+
+def _142_run_1(topology):
+ """
+ Set 'nsslapd-pwpolicy-inherit-global: on'
+ But passwordCheckSyntax is still off.
+ Make sure an entry added to ou=people has the global password syntax restrictions.
+ """
+ _header(topology, 'Case 1 - Make sure an entry added to ou=people has no password syntax restrictions.')
+
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ topology.standalone.modify_s(CONFIG_DN, [(ldap.MOD_REPLACE, ATTR_INHERIT_GLOBAL, 'on')])
+ check_attr_val(topology, CONFIG_DN, ATTR_INHERIT_GLOBAL, 'on')
+ check_attr_val(topology, CONFIG_DN, 'passwordCheckSyntax', 'off')
+ topology.standalone.simple_bind_s(BN, PASSWORD)
+ try:
+ topology.standalone.add_s(Entry(('cn=test1,%s' % OU_PEOPLE,
+ {'objectclass': "top person organizationalPerson inetOrgPerson".split(),
+ 'cn': 'test1',
+ 'sn': 'test1',
+ 'userPassword': 'short'})))
+ except ldap.LDAPError as e:
+ log.fatal('Failed to add cn=test1 with userPassword: short: ' + e.message['desc'])
+ assert False
+
+ log.info('PASSED')
+
+
+def _142_run_2(topology):
+ """
+ Set 'passwordCheckSyntax: on'
+ Set 'passwordMinLength: 9' for testing
+ Make sure an entry added to ou=people has the global password syntax restrictions.
+ """
+ _header(topology, 'Case 2 - Make sure an entry added to ou=people has the global password syntax restrictions.')
+
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ topology.standalone.modify_s(CONFIG_DN,
+ [(ldap.MOD_REPLACE, 'passwordCheckSyntax', 'on'),
+ (ldap.MOD_REPLACE, 'passwordMinLength', '9')])
+ check_attr_val(topology, CONFIG_DN, ATTR_INHERIT_GLOBAL, 'on')
+ check_attr_val(topology, CONFIG_DN, 'passwordCheckSyntax', 'on')
+ topology.standalone.simple_bind_s(BN, PASSWORD)
+ failed_as_expected = False
+ try:
+ topology.standalone.add_s(Entry(('cn=test2,%s' % OU_PEOPLE,
+ {'objectclass': "top person organizationalPerson inetOrgPerson".split(),
+ 'cn': 'test2',
+ 'sn': 'test2',
+ 'userPassword': 'Abcd2345'})))
+ except ldap.LDAPError as e:
+ log.info('Adding cn=test2 with "userPassword: Abcd2345" was expectedly rejected: ' + e.message['desc'])
+ failed_as_expected = True
+
+ if not failed_as_expected:
+ log.fatal('Adding cn=test2 with "userPassword: Abcd2345" was unexpectedly successful despite of short password.')
+ assert False
+
+ try:
+ topology.standalone.add_s(Entry(('cn=test2,%s' % OU_PEOPLE,
+ {'objectclass': "top person organizationalPerson inetOrgPerson".split(),
+ 'cn': 'test2',
+ 'sn': 'test2',
+ 'userPassword': 'Abcd23456'})))
+ except ldap.LDAPError as e:
+ log.fatal('Adding cn=test2 with "userPassword: Abcd23456" failed: ' + e.message['desc'])
+ assert False
+
+ log.info('PASSED')
+
+
+def _142_run_3(topology):
+ """
+ Set 'passwordCheckSyntax: on'
+ Set 'nsslapd-pwpolicy-inherit-global: off'
+ Make sure an entry added to ou=people has no syntax restrictions.
+ """
+ _header(topology, 'Case 3 - Make sure an entry added to ou=people has no password syntax restrictions.')
+
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ topology.standalone.modify_s(CONFIG_DN,
+ [(ldap.MOD_REPLACE, ATTR_INHERIT_GLOBAL, 'off')])
+ check_attr_val(topology, CONFIG_DN, ATTR_INHERIT_GLOBAL, 'off')
+ check_attr_val(topology, CONFIG_DN, 'passwordCheckSyntax', 'on')
+ topology.standalone.simple_bind_s(BN, PASSWORD)
+ try:
+ topology.standalone.add_s(Entry(('cn=test3,%s' % OU_PEOPLE,
+ {'objectclass': "top person organizationalPerson inetOrgPerson".split(),
+ 'cn': 'test3',
+ 'sn': 'test3',
+ 'userPassword': 'Abcd3456'})))
+ except ldap.LDAPError as e:
+ log.fatal('Adding cn=test3 with "userPassword: Abcd3456" failed: ' + e.message['desc'])
+ assert False
+
+ log.info('PASSED')
+
+
+def _142_run_4(topology):
+ """
+ Set 'passwordCheckSyntax: on'
+ Set 'nsslapd-pwpolicy-inherit-global: on'
+ Set password syntax to fine-grained password policy to check it overrides the global settings.
+ """
+ _header(topology, 'Case 4 - Make sure an entry added to ou=people follows the fine-grained password syntax restrictions.')
+
+ topology.standalone.simple_bind_s(DN_DM, PASSWORD)
+ topology.standalone.modify_s(CONFIG_DN,
+ [(ldap.MOD_REPLACE, ATTR_INHERIT_GLOBAL, 'on')])
+ check_attr_val(topology, CONFIG_DN, ATTR_INHERIT_GLOBAL, 'on')
+ check_attr_val(topology, CONFIG_DN, 'passwordCheckSyntax', 'on')
+ topology.standalone.modify_s('cn="%s",%s' % (PWP_ENTRY_DN, PWP_CONTAINER_DN),
+ [(ldap.MOD_REPLACE, 'passwordMinLength', '5'),
+ (ldap.MOD_REPLACE, 'passwordMinCategories', '2')])
+ try:
+ topology.standalone.add_s(Entry(('cn=test4,%s' % OU_PEOPLE,
+ {'objectclass': "top person organizationalPerson inetOrgPerson".split(),
+ 'cn': 'test4',
+ 'sn': 'test4',
+ 'userPassword': 'Abcd4'})))
+ except ldap.LDAPError as e:
+ log.fatal('Adding cn=test4 with "userPassword: Abcd4" failed: ' + e.message['desc'])
+ assert False
+
+ log.info('PASSED')
+
+
+def _142_final(topology):
+ topology.standalone.delete()
+ log.info('All PASSED')
+
+
+def test_ticket142(topology):
+ '''
+ 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 installation_prefix
+ installation_prefix = None
+
+ _142_init(topology)
+
+ _142_run_0(topology)
+ _142_run_1(topology)
+ _142_run_2(topology)
+ _142_run_3(topology)
+ _142_run_4(topology)
+
+ _142_final(topology)
+
+if __name__ == '__main__':
+ # Run isolated
+ # -s for DEBUG mode
+
+ CURRENT_FILE = os.path.realpath(__file__)
+ pytest.main("-s %s" % CURRENT_FILE)
commit af1fc5e7711185d921ffb67f6d4a870dfa3bbcde
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Tue Dec 15 13:37:27 2015 -0800
Ticket #142 - [RFE] Default password syntax settings don't work with fine-grained policies
Description: When a fine-grained password syntax is not set, there is no
syntax restriction for the passwords to be added or modified even though
the global password syntax is configured.
This patch introducing a config parameter:
cn=config.
nsslapd-pwpolicy-inherit-global: on | off
If on, the fine-grained password syntax inherits the global password
syntax if the global one is configured.
If off, the inheritance does not occur. This is the current behaviour.
By default, it is off.
https://fedorahosted.org/389/ticket/142
Reviewed by firstyear(a)redhat.com (Thank you, William!!)
diff --git a/ldap/servers/plugins/cos/cos_cache.c b/ldap/servers/plugins/cos/cos_cache.c
index e0b841d..db90ffa 100644
--- a/ldap/servers/plugins/cos/cos_cache.c
+++ b/ldap/servers/plugins/cos/cos_cache.c
@@ -2329,7 +2329,7 @@ static int cos_cache_query_attr(cos_cache *ptheCache, vattr_context *context,
/* now for the tests */
/* would we be allowed to supply this attribute if we had one? */
- if(entry_has_value && pAttr->attr_override == 0 && pAttr->attr_operational == 0)
+ if (entry_has_value && !pAttr->attr_override && !pAttr->attr_operational && !pAttr->attr_operational_default)
{
/* answer: no, move on to the next attribute */
attr_index++;
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
index 4661964..d108bf3 100644
--- a/ldap/servers/slapd/libglobs.c
+++ b/ldap/servers/slapd/libglobs.c
@@ -186,6 +186,7 @@ slapi_onoff_t init_csnlogging;
slapi_onoff_t init_pw_unlock;
slapi_onoff_t init_pw_must_change;
slapi_onoff_t init_pwpolicy_local;
+slapi_onoff_t init_pwpolicy_inherit_global;
slapi_onoff_t init_pw_lockout;
slapi_onoff_t init_pw_history;
slapi_onoff_t init_pw_is_global_policy;
@@ -406,6 +407,10 @@ static struct config_get_and_set {
NULL, 0,
(void**)&global_slapdFrontendConfig.pwpolicy_local,
CONFIG_ON_OFF, NULL, &init_pwpolicy_local},
+ {CONFIG_PWPOLICY_INHERIT_GLOBAL_ATTRIBUTE, config_set_pwpolicy_inherit_global,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.pwpolicy_inherit_global,
+ CONFIG_ON_OFF, NULL, &init_pwpolicy_inherit_global},
{CONFIG_AUDITLOG_MAXLOGDISKSPACE_ATTRIBUTE, NULL,
log_set_maxdiskspace, SLAPD_AUDIT_LOG,
(void**)&global_slapdFrontendConfig.auditlog_maxdiskspace,
@@ -1506,6 +1511,7 @@ FrontendConfig_init () {
init_readonly = cfg->readonly = LDAP_OFF;
init_pwpolicy_local = cfg->pwpolicy_local = LDAP_OFF;
+ init_pwpolicy_inherit_global = cfg->pwpolicy_inherit_global = LDAP_OFF;
init_pw_change = cfg->pw_policy.pw_change = LDAP_ON;
init_pw_must_change = cfg->pw_policy.pw_must_change = LDAP_OFF;
init_allow_hashed_pw = cfg->allow_hashed_pw = LDAP_OFF;
@@ -2581,7 +2587,6 @@ config_set_pw_history( const char *attrname, char *value, char *errorbuf, int ap
}
-
int
config_set_pw_must_change( const char *attrname, char *value, char *errorbuf, int apply ) {
int retVal = LDAP_SUCCESS;
@@ -2618,6 +2623,23 @@ config_set_pwpolicy_local( const char *attrname, char *value, char *errorbuf, in
return retVal;
}
+
+int
+config_set_pwpolicy_inherit_global(const char *attrname, char *value, char *errorbuf, int apply)
+{
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff (attrname,
+ value,
+ &(slapdFrontendConfig->pwpolicy_inherit_global),
+ errorbuf,
+ apply);
+
+ return retVal;
+}
+
+
int
config_set_allow_hashed_pw( const char *attrname, char *value, char *errorbuf, int apply ) {
int retVal = LDAP_SUCCESS;
@@ -5712,6 +5734,16 @@ config_get_pw_warning() {
}
int
+config_get_pwpolicy_inherit_global()
+{
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ retVal = slapdFrontendConfig->pwpolicy_inherit_global;
+ return retVal;
+}
+
+int
config_get_errorlog_level(){
slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
int retVal;
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
index 0547bc7..7d965b0 100644
--- a/ldap/servers/slapd/proto-slap.h
+++ b/ldap/servers/slapd/proto-slap.h
@@ -301,6 +301,7 @@ int config_set_pw_change(const char *attrname, char *value, char *errorbuf, int
int config_set_pw_must_change(const char *attrname, char *value, char *errorbuf, int apply );
int config_set_pwpolicy_local(const char *attrname, char *value, char *errorbuf, int apply );
int config_set_allow_hashed_pw( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_pwpolicy_inherit_global(const char *attrname, char *value, char *errorbuf, int apply );
int config_set_pw_syntax(const char *attrname, char *value, char *errorbuf, int apply );
int config_set_pw_minlength(const char *attrname, char *value, char *errorbuf, int apply );
int config_set_pw_mindigits(const char *attrname, char *value, char *errorbuf, int apply );
@@ -444,6 +445,7 @@ int config_get_pw_exp();
int config_get_pw_unlock();
int config_get_pw_lockout();
int config_get_pw_gracelimit();
+int config_get_pwpolicy_inherit_global();
int config_get_lastmod();
int config_get_nagle();
int config_get_accesscontrol();
diff --git a/ldap/servers/slapd/pw.c b/ldap/servers/slapd/pw.c
index 3985c2b..69756f3 100644
--- a/ldap/servers/slapd/pw.c
+++ b/ldap/servers/slapd/pw.c
@@ -853,7 +853,7 @@ check_pw_syntax_ext ( Slapi_PBlock *pb, const Slapi_DN *sdn, Slapi_Value **vals,
}
}
- if ( pwpolicy->pw_syntax == 1 ) {
+ if ( pwpolicy->pw_syntax == LDAP_ON ) {
for ( i = 0; vals[ i ] != NULL; ++i ) {
int syntax_violation = 0;
int num_digits = 0;
@@ -1057,7 +1057,7 @@ retry:
}
/* check for trivial words if syntax checking is enabled */
- if ( pwpolicy->pw_syntax == 1 ) {
+ if ( pwpolicy->pw_syntax == LDAP_ON ) {
/* e is null if this is an add operation*/
if ( check_trivial_words ( pb, e, vals, "uid", pwpolicy->pw_mintokenlength, smods ) == 1 ||
check_trivial_words ( pb, e, vals, "cn", pwpolicy->pw_mintokenlength, smods ) == 1 ||
@@ -1999,7 +1999,28 @@ new_passwdPolicy(Slapi_PBlock *pb, const char *dn)
if (pw_entry) {
slapi_entry_free(pw_entry);
}
- if(pb){
+ if (LDAP_ON != pwdpolicy->pw_syntax) {
+ passwdPolicy *g_pwdpolicy = &(slapdFrontendConfig->pw_policy);
+ /*
+ * When the fine-grained password policy does not set the
+ * password syntax, get the syntax from the global
+ * policy if nsslapd-pwpolicy-inherit-global is on.
+ */
+ if ((LDAP_ON == g_pwdpolicy->pw_syntax) && config_get_pwpolicy_inherit_global()) {
+ pwdpolicy->pw_minlength = g_pwdpolicy->pw_minlength;
+ pwdpolicy->pw_mindigits = g_pwdpolicy->pw_mindigits;
+ pwdpolicy->pw_minalphas = g_pwdpolicy->pw_minalphas;
+ pwdpolicy->pw_minuppers = g_pwdpolicy->pw_minuppers;
+ pwdpolicy->pw_minlowers = g_pwdpolicy->pw_minlowers;
+ pwdpolicy->pw_minspecials = g_pwdpolicy->pw_minspecials;
+ pwdpolicy->pw_min8bit = g_pwdpolicy->pw_min8bit;
+ pwdpolicy->pw_maxrepeats = g_pwdpolicy->pw_maxrepeats;
+ pwdpolicy->pw_mincategories = g_pwdpolicy->pw_mincategories;
+ pwdpolicy->pw_mintokenlength = g_pwdpolicy->pw_mintokenlength;
+ pwdpolicy->pw_syntax = LDAP_ON; /* Need to enable it to apply the default values */
+ }
+ }
+ if (pb) {
pb->pwdpolicy = pwdpolicy;
}
return pwdpolicy;
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
index 0b867ab..0474e8e 100644
--- a/ldap/servers/slapd/slap.h
+++ b/ldap/servers/slapd/slap.h
@@ -2013,6 +2013,7 @@ typedef struct _slapdEntryPoints {
#define CONFIG_GROUPEVALNESTLEVEL_ATTRIBUTE "nsslapd-groupevalnestlevel"
#define CONFIG_NAGLE_ATTRIBUTE "nsslapd-nagle"
#define CONFIG_PWPOLICY_LOCAL_ATTRIBUTE "nsslapd-pwpolicy-local"
+#define CONFIG_PWPOLICY_INHERIT_GLOBAL_ATTRIBUTE "nsslapd-pwpolicy-inherit-global"
#define CONFIG_ALLOW_HASHED_PW_ATTRIBUTE "nsslapd-allow-hashed-passwords"
#define CONFIG_PW_CHANGE_ATTRIBUTE "passwordChange"
#define CONFIG_PW_MUSTCHANGE_ATTRIBUTE "passwordMustChange"
@@ -2229,8 +2230,10 @@ typedef struct _slapdFrontendConfig {
slapi_onoff_t pwpolicy_local;
slapi_onoff_t pw_is_global_policy;
+ slapi_onoff_t pwpolicy_inherit_global;
slapi_onoff_t allow_hashed_pw;
passwdPolicy pw_policy;
+ slapi_onoff_t pw_policy_inherit_global;
/* ACCESS LOG */
slapi_onoff_t accesslog_logging_enabled;
7 years, 11 months
ldap/admin rpm/389-ds-base.spec.in rpm.mk
by Mark Reynolds
ldap/admin/src/base-initconfig.in | 6 ++++
rpm.mk | 28 +++++++++++++++++---
rpm/389-ds-base.spec.in | 51 ++++++++++++++++++++++++++++++++++----
3 files changed, 75 insertions(+), 10 deletions(-)
New commits:
commit f132cf41805a9ff525f611967b88a6d85f520def
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Wed Dec 16 15:19:24 2015 -0500
Ticket 48377 - Bundle jemalloc with Directory Server
Description: Updated spec files to download the latest supported
version of jemalloc source code, and build it. Then
include the library in the server's library directory
(/usr/lib64/dirsrv). Also, the bundled jemalloc library
can coexist with any existing jemalloc package. This
allows us to control the supported version that we ship.
Then in /etc/sysconfig/dirsrv added a commented LD_PRELOAD
line that is pre-set for the server.
Also fixed rpm.mk so that it looked at the proper spec file
for nunc-stans and jemalloc configuraton.
https://fedorahosted.org/389/ticket/48377
Reviewed by: rmeggins, wibrown, and nhosoi(Thanks!!!)
diff --git a/ldap/admin/src/base-initconfig.in b/ldap/admin/src/base-initconfig.in
index 2d47eb7..e803a36 100644
--- a/ldap/admin/src/base-initconfig.in
+++ b/ldap/admin/src/base-initconfig.in
@@ -42,3 +42,9 @@
# up before we assume there is a problem and fail to start
# if using systemd, omit the "; export VARNAME" at the end
#PID_TIME=600 ; export PID_TIME
+
+# jemalloc is a general purpose malloc implementation that emphasizes
+# fragmentation avoidance and scalable concurrency support. jemalloc
+# has been shown to have a significant positive impact on the Directory
+# Server's process size/growth.
+#LD_PRELOAD=@libdir@/@package_name(a)/libjemalloc.so.1 ; export LD_PRELOAD
diff --git a/rpm.mk b/rpm.mk
index aa397b7..4d89777 100644
--- a/rpm.mk
+++ b/rpm.mk
@@ -4,8 +4,12 @@ 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_URL ?= $(shell rpmspec -P -D 'use_nunc_stans 1' $(RPMBUILD)/SPECS/389-ds-base.spec | awk '/^Source4:/ {print $$2}')
NUNC_STANS_TARBALL ?= $(shell basename "$(NUNC_STANS_URL)")
+JEMALLOC_URL ?= $(shell rpmspec -P $(RPMBUILD)/SPECS/389-ds-base.spec | awk '/^Source3:/ {print $$2}')
+JEMALLOC_TARBALL ?= $(shell basename "$(JEMALLOC_URL)")
+NUNC_STANS_ON = 1
+BUNDLE_JEMALLOC = 1
clean:
rm -rf dist
@@ -19,7 +23,13 @@ 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)
+ cd dist/sources ; \
+ if [ $(NUNC_STANS_ON) -eq 1 ]; then \
+ wget $(NUNC_STANS_URL) ; \
+ fi ; \
+ if [ $(BUNDLE_JEMALLOC) -eq 1 ]; then \
+ wget $(JEMALLOC_URL) ; \
+ fi
rpmroot:
rm -rf $(RPMBUILD)
@@ -28,6 +38,10 @@ rpmroot:
mkdir -p $(RPMBUILD)/SOURCES
mkdir -p $(RPMBUILD)/SPECS
mkdir -p $(RPMBUILD)/SRPMS
+ sed -e s/__VERSION__/$(RPM_VERSION)/ -e s/__RELEASE__/$(RPM_RELEASE)/ \
+ -e s/__NUNC_STANS_ON__/$(NUNC_STANS_ON)/ \
+ -e s/__BUNDLE_JEMALLOC__/$(BUNDLE_JEMALLOC)/ \
+ rpm/$(PACKAGE).spec.in > $(RPMBUILD)/SPECS/$(PACKAGE).spec
rpmdistdir:
mkdir -p dist/rpms
@@ -37,10 +51,14 @@ srpmdistdir:
rpmbuildprep:
cp dist/sources/$(TARBALL) $(RPMBUILD)/SOURCES/
- cp dist/sources/$(NUNC_STANS_TARBALL) $(RPMBUILD)/SOURCES/
+ if [ $(NUNC_STANS_ON) -eq 1 ]; then \
+ cp dist/sources/$(NUNC_STANS_TARBALL) $(RPMBUILD)/SOURCES/ ; \
+ fi
+ if [ $(BUNDLE_JEMALLOC) -eq 1 ]; then \
+ cp dist/sources/$(JEMALLOC_TARBALL) $(RPMBUILD)/SOURCES/ ; \
+ fi
cp rpm/$(PACKAGE)-* $(RPMBUILD)/SOURCES/
- sed -e s/__VERSION__/$(RPM_VERSION)/ -e s/__RELEASE__/$(RPM_RELEASE)/ \
- rpm/$(PACKAGE).spec.in > $(RPMBUILD)/SPECS/$(PACKAGE).spec
+
srpms: rpmroot srpmdistdir tarballs rpmbuildprep
rpmbuild --define "_topdir $(RPMBUILD)" -bs $(RPMBUILD)/SPECS/$(PACKAGE).spec
diff --git a/rpm/389-ds-base.spec.in b/rpm/389-ds-base.spec.in
index ff85863..6e4bc48 100644
--- a/rpm/389-ds-base.spec.in
+++ b/rpm/389-ds-base.spec.in
@@ -12,13 +12,19 @@
# If perl-Socket-2.000 or newer is available, set 0 to use_Socket6.
%global use_Socket6 0
# nunc-stans only builds on x86_64 for now
-# To build without nunc-stans, set 0 to use_nunc_stans.
+# To build without nunc-stans, set use_nunc_stans to 0.
%global use_nunc_stans __NUNC_STANS_ON__
-
%if %{use_nunc_stans}
%global nunc_stans_ver 0.1.7
%endif
+# Are we bundling jemalloc?
+%global bundle_jemalloc __BUNDLE_JEMALLOC__
+%if %{bundle_jemalloc}
+# The version used in the source tarball
+%global jemalloc_ver 3.6.0
+%endif
+
# fedora 15 and later uses tmpfiles.d
# otherwise, comment this out
%{!?with_tmpfiles_d: %global with_tmpfiles_d %{_sysconfdir}/tmpfiles.d}
@@ -32,7 +38,6 @@
Summary: 389 Directory Server (base)
Name: 389-ds-base
Version: __VERSION__
-#Release: %{?relprefix}1%{?prerel}%{?dist}
Release: __RELEASE__%{?dist}
License: GPLv2 with exceptions
URL: http://port389.org/
@@ -122,8 +127,12 @@ Source0: http://port389.org/sources/%{name}-%{version}%{?prerel}.tar.bz
# 389-ds-git.sh should be used to generate the source tarball from git
Source1: %{name}-git.sh
Source2: %{name}-devel.README
+
+%if %{bundle_jemalloc}
+Source3: http://www.port389.org/binaries/jemalloc-%{jemalloc_ver}.tar.bz2
+%endif
%if %{use_nunc_stans}
-Source3: https://git.fedorahosted.org/cgit/nunc-stans.git/snapshot/nunc-stans-%{nu...
+Source4: https://git.fedorahosted.org/cgit/nunc-stans.git/snapshot/nunc-stans-%{nu...
%endif
%description
@@ -154,6 +163,12 @@ BuildRequires: libtalloc-devel
BuildRequires: libevent-devel
BuildRequires: libtevent-devel
%endif
+%if %{bundle_jemalloc}
+BuildRequires: /usr/bin/xsltproc
+%ifnarch s390
+BuildRequires: valgrind-devel
+%endif
+%endif
%description libs
Core libraries for the 389 Directory Server base package. These libraries
@@ -184,9 +199,13 @@ Development Libraries and headers for the 389 Directory Server base package.
%prep
%setup -q -n %{name}-%{version}%{?prerel}
-%if %{use_nunc_stans}
+
+%if %{bundle_jemalloc}
%setup -q -n %{name}-%{version}%{?prerel} -T -D -b 3
%endif
+%if %{use_nunc_stans}
+%setup -q -n %{name}-%{version}%{?prerel} -T -D -b 4
+%endif
cp %{SOURCE2} README.devel
%build
@@ -201,6 +220,13 @@ cp nunc-stans.h include/nunc-stans/nunc-stans.h
popd
%endif
+%if %{bundle_jemalloc}
+pushd ../jemalloc-%{jemalloc_ver}
+%configure CFLAGS='%{optflags} -msse2' --libdir=%{_libdir}/%{pkgname}
+make %{?_smp_mflags}
+popd
+%endif
+
%if %{use_openldap}
OPENLDAP_FLAG="--with-openldap"
%endif
@@ -236,6 +262,12 @@ rm -rf $RPM_BUILD_ROOT%{_includedir} $RPM_BUILD_ROOT%{_datadir} \
popd
%endif
+%if %{bundle_jemalloc}
+pushd ../jemalloc-%{jemalloc_ver}
+cp --preserve=links lib/libjemalloc.so* $RPM_BUILD_ROOT%{_libdir}/%{pkgname}
+popd
+%endif
+
make DESTDIR="$RPM_BUILD_ROOT" install
mkdir -p $RPM_BUILD_ROOT/var/log/%{pkgname}
@@ -390,6 +422,9 @@ fi
%if %{use_nunc_stans}
%{_libdir}/%{pkgname}/libnunc-stans.so
%endif
+%if %{bundle_jemalloc}
+%{_libdir}/%{pkgname}/libjemalloc.so
+%endif
%{_libdir}/pkgconfig/*
%files libs
@@ -401,8 +436,14 @@ fi
%if %{use_nunc_stans}
%{_libdir}/%{pkgname}/libnunc-stans.so*
%endif
+%if %{bundle_jemalloc}
+%{_libdir}/%{pkgname}/libjemalloc.so*
+%endif
%changelog
+* Mon Dec 14 2015 Mark Reynolds <mreynolds(a)redhat.com> - 1.3.4.1-2
+- Ticket 48377 - Include the jemalloc library
+
* Tue Jun 23 2015 Noriko Hosoi <nhosoi(a)redhat.com> - 1.3.4.1-1
- Release 1.3.4.1-1
7 years, 11 months