From b7f338f2c939c3c145bb440b4d469097c795699c Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Wed, 29 Oct 2008 13:37:15 -0400 Subject: Ensure that every replica gets a unique replication ID. Otherwise changes won't propogate between all replicas. 468732 --- ipa-server/ipa-install/ipa-replica-install | 3 +- ipa-server/ipa-install/updates/replication.update | 9 +++++ ipa-server/ipaserver/replication.py | 48 ++++++++++++++++++++++- 3 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 ipa-server/ipa-install/updates/replication.update diff --git a/ipa-server/ipa-install/ipa-replica-install b/ipa-server/ipa-install/ipa-replica-install index 0b6727e22..ce598853c 100644 --- a/ipa-server/ipa-install/ipa-replica-install +++ b/ipa-server/ipa-install/ipa-replica-install @@ -249,7 +249,8 @@ def main(): try: repl = replication.ReplicationManager(config.host_name, config.dirman_password) 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) if ret != 0: raise RuntimeError("Failed to start replication") diff --git a/ipa-server/ipa-install/updates/replication.update b/ipa-server/ipa-install/updates/replication.update new file mode 100644 index 000000000..29823a6fa --- /dev/null +++ b/ipa-server/ipa-install/updates/replication.update @@ -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' diff --git a/ipa-server/ipaserver/replication.py b/ipa-server/ipaserver/replication.py index 8fdbed19c..75dd416b1 100644 --- a/ipa-server/ipaserver/replication.py +++ b/ipa-server/ipaserver/replication.py @@ -49,6 +49,47 @@ class ReplicationManager: self.repl_man_cn = "replication manager" 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): filt = "(|(objectclass=nsDSWindowsReplicationAgreement)(objectclass=nsds5ReplicationAgreement))" try: @@ -347,11 +388,14 @@ class ReplicationManager: 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: - 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(self.conn, other_conn) return self.start_replication(other_conn) else: self.setup_agreement(self.conn, other_conn, **kargs) -- cgit