| |
@@ -0,0 +1,174 @@
|
| |
+ # --- BEGIN COPYRIGHT BLOCK ---
|
| |
+ # Copyright (C) 2020 Red Hat, Inc.
|
| |
+ # Copyright (C) 2020 William Brown <william@blackhats.net.au>
|
| |
+ # All rights reserved.
|
| |
+ #
|
| |
+ # License: GPL (version 3 or any later version).
|
| |
+ # See LICENSE for details.
|
| |
+ # --- END COPYRIGHT BLOCK ---
|
| |
+ #
|
| |
+ import pytest
|
| |
+ from lib389.replica import Replicas
|
| |
+ from lib389.tasks import *
|
| |
+ from lib389.utils import *
|
| |
+ from lib389.topologies import topology_m2 as topo_m2
|
| |
+ from . import get_repl_entries
|
| |
+ from lib389.idm.user import UserAccount
|
| |
+ from lib389.replica import ReplicationManager
|
| |
+ from lib389._constants import *
|
| |
+
|
| |
+ pytestmark = pytest.mark.tier0
|
| |
+
|
| |
+ TEST_ENTRY_NAME = 'mmrepl_test'
|
| |
+ TEST_ENTRY_DN = 'uid={},{}'.format(TEST_ENTRY_NAME, DEFAULT_SUFFIX)
|
| |
+ NEW_SUFFIX_NAME = 'test_repl'
|
| |
+ NEW_SUFFIX = 'o={}'.format(NEW_SUFFIX_NAME)
|
| |
+ NEW_BACKEND = 'repl_base'
|
| |
+
|
| |
+ 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__)
|
| |
+
|
| |
+ pytest.mark.skipif(not os.environ.get('UNSAFE_ACK', False), reason="UNSAFE tests may damage system configuration.")
|
| |
+ def test_rfc2307compat(topo_m2):
|
| |
+ """ Test to verify if 10rfc2307compat.ldif does not prevent replication of schema
|
| |
+ - Create 2 masters and a test entry
|
| |
+ - Move 10rfc2307compat.ldif to be private to M1
|
| |
+ - Move 10rfc2307.ldif to be private to M2
|
| |
+ - Add 'objectCategory' to the schema of M1
|
| |
+ - Force a replication session
|
| |
+ - Check 'objectCategory' on M1 and M2
|
| |
+ """
|
| |
+ m1 = topo_m2.ms["master1"]
|
| |
+ m2 = topo_m2.ms["master2"]
|
| |
+
|
| |
+ m1.config.loglevel(vals=(ErrorLog.DEFAULT, ErrorLog.REPLICA))
|
| |
+ m2.config.loglevel(vals=(ErrorLog.DEFAULT, ErrorLog.REPLICA))
|
| |
+
|
| |
+ m1.add_s(Entry((
|
| |
+ TEST_ENTRY_DN, {
|
| |
+ "objectClass": "top",
|
| |
+ "objectClass": "extensibleObject",
|
| |
+ 'uid': TEST_ENTRY_NAME,
|
| |
+ 'cn': TEST_ENTRY_NAME,
|
| |
+ 'sn': TEST_ENTRY_NAME,
|
| |
+ }
|
| |
+ )))
|
| |
+
|
| |
+ entries = get_repl_entries(topo_m2, TEST_ENTRY_NAME, ["uid"])
|
| |
+ assert all(entries), "Entry {} wasn't replicated successfully".format(TEST_ENTRY_DN)
|
| |
+
|
| |
+ # Clean the old locations (if any)
|
| |
+ m1_temp_schema = os.path.join(m1.get_config_dir(), 'schema')
|
| |
+ m2_temp_schema = os.path.join(m2.get_config_dir(), 'schema')
|
| |
+ m1_schema = os.path.join(m1.get_data_dir(), 'dirsrv/schema')
|
| |
+ m1_opt_schema = os.path.join(m1.get_data_dir(), 'dirsrv/data')
|
| |
+ m1_temp_backup = os.path.join(m1.get_tmp_dir(), 'schema')
|
| |
+
|
| |
+ # Does the system schema exist?
|
| |
+ if os.path.islink(m1_schema):
|
| |
+ # Then we need to put the m1 schema back.
|
| |
+ os.unlink(m1_schema)
|
| |
+ shutil.copytree(m1_temp_backup, m1_schema)
|
| |
+ if not os.path.exists(m1_temp_backup):
|
| |
+ shutil.copytree(m1_schema, m1_temp_backup)
|
| |
+
|
| |
+ shutil.rmtree(m1_temp_schema, ignore_errors=True)
|
| |
+ shutil.rmtree(m2_temp_schema, ignore_errors=True)
|
| |
+
|
| |
+ # Build a new copy
|
| |
+ shutil.copytree(m1_schema, m1_temp_schema)
|
| |
+ shutil.copytree(m1_schema, m2_temp_schema)
|
| |
+ # Ensure 99user.ldif exists
|
| |
+ with open(os.path.join(m1_temp_schema, '99user.ldif'), 'w') as f:
|
| |
+ f.write('dn: cn=schema')
|
| |
+
|
| |
+ with open(os.path.join(m2_temp_schema, '99user.ldif'), 'w') as f:
|
| |
+ f.write('dn: cn=schema')
|
| |
+
|
| |
+ # m1 has compat, m2 has legacy.
|
| |
+ os.unlink(os.path.join(m2_temp_schema, '10rfc2307compat.ldif'))
|
| |
+ shutil.copy(os.path.join(m1_opt_schema, '10rfc2307.ldif'), m2_temp_schema)
|
| |
+
|
| |
+ # Configure the instances
|
| |
+ # m1.config.replace('nsslapd-schemadir', m1_temp_schema)
|
| |
+ # m2.config.replace('nsslapd-schemadir', m2_temp_schema)
|
| |
+
|
| |
+ # Now mark the system schema as empty.
|
| |
+ shutil.rmtree(m1_schema)
|
| |
+ os.symlink('/var/lib/empty', m1_schema)
|
| |
+
|
| |
+ print("SETUP COMPLETE -->")
|
| |
+
|
| |
+ # Stop all instances
|
| |
+ m1.stop()
|
| |
+ m2.stop()
|
| |
+
|
| |
+ # udpate the schema on M1 to tag a schemacsn
|
| |
+ m1.start()
|
| |
+ objectcategory_attr = '( NAME \'objectCategory\' DESC \'test of objectCategory\' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )'
|
| |
+ m1.schema.add_schema('attributetypes', [ensure_bytes(objectcategory_attr)])
|
| |
+
|
| |
+ # Now start M2 and trigger a replication M1->M2
|
| |
+ m2.start()
|
| |
+ m1.modify_s(TEST_ENTRY_DN, [(ldap.MOD_ADD, 'cn', [ensure_bytes('value_m1')])])
|
| |
+
|
| |
+ # Now check that objectCategory is in both schema
|
| |
+ time.sleep(10)
|
| |
+ ents = m1.search_s("cn=schema", ldap.SCOPE_SUBTREE, 'objectclass=*',['attributetypes'])
|
| |
+ for value in ents[0].getValues('attributetypes'):
|
| |
+ if ensure_bytes('objectCategory') in value:
|
| |
+ log.info("M1: " + str(value))
|
| |
+ break
|
| |
+ assert ensure_bytes('objectCategory') in value
|
| |
+
|
| |
+ ents = m2.search_s("cn=schema", ldap.SCOPE_SUBTREE, 'objectclass=*',['attributetypes'])
|
| |
+ for value in ents[0].getValues('attributetypes'):
|
| |
+ if ensure_bytes('objectCategory') in value:
|
| |
+ log.info("M2: " + str(value))
|
| |
+ break
|
| |
+ assert ensure_bytes('objectCategory') in value
|
| |
+
|
| |
+ # Stop m2
|
| |
+ m2.stop()
|
| |
+
|
| |
+ # "Update" it's schema,
|
| |
+ os.unlink(os.path.join(m2_temp_schema, '10rfc2307.ldif'))
|
| |
+ shutil.copy(os.path.join(m1_temp_backup, '10rfc2307compat.ldif'), m2_temp_schema)
|
| |
+
|
| |
+ # Add some more to m1
|
| |
+ objectcategory_attr = '( NAME \'objectCategoryX\' DESC \'test of objectCategoryX\' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )'
|
| |
+ m1.schema.add_schema('attributetypes', [ensure_bytes(objectcategory_attr)])
|
| |
+
|
| |
+ # Start m2.
|
| |
+ m2.start()
|
| |
+ m1.modify_s(TEST_ENTRY_DN, [(ldap.MOD_ADD, 'cn', [ensure_bytes('value_m2')])])
|
| |
+
|
| |
+ time.sleep(10)
|
| |
+ ents = m1.search_s("cn=schema", ldap.SCOPE_SUBTREE, 'objectclass=*',['attributetypes'])
|
| |
+ for value in ents[0].getValues('attributetypes'):
|
| |
+ if ensure_bytes('objectCategoryX') in value:
|
| |
+ log.info("M1: " + str(value))
|
| |
+ break
|
| |
+ assert ensure_bytes('objectCategoryX') in value
|
| |
+
|
| |
+ ents = m2.search_s("cn=schema", ldap.SCOPE_SUBTREE, 'objectclass=*',['attributetypes'])
|
| |
+ for value in ents[0].getValues('attributetypes'):
|
| |
+ if ensure_bytes('objectCategoryX') in value:
|
| |
+ log.info("M2: " + str(value))
|
| |
+ break
|
| |
+ assert ensure_bytes('objectCategoryX') in value
|
| |
+
|
| |
+ # Success cleanup
|
| |
+ os.unlink(m1_schema)
|
| |
+ shutil.copytree(m1_temp_backup, m1_schema)
|
| |
+
|
| |
+
|
| |
+ if __name__ == '__main__':
|
| |
+ # Run isolated
|
| |
+ # -s for DEBUG mode
|
| |
+ CURRENT_FILE = os.path.realpath(__file__)
|
| |
+ pytest.main("-s %s" % CURRENT_FILE)
|
| |
Third time lucky - this is an update to 2307compat.ldif to resolve the potential conflicts with 60nis.ldif, by removing the conflicts from the 2307compat.ldif. This means that sites that rely on the nis values fro 2307bis.ldif will need to include 60nis.ldif. But it means that any site that already has 60nis.ldif will NOT need to change their config.
Given the fact we already have a difficult (if not impossible ....) process for changing 2307.ldif, it's unlikely many deployments are using 2307bis, and given the rarity of nis in reality, it is unlikely that migrations into 389 will be required to enable 60nis.ldif anyway.
Note that this is TWO commits - one for enable by default, and one for the changes, so that in the case of yet-another failure, we have an easier revert plan.
Thanks!