Esempio n. 1
0
    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)
Esempio n. 2
0
    def run(self,
            H=None,
            output=None,
            shorten_names=False,
            key=True,
            talk_to_remote=False,
            sambaopts=None,
            credopts=None,
            versionopts=None,
            color=None,
            color_scheme=None,
            utf8=False,
            format=None,
            importldif=None,
            xdot=False,
            partition=None,
            max_digits=3):
        if not talk_to_remote:
            print(
                "this won't work without talking to the remote servers "
                "(use -r)",
                file=self.outf)
            return

        # We use the KCC libraries in readonly mode to get the
        # replication graph.
        lp = sambaopts.get_loadparm()
        creds = credopts.get_credentials(lp, fallback_machine=True)
        local_kcc, dsas = get_kcc_and_dsas(H, lp, creds)
        self.samdb = local_kcc.samdb
        partition = get_partition(self.samdb, partition)

        short_partitions, long_partitions = get_partition_maps(self.samdb)
        color_scheme = self.calc_distance_color_scheme(color, color_scheme,
                                                       output)

        for part_name, part_dn in short_partitions.items():
            if partition not in (part_dn, None):
                continue  # we aren't doing this partition

            utdv_edges = get_utdv_edges(local_kcc, dsas, part_dn, lp, creds)

            distances = get_utdv_distances(utdv_edges, dsas)

            max_distance = get_utdv_max_distance(distances)

            digits = min(max_digits, len(str(max_distance)))
            if digits < 1:
                digits = 1
            c_scale = 10**digits

            s = full_matrix(distances,
                            utf8=utf8,
                            colour=color_scheme,
                            shorten_names=shorten_names,
                            generate_key=key,
                            grouping_function=get_dnstr_site,
                            colour_scale=c_scale,
                            digits=digits,
                            ylabel='DC',
                            xlabel='out-of-date-ness')

            self.write('\n%s\n\n%s' % (part_name, s), output)
Esempio n. 3
0
    def run(self,
            H=None,
            output=None,
            shorten_names=False,
            key=True,
            talk_to_remote=False,
            sambaopts=None,
            credopts=None,
            versionopts=None,
            mode='self',
            partition=None,
            color=None,
            color_scheme=None,
            utf8=None,
            format=None,
            xdot=False):
        # We use the KCC libraries in readonly mode to get the
        # replication graph.
        lp = sambaopts.get_loadparm()
        creds = credopts.get_credentials(lp, fallback_machine=True)
        local_kcc, dsas = get_kcc_and_dsas(H, lp, creds)
        unix_now = local_kcc.unix_now

        partition = get_partition(local_kcc.samdb, partition)

        # nc_reps is an autovivifying dictionary of dictionaries of lists.
        # nc_reps[partition]['current' | 'needed'] is a list of
        # (dsa dn string, repsFromTo object) pairs.
        nc_reps = defaultdict(lambda: defaultdict(list))

        guid_to_dnstr = {}

        # We run a new KCC for each DSA even if we aren't talking to
        # the remote, because after kcc.run (or kcc.list_dsas) the kcc
        # ends up in a messy state.
        for dsa_dn in dsas:
            kcc = KCC(unix_now, readonly=True)
            if talk_to_remote:
                res = local_kcc.samdb.search(dsa_dn,
                                             scope=SCOPE_BASE,
                                             attrs=["dNSHostName"])
                dns_name = str(res[0]["dNSHostName"][0])
                print("Attempting to contact ldap://%s (%s)" %
                      (dns_name, dsa_dn),
                      file=sys.stderr)
                try:
                    kcc.load_samdb("ldap://%s" % dns_name, lp, creds)
                except KCCError as e:
                    print("Could not contact ldap://%s (%s)" % (dns_name, e),
                          file=sys.stderr)
                    continue

                kcc.run(H, lp, creds)
            else:
                kcc.load_samdb(H, lp, creds)
                kcc.run(H, lp, creds, forced_local_dsa=dsa_dn)

            dsas_from_here = set(kcc.list_dsas())
            if dsas != dsas_from_here:
                print("found extra DSAs:", file=sys.stderr)
                for dsa in (dsas_from_here - dsas):
                    print("   %s" % dsa, file=sys.stderr)
                print("missing DSAs (known locally, not by %s):" % dsa_dn,
                      file=sys.stderr)
                for dsa in (dsas - dsas_from_here):
                    print("   %s" % dsa, file=sys.stderr)

            for remote_dn in dsas_from_here:
                if mode == 'others' and remote_dn == dsa_dn:
                    continue
                elif mode == 'self' and remote_dn != dsa_dn:
                    continue

                remote_dsa = kcc.get_dsa('CN=NTDS Settings,' + remote_dn)
                kcc.translate_ntdsconn(remote_dsa)
                guid_to_dnstr[str(remote_dsa.dsa_guid)] = remote_dn
                # get_reps_tables() returns two dictionaries mapping
                # dns to NCReplica objects
                c, n = remote_dsa.get_rep_tables()
                for part, rep in c.items():
                    if partition is None or part == partition:
                        nc_reps[part]['current'].append((dsa_dn, rep))
                for part, rep in n.items():
                    if partition is None or part == partition:
                        nc_reps[part]['needed'].append((dsa_dn, rep))

        all_edges = {
            'needed': {
                'to': [],
                'from': []
            },
            'current': {
                'to': [],
                'from': []
            }
        }

        short_partitions, long_partitions = get_partition_maps(local_kcc.samdb)

        for partname, part in nc_reps.items():
            for state, edgelists in all_edges.items():
                for dsa_dn, rep in part[state]:
                    short_name = long_partitions.get(partname, partname)
                    for r in rep.rep_repsFrom:
                        edgelists['from'].append(
                            (dsa_dn, guid_to_dnstr[str(r.source_dsa_obj_guid)],
                             short_name))
                    for r in rep.rep_repsTo:
                        edgelists['to'].append(
                            (guid_to_dnstr[str(r.source_dsa_obj_guid)], dsa_dn,
                             short_name))

        # Here we have the set of edges. From now it is a matter of
        # interpretation and presentation.

        if self.calc_output_format(format, output) == 'distance':
            color_scheme = self.calc_distance_color_scheme(
                color, color_scheme, output)
            header_strings = {
                'from': "RepsFrom objects for %s",
                'to': "RepsTo objects for %s",
            }
            for state, edgelists in all_edges.items():
                for direction, items in edgelists.items():
                    part_edges = defaultdict(list)
                    for src, dest, part in items:
                        part_edges[part].append((src, dest))
                    for part, edges in part_edges.items():
                        s = distance_matrix(None,
                                            edges,
                                            utf8=utf8,
                                            colour=color_scheme,
                                            shorten_names=shorten_names,
                                            generate_key=key,
                                            grouping_function=get_dnstr_site)

                        s = "\n%s\n%s" % (header_strings[direction] % part, s)
                        self.write(s, output)
            return

        edge_colours = []
        edge_styles = []
        dot_edges = []
        dot_vertices = set()
        used_colours = {}
        key_set = set()
        for state, edgelist in all_edges.items():
            for direction, items in edgelist.items():
                for src, dest, part in items:
                    colour = used_colours.setdefault((part),
                                                     colour_hash(
                                                         (part, direction)))
                    linestyle = 'dotted' if state == 'needed' else 'solid'
                    arrow = 'open' if direction == 'to' else 'empty'
                    dot_vertices.add(src)
                    dot_vertices.add(dest)
                    dot_edges.append((src, dest))
                    edge_colours.append(colour)
                    style = 'style="%s"; arrowhead=%s' % (linestyle, arrow)
                    edge_styles.append(style)
                    key_set.add(
                        (part, 'reps' + direction.title(), colour, style))

        key_items = []
        if key:
            for part, direction, colour, linestyle in sorted(key_set):
                key_items.append(
                    (False, 'color="%s"; %s' % (colour, linestyle),
                     "%s %s" % (part, direction)))
            key_items.append((False, 'style="dotted"; arrowhead="open"',
                              "repsFromTo is needed"))
            key_items.append((False, 'style="solid"; arrowhead="open"',
                              "repsFromTo currently exists"))

        s = dot_graph(dot_vertices,
                      dot_edges,
                      directed=True,
                      edge_colors=edge_colours,
                      edge_styles=edge_styles,
                      shorten_names=shorten_names,
                      key_items=key_items)

        if format == 'xdot':
            self.call_xdot(s, output)
        else:
            self.write(s, output)