def test_retrocl_exclude_attr_add(topology_st): """ Test exclude attribute feature of the retrocl plugin for add operation :id: 3481650f-2070-45ef-9600-2500cfc51559 :setup: Standalone instance :steps: 1. Enable dynamic plugins 2. Confige retro changelog plugin 3. Add an entry 4. Ensure entry attrs are in the changelog 5. Exclude an attr 6. Add another entry 7. Ensure excluded attr is not in the changelog :expectedresults: 1. Success 2. Success 3. Success 4. Success 5. Success 6. Success 7. Success """ st = topology_st.standalone log.info('Configure retrocl plugin') rcl = RetroChangelogPlugin(st) rcl.disable() rcl.enable() rcl.replace('nsslapd-attribute', 'nsuniqueid:targetUniqueId') log.info('Restarting instance') try: st.restart() except ldap.LDAPError as e: ldap.error('Failed to restart instance ' + e.args[0]['desc']) assert False users = UserAccounts(st, DEFAULT_SUFFIX) log.info('Adding user1') try: users.create( properties={ 'sn': '1', 'cn': 'user 1', 'uid': 'user1', 'uidNumber': '11', 'gidNumber': '111', 'givenname': 'user1', 'homePhone': '0861234567', 'carLicense': '131D16674', 'mail': '*****@*****.**', 'homeDirectory': '/home/user1', 'userpassword': USER_PW }) except ldap.ALREADY_EXISTS: pass except ldap.LDAPError as e: log.error("Failed to add user1: " + str(e)) log.info( 'Verify homePhone and carLicense attrs are in the changelog changestring' ) try: retro_changelog_suffix = DSLdapObjects(st, basedn=RETROCL_SUFFIX) cllist = retro_changelog_suffix.filter(f'(targetDn={USER1_DN})') except ldap.LDAPError as e: log.fatal("Changelog search failed, error: " + str(e)) assert False assert len(cllist) > 0 if cllist[0].present('changes'): clstr = str(cllist[0].get_attr_vals_utf8('changes')) assert ATTR_HOMEPHONE in clstr assert ATTR_CARLICENSE in clstr log.info('Excluding attribute ' + ATTR_HOMEPHONE) args = FakeArgs() args.connections = [ st.host + ':' + str(st.port) + ':' + DN_DM + ':' + PW_DM ] args.instance = 'standalone1' args.basedn = None args.binddn = None args.starttls = False args.pwdfile = None args.bindpw = None args.prompt = False args.exclude_attrs = ATTR_HOMEPHONE args.func = retrochangelog_add dsrc_inst = dsrc_arg_concat(args, None) inst = connect_instance(dsrc_inst, False, args) result = args.func(inst, None, log, args) disconnect_instance(inst) assert result is None log.info('Restarting instance') try: st.restart() except ldap.LDAPError as e: ldap.error('Failed to restart instance ' + e.args[0]['desc']) assert False log.info('Adding user2') try: users.create( properties={ 'sn': '2', 'cn': 'user 2', 'uid': 'user2', 'uidNumber': '22', 'gidNumber': '222', 'givenname': 'user2', 'homePhone': '0879088363', 'carLicense': '04WX11038', 'mail': '*****@*****.**', 'homeDirectory': '/home/user2', 'userpassword': USER_PW }) except ldap.ALREADY_EXISTS: pass except ldap.LDAPError as e: log.error("Failed to add user2: " + str(e)) log.info('Verify homePhone attr is not in the changelog changestring') try: cllist = retro_changelog_suffix.filter(f'(targetDn={USER2_DN})') assert len(cllist) > 0 if cllist[0].present('changes'): clstr = str(cllist[0].get_attr_vals_utf8('changes')) assert ATTR_HOMEPHONE not in clstr assert ATTR_CARLICENSE in clstr except ldap.LDAPError as e: log.fatal("Changelog search failed, error: " + str(e)) assert False
def test_dsconf_replication_monitor(topology_m2, set_log_file): """Test replication monitor that was ported from legacy tools :id: ce48020d-7c30-41b7-8f68-144c9cd757f6 :setup: 2 MM topology :steps: 1. Create DS instance 2. Run replication monitor with connections option 3. Run replication monitor with aliases option 4. Run replication monitor with --json option 5. Run replication monitor with .dsrc file created 6. Run replication monitor with connections option as if using dsconf CLI :expectedresults: 1. Success 2. Success 3. Success 4. Success 5. Success 6. Success """ m1 = topology_m2.ms["master1"] m2 = topology_m2.ms["master2"] # Enable ldapi if not already done. for inst in [topology_m2.ms["master1"], topology_m2.ms["master2"]]: if not inst.can_autobind(): # Update ns-slapd instance inst.config.set('nsslapd-ldapilisten', 'on') inst.config.set('nsslapd-ldapiautobind', 'on') inst.restart() # Ensure that updates have been sent both ways. replicas = Replicas(m1) replica = replicas.get(DEFAULT_SUFFIX) replica.test_replication([m2]) replicas = Replicas(m2) replica = replicas.get(DEFAULT_SUFFIX) replica.test_replication([m1]) alias_content = [ 'Supplier: M1 (' + m1.host + ':' + str(m1.port) + ')', 'Supplier: M2 (' + m2.host + ':' + str(m2.port) + ')' ] connection_content = 'Supplier: ' + m1.host + ':' + str(m1.port) content_list = [ 'Replica Root: dc=example,dc=com', 'Replica ID: 1', 'Replica Status: Available', 'Max CSN', 'Status For Agreement: "002" (' + m2.host + ':' + str(m2.port) + ')', 'Replica Enabled: on', 'Update In Progress: FALSE', 'Last Update Start:', 'Last Update End:', 'Number Of Changes Sent:', 'Number Of Changes Skipped: None', 'Last Update Status: Error (0) Replica acquired successfully: Incremental update succeeded', 'Last Init Start:', 'Last Init End:', 'Last Init Status:', 'Reap Active: 0', 'Replication Status: In Synchronization', 'Replication Lag Time:', 'Supplier: ', m2.host + ':' + str(m2.port), 'Replica Root: dc=example,dc=com', 'Replica ID: 2', 'Status For Agreement: "001" (' + m1.host + ':' + str(m1.port) + ')' ] error_list = [ 'consumer (Unavailable)', 'Failed to retrieve database RUV entry from consumer' ] json_list = [ 'type', 'list', 'items', 'name', m1.host + ':' + str(m1.port), 'data', '"replica_id": "1"', '"replica_root": "dc=example,dc=com"', '"replica_status": "Available"', 'maxcsn', 'agmts_status', 'agmt-name', '002', 'replica', m2.host + ':' + str(m2.port), 'replica-enabled', 'update-in-progress', 'last-update-start', 'last-update-end', 'number-changes-sent', 'number-changes-skipped', 'last-update-status', 'Error (0) Replica acquired successfully: Incremental update succeeded', 'last-init-start', 'last-init-end', 'last-init-status', 'reap-active', 'replication-status', 'In Synchronization', 'replication-lag-time', '"replica_id": "2"', '001', m1.host + ':' + str(m1.port) ] connections = [ m1.host + ':' + str(m1.port) + ':' + DN_DM + ':' + PW_DM, m2.host + ':' + str(m2.port) + ':' + DN_DM + ':' + PW_DM ] args = FakeArgs() args.connections = connections args.aliases = None args.json = False log.info('Run replication monitor with connections option') get_repl_monitor_info(m1, DEFAULT_SUFFIX, log, args) (host_m1, host_m2) = get_hostnames_from_log(m1.port, m2.port) check_value_in_log_and_reset(content_list, connection_content, error_list=error_list) # Prepare the data for next tests aliases = [ 'M1=' + host_m1 + ':' + str(m1.port), 'M2=' + host_m2 + ':' + str(m2.port) ] alias_content = [ 'Supplier: M1 (' + host_m1 + ':' + str(m1.port) + ')', 'Supplier: M2 (' + host_m2 + ':' + str(m2.port) + ')' ] dsrc_content = '[repl-monitor-connections]\n' \ 'connection1 = ' + m1.host + ':' + str(m1.port) + ':' + DN_DM + ':' + PW_DM + '\n' \ 'connection2 = ' + m2.host + ':' + str(m2.port) + ':' + DN_DM + ':' + PW_DM + '\n' \ '\n' \ '[repl-monitor-aliases]\n' \ 'M1 = ' + host_m1 + ':' + str(m1.port) + '\n' \ 'M2 = ' + host_m2 + ':' + str(m2.port) log.info('Run replication monitor with aliases option') args.aliases = aliases get_repl_monitor_info(m1, DEFAULT_SUFFIX, log, args) check_value_in_log_and_reset(content_list, alias_content) log.info('Run replication monitor with --json option') args.aliases = None args.json = True get_repl_monitor_info(m1, DEFAULT_SUFFIX, log, args) check_value_in_log_and_reset(json_list) with open(os.path.expanduser(DSRC_HOME), 'w+') as f: f.write(dsrc_content) args.connections = None args.aliases = None args.json = False log.info('Run replication monitor when .dsrc file is present with content') get_repl_monitor_info(m1, DEFAULT_SUFFIX, log, args) check_value_in_log_and_reset(content_list, alias_content) os.remove(os.path.expanduser(DSRC_HOME)) log.info( 'Run replication monitor with connections option as if using dsconf CLI' ) # Perform same test than steps 2 test but without using directly the topology instance. # but with an instance similar to those than dsconf cli generates: # step 2 args args.connections = connections args.aliases = None args.json = False # args needed to generate an instance with dsrc_arg_concat args.instance = 'master1' args.basedn = None args.binddn = None args.bindpw = None args.pwdfile = None args.prompt = False args.starttls = False dsrc_inst = dsrc_arg_concat(args, None) inst = connect_instance(dsrc_inst, True, args) get_repl_monitor_info(inst, DEFAULT_SUFFIX, log, args) check_value_in_log_and_reset(content_list, connection_content, error_list=error_list)
def test_retrocl_exclude_attr_mod(topology_st): """ Test exclude attribute feature of the retrocl plugin for mod operation :id: f6bef689-685b-4f86-a98d-f7e6b1fcada3 :setup: Standalone instance :steps: 1. Enable dynamic plugins 2. Confige retro changelog plugin 3. Add user1 entry 4. Ensure entry attrs are in the changelog 5. Exclude an attr 6. Modify user1 entry 7. Ensure excluded attr is not in the changelog :expectedresults: 1. Success 2. Success 3. Success 4. Success 5. Success 6. Success 7. Success """ st = topology_st.standalone log.info('Configure retrocl plugin') rcl = RetroChangelogPlugin(st) rcl.disable() rcl.enable() rcl.replace('nsslapd-attribute', 'nsuniqueid:targetUniqueId') log.info('Restarting instance') try: st.restart() except ldap.LDAPError as e: ldap.error('Failed to restart instance ' + e.args[0]['desc']) assert False users = UserAccounts(st, DEFAULT_SUFFIX) log.info('Adding user1') try: user1 = users.create( properties={ 'sn': '1', 'cn': 'user 1', 'uid': 'user1', 'uidNumber': '11', 'gidNumber': '111', 'givenname': 'user1', 'homePhone': '0861234567', 'carLicense': '131D16674', 'mail': '*****@*****.**', 'homeDirectory': '/home/user1', 'userpassword': USER_PW }) except ldap.ALREADY_EXISTS: user1 = UserAccount(st, dn=USER1_DN) except ldap.LDAPError as e: log.error("Failed to add user1: " + str(e)) log.info( 'Verify homePhone and carLicense attrs are in the changelog changestring' ) try: retro_changelog_suffix = DSLdapObjects(st, basedn=RETROCL_SUFFIX) cllist = retro_changelog_suffix.filter(f'(targetDn={USER1_DN})') except ldap.LDAPError as e: log.fatal("Changelog search failed, error: " + str(e)) assert False assert len(cllist) > 0 if cllist[0].present('changes'): clstr = str(cllist[0].get_attr_vals_utf8('changes')) assert ATTR_HOMEPHONE in clstr assert ATTR_CARLICENSE in clstr log.info('Excluding attribute ' + ATTR_CARLICENSE) args = FakeArgs() args.connections = [ st.host + ':' + str(st.port) + ':' + DN_DM + ':' + PW_DM ] args.instance = 'standalone1' args.basedn = None args.binddn = None args.starttls = False args.pwdfile = None args.bindpw = None args.prompt = False args.exclude_attrs = ATTR_CARLICENSE args.func = retrochangelog_add dsrc_inst = dsrc_arg_concat(args, None) inst = connect_instance(dsrc_inst, False, args) result = args.func(inst, None, log, args) disconnect_instance(inst) assert result is None log.info('Restarting instance') try: st.restart() except ldap.LDAPError as e: ldap.error('Failed to restart instance ' + e.args[0]['desc']) assert False log.info('Modify user1 carLicense attribute') try: user1.replace(ATTR_CARLICENSE, "123WX321") except ldap.LDAPError as e: log.fatal( 'test_retrocl_exclude_attr_mod: Failed to update user1 attribute: error ' + e.message['desc']) assert False log.info('Verify carLicense attr is not in the changelog changestring') try: cllist = retro_changelog_suffix.filter(f'(targetDn={USER1_DN})') assert len(cllist) > 0 # There will be 2 entries in the changelog for this user, we are only #interested in the second one, the modify operation. if cllist[1].present('changes'): clstr = str(cllist[1].get_attr_vals_utf8('changes')) assert ATTR_CARLICENSE not in clstr except ldap.LDAPError as e: log.fatal("Changelog search failed, error: " + str(e)) assert False
def test_dsrc(topo, setup): """Test "dsctl dsrc" command :id: 0610de6c-e167-4761-bdab-3e677b2d44bb :setup: Standalone Instance :steps: 1. Test creation works 2. Test creating duplicate section 3. Test adding an additional inst config works 4. Test removing an instance works 5. Test modify works 6. Test delete works 7. Test display fails when no file is present :expectedresults: 1. Success 2. Success 3. Success 4. Success 5. Success 6. Success 7. Success """ inst = topo.standalone serverid = inst.serverid second_inst_name = "Second" second_inst_basedn = "o=second" different_suffix = "o=different" # Setup our args args = FakeArgs() args.basedn = DEFAULT_SUFFIX args.binddn = DN_DM args.json = None args.uri = None args.saslmech = None args.tls_cacertdir = None args.tls_cert = None args.tls_key = None args.tls_reqcert = None args.starttls = None args.cancel_starttls = None args.pwdfile = None args.do_it = True # Create a dsrc configuration entry create_dsrc(inst, log, args) display_dsrc(inst, topo.logcap.log, args) assert topo.logcap.contains("basedn = " + args.basedn) assert topo.logcap.contains("binddn = " + args.binddn) assert topo.logcap.contains("[" + serverid + "]") topo.logcap.flush() # Attempt to add duplicate instance section with pytest.raises(ValueError): create_dsrc(inst, log, args) # Test adding a second instance works correctly inst.serverid = second_inst_name args.basedn = second_inst_basedn create_dsrc(inst, log, args) display_dsrc(inst, topo.logcap.log, args) assert topo.logcap.contains("basedn = " + args.basedn) assert topo.logcap.contains("[" + second_inst_name + "]") topo.logcap.flush() # Delete second instance delete_dsrc(inst, log, args) inst.serverid = serverid # Restore original instance name display_dsrc(inst, topo.logcap.log, args) assert not topo.logcap.contains("[" + second_inst_name + "]") assert not topo.logcap.contains("basedn = " + args.basedn) # Make sure first instance config is still present assert topo.logcap.contains("[" + serverid + "]") assert topo.logcap.contains("binddn = " + args.binddn) topo.logcap.flush() # Modify the config args.basedn = different_suffix modify_dsrc(inst, log, args) display_dsrc(inst, topo.logcap.log, args) assert topo.logcap.contains(different_suffix) topo.logcap.flush() # Remove an arg from the config args.basedn = "" modify_dsrc(inst, log, args) display_dsrc(inst, topo.logcap.log, args) assert not topo.logcap.contains(different_suffix) topo.logcap.flush() # Remove the last entry, which should delete the file delete_dsrc(inst, log, args) dsrc_file = f'{expanduser("~")}/.dsrc' assert not os.path.exists(dsrc_file) # Make sure display fails with pytest.raises(ValueError): display_dsrc(inst, log, args)