diff --git a/python/samba/kcc_utils.py b/python/samba/kcc_utils.py index 6a223389b46..1b64c2e6151 100644 --- a/python/samba/kcc_utils.py +++ b/python/samba/kcc_utils.py @@ -2,6 +2,10 @@ # # Copyright (C) Dave Craft 2011 # Copyright (C) Jelmer Vernooij 2011 +# Copyright (C) Andrew Bartlett 2015 +# +# Andrew Bartlett's alleged work performed by his underlings Douglas +# Bagnall and Garming Sam. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -1774,6 +1778,7 @@ class GraphNode(object): for dnstr, connect in dsa.connect_table.items(): self.add_edge_from(connect.from_dnstr) + def add_connections_from_edges(self, dsa): """For each edge directed to this graph node, ensure there is a corresponding nTDSConnection object in the dsa. diff --git a/source4/scripting/bin/samba_kcc b/source4/scripting/bin/samba_kcc index 44e3136214a..a47cb070262 100755 --- a/source4/scripting/bin/samba_kcc +++ b/source4/scripting/bin/samba_kcc @@ -3,6 +3,10 @@ # Compute our KCC topology # # Copyright (C) Dave Craft 2011 +# Copyright (C) Andrew Bartlett 2015 +# +# Andrew Bartlett's alleged work performed by his underlings Douglas +# Bagnall and Garming Sam. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -1858,6 +1862,9 @@ class KCC(object): to it such that (n) is the smallest non-negative integer satisfying (node_count <= 2*(n*n) + 6*n + 7) + (If the number of edges is m (i.e. n + 2), that is the same as + 2 * m*m - 2 * m + 3). + edges n nodecount 2 0 7 3 1 15 @@ -1986,7 +1993,6 @@ class KCC(object): # Certain replica graphs are produced only # for global catalogs, so test against # method input parameter - # XXX can't see this in the KCC docs, though it sounds convincing if gc_only and not dc_s.is_gc(): continue @@ -2108,7 +2114,7 @@ class KCC(object): r_list.append(l_of_x) r_list.sort(sort_replica_by_dsa_guid) - + DEBUG('\n'.join(str((x.rep_dsa_guid, x.rep_dsa_dnstr)) for x in r_list)) r_len = len(r_list) max_node_edges = self.intrasite_max_node_edges(r_len) @@ -2167,11 +2173,10 @@ class KCC(object): i = 0 while i < r_len: dsa = self.my_site.dsa_table[graph_list[i].dsa_dnstr] - DEBUG_REV_RED(dsa.dsa_dnstr) graph_list[i].add_edges_from_connections(dsa) i = i + 1 - DEBUG([x.rep_dsa_dnstr for x in r_list]) - DEBUG_YELLOW([x.dsa_dnstr for x in graph_list]) + DEBUG('reps are: %s' % ' '.join(x.rep_dsa_dnstr for x in r_list)) + DEBUG('dsas are: %s' % ' '.join(x.dsa_dnstr for x in graph_list)) for tnode in graph_list: # To optimize replication latency in sites with many NC replicas, the @@ -2196,15 +2201,21 @@ class KCC(object): while candidates and not tnode.has_sufficient_edges(): other = random.choice(candidates) + DEBUG("trying to add candidate %s" % other.dsa_dstr) if not tnode.add_edge_from(other): - DEBUG_RED("could not add remote %s" % other.dsa_dstr) + DEBUG_RED("could not add %s" % other.dsa_dstr) candidates.remove(other) + else: + DEBUG_CYAN("not adding links to %s: nodes %s, links is %s/%s" % + (tnode.dsa_dnstr, r_len, len(tnode.edge_from), tnode.max_edges)) + # Print the graph node in debug mode logger.debug("%s" % tnode) # For each edge directed to the local DC, ensure a nTDSConnection # points to us that satisfies the KCC criteria + if tnode.dsa_dnstr == dc_local.dsa_dnstr: tnode.add_connections_from_edges(dc_local) @@ -2241,16 +2252,28 @@ class KCC(object): return detect_stale = (not mysite.is_detect_stale_disabled()) + for dnstr, connect in mydsa.connect_table.items(): + if connect.to_be_added: + DEBUG_CYAN("TO BE ADDED:\n%s" % connect) - # Loop thru all the partitions. + # Loop thru all the partitions, with gc_only False for partdn, part in self.part_table.items(): self.construct_intrasite_graph(mysite, mydsa, part, False, detect_stale) + for dnstr, connect in mydsa.connect_table.items(): + if connect.to_be_added: + DEBUG_BLUE("TO BE ADDED:\n%s" % connect) + # If the DC is a GC server, the KCC constructs an additional NC # replica graph (and creates nTDSConnection objects) for the # config NC as above, except that only NC replicas that "are present" # on GC servers are added to R. + for dnstr, connect in mydsa.connect_table.items(): + if connect.to_be_added: + DEBUG_YELLOW("TO BE ADDED:\n%s" % connect) + + # Do it again, with gc_only True for partdn, part in self.part_table.items(): if part.is_config(): self.construct_intrasite_graph(mysite, mydsa, part, True, @@ -2262,6 +2285,9 @@ class KCC(object): # if the bit NTDSSETTINGS_OPT_IS_TOPL_DETECT_STALE_DISABLED were # set in the options attribute of the site settings object for # the local DC's site. (ie. we set "detec_stale" flag to False) + for dnstr, connect in mydsa.connect_table.items(): + if connect.to_be_added: + DEBUG_BLUE("TO BE ADDED:\n%s" % connect) # Loop thru all the partitions. for partdn, part in self.part_table.items(): @@ -2272,6 +2298,10 @@ class KCC(object): # replica graph (and creates nTDSConnection objects) for the # config NC as above, except that only NC replicas that "are present" # on GC servers are added to R. + for dnstr, connect in mydsa.connect_table.items(): + if connect.to_be_added: + DEBUG_RED("TO BE ADDED:\n%s" % connect) + for partdn, part in self.part_table.items(): if part.is_config(): self.construct_intrasite_graph(mysite, mydsa, part, True, @@ -2333,7 +2363,7 @@ class KCC(object): dot_edges.append((dsa.dsa_dnstr, con.from_dnstr)) verify_and_dot('dsa_initial', dot_edges, label=self.my_dsa_dnstr, properties=(), debug=DEBUG, verify=opts.verify, - dot_files=opts.dot_files) + dot_files=opts.dot_files, directed=True) dot_edges = [] for site in self.site_table.values(): @@ -2363,7 +2393,7 @@ class KCC(object): for a, b in itertools.combinations(link.site_list, 2): dot_edges.append((str(a), str(b))) verify_properties = ('connected',) - verify_and_dot('dsa_sitelink_initial', dot_edges, directed=False, label=self.my_dsa_dnstr, + verify_and_dot('dsa_sitelink_initial', dot_edges, directed=True, label=self.my_dsa_dnstr, properties=verify_properties, debug=DEBUG, verify=opts.verify, dot_files=opts.dot_files) @@ -2403,7 +2433,7 @@ class KCC(object): verify_properties = ('complete', 'connected', 'multi_edge_forest', 'forest', 'directed_double_ring') verify_and_dot('dsa_final', dot_edges, label=self.my_dsa_dnstr, properties=verify_properties, debug=DEBUG, verify=opts.verify, - dot_files=opts.dot_files) + dot_files=opts.dot_files, directed=True) except: raise @@ -2778,6 +2808,8 @@ class KCC(object): # Global Functions ################################################## def sort_replica_by_dsa_guid(rep1, rep2): + DEBUG_GREEN((ndr_pack(rep1.rep_dsa_guid), ndr_pack(rep2.rep_dsa_guid), + cmp(rep1.rep_dsa_guid, rep2.rep_dsa_guid), cmp(ndr_pack(rep1.rep_dsa_guid), ndr_pack(rep2.rep_dsa_guid)))) return cmp(ndr_pack(rep1.rep_dsa_guid), ndr_pack(rep2.rep_dsa_guid)) def sort_dsa_by_gc_and_guid(dsa1, dsa2): @@ -2785,6 +2817,7 @@ def sort_dsa_by_gc_and_guid(dsa1, dsa2): return -1 if not dsa1.is_gc() and dsa2.is_gc(): return +1 + DEBUG_CYAN((dsa1.dsa_guid, dsa2.dsa_guid, cmp(dsa1.dsa_guid, dsa2.dsa_guid))) return cmp(dsa1.dsa_guid, dsa2.dsa_guid) def is_smtp_replication_available():