[SCM] Samba Shared Repository - branch master updated

Douglas Bagnall dbagnall at samba.org
Wed Oct 31 02:41:02 UTC 2018


The branch, master has been updated
       via  0c91024 netcmd: Add 'samba-tool group stats' command
       via  ca570bd netcmd: Include num-members in 'samba-tool group list --verbose'
       via  a9a65ad selftest: Specify different DB backends for restored testenvs
       via  5a57378 netcmd: Add backend-store option to domain backup/rename cmds
       via  4a8a0ab traffic_replay: logger was ignoring smb.conf log-level
       via  4943473 traffic_replay: Change print() to use logger()
       via  b40daca traffic_replay: Generate users faster by writing to local DB
      from  aeef8b4 dsdb group audit tests: log_membership_changes extra tests

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 0c910245fca70948a33eda99c9bc198d8b34675f
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Thu Oct 18 17:08:32 2018 +1300

    netcmd: Add 'samba-tool group stats' command
    
    With large domains it's hard to get an idea of how many groups there
    are, and how many users are in each group, on average. However, this
    could have a big impact on whether a problem can be reproduced or not.
    
    This patch dumps out some summary information so that you can get a
    quick idea of how big the groups are.
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    
    Autobuild-User(master): Douglas Bagnall <dbagnall at samba.org>
    Autobuild-Date(master): Wed Oct 31 03:40:41 CET 2018 on sn-devel-144

commit ca570bd4827aa8f61ceb137fbe748ac2f7929c44
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Thu Oct 18 16:59:24 2018 +1300

    netcmd: Include num-members in 'samba-tool group list --verbose'
    
    This adds an easy way for users to see (via samba-tool) how many members
    are in various groups, without querying the members for each individual
    group.
    
    For example, you could pipe this output to grep to check for groups with
    zero or one members (i.e. historic groups that may no longer make
    sense).
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit a9a65adb023bde5567152101a7244968284b57d9
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Fri Oct 26 13:21:48 2018 +1300

    selftest: Specify different DB backends for restored testenvs
    
    Vary the DB backend that we use for the renamed DCs. The labdc and
    renamedc are fairly similar, so let's have each of them use a different
    backend.
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 5a57378d342e690c8736877fb481ef34b27d4ea4
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Thu Oct 25 09:03:53 2018 +1300

    netcmd: Add backend-store option to domain backup/rename cmds
    
    Currently the online/rename backup files always use the default backend
    (TDB) and there is no way to change this.
    
    This patch adds the backend-store option to the backup commands so that
    you can create a backup with an MDB backend, if needed.
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 4a8a0ab32be3372888b02a4f0632246e483aa491
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Tue Oct 23 10:19:38 2018 +1300

    traffic_replay: logger was ignoring smb.conf log-level
    
    We were trying to access the debug-level (in python C bindings) before
    the smb.conf had been loaded and actually set the debug-level. So it
    would default to zero, regardless of what was in the smb.conf.
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 4943473102883245fb2c286dfebe8a685d5b2026
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Wed Oct 17 11:26:28 2018 +1300

    traffic_replay: Change print() to use logger()
    
    This reduces noise, so the messages only come out if you specify
    --debug.
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit b40daca6d4c886f2cea5efce38a5e945410d65d8
Author: Tim Beale <timbeale at catalyst.net.nz>
Date:   Thu Oct 11 14:47:28 2018 +1300

    traffic_replay: Generate users faster by writing to local DB
    
    We can create user accounts much faster if the LDB connection talks
    directly to the local sam.ldb file rather than going via LDAP. This
    patch allows the 'host' argument to the tool to be a .ldb file (e.g.
    "/usr/local/samba/private/sam.ldb") instead of a server name/IP.
    
    In most cases, the traffic_replay tool wants to run on a remote device
    (because the point of it is to send traffic to the DC). However, the
    --generate-users-only is one case where the tool can be run locally,
    directly on the test DC. (The traffic_replay user generation is handy
    for standalone testing, because it also handles assigning group
    memberships to the generated user accounts).
    
    Note that you also need to use '--option="ldb:nosync = true"' to get
    the improvement in performance.
    
    Signed-off-by: Tim Beale <timbeale at catalyst.net.nz>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

-----------------------------------------------------------------------

Summary of changes:
 docs-xml/manpages/samba-tool.8.xml     |   5 ++
 python/samba/emulate/traffic.py        |   2 +-
 python/samba/join.py                   |  18 +++--
 python/samba/netcmd/domain_backup.py   |  24 +++++--
 python/samba/netcmd/group.py           | 124 ++++++++++++++++++++++++++++++---
 python/samba/tests/domain_backup.py    |  21 ++++++
 python/samba/tests/samba_tool/group.py |  18 +++++
 script/traffic_replay                  |  14 +++-
 selftest/target/Samba4.pm              |   3 +-
 9 files changed, 200 insertions(+), 29 deletions(-)


Changeset truncated at 500 lines:

diff --git a/docs-xml/manpages/samba-tool.8.xml b/docs-xml/manpages/samba-tool.8.xml
index 2c043b9..01f5313 100644
--- a/docs-xml/manpages/samba-tool.8.xml
+++ b/docs-xml/manpages/samba-tool.8.xml
@@ -644,6 +644,11 @@
 	<para>Show group object and it's attributes.</para>
 </refsect3>
 
+<refsect3>
+	<title>group stats [options]</title>
+	<para>Show statistics for overall groups and group memberships.</para>
+</refsect3>
+
 <refsect2>
 	<title>ldapcmp <replaceable>URL1</replaceable> <replaceable>URL2</replaceable> <replaceable>domain|configuration|schema|dnsdomain|dnsforest</replaceable> [options] </title>
 	<para>Compare two LDAP databases.</para>
diff --git a/python/samba/emulate/traffic.py b/python/samba/emulate/traffic.py
index 35100ca..677ad82 100644
--- a/python/samba/emulate/traffic.py
+++ b/python/samba/emulate/traffic.py
@@ -1892,7 +1892,7 @@ def add_users_to_groups(db, instance_id, assignments):
         db.modify(m)
         end = time.time()
         duration = end - start
-        print("%f\t0\tadd\tuser\t%f\tTrue\t" % (end, duration))
+        LOGGER.info("%f\t0\tadd\tuser\t%f\tTrue\t" % (end, duration))
 
 
 def generate_stats(statsdir, timing_file):
diff --git a/python/samba/join.py b/python/samba/join.py
index 01636fe..321b8c2 100644
--- a/python/samba/join.py
+++ b/python/samba/join.py
@@ -1539,11 +1539,12 @@ def join_DC(logger=None, server=None, creds=None, lp=None, site=None, netbios_na
 
 def join_clone(logger=None, server=None, creds=None, lp=None,
                targetdir=None, domain=None, include_secrets=False,
-               dns_backend="NONE"):
+               dns_backend="NONE", backend_store=None):
     """Creates a local clone of a remote DC."""
     ctx = DCCloneContext(logger, server, creds, lp, targetdir=targetdir,
                          domain=domain, dns_backend=dns_backend,
-                         include_secrets=include_secrets)
+                         include_secrets=include_secrets,
+                         backend_store=backend_store)
 
     lp.set("workgroup", ctx.domain_name)
     logger.info("workgroup is %s" % ctx.domain_name)
@@ -1616,10 +1617,11 @@ class DCCloneContext(DCJoinContext):
 
     def __init__(ctx, logger=None, server=None, creds=None, lp=None,
                  targetdir=None, domain=None, dns_backend=None,
-                 include_secrets=False):
+                 include_secrets=False, backend_store=None):
         super(DCCloneContext, ctx).__init__(logger, server, creds, lp,
                                             targetdir=targetdir, domain=domain,
-                                            dns_backend=dns_backend)
+                                            dns_backend=dns_backend,
+                                            backend_store=backend_store)
 
         # As we don't want to create or delete these DNs, we set them to None
         ctx.server_dn = None
@@ -1669,12 +1671,13 @@ class DCCloneAndRenameContext(DCCloneContext):
 
     def __init__(ctx, new_base_dn, new_domain_name, new_realm, logger=None,
                  server=None, creds=None, lp=None, targetdir=None, domain=None,
-                 dns_backend=None, include_secrets=True):
+                 dns_backend=None, include_secrets=True, backend_store=None):
         super(DCCloneAndRenameContext, ctx).__init__(logger, server, creds, lp,
                                                      targetdir=targetdir,
                                                      domain=domain,
                                                      dns_backend=dns_backend,
-                                                     include_secrets=include_secrets)
+                                                     include_secrets=include_secrets,
+                                                     backend_store=backend_store)
         # store the new DN (etc) that we want the cloned DB to use
         ctx.new_base_dn = new_base_dn
         ctx.new_domain_name = new_domain_name
@@ -1741,7 +1744,8 @@ class DCCloneAndRenameContext(DCCloneContext):
                             configdn=ctx.rename_dn(ctx.config_dn),
                             domain=ctx.new_domain_name, domainsid=ctx.domsid,
                             serverrole="active directory domain controller",
-                            dns_backend=ctx.dns_backend)
+                            dns_backend=ctx.dns_backend,
+                            backend_store=ctx.backend_store)
 
         print("Provision OK for renamed domain DN %s" % presult.domaindn)
         ctx.local_samdb = presult.samdb
diff --git a/python/samba/netcmd/domain_backup.py b/python/samba/netcmd/domain_backup.py
index c4f2045..8b8ecda 100644
--- a/python/samba/netcmd/domain_backup.py
+++ b/python/samba/netcmd/domain_backup.py
@@ -25,7 +25,7 @@ import tempfile
 import samba
 import tdb
 import samba.getopt as options
-from samba.samdb import SamDB
+from samba.samdb import SamDB, get_default_backend_store
 import ldb
 from samba import smb
 from samba.ntacls import backup_online, backup_restore, backup_offline
@@ -207,11 +207,15 @@ class cmd_domain_backup_online(samba.netcmd.Command):
         Option("--targetdir", type=str,
                help="Directory to write the backup file to"),
         Option("--no-secrets", action="store_true", default=False,
-               help="Exclude secret values from the backup created")
+               help="Exclude secret values from the backup created"),
+        Option("--backend-store", type="choice", metavar="BACKENDSTORE",
+               choices=["tdb", "mdb"],
+               help="Specify the database backend to be used "
+               "(default is %s)" % get_default_backend_store()),
     ]
 
     def run(self, sambaopts=None, credopts=None, server=None, targetdir=None,
-            no_secrets=False):
+            no_secrets=False, backend_store=None):
         logger = self.get_logger()
         logger.setLevel(logging.DEBUG)
 
@@ -230,7 +234,8 @@ class cmd_domain_backup_online(samba.netcmd.Command):
         include_secrets = not no_secrets
         ctx = join_clone(logger=logger, creds=creds, lp=lp,
                          include_secrets=include_secrets, server=server,
-                         dns_backend='SAMBA_INTERNAL', targetdir=tmpdir)
+                         dns_backend='SAMBA_INTERNAL', targetdir=tmpdir,
+                         backend_store=backend_store)
 
         # get the paths used for the clone, then drop the old samdb connection
         paths = ctx.paths
@@ -607,7 +612,11 @@ class cmd_domain_backup_rename(samba.netcmd.Command):
         Option("--keep-dns-realm", action="store_true", default=False,
                help="Retain the DNS entries for the old realm in the backup"),
         Option("--no-secrets", action="store_true", default=False,
-               help="Exclude secret values from the backup created")
+               help="Exclude secret values from the backup created"),
+        Option("--backend-store", type="choice", metavar="BACKENDSTORE",
+               choices=["tdb", "mdb"],
+               help="Specify the database backend to be used "
+               "(default is %s)" % get_default_backend_store()),
     ]
 
     takes_args = ["new_domain_name", "new_dns_realm"]
@@ -705,7 +714,7 @@ class cmd_domain_backup_rename(samba.netcmd.Command):
 
     def run(self, new_domain_name, new_dns_realm, sambaopts=None,
             credopts=None, server=None, targetdir=None, keep_dns_realm=False,
-            no_secrets=False):
+            no_secrets=False, backend_store=None):
         logger = self.get_logger()
         logger.setLevel(logging.INFO)
 
@@ -737,7 +746,8 @@ class cmd_domain_backup_rename(samba.netcmd.Command):
                                       creds=creds, lp=lp,
                                       include_secrets=include_secrets,
                                       dns_backend='SAMBA_INTERNAL',
-                                      server=server, targetdir=tmpdir)
+                                      server=server, targetdir=tmpdir,
+                                      backend_store=backend_store)
 
         # sanity-check we're not "renaming" the domain to the same values
         old_domain = ctx.domain_name
diff --git a/python/samba/netcmd/group.py b/python/samba/netcmd/group.py
index 82d215f..121161c 100644
--- a/python/samba/netcmd/group.py
+++ b/python/samba/netcmd/group.py
@@ -34,6 +34,7 @@ from samba.dsdb import (
     GTYPE_DISTRIBUTION_GLOBAL_GROUP,
     GTYPE_DISTRIBUTION_UNIVERSAL_GROUP,
 )
+from collections import defaultdict
 
 security_group = dict({"Builtin": GTYPE_SECURITY_BUILTIN_LOCAL_GROUP,
                        "Domain": GTYPE_SECURITY_DOMAIN_LOCAL_GROUP,
@@ -323,37 +324,41 @@ class cmd_group_list(Command):
 
         samdb = SamDB(url=H, session_info=system_session(),
                       credentials=creds, lp=lp)
+        attrs=["samaccountname"]
 
+        if verbose:
+            attrs += ["grouptype", "member"]
         domain_dn = samdb.domain_dn()
         res = samdb.search(domain_dn, scope=ldb.SCOPE_SUBTREE,
                            expression=("(objectClass=group)"),
-                           attrs=["samaccountname", "grouptype"])
+                           attrs=attrs)
         if (len(res) == 0):
             return
 
         if verbose:
-            self.outf.write("Group Name                                  Group Type      Group Scope\n")
-            self.outf.write("-----------------------------------------------------------------------------\n")
+            self.outf.write("Group Name                                  Group Type      Group Scope  Members\n")
+            self.outf.write("--------------------------------------------------------------------------------\n")
 
             for msg in res:
                 self.outf.write("%-44s" % msg.get("samaccountname", idx=0))
                 hgtype = hex(int("%s" % msg["grouptype"]) & 0x00000000FFFFFFFF)
                 if (hgtype == hex(int(security_group.get("Builtin")))):
-                    self.outf.write("Security         Builtin\n")
+                    self.outf.write("Security         Builtin  ")
                 elif (hgtype == hex(int(security_group.get("Domain")))):
-                    self.outf.write("Security         Domain\n")
+                    self.outf.write("Security         Domain   ")
                 elif (hgtype == hex(int(security_group.get("Global")))):
-                    self.outf.write("Security         Global\n")
+                    self.outf.write("Security         Global   ")
                 elif (hgtype == hex(int(security_group.get("Universal")))):
-                    self.outf.write("Security         Universal\n")
+                    self.outf.write("Security         Universal")
                 elif (hgtype == hex(int(distribution_group.get("Global")))):
-                    self.outf.write("Distribution     Global\n")
+                    self.outf.write("Distribution     Global   ")
                 elif (hgtype == hex(int(distribution_group.get("Domain")))):
-                    self.outf.write("Distribution     Domain\n")
+                    self.outf.write("Distribution     Domain   ")
                 elif (hgtype == hex(int(distribution_group.get("Universal")))):
-                    self.outf.write("Distribution     Universal\n")
+                    self.outf.write("Distribution     Universal")
                 else:
-                    self.outf.write("\n")
+                    self.outf.write("                          ")
+                self.outf.write("   %u\n" % len(msg.get("member", default=[])))
         else:
             for msg in res:
                 self.outf.write("%s\n" % msg.get("samaccountname", idx=0))
@@ -583,6 +588,102 @@ Example3 shows how to display a users objectGUID and member attributes.
             self.outf.write(user_ldif)
 
 
+class cmd_group_stats(Command):
+    """Summary statistics about group memberships."""
+
+    synopsis = "%prog [options]"
+
+    takes_options = [
+        Option("-H", "--URL", help="LDB URL for database or target server", type=str,
+               metavar="URL", dest="H"),
+    ]
+
+    takes_optiongroups = {
+        "sambaopts": options.SambaOptions,
+        "credopts": options.CredentialsOptions,
+        "versionopts": options.VersionOptions,
+    }
+
+    def num_in_range(self, range_min, range_max, group_freqs):
+        total_count = 0
+        for members, count in group_freqs.items():
+            if range_min <= members and members <= range_max:
+                total_count += count
+
+        return total_count
+
+    def run(self, sambaopts=None, credopts=None, versionopts=None, H=None):
+        lp = sambaopts.get_loadparm()
+        creds = credopts.get_credentials(lp, fallback_machine=True)
+
+        samdb = SamDB(url=H, session_info=system_session(),
+                      credentials=creds, lp=lp)
+
+        domain_dn = samdb.domain_dn()
+        res = samdb.search(domain_dn, scope=ldb.SCOPE_SUBTREE,
+                           expression=("(objectClass=group)"),
+                           attrs=["samaccountname", "member"])
+
+        # first count up how many members each group has
+        group_assignments = {}
+        total_memberships = 0
+
+        for msg in res:
+            name = str(msg.get("samaccountname"))
+            memberships = len(msg.get("member", default=[]))
+            group_assignments[name] = memberships
+            total_memberships += memberships
+
+        self.outf.write("Group membership statistics*\n")
+        self.outf.write("-------------------------------------------------\n")
+        self.outf.write("Total groups: {0}\n".format(res.count))
+        self.outf.write("Total memberships: {0}\n".format(total_memberships))
+        average = float(total_memberships / res.count)
+        self.outf.write("Average members per group: %.2f\n" % average)
+        group_names = list(group_assignments.keys())
+        group_members = list(group_assignments.values())
+        # note that some builtin groups have no members, so this doesn't tell us much
+        idx = group_members.index(min(group_members))
+        self.outf.write("Min members: {0} ({1})\n".format(group_members[idx],
+                                                          group_names[idx]))
+        idx = group_members.index(max(group_members))
+        max_members = group_members[idx]
+        self.outf.write("Max members: {0} ({1})\n\n".format(max_members,
+                                                            group_names[idx]))
+
+        # convert this to the frequency of group membership, i.e. how many
+        # groups have 5 members, how many have 6 members, etc
+        group_freqs = defaultdict(int)
+        for group, count in group_assignments.items():
+            group_freqs[count] += 1
+
+        # now squash this down even further, so that we just display the number
+        # of groups that fall into one of the following membership bands
+        bands = [(0, 1), (2, 4), (5, 9), (10, 14), (15, 19), (20, 24), (25, 29),
+                 (30, 39), (40, 49), (50, 59), (60, 69), (70, 79), (80, 89),
+                 (90, 99), (100, 149), (150, 199), (200, 249), (250, 299),
+                 (300, 399), (400, 499), (500, 999), (1000, 1999),
+                 (2000, 2999), (3000, 3999), (4000, 4999), (5000, 9999),
+                 (10000, max_members)]
+
+        self.outf.write("Members        Number of Groups\n")
+        self.outf.write("-------------------------------------------------\n")
+
+        for band in bands:
+            band_start = band[0]
+            band_end = band[1]
+            if band_start > max_members:
+                break
+
+            num_groups = self.num_in_range(band_start, band_end, group_freqs)
+
+            if num_groups != 0:
+                band_str = "{0}-{1}".format(band_start, band_end)
+                self.outf.write("%13s  %u\n" % (band_str, num_groups))
+
+        self.outf.write("\n* Note this does not include nested group memberships\n")
+
+
 class cmd_group(SuperCommand):
     """Group management."""
 
@@ -595,3 +696,4 @@ class cmd_group(SuperCommand):
     subcommands["listmembers"] = cmd_group_list_members()
     subcommands["move"] = cmd_group_move()
     subcommands["show"] = cmd_group_show()
+    subcommands["stats"] = cmd_group_stats()
diff --git a/python/samba/tests/domain_backup.py b/python/samba/tests/domain_backup.py
index 98863db..320ff1f 100644
--- a/python/samba/tests/domain_backup.py
+++ b/python/samba/tests/domain_backup.py
@@ -57,6 +57,12 @@ class DomainBackupBase(SambaToolCmdTest, TestCaseInTempDir):
         self.backup_markers = ['sidForRestore', 'backupDate']
         self.restore_domain = os.environ["DOMAIN"]
         self.restore_realm = os.environ["REALM"]
+        self.backend = None
+
+    def use_backend(self, backend):
+        """Explicitly set the DB backend that the backup should use"""
+        self.backend = backend
+        self.base_cmd += ["--backend-store=" + backend]
 
     def assert_partitions_present(self, samdb):
         """Asserts all expected partitions are present in the backup samdb"""
@@ -278,6 +284,13 @@ class DomainBackupBase(SambaToolCmdTest, TestCaseInTempDir):
         self.assertIsNone(res[0].get('repsFrom'))
         self.assertIsNone(res[0].get('repsTo'))
 
+        # check the DB is using the backend we supplied
+        if self.backend:
+            res = samdb.search(base="@PARTITION", scope=ldb.SCOPE_BASE,
+                               attrs=["backendStore"])
+            backend = str(res[0].get("backendStore"))
+            self.assertEqual(backend, self.backend)
+
         # check the restored DB has the expected partitions/DC/FSMO roles
         self.assert_partitions_present(samdb)
         self.assert_dcs_present(samdb, self.new_server, expected_count=1)
@@ -391,15 +404,19 @@ class DomainBackupOnline(DomainBackupBase):
         self._test_backup_untar()
 
     def test_backup_restore(self):
+        self.use_backend("tdb")
         self._test_backup_restore()
 
     def test_backup_restore_with_conf(self):
+        self.use_backend("mdb")
         self._test_backup_restore_with_conf()
 
     def test_backup_restore_no_secrets(self):
+        self.use_backend("tdb")
         self._test_backup_restore_no_secrets()
 
     def test_backup_restore_into_site(self):
+        self.use_backend("mdb")
         self._test_backup_restore_into_site()
 
 
@@ -422,15 +439,19 @@ class DomainBackupRename(DomainBackupBase):
         self._test_backup_untar()
 
     def test_backup_restore(self):
+        self.use_backend("mdb")
         self._test_backup_restore()
 
     def test_backup_restore_with_conf(self):
+        self.use_backend("tdb")
         self._test_backup_restore_with_conf()
 
     def test_backup_restore_no_secrets(self):
+        self.use_backend("mdb")
         self._test_backup_restore_no_secrets()
 
     def test_backup_restore_into_site(self):
+        self.use_backend("tdb")
         self._test_backup_restore_into_site()
 
     def test_backup_invalid_args(self):
diff --git a/python/samba/tests/samba_tool/group.py b/python/samba/tests/samba_tool/group.py
index 7a5fd96..bb701e9 100644
--- a/python/samba/tests/samba_tool/group.py
+++ b/python/samba/tests/samba_tool/group.py
@@ -208,3 +208,21 @@ class GroupCmdTestCase(SambaToolCmdTest):
             return grouplist[0]
         else:
             return None
+
+    def test_stats(self):
+        (result, out, err) = self.runsubcmd("group", "stats",
+                                            "-H", "ldap://%s" % os.environ["DC_SERVER"],
+                                            "-U%s%%%s" % (os.environ["DC_USERNAME"],
+                                                          os.environ["DC_PASSWORD"]))
+        self.assertCmdSuccess(result, out, err, "Error running stats")
+
+        # sanity-check the command reports 'total groups' correctly
+        search_filter = "(objectClass=group)"
+        grouplist = self.samdb.search(base=self.samdb.domain_dn(),
+                                      scope=ldb.SCOPE_SUBTREE,
+                                      expression=search_filter,
+                                      attrs=[])
+
+        total_groups = len(grouplist)
+        self.assertTrue("Total groups: {0}".format(total_groups) in out,
+                        "Total groups not reported correctly")
diff --git a/script/traffic_replay b/script/traffic_replay
index 6578c84..617a746 100755
--- a/script/traffic_replay
+++ b/script/traffic_replay
@@ -30,6 +30,8 @@ from samba import gensec, get_debug_level
 from samba.emulate import traffic
 import samba.getopt as options
 from samba.logger import get_samba_logger
+from samba.samdb import SamDB
+from samba.auth import system_session
 
 
 def print_err(*args, **kwargs):
@@ -135,6 +137,7 @@ def main():
         parser.print_usage()
         return
 
+    lp = sambaopts.get_loadparm()
     debuglevel = get_debug_level()
     logger = get_samba_logger(name=__name__,
                               verbose=debuglevel > 3,
@@ -171,7 +174,6 @@ def main():
     if opts.random_seed:
         random.seed(opts.random_seed)
 
-    lp = sambaopts.get_loadparm()
     creds = credopts.get_credentials(lp)
     creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL)
 
@@ -306,8 +308,16 @@ def main():
                          opts.number_of_groups)))
         sys.exit(1)
 
+    # Get an LDB connection.
     try:
-        ldb = traffic.openLdb(host, creds, lp)
+        # if we're only adding users, then it's OK to pass a sam.ldb filepath
+        # as the host, which creates the users much faster. In all other cases
+        # we should be connecting to a remote DC
+        if opts.generate_users_only and os.path.isfile(host):
+            ldb = SamDB(url="ldb://{0}".format(host),
+                        session_info=system_session(), lp=lp)
+        else:
+            ldb = traffic.openLdb(host, creds, lp)
     except:
         logger.error(("\nInitial LDAP connection failed! Did you supply "
                       "a DNS host name and the correct credentials?"))
diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm
index 0a04aa2..770ba4f 100755
--- a/selftest/target/Samba4.pm
+++ b/selftest/target/Samba4.pm
@@ -2867,6 +2867,7 @@ sub setup_renamedc
 	my $backupdir = File::Temp->newdir();
 	my $server_args = $self->get_backup_server_args($dcvars);
 	my $backup_args = "rename $env->{DOMAIN} $env->{REALM} $server_args";
+	$backup_args .= " --backend-store=tdb";
 	my $backup_file = $self->create_backup($env, $dcvars, $backupdir,
 					       $backup_args);
 	unless($backup_file) {
@@ -2963,7 +2964,7 @@ sub setup_labdc
 	my $backupdir = File::Temp->newdir();
 	my $server_args = $self->get_backup_server_args($dcvars);
 	my $backup_args = "rename $env->{DOMAIN} $env->{REALM} $server_args";
-	$backup_args .= " --no-secrets";
+	$backup_args .= " --no-secrets --backend-store=mdb";
 	my $backup_file = $self->create_backup($env, $dcvars, $backupdir,
 					       $backup_args);
 	unless($backup_file) {


-- 
Samba Shared Repository



More information about the samba-cvs mailing list