ticket48906_test.py 14 KB

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