Hi,

Please see the patch attached. Contrary to the discussion at https://fedorahosted.org/freeipa/ticket/4987 I also added the suffix option for clean_ruv command. If this command is available for normal RUVs, it should probably be available for CS-RUVs as well (or deprecated for both with advised use of clean_dangling_ruv).


Standa
From 4617ed5cdec9b30a527539c6af7c9c9235d458d6 Mon Sep 17 00:00:00 2001
From: Stanislav Laznicka <slazn...@redhat.com>
Date: Fri, 11 Mar 2016 10:15:02 +0100
Subject: [PATCH] ipa-replica-manage: added --suffix option

Added --suffix option for list-ruv/clean-ruv/abort-clean-ruv commands

https://fedorahosted.org/freeipa/ticket/4987
---
 install/tools/ipa-replica-manage       | 159 +++++++++++++++++++++++----------
 install/tools/man/ipa-replica-manage.1 |  10 ++-
 2 files changed, 119 insertions(+), 50 deletions(-)

diff --git a/install/tools/ipa-replica-manage b/install/tools/ipa-replica-manage
index 0497a0f0549b392216c654ab67d98cedbf122a4b..48d36d3e5b738da928cee0ff7c5818eb598d64af 100755
--- a/install/tools/ipa-replica-manage
+++ b/install/tools/ipa-replica-manage
@@ -67,6 +67,8 @@ commands = {
     "dnanextrange-set":(2, 2, "<master fqdn> <range>", "must provide a master and ID range"),
 }
 
+# tuple of commands that allow the --suffix option
+cs_enabled_commands = ("list-ruv", "clean-ruv", "abort-clean-ruv")
 
 def parse_options():
     parser = IPAOptionParser(version=version.VERSION)
@@ -93,6 +95,8 @@ def parse_options():
     parser.add_option("--from", dest="fromhost", help="Host to get data from")
     parser.add_option("--no-lookup", dest="nolookup", action="store_true", default=False,
                       help="do not perform DNS lookup checks")
+    parser.add_option("--suffix", dest="suffix", default=None,
+                      help="The suffix to be used (domain/ca), uses both if unset")
 
     options, args = parser.parse_args()
 
@@ -387,15 +391,38 @@ def get_ruv(realm, host, dirman_passwd, nolookup=False, ca=False):
 
     return servers
 
-def list_ruv(realm, host, dirman_passwd, verbose, nolookup=False):
+
+def get_ruv_by_suffix(realm, host, dirman_passwd, nolookup=False, suffix=None):
+    ruvs = {}
+
+    if suffix not in ('ca', 'domain', None):
+        sys.exit('Unknow suffix: \'{suffix}\''.format(suffix=suffix))
+    if suffix == 'ca' or suffix is None:
+        # this check requires Directory Manager password
+        if is_cs_set(realm, host, dirman_passwd):
+            ruvs['ca'] = get_ruv(realm, host, dirman_passwd, nolookup, True)
+    if suffix == 'domain' or suffix is None:
+        ruvs['domain'] = get_ruv(realm, host, dirman_passwd, nolookup)
+
+    return ruvs
+
+
+def list_ruv(realm, host, dirman_passwd, verbose, nolookup=False, suffix=None):
     """
     List the Replica Update Vectors on this host to get the available
     replica IDs.
     """
 
-    servers = get_ruv(realm, host, dirman_passwd, nolookup)
-    for (netloc, rid) in servers:
-        print("%s: %s" % (netloc, rid))
+    servers = get_ruv_by_suffix(realm, host, dirman_passwd, nolookup, suffix)
+    if servers.get('domain', None):
+        print('Replica Update Vectors:')
+        for (netloc, rid) in servers['domain']:
+            print("\t%s: %s" % (netloc, rid))
+    if servers.get('ca', None):
+        print('Certificate Server Replica Update Vectors:')
+        for (netloc, rid) in servers['ca']:
+            print("\t%s: %s" % (netloc, rid))
+
 
 def get_rid_by_host(realm, sourcehost, host, dirman_passwd, nolookup=False):
     """
@@ -406,7 +433,8 @@ def get_rid_by_host(realm, sourcehost, host, dirman_passwd, nolookup=False):
         if '%s:389' % host == netloc:
             return int(rid)
 
-def clean_ruv(realm, ruv, options, ca=False):
+
+def clean_ruv(realm, ruv, options):
     """
     Given an RID create a CLEANALLRUV task to clean it up.
     """
@@ -415,19 +443,22 @@ def clean_ruv(realm, ruv, options, ca=False):
     except ValueError:
         sys.exit("Replica ID must be an integer: %s" % ruv)
 
-    servers = get_ruv(realm, options.host, options.dirman_passwd,
-                      options.nolookup, ca=ca)
-    found = False
-    for (netloc, rid) in servers:
-        if ruv == int(rid):
-           found = True
-           hostname = netloc
-           break
+    servers = get_ruv_by_suffix(realm, options.host, options.dirman_passwd,
+                                options.nolookup, options.suffix)
+    tree_found = None
+    for (tree, ruvs) in servers.items():
+        for (netloc, rid) in ruvs:
+            if ruv == int(rid):
+                tree_found = tree
+                hostname = netloc
+                break
+        if tree_found:
+            break
 
-    if not found:
+    if not tree_found:
         sys.exit("Replica ID %s not found" % ruv)
 
-    if ca:
+    if tree_found == 'ca':
         print("Clean the Certificate Server Replication Update Vector for %s"
               % hostname)
     else:
@@ -442,7 +473,7 @@ def clean_ruv(realm, ruv, options, ca=False):
         if not ipautil.user_input("Continue to clean?", False):
             sys.exit("Aborted")
 
-    if ca:
+    if tree_found == 'ca':
         thisrepl = replication.get_cs_replication_manager(realm, options.host,
                                                           options.dirman_passwd)
     else:
@@ -451,6 +482,7 @@ def clean_ruv(realm, ruv, options, ca=False):
     thisrepl.cleanallruv(ruv)
     print("Cleanup task created")
 
+
 def abort_clean_ruv(realm, ruv, options):
     """
     Given an RID abort a CLEANALLRUV task.
@@ -460,38 +492,34 @@ def abort_clean_ruv(realm, ruv, options):
     except ValueError:
         sys.exit("Replica ID must be an integer: %s" % ruv)
 
-    servers = get_ruv(realm, options.host, options.dirman_passwd,
-                      options.nolookup)
-    found = False
-    for (netloc, rid) in servers:
-        if ruv == int(rid):
-           found = True
-           hostname = netloc
-           break
+    servers = get_ruv_by_suffix(realm, options.host, options.dirman_passwd,
+                                options.nolookup, options.suffix)
+    tree_found = None
+    for (tree, ruvs) in servers.items():
+        for (netloc, rid) in ruvs:
+            if ruv == int(rid):
+                tree_found = tree
+                hostname = netloc
+                break
+        if tree_found:
+            break
 
-    if not found:
-        sys.exit("Replica ID %s not found" % ruv)
-
-    servers = get_ruv(realm, options.host, options.dirman_passwd,
-                      options.nolookup)
-    found = False
-    for (netloc, rid) in servers:
-        if ruv == int(rid):
-           found = True
-           hostname = netloc
-           break
-
-    if not found:
+    if not tree_found:
         sys.exit("Replica ID %s not found" % ruv)
 
     print("Aborting the clean Replication Update Vector task for %s" % hostname)
     print()
-    thisrepl = replication.ReplicationManager(realm, options.host,
-                                              options.dirman_passwd)
+    if tree_found == 'ca':
+        thisrepl = replication.get_cs_replication_manager(realm, options.host,
+                                                          options.dirman_passwd)
+    else:
+        thisrepl = replication.ReplicationManager(realm, options.host,
+                                                  options.dirman_passwd)
     thisrepl.abortcleanallruv(ruv, options.force)
 
     print("Cleanup task stopped")
 
+
 def list_clean_ruv(realm, host, dirman_passwd, verbose, nolookup=False):
     """
     List all clean RUV tasks.
@@ -548,6 +576,10 @@ def clean_dangling_ruvs(realm, host, options):
         if options.dirman_passwd is None:
             sys.exit('Directory Manager password is required')
 
+    # we work with both trees here
+    if options.suffix:
+        options.suffix = None
+
     conn = ipaldap.IPAdmin(host, 636, cacert=CACERT)
     try:
         conn.do_simple_bind(bindpw=options.dirman_passwd)
@@ -687,7 +719,7 @@ def clean_dangling_ruvs(realm, host, options):
         for csruv in master_info['clean_csruv']:
             if csruv[1] not in cleaned:
                 cleaned.add(csruv[1])
-                clean_ruv(realm, csruv[1], options, ca=True)
+                clean_ruv(realm, csruv[1], options)
 
 
 def check_last_link(delrepl, realm, dirman_passwd, force):
@@ -1524,6 +1556,29 @@ def set_DNA_range(hostname, range, realm, dirman_passwd, next_range=False,
             sys.exit("Updating range failed: %s" % e)
 
 
+def is_cs_set(realm, host, dirman_passwd):
+    """
+    Checks whether CA is configured on the given host
+    """
+
+    conn = ipaldap.IPAdmin(host, 636, cacert=CACERT)
+    try:
+        conn.do_simple_bind(bindpw=dirman_passwd)
+        try:
+            dn = DN(('cn', 'CA'), ('cn', host), api.env.container_masters,
+                    ipautil.realm_to_suffix(realm))
+            conn.get_entry(dn)
+        except errors.NotFound:
+            return False
+    except Exception as e:
+        sys.exit(
+            "Failed to get data from '%s' while checking CA configuration: %s"
+            % (host, e))
+    finally:
+        conn.unbind()
+    return True
+
+
 def exit_on_managed_topology(what):
     sys.exit("{0} is deprecated with managed IPA replication topology. "
              "Please use `ipa topologysegment-*` commands to manage "
@@ -1562,10 +1617,13 @@ def main():
     if options.dirman_passwd:
         dirman_passwd = options.dirman_passwd
     else:
-        if not test_connection(realm, host, options.nolookup):
+        if not test_connection(realm, host, options.nolookup) or (
+           args[0] in cs_enabled_commands and options.suffix in ('ca', None)):
             dirman_passwd = installutils.read_password("Directory Manager",
                 confirm=False, validate=False, retry=False)
-            if dirman_passwd is None:
+            if dirman_passwd is None or (
+               not dirman_passwd and args[0] in cs_enabled_commands
+               and options.suffix in ('ca', None)):
                 sys.exit("Directory Manager password required")
 
     options.dirman_passwd = dirman_passwd
@@ -1583,8 +1641,6 @@ def main():
             replica = args[1]
         list_replicas(realm, host, replica, dirman_passwd, options.verbose,
                       options.nolookup)
-    elif args[0] == "list-ruv":
-        list_ruv(realm, host, dirman_passwd, options.verbose, options.nolookup)
     elif args[0] == "del":
         del_master(realm, args[1], options)
     elif args[0] == "re-initialize":
@@ -1615,10 +1671,17 @@ def main():
             replica1 = host
             replica2 = args[1]
         del_link(realm, replica1, replica2, dirman_passwd)
-    elif args[0] == "clean-ruv":
-        clean_ruv(realm, args[1], options)
-    elif args[0] == "abort-clean-ruv":
-        abort_clean_ruv(realm, args[1], options)
+    elif args[0] in cs_enabled_commands:
+        if options.suffix == 'ca' and not is_cs_set(realm, host, dirman_passwd):
+                sys.exit("CA is not configured on the host '{host}'"
+                         .format(host=host))
+        if args[0] == "list-ruv":
+            list_ruv(realm, host, dirman_passwd, options.verbose,
+                     options.nolookup, options.suffix)
+        elif args[0] == "clean-ruv":
+            clean_ruv(realm, args[1], options)
+        elif args[0] == "abort-clean-ruv":
+            abort_clean_ruv(realm, args[1], options)
     elif args[0] == "list-clean-ruv":
         list_clean_ruv(realm, host, dirman_passwd, options.verbose,
                        options.nolookup)
diff --git a/install/tools/man/ipa-replica-manage.1 b/install/tools/man/ipa-replica-manage.1
index ae109c4c5ff4720eb70b06c6f14a791088696d47..39a90c7beb667965176ce61bcc2a27a27331cf5b 100644
--- a/install/tools/man/ipa-replica-manage.1
+++ b/install/tools/man/ipa-replica-manage.1
@@ -135,6 +135,9 @@ Password for the IPA system user used by the Windows PassSync plugin to synchron
 .TP
 \fB\-\-from\fR=\fISERVER\fR
 The server to pull the data from, used by the re\-initialize and force\-sync commands.
+.TP
+\fB\-\-suffix\fR=\fIdomain \fRor \fIca\fR
+The directory tree that should be used when running a command. If not set, both domain and ipaca trees are used. Works with list-ruv, clean-ruv and abort-clean-ruv commands.
 .SH "RANGES"
 IPA uses the 389\-ds Distributed Numeric Assignment (DNA) Plugin to allocate POSIX ids for users and groups. A range is created when IPA is installed and half the range is assigned to the first IPA master for the purposes of allocation.
 .TP
@@ -190,8 +193,11 @@ Using connect/disconnect you can manage the replication topology.
 .TP
 List the replication IDs in use:
  # ipa\-replica\-manage list\-ruv
- srv1.example.com:389: 7
- srv2.example.com:389: 4
+ Replica Update Vectors:
+     srv1.example.com:389: 7
+     srv2.example.com:389: 4
+ Certificate Server Replica Update Vectors:
+     srv1.example.com:389: 9
 .TP
 Remove references to an orphaned and deleted master:
  # ipa\-replica\-manage del \-\-force \-\-cleanup master.example.com
-- 
2.5.0

-- 
Manage your subscription for the Freeipa-devel mailing list:
https://www.redhat.com/mailman/listinfo/freeipa-devel
Contribute to FreeIPA: http://www.freeipa.org/page/Contribute/Code

Reply via email to