ticket48906_test.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. # --- BEGIN COPYRIGHT BLOCK ---
  2. # Copyright (C) 2015 Red Hat, Inc.
  3. # All rights reserved.
  4. #
  5. # License: GPL (version 3 or any later version).
  6. # See LICENSE for details.
  7. # --- END COPYRIGHT BLOCK ---
  8. #
  9. import os
  10. import sys
  11. import time
  12. import ldap
  13. import logging
  14. import pytest
  15. import shutil
  16. from lib389 import DirSrv, Entry, tools, tasks
  17. from lib389.tools import DirSrvTools
  18. from lib389._constants import *
  19. from lib389.properties import *
  20. from lib389.tasks import *
  21. from ldap.controls import SimplePagedResultsControl
  22. from ldap.controls.simple import GetEffectiveRightsControl
  23. import fnmatch
  24. log = logging.getLogger(__name__)
  25. CONFIG_DN = 'cn=config'
  26. RDN_VAL_SUFFIX = 'ticket48906.org'
  27. MYSUFFIX = 'dc=%s' % RDN_VAL_SUFFIX
  28. MYSUFFIXBE = 'ticket48906'
  29. SEARCHFILTER = '(objectclass=person)'
  30. OTHER_NAME = 'other_entry'
  31. MAX_OTHERS = 10
  32. DBLOCK_DEFAULT="10000"
  33. DBLOCK_LDAP_UPDATE="20000"
  34. DBLOCK_EDIT_UPDATE="40000"
  35. DBLOCK_MIN_UPDATE=DBLOCK_DEFAULT
  36. DBLOCK_ATTR_CONFIG="nsslapd-db-locks"
  37. DBLOCK_ATTR_MONITOR="nsslapd-db-configured-locks"
  38. DBLOCK_ATTR_GUARDIAN="locks"
  39. DBCACHE_DEFAULT="10000000"
  40. DBCACHE_LDAP_UPDATE="20000000"
  41. DBCACHE_EDIT_UPDATE="40000000"
  42. DBCACHE_ATTR_CONFIG="nsslapd-dbcachesize"
  43. DBCACHE_ATTR_GUARDIAN="cachesize"
  44. ldbm_config = "cn=config,%s" % (DN_LDBM)
  45. ldbm_monitor = "cn=database,cn=monitor,%s" % (DN_LDBM)
  46. class TopologyStandalone(object):
  47. def __init__(self, standalone):
  48. standalone.open()
  49. self.standalone = standalone
  50. @pytest.fixture(scope="module")
  51. def topology(request):
  52. '''
  53. This fixture is used to standalone topology for the 'module'.
  54. '''
  55. standalone = DirSrv(verbose=True)
  56. # Args for the standalone instance
  57. args_instance[SER_HOST] = HOST_STANDALONE
  58. args_instance[SER_PORT] = PORT_STANDALONE
  59. args_instance[SER_SERVERID_PROP] = SERVERID_STANDALONE
  60. args_standalone = args_instance.copy()
  61. standalone.allocate(args_standalone)
  62. # Get the status of the instance and restart it if it exists
  63. instance_standalone = standalone.exists()
  64. # Remove the instance
  65. if instance_standalone:
  66. standalone.delete()
  67. # Create the instance
  68. standalone.create()
  69. # Used to retrieve configuration information (dbdir, confdir...)
  70. standalone.open()
  71. # clear the tmp directory
  72. standalone.clearTmpDir(__file__)
  73. # Here we have standalone instance up and running
  74. return TopologyStandalone(standalone)
  75. def test_ticket48906_setup(topology):
  76. """
  77. Check there is no core
  78. Create a second backend
  79. stop DS (that should trigger the core)
  80. check there is no core
  81. """
  82. log.info('Testing Ticket 48906 - ns-slapd crashes during the shutdown after adding attribute with a matching rule')
  83. # bind as directory manager
  84. topology.standalone.log.info("Bind as %s" % DN_DM)
  85. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  86. # check there is no core
  87. entry = topology.standalone.search_s(CONFIG_DN, ldap.SCOPE_BASE, "(cn=config)",['nsslapd-workingdir'])
  88. assert entry
  89. assert entry[0]
  90. assert entry[0].hasAttr('nsslapd-workingdir')
  91. path = entry[0].getValue('nsslapd-workingdir')
  92. cores = fnmatch.filter(os.listdir(path), 'core.*')
  93. assert len(cores) == 0
  94. # add dummy entries on backend
  95. for cpt in range(MAX_OTHERS):
  96. name = "%s%d" % (OTHER_NAME, cpt)
  97. topology.standalone.add_s(Entry(("cn=%s,%s" % (name, SUFFIX), {
  98. 'objectclass': "top person".split(),
  99. 'sn': name,
  100. 'cn': name})))
  101. topology.standalone.log.info("\n\n######################### SEARCH ALL ######################\n")
  102. topology.standalone.log.info("Bind as %s and add the READ/SEARCH SELFDN aci" % DN_DM)
  103. topology.standalone.simple_bind_s(DN_DM, PASSWORD)
  104. entries = topology.standalone.search_s(SUFFIX, ldap.SCOPE_SUBTREE, SEARCHFILTER)
  105. topology.standalone.log.info("Returned %d entries.\n", len(entries))
  106. assert MAX_OTHERS == len(entries)
  107. topology.standalone.log.info('%d person entries are successfully created under %s.' % (len(entries), SUFFIX))
  108. def _check_configured_value(topology, attr=DBLOCK_ATTR_CONFIG, expected_value=None, required=False):
  109. entries = topology.standalone.search_s(ldbm_config, ldap.SCOPE_BASE, 'cn=config')
  110. if required:
  111. assert(entries[0].hasValue(attr))
  112. elif entries[0].hasValue(attr):
  113. assert(entries[0].getValue(attr) == expected_value)
  114. def _check_monitored_value(topology, expected_value):
  115. entries = topology.standalone.search_s(ldbm_monitor, ldap.SCOPE_BASE, '(objectclass=*)')
  116. assert(entries[0].hasValue(DBLOCK_ATTR_MONITOR) and entries[0].getValue(DBLOCK_ATTR_MONITOR) == expected_value)
  117. def _check_dse_ldif_value(topology, attr=DBLOCK_ATTR_CONFIG, expected_value=DBLOCK_LDAP_UPDATE):
  118. dse_ref_ldif = topology.standalone.confdir + '/dse.ldif'
  119. dse_ref = open(dse_ref_ldif, "r")
  120. # Check the DBLOCK in dse.ldif
  121. value=None
  122. while True:
  123. line = dse_ref.readline()
  124. if (line == ''):
  125. break
  126. elif attr in line.lower():
  127. value = line.split()[1]
  128. assert(value == expected_value)
  129. break
  130. assert(value)
  131. def _check_guardian_value(topology, attr=DBLOCK_ATTR_CONFIG, expected_value=None):
  132. guardian_file = topology.standalone.dbdir + '/db/guardian'
  133. assert(os.path.exists(guardian_file))
  134. guardian = open(guardian_file, "r")
  135. value=None
  136. while True:
  137. line = guardian.readline()
  138. if (line == ''):
  139. break
  140. elif attr in line.lower():
  141. value = line.split(':')[1].replace("\n", "")
  142. print "line"
  143. print line
  144. print "expected_value"
  145. print expected_value
  146. print "value"
  147. print value
  148. assert(str(value) == str(expected_value))
  149. break
  150. assert(value)
  151. def test_ticket48906_dblock_default(topology):
  152. topology.standalone.log.info('###################################')
  153. topology.standalone.log.info('###')
  154. topology.standalone.log.info('### Check that before any change config/monitor')
  155. topology.standalone.log.info('### contains the default value')
  156. topology.standalone.log.info('###')
  157. topology.standalone.log.info('###################################')
  158. _check_monitored_value(topology, DBLOCK_DEFAULT)
  159. _check_configured_value(topology, attr=DBLOCK_ATTR_CONFIG, expected_value=DBLOCK_DEFAULT, required=False)
  160. _check_configured_value(topology, attr=DBCACHE_ATTR_CONFIG, expected_value=DBCACHE_DEFAULT, required=False)
  161. def test_ticket48906_dblock_ldap_update(topology):
  162. topology.standalone.log.info('###################################')
  163. topology.standalone.log.info('###')
  164. topology.standalone.log.info('### Check that after ldap update')
  165. topology.standalone.log.info('### - monitor contains DEFAULT')
  166. topology.standalone.log.info('### - configured contains DBLOCK_LDAP_UPDATE')
  167. topology.standalone.log.info('### - After stop dse.ldif contains DBLOCK_LDAP_UPDATE')
  168. topology.standalone.log.info('### - After stop guardian contains DEFAULT')
  169. topology.standalone.log.info('### In fact guardian should differ from config to recreate the env')
  170. topology.standalone.log.info('### Check that after restart (DBenv recreated)')
  171. topology.standalone.log.info('### - monitor contains DBLOCK_LDAP_UPDATE ')
  172. topology.standalone.log.info('### - configured contains DBLOCK_LDAP_UPDATE')
  173. topology.standalone.log.info('### - dse.ldif contains DBLOCK_LDAP_UPDATE')
  174. topology.standalone.log.info('###')
  175. topology.standalone.log.info('###################################')
  176. topology.standalone.modify_s(ldbm_config, [(ldap.MOD_REPLACE, DBLOCK_ATTR_CONFIG, DBLOCK_LDAP_UPDATE)])
  177. _check_monitored_value(topology, DBLOCK_DEFAULT)
  178. _check_configured_value(topology, attr=DBLOCK_ATTR_CONFIG, expected_value=DBLOCK_LDAP_UPDATE, required=True)
  179. topology.standalone.stop(timeout=10)
  180. _check_dse_ldif_value(topology, attr=DBLOCK_ATTR_CONFIG, expected_value=DBLOCK_LDAP_UPDATE)
  181. _check_guardian_value(topology, attr=DBLOCK_ATTR_GUARDIAN, expected_value=DBLOCK_DEFAULT)
  182. # Check that the value is the same after restart and recreate
  183. topology.standalone.start(timeout=10)
  184. _check_monitored_value(topology, DBLOCK_LDAP_UPDATE)
  185. _check_configured_value(topology, attr=DBLOCK_ATTR_CONFIG, expected_value=DBLOCK_LDAP_UPDATE, required=True)
  186. _check_dse_ldif_value(topology, attr=DBLOCK_ATTR_CONFIG, expected_value=DBLOCK_LDAP_UPDATE)
  187. def test_ticket48906_dblock_edit_update(topology):
  188. topology.standalone.log.info('###################################')
  189. topology.standalone.log.info('###')
  190. topology.standalone.log.info('### Check that after stop')
  191. topology.standalone.log.info('### - dse.ldif contains DBLOCK_LDAP_UPDATE')
  192. topology.standalone.log.info('### - guardian contains DBLOCK_LDAP_UPDATE')
  193. topology.standalone.log.info('### Check that edit dse+restart')
  194. topology.standalone.log.info('### - monitor contains DBLOCK_EDIT_UPDATE')
  195. topology.standalone.log.info('### - configured contains DBLOCK_EDIT_UPDATE')
  196. topology.standalone.log.info('### Check that after stop')
  197. topology.standalone.log.info('### - dse.ldif contains DBLOCK_EDIT_UPDATE')
  198. topology.standalone.log.info('### - guardian contains DBLOCK_EDIT_UPDATE')
  199. topology.standalone.log.info('###')
  200. topology.standalone.log.info('###################################')
  201. topology.standalone.stop(timeout=10)
  202. _check_dse_ldif_value(topology, attr=DBLOCK_ATTR_CONFIG, expected_value=DBLOCK_LDAP_UPDATE)
  203. _check_guardian_value(topology, attr=DBLOCK_ATTR_GUARDIAN, expected_value=DBLOCK_LDAP_UPDATE)
  204. dse_ref_ldif = topology.standalone.confdir + '/dse.ldif'
  205. dse_new_ldif = topology.standalone.confdir + '/dse.ldif.new'
  206. dse_ref = open(dse_ref_ldif, "r")
  207. dse_new = open(dse_new_ldif, "w")
  208. # Change the DBLOCK in dse.ldif
  209. value=None
  210. while True:
  211. line = dse_ref.readline()
  212. if (line == ''):
  213. break
  214. elif DBLOCK_ATTR_CONFIG in line.lower():
  215. value = line.split()[1]
  216. assert(value == DBLOCK_LDAP_UPDATE)
  217. new_value = [line.split()[0], DBLOCK_EDIT_UPDATE, ]
  218. new_line = "%s\n" % " ".join(new_value)
  219. else:
  220. new_line = line
  221. dse_new.write(new_line)
  222. assert(value)
  223. dse_ref.close()
  224. dse_new.close()
  225. shutil.move(dse_new_ldif, dse_ref_ldif)
  226. # Check that the value is the same after restart
  227. topology.standalone.start(timeout=10)
  228. _check_monitored_value(topology, DBLOCK_EDIT_UPDATE)
  229. _check_configured_value(topology, attr=DBLOCK_ATTR_CONFIG, expected_value=DBLOCK_EDIT_UPDATE, required=True)
  230. topology.standalone.stop(timeout=10)
  231. _check_dse_ldif_value(topology, attr=DBLOCK_ATTR_CONFIG, expected_value=DBLOCK_EDIT_UPDATE)
  232. _check_guardian_value(topology, attr=DBLOCK_ATTR_GUARDIAN, expected_value=DBLOCK_EDIT_UPDATE)
  233. def test_ticket48906_dblock_robust(topology):
  234. topology.standalone.log.info('###################################')
  235. topology.standalone.log.info('###')
  236. topology.standalone.log.info('### Check that the following values are rejected')
  237. topology.standalone.log.info('### - negative value')
  238. topology.standalone.log.info('### - insuffisant value')
  239. topology.standalone.log.info('### - invalid value')
  240. topology.standalone.log.info('### Check that minimum value is accepted')
  241. topology.standalone.log.info('###')
  242. topology.standalone.log.info('###################################')
  243. topology.standalone.start(timeout=10)
  244. _check_monitored_value(topology, DBLOCK_EDIT_UPDATE)
  245. _check_configured_value(topology, attr=DBLOCK_ATTR_CONFIG, expected_value=DBLOCK_EDIT_UPDATE, required=True)
  246. # Check negative value
  247. try:
  248. topology.standalone.modify_s(ldbm_config, [(ldap.MOD_REPLACE, DBLOCK_ATTR_CONFIG, "-1")])
  249. except ldap.UNWILLING_TO_PERFORM:
  250. pass
  251. _check_monitored_value(topology, DBLOCK_EDIT_UPDATE)
  252. _check_configured_value(topology, attr=DBLOCK_ATTR_CONFIG, expected_value=DBLOCK_LDAP_UPDATE, required=True)
  253. # Check insuffisant value
  254. too_small = int(DBLOCK_MIN_UPDATE) - 1
  255. try:
  256. topology.standalone.modify_s(ldbm_config, [(ldap.MOD_REPLACE, DBLOCK_ATTR_CONFIG, str(too_small))])
  257. except ldap.UNWILLING_TO_PERFORM:
  258. pass
  259. _check_monitored_value(topology, DBLOCK_EDIT_UPDATE)
  260. _check_configured_value(topology, attr=DBLOCK_ATTR_CONFIG, expected_value=DBLOCK_LDAP_UPDATE, required=True)
  261. # Check invalid value
  262. try:
  263. topology.standalone.modify_s(ldbm_config, [(ldap.MOD_REPLACE, DBLOCK_ATTR_CONFIG, "dummy")])
  264. except ldap.UNWILLING_TO_PERFORM:
  265. pass
  266. _check_monitored_value(topology, DBLOCK_EDIT_UPDATE)
  267. _check_configured_value(topology, attr=DBLOCK_ATTR_CONFIG, expected_value=DBLOCK_LDAP_UPDATE, required=True)
  268. #now check the minimal value
  269. topology.standalone.modify_s(ldbm_config, [(ldap.MOD_REPLACE, DBLOCK_ATTR_CONFIG, DBLOCK_MIN_UPDATE)])
  270. _check_monitored_value(topology, DBLOCK_EDIT_UPDATE)
  271. _check_configured_value(topology, attr=DBLOCK_ATTR_CONFIG, expected_value=DBLOCK_MIN_UPDATE, required=True)
  272. topology.standalone.stop(timeout=10)
  273. _check_dse_ldif_value(topology, attr=DBLOCK_ATTR_CONFIG, expected_value=DBLOCK_MIN_UPDATE)
  274. _check_guardian_value(topology, attr=DBLOCK_ATTR_GUARDIAN, expected_value=DBLOCK_EDIT_UPDATE)
  275. topology.standalone.start(timeout=10)
  276. _check_monitored_value(topology, DBLOCK_MIN_UPDATE)
  277. _check_configured_value(topology, attr=DBLOCK_ATTR_CONFIG, expected_value=DBLOCK_MIN_UPDATE, required=True)
  278. def text_ticket48906_final(topology):
  279. topology.standalone.delete()
  280. log.info('Testcase PASSED')
  281. def run_isolated():
  282. '''
  283. run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
  284. To run isolated without py.test, you need to
  285. - edit this file and comment '@pytest.fixture' line before 'topology' function.
  286. - set the installation prefix
  287. - run this program
  288. '''
  289. topo = topology(True)
  290. test_ticket48906_setup(topo)
  291. test_ticket48906_dblock_default(topo)
  292. test_ticket48906_dblock_ldap_update(topo)
  293. test_ticket48906_dblock_edit_update(topo)
  294. test_ticket48906_dblock_robust(topo)
  295. test_ticket48906_final(topo)
  296. if __name__ == '__main__':
  297. run_isolated()