def set_state(self, new_state): new_state = new_state.lower() suffix = self.get_attr_val_utf8('nsslapd-suffix') try: mt = self._mts.get(suffix) except ldap.NO_SUCH_OBJECT: raise ValueError( "Backend missing mapping tree entry, unable to set configuration" ) if new_state not in [ 'backend', 'disabled', 'referral', 'referral on update' ]: raise ValueError( f"Invalid backend state {new_state}, value must be one of the following: 'backend', 'disabled', 'referral', 'referral on update'" ) # Can not change state of replicated backend replicas = Replicas(self._instance) try: # Check if replication is enabled replicas.get(suffix) raise ValueError( "Can not change the backend state of a replicated suffix") except ldap.NO_SUCH_OBJECT: pass # Ok, change the state mt.replace('nsslapd-state', new_state)
def get_agmt_maxcsn(self): """Get the agreement maxcsn from the database RUV entry :returns: CSN string if found, otherwise None is returned """ from lib389.replica import Replicas suffix = self.get_attr_val_utf8(REPL_ROOT) agmt_name = self.get_attr_val_utf8('cn') replicas = Replicas(self._instance) replica = replicas.get(suffix) maxcsns = replica.get_ruv_agmt_maxcsns() if maxcsns is None or len(maxcsns) == 0: self._log.debug( 'get_agmt_maxcsn - Failed to get agmt maxcsn from RUV') return None for csn in maxcsns: comps = csn.split(';') if agmt_name == comps[1]: # same replica, get maxcsn if len(comps) < 6: return None else: return comps[5] self._log.debug( 'get_agmt_maxcsn - did not find matching agmt maxcsn from RUV') return None
def test_demote_fail(topo, new_suffixes, clean_up, role_from): """Check that replica demote method fails when demoted to wrong direction :feature: Replication :steps: 1. Enable replication on the instance 2. Try to demote it to wrong role (for example, consumer-supplier, hub-supplier) 3. Disable replication :expectedresults: Replica shouldn't be demoted """ inst = topo.ins["standalone1"] log.info("Enable replication on instance with a role - {}".format( role_from.name)) replicas = Replicas(inst) replica = replicas.enable(suffix=NEW_SUFFIX, role=role_from, replicaID=REPLICA_SUPPLIER_ID) for role_to in [x for x in range(1, 4) if x >= role_from.value]: role_to = ReplicaRole(role_to) log.info("Try to demote replica to {}".format(role_to.name)) with pytest.raises(ValueError): replica.demote(newrole=role_to)
def test_demote(topo, new_suffixes, clean_up, role_from, role_to): """Check that replica demote method works properly :feature: Replication :steps: 1. Enable replication on the instance 2. Demote it to another role (check supplier-hub, supplier-consumer, hub-consumer) 3. Check that role was successfully changed 4. Disable replication :expectedresults: No errors happen, replica successfully demoted """ inst = topo.ins["standalone1"] log.info("Enable replication on instance with a role - {}".format( role_from.name)) replicas = Replicas(inst) replica = replicas.enable(suffix=NEW_SUFFIX, role=role_from, replicaID=REPLICA_SUPPLIER_ID) log.info("Promote replica to {}".format(role_to.name)) replica.demote(newrole=role_to) log.info("Check that replica was successfully promoted") replica_role = replica.get_role() assert replica_role == role_to
def test_replica_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-e6181209bf92 :parametrized: yes :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 """ replica_reset(topo) replicas = Replicas(topo.standalone) # Test too small perform_invalid_create(replicas, replica_dict, attr, too_small) # Test too big perform_invalid_create(replicas, replica_dict, attr, too_big) # Test overflow perform_invalid_create(replicas, replica_dict, attr, overflow) # test not a number perform_invalid_create(replicas, replica_dict, attr, notnum) # Test valid value my_replica = copy.deepcopy(replica_dict) my_replica[attr] = valid replicas.create(properties=my_replica)
def replica_setup(topo): """Add a valid replica config entry to modify """ replicas = Replicas(topo.standalone) for r in replicas.list(): r.delete() return replicas.create(properties=replica_dict)
def test_ticket50232_normal(topology_st): """ The fix for ticket 50232 The test sequence is: - create suffix - add suffix entry and some child entries - "normally" done after populating suffix: enable replication - get RUV and database generation - export -r - import - get RUV and database generation - assert database generation has not changed """ log.info('Testing Ticket 50232 - export creates not imprtable ldif file, normal creation order') topology_st.standalone.backend.create(NORMAL_SUFFIX, {BACKEND_NAME: NORMAL_BACKEND_NAME}) topology_st.standalone.mappingtree.create(NORMAL_SUFFIX, bename=NORMAL_BACKEND_NAME, parent=None) _populate_suffix(topology_st.standalone, NORMAL_BACKEND_NAME) repl = ReplicationManager(DEFAULT_SUFFIX) repl._ensure_changelog(topology_st.standalone) replicas = Replicas(topology_st.standalone) replicas.create(properties={ 'cn': 'replica', 'nsDS5ReplicaRoot': NORMAL_SUFFIX, 'nsDS5ReplicaId': '1', 'nsDS5Flags': '1', 'nsDS5ReplicaType': '3' }) _test_export_import(topology_st.standalone, NORMAL_SUFFIX, NORMAL_BACKEND_NAME)
def resume_all_replicas(self): """Resume all agreements in the class instance""" for inst in self.all_insts.values(): replicas = Replicas(inst) replica = replicas.get(DEFAULT_SUFFIX) for agreement in replica.get_agreements().list(): agreement.resume()
def fin(): for num in range(1, 4): try: replicas = Replicas(topo.ins["standalone{}".format(num)]) replicas.disable(NEW_SUFFIX) log.info("standalone{} is disabled now".format(num)) except: pass
def test_cl_encryption_setup_process(topo): """Take an already working replication deployment, and setup changelog encryption :id: 1a1b7d29-69f5-4f0e-91c4-e7f66140ff17 :setup: Master Instance, Consumer Instance :steps: 1. Enable TLS for the server 2. Export changelog 3. Enable changelog encryption 4. Import changelog 5. Verify replication is still working :expectedresults: 1. Success 2. Success 3. Success 4. Success 5. Success """ supplier = topo.ms['master1'] consumer = topo.cs['consumer1'] # Enable TLS log.info('Enable TLS ...') supplier.enable_tls() consumer.enable_tls() # Export changelog log.info('Export changelog ...') replicas = Replicas(supplier) replica = replicas.get(DEFAULT_SUFFIX) replica.begin_task_cl2ldif() replica.task_finished() # Enable changelog encryption log.info('Enable changelog encryption ...') dse_ldif = DSEldif(supplier) supplier.stop() if ds_supports_new_changelog(): changelog = 'cn=changelog,{}'.format(DN_USERROOT_LDBM) else: changelog = DN_CHANGELOG dse_ldif.replace(changelog, 'nsslapd-encryptionalgorithm', 'AES') if dse_ldif.get(changelog, 'nsSymmetricKey'): dse_ldif.delete(changelog, 'nsSymmetricKey') supplier.start() # Import changelog log.info('Import changelog ...') replica.begin_task_ldif2cl() replica.task_finished() # Verify replication is still working log.info('Test replication is still working ...') assert replica.test_replication([consumer])
def fractional_server_to_replica(server, replica): repl = ReplicationManager(DEFAULT_SUFFIX) repl.ensure_agreement(server, replica) replica_server = Replicas(server).get(DEFAULT_SUFFIX) agmt_server = replica_server.get_agreements().list()[0] agmt_server.replace_many( ('nsDS5ReplicatedAttributeListTotal', '(objectclass=*) $ EXCLUDE telephoneNumber'), ('nsDS5ReplicatedAttributeList', '(objectclass=*) $ EXCLUDE telephoneNumber'), ('nsds5ReplicaStripAttrs', 'modifiersname modifytimestamp'), )
def test_csnpurge_large_valueset(topo_m2): """Test csn generator test :id: 63e2bdb2-0a8f-4660-9465-7b80a9f72a74 :setup: MMR with 2 masters :steps: 1. Create a test_user 2. add a large set of values (more than 10) 3. delete all the values (more than 10) 4. configure the replica to purge those values (purgedelay=5s) 5. Waiting for 6 second 6. do a series of update :expectedresults: 1. Should succeeds 2. Should succeeds 3. Should succeeds 4. Should succeeds 5. Should succeeds 6. Should not crash """ m1 = topo_m2.ms["master2"] test_user = UserAccount(m1, TEST_ENTRY_DN) if test_user.exists(): log.info('Deleting entry {}'.format(TEST_ENTRY_DN)) test_user.delete() test_user.create( properties={ 'uid': TEST_ENTRY_NAME, 'cn': TEST_ENTRY_NAME, 'sn': TEST_ENTRY_NAME, 'userPassword': TEST_ENTRY_NAME, 'uidNumber': '1000', 'gidNumber': '2000', 'homeDirectory': '/home/mmrepl_test', }) # create a large value set so that it is sorted for i in range(1, 20): test_user.add('description', 'value {}'.format(str(i))) # delete all values of the valueset for i in range(1, 20): test_user.remove('description', 'value {}'.format(str(i))) # set purging delay to 5 second and wait more that 5second replicas = Replicas(m1) replica = replicas.list()[0] log.info('nsds5ReplicaPurgeDelay to 5') replica.set('nsds5ReplicaPurgeDelay', '5') time.sleep(6) # add some new values to the valueset containing entries that should be purged for i in range(21, 25): test_user.add('description', 'value {}'.format(str(i)))
def test_healthcheck_replication_replica_not_reachable(topology_m2): """Check if HealthCheck returns DSREPLLE0005 code :id: d452a564-7b82-4c1a-b331-a71abbd82a10 :setup: Replicated topology :steps: 1. Create a replicated topology 2. On M1, set nsds5replicaport for the replication agreement to an unreachable port on the replica 3. Use HealthCheck without --json option 4. Use HealthCheck with --json option 5. On M1, set nsds5replicaport for the replication agreement to a reachable port number 6. Use HealthCheck without --json option 7. Use HealthCheck with --json option :expectedresults: 1. Success 2. Success 3. Healthcheck reports DSREPLLE0005 code and related details 4. Healthcheck reports DSREPLLE0005 code and related details 5. Success 6. Healthcheck reports no issue found 7. Healthcheck reports no issue found """ RET_CODE = 'DSREPLLE0005' M1 = topology_m2.ms['supplier1'] M2 = topology_m2.ms['supplier2'] set_changelog_trimming(M1) log.info( 'Set nsds5replicaport for the replication agreement to an unreachable port' ) repl = ReplicationManager(DEFAULT_SUFFIX) repl.wait_for_replication(M1, M2) replica_m1 = Replicas(M1).get(DEFAULT_SUFFIX) agmt_m1 = replica_m1.get_agreements().list()[0] agmt_m1.replace('nsds5replicaport', '4389') # Should generates updates here to insure that we starts a new replication session # and really try to connect to the consumer with suppress(Exception): repl.wait_for_replication(M1, M2, timeout=5) run_healthcheck_and_flush_log(topology_m2, M1, RET_CODE, json=False) run_healthcheck_and_flush_log(topology_m2, M1, RET_CODE, json=True) log.info( 'Set nsds5replicaport for the replication agreement to a reachable port' ) agmt_m1.replace('nsDS5ReplicaPort', '{}'.format(M2.port)) repl.wait_for_replication(M1, M2) run_healthcheck_and_flush_log(topology_m2, M1, CMD_OUTPUT, json=False) run_healthcheck_and_flush_log(topology_m2, M1, JSON_OUTPUT, json=True)
def test_lastupdate_attr_before_init(topo_nr): """Check that LastUpdate replica attributes show right values :id: bc8ce431-ff65-41f5-9331-605cbcaaa887 :customerscenario: True :setup: Replication setup with supplier and consumer instances without initialization :steps: 1. Check nsds5replicaLastUpdateStart value 2. Check nsds5replicaLastUpdateEnd value 3. Check nsds5replicaLastUpdateStatus value 4. Check nsds5replicaLastUpdateStatusJSON is parsable :expectedresults: 1. nsds5replicaLastUpdateStart should be equal to 0 2. nsds5replicaLastUpdateEnd should be equal to 0 3. nsds5replicaLastUpdateStatus should not be equal to "Replica acquired successfully: Incremental update started" 4. Success """ supplier = topo_nr.ins["standalone1"] consumer = topo_nr.ins["standalone2"] repl = ReplicationManager(DEFAULT_SUFFIX) repl.create_first_supplier(supplier) # Manually create an un-synced consumer. consumer_replicas = Replicas(consumer) consumer_replicas.create( properties={ 'cn': 'replica', 'nsDS5ReplicaRoot': DEFAULT_SUFFIX, 'nsDS5ReplicaId': '65535', 'nsDS5Flags': '0', 'nsDS5ReplicaType': '2', }) agmt = repl.ensure_agreement(supplier, consumer) with pytest.raises(Exception): repl.wait_for_replication(supplier, consumer, timeout=5) assert agmt.get_attr_val_utf8( 'nsds5replicaLastUpdateStart') == "19700101000000Z" assert agmt.get_attr_val_utf8( "nsds5replicaLastUpdateEnd") == "19700101000000Z" assert "replica acquired successfully" not in agmt.get_attr_val_utf8_l( "nsds5replicaLastUpdateStatus") # make sure the JSON attribute is parsable json_status = agmt.get_attr_val_utf8("nsds5replicaLastUpdateStatusJSON") if json_status is not None: json_obj = json.loads(json_status) log.debug("JSON status message: {}".format(json_obj))
def _enable_replica(instance, suffix): repl = ReplicationManager(DEFAULT_SUFFIX) repl._ensure_changelog(instance) replicas = Replicas(instance) replicas.create(properties={ 'cn': 'replica', 'nsDS5ReplicaRoot': suffix, 'nsDS5ReplicaId': '1', 'nsDS5Flags': '1', 'nsDS5ReplicaType': '3' })
def test_special_symbol_replica_agreement(topo_i2): """ Check if agreement starts with "cn=->..." then after upgrade does it get removed. :id: 68aa0072-4dd4-4e33-b107-cb383a439125 :setup: two standalone instance :steps: 1. Create and Enable Replication on standalone2 and role as consumer 2. Create and Enable Replication on standalone1 and role as master 3. Create a Replication agreement starts with "cn=->..." 4. Perform an upgrade operation over the master 5. Check if the agreement is still present or not. :expectedresults: 1. It should be successful 2. It should be successful 3. It should be successful 4. It should be successful 5. It should be successful """ master = topo_i2.ins["standalone1"] consumer = topo_i2.ins["standalone2"] consumer.replica.enableReplication(suffix=DEFAULT_SUFFIX, role=ReplicaRole.CONSUMER, replicaId=CONSUMER_REPLICAID) repl = ReplicationManager(DEFAULT_SUFFIX) repl.create_first_master(master) properties = { RA_NAME: '-\\3meTo_{}:{}'.format(consumer.host, str(consumer.port)), RA_BINDDN: defaultProperties[REPLICATION_BIND_DN], RA_BINDPW: defaultProperties[REPLICATION_BIND_PW], RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD], RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT] } master.agreement.create(suffix=SUFFIX, host=consumer.host, port=consumer.port, properties=properties) master.agreement.init(SUFFIX, consumer.host, consumer.port) replica_server = Replicas(master).get(DEFAULT_SUFFIX) master.upgrade('online') agmt = replica_server.get_agreements().list()[0] assert agmt.get_attr_val_utf8('cn') == '-\\3meTo_{}:{}'.format( consumer.host, str(consumer.port))
def simple_replica(topo, new_suffixes, request): """Enable simple multi-supplier replication""" supplier1 = topo.ins["standalone1"] supplier2 = topo.ins["standalone2"] log.info("Enable two supplier replicas") replicas_m1 = Replicas(supplier1) replica_m1 = replicas_m1.enable(suffix=NEW_SUFFIX, role=ReplicaRole.SUPPLIER, replicaID=REPLICA_SUPPLIER_ID) replicas_m2 = Replicas(supplier2) replica_m2 = replicas_m2.enable(suffix=NEW_SUFFIX, role=ReplicaRole.SUPPLIER, replicaID=REPLICA_SUPPLIER_ID + 1) log.info("Create agreements between the instances") supplier1.agreement.create(suffix=NEW_SUFFIX, host=supplier2.host, port=supplier2.port) supplier2.agreement.create(suffix=NEW_SUFFIX, host=supplier1.host, port=supplier1.port) log.info("Test replication") replicas_m1.test(NEW_SUFFIX, supplier2) def fin(): replicas_m1.disable(NEW_SUFFIX) replicas_m2.disable(NEW_SUFFIX) request.addfinalizer(fin) return [replica_m1, replica_m2]
def _compare_memoryruv_and_databaseruv(topo, operation_type): """Compare the memoryruv and databaseruv for ldap operations""" log.info( 'Checking memory ruv for ldap: {} operation'.format(operation_type)) replicas = Replicas(topo.ms['master1']) replica = replicas.list()[0] memory_ruv = replica.get_attr_val_utf8('nsds50ruv') log.info( 'Checking database ruv for ldap: {} operation'.format(operation_type)) entry = replicas.get_ruv_entry(DEFAULT_SUFFIX) database_ruv = entry.getValues('nsds50ruv')[0] assert memory_ruv == database_ruv
def test_plugin_bind_dn_tracking_and_replication(topo_m2): """Testing nsslapd-plugin-binddn-tracking does not cause issues around access control and reconfiguring replication/repl agmt. :id: dd689d03-69b8-4bf9-a06e-2acd19d5e2c9 :setup: 2 supplier topology :steps: 1. Turn on plugin binddn tracking 2. Add some users 3. Make an update as a user 4. Make an update to the replica config 5. Make an update to the repliocation agreement :expectedresults: 1. Success 2. Success 3. Success 4. Success 5. Success """ m1 = topo_m2.ms["supplier1"] # Turn on bind dn tracking m1.config.set('nsslapd-plugin-binddn-tracking', 'on') # Add two users users = UserAccounts(m1, DEFAULT_SUFFIX) user1 = users.create_test_user(uid=1011) user1.set('userpassword', PASSWORD) user2 = users.create_test_user(uid=1012) # Add an aci acival = '(targetattr ="cn")(version 3.0;acl "Test bind dn tracking"' + \ ';allow (all) (userdn = "ldap:///{}");)'.format(user1.dn) Domain(m1, DEFAULT_SUFFIX).add('aci', acival) # Bind as user and make an update user1.rebind(PASSWORD) user2.set('cn', 'new value') dm = DirectoryManager(m1) dm.rebind() # modify replica replica = Replicas(m1).get(DEFAULT_SUFFIX) replica.set(REPL_PROTOCOL_TIMEOUT, "30") # modify repl agmt agmt = replica.get_agreements().list()[0] agmt.set(REPL_PROTOCOL_TIMEOUT, "20")
def verify_keepalive_entries(topo, expected): # Check that keep alive entries exists (or not exists) for every suppliers on every suppliers # Note: The testing method is quite basic: counting that there is one keepalive entry per supplier. # that is ok for simple test cases like test_online_init_should_create_keepalive_entries but # not for the general case as keep alive associated with no more existing supplier may exists # (for example after: db2ldif / demote a supplier / ldif2db / init other suppliers) # ==> if the function is somehow pushed in lib389, a check better than simply counting the entries # should be done. for supplierId in topo.ms: supplier = topo.ms[supplierId] for replica in Replicas(supplier).list(): if (replica.get_role() != ReplicaRole.SUPPLIER): continue replica_info = f'supplier: {supplierId} RID: {replica.get_rid()} suffix: {replica.get_suffix()}' log.debug(f'Checking keepAliveEntries on {replica_info}') keepaliveEntries = get_keepalive_entries(supplier, replica) expectedCount = len(topo.ms) if expected else 0 foundCount = len(keepaliveEntries) if (foundCount == expectedCount): log.debug( f'Found {foundCount} keepalive entries as expected on {replica_info}.' ) else: log.error( f'{foundCount} Keepalive entries are found ' f'while {expectedCount} were expected on {replica_info}.') assert False
def test_lastupdate_attr_before_init(topo_nr): """Check that LastUpdate replica attributes show right values :id: bc8ce431-ff65-41f5-9331-605cbcaaa887 :setup: Replication setup with master and consumer instances without initialization :steps: 1. Check nsds5replicaLastUpdateStart value 2. Check nsds5replicaLastUpdateEnd value 3. Check nsds5replicaLastUpdateStatus value :expectedresults: 1. nsds5replicaLastUpdateStart should be equal to 0 2. nsds5replicaLastUpdateEnd should be equal to 0 3. nsds5replicaLastUpdateStatus should not be equal to "0 Replica acquired successfully: Incremental update started" """ master = topo_nr.ins["standalone1"] consumer = topo_nr.ins["standalone2"] repl = ReplicationManager(DEFAULT_SUFFIX) repl.create_first_master(master) # Manually create an un-synced consumer. consumer_replicas = Replicas(consumer) consumer_replicas.create( properties={ 'cn': 'replica', 'nsDS5ReplicaRoot': DEFAULT_SUFFIX, 'nsDS5ReplicaId': '65535', 'nsDS5Flags': '0', 'nsDS5ReplicaType': '2', }) agmt = repl.ensure_agreement(master, consumer) with pytest.raises(Exception): repl.wait_for_replication(master, consumer, timeout=5) assert agmt.get_attr_val_bytes( 'nsds5replicaLastUpdateStart') == b"19700101000000Z" assert agmt.get_attr_val_bytes( "nsds5replicaLastUpdateEnd") == b"19700101000000Z" assert b"Replica acquired successfully" not in agmt.get_attr_val_bytes( "nsds5replicaLastUpdateStatus")
def test_invalid_agmt(topo_m2): """Test adding that an invalid agreement is properly rejected and does not crash the server :id: 6c3b2a7e-edcd-4327-a003-6bd878ff722b :setup: Four masters replication setup :steps: 1. Add invalid agreement (nsds5ReplicaEnabled set to invalid value) 2. Verify the server is still running :expectedresults: 1. Invalid repl agreement should be rejected 2. Server should be still running """ m1 = topo_m2.ms["master1"] m2 = topo_m2.ms["master2"] repl = ReplicationManager(DEFAULT_SUFFIX) replicas = Replicas(m1) replica = replicas.get(DEFAULT_SUFFIX) agmts = replica.get_agreements() # Add invalid agreement (nsds5ReplicaEnabled set to invalid value) with pytest.raises(ldap.UNWILLING_TO_PERFORM): agmts.create( properties={ 'cn': 'whatever', 'nsDS5ReplicaRoot': DEFAULT_SUFFIX, 'nsDS5ReplicaBindDN': 'cn=replication manager,cn=config', 'nsDS5ReplicaBindMethod': 'simple', 'nsDS5ReplicaTransportInfo': 'LDAP', 'nsds5replicaTimeout': '5', 'description': "test agreement", 'nsDS5ReplicaHost': m2.host, 'nsDS5ReplicaPort': str(m2.port), 'nsDS5ReplicaCredentials': 'whatever', 'nsds5ReplicaEnabled': 'YEAH MATE, LETS REPLICATE' }) # Verify the server is still running repl = ReplicationManager(DEFAULT_SUFFIX) repl.test_replication(m1, m2) repl.test_replication(m2, m1)
def _lint_cl_trimming(self): """Check that cl trimming is at least defined to prevent unbounded growth""" suffix = self.get_attr_val_utf8('nsslapd-suffix') replicas = Replicas(self._instance) replica = replicas.get(suffix) bename = self.lint_uid() if replica is not None: cl = Changelog(self._instance, suffix=suffix) try: if cl.get_attr_val_utf8('nsslapd-changelogmaxentries') is None and \ cl.get_attr_val_utf8('nsslapd-changelogmaxage') is None: report = copy.deepcopy(DSCLLE0001) report['fix'] = report['fix'].replace( 'YOUR_INSTANCE', self._instance.serverid) report['check'] = f'backends:{bename}::cl_trimming' yield report except: # No changelog pass
def check_ruvs(msg, topology_m4, m4rid): """Check suppliers 1- 3 for supplier 4's rid.""" for inst in (topology_m4.ms["supplier1"], topology_m4.ms["supplier2"], topology_m4.ms["supplier3"]): clean = False replicas = Replicas(inst) replica = replicas.get(DEFAULT_SUFFIX) log.info('check_ruvs for replica %s:%s (suffix:rid)' % (replica.get_suffix(), replica.get_rid())) count = 0 while not clean and count < 20: ruv = replica.get_ruv() if m4rid in ruv._rids: time.sleep(5) count = count + 1 else: clean = True if not clean: raise Exception("Supplier %s was not cleaned in time." % inst.serverid) return True
def _create_changelog_dump(topo): """Dump changelog using nss5task and check if ldap operations are logged""" log.info( 'Dump changelog using nss5task and check if ldap operations are logged' ) if ds_supports_new_changelog(): changelog_dir = topo.ms['supplier1'].get_ldif_dir() changelog_end = '_cl.ldif' else: changelog_dir = topo.ms['supplier1'].get_changelog_dir() changelog_end = '.ldif' replicas = Replicas(topo.ms["supplier1"]) replica = replicas.get(DEFAULT_SUFFIX) log.info('Remove ldif files, if present in: {}'.format(changelog_dir)) for files in os.listdir(changelog_dir): if files.endswith(changelog_end): changelog_file = os.path.join(changelog_dir, files) try: os.remove(changelog_file) except OSError as e: log.fatal( 'Failed to remove ldif file: {}'.format(changelog_file)) raise e log.info('Existing changelog ldif file: {} removed'.format( changelog_file)) else: log.info('No existing changelog ldif files present') log.info('Running nsds5task to dump changelog database to a file') replica.begin_task_cl2ldif() log.info('Check if changelog ldif file exist in: {}'.format(changelog_dir)) for files in os.listdir(changelog_dir): if files.endswith(changelog_end): changelog_ldif = os.path.join(changelog_dir, files) log.info('Changelog ldif file exist: {}'.format(changelog_ldif)) return changelog_ldif else: log.fatal( 'Changelog ldif file does not exist in: {}'.format(changelog_dir)) assert False
def check_ruvs(msg, topology_m4, m4rid): """Check masters 1- 3 for master 4's rid.""" for inst in (topology_m4.ms["master1"], topology_m4.ms["master2"], topology_m4.ms["master3"]): clean = False replicas = Replicas(inst) replica = replicas.get(DEFAULT_SUFFIX) count = 0 while not clean and count < 10: ruv = replica.get_ruv() if m4rid in ruv._rids: time.sleep(5) count = count + 1 else: clean = True if not clean: raise Exception("Master %s was not cleaned in time." % inst.serverid) return True
def _lint_cl_trimming(self): """Check that cl trimming is at least defined to prevent unbounded growth""" bename = self.lint_uid() suffix = self.get_attr_val_utf8('nsslapd-suffix') replicas = Replicas(self._instance) try: # Check if replication is enabled replicas.get(suffix) # Check the changelog cl = Changelog(self._instance, suffix=suffix) if cl.get_attr_val_utf8('nsslapd-changelogmaxentries') is None and \ cl.get_attr_val_utf8('nsslapd-changelogmaxage') is None: report = copy.deepcopy(DSCLLE0001) report['fix'] = report['fix'].replace('YOUR_INSTANCE', self._instance.serverid) report['check'] = f'backends:{bename}::cl_trimming' yield report except: # Suffix is not replicated self._log.debug( f"_lint_cl_trimming - backend ({suffix}) is not replicated") pass
def test_multiple_changelogs(topo): """Test the multiple suffixes can be replicated with the new per backend changelog. :id: eafcdb57-4ea2-4887-a0a8-9e4d295f4f4d :setup: Supplier Instance, Consumer Instance :steps: 1. Create s second suffix 2. Enable replication for second backend 3. Perform some updates on both backends and make sure replication is working for both backends :expectedresults: 1. Success 2. Success 3. Success """ supplier = topo.ms['supplier1'] consumer = topo.cs['consumer1'] # Create second suffix dc=second_backend on both replicas for inst in [supplier, consumer]: # Create the backends props = {'cn': 'secondRoot', 'nsslapd-suffix': SECOND_SUFFIX} be = Backend(inst) be.create(properties=props) be.create_sample_entries('001004002') # Setup replication for second suffix repl = ReplicationManager(SECOND_SUFFIX) repl.create_first_supplier(supplier) repl.join_consumer(supplier, consumer) # Test replication works for each backend for suffix in [DEFAULT_SUFFIX, SECOND_SUFFIX]: replicas = Replicas(supplier) replica = replicas.get(suffix) log.info("Testing replication for: " + suffix) assert replica.test_replication([consumer])
def test_same_attr_yields_same_return_code(topo): """Test that various operations with same incorrect attribute value yield same return code """ attr = 'nsDS5ReplicaId' replica_reset(topo) replicas = Replicas(topo.standalone) e = perform_invalid_create(replicas, replica_dict, attr, too_big) assert type(e) is ldap.UNWILLING_TO_PERFORM replica = replica_setup(topo) e = perform_invalid_modify(replica, attr, too_big) assert type(e) is ldap.UNWILLING_TO_PERFORM
def test_warining_for_invalid_replica(topo_m4): """Testing logs to indicate the inconsistency when configuration is performed. :id: dd689d03-69b8-4bf9-a06e-2acd19d5e2c8 :setup: MMR with four masters :steps: 1. Setup nsds5ReplicaBackoffMin to 20 2. Setup nsds5ReplicaBackoffMax to 10 :expectedresults: 1. nsds5ReplicaBackoffMin should set to 20 2. An error should be generated and also logged in the error logs. """ replicas = Replicas(topo_m4.ms["master1"]) replica = replicas.list()[0] log.info('Set nsds5ReplicaBackoffMin to 20') replica.set('nsds5ReplicaBackoffMin', '20') with pytest.raises(ldap.UNWILLING_TO_PERFORM): log.info('Set nsds5ReplicaBackoffMax to 10') replica.set('nsds5ReplicaBackoffMax', '10') log.info('Resetting configuration: nsds5ReplicaBackoffMin') replica.remove_all('nsds5ReplicaBackoffMin') log.info('Check the error log for the error') assert topo_m4.ms["master1"].ds_error_log.match( '.*nsds5ReplicaBackoffMax.*10.*invalid.*')