From 7a1399bee1547b85186e010720a90ed6ab2f5e22 Mon Sep 17 00:00:00 2001 From: Rob Crittenden Date: Mon, 16 Jan 2012 10:24:15 -0500 Subject: Check for the existence of a replication agreement before deleting it. When using ipa-replica-manage or ipa-csreplica-manage to delete an agreement with a host we would try to make a connection to that host prior to tryign to delete it. This meant that the trying to delete a host we don't have an agreement with would return a connection error instead of a "no agreement with host foo" error. Also display a completed message when an agreement is removed. https://fedorahosted.org/freeipa/ticket/2048 https://fedorahosted.org/freeipa/ticket/2125 --- install/tools/ipa-csreplica-manage | 27 +++++++++++++++++---------- install/tools/ipa-replica-manage | 29 +++++++++++++++++------------ ipaserver/install/replication.py | 22 ++++++++++++++++++++++ 3 files changed, 56 insertions(+), 22 deletions(-) diff --git a/install/tools/ipa-csreplica-manage b/install/tools/ipa-csreplica-manage index ac39b70f..97c50455 100755 --- a/install/tools/ipa-csreplica-manage +++ b/install/tools/ipa-csreplica-manage @@ -267,12 +267,26 @@ def del_link(realm, replica1, replica2, dirman_passwd, force=False): repl1.delete_agreement(replica2) repl1.delete_referral(replica2) + print "Deleted replication agreement from '%s' to '%s'" % (replica1, replica2) + def del_master(realm, hostname, options): force_del = False delrepl = None - # 1. Connect to the dogtag DS to be removed. + + # 1. Connect to the local dogtag DS server + try: + thisrepl = CSReplicationManager(realm, options.host, + options.dirman_passwd) + except Exception, e: + sys.exit("Failed to connect to server %s: %s" % (options.host, convert_error(e))) + + # 2. Ensure we have an agreement with the master + if thisrepl.get_replication_agreement(hostname) is None: + sys.exit("'%s' has no replication agreement for '%s'" % (options.host, hostname)) + + # 3. Connect to the dogtag DS to be removed. try: delrepl = CSReplicationManager(realm, hostname, options.dirman_passwd) except Exception, e: @@ -283,21 +297,14 @@ def del_master(realm, hostname, options): print "Unable to connect to replica %s, forcing removal" % hostname force_del = True - # 2. Connect to the local dogtag DS server - try: - thisrepl = CSReplicationManager(realm, options.host, - options.dirman_passwd) - except Exception, e: - sys.exit("Failed to connect to server %s: %s" % (options.host, convert_error(e))) - - # 2. Get list of agreements. + # 4. Get list of agreements. if delrepl is None: # server not up, just remove it from this server replica_names = [options.host] else: replica_names = delrepl.find_ipa_replication_agreements() - # 3. Remove each agreement + # 5. Remove each agreement for r in replica_names: try: del_link(realm, r, hostname, options.dirman_passwd, force=True) diff --git a/install/tools/ipa-replica-manage b/install/tools/ipa-replica-manage index 8506fcba..32cee6ed 100755 --- a/install/tools/ipa-replica-manage +++ b/install/tools/ipa-replica-manage @@ -272,12 +272,25 @@ def del_link(realm, replica1, replica2, dirman_passwd, force=False): except Exception, e: print "Error deleting winsync replica shared info: %s" % str(e) + print "Deleted replication agreement from '%s' to '%s'" % (replica1, replica2) def del_master(realm, hostname, options): force_del = False - # 1. Connect to the master to be removed. + # 1. Connect to the local server + try: + thisrepl = replication.ReplicationManager(realm, options.host, + options.dirman_passwd) + except Exception, e: + print "Failed to connect to server %s: %s" % (options.host, str(e)) + sys.exit(1) + + # 2. Ensure we have an agreement with the master + if thisrepl.get_replication_agreement(hostname) is None: + sys.exit("'%s' has no replication agreement for '%s'" % (options.host, hostname)) + + # 3. Connect to the master to be removed. try: delrepl = replication.ReplicationManager(realm, hostname, options.dirman_passwd) except Exception, e: @@ -288,14 +301,6 @@ def del_master(realm, hostname, options): print "Unable to connect to replica %s, forcing removal" % hostname force_del = True - # 2. Connect to the local server - try: - thisrepl = replication.ReplicationManager(realm, options.host, - options.dirman_passwd) - except Exception, e: - print "Failed to connect to server %s: %s" % (options.host, str(e)) - sys.exit(1) - if force_del: dn = 'cn=masters,cn=ipa,cn=etc,%s' % thisrepl.suffix res = thisrepl.conn.search_s(dn, ldap.SCOPE_ONELEVEL) @@ -306,21 +311,21 @@ def del_master(realm, hostname, options): # 2. Get list of agreements. replica_names = delrepl.find_ipa_replication_agreements() - # 3. Remove each agreement + # 4. Remove each agreement for r in replica_names: try: del_link(realm, r, hostname, options.dirman_passwd, force=True) except Exception, e: print "There were issues removing a connection: %s" % str(e) - # 4. Finally clean up the removed replica common entries. + # 5. Finally clean up the removed replica common entries. try: thisrepl.replica_cleanup(hostname, realm, force=True) except Exception, e: print "Failed to cleanup %s entries: %s" % (hostname, str(e)) print "You may need to manually remove them from the tree" - # 5. And clean up the removed replica DNS entries if any. + # 6. And clean up the removed replica DNS entries if any. try: if bindinstance.dns_container_exists(options.host, thisrepl.suffix, dm_password=options.dirman_passwd): diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py index 052f1834..6f637251 100644 --- a/ipaserver/install/replication.py +++ b/ipaserver/install/replication.py @@ -211,6 +211,28 @@ class ReplicationManager(object): return res + def get_replication_agreement(self, hostname): + """ + The replication agreements are stored in + cn="$SUFFIX",cn=mapping tree,cn=config + + Get the replication agreement for a specific host. + + Returns None if not found. + """ + + filt = "(&(objectclass=nsds5ReplicationAgreement)(nsDS5ReplicaHost=%s))" % hostname + try: + entry = self.conn.search_s("cn=mapping tree,cn=config", + ldap.SCOPE_SUBTREE, filt) + except ldap.NO_SUCH_OBJECT: + return None + + if len(entry) == 0: + return None + else: + return entry[0] # There can be only one + def add_replication_manager(self, conn, dn, pw): """ Create a pseudo user to use for replication. -- cgit