[SCM] Samba Shared Repository - branch master updated

Douglas Bagnall dbagnall at samba.org
Thu Jun 28 07:24:02 UTC 2018


The branch, master has been updated
       via  211275f samba-tool showrepl tests: test all-good with --pull-summary
       via  2c9eeed samba-tool drs showrepl: add --pull-summary and --notify-summary
       via  5fcd374 s4/torture/samba_tool_drs_showrepl: use assertRegexpMatches
       via  da30b37 s4/torture/drs/python: don't double-call enable/disable replication
       via  f08e3d6 samba-tool drs showrepl test: remove useless print
       via  79c1c0c samba-tool drs showrepl: Skip deleted DSAs when checking for success
       via  3a1b710 samba-tool drs show_repl: simplify the collection of DC lists
       via  b62b3da samba-tool drs showrepl --summary for a quick local check
       via  2403b7c samba-tool drs showrepl: add a --color flag
      from  8b07ddd provision: set 'binddns dir' when making new smb.conf

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


- Log -----------------------------------------------------------------
commit 211275fae6895cdedbbe25ca3e41d0a856c1a370
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Thu Jun 28 16:19:31 2018 +1200

    samba-tool showrepl tests: test all-good with --pull-summary
    
    We test the all-good case with --pull-summary, which is the only one
    we can be reasonably certain about.
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    
    Autobuild-User(master): Douglas Bagnall <dbagnall at samba.org>
    Autobuild-Date(master): Thu Jun 28 09:23:10 CEST 2018 on sn-devel-144

commit 2c9eeedc84820d2d99c5e5fe5c19c0d58901b754
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Thu Jun 28 14:10:53 2018 +1200

    samba-tool drs showrepl: add --pull-summary and --notify-summary
    
    These separate the two halves of --summary (which is still there),
    allowing the repsto and repsfrom to be separately queried.
    
    One motivation for this is testing: it is difficult to assert the
    success of repsfrom (--notify-summary) in the test framework, because
    we can't rely on the other end behaving properly and promptly.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 5fcd374602bf75facfe98cc4736cbcdd3c2bba4a
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Wed Jun 27 13:55:16 2018 +1200

    s4/torture/samba_tool_drs_showrepl: use assertRegexpMatches
    
    rather than a local rewrite special to this file.
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit da30b37e68baee90102a95a3e62ef537b36c06af
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Wed Jun 13 16:28:55 2018 +1200

    s4/torture/drs/python: don't double-call enable/disable replication
    
    This is repeating work done in setup/teardown or doubling up in place (self._enable_all_repl includes self._enable_inbound_repl)
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit f08e3d6db56fd4c64af8ba0d2d6a99b98fb696ad
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Wed Jun 13 12:54:57 2018 +1200

    samba-tool drs showrepl test: remove useless print
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 79c1c0c914d5658d9981cb76d671e7f3a4ae8678
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Sun Jun 10 21:03:47 2018 +0200

    samba-tool drs showrepl: Skip deleted DSAs when checking for success
    
    The deleted DSAs are ignored by the server replication code, so ignore past failures
    here also.
    
    The repsFrom and repsTo entries will eventually be removed by the KCC.
    
    Signed-off-by: Andrew Bartlett <abartlet at samba.org>
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>

commit 3a1b710eacc38c868e4b09848e751fdb5733cd98
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Thu Jun 7 14:27:52 2018 +1200

    samba-tool drs show_repl: simplify the collection of DC lists
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit b62b3da976e1d14f809406ce0e87aac3d38846da
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Thu Jun 7 14:15:10 2018 +1200

    samba-tool drs showrepl --summary for a quick local check
    
    The default output ("classic") gives you a lot of very uninteresting
    detail when everything is fine. --summary shuts up about things that
    are fine but shouts a little bit when things are broken. It doesn't
    provide any new information, just tries to present it in a more useful
    format.
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

commit 2403b7c4fd5bdb77493a581115f4e902dba6528f
Author: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
Date:   Thu Jun 7 14:27:37 2018 +1200

    samba-tool drs showrepl: add a --color flag
    
    Nothing is using it yet, but the next commit will
    
    Signed-off-by: Douglas Bagnall <douglas.bagnall at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>

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

Summary of changes:
 python/samba/netcmd/drs.py                         | 101 +++++++--
 source4/torture/drs/python/repl_schema.py          |   3 -
 source4/torture/drs/python/replica_sync_rodc.py    |   2 -
 .../torture/drs/python/samba_tool_drs_showrepl.py  | 240 +++++++++++++++++----
 4 files changed, 286 insertions(+), 60 deletions(-)


Changeset truncated at 500 lines:

diff --git a/python/samba/netcmd/drs.py b/python/samba/netcmd/drs.py
index 235d82b..664a710 100644
--- a/python/samba/netcmd/drs.py
+++ b/python/samba/netcmd/drs.py
@@ -18,7 +18,6 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
-
 import samba.getopt as options
 import ldb
 import logging
@@ -38,8 +37,10 @@ from samba.dcerpc import drsuapi, misc
 from samba.join import join_clone
 from samba.ndr import ndr_unpack
 from samba.dcerpc import drsblobs
+from samba import colour
 import logging
 
+
 def drsuapi_connect(ctx):
     '''make a DRSUAPI connection to the server'''
     try:
@@ -99,27 +100,52 @@ class cmd_drs_showrepl(Command):
     takes_options = [
         Option("--json", help="replication details in JSON format",
                dest='format', action='store_const', const='json'),
+        Option("--summary", help=("summarize overall DRS health as seen "
+                                  "from this server"),
+               dest='format', action='store_const', const='summary'),
+        Option("--pull-summary", help=("Have we successfully replicated "
+                                       "from all relevent servers?"),
+               dest='format', action='store_const', const='pull_summary'),
+        Option("--notify-summary", action='store_const',
+               const='notify_summary', dest='format',
+               help=("Have we successfully notified all relevent servers of "
+                     "local changes, and did they say they successfully "
+                     "replicated?")),
         Option("--classic", help="print local replication details",
                dest='format', action='store_const', const='classic',
                default=DEFAULT_SHOWREPL_FORMAT),
         Option("-v", "--verbose", help="Be verbose", action="store_true"),
+        Option("--color", help="Use colour output (yes|no|auto)",
+               default='no'),
     ]
 
     takes_args = ["DC?"]
 
     def parse_neighbour(self, n):
         """Convert an ldb neighbour object into a python dictionary"""
+        dsa_objectguid = str(n.source_dsa_obj_guid)
         d = {
             'NC dn': n.naming_context_dn,
-            "DSA objectGUID": str(n.source_dsa_obj_guid),
+            "DSA objectGUID": dsa_objectguid,
             "last attempt time": nttime2string(n.last_attempt),
             "last attempt message": drs_errmsg(n.result_last_attempt),
             "consecutive failures": n.consecutive_sync_failures,
             "last success": nttime2string(n.last_success),
-            "NTDS DN": str(n.source_dsa_obj_dn)
+            "NTDS DN": str(n.source_dsa_obj_dn),
+            'is deleted': False
         }
 
         try:
+            self.samdb.search(base="<GUID=%s>" % dsa_objectguid,
+                              scope=ldb.SCOPE_BASE,
+                              attrs=[])
+        except ldb.LdbError as e:
+            (errno, _) = e.args
+            if errno == ldb.ERR_NO_SUCH_OBJECT:
+                d['is deleted'] = True
+            else:
+                raise
+        try:
             (site, server) = drs_parse_ntds_dn(n.source_dsa_obj_dn)
             d["DSA"] = "%s\%s" % (site, server)
         except RuntimeError:
@@ -141,9 +167,7 @@ class cmd_drs_showrepl(Command):
         self.message("\t\tLast success @ %s" % d['last success'])
         self.message("")
 
-    def drsuapi_ReplicaInfo(self, info_type):
-        '''call a DsReplicaInfo'''
-
+    def get_neighbours(self, info_type):
         req1 = drsuapi.DsReplicaGetInfoRequest1()
         req1.info_type = info_type
         try:
@@ -151,12 +175,15 @@ class cmd_drs_showrepl(Command):
                 self.drsuapi_handle, 1, req1)
         except Exception as e:
             raise CommandError("DsReplicaGetInfo of type %u failed" % info_type, e)
-        return (info_type, info)
+
+        reps = [self.parse_neighbour(n) for n in info.array]
+        return reps
 
     def run(self, DC=None, sambaopts=None,
             credopts=None, versionopts=None,
             format=DEFAULT_SHOWREPL_FORMAT,
-            verbose=False):
+            verbose=False, color='no'):
+        self.apply_colour_choice(color)
         self.lp = sambaopts.get_loadparm()
         if DC is None:
             DC = common.netcmd_dnsname(self.lp)
@@ -165,6 +192,9 @@ class cmd_drs_showrepl(Command):
         self.verbose = verbose
 
         output_function = {
+            'summary': self.summary_output,
+            'notify_summary': self.notify_summary_output,
+            'pull_summary': self.pull_summary_output,
             'json': self.json_output,
             'classic': self.classic_output,
         }.get(format)
@@ -179,6 +209,53 @@ class cmd_drs_showrepl(Command):
         del data['server']
         json.dump(data, self.outf, indent=2)
 
+    def summary_output_handler(self, typeof_output):
+        """Print a short message if every seems fine, but print details of any
+        links that seem broken."""
+        failing_repsto = []
+        failing_repsfrom = []
+
+        local_data = self.get_local_repl_data()
+
+        if typeof_output != "pull_summary":
+            for rep in local_data['repsTo']:
+                if rep['is deleted']:
+                    continue
+                if rep["consecutive failures"] != 0 or rep["last success"] == 0:
+                    failing_repsto.append(rep)
+
+        if typeof_output != "notify_summary":
+            for rep in local_data['repsFrom']:
+                if rep['is deleted']:
+                    continue
+                if rep["consecutive failures"] != 0 or rep["last success"] == 0:
+                    failing_repsto.append(rep)
+
+        if failing_repsto or failing_repsfrom:
+            self.message(colour.c_RED("There are failing connections"))
+            if failing_repsto:
+                self.message(colour.c_RED("Failing outbound connections:"))
+                for rep in failing_repsto:
+                    self.print_neighbour(rep)
+            if failing_repsfrom:
+                self.message(colour.c_RED("Failing inbound connection:"))
+                for rep in failing_repsfrom:
+                    self.print_neighbour(rep)
+
+            return 1
+
+        self.message(colour.c_GREEN("[ALL GOOD]"))
+
+
+    def summary_output(self):
+        return self.summary_output_handler("summary")
+
+    def notify_summary_output(self):
+        return self.summary_output_handler("notify_summary")
+
+    def pull_summary_output(self):
+        return self.summary_output_handler("pull_summary")
+
     def get_local_repl_data(self):
         drsuapi_connect(self)
         samdb_connect(self)
@@ -201,12 +278,8 @@ class cmd_drs_showrepl(Command):
         }
 
         conn = self.samdb.search(base=ntds_dn, expression="(objectClass=nTDSConnection)")
-        info = self.drsuapi_ReplicaInfo(
-            drsuapi.DRSUAPI_DS_REPLICA_INFO_NEIGHBORS)[1]
-        repsfrom =  [self.parse_neighbour(n) for n in info.array]
-        info = self.drsuapi_ReplicaInfo(
-            drsuapi.DRSUAPI_DS_REPLICA_INFO_REPSTO)[1]
-        repsto = [self.parse_neighbour(n) for n in info.array]
+        repsfrom = self.get_neighbours(drsuapi.DRSUAPI_DS_REPLICA_INFO_NEIGHBORS)
+        repsto = self.get_neighbours(drsuapi.DRSUAPI_DS_REPLICA_INFO_REPSTO)
 
         conn_details = []
         for c in conn:
diff --git a/source4/torture/drs/python/repl_schema.py b/source4/torture/drs/python/repl_schema.py
index 61c08be..89346af 100644
--- a/source4/torture/drs/python/repl_schema.py
+++ b/source4/torture/drs/python/repl_schema.py
@@ -308,9 +308,6 @@ class DrsReplSchemaTestCase(drs_base.DrsBaseTestCase):
 
         This ensures that the server
         """
-        # disable automatic replication temporary
-        self._disable_all_repl(self.dnsname_dc1)
-        self._disable_all_repl(self.dnsname_dc2)
 
        # add new attributeSchema object
         (a_ldn, a_dn) = self._schema_new_attr(self.ldb_dc1, "attr-OU-S", 14)
diff --git a/source4/torture/drs/python/replica_sync_rodc.py b/source4/torture/drs/python/replica_sync_rodc.py
index 907cef4..d93c454 100644
--- a/source4/torture/drs/python/replica_sync_rodc.py
+++ b/source4/torture/drs/python/replica_sync_rodc.py
@@ -43,14 +43,12 @@ class DrsReplicaSyncTestCase(drs_base.DrsBaseTestCase):
 
     def setUp(self):
         super(DrsReplicaSyncTestCase, self).setUp()
-        self._disable_inbound_repl(self.dnsname_dc1)
         self._disable_all_repl(self.dnsname_dc1)
         self.ou1 = None
         self.ou2 = None
 
     def tearDown(self):
         # re-enable replication
-        self._enable_inbound_repl(self.dnsname_dc1)
         self._enable_all_repl(self.dnsname_dc1)
 
         super(DrsReplicaSyncTestCase, self).tearDown()
diff --git a/source4/torture/drs/python/samba_tool_drs_showrepl.py b/source4/torture/drs/python/samba_tool_drs_showrepl.py
index 90bb048..4094955 100644
--- a/source4/torture/drs/python/samba_tool_drs_showrepl.py
+++ b/source4/torture/drs/python/samba_tool_drs_showrepl.py
@@ -20,8 +20,12 @@
 from __future__ import print_function
 import samba.tests
 import drs_base
+from samba.dcerpc import drsuapi
+from samba import drs_utils
 import re
 import json
+import ldb
+import random
 from samba.compat import PY3
 
 if PY3:
@@ -37,12 +41,6 @@ DN_RE = r'(?:(?:CN|DC)=[\\:\w -]+,)+DC=com'
 class SambaToolDrsShowReplTests(drs_base.DrsBaseTestCase):
     """Blackbox test case for samba-tool drs."""
 
-    def assertRegex(self, exp, s, flags=0):
-        m = re.search(exp, s, flags=flags)
-        if m is None:
-            self.fail("%r did not match /%s/" % (s, exp))
-        return m
-
     def setUp(self):
         super(SambaToolDrsShowReplTests, self).setUp()
 
@@ -84,11 +82,12 @@ class SambaToolDrsShowReplTests(drs_base.DrsBaseTestCase):
         self.assertEqual(_outbound, ' OUTBOUND NEIGHBORS ')
         self.assertEqual(_conn, ' KCC CONNECTION OBJECTS ')
 
-        self.assertRegex(r'^Default-First-Site-Name\\LOCALDC\s+'
-                         r"DSA Options: %s\s+"
-                         r"DSA object GUID: %s\s+"
-                         r"DSA invocationId: %s" %
-                         (HEX8_RE, GUID_RE, GUID_RE), header)
+        self.assertRegexpMatches(header,
+                                 r'^Default-First-Site-Name\\LOCALDC\s+'
+                                 r"DSA Options: %s\s+"
+                                 r"DSA object GUID: %s\s+"
+                                 r"DSA invocationId: %s" %
+                                 (HEX8_RE, GUID_RE, GUID_RE))
 
         # We don't assert the DomainDnsZones and ForestDnsZones are
         # there because we don't know that they have been set up yet.
@@ -96,28 +95,35 @@ class SambaToolDrsShowReplTests(drs_base.DrsBaseTestCase):
         for p in ['CN=Configuration,DC=samba,DC=example,DC=com',
                   'DC=samba,DC=example,DC=com',
                   'CN=Schema,CN=Configuration,DC=samba,DC=example,DC=com']:
-            self.assertRegex(r'%s\n'
-                             r'\tDefault-First-Site-Name\\[A-Z]+ via RPC\n'
-                             r'\t\tDSA object GUID: %s\n'
-                             r'\t\tLast attempt @ [^\n]+\n'
-                             r'\t\t\d+ consecutive failure\(s\).\n'
-                             r'\t\tLast success @ [^\n]+\n'
-                             r'\n' % (p, GUID_RE), inbound)
-
-            self.assertRegex(r'%s\n'
-                             r'\tDefault-First-Site-Name\\[A-Z]+ via RPC\n'
-                             r'\t\tDSA object GUID: %s\n'
-                             r'\t\tLast attempt @ [^\n]+\n'
-                             r'\t\t\d+ consecutive failure\(s\).\n'
-                             r'\t\tLast success @ [^\n]+\n'
-                             r'\n' % (p, GUID_RE), outbound)
-
-        self.assertRegex(r'Connection --\n'
-                         r'\tConnection name: %s\n'
-                         r'\tEnabled        : TRUE\n'
-                         r'\tServer DNS name : \w+.samba.example.com\n'
-                         r'\tServer DN name  : %s'
-                         r'\n' % (GUID_RE, DN_RE), conn)
+            self.assertRegexpMatches(
+                inbound,
+                r'%s\n'
+                r'\tDefault-First-Site-Name\\[A-Z]+ via RPC\n'
+                r'\t\tDSA object GUID: %s\n'
+                r'\t\tLast attempt @ [^\n]+\n'
+                r'\t\t\d+ consecutive failure\(s\).\n'
+                r'\t\tLast success @ [^\n]+\n'
+                r'\n' % (p, GUID_RE),
+                msg="%s inbound missing" % p)
+
+            self.assertRegexpMatches(
+                outbound,
+                r'%s\n'
+                r'\tDefault-First-Site-Name\\[A-Z]+ via RPC\n'
+                r'\t\tDSA object GUID: %s\n'
+                r'\t\tLast attempt @ [^\n]+\n'
+                r'\t\t\d+ consecutive failure\(s\).\n'
+                r'\t\tLast success @ [^\n]+\n'
+                r'\n' % (p, GUID_RE),
+                msg="%s outbound missing" % p)
+
+        self.assertRegexpMatches(conn,
+                                 r'Connection --\n'
+                                 r'\tConnection name: %s\n'
+                                 r'\tEnabled        : TRUE\n'
+                                 r'\tServer DNS name : \w+.samba.example.com\n'
+                                 r'\tServer DN name  : %s'
+                                 r'\n' % (GUID_RE, DN_RE))
 
     def test_samba_tool_showrepl_json(self):
         """Tests 'samba-tool drs showrepl --json' command.
@@ -125,8 +131,6 @@ class SambaToolDrsShowReplTests(drs_base.DrsBaseTestCase):
         out = self.check_output("samba-tool drs showrepl %s %s --json" %
                                 (self.dc1, self.cmdline_creds))
 
-        print(out)
-
         d = json.loads(out)
         self.assertEqual(set(d), set(['repsFrom',
                                       'repsTo',
@@ -135,26 +139,180 @@ class SambaToolDrsShowReplTests(drs_base.DrsBaseTestCase):
 
         # dsa
         for k in ["objectGUID", "invocationId"]:
-            self.assertRegex('^%s$' % GUID_RE, d['dsa'][k])
+            self.assertRegexpMatches(d['dsa'][k], '^%s$' % GUID_RE)
         self.assertTrue(isinstance(d['dsa']["options"], int))
 
         # repsfrom and repsto
         for reps in (d['repsFrom'], d['repsTo']):
             for r in reps:
                 for k in ('NC dn', "NTDS DN"):
-                    self.assertRegex('^%s$' % DN_RE, r[k])
+                    self.assertRegexpMatches(r[k], '^%s$' % DN_RE)
                 for k in ("last attempt time",
                           "last attempt message",
                           "last success"):
                     self.assertTrue(isinstance(r[k], json_str))
-                self.assertRegex('^%s$' % GUID_RE, r["DSA objectGUID"])
+                self.assertRegexpMatches(r["DSA objectGUID"], '^%s$' % GUID_RE)
                 self.assertTrue(isinstance(r["consecutive failures"], int))
 
         # ntdsconnection
         for n in d["NTDSConnections"]:
-            self.assertRegex(r'^[\w]+\.samba\.example\.com$', n["dns name"])
-            self.assertRegex("^%s$" % GUID_RE, n["name"])
+            self.assertRegexpMatches(n["dns name"],
+                                     r'^[\w]+\.samba\.example\.com$')
+            self.assertRegexpMatches(n["name"], "^%s$" % GUID_RE)
             self.assertTrue(isinstance(n['enabled'], bool))
             self.assertTrue(isinstance(n['options'], int))
             self.assertTrue(isinstance(n['replicates NC'], list))
-            self.assertRegex("^%s$" % DN_RE, n["remote DN"])
+            self.assertRegexpMatches(n["remote DN"], "^%s$" % DN_RE)
+
+    def _force_all_reps(self, samdb, dc, direction):
+        if direction == 'inbound':
+            info_type = drsuapi.DRSUAPI_DS_REPLICA_INFO_NEIGHBORS
+        elif direction == 'outbound':
+            info_type = drsuapi.DRSUAPI_DS_REPLICA_INFO_REPSTO
+        else:
+            raise ValueError("expected 'inbound' or 'outbound'")
+
+        self._enable_all_repl(dc)
+        lp = self.get_loadparm()
+        creds = self.get_credentials()
+        drsuapi_conn, drsuapi_handle, _ = drs_utils.drsuapi_connect(dc, lp, creds)
+        req1 = drsuapi.DsReplicaGetInfoRequest1()
+        req1.info_type = info_type
+        _, info = drsuapi_conn.DsReplicaGetInfo(drsuapi_handle, 1, req1)
+        for x in info.array:
+            # you might think x.source_dsa_address was the thing, but no.
+            # and we need to filter out RODCs and deleted DCs
+
+            res = []
+            try:
+                res = samdb.search(base=x.source_dsa_obj_dn,
+                                   scope=ldb.SCOPE_BASE,
+                                   attrs=['msDS-isRODC', 'isDeleted'],
+                                   controls=['show_deleted:0'])
+            except ldb.LdbError as e:
+                if e.args[0] != ldb.ERR_NO_SUCH_OBJECT:
+                    raise
+
+            if (len(res) == 0 or
+                len(res[0].get('msDS-isRODC', '')) > 0 or
+                res[0]['isDeleted'] == 'TRUE'):
+                continue
+
+            dsa_dn = str(ldb.Dn(samdb, x.source_dsa_obj_dn).parent())
+            try:
+                res = samdb.search(base=dsa_dn,
+                                   scope=ldb.SCOPE_BASE,
+                                   attrs=['dNSHostName'])
+            except ldb.LdbError as e:
+                if e.args[0] != ldb.ERR_NO_SUCH_OBJECT:
+                    raise
+                continue
+
+            if len(res) == 0:
+                print("server %s has no dNSHostName" % dsa_dn)
+                continue
+
+            remote = res[0].get('dNSHostName', [''])[0]
+            if remote:
+                self._enable_all_repl(remote)
+
+            if direction == 'inbound':
+                src, dest = remote, dc
+            else:
+                src, dest = dc, remote
+            self._net_drs_replicate(dest, src, forced=True)
+
+    def test_samba_tool_showrepl_pull_summary_all_good(self):
+        """Tests 'samba-tool drs showrepl --pull-summary' command."""
+        # To be sure that all is good we need to force replication
+        # with everyone (because others might have it turned off), and
+        # turn replication on for them in case they suddenly decide to
+        # try again.
+        #
+        # We don't restore them to the non-auto-replication state.
+        samdb1 = self.getSamDB("-H", "ldap://%s" % self.dc1, "-U",
+                               self.cmdline_creds)
+        self._enable_all_repl(self.dc1)
+        self._force_all_reps(samdb1, self.dc1, 'inbound')
+        self._force_all_reps(samdb1, self.dc1, 'outbound')
+
+        out = self.check_output("samba-tool drs showrepl --pull-summary %s %s" %
+                                (self.dc1, self.cmdline_creds))
+        self.assertStringsEqual(out, "[ALL GOOD]\n")
+
+        out = self.check_output("samba-tool drs showrepl --pull-summary "
+                                "--color=yes %s %s" %
+                                (self.dc1, self.cmdline_creds))
+        self.assertStringsEqual(out, "\033[1;32m[ALL GOOD]\033[0m\n")
+
+        # --verbose output is still quiet when all is good.
+        out = self.check_output("samba-tool drs showrepl --pull-summary -v %s %s" %
+                                (self.dc1, self.cmdline_creds))
+        self.assertStringsEqual(out, "[ALL GOOD]\n")
+        out = self.check_output("samba-tool drs showrepl --pull-summary -v "
+                                "--color=yes %s %s" %
+                                (self.dc1, self.cmdline_creds))
+        self.assertStringsEqual(out, "\033[1;32m[ALL GOOD]\033[0m\n")
+
+    def test_samba_tool_showrepl_summary_forced_failure(self):
+        """Tests 'samba-tool drs showrepl --summary' command when we break the
+        network on purpose.
+        """
+        self.addCleanup(self._enable_all_repl, self.dc1)
+        self._disable_all_repl(self.dc1)
+
+        samdb1 = self.getSamDB("-H", "ldap://%s" % self.dc1, "-U",
+                               self.cmdline_creds)
+        samdb2 = self.getSamDB("-H", "ldap://%s" % self.dc2, "-U",
+                               self.cmdline_creds)
+        domain_dn = samdb1.domain_dn()
+
+        # Add some things to NOT replicate
+        ou1 = "OU=dc1.%x,%s" % (random.randrange(1 << 64), domain_dn)
+        ou2 = "OU=dc2.%x,%s" % (random.randrange(1 << 64), domain_dn)
+        samdb1.add({
+            "dn": ou1,
+            "objectclass": "organizationalUnit"
+        })
+        self.addCleanup(samdb1.delete, ou1, ['tree_delete:1'])
+        samdb2.add({
+            "dn": ou2,
+            "objectclass": "organizationalUnit"
+        })
+        self.addCleanup(samdb2.delete, ou2, ['tree_delete:1'])
+
+        dn1 = 'cn=u1.%%d,%s' % (ou1)
+        dn2 = 'cn=u2.%%d,%s' % (ou2)
+
+        try:
+            for i in range(100):
+                samdb1.add({
+                    "dn": dn1 % i,
+                    "objectclass": "user"
+                })
+                samdb2.add({
+                    "dn": dn2 % i,
+                    "objectclass": "user"
+                })
+                out = self.check_output("samba-tool drs showrepl --summary -v "


-- 
Samba Shared Repository



More information about the samba-cvs mailing list