| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- # --- BEGIN COPYRIGHT BLOCK ---
- # Copyright (C) 2017 Red Hat, Inc.
- # All rights reserved.
- #
- # License: GPL (version 3 or any later version).
- # See LICENSE for details.
- # --- END COPYRIGHT BLOCK ---
- #
- import pytest
- from lib389.tasks import *
- from lib389.utils import *
- from lib389.topologies import topology_m2c2 as topo
- from lib389._constants import (PLUGIN_ACCT_POLICY, DN_PLUGIN, DN_CONFIG, DN_DM, PASSWORD,
- DEFAULT_SUFFIX, SUFFIX)
- pytestmark = pytest.mark.tier2
- DEBUGGING = os.getenv("DEBUGGING", default=False)
- if DEBUGGING:
- logging.getLogger(__name__).setLevel(logging.DEBUG)
- else:
- logging.getLogger(__name__).setLevel(logging.INFO)
- log = logging.getLogger(__name__)
- ACCPOL_DN = "cn={},{}".format(PLUGIN_ACCT_POLICY, DN_PLUGIN)
- ACCP_CONF = "{},{}".format(DN_CONFIG, ACCPOL_DN)
- USER_PW = 'Secret123'
- def _last_login_time(topo, userdn, inst_name, last_login):
- """Find lastLoginTime attribute value for a given master/consumer"""
- if 'master' in inst_name:
- if (last_login == 'bind_n_check'):
- topo.ms[inst_name].simple_bind_s(userdn, USER_PW)
- topo.ms[inst_name].simple_bind_s(DN_DM, PASSWORD)
- entry = topo.ms[inst_name].search_s(userdn, ldap.SCOPE_BASE, 'objectClass=*', ['lastLoginTime'])
- else:
- if (last_login == 'bind_n_check'):
- topo.cs[inst_name].simple_bind_s(userdn, USER_PW)
- topo.cs[inst_name].simple_bind_s(DN_DM, PASSWORD)
- entry = topo.cs[inst_name].search_s(userdn, ldap.SCOPE_BASE, 'objectClass=*', ['lastLoginTime'])
- lastLogin = entry[0].lastLoginTime
- time.sleep(1)
- return lastLogin
- def _enable_plugin(topo, inst_name):
- """Enable account policy plugin and configure required attributes"""
- log.info('Enable account policy plugin and configure required attributes')
- if 'master' in inst_name:
- log.info('Configure Account policy plugin on {}'.format(inst_name))
- topo.ms[inst_name].simple_bind_s(DN_DM, PASSWORD)
- try:
- topo.ms[inst_name].plugins.enable(name=PLUGIN_ACCT_POLICY)
- topo.ms[inst_name].modify_s(ACCPOL_DN, [(ldap.MOD_REPLACE, 'nsslapd-pluginarg0', ensure_bytes(ACCP_CONF))])
- topo.ms[inst_name].modify_s(ACCP_CONF, [(ldap.MOD_REPLACE, 'alwaysrecordlogin', b'yes')])
- topo.ms[inst_name].modify_s(ACCP_CONF, [(ldap.MOD_REPLACE, 'stateattrname', b'lastLoginTime')])
- topo.ms[inst_name].modify_s(ACCP_CONF, [(ldap.MOD_REPLACE, 'altstateattrname', b'createTimestamp')])
- topo.ms[inst_name].modify_s(ACCP_CONF, [(ldap.MOD_REPLACE, 'specattrname', b'acctPolicySubentry')])
- topo.ms[inst_name].modify_s(ACCP_CONF, [(ldap.MOD_REPLACE, 'limitattrname', b'accountInactivityLimit')])
- topo.ms[inst_name].modify_s(ACCP_CONF, [(ldap.MOD_REPLACE, 'accountInactivityLimit', b'3600')])
- except ldap.LDAPError as e:
- log.error('Failed to configure {} plugin for inst-{} error: {}'.format(PLUGIN_ACCT_POLICY, inst_name, str(e)))
- topo.ms[inst_name].restart(timeout=10)
- else:
- log.info('Configure Account policy plugin on {}'.format(inst_name))
- topo.cs[inst_name].simple_bind_s(DN_DM, PASSWORD)
- try:
- topo.cs[inst_name].plugins.enable(name=PLUGIN_ACCT_POLICY)
- topo.cs[inst_name].modify_s(ACCPOL_DN, [(ldap.MOD_REPLACE, 'nsslapd-pluginarg0', ensure_bytes(ACCP_CONF))])
- topo.cs[inst_name].modify_s(ACCP_CONF, [(ldap.MOD_REPLACE, 'alwaysrecordlogin', b'yes')])
- topo.cs[inst_name].modify_s(ACCP_CONF, [(ldap.MOD_REPLACE, 'stateattrname', b'lastLoginTime')])
- topo.cs[inst_name].modify_s(ACCP_CONF, [(ldap.MOD_REPLACE, 'altstateattrname', b'createTimestamp')])
- topo.cs[inst_name].modify_s(ACCP_CONF, [(ldap.MOD_REPLACE, 'specattrname', b'acctPolicySubentry')])
- topo.cs[inst_name].modify_s(ACCP_CONF, [(ldap.MOD_REPLACE, 'limitattrname', b'accountInactivityLimit')])
- topo.cs[inst_name].modify_s(ACCP_CONF, [(ldap.MOD_REPLACE, 'accountInactivityLimit', b'3600')])
- except ldap.LDAPError as e:
- log.error('Failed to configure {} plugin for inst-{} error {}'.format(PLUGIN_ACCT_POLICY, inst_name, str(e)))
- topo.cs[inst_name].restart(timeout=10)
- def test_ticket48944(topo):
- """On a read only replica invalid state info can accumulate
- :id: 833be131-f3bf-493e-97c6-3121438a07b1
- :feature: Account Policy Plugin
- :setup: Two master and two consumer setup
- :steps: 1. Configure Account policy plugin with alwaysrecordlogin set to yes
- 2. Check if entries are synced across masters and consumers
- 3. Stop all masters and consumers
- 4. Start master1 and bind as user1 to create lastLoginTime attribute
- 5. Start master2 and wait for the sync of lastLoginTime attribute
- 6. Stop master1 and bind as user1 from master2
- 7. Check if lastLoginTime attribute is updated and greater than master1
- 8. Stop master2, start consumer1, consumer2 and then master2
- 9. Check if lastLoginTime attribute is updated on both consumers
- 10. Bind as user1 to both consumers and check the value is updated
- 11. Check if lastLoginTime attribute is not updated from consumers
- 12. Start master1 and make sure the lastLoginTime attribute is not updated on consumers
- 13. Bind as user1 from master1 and check if all masters and consumers have the same value
- 14. Check error logs of consumers for "deletedattribute;deleted" message
- :expectedresults: No accumulation of replica invalid state info on consumers
- """
- log.info("Ticket 48944 - On a read only replica invalid state info can accumulate")
- user_name = 'newbzusr'
- tuserdn = 'uid={}1,ou=people,{}'.format(user_name, SUFFIX)
- inst_list = ['master1', 'master2', 'consumer1', 'consumer2']
- for inst_name in inst_list:
- _enable_plugin(topo, inst_name)
- log.info('Sleep for 10secs for the server to come up')
- time.sleep(10)
- log.info('Add few entries to server and check if entries are replicated')
- for nos in range(10):
- userdn = 'uid={}{},ou=people,{}'.format(user_name, nos, SUFFIX)
- try:
- topo.ms['master1'].add_s(Entry((userdn, {
- 'objectclass': 'top person'.split(),
- 'objectclass': 'inetorgperson',
- 'cn': user_name,
- 'sn': user_name,
- 'userpassword': USER_PW,
- 'mail': '{}@redhat.com'.format(user_name)})))
- except ldap.LDAPError as e:
- log.error('Failed to add {} user: error {}'.format(userdn, e.message['desc']))
- raise e
- log.info('Checking if entries are synced across masters and consumers')
- entries_m1 = topo.ms['master1'].search_s(SUFFIX, ldap.SCOPE_SUBTREE, 'uid={}*'.format(user_name), ['uid=*'])
- exp_entries = str(entries_m1).count('dn: uid={}*'.format(user_name))
- entries_m2 = topo.ms['master2'].search_s(SUFFIX, ldap.SCOPE_SUBTREE, 'uid={}*'.format(user_name), ['uid=*'])
- act_entries = str(entries_m2).count('dn: uid={}*'.format(user_name))
- assert act_entries == exp_entries
- inst_list = ['consumer1', 'consumer2']
- for inst in inst_list:
- entries_other = topo.cs[inst].search_s(SUFFIX, ldap.SCOPE_SUBTREE, 'uid={}*'.format(user_name), ['uid=*'])
- act_entries = str(entries_other).count('dn: uid={}*'.format(user_name))
- assert act_entries == exp_entries
- topo.ms['master2'].stop(timeout=10)
- topo.ms['master1'].stop(timeout=10)
- topo.cs['consumer1'].stop(timeout=10)
- topo.cs['consumer2'].stop(timeout=10)
- topo.ms['master1'].start(timeout=10)
- lastLogin_m1_1 = _last_login_time(topo, tuserdn, 'master1', 'bind_n_check')
- log.info('Start master2 to sync lastLoginTime attribute from master1')
- topo.ms['master2'].start(timeout=10)
- time.sleep(5)
- log.info('Stop master1')
- topo.ms['master1'].stop(timeout=10)
- log.info('Bind as user1 to master2 and check if lastLoginTime attribute is greater than master1')
- lastLogin_m2_1 = _last_login_time(topo, tuserdn, 'master2', 'bind_n_check')
- assert lastLogin_m2_1 > lastLogin_m1_1
- log.info('Start all servers except master1')
- topo.ms['master2'].stop(timeout=10)
- topo.cs['consumer1'].start(timeout=10)
- topo.cs['consumer2'].start(timeout=10)
- topo.ms['master2'].start(timeout=10)
- time.sleep(10)
- log.info('Check if consumers are updated with lastLoginTime attribute value from master2')
- lastLogin_c1_1 = _last_login_time(topo, tuserdn, 'consumer1', 'check')
- assert lastLogin_c1_1 == lastLogin_m2_1
- lastLogin_c2_1 = _last_login_time(topo, tuserdn, 'consumer2', 'check')
- assert lastLogin_c2_1 == lastLogin_m2_1
- log.info('Check if lastLoginTime update in consumers not synced to master2')
- lastLogin_c1_2 = _last_login_time(topo, tuserdn, 'consumer1', 'bind_n_check')
- assert lastLogin_c1_2 > lastLogin_m2_1
- lastLogin_c2_2 = _last_login_time(topo, tuserdn, 'consumer2', 'bind_n_check')
- assert lastLogin_c2_2 > lastLogin_m2_1
- time.sleep(10) # Allow replication to kick in
- lastLogin_m2_2 = _last_login_time(topo, tuserdn, 'master2', 'check')
- assert lastLogin_m2_2 == lastLogin_m2_1
- log.info('Start master1 and check if its updating its older lastLoginTime attribute to consumers')
- topo.ms['master1'].start(timeout=10)
- time.sleep(10)
- lastLogin_c1_3 = _last_login_time(topo, tuserdn, 'consumer1', 'check')
- assert lastLogin_c1_3 == lastLogin_c1_2
- lastLogin_c2_3 = _last_login_time(topo, tuserdn, 'consumer2', 'check')
- assert lastLogin_c2_3 == lastLogin_c2_2
- log.info('Check if lastLoginTime update from master2 is synced to all masters and consumers')
- lastLogin_m2_3 = _last_login_time(topo, tuserdn, 'master2', 'bind_n_check')
- time.sleep(10) # Allow replication to kick in
- lastLogin_m1_2 = _last_login_time(topo, tuserdn, 'master1', 'check')
- lastLogin_c1_4 = _last_login_time(topo, tuserdn, 'consumer1', 'check')
- lastLogin_c2_4 = _last_login_time(topo, tuserdn, 'consumer2', 'check')
- assert lastLogin_m2_3 == lastLogin_m1_2 == lastLogin_c2_4 == lastLogin_c1_4
- log.info('Checking consumer error logs for replica invalid state info')
- assert not topo.cs['consumer2'].ds_error_log.match('.*deletedattribute;deleted.*')
- assert not topo.cs['consumer1'].ds_error_log.match('.*deletedattribute;deleted.*')
- if __name__ == '__main__':
- # Run isolated
- # -s for DEBUG mode
- CURRENT_FILE = os.path.realpath(__file__)
- pytest.main("-s %s" % CURRENT_FILE)
|