ticket47553_ger.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. '''
  2. Created on Nov 7, 2013
  3. @author: tbordaz
  4. '''
  5. import os
  6. import sys
  7. import time
  8. import ldap
  9. import logging
  10. import socket
  11. import time
  12. import logging
  13. import pytest
  14. import re
  15. from lib389 import DirSrv, Entry, tools
  16. from lib389.tools import DirSrvTools
  17. from lib389._constants import *
  18. from lib389.properties import *
  19. from constants import *
  20. from lib389._constants import REPLICAROLE_MASTER
  21. from ldap.controls.simple import GetEffectiveRightsControl
  22. logging.getLogger(__name__).setLevel(logging.DEBUG)
  23. log = logging.getLogger(__name__)
  24. #
  25. # important part. We can deploy Master1 and Master2 on different versions
  26. #
  27. installation1_prefix = None
  28. installation2_prefix = None
  29. TEST_REPL_DN = "cn=test_repl, %s" % SUFFIX
  30. STAGING_CN = "staged user"
  31. PRODUCTION_CN = "accounts"
  32. EXCEPT_CN = "excepts"
  33. STAGING_DN = "cn=%s,%s" % (STAGING_CN, SUFFIX)
  34. PRODUCTION_DN = "cn=%s,%s" % (PRODUCTION_CN, SUFFIX)
  35. PROD_EXCEPT_DN = "cn=%s,%s" % (EXCEPT_CN, PRODUCTION_DN)
  36. STAGING_PATTERN = "cn=%s*,%s" % (STAGING_CN[:2], SUFFIX)
  37. PRODUCTION_PATTERN = "cn=%s*,%s" % (PRODUCTION_CN[:2], SUFFIX)
  38. BAD_STAGING_PATTERN = "cn=bad*,%s" % (SUFFIX)
  39. BAD_PRODUCTION_PATTERN = "cn=bad*,%s" % (SUFFIX)
  40. BIND_CN = "bind_entry"
  41. BIND_DN = "cn=%s,%s" % (BIND_CN, SUFFIX)
  42. BIND_PW = "password"
  43. NEW_ACCOUNT = "new_account"
  44. MAX_ACCOUNTS = 20
  45. CONFIG_MODDN_ACI_ATTR = "nsslapd-moddn-aci"
  46. class TopologyMaster1Master2(object):
  47. def __init__(self, master1, master2):
  48. master1.open()
  49. self.master1 = master1
  50. master2.open()
  51. self.master2 = master2
  52. @pytest.fixture(scope="module")
  53. def topology(request):
  54. '''
  55. This fixture is used to create a replicated topology for the 'module'.
  56. The replicated topology is MASTER1 <-> Master2.
  57. At the beginning, It may exists a master2 instance and/or a master2 instance.
  58. It may also exists a backup for the master1 and/or the master2.
  59. Principle:
  60. If master1 instance exists:
  61. restart it
  62. If master2 instance exists:
  63. restart it
  64. If backup of master1 AND backup of master2 exists:
  65. create or rebind to master1
  66. create or rebind to master2
  67. restore master1 from backup
  68. restore master2 from backup
  69. else:
  70. Cleanup everything
  71. remove instances
  72. remove backups
  73. Create instances
  74. Initialize replication
  75. Create backups
  76. '''
  77. global installation1_prefix
  78. global installation2_prefix
  79. # allocate master1 on a given deployement
  80. master1 = DirSrv(verbose=False)
  81. if installation1_prefix:
  82. args_instance[SER_DEPLOYED_DIR] = installation1_prefix
  83. # Args for the master1 instance
  84. args_instance[SER_HOST] = HOST_MASTER_1
  85. args_instance[SER_PORT] = PORT_MASTER_1
  86. args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_1
  87. args_master = args_instance.copy()
  88. master1.allocate(args_master)
  89. # allocate master1 on a given deployement
  90. master2 = DirSrv(verbose=False)
  91. if installation2_prefix:
  92. args_instance[SER_DEPLOYED_DIR] = installation2_prefix
  93. # Args for the consumer instance
  94. args_instance[SER_HOST] = HOST_MASTER_2
  95. args_instance[SER_PORT] = PORT_MASTER_2
  96. args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_2
  97. args_master = args_instance.copy()
  98. master2.allocate(args_master)
  99. # Get the status of the backups
  100. backup_master1 = master1.checkBackupFS()
  101. backup_master2 = master2.checkBackupFS()
  102. # Get the status of the instance and restart it if it exists
  103. instance_master1 = master1.exists()
  104. if instance_master1:
  105. master1.stop(timeout=10)
  106. master1.start(timeout=10)
  107. instance_master2 = master2.exists()
  108. if instance_master2:
  109. master2.stop(timeout=10)
  110. master2.start(timeout=10)
  111. if backup_master1 and backup_master2:
  112. # The backups exist, assuming they are correct
  113. # we just re-init the instances with them
  114. if not instance_master1:
  115. master1.create()
  116. # Used to retrieve configuration information (dbdir, confdir...)
  117. master1.open()
  118. if not instance_master2:
  119. master2.create()
  120. # Used to retrieve configuration information (dbdir, confdir...)
  121. master2.open()
  122. # restore master1 from backup
  123. master1.stop(timeout=10)
  124. master1.restoreFS(backup_master1)
  125. master1.start(timeout=10)
  126. # restore master2 from backup
  127. master2.stop(timeout=10)
  128. master2.restoreFS(backup_master2)
  129. master2.start(timeout=10)
  130. else:
  131. # We should be here only in two conditions
  132. # - This is the first time a test involve master-consumer
  133. # so we need to create everything
  134. # - Something weird happened (instance/backup destroyed)
  135. # so we discard everything and recreate all
  136. # Remove all the backups. So even if we have a specific backup file
  137. # (e.g backup_master) we clear all backups that an instance my have created
  138. if backup_master1:
  139. master1.clearBackupFS()
  140. if backup_master2:
  141. master2.clearBackupFS()
  142. # Remove all the instances
  143. if instance_master1:
  144. master1.delete()
  145. if instance_master2:
  146. master2.delete()
  147. # Create the instances
  148. master1.create()
  149. master1.open()
  150. master2.create()
  151. master2.open()
  152. #
  153. # Now prepare the Master-Consumer topology
  154. #
  155. # First Enable replication
  156. master1.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER_1)
  157. master2.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER_2)
  158. # Initialize the supplier->consumer
  159. properties = {RA_NAME: r'meTo_$host:$port',
  160. RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
  161. RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
  162. RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
  163. RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
  164. repl_agreement = master1.agreement.create(suffix=SUFFIX, host=master2.host, port=master2.port, properties=properties)
  165. if not repl_agreement:
  166. log.fatal("Fail to create a replica agreement")
  167. sys.exit(1)
  168. log.debug("%s created" % repl_agreement)
  169. properties = {RA_NAME: r'meTo_$host:$port',
  170. RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
  171. RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
  172. RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
  173. RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
  174. master2.agreement.create(suffix=SUFFIX, host=master1.host, port=master1.port, properties=properties)
  175. master1.agreement.init(SUFFIX, HOST_MASTER_2, PORT_MASTER_2)
  176. master1.waitForReplInit(repl_agreement)
  177. # Check replication is working fine
  178. master1.add_s(Entry((TEST_REPL_DN, {
  179. 'objectclass': "top person".split(),
  180. 'sn': 'test_repl',
  181. 'cn': 'test_repl'})))
  182. loop = 0
  183. while loop <= 10:
  184. try:
  185. ent = master2.getEntry(TEST_REPL_DN, ldap.SCOPE_BASE, "(objectclass=*)")
  186. break
  187. except ldap.NO_SUCH_OBJECT:
  188. time.sleep(1)
  189. loop += 1
  190. # Time to create the backups
  191. master1.stop(timeout=10)
  192. master1.backupfile = master1.backupFS()
  193. master1.start(timeout=10)
  194. master2.stop(timeout=10)
  195. master2.backupfile = master2.backupFS()
  196. master2.start(timeout=10)
  197. # clear the tmp directory
  198. master1.clearTmpDir(__file__)
  199. #
  200. # Here we have two instances master and consumer
  201. # with replication working. Either coming from a backup recovery
  202. # or from a fresh (re)init
  203. # Time to return the topology
  204. return TopologyMaster1Master2(master1, master2)
  205. def _bind_manager(topology):
  206. topology.master1.log.info("Bind as %s " % DN_DM)
  207. topology.master1.simple_bind_s(DN_DM, PASSWORD)
  208. def _bind_normal(topology):
  209. # bind as bind_entry
  210. topology.master1.log.info("Bind as %s" % BIND_DN)
  211. topology.master1.simple_bind_s(BIND_DN, BIND_PW)
  212. def _moddn_aci_deny_tree(topology, mod_type=None, target_from=STAGING_DN, target_to=PROD_EXCEPT_DN):
  213. '''
  214. It denies the access moddn_to in cn=except,cn=accounts,SUFFIX
  215. '''
  216. assert mod_type != None
  217. ACI_TARGET_FROM = ""
  218. ACI_TARGET_TO = ""
  219. if target_from:
  220. ACI_TARGET_FROM = "(target_from = \"ldap:///%s\")" % (target_from)
  221. if target_to:
  222. ACI_TARGET_TO = "(target_to = \"ldap:///%s\")" % (target_to)
  223. ACI_ALLOW = "(version 3.0; acl \"Deny MODDN to prod_except\"; deny (moddn)"
  224. ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
  225. ACI_BODY = ACI_TARGET_TO + ACI_TARGET_FROM + ACI_ALLOW + ACI_SUBJECT
  226. mod = [(mod_type, 'aci', ACI_BODY)]
  227. #topology.master1.modify_s(SUFFIX, mod)
  228. topology.master1.log.info("Add a DENY aci under %s " % PROD_EXCEPT_DN)
  229. topology.master1.modify_s(PROD_EXCEPT_DN, mod)
  230. def _moddn_aci_staging_to_production(topology, mod_type=None, target_from=STAGING_DN, target_to=PRODUCTION_DN):
  231. assert mod_type != None
  232. ACI_TARGET_FROM = ""
  233. ACI_TARGET_TO = ""
  234. if target_from:
  235. ACI_TARGET_FROM = "(target_from = \"ldap:///%s\")" % (target_from)
  236. if target_to:
  237. ACI_TARGET_TO = "(target_to = \"ldap:///%s\")" % (target_to)
  238. ACI_ALLOW = "(version 3.0; acl \"MODDN from staging to production\"; allow (moddn)"
  239. ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
  240. ACI_BODY = ACI_TARGET_FROM + ACI_TARGET_TO + ACI_ALLOW + ACI_SUBJECT
  241. mod = [(mod_type, 'aci', ACI_BODY)]
  242. topology.master1.modify_s(SUFFIX, mod)
  243. def _moddn_aci_from_production_to_staging(topology, mod_type=None):
  244. assert mod_type != None
  245. ACI_TARGET = "(target_from = \"ldap:///%s\") (target_to = \"ldap:///%s\")" % (PRODUCTION_DN, STAGING_DN)
  246. ACI_ALLOW = "(version 3.0; acl \"MODDN from production to staging\"; allow (moddn)"
  247. ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
  248. ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
  249. mod = [(mod_type, 'aci', ACI_BODY)]
  250. topology.master1.modify_s(SUFFIX, mod)
  251. def test_ticket47553_init(topology):
  252. """
  253. Creates
  254. - a staging DIT
  255. - a production DIT
  256. - add accounts in staging DIT
  257. - enable ACL logging (commented for performance reason)
  258. """
  259. topology.master1.log.info("\n\n######################### INITIALIZATION ######################\n")
  260. # entry used to bind with
  261. topology.master1.log.info("Add %s" % BIND_DN)
  262. topology.master1.add_s(Entry((BIND_DN, {
  263. 'objectclass': "top person".split(),
  264. 'sn': BIND_CN,
  265. 'cn': BIND_CN,
  266. 'userpassword': BIND_PW})))
  267. # DIT for staging
  268. topology.master1.log.info("Add %s" % STAGING_DN)
  269. topology.master1.add_s(Entry((STAGING_DN, {
  270. 'objectclass': "top organizationalRole".split(),
  271. 'cn': STAGING_CN,
  272. 'description': "staging DIT"})))
  273. # DIT for production
  274. topology.master1.log.info("Add %s" % PRODUCTION_DN)
  275. topology.master1.add_s(Entry((PRODUCTION_DN, {
  276. 'objectclass': "top organizationalRole".split(),
  277. 'cn': PRODUCTION_CN,
  278. 'description': "production DIT"})))
  279. # DIT for production/except
  280. topology.master1.log.info("Add %s" % PROD_EXCEPT_DN)
  281. topology.master1.add_s(Entry((PROD_EXCEPT_DN, {
  282. 'objectclass': "top organizationalRole".split(),
  283. 'cn': EXCEPT_CN,
  284. 'description': "production except DIT"})))
  285. # enable acl error logging
  286. #mod = [(ldap.MOD_REPLACE, 'nsslapd-errorlog-level', '128')]
  287. #topology.master1.modify_s(DN_CONFIG, mod)
  288. #topology.master2.modify_s(DN_CONFIG, mod)
  289. # add dummy entries in the staging DIT
  290. for cpt in range(MAX_ACCOUNTS):
  291. name = "%s%d" % (NEW_ACCOUNT, cpt)
  292. topology.master1.add_s(Entry(("cn=%s,%s" % (name, STAGING_DN), {
  293. 'objectclass': "top person".split(),
  294. 'sn': name,
  295. 'cn': name})))
  296. def test_ticket47553_mode_default_add_deny(topology):
  297. '''
  298. This test case checks that the ADD operation fails (no ADD aci on production)
  299. '''
  300. topology.master1.log.info("\n\n######################### mode moddn_aci : ADD (should fail) ######################\n")
  301. _bind_normal(topology)
  302. #
  303. # First try to add an entry in production => INSUFFICIENT_ACCESS
  304. #
  305. try:
  306. topology.master1.log.info("Try to add %s" % PRODUCTION_DN)
  307. name = "%s%d" % (NEW_ACCOUNT, 0)
  308. topology.master1.add_s(Entry(("cn=%s,%s" % (name, PRODUCTION_DN), {
  309. 'objectclass': "top person".split(),
  310. 'sn': name,
  311. 'cn': name})))
  312. assert 0 # this is an error, we should not be allowed to add an entry in production
  313. except Exception as e:
  314. topology.master1.log.info("Exception (expected): %s" % type(e).__name__)
  315. assert isinstance(e, ldap.INSUFFICIENT_ACCESS)
  316. def test_ticket47553_mode_default_ger_no_moddn(topology):
  317. topology.master1.log.info("\n\n######################### mode moddn_aci : GER no moddn ######################\n")
  318. request_ctrl = GetEffectiveRightsControl(criticality=True,authzId="dn: " + BIND_DN)
  319. msg_id = topology.master1.search_ext(PRODUCTION_DN, ldap.SCOPE_SUBTREE, "objectclass=*", serverctrls=[request_ctrl])
  320. rtype,rdata,rmsgid,response_ctrl = topology.master1.result3(msg_id)
  321. ger={}
  322. value=''
  323. for dn, attrs in rdata:
  324. topology.master1.log.info ("dn: %s" % dn)
  325. value = attrs['entryLevelRights'][0]
  326. topology.master1.log.info ("############### entryLevelRights: %r" % value)
  327. assert 'n' not in value
  328. def test_ticket47553_mode_default_ger_with_moddn(topology):
  329. '''
  330. This test case adds the moddn aci and check ger contains 'n'
  331. '''
  332. topology.master1.log.info("\n\n######################### mode moddn_aci: GER with moddn ######################\n")
  333. # successfull MOD with the ACI
  334. _bind_manager(topology)
  335. _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_DN, target_to=PRODUCTION_DN)
  336. _bind_normal(topology)
  337. request_ctrl = GetEffectiveRightsControl(criticality=True,authzId="dn: " + BIND_DN)
  338. msg_id = topology.master1.search_ext(PRODUCTION_DN, ldap.SCOPE_SUBTREE, "objectclass=*", serverctrls=[request_ctrl])
  339. rtype,rdata,rmsgid,response_ctrl = topology.master1.result3(msg_id)
  340. ger={}
  341. value = ''
  342. for dn, attrs in rdata:
  343. topology.master1.log.info ("dn: %s" % dn)
  344. value = attrs['entryLevelRights'][0]
  345. topology.master1.log.info ("############### entryLevelRights: %r" % value)
  346. assert 'n' in value
  347. # successfull MOD with the both ACI
  348. _bind_manager(topology)
  349. _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_DN, target_to=PRODUCTION_DN)
  350. _bind_normal(topology)
  351. def test_ticket47553_mode_switch_default_to_legacy(topology):
  352. '''
  353. This test switch the server from default mode to legacy
  354. '''
  355. topology.master1.log.info("\n\n######################### Disable the moddn aci mod ######################\n" )
  356. _bind_manager(topology)
  357. mod = [(ldap.MOD_REPLACE, CONFIG_MODDN_ACI_ATTR, 'off')]
  358. topology.master1.modify_s(DN_CONFIG, mod)
  359. def test_ticket47553_mode_legacy_ger_no_moddn1(topology):
  360. topology.master1.log.info("\n\n######################### mode legacy 1: GER no moddn ######################\n")
  361. request_ctrl = GetEffectiveRightsControl(criticality=True,authzId="dn: " + BIND_DN)
  362. msg_id = topology.master1.search_ext(PRODUCTION_DN, ldap.SCOPE_SUBTREE, "objectclass=*", serverctrls=[request_ctrl])
  363. rtype,rdata,rmsgid,response_ctrl = topology.master1.result3(msg_id)
  364. ger={}
  365. value=''
  366. for dn, attrs in rdata:
  367. topology.master1.log.info ("dn: %s" % dn)
  368. value = attrs['entryLevelRights'][0]
  369. topology.master1.log.info ("############### entryLevelRights: %r" % value)
  370. assert 'n' not in value
  371. def test_ticket47553_mode_legacy_ger_no_moddn2(topology):
  372. topology.master1.log.info("\n\n######################### mode legacy 2: GER no moddn ######################\n")
  373. # successfull MOD with the ACI
  374. _bind_manager(topology)
  375. _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_ADD, target_from=STAGING_DN, target_to=PRODUCTION_DN)
  376. _bind_normal(topology)
  377. request_ctrl = GetEffectiveRightsControl(criticality=True,authzId="dn: " + BIND_DN)
  378. msg_id = topology.master1.search_ext(PRODUCTION_DN, ldap.SCOPE_SUBTREE, "objectclass=*", serverctrls=[request_ctrl])
  379. rtype,rdata,rmsgid,response_ctrl = topology.master1.result3(msg_id)
  380. ger={}
  381. value=''
  382. for dn, attrs in rdata:
  383. topology.master1.log.info ("dn: %s" % dn)
  384. value = attrs['entryLevelRights'][0]
  385. topology.master1.log.info ("############### entryLevelRights: %r" % value)
  386. assert 'n' not in value
  387. # successfull MOD with the both ACI
  388. _bind_manager(topology)
  389. _moddn_aci_staging_to_production(topology, mod_type=ldap.MOD_DELETE, target_from=STAGING_DN, target_to=PRODUCTION_DN)
  390. _bind_normal(topology)
  391. def test_ticket47553_mode_legacy_ger_with_moddn(topology):
  392. topology.master1.log.info("\n\n######################### mode legacy : GER with moddn ######################\n")
  393. # being allowed to read/write the RDN attribute use to allow the RDN
  394. ACI_TARGET = "(target = \"ldap:///%s\")(targetattr=\"cn\")" % (PRODUCTION_DN)
  395. ACI_ALLOW = "(version 3.0; acl \"MODDN production changing the RDN attribute\"; allow (read,search,write)"
  396. ACI_SUBJECT = " userdn = \"ldap:///%s\";)" % BIND_DN
  397. ACI_BODY = ACI_TARGET + ACI_ALLOW + ACI_SUBJECT
  398. # successfull MOD with the ACI
  399. _bind_manager(topology)
  400. mod = [(ldap.MOD_ADD, 'aci', ACI_BODY)]
  401. topology.master1.modify_s(SUFFIX, mod)
  402. _bind_normal(topology)
  403. request_ctrl = GetEffectiveRightsControl(criticality=True,authzId="dn: " + BIND_DN)
  404. msg_id = topology.master1.search_ext(PRODUCTION_DN, ldap.SCOPE_SUBTREE, "objectclass=*", serverctrls=[request_ctrl])
  405. rtype,rdata,rmsgid,response_ctrl = topology.master1.result3(msg_id)
  406. ger={}
  407. value=''
  408. for dn, attrs in rdata:
  409. topology.master1.log.info ("dn: %s" % dn)
  410. value = attrs['entryLevelRights'][0]
  411. topology.master1.log.info ("############### entryLevelRights: %r" % value)
  412. assert 'n' in value
  413. # successfull MOD with the both ACI
  414. _bind_manager(topology)
  415. mod = [(ldap.MOD_DELETE, 'aci', ACI_BODY)]
  416. topology.master1.modify_s(SUFFIX, mod)
  417. _bind_normal(topology)
  418. def test_ticket47553_final(topology):
  419. topology.master1.stop(timeout=10)
  420. topology.master2.stop(timeout=10)
  421. def run_isolated():
  422. '''
  423. run_isolated is used to run these test cases independently of a test scheduler (xunit, py.test..)
  424. To run isolated without py.test, you need to
  425. - edit this file and comment '@pytest.fixture' line before 'topology' function.
  426. - set the installation prefix
  427. - run this program
  428. '''
  429. global installation1_prefix
  430. global installation2_prefix
  431. installation1_prefix = None
  432. installation2_prefix = None
  433. topo = topology(True)
  434. topo.master1.log.info("\n\n######################### Ticket 47553 ######################\n")
  435. test_ticket47553_init(topo)
  436. # Check that without appropriate aci we are not allowed to add/delete
  437. test_ticket47553_mode_default_add_deny(topo)
  438. test_ticket47553_mode_default_ger_no_moddn(topo)
  439. test_ticket47553_mode_default_ger_with_moddn(topo)
  440. test_ticket47553_mode_switch_default_to_legacy(topo)
  441. test_ticket47553_mode_legacy_ger_no_moddn1(topo)
  442. test_ticket47553_mode_legacy_ger_no_moddn2(topo)
  443. test_ticket47553_mode_legacy_ger_with_moddn(topo)
  444. test_ticket47553_final(topo)
  445. if __name__ == '__main__':
  446. run_isolated()