|
|
@@ -0,0 +1,322 @@
|
|
|
+import os
|
|
|
+import sys
|
|
|
+import time
|
|
|
+import ldap
|
|
|
+import logging
|
|
|
+import pytest
|
|
|
+from lib389 import DirSrv, Entry, tools, tasks
|
|
|
+from lib389.tools import DirSrvTools
|
|
|
+from lib389._constants import *
|
|
|
+from lib389.properties import *
|
|
|
+from lib389.tasks import *
|
|
|
+from lib389.utils import *
|
|
|
+
|
|
|
+logging.getLogger(__name__).setLevel(logging.DEBUG)
|
|
|
+log = logging.getLogger(__name__)
|
|
|
+
|
|
|
+installation1_prefix = None
|
|
|
+
|
|
|
+PEOPLE_OU='people'
|
|
|
+PEOPLE_DN = "ou=%s,%s" % (PEOPLE_OU, SUFFIX)
|
|
|
+MAX_ACCOUNTS=5
|
|
|
+
|
|
|
+class TopologyReplication(object):
|
|
|
+ def __init__(self, master1, master2, master3):
|
|
|
+ master1.open()
|
|
|
+ self.master1 = master1
|
|
|
+ master2.open()
|
|
|
+ self.master2 = master2
|
|
|
+ master3.open()
|
|
|
+ self.master3 = master3
|
|
|
+
|
|
|
+
|
|
|
[email protected](scope="module")
|
|
|
+def topology(request):
|
|
|
+ global installation1_prefix
|
|
|
+ if installation1_prefix:
|
|
|
+ args_instance[SER_DEPLOYED_DIR] = installation1_prefix
|
|
|
+
|
|
|
+ # Creating master 1...
|
|
|
+ master1 = DirSrv(verbose=False)
|
|
|
+ if installation1_prefix:
|
|
|
+ args_instance[SER_DEPLOYED_DIR] = installation1_prefix
|
|
|
+ args_instance[SER_HOST] = HOST_MASTER_1
|
|
|
+ args_instance[SER_PORT] = PORT_MASTER_1
|
|
|
+ args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_1
|
|
|
+ args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX
|
|
|
+ args_master = args_instance.copy()
|
|
|
+ master1.allocate(args_master)
|
|
|
+ instance_master1 = master1.exists()
|
|
|
+ if instance_master1:
|
|
|
+ master1.delete()
|
|
|
+ master1.create()
|
|
|
+ master1.open()
|
|
|
+ master1.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER_1)
|
|
|
+
|
|
|
+ # Creating master 2...
|
|
|
+ master2 = DirSrv(verbose=False)
|
|
|
+ if installation1_prefix:
|
|
|
+ args_instance[SER_DEPLOYED_DIR] = installation1_prefix
|
|
|
+ args_instance[SER_HOST] = HOST_MASTER_2
|
|
|
+ args_instance[SER_PORT] = PORT_MASTER_2
|
|
|
+ args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_2
|
|
|
+ args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX
|
|
|
+ args_master = args_instance.copy()
|
|
|
+ master2.allocate(args_master)
|
|
|
+ instance_master2 = master2.exists()
|
|
|
+ if instance_master2:
|
|
|
+ master2.delete()
|
|
|
+ master2.create()
|
|
|
+ master2.open()
|
|
|
+ master2.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER_2)
|
|
|
+
|
|
|
+ # Creating master 3...
|
|
|
+ master3 = DirSrv(verbose=False)
|
|
|
+ if installation1_prefix:
|
|
|
+ args_instance[SER_DEPLOYED_DIR] = installation1_prefix
|
|
|
+ args_instance[SER_HOST] = HOST_MASTER_3
|
|
|
+ args_instance[SER_PORT] = PORT_MASTER_3
|
|
|
+ args_instance[SER_SERVERID_PROP] = SERVERID_MASTER_3
|
|
|
+ args_instance[SER_CREATION_SUFFIX] = DEFAULT_SUFFIX
|
|
|
+ args_master = args_instance.copy()
|
|
|
+ master3.allocate(args_master)
|
|
|
+ instance_master3 = master3.exists()
|
|
|
+ if instance_master3:
|
|
|
+ master3.delete()
|
|
|
+ master3.create()
|
|
|
+ master3.open()
|
|
|
+ master3.replica.enableReplication(suffix=SUFFIX, role=REPLICAROLE_MASTER, replicaId=REPLICAID_MASTER_3)
|
|
|
+
|
|
|
+ #
|
|
|
+ # Create all the agreements
|
|
|
+ #
|
|
|
+ # Creating agreement from master 1 to master 2
|
|
|
+ properties = {RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
|
|
|
+ RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
|
|
|
+ RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
|
|
|
+ RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
|
|
|
+ m1_m2_agmt = master1.agreement.create(suffix=SUFFIX, host=master2.host, port=master2.port, properties=properties)
|
|
|
+ if not m1_m2_agmt:
|
|
|
+ log.fatal("Fail to create a master -> master replica agreement")
|
|
|
+ sys.exit(1)
|
|
|
+ log.debug("%s created" % m1_m2_agmt)
|
|
|
+
|
|
|
+ # Creating agreement from master 1 to master 3
|
|
|
+# properties = {RA_NAME: r'meTo_$host:$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]}
|
|
|
+# m1_m3_agmt = master1.agreement.create(suffix=SUFFIX, host=master3.host, port=master3.port, properties=properties)
|
|
|
+# if not m1_m3_agmt:
|
|
|
+# log.fatal("Fail to create a master -> master replica agreement")
|
|
|
+# sys.exit(1)
|
|
|
+# log.debug("%s created" % m1_m3_agmt)
|
|
|
+
|
|
|
+ # Creating agreement from master 2 to master 1
|
|
|
+ properties = {RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
|
|
|
+ RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
|
|
|
+ RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
|
|
|
+ RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
|
|
|
+ m2_m1_agmt = master2.agreement.create(suffix=SUFFIX, host=master1.host, port=master1.port, properties=properties)
|
|
|
+ if not m2_m1_agmt:
|
|
|
+ log.fatal("Fail to create a master -> master replica agreement")
|
|
|
+ sys.exit(1)
|
|
|
+ log.debug("%s created" % m2_m1_agmt)
|
|
|
+
|
|
|
+ # Creating agreement from master 2 to master 3
|
|
|
+ properties = {RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
|
|
|
+ RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
|
|
|
+ RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
|
|
|
+ RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
|
|
|
+ m2_m3_agmt = master2.agreement.create(suffix=SUFFIX, host=master3.host, port=master3.port, properties=properties)
|
|
|
+ if not m2_m3_agmt:
|
|
|
+ log.fatal("Fail to create a master -> master replica agreement")
|
|
|
+ sys.exit(1)
|
|
|
+ log.debug("%s created" % m2_m3_agmt)
|
|
|
+
|
|
|
+ # Creating agreement from master 3 to master 1
|
|
|
+# properties = {RA_NAME: r'meTo_$host:$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]}
|
|
|
+# m3_m1_agmt = master3.agreement.create(suffix=SUFFIX, host=master1.host, port=master1.port, properties=properties)
|
|
|
+# if not m3_m1_agmt:
|
|
|
+# log.fatal("Fail to create a master -> master replica agreement")
|
|
|
+# sys.exit(1)
|
|
|
+# log.debug("%s created" % m3_m1_agmt)
|
|
|
+
|
|
|
+ # Creating agreement from master 3 to master 2
|
|
|
+ properties = {RA_BINDDN: defaultProperties[REPLICATION_BIND_DN],
|
|
|
+ RA_BINDPW: defaultProperties[REPLICATION_BIND_PW],
|
|
|
+ RA_METHOD: defaultProperties[REPLICATION_BIND_METHOD],
|
|
|
+ RA_TRANSPORT_PROT: defaultProperties[REPLICATION_TRANSPORT]}
|
|
|
+ m3_m2_agmt = master3.agreement.create(suffix=SUFFIX, host=master2.host, port=master2.port, properties=properties)
|
|
|
+ if not m3_m2_agmt:
|
|
|
+ log.fatal("Fail to create a master -> master replica agreement")
|
|
|
+ sys.exit(1)
|
|
|
+ log.debug("%s created" % m3_m2_agmt)
|
|
|
+
|
|
|
+ # Allow the replicas to get situated with the new agreements...
|
|
|
+ time.sleep(5)
|
|
|
+
|
|
|
+ #
|
|
|
+ # Initialize all the agreements
|
|
|
+ #
|
|
|
+ master1.agreement.init(SUFFIX, HOST_MASTER_2, PORT_MASTER_2)
|
|
|
+ master1.waitForReplInit(m1_m2_agmt)
|
|
|
+ time.sleep(5) # just to be safe
|
|
|
+ master2.agreement.init(SUFFIX, HOST_MASTER_3, PORT_MASTER_3)
|
|
|
+ master2.waitForReplInit(m2_m3_agmt)
|
|
|
+
|
|
|
+ # Check replication is working...
|
|
|
+ if master1.testReplication(DEFAULT_SUFFIX, master2):
|
|
|
+ log.info('Replication is working.')
|
|
|
+ else:
|
|
|
+ log.fatal('Replication is not working.')
|
|
|
+ assert False
|
|
|
+
|
|
|
+ # Delete each instance in the end
|
|
|
+ def fin():
|
|
|
+ for master in (master1, master2, master3):
|
|
|
+ # master.db2ldif(bename=DEFAULT_BENAME, suffixes=[DEFAULT_SUFFIX], excludeSuffixes=[], encrypt=False, \
|
|
|
+ # repl_data=True, outputfile='%s/ldif/%s.ldif' % (master.dbdir,SERVERID_STANDALONE ))
|
|
|
+ # master.clearBackupFS()
|
|
|
+ # master.backupFS()
|
|
|
+ master.delete()
|
|
|
+ request.addfinalizer(fin)
|
|
|
+
|
|
|
+ # Clear out the tmp dir
|
|
|
+ master1.clearTmpDir(__file__)
|
|
|
+
|
|
|
+ return TopologyReplication(master1, master2, master3)
|
|
|
+
|
|
|
+def _dna_config(server, nextValue=500, maxValue=510):
|
|
|
+ log.info("Add dna plugin config entry...%s" % server)
|
|
|
+
|
|
|
+ try:
|
|
|
+ server.add_s(Entry(('cn=dna config,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config', {
|
|
|
+ 'objectclass': 'top dnaPluginConfig'.split(),
|
|
|
+ 'dnaType': 'description',
|
|
|
+ 'dnaMagicRegen': '-1',
|
|
|
+ 'dnaFilter': '(objectclass=posixAccount)',
|
|
|
+ 'dnaScope': 'ou=people,%s' % SUFFIX,
|
|
|
+ 'dnaNextValue': str(nextValue),
|
|
|
+ 'dnaMaxValue' : str(nextValue+maxValue),
|
|
|
+ 'dnaSharedCfgDN': 'ou=ranges,%s' % SUFFIX
|
|
|
+ })))
|
|
|
+
|
|
|
+ except ldap.LDAPError as e:
|
|
|
+ log.error('Failed to add DNA config entry: error ' + e.message['desc'])
|
|
|
+ assert False
|
|
|
+
|
|
|
+ log.info("Enable the DNA plugin...")
|
|
|
+ try:
|
|
|
+ server.plugins.enable(name=PLUGIN_DNA)
|
|
|
+ except e:
|
|
|
+ log.error("Failed to enable DNA Plugin: error " + e.message['desc'])
|
|
|
+ assert False
|
|
|
+
|
|
|
+ log.info("Restarting the server...")
|
|
|
+ server.stop(timeout=120)
|
|
|
+ time.sleep(1)
|
|
|
+ server.start(timeout=120)
|
|
|
+ time.sleep(3)
|
|
|
+
|
|
|
+def test_ticket4026(topology):
|
|
|
+ """Write your replication testcase here.
|
|
|
+
|
|
|
+ To access each DirSrv instance use: topology.master1, topology.master2,
|
|
|
+ ..., topology.hub1, ..., topology.consumer1, ...
|
|
|
+
|
|
|
+ Also, if you need any testcase initialization,
|
|
|
+ please, write additional fixture for that(include finalizer).
|
|
|
+ """
|
|
|
+
|
|
|
+ try:
|
|
|
+ topology.master1.add_s(Entry((PEOPLE_DN, {
|
|
|
+ 'objectclass': "top extensibleObject".split(),
|
|
|
+ 'ou': 'people'})))
|
|
|
+ except ldap.ALREADY_EXISTS:
|
|
|
+ pass
|
|
|
+
|
|
|
+ topology.master1.add_s(Entry(('ou=ranges,' + SUFFIX, {
|
|
|
+ 'objectclass': 'top organizationalunit'.split(),
|
|
|
+ 'ou': 'ranges'
|
|
|
+ })))
|
|
|
+ for cpt in range(MAX_ACCOUNTS):
|
|
|
+ name = "user%d" % (cpt)
|
|
|
+ topology.master1.add_s(Entry(("uid=%s,%s" %(name, PEOPLE_DN), {
|
|
|
+ 'objectclass': 'top posixAccount extensibleObject'.split(),
|
|
|
+ 'uid': name,
|
|
|
+ 'cn': name,
|
|
|
+ 'uidNumber': '1',
|
|
|
+ 'gidNumber': '1',
|
|
|
+ 'homeDirectory': '/home/%s' % name
|
|
|
+ })))
|
|
|
+
|
|
|
+ # make master3 having more free slots that master2
|
|
|
+ # so master1 will contact master3
|
|
|
+ _dna_config(topology.master1, nextValue=100, maxValue=10)
|
|
|
+ _dna_config(topology.master2, nextValue=200, maxValue=10)
|
|
|
+ _dna_config(topology.master3, nextValue=300, maxValue=3000)
|
|
|
+
|
|
|
+ # Turn on lots of error logging now.
|
|
|
+
|
|
|
+ mod = [(ldap.MOD_REPLACE, 'nsslapd-errorlog-level', '16384')]
|
|
|
+ #mod = [(ldap.MOD_REPLACE, 'nsslapd-errorlog-level', '1')]
|
|
|
+ topology.master1.modify_s('cn=config', mod)
|
|
|
+ topology.master2.modify_s('cn=config', mod)
|
|
|
+ topology.master3.modify_s('cn=config', mod)
|
|
|
+
|
|
|
+ # We need to wait for the event in dna.c to fire to start the servers
|
|
|
+ # see dna.c line 899
|
|
|
+ time.sleep(60)
|
|
|
+
|
|
|
+ # add on master1 users with description DNA
|
|
|
+ for cpt in range(10):
|
|
|
+ name = "user_with_desc1_%d" % (cpt)
|
|
|
+ topology.master1.add_s(Entry(("uid=%s,%s" %(name, PEOPLE_DN), {
|
|
|
+ 'objectclass': 'top posixAccount extensibleObject'.split(),
|
|
|
+ 'uid': name,
|
|
|
+ 'cn': name,
|
|
|
+ 'description' : '-1',
|
|
|
+ 'uidNumber': '1',
|
|
|
+ 'gidNumber': '1',
|
|
|
+ 'homeDirectory': '/home/%s' % name
|
|
|
+ })))
|
|
|
+ # give time to negociate master1 <--> master3
|
|
|
+ time.sleep(10)
|
|
|
+ # add on master1 users with description DNA
|
|
|
+ for cpt in range(11,20):
|
|
|
+ name = "user_with_desc1_%d" % (cpt)
|
|
|
+ topology.master1.add_s(Entry(("uid=%s,%s" %(name, PEOPLE_DN), {
|
|
|
+ 'objectclass': 'top posixAccount extensibleObject'.split(),
|
|
|
+ 'uid': name,
|
|
|
+ 'cn': name,
|
|
|
+ 'description' : '-1',
|
|
|
+ 'uidNumber': '1',
|
|
|
+ 'gidNumber': '1',
|
|
|
+ 'homeDirectory': '/home/%s' % name
|
|
|
+ })))
|
|
|
+ log.info('Test complete')
|
|
|
+ # add on master1 users with description DNA
|
|
|
+ mod = [(ldap.MOD_REPLACE, 'nsslapd-errorlog-level', '16384')]
|
|
|
+ #mod = [(ldap.MOD_REPLACE, 'nsslapd-errorlog-level', '1')]
|
|
|
+ topology.master1.modify_s('cn=config', mod)
|
|
|
+ topology.master2.modify_s('cn=config', mod)
|
|
|
+ topology.master3.modify_s('cn=config', mod)
|
|
|
+
|
|
|
+ log.info('Test complete')
|
|
|
+
|
|
|
+
|
|
|
+if __name__ == '__main__':
|
|
|
+ # Run isolated
|
|
|
+ # -s for DEBUG mode
|
|
|
+# global installation1_prefix
|
|
|
+# installation1_prefix=None
|
|
|
+# topo = topology(True)
|
|
|
+# test_ticket4026(topo)
|
|
|
+ CURRENT_FILE = os.path.realpath(__file__)
|
|
|
+ pytest.main("-s %s" % CURRENT_FILE)
|