ticket48755_test.py 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. # --- BEGIN COPYRIGHT BLOCK ---
  2. # Copyright (C) 2016 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 shlex
  13. import subprocess
  14. import ldap
  15. import logging
  16. import pytest
  17. from lib389 import DirSrv, Entry, tools, tasks
  18. from lib389.tools import DirSrvTools
  19. from lib389._constants import *
  20. from lib389.properties import *
  21. from lib389.tasks import *
  22. from lib389.utils import *
  23. logging.getLogger(__name__).setLevel(logging.DEBUG)
  24. log = logging.getLogger(__name__)
  25. installation1_prefix = None
  26. m1_m2_agmt = None
  27. class TopologyReplication(object):
  28. def __init__(self, master1, master2):
  29. master1.open()
  30. self.master1 = master1
  31. master2.open()
  32. self.master2 = master2
  33. @pytest.fixture(scope="module")
  34. def topology(request):
  35. global installation1_prefix
  36. if installation1_prefix:
  37. args_instance[SER_DEPLOYED_DIR] = installation1_prefix
  38. # Creating master 1...
  39. master1 = DirSrv(verbose=False)
  40. if installation1_prefix:
  41. args_instance[SER_DEPLOYED_DIR] = installation1_prefix
  42. args_instance[SER_HOST] = HOST_MASTER_1
  43. args_instance[SER_PORT] = PORT_MASTER_1
  44. args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_1
  45. args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX
  46. args_master = args_instance.copy()
  47. master1.allocate(args_master)
  48. instance_master1 = master1.exists()
  49. if instance_master1:
  50. master1.delete()
  51. master1.create()
  52. master1.open()
  53. master1.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER_1)
  54. # Creating master 2...
  55. master2 = DirSrv(verbose=False)
  56. if installation1_prefix:
  57. args_instance[SER_DEPLOYED_DIR] = installation1_prefix
  58. args_instance[SER_HOST] = HOST_MASTER_2
  59. args_instance[SER_PORT] = PORT_MASTER_2
  60. args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_2
  61. args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX
  62. args_master = args_instance.copy()
  63. master2.allocate(args_master)
  64. instance_master2 = master2.exists()
  65. if instance_master2:
  66. master2.delete()
  67. master2.create()
  68. master2.open()
  69. master2.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER_2)
  70. #
  71. # Create all the agreements
  72. #
  73. # Creating agreement from master 1 to master 2
  74. properties = {RA_NAME: r'meTo_%s:%s' % (master2.host, master2.port),
  75. RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
  76. RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
  77. RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
  78. RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
  79. global m1_m2_agmt
  80. m1_m2_agmt = master1.agreement.create(suffix=SUFFIX, host=master2.host, port=master2.port, properties=properties)
  81. if not m1_m2_agmt:
  82. log.fatal("Fail to create a master -> master replica agreement")
  83. sys.exit(1)
  84. log.debug("%s created" % m1_m2_agmt)
  85. # Creating agreement from master 2 to master 1
  86. properties = {RA_NAME: r'meTo_%s:%s' % (master1.host, master1.port),
  87. RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
  88. RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
  89. RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
  90. RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
  91. m2_m1_agmt = master2.agreement.create(suffix=SUFFIX, host=master1.host, port=master1.port, properties=properties)
  92. if not m2_m1_agmt:
  93. log.fatal("Fail to create a master -> master replica agreement")
  94. sys.exit(1)
  95. log.debug("%s created" % m2_m1_agmt)
  96. # Allow the replicas to get situated with the new agreements...
  97. time.sleep(5)
  98. #
  99. # Initialize all the agreements
  100. #
  101. master1.agreement.init(SUFFIX, HOST_MASTER_2, PORT_MASTER_2)
  102. master1.waitForReplInit(m1_m2_agmt)
  103. # Check replication is working...
  104. if master1.testReplication(DEFAULT_SUFFIX, master2):
  105. log.info('Replication is working.')
  106. else:
  107. log.fatal('Replication is not working.')
  108. assert False
  109. # Delete each instance in the end
  110. def fin():
  111. master1.delete()
  112. master2.delete()
  113. request.addfinalizer(fin)
  114. return TopologyReplication(master1, master2)
  115. @pytest.fixture(scope="module")
  116. def add_ou_entry(server, idx, myparent):
  117. name = 'OU%d' % idx
  118. dn = 'ou=%s,%s' % (name, myparent)
  119. server.add_s(Entry((dn, {'objectclass': ['top', 'organizationalunit'],
  120. 'ou': name})))
  121. time.sleep(1)
  122. def add_user_entry(server, idx, myparent):
  123. name = 'tuser%d' % idx
  124. dn = 'uid=%s,%s' % (name, myparent)
  125. server.add_s(Entry((dn, {'objectclass': ['top', 'person', 'organizationalPerson', 'inetorgperson'],
  126. 'givenname': 'test',
  127. 'sn': 'user%d' % idx,
  128. 'cn': 'Test User%d' % idx,
  129. 'userpassword': 'password'})))
  130. time.sleep(1)
  131. def del_user_entry(server, idx, myparent):
  132. name = 'tuser%d' % idx
  133. dn = 'uid=%s,%s' % (name, myparent)
  134. server.delete_s(dn)
  135. time.sleep(1)
  136. def add_ldapsubentry(server, myparent):
  137. name = 'nsPwPolicyContainer'
  138. container = 'cn=%s,%s' % (name, myparent)
  139. server.add_s(Entry((container, {'objectclass': ['top', 'nsContainer'],
  140. 'cn': '%s' % name})))
  141. name = 'nsPwPolicyEntry'
  142. pwpentry = 'cn=%s,%s' % (name, myparent)
  143. pwpdn = 'cn="%s",%s' % (pwpentry, container)
  144. server.add_s(Entry((pwpdn, {'objectclass': ['top', 'ldapsubentry', 'passwordpolicy'],
  145. 'passwordStorageScheme': 'ssha',
  146. 'passwordCheckSyntax': 'on',
  147. 'passwordInHistory': '6',
  148. 'passwordChange': 'on',
  149. 'passwordMinAge': '0',
  150. 'passwordExp': 'off',
  151. 'passwordMustChange': 'off',
  152. 'cn': '%s' % pwpentry})))
  153. name = 'nsPwTemplateEntry'
  154. tmplentry = 'cn=%s,%s' % (name, myparent)
  155. tmpldn = 'cn="%s",%s' % (tmplentry, container)
  156. server.add_s(Entry((tmpldn, {'objectclass': ['top', 'ldapsubentry', 'costemplate', 'extensibleObject'],
  157. 'cosPriority': '1',
  158. 'cn': '%s' % tmplentry})))
  159. name = 'nsPwPolicy_CoS'
  160. cos = 'cn=%s,%s' % (name, myparent)
  161. server.add_s(Entry((cos, {'objectclass': ['top', 'ldapsubentry', 'cosPointerDefinition', 'cosSuperDefinition'],
  162. 'costemplatedn': '%s' % tmpldn,
  163. 'cosAttribute': 'pwdpolicysubentry default operational-default',
  164. 'cn': '%s' % name})))
  165. time.sleep(1)
  166. def test_ticket48755(topology):
  167. log.info("Ticket 48755 - moving an entry could make the online init fail")
  168. M1 = topology.master1
  169. M2 = topology.master2
  170. log.info("Generating DIT_0")
  171. idx = 0
  172. add_ou_entry(M1, idx, DEFAULT_SUFFIX)
  173. ou0 = 'ou=OU%d' % idx
  174. parent0 = '%s,%s' % (ou0, DEFAULT_SUFFIX)
  175. add_ou_entry(M1, idx, parent0)
  176. add_ldapsubentry(M1, parent0)
  177. parent00 = 'ou=OU%d,%s' % (idx, parent0)
  178. for idx in range(0, 9):
  179. add_user_entry(M1, idx, parent00)
  180. if idx % 2 == 0:
  181. log.info("Turning tuser%d into a tombstone entry" % idx)
  182. del_user_entry(M1, idx, parent00)
  183. log.info('%s => %s => %s => 10 USERS' % (DEFAULT_SUFFIX, parent0, parent00))
  184. log.info("Generating DIT_1")
  185. idx = 1
  186. add_ou_entry(M1, idx, DEFAULT_SUFFIX)
  187. parent1 = 'ou=OU%d,%s' % (idx, DEFAULT_SUFFIX)
  188. add_ou_entry(M1, idx, parent1)
  189. add_ldapsubentry(M1, parent1)
  190. log.info("Moving %s to DIT_1" % parent00)
  191. M1.rename_s(parent00, ou0, newsuperior=parent1, delold=1)
  192. time.sleep(1)
  193. log.info("Moving %s to DIT_1" % parent0)
  194. parent01 = '%s,%s' % (ou0, parent1)
  195. M1.rename_s(parent0, ou0, newsuperior=parent01, delold=1)
  196. time.sleep(1)
  197. parent001 = '%s,%s' % (ou0, parent01)
  198. log.info("Moving USERS to %s" % parent0)
  199. for idx in range(0, 9):
  200. if idx % 2 == 1:
  201. name = 'tuser%d' % idx
  202. rdn = 'uid=%s' % name
  203. dn = 'uid=%s,%s' % (name, parent01)
  204. M1.rename_s(dn, rdn, newsuperior=parent001, delold=1)
  205. time.sleep(1)
  206. log.info('%s => %s => %s => %s => 10 USERS' % (DEFAULT_SUFFIX, parent1, parent01, parent001))
  207. log.info("Run Consumer Initialization.")
  208. global m1_m2_agmt
  209. M1.startReplication_async(m1_m2_agmt)
  210. M1.waitForReplInit(m1_m2_agmt)
  211. time.sleep(2)
  212. m1entries = M1.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE,
  213. '(|(objectclass=ldapsubentry)(objectclass=nstombstone)(nsuniqueid=*))')
  214. m2entries = M2.search_s(DEFAULT_SUFFIX, ldap.SCOPE_SUBTREE,
  215. '(|(objectclass=ldapsubentry)(objectclass=nstombstone)(nsuniqueid=*))')
  216. log.info("m1entry count - %d", len(m1entries))
  217. log.info("m2entry count - %d", len(m2entries))
  218. assert len(m1entries) == len(m2entries)
  219. log.info('PASSED')
  220. if __name__ == '__main__':
  221. # Run isolated
  222. # -s for DEBUG mode
  223. CURRENT_FILE = os.path.realpath(__file__)
  224. pytest.main("-s %s" % CURRENT_FILE)