Blame SOURCES/0003-Ticket-49840-ds-replcheck-command-returns-traceback-.patch

edc5f2
From 6361810037bc32c22e3e00a16bc53b34d0b0d610 Mon Sep 17 00:00:00 2001
edc5f2
From: Mark Reynolds <mreynolds@redhat.com>
edc5f2
Date: Mon, 9 Jul 2018 15:50:09 -0400
edc5f2
Subject: [PATCH] Ticket 49840 - ds-replcheck command returns traceback errors
edc5f2
 against ldif files having garbage content when run in offline mode
edc5f2
edc5f2
Description:  Added a basic check to see if the LDIF files are actually
edc5f2
              LDIF files.  Also added checks that the database RUV are
edc5f2
              present as well.
edc5f2
edc5f2
https://pagure.io/389-ds-base/issue/49840
edc5f2
edc5f2
Reviewed by: spichugi(Thanks!)
edc5f2
edc5f2
(cherry picked from commit 60cb52040704686d9541a2e2eb2765d86cb10af2)
edc5f2
---
edc5f2
 ldap/admin/src/scripts/ds-replcheck | 53 +++++++++++++++++++++++------
edc5f2
 1 file changed, 43 insertions(+), 10 deletions(-)
edc5f2
edc5f2
diff --git a/ldap/admin/src/scripts/ds-replcheck b/ldap/admin/src/scripts/ds-replcheck
edc5f2
index 62f911034..5c195f983 100755
edc5f2
--- a/ldap/admin/src/scripts/ds-replcheck
edc5f2
+++ b/ldap/admin/src/scripts/ds-replcheck
edc5f2
@@ -10,18 +10,19 @@
edc5f2
 #
edc5f2
 
edc5f2
 import os
edc5f2
+import sys
edc5f2
 import re
edc5f2
 import time
edc5f2
 import ldap
edc5f2
 import ldapurl
edc5f2
 import argparse
edc5f2
 import getpass
edc5f2
-
edc5f2
+from ldif import LDIFRecordList
edc5f2
 from ldap.ldapobject import SimpleLDAPObject
edc5f2
 from ldap.cidict import cidict
edc5f2
 from ldap.controls import SimplePagedResultsControl
edc5f2
 
edc5f2
-VERSION = "1.3"
edc5f2
+VERSION = "1.4"
edc5f2
 RUV_FILTER = '(&(nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff)(objectclass=nstombstone))'
edc5f2
 LDAP = 'ldap'
edc5f2
 LDAPS = 'ldaps'
edc5f2
@@ -386,14 +387,17 @@ def ldif_search(LDIF, dn):
edc5f2
     return result
edc5f2
 
edc5f2
 
edc5f2
-def get_dns(LDIF, opts):
edc5f2
+def get_dns(LDIF, filename, opts):
edc5f2
     ''' Get all the DN's from an LDIF file
edc5f2
     '''
edc5f2
     dns = []
edc5f2
     found = False
edc5f2
+    found_ruv = False
edc5f2
+    LDIF.seek(0)
edc5f2
     for line in LDIF:
edc5f2
         if line.startswith('dn: ') and line[4:].startswith('nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff'):
edc5f2
             opts['ruv_dn'] = line[4:].lower().strip()
edc5f2
+            found_ruv = True
edc5f2
         elif line.startswith('dn: '):
edc5f2
             found = True
edc5f2
             dn = line[4:].lower().strip()
edc5f2
@@ -407,6 +411,14 @@ def get_dns(LDIF, opts):
edc5f2
             found = False
edc5f2
             dns.append(dn)
edc5f2
 
edc5f2
+    if not found_ruv:
edc5f2
+        print('Failed to find the database RUV in the LDIF file: ' + filename + ', the LDIF ' +
edc5f2
+              'file must contain replication state information.')
edc5f2
+        dns = None
edc5f2
+    else:
edc5f2
+        # All good, reset cursor
edc5f2
+        LDIF.seek(0)
edc5f2
+
edc5f2
     return dns
edc5f2
 
edc5f2
 
edc5f2
@@ -415,6 +427,7 @@ def get_ldif_ruv(LDIF, opts):
edc5f2
     '''
edc5f2
     LDIF.seek(0)
edc5f2
     result = ldif_search(LDIF, opts['ruv_dn'])
edc5f2
+    LDIF.seek(0)  # Reset cursor
edc5f2
     return result['entry'].data['nsds50ruv']
edc5f2
 
edc5f2
 
edc5f2
@@ -549,6 +562,7 @@ def do_offline_report(opts, output_file=None):
edc5f2
     rconflicts = []
edc5f2
     rtombstones = 0
edc5f2
     mtombstones = 0
edc5f2
+    idx = 0
edc5f2
 
edc5f2
     # Open LDIF files
edc5f2
     try:
edc5f2
@@ -561,12 +575,36 @@ def do_offline_report(opts, output_file=None):
edc5f2
         RLDIF = open(opts['rldif'], "r")
edc5f2
     except Exception as e:
edc5f2
         print('Failed to open Replica LDIF: ' + str(e))
edc5f2
+        MLDIF.close()
edc5f2
+        return None
edc5f2
+
edc5f2
+    # Verify LDIF Files
edc5f2
+    try:
edc5f2
+        print("Validating Master ldif file ({})...".format(opts['mldif']))
edc5f2
+        LDIFRecordList(MLDIF).parse()
edc5f2
+    except ValueError:
edc5f2
+        print('Master LDIF file in invalid, aborting...')
edc5f2
+        MLDIF.close()
edc5f2
+        RLDIF.close()
edc5f2
+        return None
edc5f2
+    try:
edc5f2
+        print("Validating Replica ldif file ({})...".format(opts['rldif']))
edc5f2
+        LDIFRecordList(RLDIF).parse()
edc5f2
+    except ValueError:
edc5f2
+        print('Replica LDIF file is invalid, aborting...')
edc5f2
+        MLDIF.close()
edc5f2
+        RLDIF.close()
edc5f2
         return None
edc5f2
 
edc5f2
     # Get all the dn's, and entry counts
edc5f2
     print ("Gathering all the DN's...")
edc5f2
-    master_dns = get_dns(MLDIF, opts)
edc5f2
-    replica_dns = get_dns(RLDIF, opts)
edc5f2
+    master_dns = get_dns(MLDIF, opts['mldif'], opts)
edc5f2
+    replica_dns = get_dns(RLDIF, opts['rldif'], opts)
edc5f2
+    if master_dns is None or replica_dns is None:
edc5f2
+        print("Aborting scan...")
edc5f2
+        MLDIF.close()
edc5f2
+        RLDIF.close()
edc5f2
+        sys.exit(1)
edc5f2
     m_count = len(master_dns)
edc5f2
     r_count = len(replica_dns)
edc5f2
 
edc5f2
@@ -575,11 +613,6 @@ def do_offline_report(opts, output_file=None):
edc5f2
     opts['master_ruv'] = get_ldif_ruv(MLDIF, opts)
edc5f2
     opts['replica_ruv'] = get_ldif_ruv(RLDIF, opts)
edc5f2
 
edc5f2
-    # Reset the cursors
edc5f2
-    idx = 0
edc5f2
-    MLDIF.seek(idx)
edc5f2
-    RLDIF.seek(idx)
edc5f2
-
edc5f2
     """ Compare the master entries with the replica's.  Take our list of dn's from
edc5f2
     the master ldif and get that entry( dn) from the master and replica ldif.  In
edc5f2
     this phase we keep keep track of conflict/tombstone counts, and we check for
edc5f2
-- 
edc5f2
2.17.1
edc5f2