This command will delete a replication agreement unless it is the last
one on either server. It is used to change replication topology without
actually removing any single master for the domain (the del command
must be used if that the intent).

Simo.

-- 
Simo Sorce * Red Hat, Inc * New York
>From 5172b5cd1962f55a5e614f3fbbdb90d76095078a Mon Sep 17 00:00:00 2001
From: Simo Sorce <sso...@redhat.com>
Date: Tue, 14 Dec 2010 10:51:19 -0500
Subject: [PATCH 2/4] Add disconnect command to ipa-replica-manage

Can remove replication agreements between 2 replicas as long as it is
not the last agreement (except for Ad replication agreements, which can
always be removed).

Fixes: https://fedorahosted.org/freeipa/ticket/551
---
 install/tools/ipa-replica-manage |   89 +++++++++++++++++++++++++++++++++++++-
 ipaserver/install/replication.py |   22 +++++++++
 2 files changed, 109 insertions(+), 2 deletions(-)

diff --git a/install/tools/ipa-replica-manage b/install/tools/ipa-replica-manage
index 9b5aad5ce93bd1ed58c603a1156bd33cb0fb96a2..d0bc029575d81283b7864a60f5b754bec7f05757 100755
--- a/install/tools/ipa-replica-manage
+++ b/install/tools/ipa-replica-manage
@@ -55,8 +55,8 @@ def parse_options():
 
     options, args = parser.parse_args()
 
-    if not len(args) or not ("list" in args[0] or "add" in args[0] or "del" in args[0] or "init" in args[0] or "synch" in args[0]):
-        parser.error("must provide a command [list | add | del | init | synch]")
+    if not len(args) or not ("list" in args[0] or "add" in args[0] or "del" in args[0] or "init" in args[0] or "synch" in args[0] or "disconnect" in args[0]):
+        parser.error("must provide a command [list | add | del | init | synch | disconnect]")
 
     # set log level
     if options.verbose:
@@ -105,6 +105,80 @@ def list_masters(replman, verbose):
             print "  last update status: %s" % entry.nsds5replicalastupdatestatus
             print "  last update ended: %s" % str(ipautil.parse_generalized_time(entry.nsds5replicalastupdateend))
 
+def del_link(replica1, replica2, dirman_passwd, force=False):
+
+    try:
+        repl1 = replication.ReplicationManager(replica1, dirman_passwd)
+        repl1.suffix = get_suffix()
+
+        type1 = repl1.get_agreement_type(replica2)
+
+        repl_list = repl1.find_ipa_replication_agreements()
+        if not force and len(repl_list) <= 1 and type1 == replication.IPA_REPLICA:
+            print "Cannot remove the last replication link of '%s'" % replica1
+            print "Please use the 'del' command to remove it from the domain"
+            return
+
+    except ldap.NO_SUCH_OBJECT:
+        print "'%s' has no replication agreement for '%s'" % (replica1, replica2)
+        return
+    except errors.NotFound:
+        print "'%s' has no replication agreement for '%s'" % (replica1, replica2)
+        return
+    except Exception, e:
+        print "Failed to get data from '%s': %s" % (replica1, str(e))
+        return
+
+    if type1 == replication.IPA_REPLICA:
+        try:
+            repl2 = replication.ReplicationManager(replica2, dirman_passwd)
+            repl2.suffix = get_suffix()
+
+            type2 = repl2.get_agreement_type(replica1)
+
+            repl_list = repl1.find_ipa_replication_agreements()
+            if not force and len(repl_list) <= 1:
+                print "Cannot remove the last replication link of '%s'" % replica2
+                print "Please use the 'del' command to remove it from the domain"
+                return
+
+        except ldap.NO_SUCH_OBJECT:
+            print "'%s' has no replication agreement for '%s'" % (replica2, replica1)
+            if not force:
+                return
+        except errors.NotFound:
+            print "'%s' has no replication agreement for '%s'" % (replica2, replica1)
+            if not force:
+                return
+        except Exception, e:
+            print "Failed to get data from '%s': %s" % (replica2, str(e))
+            if not force:
+                return
+
+    if repl2 and type1 == replication.IPA_REPLICA:
+        failed = False
+        try:
+            repl2.delete_agreement(replica1)
+        except ldap.LDAPError, e:
+            desc = e.args[0]['desc'].strip()
+            info = e.args[0].get('info', '').strip()
+            print "Unable to remove agreement on %s: %s: %s" % (replica2, desc, info)
+            failed = True
+        except Exception, e:
+            print "Unable to remove agreement on %s: %s" % (replica2, str(e))
+            failed = True
+
+        if failed:
+            if force:
+                print "Forcing removal on '%s'" % replica1
+            else:
+                return
+
+    if not repl2 and force:
+        print "Forcing removal on '%s'" % replica1
+
+    repl1.delete_agreement(replica2)
+
 def del_master(replman, hostname, force=False):
     has_repl_agreement = True
     try:
@@ -253,6 +327,17 @@ def main():
             print "must provide hostname of supplier to synchronize with"
             sys.exit(1)
         synch_master(r, args[1])
+    elif args[0] == "disconnect":
+        if len(args) == 3:
+            replica1 = args[1]
+            replica2 = args[2]
+        elif len(args) == 2:
+            replica1 = host
+            replica2 = args[1]
+        else:
+            print "must provide the name of the server you want to disconnect"
+            sys.exit(1)
+        del_link(replica1, replica2, dirman_passwd)
     else:
         print "unknown command: %s" % args[0]
         sys.exit(1)
diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py
index e96ea59f786905f59f5749d77df39abb9483a61a..5d18c1c7a63776f80cf61f2fc374b67fcd0767c9 100644
--- a/ipaserver/install/replication.py
+++ b/ipaserver/install/replication.py
@@ -121,6 +121,28 @@ class ReplicationManager:
             return []
         return [ent.dn for ent in ents]
 
+    def find_ipa_replication_agreements(self):
+        """
+        The replication agreements are stored in
+        cn="$SUFFIX",cn=mapping tree,cn=config
+
+        Return the list of hosts we have replication agreements.
+        """
+
+        res = []
+
+        filt = "(objectclass=nsds5ReplicationAgreement)"
+        try:
+            ents = self.conn.search_s("cn=mapping tree,cn=config",
+                                      ldap.SCOPE_SUBTREE, filt)
+        except ldap.NO_SUCH_OBJECT:
+            return res
+
+        for ent in ents:
+            res.append(ent.nsds5replicahost)
+
+        return res
+
     def add_replication_manager(self, conn, passwd=None):
         """
         Create a pseudo user to use for replication. If no password
-- 
1.7.3.3

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to