Ensure that every replica gets a unique replication ID. Otherwise changes won't propogate between all replicas.

468732
This commit is contained in:
Rob Crittenden 2008-10-29 13:37:15 -04:00
parent 4862a8f9d9
commit f305864d90
3 changed files with 57 additions and 3 deletions

View File

@ -249,7 +249,8 @@ def main():
try: try:
repl = replication.ReplicationManager(config.host_name, config.dirman_password) repl = replication.ReplicationManager(config.host_name, config.dirman_password)
ret = repl.setup_replication(config.master_host_name, config.realm_name) ret = repl.setup_replication(config.master_host_name, config.realm_name)
except: except Exception, e:
logging.debug("Connection error: %s" % e)
raise RuntimeError("Unable to connect to LDAP server %s." % config.host_name) raise RuntimeError("Unable to connect to LDAP server %s." % config.host_name)
if ret != 0: if ret != 0:
raise RuntimeError("Failed to start replication") raise RuntimeError("Failed to start replication")

View File

@ -0,0 +1,9 @@
#
# Counter used to store the next replica id
#
# Start at 3 to avoid conflicts with v1.0 replica ids. The value itself
# isn't important but each replica needs a unique id.
dn: cn=replication,cn=etc,$SUFFIX
add: objectclass: nsDS5Replica
add: nsDS5ReplicaId: 3
add: nsDS5ReplicaRoot: '$SUFFIX'

View File

@ -49,6 +49,47 @@ class ReplicationManager:
self.repl_man_cn = "replication manager" self.repl_man_cn = "replication manager"
self.suffix = "" self.suffix = ""
def _get_replica_id(self, conn, master_conn):
"""
Returns the replica ID which is unique for each backend.
conn is the connection we are trying to get the replica ID for.
master_conn is the master we are going to replicate with.
"""
# First see if there is already one set
dn = self.replica_dn()
try:
replica = conn.search_s(dn, ldap.SCOPE_BASE, "objectclass=*")[0]
if replica.getValue('nsDS5ReplicaId'):
return int(replica.getValue('nsDS5ReplicaId'))
except ldap.NO_SUCH_OBJECT:
pass
# Ok, either the entry doesn't exist or the attribute isn't set
# so get it from the other master
retval = -1
dn = "cn=replication, cn=etc, %s" % self.suffix
try:
replica = master_conn.search_s(dn, ldap.SCOPE_BASE, "objectclass=*")[0]
if not replica.getValue('nsDS5ReplicaId'):
logging.debug("Unable to retrieve nsDS5ReplicaId from remote server")
raise RuntimeError("Unable to retrieve nsDS5ReplicaId from remote server")
except ldap.NO_SUCH_OBJECT:
logging.debug("Unable to retrieve nsDS5ReplicaId from remote server")
raise
# Now update the value on the master
retval = int(replica.getValue('nsDS5ReplicaId'))
mod = [(ldap.MOD_REPLACE, 'nsDS5ReplicaId', str(retval + 1))]
try:
master_conn.modify_s(dn, mod)
except Exception, e:
logging.debug("Problem updating nsDS5ReplicaID %s" % e)
raise
return retval
def find_replication_dns(self, conn): def find_replication_dns(self, conn):
filt = "(|(objectclass=nsDSWindowsReplicationAgreement)(objectclass=nsds5ReplicationAgreement))" filt = "(|(objectclass=nsDSWindowsReplicationAgreement)(objectclass=nsds5ReplicationAgreement))"
try: try:
@ -347,11 +388,14 @@ class ReplicationManager:
self.suffix = ipaldap.IPAdmin.normalizeDN(dsinstance.realm_to_suffix(realm_name)) self.suffix = ipaldap.IPAdmin.normalizeDN(dsinstance.realm_to_suffix(realm_name))
self.basic_replication_setup(self.conn, 1) local_id = self._get_replica_id(self.conn, other_conn)
self.basic_replication_setup(self.conn, local_id)
if not iswinsync: if not iswinsync:
self.basic_replication_setup(other_conn, 2) other_id = self._get_replica_id(other_conn, other_conn)
self.basic_replication_setup(other_conn, other_id)
self.setup_agreement(other_conn, self.conn) self.setup_agreement(other_conn, self.conn)
self.setup_agreement(self.conn, other_conn)
return self.start_replication(other_conn) return self.start_replication(other_conn)
else: else:
self.setup_agreement(self.conn, other_conn, **kargs) self.setup_agreement(self.conn, other_conn, **kargs)