1
0

ticket47869MMR_test.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. import os
  2. import sys
  3. import time
  4. import ldap
  5. import logging
  6. import socket
  7. import time
  8. import logging
  9. import pytest
  10. import re
  11. from lib389 import DirSrv, Entry, tools
  12. from lib389.tools import DirSrvTools
  13. from lib389._constants import *
  14. from lib389.properties import *
  15. from constants import *
  16. from lib389._constants import *
  17. logging.getLogger(__name__).setLevel(logging.DEBUG)
  18. log = logging.getLogger(__name__)
  19. #
  20. # important part. We can deploy Master1 and Master2 on different versions
  21. #
  22. installation1_prefix = None
  23. installation2_prefix = None
  24. TEST_REPL_DN = "cn=test_repl, %s" % SUFFIX
  25. ENTRY_NAME = 'test_entry'
  26. MAX_ENTRIES = 10
  27. BIND_NAME = 'bind_entry'
  28. BIND_DN = 'cn=%s, %s' % (BIND_NAME, SUFFIX)
  29. BIND_PW = 'password'
  30. class TopologyMaster1Master2(object):
  31. def __init__(self, master1, master2):
  32. master1.open()
  33. self.master1 = master1
  34. master2.open()
  35. self.master2 = master2
  36. @pytest.fixture(scope="module")
  37. def topology(request):
  38. '''
  39. This fixture is used to create a replicated topology for the 'module'.
  40. The replicated topology is MASTER1 <-> Master2.
  41. At the beginning, It may exists a master2 instance and/or a master2 instance.
  42. It may also exists a backup for the master1 and/or the master2.
  43. Principle:
  44. If master1 instance exists:
  45. restart it
  46. If master2 instance exists:
  47. restart it
  48. If backup of master1 AND backup of master2 exists:
  49. create or rebind to master1
  50. create or rebind to master2
  51. restore master1 from backup
  52. restore master2 from backup
  53. else:
  54. Cleanup everything
  55. remove instances
  56. remove backups
  57. Create instances
  58. Initialize replication
  59. Create backups
  60. '''
  61. global installation1_prefix
  62. global installation2_prefix
  63. # allocate master1 on a given deployement
  64. master1 = DirSrv(verbose=False)
  65. if installation1_prefix:
  66. args_instance[SER_DEPLOYED_DIR] = installation1_prefix
  67. # Args for the master1 instance
  68. args_instance[SER_HOST] = HOST_MASTER_1
  69. args_instance[SER_PORT] = PORT_MASTER_1
  70. args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_1
  71. args_master = args_instance.copy()
  72. master1.allocate(args_master)
  73. # allocate master1 on a given deployement
  74. master2 = DirSrv(verbose=False)
  75. if installation2_prefix:
  76. args_instance[SER_DEPLOYED_DIR] = installation2_prefix
  77. # Args for the consumer instance
  78. args_instance[SER_HOST] = HOST_MASTER_2
  79. args_instance[SER_PORT] = PORT_MASTER_2
  80. args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_2
  81. args_master = args_instance.copy()
  82. master2.allocate(args_master)
  83. # Get the status of the backups
  84. backup_master1 = master1.checkBackupFS()
  85. backup_master2 = master2.checkBackupFS()
  86. # Get the status of the instance and restart it if it exists
  87. instance_master1 = master1.exists()
  88. if instance_master1:
  89. master1.stop(timeout=10)
  90. master1.start(timeout=10)
  91. instance_master2 = master2.exists()
  92. if instance_master2:
  93. master2.stop(timeout=10)
  94. master2.start(timeout=10)
  95. if backup_master1 and backup_master2:
  96. # The backups exist, assuming they are correct
  97. # we just re-init the instances with them
  98. if not instance_master1:
  99. master1.create()
  100. # Used to retrieve configuration information (dbdir, confdir...)
  101. master1.open()
  102. if not instance_master2:
  103. master2.create()
  104. # Used to retrieve configuration information (dbdir, confdir...)
  105. master2.open()
  106. # restore master1 from backup
  107. master1.stop(timeout=10)
  108. master1.restoreFS(backup_master1)
  109. master1.start(timeout=10)
  110. # restore master2 from backup
  111. master2.stop(timeout=10)
  112. master2.restoreFS(backup_master2)
  113. master2.start(timeout=10)
  114. else:
  115. # We should be here only in two conditions
  116. # - This is the first time a test involve master-consumer
  117. # so we need to create everything
  118. # - Something weird happened (instance/backup destroyed)
  119. # so we discard everything and recreate all
  120. # Remove all the backups. So even if we have a specific backup file
  121. # (e.g backup_master) we clear all backups that an instance my have created
  122. if backup_master1:
  123. master1.clearBackupFS()
  124. if backup_master2:
  125. master2.clearBackupFS()
  126. # Remove all the instances
  127. if instance_master1:
  128. master1.delete()
  129. if instance_master2:
  130. master2.delete()
  131. # Create the instances
  132. master1.create()
  133. master1.open()
  134. master2.create()
  135. master2.open()
  136. #
  137. # Now prepare the Master-Consumer topology
  138. #
  139. # First Enable replication
  140. master1.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER_1)
  141. master2.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER_2)
  142. # Initialize the supplier->consumer
  143. properties = {RA_NAME: r'meTo_$host:$port',
  144. RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
  145. RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
  146. RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
  147. RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
  148. repl_agreement = master1.agreement.create(suffix=SUFFIX, host=master2.host, port=master2.port, properties=properties)
  149. if not repl_agreement:
  150. log.fatal("Fail to create a replica agreement")
  151. sys.exit(1)
  152. log.debug("%s created" % repl_agreement)
  153. properties = {RA_NAME: r'meTo_$host:$port',
  154. RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
  155. RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
  156. RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
  157. RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
  158. master2.agreement.create(suffix=SUFFIX, host=master1.host, port=master1.port, properties=properties)
  159. master1.agreement.init(SUFFIX, HOST_MASTER_2, PORT_MASTER_2)
  160. master1.waitForReplInit(repl_agreement)
  161. # Check replication is working fine
  162. master1.add_s(Entry((TEST_REPL_DN, {'objectclass': "top person".split(),
  163. 'sn': 'test_repl',
  164. 'cn': 'test_repl'})))
  165. loop = 0
  166. ent = None
  167. while loop <= 10:
  168. try:
  169. ent = master2.getEntry(TEST_REPL_DN, ldap.SCOPE_BASE, "(objectclass=*)")
  170. break
  171. except ldap.NO_SUCH_OBJECT:
  172. time.sleep(1)
  173. loop += 1
  174. if ent is None:
  175. assert False
  176. # Time to create the backups
  177. master1.stop(timeout=10)
  178. master1.backupfile = master1.backupFS()
  179. master1.start(timeout=10)
  180. master2.stop(timeout=10)
  181. master2.backupfile = master2.backupFS()
  182. master2.start(timeout=10)
  183. # clear the tmp directory
  184. master1.clearTmpDir(__file__)
  185. #
  186. # Here we have two instances master and consumer
  187. # with replication working. Either coming from a backup recovery
  188. # or from a fresh (re)init
  189. # Time to return the topology
  190. return TopologyMaster1Master2(master1, master2)
  191. def test_ticket47869_init(topology):
  192. """
  193. It adds an entry ('bind_entry') and 10 test entries
  194. It sets the anonymous aci
  195. """
  196. # enable acl error logging
  197. mod = [(ldap.MOD_REPLACE, 'nsslapd-errorlog-level', str(8192))] # REPL
  198. topology.master1.modify_s(DN_CONFIG, mod)
  199. topology.master2.modify_s(DN_CONFIG, mod)
  200. # entry used to bind with
  201. topology.master1.log.info("Add %s" % BIND_DN)
  202. topology.master1.add_s(Entry((BIND_DN, {
  203. 'objectclass': "top person".split(),
  204. 'sn': BIND_NAME,
  205. 'cn': BIND_NAME,
  206. 'userpassword': BIND_PW})))
  207. loop = 0
  208. ent = None
  209. while loop <= 10:
  210. try:
  211. ent = topology.master2.getEntry(BIND_DN, ldap.SCOPE_BASE, "(objectclass=*)")
  212. break
  213. except ldap.NO_SUCH_OBJECT:
  214. time.sleep(1)
  215. loop += 1
  216. if ent is None:
  217. assert False
  218. # keep anonymous ACI for use 'read-search' aci in SEARCH test
  219. ACI_ANONYMOUS = "(targetattr!=\"userPassword\")(version 3.0; acl \"Enable anonymous access\"; allow (read, search, compare) userdn=\"ldap:///anyone\";)"
  220. mod = [(ldap.MOD_REPLACE, 'aci', ACI_ANONYMOUS)]
  221. topology.master1.modify_s(SUFFIX, mod)
  222. topology.master2.modify_s(SUFFIX, mod)
  223. # add entries
  224. for cpt in range(MAX_ENTRIES):
  225. name = "%s%d" % (ENTRY_NAME, cpt)
  226. mydn = "cn=%s,%s" % (name, SUFFIX)
  227. topology.master1.add_s(Entry((mydn,
  228. {'objectclass': "top person".split(),
  229. 'sn': name,
  230. 'cn': name})))
  231. loop = 0
  232. ent = None
  233. while loop <= 10:
  234. try:
  235. ent = topology.master2.getEntry(mydn, ldap.SCOPE_BASE, "(objectclass=*)")
  236. break
  237. except ldap.NO_SUCH_OBJECT:
  238. time.sleep(1)
  239. loop += 1
  240. if ent is None:
  241. assert False
  242. def test_ticket47869_check(topology):
  243. '''
  244. On Master 1 and 2:
  245. Bind as Directory Manager.
  246. Search all specifying nscpEntryWsi in the attribute list.
  247. Check nscpEntryWsi is returned.
  248. On Master 1 and 2:
  249. Bind as Bind Entry.
  250. Search all specifying nscpEntryWsi in the attribute list.
  251. Check nscpEntryWsi is not returned.
  252. On Master 1 and 2:
  253. Bind as anonymous.
  254. Search all specifying nscpEntryWsi in the attribute list.
  255. Check nscpEntryWsi is not returned.
  256. '''
  257. topology.master1.log.info("\n\n######################### CHECK nscpentrywsi ######################\n")
  258. topology.master1.log.info("##### Master1: Bind as %s #####" % DN_DM)
  259. topology.master1.simple_bind_s(DN_DM, PASSWORD)
  260. topology.master1.log.info("Master1: Calling search_ext...")
  261. msgid = topology.master1.search_ext(SUFFIX, ldap.SCOPE_SUBTREE, 'objectclass=*', ['nscpentrywsi'])
  262. nscpentrywsicnt = 0
  263. rtype, rdata, rmsgid = topology.master1.result2(msgid)
  264. topology.master1.log.info("%d results" % len(rdata))
  265. topology.master1.log.info("Results:")
  266. for dn, attrs in rdata:
  267. topology.master1.log.info("dn: %s" % dn)
  268. if 'nscpentrywsi' in attrs:
  269. nscpentrywsicnt += 1
  270. topology.master1.log.info("Master1: count of nscpentrywsi: %d" % nscpentrywsicnt)
  271. topology.master2.log.info("##### Master2: Bind as %s #####" % DN_DM)
  272. topology.master2.simple_bind_s(DN_DM, PASSWORD)
  273. topology.master2.log.info("Master2: Calling search_ext...")
  274. msgid = topology.master2.search_ext(SUFFIX, ldap.SCOPE_SUBTREE, 'objectclass=*', ['nscpentrywsi'])
  275. nscpentrywsicnt = 0
  276. rtype, rdata, rmsgid = topology.master2.result2(msgid)
  277. topology.master2.log.info("%d results" % len(rdata))
  278. topology.master2.log.info("Results:")
  279. for dn, attrs in rdata:
  280. topology.master2.log.info("dn: %s" % dn)
  281. if 'nscpentrywsi' in attrs:
  282. nscpentrywsicnt += 1
  283. topology.master2.log.info("Master2: count of nscpentrywsi: %d" % nscpentrywsicnt)
  284. # bind as bind_entry
  285. topology.master1.log.info("##### Master1: Bind as %s #####" % BIND_DN)
  286. topology.master1.simple_bind_s(BIND_DN, BIND_PW)
  287. topology.master1.log.info("Master1: Calling search_ext...")
  288. msgid = topology.master1.search_ext(SUFFIX, ldap.SCOPE_SUBTREE, 'objectclass=*', ['nscpentrywsi'])
  289. nscpentrywsicnt = 0
  290. rtype, rdata, rmsgid = topology.master1.result2(msgid)
  291. topology.master1.log.info("%d results" % len(rdata))
  292. for dn, attrs in rdata:
  293. if 'nscpentrywsi' in attrs:
  294. nscpentrywsicnt += 1
  295. assert nscpentrywsicnt == 0
  296. topology.master1.log.info("Master1: count of nscpentrywsi: %d" % nscpentrywsicnt)
  297. # bind as bind_entry
  298. topology.master2.log.info("##### Master2: Bind as %s #####" % BIND_DN)
  299. topology.master2.simple_bind_s(BIND_DN, BIND_PW)
  300. topology.master2.log.info("Master2: Calling search_ext...")
  301. msgid = topology.master2.search_ext(SUFFIX, ldap.SCOPE_SUBTREE, 'objectclass=*', ['nscpentrywsi'])
  302. nscpentrywsicnt = 0
  303. rtype, rdata, rmsgid = topology.master2.result2(msgid)
  304. topology.master2.log.info("%d results" % len(rdata))
  305. for dn, attrs in rdata:
  306. if 'nscpentrywsi' in attrs:
  307. nscpentrywsicnt += 1
  308. assert nscpentrywsicnt == 0
  309. topology.master2.log.info("Master2: count of nscpentrywsi: %d" % nscpentrywsicnt)
  310. # bind as anonymous
  311. topology.master1.log.info("##### Master1: Bind as anonymous #####")
  312. topology.master1.simple_bind_s("", "")
  313. topology.master1.log.info("Master1: Calling search_ext...")
  314. msgid = topology.master1.search_ext(SUFFIX, ldap.SCOPE_SUBTREE, 'objectclass=*', ['nscpentrywsi'])
  315. nscpentrywsicnt = 0
  316. rtype, rdata, rmsgid = topology.master1.result2(msgid)
  317. topology.master1.log.info("%d results" % len(rdata))
  318. for dn, attrs in rdata:
  319. if 'nscpentrywsi' in attrs:
  320. nscpentrywsicnt += 1
  321. assert nscpentrywsicnt == 0
  322. topology.master1.log.info("Master1: count of nscpentrywsi: %d" % nscpentrywsicnt)
  323. # bind as bind_entry
  324. topology.master2.log.info("##### Master2: Bind as anonymous #####")
  325. topology.master2.simple_bind_s("", "")
  326. topology.master2.log.info("Master2: Calling search_ext...")
  327. msgid = topology.master2.search_ext(SUFFIX, ldap.SCOPE_SUBTREE, 'objectclass=*', ['nscpentrywsi'])
  328. nscpentrywsicnt = 0
  329. rtype, rdata, rmsgid = topology.master2.result2(msgid)
  330. topology.master2.log.info("%d results" % len(rdata))
  331. for dn, attrs in rdata:
  332. if 'nscpentrywsi' in attrs:
  333. nscpentrywsicnt += 1
  334. assert nscpentrywsicnt == 0
  335. topology.master2.log.info("Master2: count of nscpentrywsi: %d" % nscpentrywsicnt)
  336. topology.master1.log.info("##### ticket47869 was successfully verified. #####")
  337. def test_ticket47869_final(topology):
  338. topology.master1.delete()
  339. topology.master2.delete()
  340. def run_isolated():
  341. '''
  342. run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
  343. To run isolated without py.test, you need to
  344. - edit this file and comment '@pytest.fixture' line before 'topology' function.
  345. - set the installation prefix
  346. - run this program
  347. '''
  348. global installation1_prefix
  349. global installation2_prefix
  350. installation1_prefix = None
  351. installation2_prefix = None
  352. topo = topology(True)
  353. test_ticket47869_init(topo)
  354. test_ticket47869_check(topo)
  355. test_ticket47869_final(topo)
  356. if __name__ == '__main__':
  357. run_isolated()