netcmd/drs: add cmd_drs_uptodateness with json support
authorJoe Guo <joeg@catalyst.net.nz>
Wed, 3 Oct 2018 22:28:44 +0000 (11:28 +1300)
committerAndrew Bartlett <abartlet@samba.org>
Thu, 18 Oct 2018 04:15:25 +0000 (06:15 +0200)
Add cmd to print uptodateness summary with json support.

Signed-off-by: Joe Guo <joeg@catalyst.net.nz>
Reviewed-by: Douglas Bagnall <douglas.bagnall@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
BUG: https://bugzilla.samba.org/show_bug.cgi?id=13658

python/samba/netcmd/drs.py

index 0f7a243912d2531814bd9e3fde3c3040f54b0924..0b2ed37d214f435ba53edc5efeeb9a741f196136 100644 (file)
@@ -18,6 +18,8 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #
+from __future__ import print_function
+
 import samba.getopt as options
 import ldb
 import logging
@@ -39,6 +41,14 @@ from samba.ndr import ndr_unpack
 from samba.dcerpc import drsblobs
 from samba import colour
 
+from samba.uptodateness import (
+    get_partition_maps,
+    get_utdv_edges,
+    get_utdv_distances,
+    get_utdv_summary,
+    get_kcc_and_dsas,
+)
+
 
 def drsuapi_connect(ctx):
     '''make a DRSUAPI connection to the server'''
@@ -769,6 +779,88 @@ class cmd_drs_clone_dc_database(Command):
                    targetdir=targetdir, include_secrets=include_secrets)
 
 
+class cmd_drs_uptodateness(Command):
+    """Show uptodateness status"""
+
+    synopsis = "%prog [options]"
+
+    takes_optiongroups = {
+        "sambaopts": options.SambaOptions,
+        "versionopts": options.VersionOptions,
+        "credopts": options.CredentialsOptions,
+    }
+
+    takes_options = [
+        Option("-H", "--URL", metavar="URL", dest="H",
+               help="LDB URL for database or target server"),
+        Option("-p", "--partition",
+               help="restrict to this partition"),
+        Option("--json", action='store_true',
+               help="Print data in json format"),
+        Option("--maximum", action='store_true',
+               help="Print maximum out-of-date-ness only"),
+        Option("--median", action='store_true',
+               help="Print median out-of-date-ness only"),
+        Option("--full", action='store_true',
+               help="Print full out-of-date-ness data"),
+    ]
+
+    def format_as_json(self, partitions_summaries):
+        return json.dumps(partitions_summaries, indent=2)
+
+    def format_as_text(self, partitions_summaries):
+        lines = []
+        for part_name, summary in partitions_summaries.items():
+            items = ['%s: %s' % (k, v) for k, v in summary.items()]
+            line = '%-15s %s' % (part_name, '  '.join(items))
+            lines.append(line)
+        return '\n'.join(lines)
+
+    def run(self, H=None, partition=None,
+            json=False, maximum=False, median=False, full=False,
+            sambaopts=None, credopts=None, versionopts=None,
+            quiet=False, verbose=False):
+
+        lp = sambaopts.get_loadparm()
+        creds = credopts.get_credentials(lp, fallback_machine=True)
+        local_kcc, dsas = get_kcc_and_dsas(H, lp, creds)
+        samdb = local_kcc.samdb
+        short_partitions, _ = get_partition_maps(samdb)
+        if partition:
+            if partition in short_partitions:
+                part_dn = short_partitions[partition]
+                # narrow down to specified partition only
+                short_partitions = {partition: part_dn}
+            else:
+                raise CommandError("unknown partition %s" % partition)
+
+        filters = []
+        if maximum:
+            filters.append('maximum')
+        if median:
+            filters.append('median')
+
+        partitions_distances = {}
+        partitions_summaries = {}
+        for part_name, part_dn in short_partitions.items():
+            utdv_edges = get_utdv_edges(local_kcc, dsas, part_dn, lp, creds)
+            distances = get_utdv_distances(utdv_edges, dsas)
+            summary = get_utdv_summary(distances, filters=filters)
+            partitions_distances[part_name] = distances
+            partitions_summaries[part_name] = summary
+
+        if full:
+            # always print json format
+            output = self.format_as_json(partitions_distances)
+        else:
+            if json:
+                output = self.format_as_json(partitions_summaries)
+            else:
+                output = self.format_as_text(partitions_summaries)
+
+        print(output, file=self.outf)
+
+
 class cmd_drs(SuperCommand):
     """Directory Replication Services (DRS) management."""
 
@@ -779,3 +871,4 @@ class cmd_drs(SuperCommand):
     subcommands["showrepl"] = cmd_drs_showrepl()
     subcommands["options"] = cmd_drs_options()
     subcommands["clone-dc-database"] = cmd_drs_clone_dc_database()
+    subcommands["uptodateness"] = cmd_drs_uptodateness()