|
|
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 |
|