From 9e2009ae7105dda5493d4d60b20f15ffb369ab26 Mon Sep 17 00:00:00 2001 From: Mark Reynolds Date: Feb 16 2018 14:15:59 +0000 Subject: Ticket 49566 - ds-replcheck needs to work with hidden conflict entries Description: Conflict entries are now hidden and the tool needs to account for it. The filter needs to include "objectclass=ldapsubentry" Added option to prompt for password, and cleaned up man page. https://pagure.io/389-ds-base/issue/49566 Reviewed by: spichugi(Thanks!) --- diff --git a/ldap/admin/src/scripts/ds-replcheck b/ldap/admin/src/scripts/ds-replcheck index 0b7e70e..45c4670 100755 --- a/ldap/admin/src/scripts/ds-replcheck +++ b/ldap/admin/src/scripts/ds-replcheck @@ -14,6 +14,7 @@ import time import ldap import ldapurl import argparse +import getpass from ldap.ldapobject import SimpleLDAPObject from ldap.cidict import cidict @@ -878,14 +879,16 @@ def do_online_report(opts, output_file=None): controls = [paged_ctrl] req_pr_ctrl = controls[0] try: - master_msgid = master.search_ext(opts['suffix'], ldap.SCOPE_SUBTREE, "objectclass=*", + master_msgid = master.search_ext(opts['suffix'], ldap.SCOPE_SUBTREE, + "(|(objectclass=*)(objectclass=ldapsubentry))", ['*', 'createtimestamp', 'nscpentrywsi', 'nsds5replconflict'], serverctrls=controls) except ldap.LDAPError as e: print("Error: Failed to get Master entries: %s", str(e)) exit(1) try: - replica_msgid = replica.search_ext(opts['suffix'], ldap.SCOPE_SUBTREE, "objectclass=*", + replica_msgid = replica.search_ext(opts['suffix'], ldap.SCOPE_SUBTREE, + "(|(objectclass=*)(objectclass=ldapsubentry))", ['*', 'createtimestamp', 'nscpentrywsi', 'nsds5replconflict'], serverctrls=controls) except ldap.LDAPError as e: @@ -928,7 +931,8 @@ def do_online_report(opts, output_file=None): if m_pctrls[0].cookie: # Copy cookie from response control to request control req_pr_ctrl.cookie = m_pctrls[0].cookie - master_msgid = master.search_ext(opts['suffix'], ldap.SCOPE_SUBTREE, "objectclass=*", + master_msgid = master.search_ext(opts['suffix'], ldap.SCOPE_SUBTREE, + "(|(objectclass=*)(objectclass=ldapsubentry))", ['*', 'createtimestamp', 'nscpentrywsi', 'nsds5replconflict'], serverctrls=controls) else: m_done = True # No more pages available @@ -947,7 +951,8 @@ def do_online_report(opts, output_file=None): if r_pctrls[0].cookie: # Copy cookie from response control to request control req_pr_ctrl.cookie = r_pctrls[0].cookie - replica_msgid = replica.search_ext(opts['suffix'], ldap.SCOPE_SUBTREE, "objectclass=*", + replica_msgid = replica.search_ext(opts['suffix'], ldap.SCOPE_SUBTREE, + "(|(objectclass=*)(objectclass=ldapsubentry))", ['*', 'createtimestamp', 'nscpentrywsi', 'nsds5replconflict'], serverctrls=controls) else: r_done = True # No more pages available @@ -976,8 +981,9 @@ def main(): parser = argparse.ArgumentParser(description=desc) parser.add_argument('-v', '--verbose', help='Verbose output', action='store_true', default=False, dest='verbose') parser.add_argument('-o', '--outfile', help='The output file', dest='file', default=None) - parser.add_argument('-D', '--binddn', help='The Bind DN', dest='binddn', default="") - parser.add_argument('-w', '--bindpw', help='The Bind password', dest='bindpw', default="") + parser.add_argument('-D', '--binddn', help='The Bind DN', dest='binddn', default=None) + parser.add_argument('-w', '--bindpw', help='The Bind password', dest='bindpw', default=None) + parser.add_argument('-W', '--prompt', help='Prompt for the bind password', action='store_true', dest='prompt', default=False) parser.add_argument('-m', '--master_url', help='The LDAP URL for the Master server (REQUIRED)', dest='murl', default=None) parser.add_argument('-r', '--replica_url', help='The LDAP URL for the Replica server (REQUIRED)', @@ -1012,7 +1018,7 @@ def main(): elif (args.mldif is None and (args.suffix is None or args.binddn is None or - args.bindpw is None or + (args.bindpw is None and args.prompt is False) or args.murl is None or args.rurl is None)): print("\n-------> Missing required options for online mode!\n") @@ -1098,6 +1104,9 @@ def main(): print("Can't open file: " + args.file) exit(1) + if args.prompt: + opts['bindpw'] = getpass.getpass('Enter password:') + if opts['mldif'] is not None and opts['rldif'] is not None: print ("Performing offline report...") do_offline_report(opts, OUTPUT_FILE) diff --git a/man/man1/ds-replcheck.1 b/man/man1/ds-replcheck.1 index 21b4802..3f14e11 100644 --- a/man/man1/ds-replcheck.1 +++ b/man/man1/ds-replcheck.1 @@ -2,7 +2,7 @@ .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) -.TH DS-REPLCHECK 1 "May 2, 2017" +.TH DS-REPLCHECK 1 "Feb 14, 2018" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: @@ -19,7 +19,7 @@ ds-replcheck - Performs replication synchronization report between two replicas .SH SYNOPSIS -ds-replcheck [-h] [-o FILE] [-D BINDDN] [-w BINDPW] [-m MURL] +ds-replcheck [-h] [-o FILE] [-D BINDDN] [[-w BINDPW] [-W]] [-m MURL] [-r RURL] [-b SUFFIX] [-l LAG] [-Z CERTDIR] [-i IGNORE] [-p PAGESIZE] [-M MLDIF] [-R RLDIF] @@ -41,6 +41,10 @@ The Directory Manager DN, or root DN.a (online mode) .B \fB\-w\fR \fIPASSWORD\fR The Directory Manager password (online mode) .TP +.B \fB\-W\fR +.br +Prompt for the Directory Manager password (online mode) +.TP .B \fB\-m\fR \fILDAP_URL\fR The LDAP Url for the first replica (online mode) .TP @@ -59,6 +63,10 @@ The directory containing a certificate database for StartTLS/SSL connections. ( .B \fB\-i\fR \fIIGNORE LIST\fR Comma separated list of attributes to ignore in the report (online & offline) .TP +.B \fB\-c\fR +.br +Display verbose conflict entry information +.TP .B \fB\-M\fR \fILDIF FILE\fR The LDIF file for the first replica (offline mode) .TP @@ -81,5 +89,5 @@ ds-replcheck was written by the 389 Project. .SH "REPORTING BUGS" Report bugs to https://pagure.io/389-ds-base/new_issue .SH COPYRIGHT -Copyright \(co 2017 Red Hat, Inc. +Copyright \(co 2018 Red Hat, Inc.