def test_agmt_num_add(topo, attr, too_small, too_big, overflow, notnum, valid): """Test all the number values you can set for a replica config entry :id: a8b47d4a-a089-4d70-8070-e6181209bf94 :setup: standalone instance :steps: 1. Use a value that is too small 2. Use a value that is too big 3. Use a value that overflows the int 4. Use a value with character value (not a number) 5. Use a valid value :expectedresults: 1. Add is rejected 2. Add is rejected 3. Add is rejected 4. Add is rejected 5. Add is allowed """ agmt_reset(topo) replica = replica_setup(topo) agmts = Agreements(topo.standalone, basedn=replica.dn) # Test too small perform_invalid_create(agmts, agmt_dict, attr, too_small) # Test too big perform_invalid_create(agmts, agmt_dict, attr, too_big) # Test overflow perform_invalid_create(agmts, agmt_dict, attr, overflow) # test not a number perform_invalid_create(agmts, agmt_dict, attr, notnum) # Test valid value my_agmt = copy.deepcopy(agmt_dict) my_agmt[attr] = valid agmts.create(properties=my_agmt)
def _create_entries(topology_m2c2): """ A fixture that will create first test user and create fractional Agreement """ # Defining as global , as same value will be used everywhere with same name. global MASTER1, MASTER2, CONSUMER1, CONSUMER2 MASTER1 = topology_m2c2.ms['master1'] MASTER2 = topology_m2c2.ms['master2'] CONSUMER1 = topology_m2c2.cs['consumer1'] CONSUMER2 = topology_m2c2.cs['consumer2'] users = UserAccounts(MASTER1, DEFAULT_SUFFIX) _create_users(users, 'Sam Carter', 'Carter', 'Sam', ['Accounting', 'People'], 'Sunnyvale', 'scarter', '*****@*****.**', '+1 408 555 4798', '+1 408 555 9751', '4612') for ins, num in [(MASTER1, 1), (MASTER2, 2), (MASTER1, 2), (MASTER2, 1)]: Agreements(ins).list()[num].replace( 'nsDS5ReplicatedAttributeList', '(objectclass=*) $ EXCLUDE audio businessCategory carLicense departmentNumber ' 'destinationIndicator displayName employeeNumber employeeType facsimileTelephoneNumber ' 'roomNumber telephoneNumber memberOf manager accountUnlockTime ' 'passwordRetryCount retryCountResetTime') Agreements(ins).list()[num].replace( 'nsDS5ReplicatedAttributeListTotal', '(objectclass=*) $ EXCLUDE audio businessCategory carLicense departmentNumber ' 'destinationIndicator displayName employeeNumber employeeType facsimileTelephoneNumber ' 'roomNumber telephoneNumber accountUnlockTime passwordRetryCount retryCountResetTime' ) Agreements(ins).list()[num].begin_reinit() Agreements(ins).list()[num].wait_reinit()
def agmt_setup(topo): """Add a valid replica config entry to modify """ # Reset the agreements too. replica = replica_setup(topo) agmts = Agreements(topo.standalone, basedn=replica.dn) for a in agmts.list(): a.delete() return agmts.create(properties=agmt_dict)
def config_memberof(server): """Configure memberOf plugin and configure fractional to prevent total init to send memberof """ memberof = MemberOfPlugin(server) memberof.enable() memberof.set_autoaddoc('nsMemberOf') server.restart() agmts = Agreements(server) for agmt in agmts.list(): log.info('update %s to add nsDS5ReplicatedAttributeListTotal' % agmt.dn) agmt.replace_many(('nsDS5ReplicatedAttributeListTotal', '(objectclass=*) $ EXCLUDE '), ('nsDS5ReplicatedAttributeList', '(objectclass=*) $ EXCLUDE memberOf'))
def test_attribute_nsds5replicatedattributelisttotal(_create_entries, _add_user_clean): """This test case is to test the newly added attribute nsds5replicatedattributelistTotal. :id: 35de9ff0-38eb-11ea-b420-8c16451d917b :setup: Master and Consumer :steps: 1. Add a new entry to MASTER1. 2. Enabling memberOf plugin and then adding few groups with member attributes. 3. No memberOf plugin enabled in other consumers,ie., the read only replicas won't get incremental updates for the attributes mentioned in the list. 4. Run total update and verify the same attributes added/modified in the read-only replicas. :expected results: 1. Success 2. Success 3. Success 4. Success """ # Run total update and verify the same attributes added/modified in the read-only replicas. user = f'uid=test_user_1000,ou=People,{DEFAULT_SUFFIX}' for agreement in Agreements(MASTER1).list(): agreement.begin_reinit() agreement.wait_reinit() check_all_replicated() for instance in (MASTER1, MASTER2): assert Groups( MASTER1, DEFAULT_SUFFIX).list()[0].get_attr_val_utf8("member") == user assert UserAccount(instance, user).get_attr_val_utf8("sn") == "test_user_1000" for instance in (CONSUMER1, CONSUMER2): for value in ("memberOf", "manager", "sn"): assert UserAccount(instance, user).get_attr_val_utf8(value)
def test_not_int_value(topology_m2): """Tests not integer value :id: 67c9994f-9251-425a-8197-8d12ad9beafc :setup: Replication with two suppliers :steps: 1. Try to set some string value to nsDS5ReplicaWaitForAsyncResults :expectedresults: 1. Invalid syntax error should be raised """ supplier1 = topology_m2.ms["supplier1"] agmt = Agreements(supplier1).list()[0] with pytest.raises(ldap.INVALID_SYNTAX): agmt.set_wait_for_async_results("ws2")
def test_referral_during_tot(topology_m2): master1 = topology_m2.ms["master1"] master2 = topology_m2.ms["master2"] users = UserAccounts(master2, DEFAULT_SUFFIX) u = users.create(properties=TEST_USER_PROPERTIES) u.set('userPassword', 'password') binddn = u.dn bindpw = 'password' # Create a bunch of entries on master1 ldif_dir = master1.get_ldif_dir() import_ldif = ldif_dir + '/ref_during_tot_import.ldif' dbgen(master1, 10000, import_ldif, DEFAULT_SUFFIX) master1.stop() master1.ldif2db(bename=None, excludeSuffixes=None, encrypt=False, suffixes=[DEFAULT_SUFFIX], import_file=import_ldif) master1.start() # Recreate the user on m1 also, so that if the init finishes first ew don't lose the user on m2 users = UserAccounts(master1, DEFAULT_SUFFIX) u = users.create(properties=TEST_USER_PROPERTIES) u.set('userPassword', 'password') # Now export them to master2 agmts = Agreements(master1) agmts.list()[0].begin_reinit() # While that's happening try to bind as a user to master 2 # This should trigger the referral code. referred = False for i in range(0, 100): conn = ldap.initialize(master2.toLDAPURL()) conn.set_option(ldap.OPT_REFERRALS, False) try: conn.simple_bind_s(binddn, bindpw) conn.unbind_s() except ldap.REFERRAL: referred = True break # Means we never go a referral, should not happen! assert referred
def test_rename_entry(topo_m2, _delete_after): """Rename entry crashed a server :id: 3866f9d6-a946-11ea-a3f8-8c16451d917b :setup: MMR with 2 masters :steps: 1. Adding entry 2. Stop Agreement for both 3. Change description 4. Change will not reflect on other master 5. Turn on agreement on both 6. Change will reflect on other master :expected results: 1. Should succeeds 2. Should succeeds 3. Should succeeds 4. Should succeeds 5. Should succeeds 6. Should succeeds """ m1 = topo_m2.ms["master1"] m2 = topo_m2.ms["master2"] # Adding entry user1 = UserAccounts(m1, DEFAULT_SUFFIX, rdn=None).create_test_user(uid=1, gid=1) repl_manager = ReplicationManager(DEFAULT_SUFFIX) repl_manager.wait_for_replication(m1, m2, timeout=100) user2 = UserAccount(m2, user1.dn) assert user2.status() # Stop Agreement for both agree1 = Agreements(m1).list()[0] agree2 = Agreements(m2).list()[0] for agree in [agree1, agree2]: agree.pause() # change description user1.replace('description', 'New Des') assert user1.get_attr_val_utf8('description') # Change will not reflect on other master with pytest.raises(AssertionError): assert user2.get_attr_val_utf8('description') # Turn on agreement on both for agree in [agree1, agree2]: agree.resume() repl_manager.wait_for_replication(m1, m2, timeout=100) for instance in [user1, user2]: assert instance.get_attr_val_utf8('description')
def test_online_reinit_may_hang(topo_with_sigkill): """Online reinitialization may hang when the first entry of the DB is RUV entry instead of the suffix :id: cded6afa-66c0-4c65-9651-993ba3f7a49c :setup: 2 Supplier Instances :steps: 1. Export the database 2. Move RUV entry to the top in the ldif file 3. Import the ldif file 4. Check that replication is still working 5. Online replica initializaton :expectedresults: 1. Ldif file should be created successfully 2. RUV entry should be on top in the ldif file 3. Import should be successful 4. Replication should work 5. Server should not hang and consume 100% CPU """ M1 = topo_with_sigkill.ms["supplier1"] M2 = topo_with_sigkill.ms["supplier2"] M1.stop() ldif_file = '%s/supplier1.ldif' % M1.get_ldif_dir() M1.db2ldif(bename=DEFAULT_BENAME, suffixes=[DEFAULT_SUFFIX], excludeSuffixes=None, repl_data=True, outputfile=ldif_file, encrypt=False) _move_ruv(ldif_file) M1.ldif2db(DEFAULT_BENAME, None, None, None, ldif_file) M1.start() # After this server may hang # Exporting idle server with replication data and reimporting # should not break replication (Unless we hit issue 5098) # So let check that replication is still working. repl = ReplicationManager(DEFAULT_SUFFIX) repl.test_replication_topology(topo_with_sigkill) agmt = Agreements(M1).list()[0] agmt.begin_reinit() (done, error) = agmt.wait_reinit() assert done is True assert error is False repl = ReplicationManager(DEFAULT_SUFFIX) repl.test_replication_topology(topo_with_sigkill) if DEBUGGING: # Add debugging steps(if any)... pass
def test_healthcheck_replication_out_of_sync_not_broken(topology_m3): """Check if HealthCheck returns DSREPLLE0003 code :id: 8305000d-ba4d-4c00-8331-be0e8bd92150 :setup: 3 MMR topology :steps: 1. Create a 3 masters full-mesh topology, all replicas being synchronized 2. Stop M1 3. Perform an update on M2 and M3. 4. Check M2 and M3 are synchronized. 5. From M2, reinitialize the M3 agreement 6. Stop M2 and M3 7. Restart M1 8. Start M3 9. Use HealthCheck without --json option 10. Use HealthCheck with --json option :expectedresults: 1. Success 2. Success 3. Success 4. Success 5. Success 6. Success 7. Success 8. Success 9. Healthcheck reports DSREPLLE0003 code and related details 10. Healthcheck reports DSREPLLE0003 code and related details """ RET_CODE = 'DSREPLLE0003' M1 = topology_m3.ms['master1'] M2 = topology_m3.ms['master2'] M3 = topology_m3.ms['master3'] log.info('Stop master1') M1.stop() log.info('Perform update on master2 and master3') test_users_m2 = UserAccounts(M2, DEFAULT_SUFFIX) test_users_m3 = UserAccounts(M3, DEFAULT_SUFFIX) test_users_m2.create_test_user(1000, 2000) test_users_m3.create_test_user(1001, 2000) log.info('Init M2->M3 agreement') agmt = Agreements(M2).list()[1] agmt.begin_reinit() agmt.wait_reinit() log.info('Stop M2 and M3') M2.stop() M3.stop() log.info('Start M1 first, then M3') M1.start() M3.start() run_healthcheck_and_flush_log(topology_m3, M3, RET_CODE, json=False) run_healthcheck_and_flush_log(topology_m3, M3, RET_CODE, json=True)
def test_value_check(topology_m2, waitfor_async_attr): """Checks that value has been set correctly :id: 3e81afe9-5130-410d-a1bb-d798d8ab8519 :setup: Replication with two masters, wait for async set on all masters, try: None, '2000', '0', '-5' :steps: 1. Search for nsDS5ReplicaWaitForAsyncResults on master 1 2. Search for nsDS5ReplicaWaitForAsyncResults on master 2 :expectedresults: 1. nsDS5ReplicaWaitForAsyncResults should be set correctly 2. nsDS5ReplicaWaitForAsyncResults should be set correctly """ attr_value = waitfor_async_attr[0] for master in topology_m2.ms.values(): agmt = Agreements(master).list()[0] server_value = agmt.get_wait_for_async_results_utf8() assert server_value == attr_value
def test_multi_value(topology_m2): """Tests multi value :id: 1932301a-db29-407e-b27e-4466a876d1d3 :setup: Replication with two suppliers :steps: 1. Set nsDS5ReplicaWaitForAsyncResults to some int 2. Try to add one more int value to nsDS5ReplicaWaitForAsyncResults :expectedresults: 1. nsDS5ReplicaWaitForAsyncResults should be set 2. Object class violation error should be raised """ supplier1 = topology_m2.ms["supplier1"] agmt = Agreements(supplier1).list()[0] agmt.set_wait_for_async_results('100') with pytest.raises(ldap.OBJECT_CLASS_VIOLATION): agmt.add('nsDS5ReplicaWaitForAsyncResults', '101')
def waitfor_async_attr(topology_m2, request): """Sets attribute on all replicas""" attr_value = request.param[0] expected_result = request.param[1] # Run through all suppliers for supplier in topology_m2.ms.values(): agmt = Agreements(supplier).list()[0] if attr_value: agmt.set_wait_for_async_results(attr_value) else: try: # Sometimes we can double remove this. agmt.remove_wait_for_async_results() except ldap.NO_SUCH_ATTRIBUTE: pass return (attr_value, expected_result)
def agmt_reset(topo): """Purge all existing agreements for testing""" agmts = Agreements(topo.standalone) for a in agmts.list(): a.delete()
def test_memberof_groups(self, topology_m2, base_m2): """Check that conflict properly resolved for operations with memberOf and groups :id: 77f09b18-03d1-45da-940b-1ad2c2908eb3 :setup: Two master replication, test container for entries, enable plugin logging, audit log, error log for replica and access log for internal :steps: 1. Enable memberOf plugin 2. Add 30 users to m1 and wait for replication to happen 3. Pause replication 4. Create a group on m1 and m2 5. Create a group on m1 and m2, delete from m1 6. Create a group on m1, delete from m1, and create on m2, 7. Create a group on m2 and m1, delete from m1 8. Create two different groups on m2 9. Resume replication 10. Check that the entries on both masters are the same and replication is working :expectedresults: 1. It should pass 2. It should pass 3. It should pass 4. It should pass 5. It should pass 6. It should pass 7. It should pass 8. It should pass 9. It should pass 10. It should pass """ pytest.xfail("Issue 49591 - work in progress") M1 = topology_m2.ms["master1"] M2 = topology_m2.ms["master2"] test_users_m1 = UserAccounts(M1, base_m2.dn, rdn=None) test_groups_m1 = Groups(M1, base_m2.dn, rdn=None) test_groups_m2 = Groups(M2, base_m2.dn, rdn=None) repl = ReplicationManager(SUFFIX) for inst in topology_m2.ms.values(): memberof = MemberOfPlugin(inst) memberof.enable() agmt = Agreements(inst).list()[0] agmt.replace_many(('nsDS5ReplicatedAttributeListTotal', '(objectclass=*) $ EXCLUDE '), ('nsDS5ReplicatedAttributeList', '(objectclass=*) $ EXCLUDE memberOf')) inst.restart() user_dns = [] for user_num in range(10): user_trio = [] for num in range(0, 30, 10): user = _create_user(test_users_m1, 1200 + user_num + num) user_trio.append(user.dn) user_dns.append(user_trio) repl.test_replication(M1, M2) topology_m2.pause_all_replicas() log.info("Check a simple conflict") group_num = 0 _create_group(test_groups_m1, group_num, user_dns[group_num], sleep=True) _create_group(test_groups_m2, group_num, user_dns[group_num], sleep=True) log.info("Check a add - del") group_num += 1 _create_group(test_groups_m1, group_num, user_dns[group_num], sleep=True) _create_group(test_groups_m2, group_num, user_dns[group_num], sleep=True) _delete_group(test_groups_m1, group_num) group_num += 1 _create_group(test_groups_m1, group_num, user_dns[group_num]) _delete_group(test_groups_m1, group_num, sleep=True) _create_group(test_groups_m2, group_num, user_dns[group_num]) group_num += 1 _create_group(test_groups_m2, group_num, user_dns[group_num], sleep=True) _create_group(test_groups_m1, group_num, user_dns[group_num]) _delete_group(test_groups_m1, group_num, sleep=True) group_num += 1 _create_group(test_groups_m2, group_num, user_dns[group_num]) group_num += 1 _create_group(test_groups_m2, group_num, user_dns[group_num]) topology_m2.resume_all_replicas() repl.test_replication_topology(topology_m2) group_dns_m1 = [group.dn for group in test_groups_m1.list()] group_dns_m2 = [group.dn for group in test_groups_m2.list()] assert set(group_dns_m1) == set(group_dns_m2)
def test_csngen_state_not_updated_if_different_uuid(topo_m2c2): """Check that csngen remote offset is not updated if RUV generation uuid are different :id: 77694b8e-22ae-11eb-89b2-482ae39447e5 :setup: Two suppliers + two consumers replication setup :steps: 1. Disable m1<->m2 agreement to avoid propagate timeSkew 2. Generate ldif without replication data 3. Increase time skew on supplier2 4. Init both suppliers from that ldif (to clear the ruvs and generates different generation uuid) 5. Perform on line init from supplier1 to consumer1 and supplier2 to consumer2 6. Perform update on both suppliers 7: Check that c1 has no time skew 8: Check that c2 has time skew 9. Init supplier2 from supplier1 10. Perform update on supplier2 11. Check that c1 has time skew :expectedresults: 1. No error 2. No error while generating ldif 3. No error 4. No error while importing the ldif file 5. No error and Initialization done. 6. No error 7. c1 time skew should be lesser than threshold 8. c2 time skew should be higher than threshold 9. No error and Initialization done. 10. No error 11. c1 time skew should be higher than threshold """ # Variables initialization repl = ReplicationManager(DEFAULT_SUFFIX) m1 = topo_m2c2.ms["supplier1"] m2 = topo_m2c2.ms["supplier2"] c1 = topo_m2c2.cs["consumer1"] c2 = topo_m2c2.cs["consumer2"] replica_m1 = Replicas(m1).get(DEFAULT_SUFFIX) replica_m2 = Replicas(m2).get(DEFAULT_SUFFIX) replica_c1 = Replicas(c1).get(DEFAULT_SUFFIX) replica_c2 = Replicas(c2).get(DEFAULT_SUFFIX) replicid_m2 = replica_m2.get_rid() agmts_m1 = Agreements(m1, replica_m1.dn) agmts_m2 = Agreements(m2, replica_m2.dn) m1_m2 = get_agreement(agmts_m1, m2) m1_c1 = get_agreement(agmts_m1, c1) m1_c2 = get_agreement(agmts_m1, c2) m2_m1 = get_agreement(agmts_m2, m1) m2_c1 = get_agreement(agmts_m2, c1) m2_c2 = get_agreement(agmts_m2, c2) # Step 1: Disable m1<->m2 agreement to avoid propagate timeSkew m1_m2.pause() m2_m1.pause() # Step 2: Generate ldif without replication data m1.stop() m2.stop() ldif_file = '%s/norepl.ldif' % m1.get_ldif_dir() m1.db2ldif(bename=DEFAULT_BENAME, suffixes=[DEFAULT_SUFFIX], excludeSuffixes=None, repl_data=False, outputfile=ldif_file, encrypt=False) # Remove replication metadata that are still in the ldif # _remove_replication_data(ldif_file) # Step 3: Increase time skew on supplier2 timeSkew = 6 * 3600 # We can modify supplier2 time skew # But the time skew on the consumer may be smaller # depending on when the cnsgen generation time is updated # and when first csn get replicated. # Since we use timeSkew has threshold value to detect # whether there are time skew or not, # lets add a significative margin (longer than the test duration) # to avoid any risk of erroneous failure timeSkewMargin = 300 DSEldif(m2)._increaseTimeSkew(DEFAULT_SUFFIX, timeSkew + timeSkewMargin) # Step 4: Init both suppliers from that ldif m1.ldif2db(DEFAULT_BENAME, None, None, None, ldif_file) m2.ldif2db(DEFAULT_BENAME, None, None, None, ldif_file) m1.start() m2.start() # Step 5: Perform on line init from supplier1 to consumer1 # and from supplier2 to consumer2 m1_c1.begin_reinit() m2_c2.begin_reinit() (done, error) = m1_c1.wait_reinit() assert done is True assert error is False (done, error) = m2_c2.wait_reinit() assert done is True assert error is False # Step 6: Perform update on both suppliers repl.test_replication(m1, c1) repl.test_replication(m2, c2) # Step 7: Check that c1 has no time skew # Stop server to insure that dse.ldif is uptodate c1.stop() c1_nsState = DSEldif(c1).readNsState(DEFAULT_SUFFIX)[0] c1_timeSkew = int(c1_nsState['time_skew']) log.debug(f"c1 time skew: {c1_timeSkew}") if (c1_timeSkew >= timeSkew): log.error( f"c1 csngen state has unexpectedly been synchronized with m2: time skew {c1_timeSkew}" ) assert False c1.start() # Step 8: Check that c2 has time skew # Stop server to insure that dse.ldif is uptodate c2.stop() c2_nsState = DSEldif(c2).readNsState(DEFAULT_SUFFIX)[0] c2_timeSkew = int(c2_nsState['time_skew']) log.debug(f"c2 time skew: {c2_timeSkew}") if (c2_timeSkew < timeSkew): log.error( f"c2 csngen state has not been synchronized with m2: time skew {c2_timeSkew}" ) assert False c2.start() # Step 9: Perform on line init from supplier1 to supplier2 m1_c1.pause() m1_m2.resume() m1_m2.begin_reinit() (done, error) = m1_m2.wait_reinit() assert done is True assert error is False # Step 10: Perform update on supplier2 repl.test_replication(m2, c1) # Step 11: Check that c1 has time skew # Stop server to insure that dse.ldif is uptodate c1.stop() c1_nsState = DSEldif(c1).readNsState(DEFAULT_SUFFIX)[0] c1_timeSkew = int(c1_nsState['time_skew']) log.debug(f"c1 time skew: {c1_timeSkew}") if (c1_timeSkew < timeSkew): log.error( f"c1 csngen state has not been synchronized with m2: time skew {c1_timeSkew}" ) assert False
def test_fetch_bindDnGroup(topo_m2): """Check the bindDNGroup is fetched on first replication session :id: 5f1b1f59-6744-4260-b091-c82d22130025 :setup: 2 Master Instances :steps: 1. Create a replication bound user and group, but the user *not* member of the group 2. Check that replication is working 3. Some preparation is required because of lib389 magic that already define a replication via group - define the group as groupDN for replication and 60sec as fetch interval - pause RA in both direction - Define the user as bindDn of the RAs 4. restart servers. It sets the fetch time to 0, so next session will refetch the group 5. Before resuming RA, add user to groupDN (on both side as replication is not working at that time) 6. trigger an update and check replication is working and there is no failure logged on supplier side 'does not have permission to supply replication updates to the replica' :expectedresults: 1. Success 2. Success 3. Success 4. Success 5. Success 6. Success """ # If you need any test suite initialization, # please, write additional fixture for that (including finalizer). # Topology for suites are predefined in lib389/topologies.py. # If you need host, port or any other data about instance, # Please, use the instance object attributes for that (for example, topo.ms["master1"].serverid) M1 = topo_m2.ms['master1'] M2 = topo_m2.ms['master2'] # Enable replication log level. Not really necessary M1.modify_s('cn=config', [(ldap.MOD_REPLACE, 'nsslapd-errorlog-level', b'8192')]) M2.modify_s('cn=config', [(ldap.MOD_REPLACE, 'nsslapd-errorlog-level', b'8192')]) # Create a group and a user PEOPLE = "ou=People,%s" % SUFFIX PASSWD = 'password' REPL_MGR_BOUND_DN = 'repl_mgr_bound_dn' uid = REPL_MGR_BOUND_DN.encode() users = UserAccounts(M1, PEOPLE, rdn=None) user_props = TEST_USER_PROPERTIES.copy() user_props.update({ 'uid': uid, 'cn': uid, 'sn': '_%s' % uid, 'userpassword': PASSWD.encode(), 'description': b'value creation' }) create_user = users.create(properties=user_props) groups_M1 = Groups(M1, DEFAULT_SUFFIX) group_properties = {'cn': 'group1', 'description': 'testgroup'} group_M1 = groups_M1.create(properties=group_properties) group_M2 = Group(M2, group_M1.dn) assert (not group_M1.is_member(create_user.dn)) # Check that M1 and M2 are in sync repl = ReplicationManager(DEFAULT_SUFFIX) repl.wait_for_replication(M1, M2, timeout=20) # Define the group as the replication manager and fetch interval as 60sec replicas = Replicas(M1) replica = replicas.list()[0] replica.apply_mods([ (ldap.MOD_REPLACE, 'nsDS5ReplicaBindDnGroupCheckInterval', '60'), (ldap.MOD_REPLACE, 'nsDS5ReplicaBindDnGroup', group_M1.dn) ]) replicas = Replicas(M2) replica = replicas.list()[0] replica.apply_mods([ (ldap.MOD_REPLACE, 'nsDS5ReplicaBindDnGroupCheckInterval', '60'), (ldap.MOD_REPLACE, 'nsDS5ReplicaBindDnGroup', group_M1.dn) ]) # Then pause the replication agreement to prevent them trying to acquire # while the user is not member of the group topo_m2.pause_all_replicas() # Define the user as the bindDN of the RAs for inst in (M1, M2): agmts = Agreements(inst) agmt = agmts.list()[0] agmt.replace('nsDS5ReplicaBindDN', create_user.dn.encode()) agmt.replace('nsds5ReplicaCredentials', PASSWD.encode()) # Key step # The restart will fetch the group/members define in the replica # # The user NOT member of the group replication will not work until bindDNcheckInterval # # With the fix, the first fetch is not taken into account (fetch time=0) # so on the first session, the group will be fetched M1.restart() M2.restart() # Replication being broken here we need to directly do the same update. # Sorry not found another solution except total update group_M1.add_member(create_user.dn) group_M2.add_member(create_user.dn) topo_m2.resume_all_replicas() # trigger updates to be sure to have a replication session, giving some time M1.modify_s(create_user.dn, [(ldap.MOD_ADD, 'description', b'value_1_1')]) M2.modify_s(create_user.dn, [(ldap.MOD_ADD, 'description', b'value_2_2')]) time.sleep(10) # Check replication is working ents = M1.search_s(create_user.dn, ldap.SCOPE_BASE, '(objectclass=*)') for ent in ents: assert (ent.hasAttr('description')) found = 0 for val in ent.getValues('description'): if (val == b'value_1_1'): found = found + 1 elif (val == b'value_2_2'): found = found + 1 assert (found == 2) ents = M2.search_s(create_user.dn, ldap.SCOPE_BASE, '(objectclass=*)') for ent in ents: assert (ent.hasAttr('description')) found = 0 for val in ent.getValues('description'): if (val == b'value_1_1'): found = found + 1 elif (val == b'value_2_2'): found = found + 1 assert (found == 2) # Check in the logs that the member was detected in the group although # at startup it was not member of the group regex = re.compile( "does not have permission to supply replication updates to the replica." ) errorlog_M1 = open(M1.errlog, "r") errorlog_M2 = open(M1.errlog, "r") # Find the last restart position restart_location_M1 = find_start_location(errorlog_M1, 2) assert (restart_location_M1 != -1) restart_location_M2 = find_start_location(errorlog_M2, 2) assert (restart_location_M2 != -1) # Then check there is no failure to authenticate count = pattern_errorlog(errorlog_M1, regex, start_location=restart_location_M1) assert (count <= 1) count = pattern_errorlog(errorlog_M2, regex, start_location=restart_location_M2) assert (count <= 1) if DEBUGGING: # Add debugging steps(if any)... pass
def test_online_init_should_create_keepalive_entries(topo_m2): """Check that keep alive entries are created when initializinf a supplier from another one :id: d5940e71-d18a-4b71-aaf7-b9185361fffe :setup: Two suppliers replication setup :steps: 1. Generate ldif without replication data 2 Init both suppliers from that ldif 3 Check that keep alive entries does not exists 4 Perform on line init of supplier2 from supplier1 5 Check that keep alive entries exists :expectedresults: 1. No error while generating ldif 2. No error while importing the ldif file 3. No keepalive entrie should exists on any suppliers 4. No error while initializing supplier2 5. All keepalive entries should exist on every suppliers """ repl = ReplicationManager(DEFAULT_SUFFIX) m1 = topo_m2.ms["supplier1"] m2 = topo_m2.ms["supplier2"] # Step 1: Generate ldif without replication data m1.stop() m2.stop() ldif_file = '%s/norepl.ldif' % m1.get_ldif_dir() m1.db2ldif(bename=DEFAULT_BENAME, suffixes=[DEFAULT_SUFFIX], excludeSuffixes=None, repl_data=False, outputfile=ldif_file, encrypt=False) # Remove replication metadata that are still in the ldif _remove_replication_data(ldif_file) # Step 2: Init both suppliers from that ldif m1.ldif2db(DEFAULT_BENAME, None, None, None, ldif_file) m2.ldif2db(DEFAULT_BENAME, None, None, None, ldif_file) m1.start() m2.start() """ Replica state is now as if CLI setup has been done using: dsconf supplier1 replication enable --suffix "${SUFFIX}" --role supplier dsconf supplier2 replication enable --suffix "${SUFFIX}" --role supplier dsconf supplier1 replication create-manager --name "${REPLICATION_MANAGER_NAME}" --passwd "${REPLICATION_MANAGER_PASSWORD}" dsconf supplier2 replication create-manager --name "${REPLICATION_MANAGER_NAME}" --passwd "${REPLICATION_MANAGER_PASSWORD}" dsconf supplier1 repl-agmt create --suffix "${SUFFIX}" dsconf supplier2 repl-agmt create --suffix "${SUFFIX}" """ # Step 3: No keepalive entrie should exists on any suppliers verify_keepalive_entries(topo_m2, False) # Step 4: Perform on line init of supplier2 from supplier1 agmt = Agreements(m1).list()[0] agmt.begin_reinit() (done, error) = agmt.wait_reinit() assert done is True assert error is False # Step 5: All keepalive entries should exists on every suppliers # Verify the keep alive entry once replication is in sync # (that is the step that fails when bug is not fixed) repl.wait_for_ruv(m2, m1) verify_keepalive_entries(topo_m2, True)
def test_ruv_url_not_added_if_different_uuid(topo_m2c2): """Check that RUV url is not updated if RUV generation uuid are different :id: 7cc30a4e-0ffd-4758-8f00-e500279af344 :setup: Two suppliers + two consumers replication setup :steps: 1. Generate ldif without replication data 2. Init both suppliers from that ldif (to clear the ruvs and generates different generation uuid) 3. Perform on line init from supplier1 to consumer1 and from supplier2 to consumer2 4. Perform update on both suppliers 5. Check that c1 RUV does not contains URL towards m2 6. Check that c2 RUV does contains URL towards m2 7. Perform on line init from supplier1 to supplier2 8. Perform update on supplier2 9. Check that c1 RUV does contains URL towards m2 :expectedresults: 1. No error while generating ldif 2. No error while importing the ldif file 3. No error and Initialization done. 4. No error 5. supplier2 replicaid should not be in the consumer1 RUV 6. supplier2 replicaid should be in the consumer2 RUV 7. No error and Initialization done. 8. No error 9. supplier2 replicaid should be in the consumer1 RUV """ # Variables initialization repl = ReplicationManager(DEFAULT_SUFFIX) m1 = topo_m2c2.ms["supplier1"] m2 = topo_m2c2.ms["supplier2"] c1 = topo_m2c2.cs["consumer1"] c2 = topo_m2c2.cs["consumer2"] replica_m1 = Replicas(m1).get(DEFAULT_SUFFIX) replica_m2 = Replicas(m2).get(DEFAULT_SUFFIX) replica_c1 = Replicas(c1).get(DEFAULT_SUFFIX) replica_c2 = Replicas(c2).get(DEFAULT_SUFFIX) replicid_m2 = replica_m2.get_rid() agmts_m1 = Agreements(m1, replica_m1.dn) agmts_m2 = Agreements(m2, replica_m2.dn) m1_m2 = get_agreement(agmts_m1, m2) m1_c1 = get_agreement(agmts_m1, c1) m1_c2 = get_agreement(agmts_m1, c2) m2_m1 = get_agreement(agmts_m2, m1) m2_c1 = get_agreement(agmts_m2, c1) m2_c2 = get_agreement(agmts_m2, c2) # Step 1: Generate ldif without replication data m1.stop() m2.stop() ldif_file = '%s/norepl.ldif' % m1.get_ldif_dir() m1.db2ldif(bename=DEFAULT_BENAME, suffixes=[DEFAULT_SUFFIX], excludeSuffixes=None, repl_data=False, outputfile=ldif_file, encrypt=False) # Remove replication metadata that are still in the ldif # _remove_replication_data(ldif_file) # Step 2: Init both suppliers from that ldif m1.ldif2db(DEFAULT_BENAME, None, None, None, ldif_file) m2.ldif2db(DEFAULT_BENAME, None, None, None, ldif_file) m1.start() m2.start() # Step 3: Perform on line init from supplier1 to consumer1 # and from supplier2 to consumer2 m1_c1.begin_reinit() m2_c2.begin_reinit() (done, error) = m1_c1.wait_reinit() assert done is True assert error is False (done, error) = m2_c2.wait_reinit() assert done is True assert error is False # Step 4: Perform update on both suppliers repl.test_replication(m1, c1) repl.test_replication(m2, c2) # Step 5: Check that c1 RUV does not contains URL towards m2 ruv = replica_c1.get_ruv() log.debug(f"c1 RUV: {ruv}") url = ruv._rid_url.get(replica_m2.get_rid()) if url is None: log.debug(f"No URL for RID {replica_m2.get_rid()} in RUV") else: log.debug(f"URL for RID {replica_m2.get_rid()} in RUV is {url}") log.error(f"URL for RID {replica_m2.get_rid()} found in RUV") # Note: this assertion fails if issue 2054 is not fixed. assert False # Step 6: Check that c2 RUV does contains URL towards m2 ruv = replica_c2.get_ruv() log.debug(f"c1 RUV: {ruv} {ruv._rids} ") url = ruv._rid_url.get(replica_m2.get_rid()) if url is None: log.error(f"No URL for RID {replica_m2.get_rid()} in RUV") assert False else: log.debug(f"URL for RID {replica_m2.get_rid()} in RUV is {url}") # Step 7: Perform on line init from supplier1 to supplier2 m1_m2.begin_reinit() (done, error) = m1_m2.wait_reinit() assert done is True assert error is False # Step 8: Perform update on supplier2 repl.test_replication(m2, c1) # Step 9: Check that c1 RUV does contains URL towards m2 ruv = replica_c1.get_ruv() log.debug(f"c1 RUV: {ruv} {ruv._rids} ") url = ruv._rid_url.get(replica_m2.get_rid()) if url is None: log.error(f"No URL for RID {replica_m2.get_rid()} in RUV") assert False else: log.debug(f"URL for RID {replica_m2.get_rid()} in RUV is {url}")