diff options
author | Andrew Tridgell <tridge@samba.org> | 2010-11-29 14:10:26 +1100 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2010-11-29 18:04:42 +1100 |
commit | abe9ac53f0d240a867d499f184866603143756cf (patch) | |
tree | fcb5c963ff38f285ad68ba1e78170749d28f8899 | |
parent | f8d73e466b454a63f256021ad2f353e9ad93e8f7 (diff) | |
download | samba-abe9ac53f0d240a867d499f184866603143756cf.tar.gz samba-abe9ac53f0d240a867d499f184866603143756cf.tar.bz2 samba-abe9ac53f0d240a867d499f184866603143756cf.zip |
s4-ldapcmp: make ldapcmp a samba-tool command
The ldapcmp tool is very useful, and should be available to Samba
admins, not just developers. This makes it a samba-tool command, which
also gives it the nicer command line handling that samba-tool has
-rw-r--r-- | source4/scripting/python/samba/netcmd/__init__.py | 2 | ||||
-rwxr-xr-x | source4/scripting/python/samba/netcmd/ldapcmp.py (renamed from source4/scripting/devel/ldapcmp) | 194 |
2 files changed, 105 insertions, 91 deletions
diff --git a/source4/scripting/python/samba/netcmd/__init__.py b/source4/scripting/python/samba/netcmd/__init__.py index d47b39dced..5a6a68cd29 100644 --- a/source4/scripting/python/samba/netcmd/__init__.py +++ b/source4/scripting/python/samba/netcmd/__init__.py @@ -172,3 +172,5 @@ from samba.netcmd.drs import cmd_drs commands["drs"] = cmd_drs() from samba.netcmd.gpo import cmd_gpo commands["gpo2"] = cmd_gpo() +from samba.netcmd.ldapcmp import cmd_ldapcmp +commands["ldapcmp"] = cmd_ldapcmp() diff --git a/source4/scripting/devel/ldapcmp b/source4/scripting/python/samba/netcmd/ldapcmp.py index 8e40877a22..8bb1c8a8c7 100755 --- a/source4/scripting/devel/ldapcmp +++ b/source4/scripting/python/samba/netcmd/ldapcmp.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # Unix SMB/CIFS implementation. -# A script to compare differences of objects and attributes between +# A command to compare differences of objects and attributes between # two LDAP servers both running at the same time. It generally compares # one of the three pratitions DOMAIN, CONFIGURATION or SCHEMA. Users # that have to be provided sheould be able to read objects in any of the @@ -26,9 +26,6 @@ import os import re import sys -from optparse import OptionParser - -sys.path.insert(0, "bin/python") import samba import samba.getopt as options @@ -36,20 +33,28 @@ from samba import Ldb from samba.ndr import ndr_pack, ndr_unpack from samba.dcerpc import security from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, ERR_NO_SUCH_OBJECT, LdbError +from samba.netcmd import ( + Command, + CommandError, + Option, + SuperCommand, + ) global summary summary = {} class LDAPBase(object): - def __init__(self, host, cmd_opts, creds, lp): + def __init__(self, host, creds, lp, + two=False, quiet=False, descriptor=False, verbose=False, + view="section"): ldb_options = [] samdb_url = host if not "://" in host: if os.path.isfile(host): samdb_url = "tdb://%s" % host else: - samdb_url = "ldap://%s:389" % host + samdb_url = "ldap://%s" % host # use 'paged_search' module when connecting remotely if samdb_url.lower().startswith("ldap://"): ldb_options = ["modules:paged_searches"] @@ -57,11 +62,11 @@ class LDAPBase(object): credentials=creds, lp=lp, options=ldb_options) - self.two_domains = cmd_opts.two - self.quiet = cmd_opts.quiet - self.descriptor = cmd_opts.descriptor - self.view = cmd_opts.view - self.verbose = cmd_opts.verbose + self.two_domains = two + self.quiet = quiet + self.descriptor = descriptor + self.view = view + self.verbose = verbose self.host = host self.base_dn = self.find_basedn() self.domain_netbios = self.find_netbios() @@ -735,84 +740,91 @@ class LDAPBundel(object): self.log( "".join([str("\n" + 4*" " + x) for x in self.summary["df_value_attrs"]]) ) self.summary["df_value_attrs"] = [] -### - -if __name__ == "__main__": - parser = OptionParser("ldapcmp [options] domain|configuration|schema") - sambaopts = options.SambaOptions(parser) - parser.add_option_group(sambaopts) - credopts = options.CredentialsOptionsDouble(parser) - parser.add_option_group(credopts) - - parser.add_option("", "--host", dest="host", - help="IP of the first LDAP server",) - parser.add_option("", "--host2", dest="host2", - help="IP of the second LDAP server",) - parser.add_option("-w", "--two", dest="two", action="store_true", default=False, - help="Hosts are in two different domains",) - parser.add_option("-q", "--quiet", dest="quiet", action="store_true", default=False, - help="Do not print anything but relay on just exit code",) - parser.add_option("-v", "--verbose", dest="verbose", action="store_true", default=False, - help="Print all DN pairs that have been compared",) - parser.add_option("", "--sd", dest="descriptor", action="store_true", default=False, - help="Compare nTSecurityDescriptor attibutes only",) - parser.add_option("", "--view", dest="view", default="section", - help="Display mode for nTSecurityDescriptor results. Possible values: section or collision.",) - (opts, args) = parser.parse_args() - - lp = sambaopts.get_loadparm() - creds = credopts.get_credentials(lp) - creds2 = credopts.get_credentials2(lp, False) - if creds2.is_anonymous(): - creds2 = creds - - if creds.is_anonymous(): - parser.error("You must supply at least one username/password pair") - - # make a list of contexts to compare in - contexts = [] - if len(args) == 0: - # if no argument given, we compare all contexts - contexts = ["DOMAIN", "CONFIGURATION", "SCHEMA"] - else: - for context in args: - if not context.upper() in ["DOMAIN", "CONFIGURATION", "SCHEMA"]: - parser.error("Incorrect argument: %s" % context) - contexts.append(context.upper()) - - if opts.verbose and opts.quiet: - parser.error("You cannot set --verbose and --quiet together") - if opts.descriptor and opts.view.upper() not in ["SECTION", "COLLISION"]: - parser.error("Unknown --view option value. Choose from: section or collision.") - - con1 = LDAPBase(opts.host, opts, creds, lp) - assert len(con1.base_dn) > 0 - - con2 = LDAPBase(opts.host2, opts, creds2, lp) - assert len(con2.base_dn) > 0 - - status = 0 - for context in contexts: - if not opts.quiet: - print "\n* Comparing [%s] context..." % context - - b1 = LDAPBundel(con1, context=context) - b2 = LDAPBundel(con2, context=context) - - if b1 == b2: - if not opts.quiet: - print "\n* Result for [%s]: SUCCESS" % context +class cmd_ldapcmp(Command): + """compare two ldap databases""" + synopsis = "ldapcmp URL1 URL2 <domain|configuration|schema> [options]" + + takes_optiongroups = { + "sambaopts": options.SambaOptions, + "versionopts": options.VersionOptions, + "credopts": options.CredentialsOptionsDouble, + } + + takes_args = ["URL1", "URL2", "context1?", "context2?", "context3?"] + + takes_options = [ + Option("-w", "--two", dest="two", action="store_true", default=False, + help="Hosts are in two different domains"), + Option("-q", "--quiet", dest="quiet", action="store_true", default=False, + help="Do not print anything but relay on just exit code"), + Option("-v", "--verbose", dest="verbose", action="store_true", default=False, + help="Print all DN pairs that have been compared"), + Option("--sd", dest="descriptor", action="store_true", default=False, + help="Compare nTSecurityDescriptor attibutes only"), + Option("--view", dest="view", default="section", + help="Display mode for nTSecurityDescriptor results. Possible values: section or collision.") + ] + + def run(self, URL1, URL2, + context1=None, context2=None, context3=None, + two=False, quiet=False, verbose=False, descriptor=False, view="section", + credopts=None, sambaopts=None, versionopts=None): + lp = sambaopts.get_loadparm() + creds = credopts.get_credentials(lp) + creds2 = credopts.get_credentials2(lp, False) + if creds2.is_anonymous(): + creds2 = creds + if not creds.authentication_requested(): + raise CommandError("You must supply at least one username/password pair") + + # make a list of contexts to compare in + contexts = [] + if context1 is None: + # if no argument given, we compare all contexts + contexts = ["DOMAIN", "CONFIGURATION", "SCHEMA"] else: - if not opts.quiet: - print "\n* Result for [%s]: FAILURE" % context - if not opts.descriptor: - assert len(b1.summary["df_value_attrs"]) == len(b2.summary["df_value_attrs"]) - b2.summary["df_value_attrs"] = [] - print "\nSUMMARY" - print "---------" - b1.print_summary() - b2.print_summary() - # mark exit status as FAILURE if a least one comparison failed - status = -1 - - sys.exit(status) + for c in [context1, context2, context3]: + if c is None: + continue + if not c.upper() in ["DOMAIN", "CONFIGURATION", "SCHEMA"]: + raise CommandError("Incorrect argument: %s" % c) + contexts.append(c.upper()) + + if verbose and quiet: + raise CommandError("You cannot set --verbose and --quiet together") + if descriptor and view.upper() not in ["SECTION", "COLLISION"]: + raise CommandError("Unknown --view option value. Choose from: section or collision.") + + con1 = LDAPBase(URL1, creds, lp, + two=two, quiet=quiet, descriptor=descriptor, verbose=verbose, view=view) + assert len(con1.base_dn) > 0 + + con2 = LDAPBase(URL2, creds2, lp, + two=two, quiet=quiet, descriptor=descriptor, verbose=verbose, view=view) + assert len(con2.base_dn) > 0 + + status = 0 + for context in contexts: + if not quiet: + print "\n* Comparing [%s] context..." % context + + b1 = LDAPBundel(con1, context=context) + b2 = LDAPBundel(con2, context=context) + + if b1 == b2: + if not quiet: + print "\n* Result for [%s]: SUCCESS" % context + else: + if not quiet: + print "\n* Result for [%s]: FAILURE" % context + if not descriptor: + assert len(b1.summary["df_value_attrs"]) == len(b2.summary["df_value_attrs"]) + b2.summary["df_value_attrs"] = [] + print "\nSUMMARY" + print "---------" + b1.print_summary() + b2.print_summary() + # mark exit status as FAILURE if a least one comparison failed + status = -1 + if status != 0: + raise CommandError("Compare failed: %d" % status) |